Difference between revisions of "One Script, many doors"

From Second Life Wiki
Jump to navigation Jump to search
(corrected again the mask from 1FFF to FFF)
 
(11 intermediate revisions by 5 users not shown)
Line 1: Line 1:
This script is my attempt at solving the massive amount of simple door scripts one can have in a sim (i removed about 110 door scripts in my sim using this system)
This script is my attempt at solving the massive amount of simple door scripts one can have in a sim (I removed about 110 door scripts in my sim using this system)


It handle clockwise and counter clockwise door direction, a name based access control list, play sounds
It handles clockwise and counter clockwise door direction, a name-based access control list, play sounds, and the root prim reports memory free (useful for REALLY big door sets).


HOW TO USE IT
HOW TO USE IT
Line 8: Line 8:
All your doors have to be one prim, typical cube with a path cut of 0.125 0.625 .
All your doors have to be one prim, typical cube with a path cut of 0.125 0.625 .


* All your doors must be linked to a root prim wich won't be a door.
* All your doors must be linked to a root prim which won't be a door.
* All the doors must be uniquely named
* All the doors must be uniquely named.
* All the doors must have "left" or "right" in their description depending of the direction you want them to swing to.
* All the doors must have "left" or "right" in their description depending on the direction you want them to swing to.


* In the root prim you will need 3 rezzable objects (simple cubes will do) named "open" , "close" and "lock" with, in them, the corresponding scripts (see at the bottom of the page) in order to play sounds at the right place.
* In the root prim you will need 3 rezzable objects (simple cubes will do) named "open" , "close" and "lock" with, in them, the corresponding scripts (see at the bottom of the page) in order to play sounds at the right place.
You should set them to phantom and TEMP ON REZ.


* You need a configuration notecard called "config"
* You need a configuration notecard called "config"
If you want to lock a door simply add the door name to the notecard followed by the list of avatars allowed to open it separated by commas, example:
My fancy door name=Kyrah Abattoir,John Doe,Mister X
Wich also means if you want to condemn a door you can simply enter something that isn't a valid avatar name like:
My fancy door name=locked


