// Davan Camus, 2006 // controller.lsl // for managing a "scene", can // query nearby devices for their settings, remember // a scene by name, and set it again. // integer COMMAND_CHANNEL = 31; // set to zero to disable integer DEVICE_CHANNEL = 32; // channel to ask devices on integer gListenerNumber = 0; float gTickSize = 0; integer gDebug = 0; integer SAVE_TIME = 10; // how long to capture replies from devices integer gDialogCommandChannel; // temporary, during dialog up integer gDialogListenerNumber = 0; // temporary, during dialog up float gChatTime = 0; //chat commands only work while positive... doDialog resets it. float gChatTimeout = 50.0; // how long the channel is active after a dialog starts. string gVersion = "0.0"; // wrapper for set timer event, where we keep track of it. setTimerEvent(float t) { gTickSize = t; llSetTimerEvent(t); } // d([this, that, the other]); prints debug stuff // (I find it easier to type the [list,notation] than all // that tedious casting-to-string and adding stuff d(list debugList) { if(!gDebug) return; else { string s = (string)(debugList); llOwnerSay("(dbg) "+s); } } // Take a list, type-and-cast appropriately, and concat it // all into a string. useful for debug displays. string list2String(list x) { string s = ""; integer len = llGetListLength(x); integer i; for(i = 0; i < len; i++) { integer t = llGetListEntryType(x,i); if(t == TYPE_STRING) s += llList2String(x,i); else if(t == TYPE_INTEGER) s += (string)llList2Integer(x,i); else if(t == TYPE_FLOAT) s += (string)llList2Float(x,i); else if(t == TYPE_FLOAT) s += (string)llList2Float(x,i); else if(t == TYPE_VECTOR) s += (string)llList2Vector(x,i); else if(t == TYPE_ROTATION) s += (string)llList2Rot(x,i); else s += "(item " + (string)i + ")"; } return s; } float gSaveCountdown = 0; integer gSaveListenerNumber = 0; string gSaveScene; list gSceneSettings; // quadruplets of (scene,name,param,value) doSave(string sceneName) { gSaveScene = sceneName; llShout(DEVICE_CHANNEL,"report"); llListenRemove(gSaveListenerNumber); gSaveListenerNumber = llListen(DEVICE_CHANNEL,"","",""); gSaveCountdown = SAVE_TIME; setTimerEvent(SAVE_TIME / 7); } // device message -- should only be for a "report" // message is param(space)value. Value may have spaces in it. addSceneSetting(string scene,string deviceName,string message) { integer x = llSubStringIndex(message," "); string deviceParam = llGetSubString(message,0,x - 1); string deviceValue = llGetSubString(message,x + 1, -1); // we simply add all quadruplets into our scene-settings // list! when called upon to set a scene, the entire // list is traversed, and only certain settings // are shouted to devices: those for the particular // scene. gSceneSettings += [scene,deviceName,deviceParam,deviceValue]; d(["adding to ",scene,": ",deviceName,".",deviceParam,"=",deviceValue]); d(["gSceneSettings size: ",llGetListLength(gSceneSettings)]); } setScene(string scene) { integer k = llGetListLength(gSceneSettings); integer i; integer paramCount = 0; for(i = 0; i < k; i += 4) { string aScene = llList2String(gSceneSettings,i); if(aScene == scene) { string deviceName = llList2String(gSceneSettings,i + 1); string deviceParam = llList2String(gSceneSettings,i + 2); string deviceValue = llList2String(gSceneSettings,i + 3); paramCount++; llShout(DEVICE_CHANNEL,(string)[deviceName," ",deviceParam," ",deviceValue]); } } llSetText("scene " + scene,<1,1,1>,1); } doneSave() { setTimerEvent(10); // slow again, nothing much doing llListenRemove(gSaveListenerNumber); gSaveListenerNumber = 0; llSay(0,"saved scene " + gSaveScene); gSaveScene = ""; llSay(0,(string)llGetFreeMemory() + " bytes free"); } // report a scene, for debugging... showScene(string scene) { integer k = llGetListLength(gSceneSettings); integer i; integer paramCount = 0; for(i = 0; i < k; i += 4) { string aScene = llList2String(gSceneSettings,i); if(aScene == scene) { string deviceName = llList2String(gSceneSettings,i + 1); string deviceParam = llList2String(gSceneSettings,i + 2); string deviceValue = llList2String(gSceneSettings,i + 3); paramCount++; llSay(0,(string)[paramCount,". ",aScene,": ",deviceName,".",deviceParam,"=",deviceValue]); } } } // All commands (link or chat) come through here // Empty command brings up dialog. doCommand(key av,string message) { gChatTime = gChatTimeout; if(message == "") { doDialog(av); return; } list messageL = llParseString2List(message,[" "],[]); string cmd = llToLower(llList2String(messageL,0)); integer arg1 = llList2Integer(messageL,1); string arg1S = llList2String(messageL,1); integer arg1OnOff = 0; if(llToLower(arg1S) == "on" || ((integer)arg1S > 0) || arg1S == "" ) arg1OnOff = 1; if(cmd == "save") { if(arg1S != "") doSave(arg1S); } else if(cmd == "s" || cmd == "scene") { setScene(arg1S); } else if(cmd == "show") { showScene(arg1S); } else if(cmd == "add") { // manually add a setting addSceneSetting(arg1S,llList2String(messageL,2),llList2String(messageL,3) + " " + llList2String(messageL,4) + " " + llList2String(messageL,5)); } else if(cmd == "clear") { // erase everything gSceneSettings = []; } // ... } integer doListen() { noListen(); // clear out any old one... gDialogCommandChannel = COMMAND_CHANNEL + 100 + (integer)(llFrand(10000)); gDialogListenerNumber = llListen(gDialogCommandChannel,"","",""); gChatTime = gChatTimeout; // start the countdown return gDialogCommandChannel; } noListen() { gChatTime = 0; llListenRemove(gDialogListenerNumber); } // dialogs start by getting a random temporary listener number, which // stays active for a little while. You can use over and over, // the timeout gets reset each time a command is received. doDialog(key av) { doListen(); // turn on the chat listener for the next command. list choices = [ "cmd 1","cmd 2","cmd 3" ]; string s = "Device" + "\nVersion" + gVersion + "\nMechanism by Davan Camus"; llDialog(av,s,choices,gDialogCommandChannel); // a short-lived channel number } init() { llListenRemove(gListenerNumber); if(COMMAND_CHANNEL) { gListenerNumber = llListen(COMMAND_CHANNEL,"","",""); d(["listening on ",COMMAND_CHANNEL]); } setTimerEvent(10); } default { on_rez(integer n) { llResetScript(); } state_entry() { init(); d(["state_entry"]); } touch_start(integer total_number) { d(["touched by: ",llDetectedName(0)]); doDialog(llDetectedKey(0)); } listen(integer channel,string name,key id,string message) { d(["listen (",name," on ",channel,"): ",message]); if(channel == COMMAND_CHANNEL || channel == gDialogListenerNumber) doCommand(id,message); else if(channel == DEVICE_CHANNEL) addSceneSetting(gSaveScene,name,message); } timer() { // dialog timeout if(gChatTime > 0) { gChatTime -= gTickSize; // if(gChatTime <= 0) noListen(); // no more chat. } if(gSaveCountdown > 0) { gSaveCountdown -= gTickSize; if(gSaveCountdown <= 0) doneSave(); } } } // end of file