/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueGet(string var, string kvp) { list dVars = llParseString2List(kvp, ["&"], []); do { list data = llParseString2List(llList2String(dVars, 0), ["="], []); string k = llList2String(data, 0); if(k != var) jump continue; return llList2String(data, 1); @continue; dVars = llDeleteSubList(dVars, 0, 0); } while(llGetListLength(dVars)); return ""; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueSet(string var, string val, string kvp) { list dVars = llParseString2List(kvp, ["&"], []); if(llGetListLength(dVars) == 0) return var + "=" + val; list result = []; do { list data = llParseString2List(llList2String(dVars, 0), ["="], []); string k = llList2String(data, 0); if(k == "") jump continue; if(k == var && val == "") jump continue; if(k == var) { result += k + "=" + val; val = ""; jump continue; } string v = llList2String(data, 1); if(v == "") jump continue; result += k + "=" + v; @continue; dVars = llDeleteSubList(dVars, 0, 0); } while(llGetListLength(dVars)); if(val != "") result += var + "=" + val; return llDumpList2String(result, "&"); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// integer wasMenuIndex = 0; list wasEndlessMenu(list input, list actions, string direction) { integer cut = 11-wasListCountExclude(actions, [""]); if(direction == ">" && (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) { ++wasMenuIndex; jump slice; } if(direction == "<" && wasMenuIndex-1 >= 0) { --wasMenuIndex; jump slice; } @slice; integer multiple = wasMenuIndex*cut; input = llList2List(input, multiple+wasMenuIndex, multiple+cut+wasMenuIndex); input = wasListMerge(input, actions, ""); return input; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// integer wasListCountExclude(list input, list exclude) { if(llGetListLength(input) == 0) return 0; if(llListFindList(exclude, (list)llList2String(input, 0)) == -1) return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude); return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// list wasListMerge(list l, list m, string merge) { if(llGetListLength(l) == 0 && llGetListLength(m) == 0) return []; string a = llList2String(m, 0); if(a != merge) return [ a ] + wasListMerge(l, llDeleteSubList(m, 0, 0), merge); return [ llList2String(l, 0) ] + wasListMerge(llDeleteSubList(l, 0, 0), llDeleteSubList(m, 0, 0), merge); } //pragma inline moveTo(vector target, integer bb) { llStopMoveToTarget(); llTargetRemove(_aMoveTarget); vector pointTo = target - llGetPos(); llOwnerSay("@setrot:" + (string)llAtan2(pointTo.x, pointTo.y) + "=force"); _aMoveTarget = llTarget(target, 2 + bb); llMoveToTarget(target, 2); } //pragma inline stopMove() { llSensorRemove(); llStopMoveToTarget(); llTargetRemove(_aMoveTarget); _leashedKey = NULL_KEY; llParticleSystem([]); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // // Original by: By Marine Kelley, Maike Short and Felis Darwin // /////////////////////////////////////////////////////////////////////////// wasTrapCommand(key id, string message) { list tokens = llParseString2List (message, [","], []); if (llGetListLength (tokens) != 3) return; string cmd_id = llList2String(tokens, 0); if (llList2Key(tokens, 1) != llGetOwner ()) return; list commands = llParseString2List(llList2String(tokens, 2), ["|"], []); do { string command = llList2String(commands, 0); // relay metacommands if(command == "!release") { do { string restriction = llList2String(_relayRestrictions, 0); if(llGetSubString(restriction, 0, 0) != "@") jump next; llOwnerSay(restriction + "=y"); @next; _relayRestrictions = llDeleteSubList(_relayRestrictions, 0, 0); } while(llGetListLength(_relayRestrictions) != 0); llShout(-1812221819, cmd_id + "," + (string)id + "," + command + "," + "ok"); return; } if (command == "!version") { llShout(-1812221819, cmd_id + "," + (string)id + "," + command + "," + "1100"); jump continue; } // standard commands if (llGetSubString(command, 0, 0) != "@") jump continue; list commandTokens = llParseString2List (command, ["="], [""]); string behav = llList2String(commandTokens, 0); string param = llList2String(commandTokens, 1); integer idx = llListFindList(_relayRestrictions, [behav]); if ((param == "n" || param == "add") && idx == -1) { llOwnerSay(behav + "=n"); _relayRestrictions += [behav]; jump acknowledge; } if ((param == "y" || param == "rem") && idx != -1) { llOwnerSay(llList2String(_relayRestrictions, idx) + "=y"); _relayRestrictions = llDeleteSubList(_relayRestrictions, idx, idx); jump acknowledge; } llOwnerSay(command); @acknowledge; llShout(-1812221819, cmd_id + "," + (string)id + "," + command + "," + "ok"); @continue; commands = llDeleteSubList(commands, 0, 0); } while(llGetListLength(commands) != 0); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// LID(key id) { if(id != NULL_KEY && llGetAttached() != 0) { llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", (string)((integer)wasKeyValueGet("login", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))+1), llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llResetScript(); } llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "-1", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); } // General variables list _menuItems = []; list _objectKeys = []; list _mList = []; key _aMaster = NULL_KEY; integer _aMoveTarget = 0; string _SCAN = ""; string _FFA = ""; string _LOCK = ""; string _RELAY = ""; key _leashedKey = NULL_KEY; integer _comChannel = 0; integer _comHandle = 0; // RLV relay variables integer _relayHandle = 0; key _relayObject = NULL_KEY; string _relayCommand = ""; integer _relayTmpHandle = 0; integer _relayConfirmed = FALSE; list _relayRestrictions = []; default { state_entry() { // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments // if LID™, then login = 1 // else login = 0 - script running | parameter undefined if((integer)wasKeyValueGet("login", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) > 0) { llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llSetTimerEvent(25); return; } llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); state check; } timer() { state check; } changed(integer change) { if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) { llResetScript(); } } // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments attach(key id) { LID(id); } } state check { state_entry() { llSetTimerEvent(5); _comChannel = 10+(integer)llFrand(10); llListen(_comChannel, "", llGetOwner(), ""); llOwnerSay("@version=" + (string)_comChannel); } listen(integer channel, string name, key id, string message) { llSetTimerEvent(0); @setup; if(wasKeyValueGet("lock", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "on") { llOwnerSay("@detach=n"); _LOCK = "LOCK: ON"; jump setffa; } llOwnerSay("@detach=y"); _LOCK = "LOCK: OFF"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("lock", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); @setffa; if(wasKeyValueGet("ffa", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "on") { _FFA = "FFA: ON"; jump setrelay; } _FFA = "FFA: OFF"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("ffa", "OFF", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); @setrelay; if(wasKeyValueGet("relay", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "on") { _RELAY = "RELAY: ON"; jump donesettings; } _RELAY = "RELAY: OFF"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("relay", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); @donesettings; _mList = []; integer i = llGetInventoryNumber(INVENTORY_NOTECARD)-1; do { if(llGetInventoryName(INVENTORY_NOTECARD, i) == "Masters") jump foundmasters; } while(--i>-1); state main; @foundmasters; _comHandle = 0; _aMaster = llGetNotecardLine("Masters", _comHandle); } dataserver(key query_id, string data) { if(query_id != _aMaster) return; if(data == EOF) { _comHandle = 0; state main; } if(data == "") jump continue; _mList += [llStringTrim(data, STRING_TRIM)]; @continue; _aMaster = llGetNotecardLine("Masters", ++_comHandle); } timer() { llSetTimerEvent(0); llOwnerSay("[QuickCollar℠]: Your viewer is not RLV-enabled. This gizmo requires a RLV-enabled viewer. Cannot proceed."); } changed(integer change) { if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) { llResetScript(); } } // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments attach(key id) { LID(id); } } state main { state_entry() { llListen(1, "", "", llGetSubString(llToLower(llKey2Name(llGetOwner())), 0, 1)); if(_SCAN == "wearables") { _comHandle = llListen(_comChannel+1, "", _aMaster, ""); return; } if(_SCAN == "attachments") { _comHandle = llListen(_comChannel+2, "", _aMaster, ""); return; } if(_RELAY == "RELAY: ON") { _relayHandle = llListen(-1812221819, "", "", ""); } } sensor(integer num) { llSetTimerEvent(60); _menuItems = []; _objectKeys = []; --num; do { _menuItems += llGetSubString(llDetectedName(num), 0, 23); _objectKeys += llDetectedKey(num); } while(--num>-1); if(llGetListLength(_menuItems) == 0) { llInstantMessage(_aMaster, "[QuickCollar℠]: Sorry, no objects or avatars detected..."); return; } if(_SCAN == "sit") { _comHandle = llListen(_comChannel+3, "", _aMaster, ""); llDialog(_aMaster, "Please select an object to sit the wearer on:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], ""), _comChannel+3); return; } if(_SCAN == "go") { _comHandle = llListen(_comChannel+4, "", _aMaster, ""); llDialog(_aMaster, "Please select the destination to send the wearer to:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], ""), _comChannel+4); return; } if(_SCAN == "leash") { _comHandle = llListen(_comChannel+5, "", _aMaster, ""); llDialog(_aMaster, "Please select the object or avatar to leash the wearer to:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], ""), _comChannel+5); return; } } at_target( integer tnum, vector targetpos, vector ourpos ) { if(tnum != _aMoveTarget) return; llStopMoveToTarget(); vector pointTo = targetpos - llGetPos(); llOwnerSay("@setrot:" + (string)llAtan2(pointTo.x, pointTo.y) + "=force"); llTargetRemove(_aMoveTarget); } run_time_permissions(integer perm) { if (perm & PERMISSION_TAKE_CONTROLS) { llTakeControls(0, FALSE, FALSE); llOwnerSay("[QuickCollar℠]: " + llKey2Name(_aMaster) + " has made you stay."); } } listen(integer channel, string name, key id, string message) { llSetTimerEvent(60); if(message == llGetSubString(llToLower(llKey2Name(llGetOwner())), 0, 1) && ((id != llGetOwner() && _FFA == "FFA: ON") || id == llGetOwner() || llListFindList(_mList, (list)((string)id)) != -1)) { _aMaster = id; jump remenu; } if(message == "⏏ Exit") jump remenu; if(message == "⟻ Back") { llDialog(_aMaster, "Please browse the available items:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], "<"), channel); return; } if(message == "Next ⟼") { llDialog(_aMaster, "Please browse the available items:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], ">"), channel); return; } if(message == "FFA: OFF" || message == "FFA: ON") { if(_FFA == "FFA: OFF") { _FFA = "FFA: ON"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("ffa", "on", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); jump remenu; } _FFA = "FFA: OFF"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("ffa", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); jump remenu; } if(message == "LOCK: OFF" || message == "LOCK: ON") { if(_LOCK == "LOCK: OFF") { llOwnerSay("@detach=n"); _LOCK = "LOCK: ON"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("lock", "on", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); jump remenu; } llOwnerSay("@detach=y"); _LOCK = "LOCK: OFF"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("lock", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); jump remenu; } if(message == "RELAY: OFF" || message == "RELAY: ON") { _relayConfirmed = FALSE; llListenRemove(_relayHandle); if(_RELAY == "RELAY: OFF") { _relayHandle = llListen(-1812221819, "", "", ""); _RELAY = "RELAY: ON"; llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("relay", "on", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); jump remenu; } _RELAY = "RELAY: OFF"; _relayObject = NULL_KEY; do { string restriction = llList2String(_relayRestrictions, 0); if(llGetSubString(restriction, 0, 0) != "@") jump next; llOwnerSay(restriction + "=y"); @next; _relayRestrictions = llDeleteSubList(_relayRestrictions, 0, 0); } while(llGetListLength(_relayRestrictions)); llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("relay", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); jump remenu; } if(message == "⚐ PANIC") { llOwnerSay("@clear"); llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("ffa", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("lock", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("relay", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llResetScript(); } if(message == "[ ︻ Sits ]" ) { llDialog(_aMaster, "Please select whether to sit or unsit:\n", ["⏏ Exit", "︻ Sit", "┯ Stand"], _comChannel); return; } if(message == "┯ Stand") { llOwnerSay("@unsit=force"); jump remenu; } if(message == "︻ Sit") { _SCAN = "sit"; llInstantMessage(_aMaster, "[QuickCollar℠]: Scanning for nearby objects, please wait..."); llSensor("", "", (PASSIVE | ACTIVE), 10, PI); return; } if(message == "[ ✣ Moves ]") { llDialog(_aMaster, "Please select the desired movement:\n", ["⏏ Exit", "⌲ Go To", "⍊ Stay", "☼ Free"], _comChannel); return; } if(message == "☼ Free") { llReleaseControls(); llOwnerSay("[QuickCollar℠]: " + llKey2Name(id) + " has allowed you to move freely..."); jump remenu; } if(message == "⍊ Stay") { llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS); jump remenu; } if(message == "⌲ Go To") { _SCAN = "go"; llInstantMessage(_aMaster, "[QuickCollar℠]: Scanning for nearby targets, please wait..."); llSensor("", "", (AGENT | PASSIVE | ACTIVE), 10, PI); return; } if(message == "[ ❖ Clothes ]" ) { llDialog(_aMaster, "Please select the type of clothing to remove:\n", ["⏏ Exit", "▦ Worn", "▣ Attached"], _comChannel); return; } if(message == "▦ Worn") state show_wearables; if(message == "▣ Attached") state show_attachments; if(message == "[ ⚉ Hide ]" ) { llDialog(_aMaster, "Please select whether to hide or show the collar:\n", ["⏏ Exit", "⚉ Hide", "⚇ Show"], _comChannel); return; } if(message == "⚉ Hide") { llSetLinkAlpha(LINK_SET, .0, ALL_SIDES); jump remenu; } if(message == "⚇ Show") { llSetLinkAlpha(LINK_SET, 1, ALL_SIDES); jump remenu; } if(message == "[ 乀 Leash ]" ) { llDialog(_aMaster, "Please select whether to leash or unleash the wearer:\n", ["⏏ Exit", "乀 Leash", "✂ Release"], _comChannel); return; } if(message == "乀 Leash" ) { _SCAN = "leash"; llInstantMessage(_aMaster, "[QuickCollar℠]: Scanning for nearby objects, please wait..."); llSensor("", "", (AGENT | PASSIVE | ACTIVE), 10, PI); return; } if(message == "✂ Release" ) { llSensorRemove(); llStopMoveToTarget(); llTargetRemove(_aMoveTarget); _leashedKey = NULL_KEY; llParticleSystem([]); jump remenu; } if(channel == -1812221819 && _RELAY == "RELAY: ON" && _relayConfirmed == TRUE && id == _relayObject) { list tokens = llParseString2List(message, [","], []); if (llList2String(tokens, 1) != llGetOwner()) return; if (llGetListLength(tokens) != 3) return; wasTrapCommand(id, message); if(llList2String(tokens, 2) == "!release") { _relayObject = NULL_KEY; _relayConfirmed = FALSE; } return; } if(channel == -1812221819 && _RELAY == "RELAY: ON" && _relayConfirmed == FALSE && _relayObject == NULL_KEY) { list tokens = llParseString2List(message, [","], []); if(llList2String(tokens, 1) != llGetOwner()) return; if(llGetListLength(tokens) != 3) return; string meta = llList2String(tokens, 2); if(meta == "!version" || meta == "!release") { wasTrapCommand(id, message); return; } _relayObject = id; _relayCommand = message; _relayTmpHandle = llListen(_comChannel+6, "", llGetOwner(), ""); llDialog(llGetOwner(), name + " would like to control your viewer. Do you want to allow it?", ["Yes", "No"], _comChannel+6); return; } if(channel == _comChannel + 6) { if(message == "Yes") { _relayConfirmed = TRUE; wasTrapCommand(_relayObject, _relayCommand); return; } _relayConfirmed = FALSE; _relayObject = NULL_KEY; llListenRemove(_relayTmpHandle); return; } if(channel == _comChannel + 1) { llOwnerSay("@remoutfit:" + message + "=force"); state show_wearables; } if(channel == _comChannel + 2) { llOwnerSay("@detach:" + message + "=force"); state show_attachments; } if(channel == _comChannel + 3) { do { if(llSubStringIndex(llList2String(_menuItems, 0), message) != -1) jump rlvsit; _menuItems = llDeleteSubList(_menuItems, 0, 0); _objectKeys = llDeleteSubList(_objectKeys, 0, 0); } while(llGetListLength(_menuItems)); jump remenu; @rlvsit; llOwnerSay("@sit:" + llList2String(_objectKeys, 0) + "=force"); _menuItems = []; _objectKeys = []; jump remenu; } if(channel == _comChannel + 4) { do { if(llSubStringIndex(llList2String(_menuItems, 0), message) != -1) jump rlvmove; _menuItems = llDeleteSubList(_menuItems, 0, 0); _objectKeys = llDeleteSubList(_objectKeys, 0, 0); } while(llGetListLength(_menuItems)); jump remenu; @rlvmove; llParticleSystem([]); llSensorRemove(); _leashedKey = NULL_KEY; moveTo(llList2Vector(llGetObjectDetails(llList2String(_objectKeys, 0), [OBJECT_POS]), 0), (integer)(llVecDist(llList2Vector(llGetBoundingBox(llList2String(_objectKeys, 0)), 1), llList2Vector(llGetBoundingBox(llList2String(_objectKeys, 0)), 0))/2.0)); _menuItems = []; _objectKeys = []; jump remenu; } if(channel == _comChannel + 5) { do { if(llSubStringIndex(llList2String(_menuItems, 0), message) != -1) jump rlvleash; _menuItems = llDeleteSubList(_menuItems, 0, 0); _objectKeys = llDeleteSubList(_objectKeys, 0, 0); } while(llGetListLength(_menuItems)); jump remenu; @rlvleash; _leashedKey = llList2Key(_objectKeys, 0); llSensorRepeat("", NULL_KEY, AGENT, .1, 0, 1.2-llGetRegionTimeDilation()); llParticleSystem([12,"0560a0ad-ee6e-9a87-6a27-9322bad689ce",5,<3.0e-2,3.0e-2,3.0e-2>,6,<5.0e-2,5.0e-2,5.0e-2>,1,<1,1,1>,3,<1,1,1>,2,1,4,1,15,10,13,1e-3,7,10,9,1,8,<0,0,-.1>,0,355,20,_leashedKey]); _menuItems = []; _objectKeys = []; jump remenu; } return; @remenu; llListenRemove(_comHandle); _comChannel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6)); _comHandle = llListen(_comChannel, "", _aMaster, ""); llDialog(_aMaster, "\n Welcome to the Quick Collar℠.\nCreated in 2013 by Wizardry and Steamworks\n 15 July 2013: Version: 1.1\n", [_FFA, _LOCK, _RELAY, "[ ❖ Clothes ]", "⚐ PANIC", "[ ︻ Sits ]", "[ ✣ Moves ]", "[ 乀 Leash ]", "[ ⚉ Hide ]"], _comChannel); } no_sensor() { if(llStringLength(llKey2Name(_leashedKey)) == 0) jump awol; vector target = llList2Vector(llGetObjectDetails(_leashedKey, [OBJECT_POS]), 0); integer distance = (integer)llVecDist(target, llGetPos()); if(distance < 5) return; if(distance >= 5 && distance < 65) { moveTo(target, (integer)(llVecDist(llList2Vector(llGetBoundingBox(_leashedKey), 1), llList2Vector(llGetBoundingBox(_leashedKey), 0))/2.0)); return; } @awol; llOwnerSay("[QuickCollar℠]: Your master is AWOL. You are free to move."); stopMove(); } timer() { llSetTimerEvent(0); llListenRemove(_comHandle); } touch_start(integer num) { key toucher = llDetectedKey(0); if(toucher != llGetOwner() && llListFindList(_mList, (list)((string)toucher)) == -1 && _FFA == "FFA: OFF") return; _aMaster = toucher; _comChannel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6)); _comHandle = llListen(_comChannel, "", _aMaster, ""); llSetTimerEvent(60); llDialog(_aMaster, "\n Welcome to the Quick Collar℠.\nCreated in 2013 by Wizardry and Steamworks\n 15 July 2013: Version: 1.1\n", [_FFA, _LOCK, _RELAY, "[ ❖ Clothes ]", "⚐ PANIC", "[ ︻ Sits ]", "[ ✣ Moves ]", "[ 乀 Leash ]", "[ ⚉ Hide ]"], _comChannel); } changed(integer change) { if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) { llResetScript(); } } // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments attach(key id) { LID(id); } } state show_wearables { state_entry() { integer RLVchannel = 10+(integer)llFrand(10); llListen(RLVchannel, "", llGetOwner(), ""); llOwnerSay("@getoutfit=" + (string)RLVchannel); } listen(integer channel,string name,key id,string message) { list CLOTHES = [ "gloves","jacket","pants","shirt","shoes","skirt","socks","underpants","undershirt","skin","eyes","hair","shape", "alpha", "tattoo", "physics" ]; _menuItems = []; channel = 0; do { if(llGetSubString(message, channel, channel) != "1") jump skip; _menuItems += llList2String(CLOTHES, channel); @skip; } while(++channel<41); CLOTHES = []; _SCAN = "wearables"; llDialog(_aMaster, "Please select the wearables to take off:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], ""), _comChannel+1); _SCAN = "wearables"; state main; } changed(integer change) { if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) { llResetScript(); } } // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments attach(key id) { LID(id); } } state show_attachments { state_entry() { integer RLVchannel = 10+(integer)llFrand(10); llListen(RLVchannel, "", llGetOwner(), ""); llOwnerSay("@getattach=" + (string)RLVchannel); } listen(integer channel,string name,key id,string message) { list ATTACHMENTS = [ "none","chest","skull","left shoulder","right shoulder","left hand","right hand","left foot","right foot","spine","pelvis","mouth","chin","left ear","right ear","left eyeball","right eyeball","nose","r upper arm","r forearm","l upper arm","l forearm","right hip","r upper leg","r lower leg","left hip","l upper leg","l lower leg","stomach","left pec","right pec","center 2","top right","top","top left","center","bottom left","bottom","bottom right","neck","root"]; _menuItems = []; channel = 0; do { if(llGetSubString(message, channel, channel) != "1") jump skip; _menuItems += llList2String(ATTACHMENTS, channel); @skip; } while(++channel<41); ATTACHMENTS = []; llDialog(_aMaster, "Please select the attachments to detach:\n", wasEndlessMenu(_menuItems, ["⏏ Exit", "⟻ Back", "Next ⟼"], ""), _comChannel+2); _SCAN = "attachments"; state main; } changed(integer change) { if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) { llResetScript(); } } // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments attach(key id) { LID(id); } }