main door script: must be in the root prim of the door link set.
main door script: must be in the root prim of the door link set.
<lsl>
<source lang="lsl2">
/*******************************************
/*******************************************
Single script, linked, lockable, door system
Single script, linked, lockable, door system
Line 39: Line 32:
//This functions is from Nomad Padar, pretty awesome!
//This functions is from Nomad Padar, pretty awesome!
//encode from vector to integer
//encode from vector to integer
integer vec2int(vector v)  
integer vec2int(vector v)
{
{
     integer x = (integer)(v.x);
     integer x = (integer)(v.x);
Line 45: Line 38:
     integer z = (integer)(v.z);
     integer z = (integer)(v.z);
     integer out;
     integer out;
 
     //Rounds to 0, .5, or 1.0
     //Rounds to 0, .5, or 1.0
     float delta = v.x-x;
     float delta = v.x-x;
   
 
     if((delta>.25) && (delta<.75))  
     if((delta>.25) && (delta<.75))
    out += 0x10000000;
        out += 0x10000000;
     else if(delta>.75)  
     else if(delta>.75)
    out += 0x1;
        out += 0x1;
   
 
     delta = v.y-y;
     delta = v.y-y;
   
 
     if((delta>.25) && (delta<.75))  
     if((delta>.25) && (delta<.75))
    out += 0x20000000;
        out += 0x20000000;
     else if(delta>.75)  
     else if(delta>.75)
    out += 0x100;
        out += 0x100;
   
 
     delta = v.z-z;
     delta = v.z-z;
   
 
     if((delta>.25) && (delta<.75))  
     if((delta>.25) && (delta<.75))
    out += 0x40000000;
        out += 0x40000000;
     else if(delta>.75)  
     else if(delta>.75)
    out += 0x10000;
        out += 0x10000;
   
 
     out += x+(y<<8)+(z<<16);
     out += x+(y<<8)+(z<<16);
     return out;
     return out;
}
}


list door_names = [];//door list
list door_names         = [];//door list
list door_num = [];//corresponding link numbers
list door_num           = [];//corresponding link numbers
list door_closed_rot = [];//corresponding closed state rotation
list door_closed_rot   = [];//corresponding closed state rotation
list door_direction = [];//wich direction the door spin open
list door_direction     = [];//which direction the door spin open
list door_open = [];//is the door open?
list door_open         = [];//is the door open?
list door_open_time = [];//when was it open?
list door_open_time     = [];//when was it open?
list door_acl = [];//who can open the door (by user id)
list door_acl           = [];//who can open the door (by user id)
list door_pos = [];//the position of the door
list door_pos           = [];//the position of the door


list user_indexes = [];//list of users (user ids)
list user_indexes       = [];//list of users (user ids)


integer is_active = FALSE;//if this is false the script ignore touches
integer is_active = FALSE;//if this is false the script ignore touches
Line 87: Line 80:
recount_doors()
recount_doors()
{
{
//this function recount the doors and record all the different door characteristics
    //this function recount the doors and record all the different door characteristics
//only ran after script reset/when an object is linked/unlinked
    //only ran after script reset/when an object is linked/unlinked
is_active = FALSE;
    is_active = FALSE;
llSetText("recounting doors...",<1,1,1>,1.0);
    llSetText("recounting doors...",<1.0,1.0,1.0>,1.0);
integer prims = llGetNumberOfPrims();
    integer prims = llGetNumberOfPrims();
integer i;
for(i=2;i<=prims;i++)
{
key prim = llGetLinkKey(i);
list tmp = llGetObjectDetails(prim,[OBJECT_NAME,OBJECT_DESC,OBJECT_ROT,OBJECT_POS]);
string prim_name = llList2String(tmp,0);
string prim_descr = llList2String(tmp,1);
rotation prim_rot = (rotation)llList2String(tmp,2);
vector prim_pos = (vector)llList2String(tmp,3);


door_num += [i];
    integer i;
door_names += [prim_name];
    for(i=2;i<=prims;i++)
door_closed_rot += [prim_rot];
    {
door_open += [FALSE];
        key prim = llGetLinkKey(i);
door_open_time += [0];
        list tmp = llGetObjectDetails(prim,[OBJECT_NAME,OBJECT_DESC,OBJECT_ROT,OBJECT_POS]);
if(prim_descr == "right")
        string prim_name = llList2String(tmp,0);
door_direction += [TRUE];
        string prim_descr = llList2String(tmp,1);
else
        rotation prim_rot = (rotation)llList2String(tmp,2);
door_direction += [FALSE];
        vector prim_pos = (vector)llList2String(tmp,3);
door_acl += [""];
 
door_pos += [prim_pos];
        door_num += [i];
}
        door_names += [prim_name];
llSetText("...done!",<1,1,1>,1.0);
        door_closed_rot += [prim_rot];
reload_acl();
        door_open += [FALSE];
        door_open_time += [0];
        if(prim_descr == "right")
            door_direction += [TRUE];
        else
            door_direction += [FALSE];
        door_acl += [""];
        door_pos += [prim_pos];
    }
    llSetText("...done!",<1,1,1>,1.0);
    reload_acl();
}
}


Line 126: Line 119:
reload_acl()
reload_acl()
{
{
 
llSetText("reloading access controls...",<1,1,1>,1.0);
    llSetText("reloading access controls...",<1,1,1>,1.0);
is_active = FALSE;
    is_active = FALSE;
nLine = 0;
    nLine = 0;
//remove all acl
    //remove all acl
integer i;
    integer i;
for(i=0;i<llGetListLength(door_num);i++)
    for(i=0;i<llGetListLength(door_num);i++)
door_acl = llListReplaceList(door_acl,[""],i,i);
        door_acl = llListReplaceList(door_acl,[""],i,i);
 
user_indexes = [];
    user_indexes = [];
llGetNotecardLine(config,nLine);
    llGetNotecardLine(config,nLine);
}
}


Line 142: Line 135:
close(integer index)
close(integer index)
{
{
integer linknum = llList2Integer(door_num,index);
    integer linknum = llList2Integer(door_num,index);
 
rotation closed = llList2Rot(door_closed_rot,index);
    rotation closed = llList2Rot(door_closed_rot,index);
llSetLinkPrimitiveParams(linknum,[PRIM_ROTATION,closed]);
    llSetLinkPrimitiveParams(linknum,[PRIM_ROTATION,closed]);
 
door_open = llListReplaceList(door_open,[FALSE],index,index);  
    door_open = llListReplaceList(door_open,[FALSE],index,index);
}
}


//close a door (by index) using the stored rotation and adding or substracting 90 degrees  
//close a door (by index) using the stored rotation and adding or substracting 90 degrees
//on the Z world axis depending of the direction recorded for the door.
//on the Z world axis depending of the direction recorded for the door.
//also record it's opening time (unix timestamp)
//also record it's opening time (unix timestamp)
open(integer index)
open(integer index)
{
{
integer linknum = llList2Integer(door_num,index);
    integer linknum = llList2Integer(door_num,index);
rotation closed = llList2Rot(door_closed_rot,index);
    rotation closed = llList2Rot(door_closed_rot,index);
rotation open;
    rotation open;
if( llList2Integer(door_direction,index) )
    if( llList2Integer(door_direction,index) )
open = llEuler2Rot(llRot2Euler(closed)+ (<0,0,90> *DEG_TO_RAD));
        open = llEuler2Rot(llRot2Euler(closed)+ (<0,0,90> *DEG_TO_RAD));
else
    else
open = llEuler2Rot(llRot2Euler(closed)+ (<0,0,-90> *DEG_TO_RAD));  
        open = llEuler2Rot(llRot2Euler(closed)+ (<0,0,-90> *DEG_TO_RAD));
llSetLinkPrimitiveParams(linknum,[PRIM_ROTATION,open]);
    llSetLinkPrimitiveParams(linknum,[PRIM_ROTATION,open]);
 
door_open_time = llListReplaceList(door_open_time,[llGetUnixTime()],index,index);
    door_open_time = llListReplaceList(door_open_time,[llGetUnixTime()],index,index);
door_open = llListReplaceList(door_open,[TRUE],index,index);
    door_open = llListReplaceList(door_open,[TRUE],index,index);
 
llSetTimerEvent(1.0);
    llSetTimerEvent(1.0);
}
}


Line 173: Line 166:
play_open(vector pos)
play_open(vector pos)
{
{
llRezObject("open",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
    llRezObject("open",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
}
}
play_close(vector pos)
play_close(vector pos)
{
{
llRezObject("close",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
    llRezObject("close",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
}
}
play_lock(vector pos)
play_lock(vector pos)
{
{
llRezObject("lock",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
    llRezObject("lock",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
}
}


Line 189: Line 182:
     touch_start(integer total_number)
     touch_start(integer total_number)
     {
     {
    integer userid;
        integer userid;
   
 
    if(!is_active)
        if(!is_active)
    return;
            return;
   
 
    //considering we MAY receive more than one touch at the same time since  
        //considering we MAY receive more than one touch at the same time since
    //we can manage many doors.
        //we can manage many doors.
    for(userid=0;userid<total_number;userid++)
        for(userid=0;userid<total_number;userid++)
    {
        {
    integer door_id = llDetectedLinkNumber(userid);
            integer door_id = llDetectedLinkNumber(userid);
    string clicker_name = llDetectedName(userid);
            string clicker_name = llDetectedName(userid);
   
 
    integer door_index = llListFindList(door_num,[door_id]);
            integer door_index = llListFindList(door_num,[door_id]);
    if(door_index == -1)
            if(door_index == -1)
    return;//unknown door? do nothing
                return;//unknown door? do nothing
   
 
    integer is_open = llList2Integer(door_open,door_index);
            integer is_open = llList2Integer(door_open,door_index);
    vector door_vec = llList2Vector(door_pos,door_index);
            vector door_vec = llList2Vector(door_pos,door_index);
   
 
    //we do not accept touches that are further away from activation_distance
            //we do not accept touches that are further away from activation_distance
    if( llVecDist(door_vec,llDetectedPos(userid) )> activation_distance )
            if( llVecDist(door_vec,llDetectedPos(userid) )> activation_distance )
    llInstantMessage(llDetectedKey(userid),"You can't use this from this distance.");
                llInstantMessage(llDetectedKey(userid),"You can't use this from this distance.");
  else
            else
    {
            {
    if(is_open)
                if(is_open)
    { //if the door is open, simply play sound and close it.
                {   //if the door is open, simply play sound and close it.
    play_close(door_vec);
                    play_close(door_vec);
    close(door_index);
                    close(door_index);
    }
                }
    else
                else
    {
                {
    string acl_string = llList2String(door_acl,door_index);
                    string acl_string = llList2String(door_acl,door_index);
   
 
    //if the acl string is empty for this door we simply open it
                    //if the acl string is empty for this door we simply open it
    if(acl_string == "") //no specific locking
                    if(acl_string == "") //no specific locking
    {
                    {
    play_open(door_vec);
                        play_open(door_vec);
    open(door_index);
                        open(door_index);
    }
                    }
    else
                    else
    {
                    {
    //otherwise we lookup if the userid that correspond to the person who touched
                        //otherwise we lookup if the userid that correspond to the person who touched
    //the door match any of the ones in the ACL string
                        //the door match any of the ones in the ACL string
    integer user_index = llListFindList(user_indexes,[clicker_name]);
                        integer user_index = llListFindList(user_indexes,[clicker_name]);
   
 
    if(user_index == -1)//we don't even know this user? sure as hell there is no acl about him
                        if(user_index == -1) //we don't even know this user? sure as hell there is no acl about him
    play_lock(door_vec);
                            play_lock(door_vec);
    else
                        else
    {
                        {
    list acl_list =  llParseString2List(acl_string,[","],[]);
                            list acl_list =  llParseString2List(acl_string,[","],[]);
   
 
    if(llListFindList(acl_list,[(string)user_index]) != -1)
                            if(llListFindList(acl_list,[(string)user_index]) != -1)
    {
                            {
    play_open(door_vec);
                                play_open(door_vec);
    open(door_index);
                                open(door_index);
    }
                            }
    else
                            else
    play_lock(door_vec);
                                play_lock(door_vec);
    }
                        }
    }
                    }
    }
                }
    }
            }
    }
        }
     }
     }
     dataserver(key id,string data)
     dataserver(key id,string data)
     {
     {
    //notecard reading stuff
        //notecard reading stuff
    if(data != EOF)
        if(data != EOF)
    {
        {
    if(data != "" && data != " " && llGetSubString(data,0,1) != "//")
            if(data != "" && data != " " && llGetSubString(data,0,1) != "//")
    {
            {
    list command_and_data = llParseString2List(data,["="],[]);
                list command_and_data = llParseString2List(data,["="],[]);
    string door_name = llList2String(command_and_data,0);
                string door_name = llList2String(command_and_data,0);
    string user_names_string = llList2String(command_and_data,1);
                string user_names_string = llList2String(command_and_data,1);
   
 
    integer index = llListFindList(door_names,[door_name]);
                integer index = llListFindList(door_names,[door_name]);
    if(index != -1)
                if(index != -1)
    {
                {
    list user_names_list = llParseString2List(user_names_string,[","],[]);
                    list user_names_list = llParseString2List(user_names_string,[","],[]);
    integer j;
                    integer j;
   
 
    list pre_acl_list;
                    list pre_acl_list;
    for(j=0;j<llGetListLength(user_names_list);j++)
                    for(j=0;j<llGetListLength(user_names_list);j++)
    {
                    {
    string user_name = llList2String(user_names_list,j);
                        string user_name = llList2String(user_names_list,j);
    integer index2 = llListFindList(user_indexes,[user_name]);
                        integer index2 = llListFindList(user_indexes,[user_name]);
    if( index2 == -1)
                        if( index2 == -1)
    {
                        {
    pre_acl_list += llGetListLength(user_indexes);
                            pre_acl_list += llGetListLength(user_indexes);
    user_indexes += [user_name];
                            user_indexes += [user_name];
    }
                        }
    else
                        else
    pre_acl_list += [index2];
                            pre_acl_list += [index2];
   
 
    }
                    }
    string pre_acl_string = llDumpList2String(pre_acl_list,",");
                    string pre_acl_string = llDumpList2String(pre_acl_list,",");
    door_acl = llListReplaceList(door_acl,[pre_acl_string],index,index);
                    door_acl = llListReplaceList(door_acl,[pre_acl_string],index,index);
    }
                }
    }
            }
    nLine++;
            nLine++;
    llGetNotecardLine(config,nLine);
            llGetNotecardLine(config,nLine);
    }
        }
    else
        else
    {
        {
    is_active = TRUE;
            is_active = TRUE;
    llOwnerSay("config reloaded");
            llOwnerSay("config reloaded");
    llSetText((string)llGetFreeMemory()+"bits free",<.5,.5,.5>,.5);
            llSetText((string)llGetFreeMemory()+"bits free",<.5,.5,.5>,.5);
    }
        }
     }
     }
     state_entry()
     state_entry()
     {
     {
    recount_doors();
        recount_doors();
     }
     }
     changed(integer change)
     changed(integer change)
     {
     {
    //if we detect an inventory change we reread the notecard
        //if we detect an inventory change we reread the notecard
    //if we detect a linkchange we reset the script and recount doors first
        //if we detect a linkchange we reset the script and recount doors first
    if( (change & CHANGED_INVENTORY) == CHANGED_INVENTORY)
        if( (change & CHANGED_INVENTORY) == CHANGED_INVENTORY)
    reload_acl();
            reload_acl();
    if( (change & CHANGED_LINK) == CHANGED_LINK)
        if( (change & CHANGED_LINK) == CHANGED_LINK)
    llResetScript();
            llResetScript();
     }
     }
     timer()
     timer()
     {
     {
    //timer will run once a second as long as at least one door is open.
        //timer will run once a second as long as at least one door is open.
    if(llListFindList(door_open,[TRUE]) == -1)
        if(llListFindList(door_open,[TRUE]) == -1)
    {
        {
    llSetTimerEvent(0.0);
            llSetTimerEvent(0.0);
    return;
            return;
    }
        }
    integer i;
        integer i;
   
 
    //each run of the timer we loop through the timestamps to check if one of them is too old
        //each run of the timer we loop through the timestamps to check if one of them is too old
    //(wich means we can force close the assossiated door
        //(which means we can force close the associated door
    for(i=0;i<llGetListLength(door_open_time);i++)
        for(i=0;i<llGetListLength(door_open_time);i++)
    {
        {
    integer is_open = llList2Integer(door_open,i);
            integer is_open = llList2Integer(door_open,i);
    integer time = llList2Integer(door_open_time,i);
            integer time = llList2Integer(door_open_time,i);
    if( is_open && ((time + autoclose_time) <  llGetUnixTime()))
            if( is_open && ((time + autoclose_time) <  llGetUnixTime()))
    {
            {
    vector door_vec = llList2Vector(door_pos,i);
                vector door_vec = llList2Vector(door_pos,i);
    llRezObject("close",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(door_vec));
                llRezObject("close",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(door_vec));
    close(i);
                close(i);
    }
            }
    }
        }
     }
     }
}
}
</lsl>
</source>


Sound emitter script
Sound emitter script
Line 342: Line 335:
You need this script in the 3 rezzable objects "open" "close" and "lock" in order to play your door sounds at the right place (At the time i wrote this , lsl doesn't allow yet to play sounds from an unscripted prim in a link set)
You need this script in the 3 rezzable objects "open" "close" and "lock" in order to play your door sounds at the right place (At the time i wrote this , lsl doesn't allow yet to play sounds from an unscripted prim in a link set)


<lsl>
<source lang="lsl2">
string sound_to_play = "my door sound";// put your sound name/key here
string sound_to_play = "my door sound";// put your sound name/key here


//This functions is from Nomad Padar, pretty awesome!
//This functions is from Nomad Padar, pretty awesome!
//decode from integer to vector
//decode from integer to vector
vector int2vec(integer n)  
vector int2vec(integer n)
{
{
     //0zyx ZZZZ ZZZZ ZZZZ YYYY YYYY XXXX XXXX
     //0zyx ZZZZ ZZZZ ZZZZ YYYY YYYY XXXX XXXX
     return <n&0xFF, (n>>8)&0xFF, ((n>>16)&0xFF)> + <((n&0x10000000)!=0)*.5,((n&0x20000000)!=0)*.5,((n&0x40000000)!=0)*.5>;
     return <n&0xFF, (n>>8)&0xFF, ((n>>16)&0xFFF)> + <((n&0x10000000)!=0)*.5,((n&0x20000000)!=0)*.5,((n&0x40000000)!=0)*.5>;
}
}


default  
default
{
{
     state_entry()
     state_entry()
Line 359: Line 352:
         llSetStatus(STATUS_PHANTOM, TRUE);
         llSetStatus(STATUS_PHANTOM, TRUE);
         llSetPrimitiveParams([PRIM_TEMP_ON_REZ, TRUE]);
         llSetPrimitiveParams([PRIM_TEMP_ON_REZ, TRUE]);
        llSetTexture(TEXTURE_TRANSPARENT,ALL_SIDES);
     }
     }
     on_rez(integer a)
     on_rez(integer a)
     {
     {
    if(a == 0)
        if(a == 0)
    return;
            return;
   
 
    vector destination = int2vec(a);
        vector destination = int2vec(a);
   
 
    integer i;
        integer i;
    for(i=0 ; i<50 && (llGetPos() != destination) ; i++)
        for(i=0 ; i<50 && (llGetPos() != destination) ; i++)
    llSetPos(destination);
            llSetLinkPrimitiveParamsFast(0, [PRIM_POSITION, destination]);
   
 
    if(llGetPos() == destination)
        if(llGetPos() == destination)
    llTriggerSound(sound_to_play,1.0);
            llTriggerSound(sound_to_play,1.0);
    llDie();
        llDie();
     }
     }
}
}
</lsl>
</source>
Example "config" notecard:
//lines starting with "//" are ignored
//Syntax: one line per door in the format door_name=user name,user name
 
My fancy front door=Kyrah Abattoir
My secret playroom door=Kyrah Abattoir,Timeless Prototype
 
//of course if you want to lock a door from anybody you can set it to something like this:
 
Mine entrance=condemned until further notice
--[[User:Kyrah Abattoir|Kyrah Abattoir]] 18:46, 7 March 2010 (UTC)
--[[User:Kyrah Abattoir|Kyrah Abattoir]] 18:46, 7 March 2010 (UTC)

Latest revision as of 09:25, 28 September 2015

This script is my attempt at solving the massive amount of simple door scripts one can have in a sim (I removed about 110 door scripts in my sim using this system)

It handles clockwise and counter clockwise door direction, a name-based access control list, play sounds, and the root prim reports memory free (useful for REALLY big door sets).

HOW TO USE IT


All your doors have to be one prim, typical cube with a path cut of 0.125 0.625 .

  • All your doors must be linked to a root prim which won't be a door.
  • All the doors must be uniquely named.
  • All the doors must have "left" or "right" in their description depending on the direction you want them to swing to.
  • In the root prim you will need 3 rezzable objects (simple cubes will do) named "open" , "close" and "lock" with, in them, the corresponding scripts (see at the bottom of the page) in order to play sounds at the right place.
  • You need a configuration notecard called "config"

main door script: must be in the root prim of the door link set.

/*******************************************
Single script, linked, lockable, door system
by Kyrah Abattoir

allow you to control many doors from a single
core script, complete with sound projectors
and name based access control!
*******************************************/

