Dialog Texture Changer

// Script to present a dialog populated with a list of textures
// either from the prims inventory or specified by UUID in a notecard.
//
// Notecard lines have the form:
//    Texture Name=UUID
//
// Note that only the first 24 characters of the texture names
// are actually used - as only 24 chars can be placed in a dialog
// button.  This means that if two textures have the first 24 chars
// the same, the second will be ignored ...
//
// Note however that usually, buttons don't display more than, say,
// around 10 or so characters anyway!!
//
// There are two methods of setting textures - one (gSetTexture = TRUE)
// allows you to use UUIDs, etc, but the other (gSetTexture = FALSE)
// will allow you to specify the rotation and offset values.
//
// There is also an option to just use the values from the texture already
// on the face (but this won't work for ALL_SIDES).
//
// Both allow you to set the face.
//
// Kimm Paulino
// Feb 2012
 
// Controls how the script operates:
integer gReshow = FALSE;
integer gSetTexture = FALSE;               // Use SetTexture method (needed for textures not in the prim inventory)
integer gNotecards = TRUE;               // Get textures to use from a notecard not inventory
integer gPreserveTextures = FALSE;      // Read offset/rotation values from existing texture
 
// configures how textures appear
integer gFace = 1;
vector  gRepeats = <1.0, 1.0, 1.0>;
vector  gOffsets = <1.0, 1.0, 1.0>;
float     gRotationInDegrees = 0.0;
 
// Do not change anything below this line (unless you know what you are doing)
integer gDebug = FALSE;
integer gMenuPage;
integer gNumTextures;
list gTextures;
list gTextureUUIDs;
 
string gNotecardName;
integer gNotecardLine = 0;
key gQueryID;
 
integer gListenChannel;
integer gListenHandle;
float     gListenTimer;
float     LISTEN_TIMEOUT=300.0;
 
string MENU_NEXT="Next>";
string MENU_TOP="Top";
string MENU_BACK="<Back";
string MENU_SPACE=" ";
 
doDebug (string msg)
{
    if (gDebug)
    {
        llOwnerSay (msg);
    }
}
 
integer getRandomChannel ()
{
    // Based on http://tali.appspot.com/html/scripting/snippets.html
    // Always leaves 17th bit set (so never a number less than 65535)
    // Always leaves sign bit unset (so is always positive)
    integer pos_int = (((integer)llFrand(16384)) << 17) | 65536 | ((integer)llFrand(65535));
    return -pos_int;
}
 
integer read_textures_from_inventory ()
{
    gNumTextures = llGetInventoryNumber (INVENTORY_TEXTURE);
    gTextures = [];
 
    integer i;
    for (i=0; i<gNumTextures; i++)
    {
        string texture = llGetInventoryName (INVENTORY_TEXTURE, i);
        // Only store the first 24 characters of the name as this is all we can
        // show in a dialog anyway
        gTextures += [llGetSubString (texture, 0, 23)];
        doDebug ("read_textures: adding texture: " + texture);
    }
 
    return gNumTextures;
}
 
integer read_textures_from_notecards ()
{
    // Read texture information from the first notecard in inventory
    gNotecardName = llGetInventoryName(INVENTORY_NOTECARD, 0);
    if (gNotecardName == "")
    {
        return FALSE;
    }
    else
    {
        gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
        return TRUE;
    }
}
 
set_texture (string texture)
{
    if (gSetTexture)
    {
        llSetTexture (texture, gFace);
    }
    else if (gPreserveTextures && gFace != ALL_SIDES)
    {
        // returns: [string texture, vector scale, vector offset, float rotation]
        list scale_offset_rot = llGetPrimitiveParams ([PRIM_TEXTURE, gFace]);
 
        llSetPrimitiveParams([PRIM_TEXTURE,
                                    gFace,
                                    texture,
                                    llList2Vector (scale_offset_rot, 1),
                                    llList2Vector (scale_offset_rot, 2),
                                    llList2Float   (scale_offset_rot, 3)]
                                    );
    }
    else
    {
        llSetPrimitiveParams([PRIM_TEXTURE,
                                    gFace,
                                    texture,
                                    gRepeats,
                                    gOffsets,
                                    gRotationInDegrees*DEG_TO_RAD]
                                    );
    }
}
 
apply_texture (string texture)
{
    integer idx = llListFindList (gTextures, [texture]);
    if (idx == -1)
    {
        // Didn't find it in the list - might not be a texture
        return;
    }
 
    // Now need to find the texture that matches from the inventory
    // and give it out
    integer i;
    for (i=0; i<gNumTextures ; i++)
    {
        if (gNotecards)
        {
            string texture_uuid = llList2Key (gTextureUUIDs, idx);
            if (texture_uuid != "")
            {
                doDebug ("apply_texture: applying texture: " + texture_uuid);
                set_texture (texture_uuid);
                return;
            }
        }
        else
        {
            string texture_full = llGetInventoryName(INVENTORY_TEXTURE, i);
            if (llGetSubString (texture_full, 0, 23) == texture)
            {
                // This is the one
                doDebug ("apply_texture: applying texture: " + texture_full);
                set_texture (texture_full);
                return;
            }
        }
    }    
}
 
