User:Zai Lynch/Sandbox/LSL Goodies

From Second Life Wiki
< User:Zai Lynch‎ | Sandbox
Revision as of 18:14, 26 October 2008 by Zai Lynch (Talk | contribs)

Jump to: navigation, search


Intro

So just for the record: I'm a complete LSL n00b. So don't expect much from this page. 'Cause I love the Open Source concept, I'd like to share some of my scripts with other SL Residents =)
Since these are contributions to the SL Wiki, all scripts are released under Creative Commons Attribution-Share Alike 3.0 License.


Simple Countdown

This script displays a hovering countdown above the item it's placed in. Need to provide time difference between start and end of the countdown. Another implementation, needing date and time when the countdown is supposed to finish, can be found below.


<lsl> ////////////////////////////////////////////////////// // // // Simple Countdown Script // // released under // // Creative Commons Attribution-Share Alike 3.0 // // by Zai Lynch // // // //////////////////////////////////////////////////////


integer DAYS = 28; // Days until the countdown finishs integer HOURS = 6; // Hours until the countdown finishs integer MINUTES = 42; // Minutes until the countdown finishs integer SECONDS = 12; // Seconds until the countdown finishs string TEXT = "The end of the world will come in"; // Additional text defining the event string FINISHED = "uh oh..."; // Text displayed when event happened vector COLOR = <1,1,1>; // Color of the displayed text


countdown() {

   llSetText(TEXT+"\n"+(string)(SECONDS/86400)+" days, "
       +(string)((SECONDS%86400)/3600)+" hours, "
       +(string)(((SECONDS%86400)%3600)/60)+" minutes, "
       +(string)(((SECONDS%86400)%3600)%60)+ "seconds.",COLOR,1);

}


default {

   state_entry()
   {
       SECONDS = SECONDS + MINUTES * 60 + HOURS * 3600 + DAYS * 86400;
       llSetTimerEvent(1);
       countdown();
   }


   timer()
   {
       if (SECONDS > 0)
       {
           SECONDS = SECONDS - 1;
           countdown();
       }
       else 
       {
           llSetText(FINISHED, COLOR,1);
           llSetTimerEvent(0);
       }
   }

} </lsl>


The next version is based on a timestamp -> unixtime conversion by Trinity Coulter.

<lsl> // _ _ _ // (_) | | | | // __ ____ _ _ | |_ _ _ __ ___| |__ // |_ / _` | | | | | | | '_ \ / __| '_ \ // / / (_| | | | | |_| | | | | (__| | | | // /___\__,_|_| |_|\__, |_| |_|\___|_| |_| // __/ | // |___/ // // released this script under // Creative Commons Attribution-Share Alike 3.0 // // Based on a timestamp -> unixtime // conversion script by Trinity Coulter // taken from // https://wiki.secondlife.com/wiki/User:Trinity_Coulter/Using_HTTPRequest_to_Convert_GMT_to_Unix_time // at September 4th 2008 //


// Specify time and date in UTC

string Date = "2009.09.04"; // YYYY.MM.DD string Time = "15:44:00"; // hh:mm:ss

string TEXT = "The end of the world will come in"; // Additional text defining the event string FINISHED = "uh oh..."; // Text displayed when event happened vector COLOR = <1,1,1>; // Color of the displayed text


string myGMTTime; integer SECONDS;

countdown() {

   llSetText(TEXT+"\n"+(string)(SECONDS/86400)+" days, "
       +(string)((SECONDS%86400)/3600)+" hours, "
       +(string)(((SECONDS%86400)%3600)/60)+" minutes, "
       +(string)(((SECONDS%86400)%3600)%60)+ "seconds.",COLOR,1);

}


default {

   state_entry()
   {
       myGMTTime = Date +"."+Time;
       string toUnix = "http://www.iwebtool.com/tool/tools/unix_time_converter/unix_time_converter.php?year=" 
       + llGetSubString(myGMTTime,0,3) + "&mon=" + llGetSubString(myGMTTime,5,6) + "&day=" 
       + llGetSubString(myGMTTime,8,9) + "&hour=" + llGetSubString(myGMTTime,11,12) + "&min=" 
       + llGetSubString(myGMTTime,14,15) + "&sec=" + llGetSubString(myGMTTime,17,18);
       SECONDS = llGetUnixTime();
       llHTTPRequest(toUnix,[HTTP_METHOD,"GET"],"");
   }


   http_response(key request_id,integer status, list metadata, string body)
   {
       body = llGetSubString(body, 50, -9);
       SECONDS = (integer)body + 18000 - (2 * llGetUnixTime()) + SECONDS;
       llSetTimerEvent(1); 
   }

   timer()
   {
       if (SECONDS > 0)
       {
           SECONDS = SECONDS - 1;
           countdown();
       }
       else 
       {
           llSetText(FINISHED, COLOR,1);
           llSetTimerEvent(0);
       }
   }

} </lsl>