float autoclose_time = 30.0;//define how long the script will wait before closing a door.
float activation_distance = 2.0;//define how long the script will wait before closing a door.

//This functions is from Nomad Padar, pretty awesome!
//encode from vector to integer
integer vec2int(vector v)
{
    integer x = (integer)(v.x);
    integer y = (integer)(v.y);
    integer z = (integer)(v.z);
    integer out;

    //Rounds to 0, .5, or 1.0
    float delta = v.x-x;

    if((delta>.25) && (delta<.75))
        out += 0x10000000;
    else if(delta>.75)
        out += 0x1;

    delta = v.y-y;

    if((delta>.25) && (delta<.75))
        out += 0x20000000;
    else if(delta>.75)
        out += 0x100;

    delta = v.z-z;

    if((delta>.25) && (delta<.75))
        out += 0x40000000;
    else if(delta>.75)
        out += 0x10000;

    out += x+(y<<8)+(z<<16);
    return out;
}

list door_names         = [];//door list
list door_num           = [];//corresponding link numbers
list door_closed_rot    = [];//corresponding closed state rotation
list door_direction     = [];//which direction the door spin open
list door_open          = [];//is the door open?
list door_open_time     = [];//when was it open?
list door_acl           = [];//who can open the door (by user id)
list door_pos           = [];//the position of the door

