Combined LockMeister Handle Post and Collar
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
LockMeister+ Handles, Posts and Collar
Overview
The LockMeister system protocol for cuffs, collars and leash handles has been around from many years and in that time a number of extensions to the protocol have been added and have been documented.
LockMeister+ is an effort to bring together those extensions and define a set of expected behaviours to allow greater interoperability and functionality between devices that use the extended protocol. The aims of LockMeister+ are:
- To gather up the existing extensions into a new extended protocol.
- To add functionality that can be gained from combining those extensions.
- To define the expected behaviour for a number if classes of devices.
- To be 100% backwards compatible with what has gone before.
The LockMeister+ Handle reference script
The LockMeister+ Handle:
- MUST respond to basic "handle" messages with an "ok".
- MUST implement the "here" and "gone" messages.
<lsl>/////////////////////////////////////////////////////////////////////// // // Lockmeister+ Handle Reference Script // // Tianna Violet // 20 Jan 2010 // // http://wiki.secondlife.com/wiki/LSL_Protocol/LockMeister_System // // Note that this script will only work in the ROOT PRIM ONLY as it // uses an "attach" event which aren't handled properly in child prims. /////////////////////////////////////////////////////////////////////// // The lockmeister name of the handle. string LOCKMEISTER_NAME = "handle"; /////////////////////////////////////////////////////////////////////// string gCuffMessage;
default {
state_entry() { gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME; llListen(-8888, "", NULL_KEY, ""); }
attach(key id) { string message;
message = " gone"; if (id) { gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME; message = " here"; } llSay(-8888, gCuffMessage + message); // send the "here" and "gone" message }
listen(integer channel, string name, key id, string message) { if (message == gCuffMessage) { llSay(-8888, gCuffMessage + " ok"); // the basic response return; } }
} </lsl>
The LockMeister+ Post reference script
The LockMeister+ Post:
- MUST send a "posk ok" message when the post is touched the key being the toucher's UUID
- MUST respond to basic "handle" messages where the message key is its own UUID with an "ok".
- SHOULD contain 'post' in its name and script SHOULD be in the root prim so that a post that is found through a scan of nearby objects can be confirmed as a LockMeister+ post.
<lsl>/////////////////////////////////////////////////////////////////////// // // Lockmeister+ Post Reference Script // // Tianna Violet // 21 Jan 2010 // // http://wiki.secondlife.com/wiki/LSL_Protocol/LockMeister_System /////////////////////////////////////////////////////////////////////// // The lockmeister name of the leash. string LOCKMEISTER_NAME = "handle"; ///////////////////////////////////////////////////////////////////////
default {
state_entry() { llListen(-8888, "", NULL_KEY, ""); }
touch_start(integer total_number) { llSay(-8888, (string) llDetectedKey(0) + "post ok"); }
listen(integer channel, string name, key id, string message) { string postMessage;
postMessage = (string) llGetKey() + LOCKMEISTER_NAME; if (message == postMessage) { llSay(-8888, postMessage + " ok"); return; } }
} </lsl>
The LockMeister+ Collar reference script
The LockMeister+ Collar:
- MUST look for a handle using the basic LockMeister query/response.
- MUST monitor "here" messages in order to connect to a handle should it appear.
- MUST monitor the "gone" event to remove the leash should the handle disappear.
- MUST send out new target requests should the current handle disappear.
- MUST support the "post ok" message and basic query/response to the post.
- SHOULD support basic LockMeister query/responses for the "collar" attach point.
- SHOULD reconnect the leash when the AV logs on if the attach point is still available.
- SHOULD support one touch transfer of the leash from the leash holder to a post.
- SHOULD support one touch transfer of the leash from a post to an AV with leash access.
<lsl>/////////////////////////////////////////////////////////////////////// // // Lockmeister+ Collar Reference Script // // Tianna Violet // 31 Jan 2010 // // http://wiki.secondlife.com/wiki/LSL_Protocol/LockMeister_System // // the collar reponds on channel 53 // // /53xxleash - grab the leash // /53xxunleash - unleash // /53xxleashpost - leash to a previously touch post // // xx = the initials of the wearer or * to effect all collars // // Note that this script will only work in the ROOT PRIM ONLY as it // uses an "attach" event which aren't handled properly in child prims. /////////////////////////////////////////////////////////////////////// // The lockmeister name of the collar. string LOCKMEISTER_NAME = "collar"; string gCuffMessage; key gLeashHolder; key gCurrentTarget; key gPostToucher; key gPost; key gPending; integer isLeashed; string gPrefix;
// Who has access to the collar
// This is where the owner list etc is checked
integer hasAccess(key id)
{
return TRUE; // everyone has access
}
// Start or update the particle stream updateParticles() {
llParticleSystem( [PSYS_PART_START_SCALE, <0.1, 0.1, 0>, PSYS_PART_END_SCALE, <1, 1, 0>, PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>, PSYS_PART_START_ALPHA, 1.0, PSYS_PART_END_ALPHA, 1.0, PSYS_SRC_TEXTURE, "1ffb37fa-2fc1-dbec-d8ea-0607583a03c6", PSYS_SRC_BURST_PART_COUNT, 1, PSYS_SRC_BURST_RATE, 0.0, PSYS_PART_MAX_AGE, 2, PSYS_SRC_MAX_AGE, 0.0, PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_DROP, PSYS_SRC_BURST_RADIUS, 0.5, PSYS_SRC_INNERANGLE, 0.0, PSYS_SRC_OUTERANGLE, 0.0, PSYS_SRC_OMEGA, <0, 0, 0>, PSYS_SRC_ACCEL, <0, 0, -0.7>, PSYS_SRC_BURST_SPEED_MIN, 1000.0, PSYS_SRC_BURST_SPEED_MAX, 1000.0, PSYS_SRC_TARGET_KEY, gCurrentTarget, PSYS_PART_FLAGS, PSYS_PART_FOLLOW_VELOCITY_MASK | PSYS_PART_FOLLOW_SRC_MASK | PSYS_PART_TARGET_POS_MASK]);
}
setPrefix() {
list l;
l = llParseString2List(llToLower(llKey2Name(llGetOwner())), [" "], []); gPrefix = llGetSubString(llList2String(l, 0), 0, 0) + llGetSubString(llList2String(l, 1), 0, 0);
}
releash() {
if (isLeashed) { if (gLeashHolder) { llSensor("", gLeashHolder, AGENT, 30.0, PI); } else { gPending = gCurrentTarget; llSay(-8888, ((string) gPending + "handle")); } llParticleSystem([]); isLeashed = 0; gLeashHolder = NULL_KEY; gCurrentTarget = NULL_KEY; }
}
default {
state_entry() { gLeashHolder = NULL_KEY; gCurrentTarget = NULL_KEY; gPostToucher = NULL_KEY; gPost = NULL_KEY; gPending = NULL_KEY; isLeashed = 0; setPrefix(); gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME; llListen(-8888, "", NULL_KEY, ""); llListen(53, "", NULL_KEY, ""); }
listen(integer channel, string name, key id, string message) { list commands = ["leash", "unleash", "leashpost"]; list responses = ["handle ok", "handle here", "handle gone", "post ok"]; key target; integer index; integer len;
if (channel == 53 && hasAccess(id)) { message = llStringTrim(llToLower(message), STRING_TRIM); index = -1; if (llGetSubString(message, 0, 0) == "*") { index = 1; } else { len = llStringLength(gPrefix); if (llGetSubString(message, 0, len - 1) == gPrefix) { index = len; } } if (~index) { index = llListFindList(commands, [llGetSubString(message, index, -1)]); } if (~index) { gPending = NULL_KEY; if (!index) { if (gLeashHolder == NULL_KEY) { gLeashHolder = id; gCurrentTarget = id; isLeashed = 1; updateParticles(); llSay(-8888, ((string) id) + "handle"); gPending = id; } } if (gLeashHolder == NULL_KEY || gLeashHolder == id) { if (index == 1) { gLeashHolder = NULL_KEY; isLeashed = 0; llParticleSystem([]); } if (index == 2) { if (gPost != NULL_KEY && gPost != gCurrentTarget && gPostToucher == id) { llSay(-8888, ((string) gPost) + "handle"); gPending = gPost; } } } } }
if (channel == -8888) { if (message == gCuffMessage) { llSay(-8888, gCuffMessage + " ok"); // the basic response return; } target = (key) llGetSubString(message, 0, 35); if (target) { index = llListFindList(responses, [llGetSubString(message, 36, -1)]); if (~index) { if (!index && target == gPending) { gCurrentTarget = id; isLeashed = 1; if (id == target) { gLeashHolder = NULL_KEY; } gPending = NULL_KEY; updateParticles(); } if (target == gLeashHolder) { if (index == 1 && gCurrentTarget != id) { gCurrentTarget = id; isLeashed = 1; gPending = NULL_KEY; updateParticles(); } if (index == 2 && gCurrentTarget == id) { releash(); } } if (index == 3) { if (target == gLeashHolder || (gLeashHolder == NULL_KEY && hasAccess(target))) { gPostToucher = target; gPost = id; if (gPost != gCurrentTarget) { if (gLeashHolder != NULL_KEY) { gLeashHolder = NULL_KEY; gCurrentTarget = gPost; isLeashed = 1; gPending = NULL_KEY; updateParticles(); } } else { gLeashHolder = target; gCurrentTarget = target; isLeashed = 1; updateParticles(); gPending = target; llSay(-8888, ((string) target) + "handle"); } } } } } } }
attach(key id) { string message;
message = " gone"; if (id) { gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME; message = " here"; if (isLeashed) { releash(); } } llSay(-8888, gCuffMessage + message); // send the "here" and "gone" message }
sensor(integer total_number) { gLeashHolder = llDetectedKey(0); gCurrentTarget = gLeashHolder; isLeashed = 1; updateParticles(); llSay(-8888, ((string) gLeashHolder) + "handle"); gPending = gLeashHolder; }
on_rez(integer start_param) { setPrefix(); }
} </lsl>