An update to: Sheena Desade's Sim-to-Sim Teleporter Script and Notecard (was 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.
Modified by: Donjr Spiegelblatt (May 17, 2012) add support for: multi-users of the menu system at the same time Cancel button when only one menu is used support for comment lines in Data starting with # character new features: PrettyButton layout of the buttons in dialogs combined placeNames, simNames and locationVectors into a two strided list called places
// Script Name: Sim-to-Sim_Pseudo-Teleporter_v41.lsl // Author: donjr Spiegelblatt // An update to: Sheena Desade's Sim-to-Sim Teleporter Script and Notecard (was 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. // //This is an update of the original script from http://www.free-lsl-scripts.com/cgi/freescripts.plx?ID=1646 // Downloaded from : http://www.free-lsl-scripts.com/cgi/freescripts.plx?ID=1651 // 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 //////////////////////////////////////////// // modified by: Donjr Spiegelblatt (May 17, 2012) //add support for: // multi-users of the menu system at the same time // Cancel button when only one menu is used // suppot for comment lines in Data starting with # character //new features: // PrettyButton layout of the buttons in dialogs // combined placeNames, simNames and locationVectors into a two strided list called places // Modified to use SLURs by Ferd Frederix 6-7-2013 // modified by: Donjr Spiegelblatt (May 17, 2012) //add support for: // multi-users of the menu system at the same time // Cancel button when only one menu is used // suppot for comment lines in Data starting with # character //new features: // PrettyButton layout of the buttons in dialogs // combined placeNames, simNames and locationVectors into a two strided list called places // Script Name: Sim-to-Sim_Pseudo-Teleporter_v31.lsl // 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. /* 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. :-) */ /* ********************************* modified by: Donjr Spiegelblatt (May 17, 2012) add support for: multi-users of the menu system at the same time Cancel button when only one menu is used suppot for comment lines in Data starting with # character new features: PrettyButton layout of the buttons in dialogs combined placeNames, simNames and locationVectors into a two strided list called places ********************************** */ // Modded by Ferd Frederix on 5-30-2013 to run in OpenSim // ******** OPTIONAL SETTINGS ********** string hoverText = "Sim-to-Sim Pseudo Teleporter - click for destinations."; integer menuWait = 30; // How long to wait for the user to pick a menu choice integer menuChannel = -14469; // 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 list menu_users = []; // strided list of menu users // [ // integer MENU_user = 0; // key of this menu user, unique one entry per user integer MENU_handle = 1; // listen handle of this users llListen integer MENU_timeout = 2; // creation time of this dialog integer MENU_curList = 3; // the current page for this user // ]; integer MENU_stride = 4; // Length of one strided of this list // The following are required to read the notecard properly integer notecardLine = 0; key currentDataRequest = NULL_KEY; key notecarduuid = NULL_KEY; integer length; // How many menu pages we have list places; // strided list of Placename and Sim/position string BLANK = " "; // used for filler space(s) in dialogs string Prev = "<< Prev "; string Cancel = "Cancel "; string Next = "Next >> "; list Navigate ; // the full navagation functions // ******** END OF SYSTEM SETTINGS and Globals ********** list PrettyButtons(list options, list utilitybuttons) // from SchmoDialog { // returns a list formatted to that "options" will start in the top left of a dialog, // and "utilitybuttons" will start in the bottom right list spacers; list combined = options + utilitybuttons; while (llGetListLength(combined) % 3 != 0 && llGetListLength(combined) < 12) { spacers += [BLANK]; combined = options + spacers + utilitybuttons; } return llList2List(combined, 9, 11) + llList2List(combined, 6, 8) + llList2List(combined, 3, 5) + llList2List(combined, 0, 2); } advancedMenu(key user, integer curList) { integer StartTimer = (menu_users == []); // check if the timer needs starting integer p = llListFindList(menu_users,[user]); if(~p) // update the returning user's "creation time and curList" menu_users = llListReplaceList( menu_users, [llGetUnixTime(), curList], p + MENU_timeout, p+MENU_curList); else if(llGetListLength(menu_users) > 63) // make sure a listen is aviable { llInstantMessage(user, "Please try again later the system is currently full!"); return; } else // first time menu user open there listen and create there entry menu_users += [user, llListen(menuChannel,"",user,""),llGetUnixTime(), curList]; list buttons = llList2ListStrided(places,0,-1,2); // make a list of only Places list utility = [Cancel]; // user should always have a Cancel option if (length > 1) { // We have more than one page of places. p = 9 * curList; // Figures out the start of the subsection of places to display buttons = llList2List(buttons, p, p+8); // 'buttons' now has one to nine places utility = Navigate; // give full navigation buttons } buttons = PrettyButtons(buttons, utility); // the 'buttons' list also now has other options besides our Places // and the 'utility' button(s) are always on the bottom row. llDialog(user,menuText,buttons,menuChannel); // Sends a dialog to the user with the new improved button list if(StartTimer) llSetTimerEvent(5.0); // how often to check for possible timeouts, low number here would just waste processor time } remove(integer index, string message) { // Close this users Listen llListenRemove(llList2Integer(menu_users, index+MENU_handle)); // Instant message the message to the user llInstantMessage(llList2Key(menu_users, index), message); // delete there menu_users entry menu_users = llDeleteSubList(menu_users, index, index+MENU_stride-1); if(menu_users == []) // if there are no current users llSetTimerEvent(0.0); // stop the timer } default { on_rez(integer param) { llResetScript(); // Resets script on rez } state_entry() { Navigate = [ Prev, Cancel, Next ]; // the full navagation functions llOwnerSay("Initializing..."); llOwnerSay("Reading item data..."); // we start reading the notecard at line 0, the first line specify our initial request if(llGetInventoryType(itemDataNotecard) == INVENTORY_NOTECARD) { notecardLine=0; currentDataRequest = llGetNotecardLine(itemDataNotecard,notecardLine); } else { state configured; // Handle the condition of no Data notecard } } dataserver(key query, string data) { if (query == currentDataRequest) // if we are trying to read the notecard { llOwnerSay(data); currentDataRequest = NULL_KEY; // Prevent a bug that occurs with dataserver events. if (data == EOF) // If it the end of the file { // Define how many pages of entries we have in the places list length = llGetListLength(places) / 2; if(length < 12) length = 1; else length = length / 9 + 1; llOwnerSay ("Done reading data."); state configured; } else { // **** 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! **** data = llStringTrim(data, STRING_TRIM); // remove pesky leading and trailing whitespace if(llGetSubString(data,0,0) != "#" && data != "") // lines starting with # are comments { // We're looking for the | and @ symbol in our data line list psv = llParseString2List(data,["|","@"],[]); if(llGetListLength(psv) == 3) // If we found them { // note: Appending the BLANK make Ignore not a key word string place = llStringTrim(llList2String(psv,0), STRING_TRIM)+BLANK; // make sure it NOT a BLANK or one of the navigation entries if(llListFindList(Navigate+[BLANK], [place]) == -1) // these we don't want { string sim = llDumpList2String(llParseString2List(llStringTrim(llList2String(psv,1), STRING_TRIM), [" "], [""]), "%20"); // into sim erasing all internal spaces and replacing them with %20... there might be a better way to do this // Generate a new temp record entry list tmp = [place, sim+"/"+llStringTrim(llList2String(psv,2), STRING_TRIM)]; // update entry matching on 'place' or append new entry to end of list integer x = llListFindList(llList2ListStrided(places+tmp,0,-1,2),[place])*2; places = llListReplaceList(places, tmp, x, x+1); // We put it here so that it will not add the location unless there are also sim and placeNames. // (donjr) No you put it here as you don't have all the info until this point } } 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 = (integer)data; } } } // Get the next line currentDataRequest = llGetNotecardLine(itemDataNotecard, ++notecardLine); } } } } state configured { on_rez(integer param) { llResetScript(); // Resets script on rez } state_entry() { // collects our notecarduuid as soon as we enter this state notecarduuid = llGetInventoryKey(itemDataNotecard); if (hoverText != "none") llSetText(hoverText, <1.0,1.0,1.0>, 1); // if you want hovertext else llSetText("", <1.0, 1.0, 1.0>, 0); // if you do not want hovertext llWhisper(0, "Ready and waiting."); } changed(integer change) { // We want to reload the Data 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() { integer dietime = llGetUnixTime() - menuWait; // moving backward through the list/array // allows us to delete records without messing up the index. integer index = llGetListLength(menu_users); while(index) { index -= MENU_stride; if(llList2Integer(menu_users, index+MENU_timeout) < dietime) remove(index, "Menu session timed out."); } } touch_start(integer num) { do { --num; advancedMenu(llDetectedKey(num), 0); // Send the user the dialog box, first page } while(num); } listen(integer index,string name,key user,string message) { // this is for the script to follow instructions based on what happens with the menu. index = llListFindList(menu_users,[user]); if(~index) // not sure this will ever fail, but proper Bookkeeping requires it { integer curList = llList2Integer(menu_users, index + MENU_curList); if(message == Prev || message == Next || message == BLANK) { if(message == Prev) { if(curList == 0) // If we're on the first page curList = length - 1; // wrap to the last page else // If we're not on page one curList--; // Go backwards a page } else if(message == Next) curList = (curList + 1) % length; // this takes care of the wraping // else if (message == BLANK) // { } // do nothing here user selected a spacer just redisplay the same menu advancedMenu(user, curList); // Give the user the dialog menu } else { if(message == Cancel) remove(index, "Teleport cancelled."); else { // determine which location we are teleporting to integer loc = llListFindList(llList2ListStrided(places,0,-1,2), [message]); if(~loc) // if it's an actual location { loc *= 2; // convert from Record number to index // Give them the link to click message = "http://slurl.com/secondlife/" + llList2String(places, loc+1); remove(index, "Click this link to teleport to your target location - "+message); } else // on unknown message just give the dialog back to the user advancedMenu(user, curList); // Give the user the dialog menu } } } } }