User:Luisa Bourgoin/Burn2

From Second Life Wiki
Jump to navigation Jump to search

The Burning Man Temple rebuilt inside SecondLife

If you take a tour around Flickr, searching for snapshots of the original built you will see visitors left inscriptions on the construction wood. I aimed for establishing something similar for the SL Temple rebuilt.

The technology restrictions are very limiting. Since some years the most one can do to add text onto a Prim is using hoovertext. The LSL call llSetText() allows showing up to somewhat 255 chars above a Prim.

Some tinkering revealed that the position of the text shown is dependant on the Z size of the Primitive. Mostly one experiences hoovertext floating way above of any item, because builders can't change Z size to make it fit better, in any cases.

Taking these two ideas, using small Z sizes and a substring of the total data amount of user-recorded text has lead onto the following code. It scrolls through the user recorded chat messages. People left up to a dozen poem lines on the construction plywood that years.

This contains a showtime state where each message line got transmitted onto a chat channel. You need receiver item that picks them up there, sending acknowledges to forward the spool process.

<lsl>// Created early in September 2012 by Luisa Bourgoin for the Burn2 Temple built // published under Creative Commons on the Second Life wiki 9/23/2012

// Update from 10/18/2012 adds showtime state and spans across two prims

//use a cube like 2.00 2.00 0.05 size. the Z size decideds how high above a prim the hoovertext //appears, so using flat small Z values make it visible almost on center of a prim, turned by 90° //you can slice it a bit for better fitting

string boilerplate = "(click & chat to inscript)\n"; integer max_message_lines = 50; //memory limitation. don't get tempted to squish // 1k textlines inside. you can shift-copy the whole item during showtime, scales linearily integer visible_lines = 12; //only some 254 chars can be shown on single Prim. // Using 2nd Prim starting with 7th textline allows ~500 chars. I'm assuming an average linelength of 40 float scroll_delay = 5.17; vector color = <255, 255, 255>; float wipe_hours = -1; //if you want a scratchboard that cleans every N hours integer owner_only = FALSE;

greeter(string displayname) {

   llSay(0, "Welcome to the Temple, "+displayname+". To leave an inscript please chat a single textline in between next 20 seconds!\n(You can use \\n for line breaks)");

}

//no serviceable parts below this line integer open = TRUE; integer LISTEN_HANDLE_1 = -1; integer showtime_channel; list splitted_text = []; string text = "

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia nisl eu mi lobortis id pellentesque diam mattis.

Proin tellus lacus, pulvinar et porta et, posuere vel ante. Cras cursus venenatis ultricies.

Morbi tempor, dolor non sodales dictum, nisi nisl luctus est, ultricies sodales lectus arcu in neque.

Mauris elementum justo eget eros mattis semper. Nam eu lorem at elit aliquet malesuada.

Mauris libero est, molestie id cursus eu, egestas in arcu.


"; //~"01 Start //~ 02 Lorem ipsum dolor sit amet, //~ 03 consectetur adipiscing elit. //~ 04 Vivamus lacinia nisl eu mi lobortis //~ 05 id pellentesque diam mattis. //~ 06 //~ 07 Proin tellus lacus, //~ 08 pulvinar et porta et, //~ 09 posuere vel ante. //~ 10 Cras cursus venenatis ultricies. //~ 11 //~ 12 Morbi tempor, dolor non sodales dictum, //~ 13 nisi nisl luctus est, //~ 14 ultricies sodales lectus arcu in neque. //~ 15 //~ 16 Mauris elementum justo eget eros mattis semper. //~ 17 Nam eu lorem at elit //~ 18 aliquet malesuada. //~ 19 //~ 20 Mauris libero est, //~ 21 molestie id cursus eu, //~ 22 egestas in arcu. //~ 23 End"; integer top_line = 0; string whitespace_NL = " \n"; integer memory_remaining; float clicked_time;

string left(string src, string divider) {

   integer index = llSubStringIndex(src, divider);
   if(~index)
       return llDeleteSubString(src, index, -1);
   return src;

}

string DisplayName(key ID) {

   string name = llGetDisplayName(ID);
   if(name == "???") name = llList2String(llGetObjectDetails(ID, [OBJECT_NAME]), 0); //gaaaah.. Displaynames!
   return name;

}

string show_boilderplate() {

   if(open && llGetListLength(splitted_text) <= max_message_lines) return(boilerplate);
   return("");

}

string spacer(integer height) {

   return(llGetSubString(" \n \n \n \n \n \n \n \n \n \n \n", 0, height*2));

}

