Hi Void, and others.
I've been worrying at this llMessageLinked thing for a good while now but don't seem to be getting my head round it and would very much appreciate some help.
I've been trying to dissect the timeless door script which has touchstart and voice control, and also appears to have messagelinked control for a remote control but I'm way out of my comprehension comfort zone, and can't work out how to mod the link_message component to act when the message is sent from the touched remote prim.
Apologies in advance for length of post - the door script is not short!
I started with Jopsy's Touch Toggle Controller in the prim which sends off/on message and understand the function of this. (For brevity, I've omitted some of Jopsy's comment text):
//// "Touch Toggle" CONTROLLER TEMPLATE v1 - by Jopsy Pendragon - 4/8/2008
//// You are free to use this script as you please, so long as you include this line:
//** The original 'free' version of this script came from THE PARTICLE LABORATORY. **//
// EFFECT: 'Touching' this prim will ACTIVATE or DEACTIVE particles.
// SETUP: Drop this CONTROLLER TEMPLATE script into any prim of the same
// linked object as your PARTICLE TEMPLATE. It should be responsive immediately.
integer PLAY_SOUND = TRUE; // TRUE for a click-sound, FALSE for silent.
string SOUND = "bac3e333-9624-4b1a-ade2-d2b01d5960aa"; // a click sound
string CONTROLLER_ID = "B"; // see more about CONTROL TEMPLATES at end.
integer mode = 0; // keep track of whether particles are ON(1) or OFF(0).
default {
touch_start(integer total_number) {
if ( PLAY_SOUND ) llPlaySound( SOUND, 0.5 );
mode = ! mode; // flip on to off, (or off to on).
llMessageLinked( LINK_SET, mode, CONTROLLER_ID, NULL_KEY ); // send command
}
// Listen for other controllers sending ON/OFF commands and remember changes:
link_message( integer sibling, integer num, string controller_id, key ignore ) {
if ( controller_id != CONTROLLER_ID ) return; // this message is not for us.
mode = num;
}
}
The door will need to have the matching link_message received and acted on, and this is where I lose it. I pulled what I think to be the relevant bit from another of Jopsy's particle scripts on the basis that I could apply the on/off toggle effect to the required open/close action by changing the llParticleSystem line to something else:
link_message( integer sibling, integer num, string mesg, key target_key ) {
if ( mesg != CONTROLLER_ID ) { // this message isn't for me. Bail out.
return;
} else if ( num == 0 ) { // Message says to turn particles OFF:
llParticleSystem( [ ] );
} else if ( num == 1 ) { // Message says to turn particles ON:
llParticleSystem( particle_parameters + target_parameters );
} else if ( num == 2 ) { // Turn on, and remember and use the key sent us as a target:
target_parameters = [ PSYS_SRC_TARGET_KEY, target_key ];
llParticleSystem( particle_parameters + target_parameters );
} else { // bad instruction number
// do nothing.
}
}
I've looked through the door script what seems like countless times now to try and work out where/how to mod it and insert the link-message control. Looking at the touch-start portion, I think it's got something to do with myToggleDoor but am stumped - I obviously haven't mastered anything other than the absolute basics!
Any assistance would be welcomed. I'm happy to talk in-world if that's easier than megalength posts
I've attached an abbreviated copy of the door script below.
Thanks
Carbon
string doorOpenSound = "cb340647-9680-dd5e-49c0-86edfa01b3ac";
string doorCloseSound = "e7ff1054-003d-d134-66be-207573f2b535";
string confirmedSound = "69743cb2-e509-ed4d-4e52-e697dc13d7ac";
string accessDeniedSound = "58da0f9f-42e5-8a8f-ee51-4fac6c247c98";
string doorBellSound = "ee871042-e272-d8ec-3d40-0b0cb3371346"; // Setting to empty stops door announcements too.
float autoCloseTime = 120.0; // 0 seconds to disable auto close.
integer allowGroupToo = TRUE; // Set to FALSE to disallow same group access to door.
list allowedAgentUUIDs = ["8efecbac-35de-4f40-89c1-2c772b83cafa"]; // Comma-separated, quoted list of avatar UUIDs who are allowed access to this door.
integer listenChannel = 0;
string CONTROLLER_ID = "B"; // See comments at end regarding CONTROLLERS.
integer AUTO_START = FALSE; // Optionally FALSE only if using CONTROLLERS.
//------------------------------------------------------
// Leave the rest of the settings alone, these are
// handled by the script itself.
//------------------------------------------------------
integer isLocked = FALSE; // Only when the door is locked do the permissions apply.
integer isOpen = TRUE;
vector openPos = ZERO_VECTOR;
rotation openRot = ZERO_ROTATION;
vector openScale = ZERO_VECTOR;
vector closedPos = ZERO_VECTOR;
rotation closedRot = ZERO_ROTATION;
vector closedScale = ZERO_VECTOR;
key openerKey = NULL_KEY;
key closerKey = NULL_KEY;
integer isSetup = FALSE;
integer listenHandle = 0;
string avatarName = "";
string action;
list target_parameters=[]; // remembers targets found using TARGET TEMPLATE scripts.
integer mode = 0; // keep track of whether particles are ON(1) or OFF(0).
// code string used for the parameter encoding/decoding
string code68 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX YZ0123456789@$#&!?";
mySayName(integer channel, string objectName, string message)
{
string name = llGetObjectName();
llSetObjectName(objectName);
llSay(0, "/me " + message);
llSetObjectName(name);
}
mySay(integer channel, string message)
{
string name = llGetObjectName();
llSetObjectName("Door"

;
llSay(0, message);
llSetObjectName(name);
}
myOwnerSay(string message)
{
string name = llGetObjectName();
llSetObjectName("Door"

;
llOwnerSay(message);
llSetObjectName(name);
}
mySoundConfirmed()
{
if (confirmedSound != ""

{
llTriggerSound(confirmedSound, 1.0);
}
}
mySoundAccessDenied()
{
if (accessDeniedSound != ""

{
llTriggerSound(accessDeniedSound, 1.0);
}
}
myGetDoorParams()
{
isSetup = FALSE;
if (llSubStringIndex(llGetObjectDesc(), "door:"

== 0)
{
string s = llGetObjectDesc();
integer k = 5;
openPos.x = decode_float( llGetSubString(s,k,k+4) ); k += 5;
etc. etc. etc.....................
.............
closedScale.z = decode_float( llGetSubString(s,k,k+4) ); k += 5;
isSetup = TRUE;
}
else
{
myOwnerSay("The door prim's description is empty of has invalid syntax. Delete the door prim's description and setup the door prim again."

;
}
}
mySetDoorParams(vector openPos, rotation openRot, vector openScale, vector closedPos, rotation closedRot, vector closedScale)
{
string s = "door:";
s += encode_float(openPos.x);
etc. etc etc..............................
..............................................
s += encode_float(closedScale.z);
llSetObjectDesc(s);
isSetup = TRUE;
mySay(0,"Parameters are stored"

;
}
integer myPermissionCheck(key id)
{
integer hasPermission = FALSE;
if (isLocked == FALSE)
{
hasPermission = TRUE;
}
else if (llGetOwnerKey(id) == llGetOwner())
{
hasPermission = TRUE;
}
else if (allowGroupToo == TRUE && llSameGroup(id))
{
hasPermission = TRUE;
}
else if (llListFindList(allowedAgentUUIDs, [(string)id]) != -1)
{
hasPermission = TRUE;
}
return hasPermission;
}
myOpenDoor()
{
isOpen = FALSE;
myToggleDoor();
}
myCloseDoor()
{
isOpen = TRUE;
myToggleDoor();
}
myToggleDoor()
{
if (isSetup == FALSE)
{
myOwnerSay("The door prim has not been configured yet. Please read the usage instructions in the door script."

;
}
else if (llGetLinkNumber() == 0 || llGetLinkNumber() == 1)
{
myOwnerSay("The door prim must be linked to at least one other prim and the door prim must not be the root prim"

;
}
else
{
isOpen = !isOpen;
if (isOpen)
{
if (doorBellSound != ""

{
llTriggerSound(doorBellSound, 1.0);
if (avatarName != ""

{
mySayName(0, avatarName, "is at the door."

;
avatarName = "";
}
}
if (doorOpenSound != ""

{
llTriggerSound(doorOpenSound, 1.0);
}
llSetPrimitiveParams([ PRIM_POSITION, openPos, PRIM_ROTATION, ZERO_ROTATION * openRot / llGetRootRotation(), PRIM_SIZE, openScale ]);
// Door API.
llMessageLinked(LINK_SET, 255, "cmd|door|opened", NULL_KEY);
}
else
{
if (doorCloseSound != ""

{
llTriggerSound(doorCloseSound, 1.0);
}
llSetPrimitiveParams([ PRIM_POSITION, closedPos, PRIM_ROTATION, ZERO_ROTATION * closedRot / llGetRootRotation(), PRIM_SIZE, closedScale ]);
// Door API.
llMessageLinked(LINK_SET, 255, "cmd|door|closed", NULL_KEY);
}
llSetTimerEvent(0.0);
if (isOpen == TRUE && autoCloseTime != 0.0)
{
llSetTimerEvent(autoCloseTime);
}
}
}
//================================================== ========================
// encode a float with 7 digits precision into a 5-character string
// minimum=1e-31, maximum=1e+31
// example: 1.234567 --> "hAM70"
//================================================== ========================
.........................................omitted for brevity
//================================================== ========================
// decode a 5-character string into a float with 7 digits precision
// example: "hAM70" --> 1.234567
//================================================== ========================
...........................................omitted for brevity
default
{
state_entry()
{
listenHandle = llListen(listenChannel, "", NULL_KEY, ""

;
myGetDoorParams();
}
touch_start(integer total_number)
{
if (myPermissionCheck(llDetectedKey(0)) == TRUE)
{
avatarName = llDetectedName(0);
myToggleDoor();
}
else
{
mySoundAccessDenied();
}
}
timer()
{
myCloseDoor();
}
//link_message(integer sender_num, integer num, string str, key id)
//{
// Door API. The API is here in case you want to create PIN entry keypads or whatever.
//if (num == llGetLinkNumber())
//{
//if (str == "cmd|door|doOpen"

//{
//myOpenDoor();
//}
//else if (str == "cmd|door|doClose"

//{
//myCloseDoor();
//}
//}
//if (str == "cmd|door|discover"

//{
//llMessageLinked(LINK_SET, 255, "cmd|door|discovered|" + (string)llGetKey(), id);
//}
//}
listen(integer channel, string name, key id, string message)
{
// Performance note: it's quicker to compare the strings than to compare
// permissions each time anyone says anything on this channel.
if (message == "open"

{
if (myPermissionCheck(id) == TRUE)
{
// Only open the door if the person is quite close to this door.
openerKey = id;
closerKey = NULL_KEY;
avatarName = name;
llSensor(name, id, AGENT, 5.0, TWO_PI);
}
else
{
mySoundAccessDenied();
}
}
else if (message == "close"

{
if (myPermissionCheck(id) == TRUE)
{
openerKey = NULL_KEY;
closerKey = id;
avatarName = name;
// Only close the door if the person is quite close to this door.
llSensor(name, id, AGENT, 5.0, TWO_PI);
}
else
{
mySoundAccessDenied();
}
}
else if (message == "lock"

{
if (myPermissionCheck(id) == TRUE)
{
isLocked = TRUE;
mySoundConfirmed();
}
else
{
mySoundAccessDenied();
}
}
else if (message == "unlock"

{
if (myPermissionCheck(id) == TRUE)
{
isLocked = FALSE;
mySoundConfirmed();
}
else
{
mySoundAccessDenied();
}
}
else if (message == "/door opened" && llSubStringIndex(llGetObjectDesc(), "door:"

== -1)
{
if (llGetOwnerKey(id) == llGetOwner())
{
mySoundConfirmed();
openPos = llGetLocalPos();
openRot = llGetLocalRot();
openScale = llGetScale();
isOpen = TRUE;
if (! (closedPos == ZERO_VECTOR && closedRot == ZERO_ROTATION && closedScale == ZERO_VECTOR))
{
mySetDoorParams(openPos, openRot, openScale, closedPos, closedRot, closedScale);
}
}
else
{
mySoundAccessDenied();
}
}
else if (message == "/door closed" && llSubStringIndex(llGetObjectDesc(), "door:"

== -1)
{
if (llGetOwnerKey(id) == llGetOwner())
{
mySoundConfirmed();
closedPos = llGetLocalPos();
closedRot = llGetLocalRot();
closedScale = llGetScale();
isOpen = FALSE;
if (! (openPos == ZERO_VECTOR && openRot == ZERO_ROTATION && openScale == ZERO_VECTOR))
{
mySetDoorParams(openPos, openRot, openScale, closedPos, closedRot, closedScale);
}
}
else
{
mySoundAccessDenied();
}
}
}
sensor(integer num_detected)
{
if (openerKey != NULL_KEY)
{
integer i;
for (i = 0; i < num_detected; i++)
{
if (llDetectedKey(i) == openerKey && myPermissionCheck(llDetectedKey(i)) == TRUE)
{
myOpenDoor();
}
}
openerKey = NULL_KEY;
}
else
{
integer i;
for (i = 0; i < num_detected; i++)
{
if (llDetectedKey(i) == closerKey && myPermissionCheck(llDetectedKey(i)) == TRUE)
{
myCloseDoor();
}
}
closerKey = NULL_KEY;
}
}