list user_indexes       = [];//list of users (user ids)

integer is_active = FALSE;//if this is false the script ignore touches

recount_doors()
{
    //this function recount the doors and record all the different door characteristics
    //only ran after script reset/when an object is linked/unlinked
    is_active = FALSE;
    llSetText("recounting doors...",<1.0,1.0,1.0>,1.0);
    integer prims = llGetNumberOfPrims();

    integer i;
    for(i=2;i<=prims;i++)
    {
        key prim = llGetLinkKey(i);
        list tmp = llGetObjectDetails(prim,[OBJECT_NAME,OBJECT_DESC,OBJECT_ROT,OBJECT_POS]);
        string prim_name = llList2String(tmp,0);
        string prim_descr = llList2String(tmp,1);
        rotation prim_rot = (rotation)llList2String(tmp,2);
        vector prim_pos = (vector)llList2String(tmp,3);

        door_num += [i];
        door_names += [prim_name];
        door_closed_rot += [prim_rot];
        door_open += [FALSE];
        door_open_time += [0];
        if(prim_descr == "right")
            door_direction += [TRUE];
        else
            door_direction += [FALSE];
        door_acl += [""];
        door_pos += [prim_pos];
    }
    llSetText("...done!",<1,1,1>,1.0);
    reload_acl();
}