default {

   state_entry()
   {
       splitted_text = llParseStringKeepNulls(text + "\n\n\n\n", ["\n"], []);
       if(color.x + color.y + color.z > 3.0) color = color / 255.0;
       llResetTime();
       llSetTimerEvent(scroll_delay);
       memory_remaining = llGetFreeMemory();
   }
   touch_start(integer num_detected)
   {
       key ID = llDetectedKey(0);
       if(owner_only && ID != llGetOwner()) return;
       memory_remaining = llGetFreeMemory();
       if(ID != llGetOwner() && (!open || llGetListLength(splitted_text) > max_message_lines)) return;
               
       llListenRemove(LISTEN_HANDLE_1);
       LISTEN_HANDLE_1 = llListen(0, "", ID, "");
       clicked_time = llGetTime();
       
       if(ID != llGetOwner()) greeter(left(DisplayName(ID), " "));
   }
   
   listen(integer listenchannel, string name, key id, string message)
   {
       llListenRemove(LISTEN_HANDLE_1);
       LISTEN_HANDLE_1 = -1;
       if(owner_only && id != llGetOwner()) return;
       
       if(id == llGetOwner())
       {
           if(message == "dump")
           {
               integer i=0;
               for(; i<llGetListLength(splitted_text); i++) {
                   llSay(0, llList2String(splitted_text, i));
                   llSleep(0.2); //otherwise, chatlines ordre get can grabled!
               }
               return;
           }
           if(message == "open") {
               open = TRUE;
               return;
           }
           if(message == "closed") {
               open = FALSE;
               return;
           }
           if(message == "pause") {
               llSetTimerEvent(0);
               return;
           }
           if(message == "continue") {
               llSetTimerEvent(scroll_delay);
               return;
           }
           if(llGetSubString(message,0,5) == "delete") {
               string pattern = llGetSubString(message,7,-1);
               splitted_text = llParseStringKeepNulls(text, ["\n"], []);
               integer i=0;
               for(; i<llGetListLength(splitted_text); i++)
               {
                   if(llSubStringIndex(llList2String(splitted_text, i), pattern) >= 0)
                   {
                       splitted_text = llDeleteSubList(splitted_text, i, i);
                       i--; //since it just shortened
                   }
               }
               text = llDumpList2String(splitted_text, "\n");
               splitted_text = llParseStringKeepNulls(text + "\n\n\n\n", ["\n"], []);
               return;
           }
           if(llGetSubString(message,0,7) == "showtime") {
               showtime_channel = (integer)llGetSubString(message,9,-1);
               state showtime;
           }
       }
           
       message = llDumpList2String(llParseStringKeepNulls((message = "") + message, ["\\n"], []), "\n");
       text = text + message + "\n\n"; //adds a newline. We assume message ends blank
       splitted_text = llParseStringKeepNulls(text + "\n\n\n\n", ["\n"], []);
   }
   
   timer()
   {
       if(LISTEN_HANDLE_1 != -1 && (llGetTime() - clicked_time > 20))
       {
           llListenRemove(LISTEN_HANDLE_1);
           LISTEN_HANDLE_1 = -1;
           llSay(0, "aborting due to timeout");
       }
       
       if(wipe_hours > 0 && (llGetTime() / 3600.0) > wipe_hours) llResetScript();
       if(visible_lines <= 6)
           llSetText(show_boilderplate()+llDumpList2String(llList2List(splitted_text, top_line, top_line+visible_lines-1), whitespace_NL)+whitespace_NL, color,1);
       
       if(visible_lines > 6)
       {
           list bottom = llList2List(splitted_text, top_line+6, top_line+6+visible_lines-7);
           llSetText(show_boilderplate()+llDumpList2String(llList2List(splitted_text, top_line, top_line+5), whitespace_NL)+whitespace_NL+spacer(llGetListLength(bottom)-1), color,1);
           //scroll over onto next prim on linkset. Must be on same position, built same dimensions
           llSetLinkPrimitiveParamsFast(2,[PRIM_TEXT,llDumpList2String(bottom, whitespace_NL)+whitespace_NL,color,1]);
       }
       
       top_line++;
       if((top_line + visible_lines) > llGetListLength(splitted_text)) top_line = 0;
   }

}

state showtime {

   state_entry()
   {
       top_line = 0;
       splitted_text = llParseStringKeepNulls(text, ["\n"], []);
       llListen(showtime_channel, "", NULL_KEY, "ack");
       llSetText("dump: "+(string)(top_line+1), color,1);
       llSetLinkPrimitiveParamsFast(2,[PRIM_TEXT,"",color,1]);
       llSay(showtime_channel, llList2String(splitted_text, top_line));
       top_line++;
   }
   
   listen(integer listenchannel, string name, key id, string message)
   {
       llSetText("dump: "+(string)(top_line+1), color,1);
       llSay(showtime_channel, llList2String(splitted_text, top_line));
       top_line++;
       if(top_line >= llGetListLength(splitted_text)) state default;
   }
   
   touch_start(integer num_detected)
   {
       key ID = llDetectedKey(0);
       if(ID == llGetOwner()) state default;
   }

} //~ eof</lsl>