Basic Notecard-Reader

This script reads notecards placed in the same prim as the script itself.

<lsl> ////////////////////////////////////////////////////// // // // Basic Notecard-Reader // // released under // // Creative Commons Attribution-Share Alike 3.0 // // by Zai Lynch // // // //////////////////////////////////////////////////////


// Constants

integer CHANNEL = 2130214; list MENU = ["Forward", "Backward", "Load", "Play", "Stop", "Time"];

// Variables list gMenuNC; integer gLine = 0; integer gTime = 5; string gNC = "";


zlGenerateList() {

   integer i;
   integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
   string name;
   gMenuNC = [];
   if (n > 0)
   {
       for (i=0; i<n; i++)
       {
           name = llGetInventoryName(INVENTORY_NOTECARD, i);
           if (llStringLength(name) < 25)
               gMenuNC = gMenuNC + [name];
           else 
           {
               llSay(0, "Name: "+name + " is to long.");
               llRemoveInventory(name);
               llSay(0, "Notecard removed.");
           }
       }
   }
   if (gNC == "") gNC=llGetInventoryName(INVENTORY_NOTECARD,0);

}


default {

   state_entry()
   {
       zlGenerateList();
       llListen(CHANNEL, "", llGetOwner(), "");
       llListen(CHANNEL+1, "", llGetOwner(), "");
   }
   
   on_rez(integer start_param)
   {
       llResetScript();
   }
   
   changed(integer change)
   {
       if (change == CHANGED_INVENTORY) zlGenerateList();
   }
   
   touch_start(integer num)
   {
       if (llDetectedKey(0) == llGetOwner()) llDialog(llGetOwner()," ",MENU,CHANNEL);
   }
   
   listen(integer cha, string name, key id, string msg)
   {
       if (cha == CHANNEL)
       {
           if (msg == "Stop") 
           {
               llSetTimerEvent(0);
               llDialog(llGetOwner()," ",MENU,CHANNEL);
           }
           if (msg == "Play") 
           {
               llSetTimerEvent(gTime); 
               llGetNotecardLine(gNC, gLine); 
               llDialog(llGetOwner()," ",MENU,CHANNEL);
           }
           if (msg == "Forward") 
           {
               gLine = gLine + 1; 
               llGetNotecardLine(gNC, gLine); 
               llDialog(llGetOwner()," ",MENU,CHANNEL); 
               llSetTimerEvent(0);
           }
           if ((msg == "Backward") && (gLine > 0)) 
           {
               gLine = gLine - 1; 
               llGetNotecardLine(gNC, gLine); 
               llDialog(llGetOwner()," ",MENU,CHANNEL); 
               llSetTimerEvent(0);
           }
           if (msg == "Load") 
               llDialog(llGetOwner(), " ", gMenuNC, CHANNEL+1);
           if (msg == "Time") 
               state listening;
       }
       if (cha == (CHANNEL+1))
       {
           gNC = msg;
           gLine = 0;
           llDialog(llGetOwner()," ",MENU,CHANNEL);
       }
   }
   
   timer()
   {
       gLine = gLine+1;  
       llGetNotecardLine(gNC, gLine);
   }
   
   dataserver(key qid, string data)
   {
       llSay(0, data);        
   }
   
   state_exit()
   {
       llSetTimerEvent(0);
   }
       

}

state listening {

   state_entry()
   {
       llSetTimerEvent(30);
       llListen(0, "", llGetOwner(), "");
       llSay(0,"Please tell me the desired updatetime in seconds.");
   }
   
   listen(integer cha, string name, key id, string msg)
   {
       gTime = (integer)msg;
       llSay(0, "Time set.");
       state default;
   }    
   
   timer()
   {
       llSay(0,"Sorry, the request timed out.");
       state default;
   }
   
   state_exit()
   {
       llSetTimerEvent(0);
       llDialog(llGetOwner()," ",MENU,CHANNEL);
   }

} </lsl>


Teleport via Map

Set the description of the prim this script is attached to, to: SIMNAME/X/Y/Z
The script will read the description and open the map at the defined position in case it is clicked.
Click and hold the prim clicked for more then 4 seconds in order to re-initialize the script.

<lsl> ////////////////////////////////////////////////////// // // // Teleport via Map // // released under // // Creative Commons Attribution-Share Alike 3.0 // // by Zai Lynch // // // //////////////////////////////////////////////////////

string simname; vector pos; integer touchStartTime;