string config = "config";//name of the configuration file
integer nLine = 0;//current line we are reading

//this function re read the config notecard and populate the
//user list and acl table
reload_acl()
{

    llSetText("reloading access controls...",<1,1,1>,1.0);
    is_active = FALSE;
    nLine = 0;
    //remove all acl
    integer i;
    for(i=0;i<llGetListLength(door_num);i++)
        door_acl = llListReplaceList(door_acl,[""],i,i);

    user_indexes = [];
    llGetNotecardLine(config,nLine);
}

//close a door (by index) using the stored rotation
close(integer index)
{
    integer linknum = llList2Integer(door_num,index);

    rotation closed = llList2Rot(door_closed_rot,index);
    llSetLinkPrimitiveParams(linknum,[PRIM_ROTATION,closed]);

    door_open = llListReplaceList(door_open,[FALSE],index,index);
}

//close a door (by index) using the stored rotation and adding or substracting 90 degrees
//on the Z world axis depending of the direction recorded for the door.
//also record it's opening time (unix timestamp)
open(integer index)
{
    integer linknum = llList2Integer(door_num,index);
    rotation closed = llList2Rot(door_closed_rot,index);
    rotation open;
    if( llList2Integer(door_direction,index) )
        open = llEuler2Rot(llRot2Euler(closed)+ (<0,0,90> *DEG_TO_RAD));
    else
        open = llEuler2Rot(llRot2Euler(closed)+ (<0,0,-90> *DEG_TO_RAD));
    llSetLinkPrimitiveParams(linknum,[PRIM_ROTATION,open]);

    door_open_time = llListReplaceList(door_open_time,[llGetUnixTime()],index,index);
    door_open = llListReplaceList(door_open,[TRUE],index,index);

    llSetTimerEvent(1.0);
}

