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>