init() {

   if (llGetObjectDesc() != "")
   {
   string desc = llGetObjectDesc();
   simname = llGetSubString(desc,0,llSubStringIndex(desc,"/")-1);
   desc = llGetSubString(desc,llSubStringIndex(desc,"/")+1,llStringLength(desc)+1);
   integer x = (integer)llGetSubString(desc,0,llSubStringIndex(desc,"/")-1);
   desc = llGetSubString(desc,llSubStringIndex(desc,"/")+1,llStringLength(desc)+1);
   integer y = (integer)llGetSubString(desc,0,llSubStringIndex(desc,"/")-1);
   desc = llGetSubString(desc,llSubStringIndex(desc,"/")+1,llStringLength(desc)+1);
   integer z = (integer)llGetSubString(desc,0,llStringLength(desc)-1);
   pos = <x,y,z>;
   }
   else
   {
       simname="Omidyar";
       pos=<130,86,200>;
   }

}


default {

   state_entry()
   {
       init();
   }
   
   touch_start(integer num_detected)
   {
       touchStartTime = llGetUnixTime();
   }
   
   touch_end(integer num_detected)
   {
       if (llGetUnixTime() > touchStartTime + 4)
       {
           llSay(0,"Resetting...");
           init();
       }
       else 
       llMapDestination(simname, pos, <1,1,1> );
   }

} </lsl>


Buzzer

This script is supposed to be used during meetings so a speaker isn't interrupted by questions while people can still indicate that they would like to speak. Up to 8 people might leave their indication by clicking the item where the script is attached to. Every name will only be listed once.

Click and hold it clicked for more than 3 seconds to delete the upmost name.

<lsl> ////////////////////////////////////////////////////// // // // zlBuzzer // // released under // // Creative Commons Attribution-Share Alike 3.0 // // by Zai Lynch // // // //////////////////////////////////////////////////////


integer time;

string q0 = "User with questions:"; string q1 = ""; string q2 = ""; string q3 = ""; string q4 = ""; string q5 = ""; string q6 = ""; string q7 = ""; string q8 = "";

erase() {

   q1 = q2;
   q2 = q3;
   q3 = q4;
   q4 = q5;
   q5 = q6;
   q6 = q7;
   q7 = q8;
   q8 = "";

}

add(string name) {

   if ((name != q1) && (name != q2) && (name != q3) && (name != q4) && 
   (name != q5) && (name != q6) && (name != q7) && (name != q8))
   if (q1=="") q1=name;
   else if (q2 == "") q2=name;
   else if (q3 == "") q3=name;
   else if (q4 == "") q4=name;
   else if (q5 == "") q5=name;
   else if (q6 == "") q6=name;
   else if (q7 == "") q7=name;
   else if (q8 == "") q8=name;
   

}


default {

   state_entry()
   {
       llSetText(q0,<1,1,1>,1);
   }
   touch_start(integer total_number)
   {
       time = llGetUnixTime();
   }
   
   touch_end(integer num_detected)
   {
       if (llGetUnixTime() < time + 3)
       add(llDetectedName(0));
       else erase();
       llSetText(q0+"\n"+q1+"\n"+q2+"\n"+q3+"\n"+q4+"\n"
       +q5+"\n"+q6+"\n"+q7+"\n"+q8, <1,1,1>,1);
   }

} </lsl>

Landmark Replacer

The following two scripts are supposed to be used by shop owners who are moving their store to a new spot. Since most owners box their items with a landmark to their shop, all these landmarks need to be updated after the move. Depending on the number of items, this can become an exhausting exercise. It will still remain an exhausting exercise, even with the use of these scripts, but it will at least make it a little faster. The first script zlLandmarkSender is supposed to be placed in a single prim, which contains the landmark to the new store. Alter the LM variable that way, that it's value equals the exact name of the landmark in the objects inventory. Afterwards, rez all your boxes and place the zlLandmarkCleaner&Replacer script inside them. This script will search for exisiting landmarks and remove them. Afterwards, it will ask the previously rezzed prim (server) for the uptated landmark. When you finished placing your scripts in the old boxes, you can click the initially rezzed serverprim and answer the upcoming question with yes in order to remove all zlLandmarkCleaner&Replacer scripts from the boxes and to de-rez the server prim.

zlLandmarkSender

<lsl> // _ _ _ // (_) | | | | // __ ____ _ _ | |_ _ _ __ ___| |__ // |_ / _` | | | | | | | '_ \ / __| '_ \ // / / (_| | | | | |_| | | | | (__| | | | // /___\__,_|_| |_|\__, |_| |_|\___|_| |_| // __/ | // |___/ // // released this script under // Creative Commons Attribution-Share Alike 3.0 //


// This script provides the landmark(s) the landmarks and sends // the kill code to remove the scripts, once the process finished. // Just add the new landmark to the prim containing this script, // specify the name of the landmark in the LM variable below, // place all the zlLanmarkCleaner&Receiver scripts in the obsolete // boxes. When all scripts are placed, you can click the prim where // this script here is in and answer the upcoming question with "yes".


