One Script, many doors

From Second Life Wiki
Revision as of 03:35, 8 October 2013 by Kireji Haiku (talk | contribs) (-1 >> ERR_GENERIC)
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 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. <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 = [];//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 == ERR_GENERIC)
               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 == ERR_GENERIC)//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 != ERR_GENERIC)
               {
                   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 == ERR_GENERIC)
                       {
                           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]) == ERR_GENERIC)
       {
           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);
           }
       }
   }

} </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]);
       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++)
           llSetPos(destination);
       if(llGetPos() == destination)
           llTriggerSound(sound_to_play,1.0);
       llDie();
   }

} </lsl> 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)