# One Script, many doors

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, and play sounds

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 wich won't be a door.
• 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.
• 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. <lsl> /******************************************* 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 = [];//wich 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,1,1>,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);

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++)
{
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)
{
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;
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)
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
//(wich means we can force close the assossiated 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);
}
}
}
```

} </lsl>

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)

<lsl> 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)&0xFF)> + <((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]);
}
on_rez(integer a)
{
if(a == 0)
return;

vector destination = int2vec(a);

integer i;
for(i=0 ; i<50 && (llGetPos() != destination) ; i++)
llSetPos(destination);

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

} </lsl> Example "config" notecard: <lsl> //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 </lsl --Kyrah Abattoir 18:46, 7 March 2010 (UTC)