Sim to Sim Pseudo Teleporter

Written by: Headmaster
Sheena Desade's Sim-to-Sim Teleporter Script and Notecard (v3.1). Includes dynamic smart menu and instant teleportation (no confirmation required) via chat link. Missing sanity checks, so format things correctly! Public domain (open-source) since April 10, 2012.

See http://www.free-lsl-scripts.com/cgi/freescripts.plx?ID=1651 for an updated version by Donjr Spiegelblatt

This is Sheena Desade's Sim-to-Sim Teleporter Script (v3.1). 

Features/Pros: 
Smart Menu - seamlessly cycles, rearranges buttons in a logical order.
Dynamic List Parsing - never worry about breaking the script by adding or removing a location.
Instant Teleportation (no confirmation required!) via chat link (visit http://wiki.secondlife.com/wiki/Viewer_URI_Name_Space for more nifty links you can add to your own products).
Add as many locations as the script's memory can hold!

Missing/Cons:
Sanity checks! Format things correctly, or it will break.
Private chat - this says everything on channel zero for everyone to hear (does not use llRegionSayTo).
Annoying notecard configuration.
The sim/place names/location vectors lists could have been combined into one to save a little more memory.

---------
'Data' notecard: 

Hover_Text = Multi-Region Pseudo Teleporter: Click for Destinations
Menu_Text = Please select your destination:
Menu_Channel = 4765
Selection_Wait_Time = 30.0
Niamhinations! | Windlesham @ 207/580/133
---------

(template for the locations: Company Name | Region Name @ location x/location y/location z)

// Script Name: Sim-to-Sim_Pseudo-Teleporter_v31.lsl
// Author: Sheena Desade
// Sheena Desade's Sim-to-Sim Teleporter Script and Notecard (v3.1). Includes dynamic smart menu and instant teleportation (no confirmation required) via chat link. Missing sanity checks, so format things correctly! Public domain (open-source) since April 10, 2012.
//
//See http://www.free-lsl-scripts.com/cgi/freescripts.plx?ID=1651 for an updated version by Donjr Spiegelblatt

// Downloaded from : http://www.free-lsl-scripts.com/cgi/freescripts.plx?ID=1646

// This program is free software; you can redistribute it and/or modify it.
// Additional Licenes may apply that prevent you from selling this code
// You must leave any author credits and any headers intact in any script you use or publish.
///////////////////////////////////////////////////////////////////////////////////////////////////
// If you don't like these restrictions and licenses, then don't use these scripts.
//////////////////////// ORIGINAL AUTHORS CODE BEGINS ////////////////////////////////////////////


// This is Sheena Desade's Sim-to-Sim Teleporter Script (v3.1). 
//
//Features/Pros: 
//Smart Menu - seamlessly cycles, rearranges buttons in a logical order.
//Dynamic List Parsing - never worry about breaking the script by adding or removing a location.
//Instant Teleportation (no confirmation required!) via chat link (visit http://wiki.secondlife.com/wiki/Viewer_URI_Name_Space for more nifty links you can add to your own products).
//Add as many locations as the script's memory can hold!
//
//Missing/Cons:
//Sanity checks! Format things correctly, or it will break.
//Private chat - this says everything on channel zero for everyone to hear (does not use llRegionSayTo).
//Annoying notecard configuration.
//The sim/place names/location vectors lists could have been combined into one to save a little more memory.
//
//---------
//'Data' notecard: 
//
//Hover_Text = Multi-Region Pseudo Teleporter: Click for Destinations
//Menu_Text = Please select your destination:
//Menu_Channel = 4765
//Selection_Wait_Time = 30.0
//Niamhinations! | Windlesham @ 207/580/133
//---------
//
//(template for the locations: Company Name | Region Name @ location x/location y/location z)
/* 
This script was made April 10, 2012 by Sheena Desade. It is meant only to be redistributed freely (not ever to be sold)! Leave this header intact; other than those two requirements, do what you will with it. And if you make an improvement, feel free to send me a copy. :-)
*/

// ******** OPTIONAL SETTINGS **********
string hoverText = "Sim-to-Sim Pseudo Teleporter - click for destinations.";
float menuWait = 30.0;          // How long to wait for the user to pick a menu choice
integer menuChannel = 0;        // what channel for the object to 'listen' on. You can change this channel as needed, 
                                // it's not calling out to an object outside of itself. 
string menuText = "Please select your destination:";
string itemDataNotecard = "Data";
                                // The name of the notecard to read from
// ******** END OF OPTIONAL SETTINGS **********

// ******** SYSTEM SETTINGS - DO NOT MODIFY **********

// General variables
integer menu_handler;        // what the function that brings up the menu is called
integer loc = -1;            // -1 = none chosen; 0 = first location, etc.
integer length;              // How long the placeNames list is, which we base everything else off of
integer curList = 1;         // The current list number we're on
key curUser = NULL_KEY;      // The current user's key

// The following are required to read the notecard properly
integer notecardLine;
key currentDataRequest;
key notecarduuid;  

// These are the lists that hold all of our information
list simNames;               // The sim names of the places to teleport to
list placeNames;             // The region names of the places to teleport to
list locationVectors;        // The position to teleport to
// ******** END OF SYSTEM SETTINGS **********

init() // Setup the dataserver event for future use
{
    llOwnerSay("Reading item data...");
    notecardLine = 0; // we start reading the notecard at line 0, the first line
    currentDataRequest = llGetNotecardLine(itemDataNotecard, notecardLine); // specify our initial request
}

advancedMenu(key user, string text, integer channel)
{
    menu_handler = llListen(menuChannel,"","",""); // Lets the object 'hear' the option you choose
    if (length <= 12) llDialog(user,text,placeNames,channel); // Brings up a simple dialog if you have 12 or less options.
    
    else // If we have more than 12 options, create a multi-page dialog
    {
        list buttons; // Makes a list called 'buttons' that we will use later
        
        if (curList >= 1) // If we are not on page 0 (shouldn't be possible)
        {
            integer temp = (9*curList)-1; // Figures out which locations to display as buttons
            buttons = llList2List(placeNames, temp-8, temp); // the 'buttons' list now has nine locations
            // (List2List starts at 0, so we count 0 as 1)
            buttons = llListInsertList(buttons, ["<< Prev", "Cancel", "Next >>"], temp+1); 
            // the 'buttons' list also now has three other options besides our nine locations
            // (ListInsertList does NOT start at 0. It starts at 1.)
        }
        
        buttons = 
          llList2List(buttons, -3, -1)
        + llList2List(buttons, -6, -4)
        + llList2List(buttons, -9, -7)
        + llList2List(buttons, -12, -10);  // Puts our buttons in the logical order, instead of the default reversed one
        
        llDialog(user,text,buttons,channel);  // Sends a dialog to the user with the new improved button list
    
    }
}

default
{
    on_rez(integer param)
    {
        llResetScript(); // Resets script on rez
    }
    
    state_entry()
    {
        llOwnerSay("Initializing...");
        notecarduuid = llGetInventoryKey(itemDataNotecard); // collects our notecarduuid as soon as we enter this state
        init(); // runs our init function to use with our dataserver function
    }
    
    dataserver(key query, string data) 
    {
        if (query == currentDataRequest) // if we are trying to read the notecard
        {
            currentDataRequest = ""; // Prevent a bug that occurs with dataserver events.
            if (data != EOF) // If it isn't the end of the file
                        
            // **** IMPORTANT: I did not put any sanity checks in here, so you'll need to type
            // it all correctly, in the format "Store Name | Sim Name @ x/y/z" or it will not
            // work correctly! ****
            
            {
                integer s = llSubStringIndex(data, "@"); // We're looking for the @ symbol in our NC line
                if(~s) // If we find it
                {
                    string data1 = llStringTrim(llDeleteSubString(data, s, -1), STRING_TRIM);
                    // this line cuts out and saves everything before the @ symbol to use for the next index
                    string data4 = llStringTrim(llDeleteSubString(data, 0, s), STRING_TRIM);
                    // this line erases the @ symbol and temporarily saves the location into a seperate string
                    
                    integer s = llSubStringIndex(data1, "|"); // Now we're looking for the pipe symbol in only the 
                    // 'data1' variable defined when we were parsing for the @ symbol
                    if(~s) // If we find it (which we should, but we will check later to make sure our lists are
                    // the same length, anyway)
                    {
                        string data2 = llDumpList2String(llParseString2List(llStringTrim(llDeleteSubString(data1, 0, s), STRING_TRIM), [" "], [""]), "%20");
                        // Saves the first part in a temp string, erasing all spaces and replacing them with %20... there might be a better way to do this
                        string data3 = llStringTrim(llDeleteSubString(data1, s, -1), STRING_TRIM);
                        // Saves the second part in a temp string
                        
                        simNames += [data2];
                        // copies the temporary string data2 into our simNames list. Could probably combine the two 
                        // commands as with locationVectors.
                        placeNames += [data3];
                        // copies the temporary string data3 into our placeNames list. Could probably combine the 
                        // two commands, as with locationVectors and simNames.
                        locationVectors += [data4];
                        // this line copies the temporary string into our locationVectors list. We put it here so that it
                        // will not add the locationVector unless there are also sim and placeNames.
                    }
                }
                
                else
                {
                    integer s = llSubStringIndex(data, "="); // Now we are looking for the = symbol
                    if(~s) // if we find it
                    {
                        string token = llToLower(llStringTrim(llDeleteSubString(data, s, -1), STRING_TRIM));
                        // use our tokens to determine which variable we are defining
                        data = llStringTrim(llDeleteSubString(data, 0, s), STRING_TRIM);
                        // use our data to define our chosen variable
                        
                        if (token == "hover_text")
                            hoverText = data;
                        else if (token == "menu_text")
                            menuText = data;
                        else if (token == "menu_channel")
                            menuChannel = (integer)data;
                        else if (token == "selection_wait_time")
                            menuWait = (float)data;
                    }
                }
                
                notecardLine++;
                // Get the next line
                currentDataRequest = llGetNotecardLine(itemDataNotecard, notecardLine);
            }
            
            else // If it is the End of File
            {                
                length = llGetListLength(placeNames); // Defines how many entries we have in the placeNames list
                llOwnerSay ("Done reading data.");
                state configured;
            }
        }
    }
}

state configured
{
    state_entry()
    {
       if (hoverText != "none") llSetText(hoverText, <1.0,1.0,1.0>, 1); // if you want hovertext
       if (hoverText == "none") llSetText("---", <1.0, 1.0, 1.0>, 0); // if you do not want hovertext
       llWhisper(0, "Ready and waiting.");
       loc = -1; // Resets the location to none
    }
    
    changed(integer change)         
    {
        // We want to reload channel notecard if it changed
        if (change & CHANGED_INVENTORY)
        {
            if(notecarduuid != llGetInventoryKey(itemDataNotecard)) // If the change was triggered by saving the NC
            {
                llOwnerSay("Notecard change detected, resetting script.");
                llResetScript(); // resets the script
            }
        }
    }

    timer()
    {
        llListenRemove(menu_handler); // remove the listen event
        llInstantMessage(curUser, "Menu session timed out; choices automatically reset.");
        llSetTimerEvent(0.0); // removes the timer event, as it's not needed at the moment
        curList = 1; // reset our page to page one
        loc = -1; // set our location to none
        curUser = NULL_KEY; // resets the user to none
    }
    
    touch_start(integer total_number)
    {
        if(curUser == NULL_KEY || curUser == llDetectedKey(0)) // if there is no user or the toucher is the 
        // current user
            {
                curUser = llDetectedKey(0); // records the key of the curent user
                advancedMenu(curUser, menuText, menuChannel); // Sends the user our dialog box
                llSetTimerEvent(menuWait); // Sets our timer event so the menu will time out
            }
        
        if(curUser != NULL_KEY && curUser != llDetectedKey(0)) // If the toucher is not the current user
            llInstantMessage(llDetectedKey(0), "Sorry, this terminal is in use. Please wait your turn.");
    }
    
    listen(integer channel,string name,key id,string message) 
    //this is for the script to follow instructions based on what happens with the menu.
    {        
        if(message == "<< Prev")
        {            
            if(curList <= 1) // If we're on the first page
            { 
                curList = llCeil((float)length/9); // the current page needs to be changed to the last page, since
                // we're cycling backwards. We do this by rounding up (to cover any remainders) the length variable
                // (how many options we have total) divided by nine (since that's the number of buttons we need). 4.000 
                // will always round up to 4 (I think?).
                advancedMenu(curUser, menuText, menuChannel); // Give them our menu dialog
                llSetTimerEvent(menuWait); // how long until the menu times out?
            }
            
            else // If we're not on page one
            {
                curList--; // Go backwards a page
                advancedMenu(curUser, menuText, menuChannel); // Give them our menu dialog
                llSetTimerEvent(menuWait); // how long until the menu times out?
            }
        }
        
        else if(message == "Next >>")
        {
            if(curList*9 >= length) // if we have cycled through all options in our list
            {
                curList = 1; // go to page one
                advancedMenu(curUser, menuText, menuChannel); // Give the user our dialog menu
                llSetTimerEvent(menuWait); // how long until the menu times out?
            }
            
            else
            { 
                curList++; // go to the next page
                advancedMenu(curUser, menuText, menuChannel);  // Give the user our dialog menu
                llSetTimerEvent(menuWait); // how long until the menu times out?
            }
        }
        
        else if(message == "Cancel")
        {
            llInstantMessage(curUser, "Teleport cancelled.");
            curUser = NULL_KEY; // Erase the current user
            curList = 1; // Put our page back on the first page
            llListenRemove(menu_handler); // remove our listen event
            llSetTimerEvent(0.0); //removes the timer event, as it's not needed at the moment
        }
        
        else
        {
            
            loc = llListFindList(placeNames, (list)message); // determine which location we are teleporting to
            
            if(loc >= 0) // if it's an actual location
            {
                if (hoverText != "none") llSetText("Click the link to teleport", <1.0,1.0,1.0>, 1); 
                // if you want hovertext
                llInstantMessage(curUser, "Click this link to teleport to your target location - " + "secondlife:///app/teleport/" + llList2String(simNames, loc) + "/" + llList2String(locationVectors, loc)); // Give them the link to click
                llSetTimerEvent(0.0); // removes the timer event, as it's not needed at the moment
                llSleep(2.5);
                curUser = NULL_KEY; // resets our user so others can use the teleporter
                loc = -1; // reset our location to none
                curList = 1; // reset our page to one
                if (hoverText != "none") llSetText(hoverText, <1.0,1.0,1.0>, 1); 
            }
        }
    }
}

 

Category: