Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Help! Memory Hog

Shifting Dreamscape
Always questioning ...
Join date: 12 Dec 2007
Posts: 266
05-24-2008 03:44
Hi all ... was hoping someone might be able to point out where I am going wrong ion the following script. Works fine its just that if I ask for Free Memory right on the entry into the default state it tells me somewhere between 4 and 5k. Started to make some changes to reduce but, short of removing all my states I can't thing of where else this is going wrong. Even the states with their events (headers only not counting the code in them) only take a little over 1k ....

So any help is greatly appreciated!

//
CODE

// Door Control
//
// *******************************************************************
// This program is free software; you can redistribute it and/or
// modify as you wish. Just don't try and sell it to someone ...
// that would not be nice or fair.
// If you have paid someone for this script .. contact me and we'll
// track them down inworld and harass them ;-)
//
// While I do not offer support for this script if you have questions
// feel free to contact me inworld.
//
// Writen by Shifting Dreamscape
// *******************************************************************

//'Bootstrap' Values ...
//Channel to call the param Reader ... Same for all scripts
integer PARAMETER_APP = -741037;
//My Id for them to return my request on ... unique for all scripts
integer MY_PARAM = -110110;

//The keys I am interested in
list PARAM_KEYS = ["control_channel","response_channel", "dialog_channel", "doorcontrol_chat_channel", "control_key", "door_individ", "user_control_channel", "user_resp_channel", "repeater_channel"];

//The position constants for the list
integer DOOR_CHAN = 0;//Channel the doors talk on
integer DOOR_RESP_CHAN = 1;//For responses fromn the door during setting
integer DIALOG_CHAN = 2;//Dialog Channel to listen on
integer DATA_CHAN = 3;//DataLink 'channel'
integer CONTROL_KEY = 4;//ID of the controller
integer INDIVID_CHAN = 5;//Link channels 'listened' to
integer USER_CHAN = 6;//For calls to the user control
integer USER_RESP_CHAN = 7;//Responses from the user control
integer REPEATER_CHAN = 8;//Channel (link) for talking to the repeater

//Values from Param app
list gParams;
//End Bootstrap Variables

//Parameter Notecard
string CONFIG_NOTECARD = "door_config";

//Notecard read variables
integer gConfigLine;
key gReadConfig;

//Options for doors
list DOOR_OPTIONS = ["Lock", "Unlock"];

//Door data
list gDoors = [];
list gDoorStatus = [];
list gDoorAccess = [];
list gTempDoors = [];

//The index in the list of the door selected
integer gIndex;

//Holds the name of the door while user is being checked
string gHoldDoor;

//Holds the human arranged list of doors ,,
list gDoorOptions;

//Flag if we have called the user control
integer gRequested = C_FALSE;

//For use with repeaters
string gHoldMessage;
string gLastDay;
list gMsgIds = [];

//Hold the key of the user for dialogs
key gCurId;

//Memory Saving Constants?
string EMPTY_STR = "";
string @_STR = "@";

integer C_TRUE = TRUE;
integer C_FALSE = FALSE;

key C_NULL_KEY = NULL_KEY;


//Repeater Functions

//These functions are used to be able to transmit messages further than the current limits of a say
//Apart from using llSay it will as well send a link message that will be picked up by any linked
//repeaters that will then say as well. To avoid duplication messages transmitted this way will have
//an id added to the beginning based on the seconds after midnight (LST). The receiving script will
//check to see if it already received that message and ignore if so, otherwise it will store the id
//in an internal list. As well the object will store the day it last received a message to be able
//to reset the list

//Function to add the id to the message and say/link message it
adv_say(integer channel, string message)
{
integer seconds;
string msgId;
integer length;
integer i;

//The id will ALWAYS be in the format MID##### so we will need to add lead 0's in many cases to the seconds
//Get the time in seconds
seconds = (integer)llGetWallclock();
//now convert to string
msgId = (string)seconds;
//Based on the length add leading 0's
length = llStringLength(msgId);
for (i = length; i < 5; i++)
{
msgId = "0" + msgId;
}
msgId = "MID" + msgId;

//append to message
message = msgId + @_STR + message;

//send out
llSay(channel, message);
llMessageLinked(LINK_ALL_OTHERS, llList2Integer(gParams, REPEATER_CHAN), message, (string)channel);

//Clean Up varianles
msgId = EMPTY_STR;
message = EMPTY_STR;


}//End adv_say

//function that checks the message id .. and manages the lists of ids
integer check_message(string message)
{
list dataList;
string firstElement;
integer result = C_FALSE;
integer msgId;
string today;

//First see if we have a message id
//Split
dataList = llParseString2List(message, [@_STR], [EMPTY_STR]);
//If the first element does not start with MID .. and is not 8 chars long .. it is not a message id and we ignore
firstElement = llList2String(dataList, 0);

if (llStringLength(firstElement) != 8 || llGetSubString(firstElement, 0, 2) != "MID")
{
//No message id so ignore ad we are done
result = C_TRUE;
}
else
{
//reset the message removing the first element
dataList = llList2List(dataList, 1, llGetListLength(dataList) - 1);
message = llDumpList2String(dataList, @_STR);

//Now strip the MID off the id
msgId = (integer)llGetSubString(firstElement, 3, 8);

//First check the last day we were called. If it is not today then we empty are list, and this one is good
today = llGetDate();

if (gLastDay != today)
{
gMsgIds = [msgId];
result = C_TRUE;
gLastDay = today;
}
else
{
//check for id in list
if (llListFindList(gMsgIds, [msgId]) == -1)
{
//not there so its good ...
result = C_TRUE;
//Prune old values to keep list size manageable
prune_data_list();
//Add this value to the list
gMsgIds = (gMsgIds=[]) + gMsgIds + [msgId];
gLastDay = today;
}
else
{
//Already recieved ...
result = C_FALSE;
//Prune old values to keep list size manageable
prune_data_list();
}
}
}
//We set the message to a global since LSL only passes byVal and we cannot manipulate the original here
gHoldMessage = message;

//Clean Up variables
dataList = [];
firstElement = EMPTY_STR;
today = EMPTY_STR;
message = EMPTY_STR;

return result;

}//End check_message

//Function to manage the list of received message ids
//Cleans up the mesage id list, removing any more that 5 min old to keep size manageable
prune_data_list()
{
list tempList = [];
integer quit = C_FALSE;
integer seconds;
integer posit;
integer cur = 0;
integer checkValue;

//Get Current seconds and then take back 5 minutes
seconds = (integer)llGetWallclock() - 600;

//If seconds are 0 or less we will have no ids older than 5 minutes so we are done
if (seconds > 0)
{
//now we run through the list .. going backwards till we are at 5 min ...
posit = llGetListLength(gMsgIds);

while (quit == C_FALSE && cur < posit)
{
checkValue = llList2Integer(gMsgIds, cur);
if (checkValue < seconds)
{
//Keep going
cur++;
}
else
{
//we found where the ones to keep begin
tempList = llList2List(gMsgIds, cur, posit - 1);
quit = C_TRUE;
}
}
gMsgIds = tempList;

//Clean Up variables
tempList = [];

}
}//End prune_data_list
//End Repeater Functions

//#######
//Principal work functions for actions of the Door controller

//Function to check if the door can be opened
respond_door(string message)
{
integer continue;
string doorId;
integer index;
string openDoor;
list dataList;
key user;

//First we check the message to see if already received (repeater function)
continue = check_message(message);
//Since LSL always passes ByVal we need to retrieve the message from a global
//as it has had the id portion stripped off
message = gHoldMessage;
gHoldMessage = EMPTY_STR;

if (continue == C_TRUE)
{
dataList = llParseString2List(message, [@_STR], [EMPTY_STR]);
user = llList2String(dataList, 0);
doorId = llList2String(dataList, 1);
index = llListFindList(gDoors, [doorId]);

if (index != -1)
{
if (llList2String(gDoorStatus, index) == "Unlock")
{
openDoor = "true";
}
else if (llList2String(gDoorAccess, index) == "Owner Only" && user == llGetOwner())
{
openDoor = "true";
}
else
{
//We need to call the user control to check
openDoor = "check";
gRequested = C_TRUE;
llMessageLinked(LINK_THIS, USER_CHAN, "check", user);
gHoldDoor = doorId;
}

//Create return .. if we haven't called for a user check
if (openDoor != "check")
{
adv_say(llList2Integer(gParams, DOOR_RESP_CHAN), doorId + @_STR + llList2String(gParams, CONTROL_KEY) + @_STR + openDoor);
}
}
}

//Clean up variables
doorId = EMPTY_STR;
openDoor = EMPTY_STR;
dataList = [];
user = C_NULL_KEY;
message = EMPTY_STR;

}//End respond_door

//During setup ... when we are setting a number of doors
//This function basically just holds the door id until we are done
set_door_data(string message)
{
integer continue;
string doorId;

//First we check the message to see if already received (repeater function)
continue = check_message(message);
//Since LSL always passes ByVal we need to retrieve the message from a global
//as it has had the id portion stripped off
message = gHoldMessage;
gHoldMessage = EMPTY_STR;

if (continue == C_TRUE)
{
llSay(0,message);
//This is the door calling to check on what has been set or passing its data
//the message has passed the name of who touched the door and door ID
doorId = llList2String(llParseString2List(message, [@_STR], [EMPTY_STR]), 1);

gTempDoors = (gTempDoors=[]) + gTempDoors + [doorId];
//and respond so the door can turn off its listener
adv_say(llList2Integer(gParams, DOOR_RESP_CHAN), doorId + @_STR + "0" + @_STR + "0");
llOwnerSay("Door Set: " + doorId);
}

//Clean Up variables
message = EMPTY_STR;
doorId = EMPTY_STR;
}//End set_door_data


//If we are just adding a single door to the currnt list, this is the function executed
add_door_data(string message)
{
integer continue;
string doorId;

//First we check the message to see if already received (repeater function)
continue = check_message(message);
//Since LSL always passes ByVal we need to retrieve the message from a global
//as it has had the id portion stripped off
message = gHoldMessage;
gHoldMessage = EMPTY_STR;

if (continue == C_TRUE)
{
//Call the door back to let it know to turn off the listener
doorId = llList2String(llParseString2List(message, [@_STR], [EMPTY_STR]), 1);
adv_say(llList2Integer(gParams, DOOR_RESP_CHAN), doorId + @_STR + "0" + @_STR + "0");

gDoors = (gDoors=[]) + gDoors + [doorId];
gDoorStatus = (gDoorStatus=[]) + gDoorStatus + ["Unlock"];
gDoorAccess = (gDoorAccess=[]) + gDoorAccess + ["Owner Only"];

gDoorOptions = gDoors + ["All"];

llOwnerSay("Done. By default the door is unlocked, and set to Owner only");
}
//Clean Up variables
message = EMPTY_STR;
doorId = EMPTY_STR;
}//End add_door_data

//This function dumps the door configurations to chat
//to allow them to be stored in a notecard
dump_data()
{
integer i;
integer length;

//Dumps the configuration data to chat
//so that it can be copied into the config notecard
llOwnerSay("Data Dump to follow");

length = llGetListLength(gDoors);
for (i = 0; i < length; ++i)
{
llSay(0, "=" + llList2String(gDoors, i) + @_STR + llList2String(gDoorStatus, i) + @_STR + llList2String(gDoorAccess, i));
}
}//End dump_data
//End Door Functions

//#####
//Common functions
//Any 'standard' functions used in this or other scripts


//!!!! Need to check function cost compared to two time inline

//Reorders the button text into a human order for the dialog
list set_buttons(list baseList)
{
integer i;

for (i=0; i<llGetListLength(baseList); i+=3)
{
baseList = llListInsertList(llDeleteSubList(baseList, -3, -1), llList2List(baseList, -3, -1), i);
}
return baseList;
}//End set_buttons
//End Common functions

//End Functions

//#####
//Body

//Default State
// Used to read in our parameter data ... only executed on start
default
{
state_entry()
{
llOwnerSay("Door Control: Requesting Parameters");
//Get my params from the notecard reader
llMessageLinked(LINK_THIS, PARAMETER_APP, llDumpList2String(PARAM_KEYS, @_STR), (string)MY_PARAM);
} // end state_entry

dataserver(key requested, string data)
{
list dataPair;

if (requested == gReadConfig)
{
if (data != EOF)
{
if (gConfigLine == 0)
{
if (data == "set")
{
//We then read in the rest until EOF
gConfigLine++;
gReadConfig = llGetNotecardLine(CONFIG_NOTECARD, gConfigLine);
}
else
{
//No data in the notecard so off to run
state running;
}
}
else
{
//only here if we have preset data
//set the data to the lists
dataPair = llParseString2List(data, ["="], [EMPTY_STR]);

//First is the text from the say .. we then need to parse the second part
dataPair = llParseString2List(llList2String(dataPair,1), [@_STR], [EMPTY_STR]);
gDoors = (gDoors=[]) + gDoors + llList2String(dataPair, 0);
gDoorStatus = (gDoorStatus=[]) + gDoorStatus + llList2String(dataPair, 1);
gDoorAccess = (gDoorAccess=[]) + gDoorAccess + llList2String(dataPair, 2);

//Read the next line
gConfigLine++;
gReadConfig = llGetNotecardLine(CONFIG_NOTECARD, gConfigLine);
}
}
else
{
state running;
}
}
}//End dataserevr

link_message(integer sender, integer channel, string message, key id)
{
//Only listen from this prim ... and my param chan
if (sender == LINK_ROOT && channel == MY_PARAM)
{
gParams = llParseString2List(message, [@_STR], [EMPTY_STR]);
llOwnerSay("Door Control: Parameters Loaded");

//Clear lists
gDoors = [];
gDoorStatus = [];
gDoorAccess = [];

//Read in my configuration data
gConfigLine = 0;
gReadConfig = llGetNotecardLine(CONFIG_NOTECARD, gConfigLine);

// state config_load;
}
}//End link_message

state_exit()
{
llOwnerSay("Door Control: Parameters Loaded");
}//End state_exit
}//End default


