30 September 2013
17 August 2013
11 August 2013
7 August 2013
!release
command should now work properly (master object was not cleared after a !release
meta)._relayMaster
to _relayObject
since it holds the key
of an object, not an avatar.14 July 2013
13 July 2013
/1q
), thank you Allison Lynagh.12 July 2013
12 April 2012
3 June 2012
llTakeControls(0, FALSE, FALSE);
should be able to properly lock an avatar down.
4 March 2012
This is a typical RLV collar that does not use off-world databases and allows the manipulation of clothes, sitting, unsitting, moving the avatar around, locking avatars into place, releasing, leashing avatars to objects or other avatars.
By default, the collar reacts only to the owner if RLV is turned on. There is also a switch accessible to the one controlling as well as the owner called FFA which enables anybody to control the wearer of the collar. By default FFA is turned off and just the wearer. Additionally, a notecard named Masters
placed alongside the script into the same primitive allows a key-based list of avatars to be specified that will become permanent masters (until they are manually removed from the notecard).
Masters
and add the keys of avatars that will have access to the collar line-by-line. For example:29586384-8b41-4136-9591-5afd84233235 d5b7b715-f179-4f22-bad8-04f84335fedf
remember to leave a blank line at the end of the notecard.
Click the collar to trigger the menu or type /1q
on local chat (and press enter) in order to open the menu.
/////////////////////////////////////////////////////////////////////////// // 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); } }