Difference between revisions of "User:Luisa Bourgoin/Burn2"

From Second Life Wiki
Jump to navigation Jump to search
 
Line 8: Line 8:


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.
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
<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
// 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
//use a cube like 2.00 2.00 0.05 size. the Z size decideds how high above a prim the hoovertext
Line 17: Line 21:


string boilerplate = "(click & chat to inscript)\n";
string boilerplate = "(click & chat to inscript)\n";
integer max_message_lines = 50; //memory limitation
integer max_message_lines = 50; //memory limitation. don't get tempted to squish
integer visible_lines = 4; //only some 255 chars can be shown, so short lines can be shown more visibly
// 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>;
vector color = <255, 255, 255>;
float wipe_hours = -1; //if you want a scratchboard that cleans every N hours
float wipe_hours = -1; //if you want a scratchboard that cleans every N hours
integer owner_only = FALSE;
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
//no serviceable parts below this line
integer open = TRUE;
integer open = TRUE;
integer LISTEN_HANDLE_1 = -1;
integer LISTEN_HANDLE_1 = -1;
list marque_text = [];
integer showtime_channel;
string text = "\n\n\n\n"; //consider visible_lines
list splitted_text = [];
integer marque_line = 0;
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) {
string left(string src, string divider) {
Line 43: Line 107:
     if(name == "???") name = llList2String(llGetObjectDetails(ID, [OBJECT_NAME]), 0); //gaaaah.. Displaynames!
     if(name == "???") name = llList2String(llGetObjectDetails(ID, [OBJECT_NAME]), 0); //gaaaah.. Displaynames!
     return name;
     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));
}
}


Line 49: Line 124:
     state_entry()
     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();
         llResetTime();
         llSetTimerEvent(3.17); //scrolling speed reasonably low!
         llSetTimerEvent(scroll_delay);
         marque_line = 0;
         memory_remaining = llGetFreeMemory();
        color = color / 255.0;
     }
     }


     touch_start(integer num_detected)
     touch_start(integer num_detected)
     {
     {
         if(open && llGetListLength(marque_text) <= max_message_lines)
         key ID = llDetectedKey(0);
        {
        if(owner_only && ID != llGetOwner()) return;
            key ID = llDetectedKey(0);
        memory_remaining = llGetFreeMemory();
            if(owner_only && ID != llGetOwner()) return;
        if(ID != llGetOwner() && (!open || llGetListLength(splitted_text) > max_message_lines)) return;
            string displayname = left(DisplayName(ID), " ");
               
            llListenRemove(LISTEN_HANDLE_1);
        llListenRemove(LISTEN_HANDLE_1);
            LISTEN_HANDLE_1 = llListen(0, "", ID, "");
        LISTEN_HANDLE_1 = llListen(0, "", ID, "");
            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)");
        clicked_time = llGetTime();
        }
       
        if(ID != llGetOwner()) greeter(left(DisplayName(ID), " "));
     }
     }
      
      
