Don't click here unless you want to be banned.

LSL Wiki : LibraryTimelessLinkedDoor

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl338.us.archive.org

Timeless Linked Door


Conversational name: linked door.
Discussion thread in forums: http://forums.secondlife.com/showthread.php?t=102699

The Timeless Linked Door is a full-featured door script developed for ease of use by builders and users alike.

Simplest usage for builders:
1. Copy and paste this script into the door prim and link it to the other prims (of a house for example).
2. When the door is in the closed position say '/door closed' to record it.
3. When the door is in the open position say '/door opened' to record it.
The door is now ready for use.

More advanced features can be explored by reading the usage instructions at the top of the script.

The Timeless Linked Door script also has an API for advanced scripted to communicate with it.

I DO NOT support this script so please don't ask me about it.

This script is free to use, but the intellectual property is still mine. You may not sell Timeless Linked Door script unless it is part of your pre-fabricated product (eg. house with a door). If you are making a raging profit, please show your financial appreciation by donating to TimelessPrototype in SL.

NOTE: As of Jan 31, 2008 all object names are truncated to 63 characters. (as per Jira SVC-674). This means there was no longer enough room in the object name to save the door configuration unpacked. It now removes extra characters from the values stored and converts the rotations to Euler representations. If an object is being updated with this newer version of the script the /door opened and /door closed configuration will have to be redone (not a big deal since the values will be truncated and it will break anyway if you do anything to reset the script).

Here is the script to place in the door prim:
//------------------------------------------------------
// Timeless Linked Door Script by Timeless Prototype
//------------------------------------------------------
// 2008-08-23 Ibrew Meads
// Minor changes to configuration storage.
//------------------------------------------------------
// The latest version of this script can always be found
// in the Library section of the wiki:
// http://www.secondlife.com/badgeo/
// This script is free to use, but whereever it is used
// the SCRIPT's permissions MUST be set to:
// [x] Next owner can modify
// [x] Next owner can copy
// [x] Next owner can transfer
// [x] Allow anyone to copy
// [x] Share with group

//------------------------------------------------------
// USAGE INSTRUCTIONS FOR EVERYDAY USE:
//------------------------------------------------------
// Say the following commands on channel 0:
// 'unlock'     - Unlocks all doors in range.
// 'lock'       - Locks all doors in range and allows
//                only the permitted users to open it.
// To open the door, either Touch it, Walk into it or
// say 'open' or say 'close'.

//------------------------------------------------------
// USAGE INSTRUCTIONS FOR BUILDERS:
//------------------------------------------------------
// 1. Copy and paste this script into the door prim and
//    change the settings (see further down).
// 2. The door prim must be linked to at least one other
//    prim (could be linked to the house for example).
// 3. The door prim MUST NOT be the root prim.
// 4. Use Edit Linked Parts to move, rotate and size the
//    door prim for the closed state.
// 5. When ready, stand close to the door and say
//    '/door closed' (this records the closed door
//    position, rotation and size to the object's
//    name and description).
// 6. Use the Edit Linked parts to move, rotate and size
//    the door prim for the opened state.
// 7. When ready, stand close to the door and say
//    '/door opened' (this records the opened door
//    position, rotation and size).
// 8. Once recorded it will not accept these commands
//    again. If you do need to redo the settings then
//    delete the Name and Description of the door prim
//    (these are where the position information is
//    stored), and then follow the steps above again.
//    Note: deleting the object name won't save, so set
//    the object name to 'Object' to reset the object
//    name.

//------------------------------------------------------
// Change these settings to suit your needs.
//------------------------------------------------------
// To mute any/all of the sounds set the sound string(s)
// to "" (empty string).
// To get the UUID of a sound, right click on the sound
// in your inventory and choose "Copy Asset UUID", then
// paste the UUID in here.
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      doorName            = "Door";  // How this door will identify itself when speaking on chat

//------------------------------------------------------
// 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          = "";

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(doorName);
    llSay(0, message);
    llSetObjectName(name);
}

myOwnerSay(string message)
{
    string name = llGetObjectName();
    llSetObjectName(doorName);
    llOwnerSay(message);
    llSetObjectName(name);
}

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

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

string mySubStr(string data, list drop, string replace)
{
    list listdata = llParseString2List(data,drop,[]);
    return llDumpList2String(listdata,replace);
}

string myDropWS(string data)
{
    data = mySubStr(data,[" ","<",">"],""); // get rid of spaces and vector/rotation delimiters
    data = mySubStr(data,["-0."],"-.");     // no leading zeros
    data = mySubStr(data,[",0."],",.");
    data = mySubStr(data,[";0."],";.");
    return data;
}

vector myGetVector(list listdata, integer loc)
{
    return (vector)("<"+(string)llList2String(listdata,loc)+">");
}

rotation myGetRot(list listdata, integer loc)
{
    return llEuler2Rot(myGetVector(listdata,loc));
}

myGetDoorParams()
{
    isSetup = FALSE;
    if (llSubStringIndex(llGetObjectDesc(), "dr;") == 0 && llSubStringIndex(llGetObjectName(), "dr;") == 0)
    {
        list nameWords = llParseString2List(llGetObjectName(), [";"], []);
        list descWords = llParseString2List(llGetObjectDesc(), [";"], []);
        if (llGetListLength(nameWords) != 3 || llGetListLength(descWords) != 5)
        {
            myOwnerSay("The "+doorName+" prim's name and/or description has invalid syntax and/or number of parameters. Delete the "+doorName+" prim's name and description and setup the door "+doorName+" again.");
        }
        else
        {
            openPos = myGetVector(nameWords, 1);
            closedPos = myGetVector(nameWords, 2);

            openRot = myGetRot(descWords, 1);
            closedRot = myGetRot(descWords, 2);
            openScale = myGetVector(descWords, 3);
            closedScale = myGetVector(descWords, 4);
            isSetup = TRUE;
        }
    }
}

mySetDoorParams(vector openPos, rotation openRot, vector openScale, vector closedPos, rotation closedRot, vector closedScale)
{
    llSetObjectName(myDropWS("dr;" +
        (string)openPos + ";" +
        (string)closedPos));
    llSetObjectDesc(myDropWS("dr;" +
        (string)llRot2Euler(openRot) + ";" +
        (string)llRot2Euler(closedRot) + ";" +
        (string)openScale + ";" +
        (string)closedScale));
    isSetup = TRUE;
}

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 "+doorName+" prim has not been configured yet. Please read the usage instructions in the "+doorName+" script.");
    }
    else if (llGetLinkNumber() == 0 || llGetLinkNumber() == 1)
    {
        myOwnerSay("The "+doorName+" prim must be linked to at least one other prim and the "+doorName+" 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 "+doorName+".");
                    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);
        }
    }
}

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(llGetObjectName(), "dr;") == -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(), "dr;") == -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;
        }
    }

//------------------------------------------------------
// Uncomment the following code if you particularly want
// collisions to affect the door state.    
//------------------------------------------------------

//    collision_start(integer num_detected)
//    {
//        integer i;
//        for (i = 0; i < num_detected; i++)
//        {
//            if (myPermissionCheck(llDetectedKey(i)) == TRUE)
//            {
//                avatarName = llDetectedName(i);
//                myOpenDoor();
//            }
//            else if (llDetectedType(i) & AGENT)
//            {
//                mySoundAccessDenied();
//            }
//        }
//    }

} // End of default state and end of script.
There is no comment on this page. [Display comments/form]