string LM = "NAME"; // Please enter the correct name of the landmark here.


integer CHANNEL = -1564876734;


default {

   state_entry()
   {
       llListen(CHANNEL, "", "", "Gimme LM plz");
       llListen(CHANNEL + 1, "", llGetOwner(), "");
   }
   
   
   listen(integer cha, string name, key id, string msg)
   {
       if (cha == CHANNEL) llGiveInventory(id, LM);
       else {
           if (msg == "Yes") 
           {
               llShout(CHANNEL, "kill");
               llOwnerSay("All scripts killed. Job done. Removing myself.");
               llDie();
           }
       }
   }
   
   touch_start(integer num)
   {
       if (llDetectedKey(0) == llGetOwner())
       llDialog(llDetectedKey(0), "Kill all scripts?", ["Yes", "No"], CHANNEL+1);
   }

} </lsl>


zlLandmarkCleaner&Receiver

<lsl> // _ _ _ // (_) | | | | // __ ____ _ _ | |_ _ _ __ ___| |__ // |_ / _` | | | | | | | '_ \ / __| '_ \ // / / (_| | | | | |_| | | | | (__| | | | // /___\__,_|_| |_|\__, |_| |_|\___|_| |_| // __/ | // |___/ // // released this script under // Creative Commons Attribution-Share Alike 3.0 //


// This script is supposed to be placed in boxes which // contain obsolete landmarks. It should be added AFTER // the server prim with the zlLandmarkSenderScript is set up.


integer CHANNEL = -1564876734;


default {

   state_entry()
   {   
       integer b = llGetInventoryNumber(INVENTORY_LANDMARK);
       integer a;
       if (b > 0)
       {
       for (a = 0; a < b; a++)
       llRemoveInventory(llGetInventoryName(INVENTORY_LANDMARK,0));
       }
           
       llShout(CHANNEL, "Gimme LM plz");
       llListen(CHANNEL, "", "", "kill");
       
   }
   listen(integer cha, string name, key id, string msg)
   {
       if (llGetOwnerKey(id) == llGetOwner()) llRemoveInventory(llGetScriptName());
   }

} </lsl>

IM Greeter

This is supposed to be a low spam IM greeter.

<lsl> // _ _ _ // (_) | | | | // __ ____ _ _ | |_ _ _ __ ___| |__ // |_ / _` | | | | | | | '_ \ / __| '_ \ // / / (_| | | | | |_| | | | | (__| | | | // /___\__,_|_| |_|\__, |_| |_|\___|_| |_| // __/ | // |___/ // // released this script under // Creative Commons Attribution-Share Alike 3.0 //


string MESSAGE = "Heyas!"; // Message that's supposed to be send.

integer RANGE = 5; // Scans RANGE meter. integer RATE = 5; // Scans every RATE seconds. integer CLEANTIME = 300; // List is cleaned every CLEANTIME seconds. integer ABSENTTIME = 300; // Time ava is allowed to

                         // be out of scanning range before getting removed
                         // from the list.

list MyAvatarList = []; // List that stores avas and timestamps.


default{

   state_entry(){
       llSensorRepeat("", "", AGENT, RANGE, PI, RATE); // start scanner
       llSetTimerEvent(CLEANTIME); // start timer for cleanup
   }
   
   on_rez(integer start){
       MyAvatarList = []; // Clean the list when item is rezzed.
   }
   
   sensor(integer num_detected){
       integer i = 0; 
       for (;i < num_detected; i++){ // for each detected ava do
           key ava = llDetectedKey(i); // grab the key
           integer index = llListFindList(MyAvatarList, (list)ava); // grab position in list           
           if(~index){ // if ava in list
               // update the timestamp
               llListReplaceList(MyAvatarList, [llGetUnixTime()], index+1, index+1);
           }
           else {  // else
               MyAvatarList += [ava, llGetUnixTime()]; // add ava to list
               llInstantMessage(ava, MESSAGE); // greet ava via IM
           }
       }
   }
   
   timer(){ // start to clean obsolete entries
       integer length = llGetListLength(MyAvatarList);
       integer i = 1;
       integer time = llGetUnixTime(); // store current time
       list copy = MyAvatarList; // store a copy of the list
       integer indexoffset = 0;
       for (; i < length; i += 2) { // for all timestamps
           if (time - llList2Integer(MyAvatarList,i) > ABSENTTIME){ // compare timestamp with current time
               // delete ava from copied list when absent for to long
               copy = llDeleteSubList(MyAvatarList, i-1-indexoffset, -indexoffset); 
               indexoffset += 2;
           }
       }
       MyAvatarList = copy; // replace ava list with updated copy
   }

}</lsl>

Zai landing.png