Line 71: Line 148:
     {
     {
         llListenRemove(LISTEN_HANDLE_1);
         llListenRemove(LISTEN_HANDLE_1);
        LISTEN_HANDLE_1 = -1;
        if(owner_only && id != llGetOwner()) return;
          
          
         if(id == llGetOwner())
         if(id == llGetOwner())
Line 77: Line 156:
             {
             {
                 integer i=0;
                 integer i=0;
                 for(; i<llGetListLength(marque_text); i++) {
                 for(; i<llGetListLength(splitted_text); i++) {
                     llSay(0, llList2String(marque_text, i));
                     llSay(0, llList2String(splitted_text, i));
                     llSleep(0.2); //otherwise, chatlines order can get garbled!
                     llSleep(0.2); //otherwise, chatlines ordre get can grabled!
                 }
                 }
                 return;
                 return;
Line 89: Line 168:
             if(message == "closed") {
             if(message == "closed") {
                 open = FALSE;
                 open = FALSE;
                 LISTEN_HANDLE_1 = llListen(0, "", llGetOwner(), "open"); //sic!
                 return;
            }
            if(message == "pause") {
                llSetTimerEvent(0);
                return;
            }
            if(message == "continue") {
                llSetTimerEvent(scroll_delay);
                 return;
                 return;
             }
             }
             if(llGetSubString(message,0,5) == "delete") {
             if(llGetSubString(message,0,5) == "delete") {
                 string pattern = llGetSubString(message,7,-1);
                 string pattern = llGetSubString(message,7,-1);
                splitted_text = llParseStringKeepNulls(text, ["\n"], []);
                 integer i=0;
                 integer i=0;
                 for(; i<llGetListLength(marque_text); i++)
                 for(; i<llGetListLength(splitted_text); i++)
                 {
                 {
                     if(llSubStringIndex(llList2String(marque_text, i), pattern) >= 0)
                     if(llSubStringIndex(llList2String(splitted_text, i), pattern) >= 0)
                     {
                     {
                         marque_text = llDeleteSubList(marque_text, i, i);
                         splitted_text = llDeleteSubList(splitted_text, i, i);
                         i--; //since it just shortened
                         i--; //since it just shortened
                     }
                     }
                 }
                 }
                 text = llDumpList2String(marque_text, "\n");
                 text = llDumpList2String(splitted_text, "\n");
                splitted_text = llParseStringKeepNulls(text + "\n\n\n\n", ["\n"], []);
                 return;
                 return;
            }
            if(llGetSubString(message,0,7) == "showtime") {
                showtime_channel = (integer)llGetSubString(message,9,-1);
                state showtime;
             }
             }
         }
         }
       
        if(owner_only && id != llGetOwner()) return;
              
              
         message = llDumpList2String(llParseStringKeepNulls((message = "") + message, ["\\n"], []), "\n");
         message = llDumpList2String(llParseStringKeepNulls((message = "") + message, ["\\n"], []), "\n");
         text = text + message + "\n\n";
         text = text + message + "\n\n"; //adds a newline. We assume message ends blank
         marque_text = llParseStringKeepNulls(text+"\n\n\n\n\n", ["\n"], []);
         splitted_text = llParseStringKeepNulls(text + "\n\n\n\n", ["\n"], []);
     }
     }
      
      
     timer()
     timer()
     {
     {
        //timeouts are missing :(
         if(LISTEN_HANDLE_1 != -1 && (llGetTime() - clicked_time > 20))
//~         if(LISTEN_HANDLE_1 != -1 && )
         {
//~         {
             llListenRemove(LISTEN_HANDLE_1);
//~             llListenRemove(LISTEN_HANDLE_1);
             LISTEN_HANDLE_1 = -1;
//~             LISTEN_HANDLE_1 = -1;
            llSay(0, "aborting due to timeout");
//~         }
         }
          
          
         if(wipe_hours > 0 && (llGetTime() / 3600.0) > wipe_hours) llResetScript();
         if(wipe_hours > 0 && (llGetTime() / 3600.0) > wipe_hours) llResetScript();
           
 
        //handles the scrolling effect called 'marque' herein
         if(visible_lines <= 6)
         if((marque_line + visible_lines) >= llGetListLength(marque_text)) marque_line = 0;
             llSetText(show_boilderplate()+llDumpList2String(llList2List(splitted_text, top_line, top_line+visible_lines-1), whitespace_NL)+whitespace_NL, color,1);
        if(open && llGetListLength(marque_text) <= max_message_lines)
       
             llSetText(boilerplate+llDumpList2String(llList2List(marque_text,marque_line,marque_line+visible_lines), " \n")+" \n", <1,1,1>,1);
        if(visible_lines > 6)
        else
        {
             llSetText(llDumpList2String(llList2List(marque_text,marque_line,marque_line+visible_lines), " \n")+" \n", <1,1,1>,1);
            list bottom = llList2List(splitted_text, top_line+6, top_line+6+visible_lines-7);
         marque_line++;
             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>
//~ eof</lsl>

Latest revision as of 05:39, 18 October 2012

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>