User:Zai Lynch/Sandbox/LSL Goodies

From Second Life Wiki
< User:Zai Lynch‎ | Sandbox
Revision as of 15:58, 10 August 2009 by Zai Lynch (talk | contribs) (+jira issue parser)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.


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 // http://tinyurl.com/6hyf4z // 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 = ""; key owner;

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();
       owner = llGetOwner();
       llListen(CHANNEL, "", owner, "");
       llListen(CHANNEL+1, "", owner, "");
   }
   
   on_rez(integer start_param){
       llResetScript();
   }
   
   changed(integer change){
       if (change & CHANGED_INVENTORY) zlGenerateList();
       else if (change & CHANGED_OWNER) llResetScript();
   }
   
   touch_start(integer num){
       if (llDetectedKey(0) == owner) llDialog(owner," ",MENU,CHANNEL);
   }
   
   listen(integer cha, string name, key id, string msg){
       if (cha == CHANNEL){
           if (msg == "Stop") {
               llSetTimerEvent(0);
           }
           else if (msg == "Play") {
               llSetTimerEvent(gTime); 
               llGetNotecardLine(gNC, gLine); 
           }
           else if (msg == "Forward") {
               gLine = gLine + 1; 
               llGetNotecardLine(gNC, gLine); 
               llSetTimerEvent(0);
           }
           else if ((msg == "Backward") && (gLine > 0)) {
               gLine = gLine - 1; 
               llGetNotecardLine(gNC, gLine); 
               llSetTimerEvent(0);
           }
           else if (msg == "Load") {
               llDialog(owner, " ", gMenuNC, CHANNEL+1);
               return;
           }
           else if (msg == "Time") 
               state listening;
       }
       else {
           gNC = msg;
           gLine = 0;
       }
       llDialog(owner," ",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, "", owner, "");
       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(owner," ",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> // _ _ _ // (_) | | | | // __ ____ _ _ | |_ _ _ __ ___| |__ // |_ / _` | | | | | | | '_ \ / __| '_ \ // / / (_| | | | | |_| | | | | (__| | | | // /___\__,_|_| |_|\__, |_| |_|\___|_| |_| // __/ | // |___/ // // released this script under // Creative Commons Attribution-Share Alike 3.0 //

integer time; list q = [];


default {

   state_entry(){
       llSetText("User with questions:",<1,1,1>,1);
   }
   
   on_rez(integer startparam){
       llResetScript();
   }

   touch_start(integer total_number){
       time = llGetUnixTime();
   }

   touch_end(integer num_detected){
       if (llGetUnixTime() < time + 3){
           string name = llDetectedName(0);
           if(!(~llListFindList(q,(list)name))) q += [name];
       }
       else q = llDeleteSubList(q,0,0);
       string text = "User with questions:";
       integer i;
       for (i = 0; ((i < llGetListLength(q))&&(i < 8));i++){
           text += "\n"+llList2String(q,i);
       }
       llSetText(text, <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){
       llResetScript(); // Reset script when greeter 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
               MyAvatarList = 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
       for (; i < length; i += 2) { // for all timestamps
           if (time - llList2Integer(MyAvatarList,i) > ABSENTTIME){ // compare timestamp with current time
               // delete ava from list when absent for to long
               MyAvatarList = llDeleteSubList(MyAvatarList, i-1, i); 
               i -= 2;  // offset
               length -= 2; // offset
           }
       }
   }

}</lsl>

JIRA issue parser

I saw an item like this at the Hippotropolis bug triage meeting place, made by Moon Metty and thought that it was a neat idea. Since I didn't script for quite some time, I gave it a try to reverse engineer it.
When activated (on click), it listens to open chat. When a JIRA issue ID is entered, it displays a link to the jira issue.

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

// JIRA URL string string JIRA = "http://jira.secondlife.com/browse/"; // list of JIRA projects list projects = ["CT", "VWR", "SVC", "WEB", "MISC"]; // string for hover text string status = "JIRA issue parser\n"; // boolean variable to indicate on/off integer on; // listen handler integer lh;

// function to switch parser off zlOff(){

   on = FALSE;
   llListenRemove(lh);
   llSetText(status + "OFF", <1.0, 0.0, 0.0>, 1.0); 
   llSetColor(<1.0, 0.0, 0.0> ,ALL_SIDES);

}

// function to switch parser on zlOn(){

   on = TRUE;
   lh = llListen(0,"","","");
   llSetText(status + "ON", <0.0, 1.0, 0.0>, 1.0);
   llSetColor(<0.0, 1.0, 0.0> ,ALL_SIDES);

}

default{

   state_entry(){
       llSetObjectName("JIRA_parser");
       zlOff();
   }
   
   on_rez(integer start){
       llResetScript();
   }
   
   touch_start(integer num){
       if (on) zlOff();
       else zlOn();
   }
   listen(integer cha, string name, key id, string msg){
       // trim whitespaces
       msg = llStringTrim( msg, STRING_TRIM );
       // find the first appearence of "-"
       integer index = llSubStringIndex(msg, "-");
       // if the string contains a "-" but no blank
       if ((~index)&&(!(~llSubStringIndex(msg, " ")))){
           // test if first letters match a project
           if(~llListFindList(projects, (list)llGetSubString(msg,0,index-1))){
               // if so, print the URL
               llSay(0, JIRA + msg);
           }            
       }
   }

}</lsl>

Zai landing.png