show_dialog (key id)
{
    list buttons = [];
 
    if (gNumTextures == 0)
    {
        do_dialog (id, "There are no textures to select at present.", []);
        return;
    }
 
    // If several people are using the giver, then it is possible
    // for gMenuPage to go negative or too high
    if (gMenuPage < 0)
    {
        // Reset ...
        gMenuPage = 0;
    }
    integer num_pages = ((gNumTextures+8)/9);
    if (gMenuPage >= num_pages)
    {
        // gMenuPage is an index starting at 0...
        // max is a 1...
        gMenuPage = num_pages-1;
    }
 
    // Max buttons on a dialog is 12, so if more than that, then need to 
    // include special next/back button handling
    integer first_texture = 0;
    integer last_texture = gNumTextures-1;
    if (gNumTextures > 12)
    {
        // Note: This yields notecards counting as follows:
        // 0 to 8 = first page,
        // 9 to 17 = next page, etc
        first_texture = gMenuPage * 9;
        last_texture = first_texture + 9 - 1;
        if (last_texture >= gNumTextures)
        {
            // recall last_texture indexed from 0, but
            // gNumTextures is indexed from 1
            last_texture = gNumTextures-1;
        }
 
        if (gMenuPage > 0)
        {
            buttons += [MENU_BACK];
        }
        else
        {
            buttons += [MENU_SPACE];
        }
 
        if (gMenuPage == 0)
        {
            buttons += [MENU_SPACE];
        }    
        else
        {
            buttons += [MENU_TOP];
        }
 
        // If not on the last page, and there are more pages to come ...
        if (gNumTextures > 9 && gMenuPage < (num_pages-1))
        {
            buttons += [MENU_NEXT];
        }
        else
        {
            buttons += [MENU_SPACE];
        }
    }
 
    integer i;
    for (i=first_texture; (i <= last_texture) && (i < gNumTextures); i++)
    {
        buttons += [llList2String (gTextures, i)];
    }
 
    do_dialog (id, "\n\n(click \"Ignore\" when done)", buttons);
}
 
do_dialog (key id, string msg, list buttons)
{
    llListenRemove (gListenHandle);
    gListenChannel = getRandomChannel();
    gListenHandle = llListen (gListenChannel, "", id, "");
    llSetTimerEvent (LISTEN_TIMEOUT);
    llDialog (id, msg, buttons, gListenChannel);
}
 
default
{
    on_rez (integer start_param)
    {
        llResetScript();
    }
 
    state_entry()
    {
        if (read_textures_from_inventory())
        {
            // We have textures in the inventory and have read them
            gNotecards = FALSE;
        }
        else if (read_textures_from_notecards())
        {
            // We have textures read in from a notecard by UUID
            // (or will have pretty soon)
            gNotecards = TRUE;
        }
        else
        {
            llOwnerSay ("Note: There are no textures or notecards in this prim ...");
        }
        gMenuPage = 0;
    }
 
    touch_start(integer total_number)
    {
        // Start menu system again. Note that I don't do anything special
        // with several people trying to touch it at the same time - it will
        // always overlap the processing of gMenuPage, but all that will
        // happen is that peoples next/back might be a bit quirky for a while.
        // Eventually, they will sort themselves out!
        gMenuPage = 0;
        show_dialog (llDetectedKey(0));
    }
 
    listen (integer channel, string name, key id, string msg)
    {
        if (channel == gListenChannel)
        {
            if (msg == MENU_BACK)
            {
                gMenuPage--;
                show_dialog (id);
            }
            else if (msg == MENU_TOP)
            {
                gMenuPage = 0;
                show_dialog (id);
            }
            else if (msg == MENU_NEXT)
            {
                gMenuPage++;
                show_dialog (id);
            }            
            else
            {
                // should be something in the inventory to give out
                apply_texture (msg);
 
                // reshow the dialog
                if (gReshow)
                {
                    show_dialog(id);
                }
            }
        }
    }
 
    timer ()
    {
        // First see if we are timing out on a listen event
        if (gListenHandle != 0)
        {
            // Remove the old listen
            llListenRemove (gListenHandle);
            gListenHandle = 0;
            gListenChannel = 0;
        }
    }
 
    dataserver(key query_id, string line)
    {
        if (query_id == gQueryID)
        {
            if (line != EOF)
            {
                if (llSubStringIndex (line, "=") != 0)
                {
                    list vals = llParseString2List (line, ["="], []);
 
                    // Only store the first 24 characters of the name as this is all we can
                    // show in a dialog anyway
                    string texture = llList2String (vals, 0);
                    string uuid = llList2Key (vals, 1);
                    gTextures += [llGetSubString (texture, 0, 23)];
                    gTextureUUIDs += uuid;
                    doDebug ("Adding: " + texture + " ("+uuid+")");
                }
 
                // Now get the next line
                gNotecardLine++;
                gQueryID = llGetNotecardLine(gNotecardName, gNotecardLine);
            }
            else
            {
                gNumTextures = llGetListLength (gTextures);
                doDebug ("Found " + (string)gNumTextures + " textures.");
            }
        }
    }
 
    changed (integer change)
    {
        if (change & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
}

 

Flash Scratch to SL - Your Scripting Tool

Script ImageNeed to write a LSL script and don't know how to script?  I know I hate trying to get my head around LSLS when I an in a time crunch. So why not give Flash Scratch a try! Its a great tool for learning and scoding your own scripts for Second Life without having to pay someone to do it and without a crash course in LSL

A Huge thanks to John Bennet of ATLAS Institute at University of Colorado and Eric Rosenbaum at MIT for writing Scratch for SL to begin with.

Read more: Flash Scratch to SL - Your Scripting Tool