Difference between revisions of "Combined LockMeister Handle Post and Collar"

From Second Life Wiki
Jump to navigation Jump to search
(Created page with '{{LSL Header}} == LockMeister+ Handles, Posts and Collar == === Overview === The LockMeister system protocol for cuffs, collars and leash h...')
 
m ([Category:LockMeister])
 
(2 intermediate revisions by one other user not shown)
Line 40: Line 40:
default
default
{
{
state_entry()
    state_entry()
{
    {
gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
        gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
llListen(-8888, "", NULL_KEY, "");
        llListen(-8888, "", NULL_KEY, "");
}
    }


attach(key id)
    attach(key id)
{
    {
string message;
        string message;


message = " gone";
        message = " gone";
if (id)
        if (id)
{
        {
gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
            gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
message = " here";
            message = " here";
}
        }
llSay(-8888, gCuffMessage + message); // send the "here" and "gone" message
        llSay(-8888, gCuffMessage + message); // send the "here" and "gone" message
}
    }


listen(integer channel, string name, key id, string message)
    listen(integer channel, string name, key id, string message)
{
    {
if (message == gCuffMessage)
        if (message == gCuffMessage)
{
        {
llSay(-8888, gCuffMessage + " ok"); // the basic response
            llSay(-8888, gCuffMessage + " ok"); // the basic response
return;
            return;
}
        }
}
    }
}
}
</lsl>
</lsl>
Line 93: Line 93:
default
default
{
{
state_entry()
    state_entry()
{
    {
llListen(-8888, "", NULL_KEY, "");
        llListen(-8888, "", NULL_KEY, "");
}
    }


touch_start(integer total_number)
    touch_start(integer total_number)
{
    {
llSay(-8888, (string) llDetectedKey(0) + "post ok");
        llSay(-8888, (string) llDetectedKey(0) + "post ok");
}
    }


listen(integer channel, string name, key id, string message)
    listen(integer channel, string name, key id, string message)
{
    {
string postMessage;
        string postMessage;


postMessage = (string) llGetKey() + LOCKMEISTER_NAME;
        postMessage = (string) llGetKey() + LOCKMEISTER_NAME;
if (message == postMessage)
        if (message == postMessage)
{
        {
llSay(-8888, postMessage + " ok");
            llSay(-8888, postMessage + " ok");
return;
            return;
}
        }
}
    }
}
}
</lsl>
</lsl>
Line 129: Line 129:
*SHOULD reconnect the leash when the AV logs on if the attach point is still available.
*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 the leash holder to a post.
*SHOULD support one touch transfer of the leash from a post to an AV with leash access.


<lsl>///////////////////////////////////////////////////////////////////////
<lsl>///////////////////////////////////////////////////////////////////////
Line 166: Line 167:
integer hasAccess(key id)
integer hasAccess(key id)
{
{
return TRUE; // everyone has access
    return TRUE;   // everyone has access
}
}


Line 172: Line 173:
updateParticles()
updateParticles()
{
{
llParticleSystem( [PSYS_PART_START_SCALE, <0.1, 0.1, 0>, PSYS_PART_END_SCALE, <1, 1, 0>,
    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_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>,
PSYS_PART_START_ALPHA, 1.0, PSYS_PART_END_ALPHA, 1.0,
        PSYS_PART_START_ALPHA, 1.0, PSYS_PART_END_ALPHA, 1.0,
PSYS_SRC_TEXTURE, "1ffb37fa-2fc1-dbec-d8ea-0607583a03c6",
        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_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_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_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_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_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]);
        PSYS_PART_FLAGS, PSYS_PART_FOLLOW_VELOCITY_MASK | PSYS_PART_FOLLOW_SRC_MASK | PSYS_PART_TARGET_POS_MASK]);
}
}


setPrefix()
setPrefix()
{
{
list l;
    list l;


l = llParseString2List(llToLower(llKey2Name(llGetOwner())), [" "], []);
    l = llParseString2List(llToLower(llKey2Name(llGetOwner())), [" "], []);
gPrefix = llGetSubString(llList2String(l, 0), 0, 0) + llGetSubString(llList2String(l, 1), 0, 0);
    gPrefix = llGetSubString(llList2String(l, 0), 0, 0) + llGetSubString(llList2String(l, 1), 0, 0);
}
}