//those 3 functions rez a sound emitter with it's destination position encoded in integer
play_open(vector pos)
{
    llRezObject("open",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
}
play_close(vector pos)
{
    llRezObject("close",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
}
play_lock(vector pos)
{
    llRezObject("lock",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(pos));
}


default
{
    touch_start(integer total_number)
    {
        integer userid;

        if(!is_active)
            return;

        //considering we MAY receive more than one touch at the same time since
        //we can manage many doors.
        for(userid=0;userid<total_number;userid++)
        {
            integer door_id = llDetectedLinkNumber(userid);
            string clicker_name = llDetectedName(userid);

            integer door_index = llListFindList(door_num,[door_id]);
            if(door_index == -1)
                return;//unknown door? do nothing

            integer is_open = llList2Integer(door_open,door_index);
            vector door_vec = llList2Vector(door_pos,door_index);

            //we do not accept touches that are further away from activation_distance
            if( llVecDist(door_vec,llDetectedPos(userid) )> activation_distance )
                llInstantMessage(llDetectedKey(userid),"You can't use this from this distance.");
            else
            {
                if(is_open)
                {   //if the door is open, simply play sound and close it.
                    play_close(door_vec);
                    close(door_index);
                }
                else
                {
                    string acl_string = llList2String(door_acl,door_index);

                    //if the acl string is empty for this door we simply open it
                    if(acl_string == "") //no specific locking
                    {
                        play_open(door_vec);
                        open(door_index);
                    }
                    else
                    {
                        //otherwise we lookup if the userid that correspond to the person who touched
                        //the door match any of the ones in the ACL string
                        integer user_index = llListFindList(user_indexes,[clicker_name]);

                        if(user_index == -1)  //we don't even know this user? sure as hell there is no acl about him
                            play_lock(door_vec);
                        else
                        {
                            list acl_list =  llParseString2List(acl_string,[","],[]);

                            if(llListFindList(acl_list,[(string)user_index]) != -1)
                            {
                                play_open(door_vec);
                                open(door_index);
                            }
                            else
                                play_lock(door_vec);
                        }
                    }
                }
            }
        }
    }
    dataserver(key id,string data)
    {
        //notecard reading stuff
        if(data != EOF)
        {
            if(data != "" && data != " " && llGetSubString(data,0,1) != "//")
            {
                list command_and_data = llParseString2List(data,["="],[]);
                string door_name = llList2String(command_and_data,0);
                string user_names_string = llList2String(command_and_data,1);

                integer index = llListFindList(door_names,[door_name]);
                if(index != -1)
                {
                    list user_names_list = llParseString2List(user_names_string,[","],[]);
                    integer j;

                    list pre_acl_list;
                    for(j=0;j<llGetListLength(user_names_list);j++)
                    {
                        string user_name = llList2String(user_names_list,j);
                        integer index2 = llListFindList(user_indexes,[user_name]);
                        if( index2 == -1)
                        {
                            pre_acl_list += llGetListLength(user_indexes);
                            user_indexes += [user_name];
                        }
                        else
                            pre_acl_list += [index2];

                    }
                    string pre_acl_string = llDumpList2String(pre_acl_list,",");
                    door_acl = llListReplaceList(door_acl,[pre_acl_string],index,index);
                }
            }
            nLine++;
            llGetNotecardLine(config,nLine);
        }
        else
        {
            is_active = TRUE;
            llOwnerSay("config reloaded");
            llSetText((string)llGetFreeMemory()+"bits free",<.5,.5,.5>,.5);
        }
    }
    state_entry()
    {
        recount_doors();
    }
    changed(integer change)
    {
        //if we detect an inventory change we reread the notecard
        //if we detect a linkchange we reset the script and recount doors first
        if( (change & CHANGED_INVENTORY) == CHANGED_INVENTORY)
            reload_acl();
        if( (change & CHANGED_LINK) == CHANGED_LINK)
            llResetScript();
    }
    timer()
    {
        //timer will run once a second as long as at least one door is open.
        if(llListFindList(door_open,[TRUE]) == -1)
        {
            llSetTimerEvent(0.0);
            return;
        }
        integer i;

        //each run of the timer we loop through the timestamps to check if one of them is too old
        //(which means we can force close the associated door
        for(i=0;i<llGetListLength(door_open_time);i++)
        {
            integer is_open = llList2Integer(door_open,i);
            integer time = llList2Integer(door_open_time,i);
            if( is_open && ((time + autoclose_time) <  llGetUnixTime()))
            {
                vector door_vec = llList2Vector(door_pos,i);
                llRezObject("close",llGetPos(),ZERO_VECTOR,ZERO_ROTATION,vec2int(door_vec));
                close(i);
            }
        }
    }
}

Sound emitter script


You need this script in the 3 rezzable objects "open" "close" and "lock" in order to play your door sounds at the right place (At the time i wrote this , lsl doesn't allow yet to play sounds from an unscripted prim in a link set)

string sound_to_play = "my door sound";// put your sound name/key here

//This functions is from Nomad Padar, pretty awesome!
//decode from integer to vector
vector int2vec(integer n)
{
    //0zyx ZZZZ ZZZZ ZZZZ YYYY YYYY XXXX XXXX
    return <n&0xFF, (n>>8)&0xFF, ((n>>16)&0xFFF)> + <((n&0x10000000)!=0)*.5,((n&0x20000000)!=0)*.5,((n&0x40000000)!=0)*.5>;
}

default
{
    state_entry()
    {
        llSetStatus(STATUS_PHANTOM, TRUE);
        llSetPrimitiveParams([PRIM_TEMP_ON_REZ, TRUE]);
        llSetTexture(TEXTURE_TRANSPARENT,ALL_SIDES);
    }
    on_rez(integer a)
    {
        if(a == 0)
            return;

        vector destination = int2vec(a);

        integer i;
        for(i=0 ; i<50 && (llGetPos() != destination) ; i++)
            llSetLinkPrimitiveParamsFast(0, [PRIM_POSITION, destination]);

        if(llGetPos() == destination)
            llTriggerSound(sound_to_play,1.0);
        llDie();
    }
}

Example "config" notecard:

//lines starting with "//" are ignored
//Syntax: one line per door in the format door_name=user name,user name
My fancy front door=Kyrah Abattoir
My secret playroom door=Kyrah Abattoir,Timeless Prototype
//of course if you want to lock a door from anybody you can set it to something like this:
Mine entrance=condemned until further notice

--Kyrah Abattoir 18:46, 7 March 2010 (UTC)