//Running State
// The script is normally in this state listening for calls ...
// be the call from a door checking of it can open, or from
// the building controller requesting the dialog
state running
{
state_entry()
{
//set up listen for doors to call
llListen(llList2Integer(gParams, DOOR_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);
}//End state_entry

link_message(integer sender, integer channel, string message, key id)
{
//Building control calling for the dialog
if (sender == LINK_ROOT && channel == llList2Integer(gParams, INDIVID_CHAN))
{
//Hold the id of the user for the dialog
gCurId = id;
//Show the dialog to select the door
state dialog_select;
}
//Call from a door passed on by a repeater
else if (channel == llList2Integer(gParams, REPEATER_CHAN))
{
//we use the (key)Id to pass the actual channel that comms were on
//seems I need to cast to a string before I can cast to an integer
string sId = (string)id;

if ((integer)sId == llList2Integer(gParams, DOOR_CHAN))
{
respond_door(message);
}
}
//Return from checking the user id to open the door
else if (sender == LINK_ROOT && channel == llList2Integer(gParams, USER_RESP_CHAN) && gRequested ==C_TRUE)
{
//Just pass to the door
gRequested = C_FALSE;
adv_say(llList2Integer(gParams, DOOR_RESP_CHAN), gHoldDoor + @_STR + llList2String(gParams, CONTROL_KEY) + @_STR + message);
}
}//End link_message

//Just hearing a door asking for a check
listen(integer channel, string name, key id, string message)
{
respond_door(message);
}//End listen


}//End running
Shifting Dreamscape
Always questioning ...
Join date: 12 Dec 2007
Posts: 266
05-24-2008 03:47
//Dialog States ...
// The following states are activated based on a dialog being shown
// and actually are what shows the particular dialog and responds

//First dialog shown, to select what door to set
state dialog_select
{
state_entry()
{
list buttons;

//Check to see if the owner to add the edit functions
if (llGetOwnerKey(llGetKey()) == gCurId)
{
buttons = gDoorOptions + ["Edit"];
}
else
{
buttons = gDoorOptions;
}
buttons = set_buttons(buttons);

//Show the dialog
llDialog(gCurId, "Which door would you like to set?", buttons, llList2Integer(gParams, DIALOG_CHAN));

//Start Listening
llListen(llList2Integer(gParams, DIALOG_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);

//Set Timer to Turn off listen in case the user does not go all the way through
llSetTimerEvent(10.0);
llResetTime();

//Clean up Vairbales
buttons = [];

}//End state_entry

//Only listening to the dialog channel
listen(integer channel, string name, key id, string message)
{
if (message == "Edit";)
{
state dialog_edit;
}
else
{
//A door (or all) has been choosen
if (message == "All";)
{
gIndex = -2;
}
else
{
gIndex = llListFindList(gDoors, [message]);
}
state dialog_settings;
}
}//End listen

timer()
{
// user never selected ...
state running;

}//End timer

state_exit()
{
llSetTimerEvent(0.0);
}//End state_exit

}//End dialog_select

//Allows for the lock/unlock of the door and assign allowed
state dialog_settings
{
state_entry()
{
list buttons;

//Now Check to see if the owner to add the list functions ...
if (llGetOwnerKey(llGetKey()) == gCurId)
{
buttons = DOOR_OPTIONS + ["Owner Only", "Auth Users"];
}
else
{
buttons = DOOR_OPTIONS;
}
buttons = set_buttons(buttons);
llDialog(gCurId, "What would you like to set?", buttons, llList2Integer(gParams, DIALOG_CHAN));

//Start Listening
llListen(llList2Integer(gParams, DIALOG_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);

//Set Timer to Turn off this channel in case the user does not go all the way through
llSetTimerEvent(10.0);
llResetTime();

}//End state_entry

//Only listening to the dialog channel
listen(integer channel, string name, key id, string message)
{
//Set the door(s) as appropriate then back to run
if (gIndex == -2)
{
//###Will call this if we implement estate, until then code in
//###the event for speddier execution
//set_all_doors(message);
integer length;
integer i;
list tempList;

length = llGetListLength(gDoorStatus);

//Temp set to all doors
for (i = 0; i < length; ++i)
{
tempList = (tempList=[]) + tempList + [message];
}

if (message == "Lock" || message == "Unlock";)
{
gDoorStatus = tempList;
}
else
{
gDoorAccess = tempList;
}
}
else
{
if (message == "Lock" || message == "Unlock";)
{
gDoorStatus = llListReplaceList(gDoorStatus, [message], gIndex, gIndex);
}
else
{
gDoorAccess = llListReplaceList(gDoorAccess, [message], gIndex, gIndex);
}
}
state running;
}//End Listen

timer()
{
state running;
}//End timer

state_exit()
{
llSetTimerEvent(0.0);
}//End state_exit
}//End dialog_settings

//Show the options for editing
state dialog_edit
{
state_entry()
{
list buttons;

//We show the Edit Dialog
//Check to see if we have any doors to show or not the remove option
if (llGetListLength(gDoors) > 0)
{
buttons = ["Add", "Remove", "Reload"];
}
else
{
buttons = ["Add", "Reload"];
}
buttons = (buttons=[]) + buttons + ["Set", "Dump Data"];

llDialog(gCurId, "Select your edit option", buttons, llList2Integer(gParams, DIALOG_CHAN));

//Start Listening
llListen(llList2Integer(gParams, DIALOG_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);

//Set Timer to Turn off this channel in case the user does not go all the way through
llSetTimerEvent(10.0);
llResetTime();
}//End state_entry

//Only listening to the dialog
listen(integer channel, string name, key id, string message)
{
//Off to the proper state based on the selection
if (message == "Set";)
{
state setting;
}
else if (message == "Remove";)
{
state remove;
}
else if (message == "Add";)
{
state add;
}
else if (message == "Dump Data";)
{
dump_data();
state running;
}
else if (message == "Reload";)
{
state default;
}

}//End listen

timer()
{
// user never selected ...
state running;

}//End timer

state_exit()
{
llSetTimerEvent(0.0);
}//End state_exit
}//End dialog_edit
//End Dialog States


//Editing states
// The following states are called when we are in some way editing
// the door configuration lists

//State called when setting the list from scratch
state setting
{
state_entry()
{
gTempDoors = [];

llOwnerSay("To set the doors into the controller simply touch each door.";);
llOwnerSay("When you are done say on channel " + llList2String(gParams, DATA_CHAN) + " 'Done'";);
llOwnerSay("If you want to cancel the setting simply say 'Cancel' on channel " + llList2String(gParams, DATA_CHAN));
llOwnerSay("If you spend more than 60 seconds between doors this process will timeout";);

//Need to listen both for user comments (DATA_CHAN) ... and the doors (DOOR_CHAN)
llListen(llList2Integer(gParams, DATA_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);
llListen(llList2Integer(gParams, DOOR_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);
llSetTimerEvent(60.0);
llResetTime();
}//End state_entry

listen(integer channel, string name, key id, string message)
{
integer length;
integer i;

//Door calling with its ID
if (channel == llList2Integer(gParams, DOOR_CHAN))
{
llResetTime();
set_door_data(message);
}
//User chat channel .. either we are done or canceling
else if (message == "Done";)
{
//Set the temp data to actuals, put in default states,
//dump data and then back to run
gDoors = gTempDoors;

length = llGetListLength(gTempDoors);
gDoorStatus = [];
gDoorAccess = [];

//Set to all doors
for (i = 0; i < length; ++i)
{
gDoorStatus = (gDoorStatus=[]) + gDoorStatus + ["Unlock"];
gDoorAccess = (gDoorAccess=[]) + gDoorAccess + ["Owner Only"];
}
gDoorOptions = gDoors + ["All"];

llOwnerSay("Done. By default all doors are unlocked, and set to Owner only.";);
dump_data();
state running;
}
else if (message == "Cancel";)
{
llOwnerSay("Configuration Canceled by User";);
state running;
}

}//End listen

//Getting messages from the repeater for doors that are out of range
link_message(integer sender, integer channel, string message, key id)
{
if (channel == llList2Integer(gParams, REPEATER_CHAN))
{
//we use the (key)Id to pass the actual channel that comms were on
//seems I need to cast to a string before I can cast to an integer
string sId = (string)id;

if ((integer)sId == llList2Integer(gParams, DOOR_CHAN))
{
llResetTime();
set_door_data(message);
}
}
}

timer()
{
// user never selected ...
llOwnerSay("Too much time between touching doors, configuration timed out";);
state running;
}//End timer

state_exit()
{
gTempDoors = [];
llSetTimerEvent(0.0);
}//End state_exit
}//End setting

//Used when we are adding a single new door to the list
state add
{
state_entry()
{
llOwnerSay("Simply touch the door you wish to add.";);
llOwnerSay("If you want to cancel the setting simply say 'Cancel' on channel " + llList2String(gParams, DATA_CHAN));
llOwnerSay("If you spend more than 60 seconds this process will timeout";);

//Need to listen both for user comments (DATA_CHAN) ... and the doors (DOOR_CHAN)
llListen(llList2Integer(gParams, DATA_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);
llListen(llList2Integer(gParams, DOOR_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);
llSetTimerEvent(60.0);
llResetTime();
}//End state_entry

//All we do in the listens is add the door then back to run
//Only listening on the door channel
listen(integer channel, string name, key id, string message)
{
if (channel == llList2Integer(gParams, DOOR_CHAN))
{
add_door_data(message);
dump_data();
state running;
}
else if (message == "Cancel";)
{
llOwnerSay("Configuration Canceled by User";);
state running;
}

}//End listen

//Could get the call from the repeater
link_message(integer sender, integer channel, string message, key id)
{
if (channel == llList2Integer(gParams, REPEATER_CHAN))
{
//we use the (key)Id to pass the actual channel that comms were on
//seems I need to cast to a string before I can cast to an integer
string sId = (string)id;

if ((integer)sId == llList2Integer(gParams, DOOR_CHAN))
{
add_door_data(message);
dump_data();
state running;
}
}
}

timer()
{
// user never selected ...
llOwnerSay("Too much time before touching the door, configuration timedout";);
state running;
}//End timer

state_exit()
{
llSetTimerEvent(0.0);
}//End state_exit
}//End add

//Used to remove a door from the configuration lists
state remove
{
state_entry()
{
//We show another dialog to allow the user to select the door to be removed
llDialog(gCurId, "Which door do you want to remove?", set_buttons(gDoors), llList2Integer(gParams, DIALOG_CHAN));
llListen(llList2Integer(gParams, DIALOG_CHAN), EMPTY_STR, C_NULL_KEY, EMPTY_STR);
llSetTimerEvent(10.0);
llResetTime();
}//End state_entry

//Only listening to the dialog
listen(integer channel, string name, key id, string message)
{
integer index;

//Remove the selected door from the lists
index = llListFindList(gDoors, [message]);
if (index != -1)
{
gDoors = llDeleteSubList(gDoors, index, index);
gDoorStatus = llDeleteSubList(gDoorStatus, index, index);
gDoorAccess = llDeleteSubList(gDoorAccess, index, index);

gDoorOptions = gDoors + ["All"];
}
state running;
}//End listen

timer()
{
// user never selected ... or canceled
llOwnerSay("Door remove canceled, timeout";);
state running;
}//End timer

state_exit()
{
llSetTimerEvent(0.0);
}//End state_exit
}//End remove
//End Editing States
//[/PHP]