releash()
releash()
{
{
if (isLeashed)
    if (isLeashed)
{
    {
if (gLeashHolder)
        if (gLeashHolder)
{
        {
llSensor("", gLeashHolder, AGENT, 30.0, PI);
            llSensor("", gLeashHolder, AGENT, 30.0, PI);
} else {
        } else {
gPending = gCurrentTarget;
            gPending = gCurrentTarget;
llSay(-8888, ((string) gPending + "handle"));
            llSay(-8888, ((string) gPending + "handle"));
}
        }
llParticleSystem([]);
        llParticleSystem([]);
isLeashed = 0;
        isLeashed = 0;
gLeashHolder = NULL_KEY;
        gLeashHolder = NULL_KEY;
gCurrentTarget = NULL_KEY;
        gCurrentTarget = NULL_KEY;
}
    }
}
}


default
default
{
{
state_entry()
    state_entry()
{
    {
gLeashHolder = NULL_KEY;
        gLeashHolder = NULL_KEY;
gCurrentTarget = NULL_KEY;
        gCurrentTarget = NULL_KEY;
gPostToucher = NULL_KEY;
        gPostToucher = NULL_KEY;
gPost = NULL_KEY;
        gPost = NULL_KEY;
gPending = NULL_KEY;
        gPending = NULL_KEY;
isLeashed = 0;
        isLeashed = 0;
setPrefix();
        setPrefix();
gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
        gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
llListen(-8888, "", NULL_KEY, "");
        llListen(-8888, "", NULL_KEY, "");
llListen(53, "", NULL_KEY, "");
        llListen(53, "", NULL_KEY, "");
}
    }


listen(integer channel, string name, key id, string message)
    listen(integer channel, string name, key id, string message)
{
    {
list commands = ["leash", "unleash", "leashpost"];
        list commands = ["leash", "unleash", "leashpost"];
list responses = ["handle ok", "handle here", "handle gone", "post ok"];
        list responses = ["handle ok", "handle here", "handle gone", "post ok"];
key target;
        key target;
integer index;
        integer index;
integer len;
        integer len;


if (channel == 53 && hasAccess(id))
        if (channel == 53 && hasAccess(id))
{
        {
message = llStringTrim(llToLower(message), STRING_TRIM);
            message = llStringTrim(llToLower(message), STRING_TRIM);
index = -1;
            index = -1;
if (llGetSubString(message, 0, 0) == "*")
            if (llGetSubString(message, 0, 0) == "*")
{
            {
index = 1;
                index = 1;
} else {
            } else {
len = llStringLength(gPrefix);
                len = llStringLength(gPrefix);
if (llGetSubString(message, 0, len - 1) == gPrefix)
                if (llGetSubString(message, 0, len - 1) == gPrefix)
{
                {
index = len;
                    index = len;
}
                }
}
            }
if (~index)
            if (~index)
{
            {
index = llListFindList(commands, [llGetSubString(message, index, -1)]);
                index = llListFindList(commands, [llGetSubString(message, index, -1)]);
}
            }
if (~index)
            if (~index)
{
            {
gPending = NULL_KEY;
                gPending = NULL_KEY;
if (!index)
                if (!index)
{
                {
if (gLeashHolder == NULL_KEY)
                    if (gLeashHolder == NULL_KEY)
{
                    {
gLeashHolder = id;
                        gLeashHolder = id;
gCurrentTarget = id;
                        gCurrentTarget = id;
isLeashed = 1;
                        isLeashed = 1;
updateParticles();
                        updateParticles();
llSay(-8888, ((string) id) + "handle");
                        llSay(-8888, ((string) id) + "handle");
gPending = id;
                        gPending = id;
}
                    }
}
                }
if (gLeashHolder == NULL_KEY || gLeashHolder == id)
                if (gLeashHolder == NULL_KEY || gLeashHolder == id)
{
                {
if (index == 1)
                    if (index == 1)
{
                    {
gLeashHolder = NULL_KEY;
                        gLeashHolder = NULL_KEY;
isLeashed = 0;
                        isLeashed = 0;
llParticleSystem([]);
                        llParticleSystem([]);
}
                    }
if (index == 2)
                    if (index == 2)
{
                    {
if (gPost != NULL_KEY && gPost != gCurrentTarget && gPostToucher == id)
                        if (gPost != NULL_KEY && gPost != gCurrentTarget && gPostToucher == id)
{
                        {
llSay(-8888, ((string) gPost) + "handle");
                            llSay(-8888, ((string) gPost) + "handle");
gPending = gPost;
                            gPending = gPost;
}
                        }
}
                    }
}
                }
}
            }
}
        }


if (channel == -8888)
        if (channel == -8888)
{
        {
if (message == gCuffMessage)
            if (message == gCuffMessage)
{
            {
llSay(-8888, gCuffMessage + " ok"); // the basic response
                llSay(-8888, gCuffMessage + " ok");   // the basic response
return;
                return;
}
            }
target = (key) llGetSubString(message, 0, 35);
            target = (key) llGetSubString(message, 0, 35);
if (target)
            if (target)
{
            {
index = llListFindList(responses, [llGetSubString(message, 36, -1)]);
                index = llListFindList(responses, [llGetSubString(message, 36, -1)]);
if (~index)
                if (~index)
{
                {
if (!index && target == gPending)
                    if (!index && target == gPending)
{
                    {
gCurrentTarget = id;
                        gCurrentTarget = id;
isLeashed = 1;
                        isLeashed = 1;
if (id == target)
                        if (id == target)
{
                        {
gLeashHolder = NULL_KEY;
                            gLeashHolder = NULL_KEY;
}
                        }
gPending = NULL_KEY;
                        gPending = NULL_KEY;
updateParticles();
                        updateParticles();
}
                    }
if (target == gLeashHolder)
                    if (target == gLeashHolder)
{
                    {
if (index == 1 && gCurrentTarget != id)
                        if (index == 1 && gCurrentTarget != id)
{
                        {
gCurrentTarget = id;
                            gCurrentTarget = id;
isLeashed = 1;
                            isLeashed = 1;
gPending = NULL_KEY;
                            gPending = NULL_KEY;
updateParticles();
                            updateParticles();
}
                        }
if (index == 2 && gCurrentTarget == id)
                        if (index == 2 && gCurrentTarget == id)
{
                        {
releash();
                            releash();
}
                        }
}
                    }
if (index == 3)
                    if (index == 3)
{
                    {
if (target == gLeashHolder || (gLeashHolder == NULL_KEY && hasAccess(target)))
                        if (target == gLeashHolder || (gLeashHolder == NULL_KEY && hasAccess(target)))
{
                        {
gPostToucher = target;
                            gPostToucher = target;
gPost = id;
                            gPost = id;
if (gLeashHolder != NULL_KEY && gPost != gCurrentTarget)
                            if (gPost != gCurrentTarget)
{
                            {
gLeashHolder = NULL_KEY;
                                if (gLeashHolder != NULL_KEY)
gCurrentTarget = gPost;
                                {
isLeashed = 1;
                                    gLeashHolder = NULL_KEY;
gPending = NULL_KEY;
                                    gCurrentTarget = gPost;
updateParticles();
                                    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;


attach(key id)
        message = " gone";
{
        if (id)
string message;
        {
            gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
            message = " here";
            if (isLeashed)
            {
                releash();
            }
        }
        llSay(-8888, gCuffMessage + message);    // send the "here" and "gone" message
    }


message = " gone";
    sensor(integer total_number)
if (id)
    {
{
        gLeashHolder = llDetectedKey(0);
gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
        gCurrentTarget = gLeashHolder;
message = " here";
        isLeashed = 1;
if (isLeashed)
        updateParticles();
{
        llSay(-8888, ((string) gLeashHolder) + "handle");
releash();
        gPending = gLeashHolder;
}
    }
}
llSay(-8888, gCuffMessage + message); // send the "here" and "gone" message
}


sensor(integer total_number)
    on_rez(integer start_param)
{
    {
gLeashHolder = llDetectedKey(0);
        setPrefix();
gCurrentTarget = gLeashHolder;
    }
isLeashed = 1;
updateParticles();
llSay(-8888, ((string) gLeashHolder) + "handle");
gPending = gLeashHolder;
}
 
on_rez(integer start_param)
{
setPrefix();
        }
}
}
</lsl>
</lsl>
[[Category:LockMeister]]

Latest revision as of 12:33, 16 June 2011

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>