One Script, many doors

From Second Life Wiki
Jump to navigation Jump to search

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

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 should set them to phantom and TEMP ON REZ.

-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.**

<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 integer to vector 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);

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
   	//(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

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 {

   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