/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2021 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueEncode(list data) { integer i = llGetListLength(data); if (i % 2 != 0 || i == 0) return ""; --i; do { data = llListInsertList( llDeleteSubList( data, i-1, i ), [ llList2String(data, i-1) + "=" + llList2String(data, i) ], i-1 ); i -= 2; } while(i > 0); return llDumpList2String(data, "&"); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueGet(string k, string data) { if(llStringLength(data) == 0) return ""; if(llStringLength(k) == 0) return ""; list a = llParseStringKeepNulls(data, ["&", "="], []); integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); if(i != -1) return llList2String(a, 2*i+1); return ""; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueSet(string k, string v, string data) { if(llStringLength(k) == 0) return ""; if(llStringLength(v) == 0) return ""; if(llStringLength(data) == 0) return k + "=" + v; integer i = llListFindList( llList2ListStrided( llParseString2List(data, ["&", "="], []), 0, -1, 2 ), [ k ]); if(i != -1) return llDumpList2String( llListReplaceList( llParseString2List(data, ["&"], []), [ k + "=" + v ], i, i), "&"); return data + "&" + k + "=" + v; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// integer wasMenuIndex = 0; list wasDialogMenu(list input, list actions, string direction) { integer x = 11-wasListCountExclude(actions, [""]); if(direction == ">" && (wasMenuIndex+1)*x+wasMenuIndex+1 < llGetListLength(input)) { ++wasMenuIndex; jump slice; } if(direction == "<" && wasMenuIndex-1 >= 0) { --wasMenuIndex; jump slice; } @slice; integer m = wasMenuIndex*x; return wasListMerge( wasDialogSort( llList2List( input, m+wasMenuIndex, m+x+wasMenuIndex ), "" ), actions, "", " " ); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// list wasDialogSort(list input, string pad) { input = llList2List( input + [ pad, pad, pad, pad, pad, pad, pad, pad, pad, pad, pad, pad ], 0, 12 ); return llList2List(input, 9, 11) + llList2List(input, 6, 8) + llList2List(input, 3, 5) + llList2List(input, 0, 2); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// list wasListMerge(list a, list b, string merge, string pad) { if(llGetListLength(a) == 0 && llGetListLength(b) == 0) return []; string af = llList2String(a, 0); a = llDeleteSubList(a, 0, 0); string bf = llList2String(b, 0); b = llDeleteSubList(b, 0, 0); if(af != merge && bf == merge) return [ af ] + wasListMerge(a, b, merge, pad); if(af == merge && bf != merge) return [ bf ] + wasListMerge(a, b, merge, pad); if(af != merge && bf != merge) return [ af, bf ] + wasListMerge(a, b, merge, pad); // assert: af == merge && bf == merge return [ pad ] + wasListMerge(a, b, merge, pad); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// integer wasListCountExclude(list input, list exclude) { if(llGetListLength(input) == 0) return 0; if(llListFindList(exclude, (list)llList2String(input, 0)) == -1) return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude); return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude); } list destinationNames = []; list safe_destinationNames = []; list coordinates = []; key sitting = NULL_KEY; string firstname = ""; integer selected = FALSE; integer line = 0; string destinationName = ""; vector destination = ZERO_VECTOR; integer timeout = 30; integer dish_channel = 0; default { state_entry() { // set the overhead text mode if(wasKeyValueGet("text", llGetObjectDesc()) == "false") { llSetText("", <0, 0, 0>, 0.0); } // read the destination notecard if(llGetInventoryType(llGetInventoryName(INVENTORY_NOTECARD, 0)) != INVENTORY_NOTECARD) { llOwnerSay("Failed to find a \"Destinations\" notecard in the teleporter inventory.\nPlease add a notecard containing destinations."); return; } if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText("Reading destinations.", <1, 1, 0>, 1.0); } llGetNotecardLine( llGetInventoryName(INVENTORY_NOTECARD, 0), line ); } dataserver(key id, string data) { if(data == EOF) { if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText("Read destinations.", <1, 0, 0>, 1.0); } // check for consistency if(llGetListLength(destinationNames) != llGetListLength(coordinates)) { if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText("Error reading destinations. Restarting...", <1, 0, 0>, 1.0); } llSetTimerEvent(1); return; } state select; return; } if(data == "") { llGetNotecardLine( llGetInventoryName(INVENTORY_NOTECARD, 0), ++line ); return; } list teleport = llParseString2List(data, ["#"], []); destinationNames += llStringTrim( llList2String(teleport, 0), STRING_TRIM ); coordinates += (vector)llStringTrim( llList2String(teleport, 1), STRING_TRIM ); llGetNotecardLine( llGetInventoryName(INVENTORY_NOTECARD, 0), ++line ); } timer() { llResetScript(); } changed(integer change) { llResetScript(); } on_rez(integer num) { llResetScript(); } } state select { state_entry() { if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText("Touch me to select a destination.", <0, 1, 0>, 1.0); } dish_channel = (integer)("0x8" + llGetSubString(llGetOwner(), 0, 6)); llListen(dish_channel, "", "", ""); } touch_start(integer total_numer) { key click = llDetectedKey(0); // check if the device is locked if((wasKeyValueGet("lock", llGetObjectDesc()) == "true" && click != llGetOwner()) || (wasKeyValueGet("group", llGetObjectDesc()) == "true" && llDetectedGroup(0) == FALSE)) { return; } // block if teleporter is in use if(sitting != NULL_KEY && click != sitting) { return; } // grab user key and name sitting = click; firstname = llList2String( llParseString2List( llDetectedName(0), [ " " ], [] ), 0 ); // display overhead text and set the countdown if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText(firstname + " is using the teleporter [" + (string)timeout + "s].", <1, 1, 0>, 1.0); } llSetTimerEvent(1); // generate the list of destinations and send the dialog integer s = llGetListLength(destinationNames); integer i = 0; safe_destinationNames = []; do { safe_destinationNames += llGetSubString( `llList2String( destinationNames, i ), 0, 8 ); } while(++i < s); integer channel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6)); llListen(channel, "", sitting, ""); llDialog( sitting, "Choose a destination to teleport to from the provided list of destinations or select \"✖︎ Abort\" to cancel the selection.", wasDialogMenu( safe_destinationNames, [ "⟵ Back", "◉ Options", "Next ⟶", "", "", "✖︎ Abort" ], "" ), channel ); } listen(integer channel, string name, key id, string message) { // dish message if(message == "OK") { llResetScript(); } if(message == "⏏ Exit") { llDialog( sitting, "Choose a destination to teleport to from the provided list of destinations or select \"✖︎ Abort\" to cancel the selection.", wasDialogMenu( safe_destinationNames, [ "⟵ Back", "◉ Options", "Next ⟶", "", "", "✖︎ Abort" ], "" ), channel ); return; } if(message == "✖︎ Abort") { llWhisper(dish_channel, "DIE"); llResetScript(); } if(message == "⟵ Back") { llDialog( sitting, "Choose a destination to teleport to from the provided list of destinations or select \"✖︎ Abort\" to cancel the selection.", wasDialogMenu( safe_destinationNames, [ "⟵ Back", "◉ Options", "Next ⟶", "", "", "✖︎ Abort" ], "<" ), channel ); return; } if(message == "Next ⟶") { llDialog( sitting, "Choose a destination to teleport to from the provided list of destinations or select \"✖︎ Abort\" to cancel the selection.", wasDialogMenu( safe_destinationNames, [ "⟵ Back", "◉ Options", "Next ⟶", "", "", "✖︎ Abort" ], ">" ), channel ); return; } // restrict the options menu to the owner of the dish list options = ["◉ Options", "◯ Owner", "◉ Owner", "◯ Group", "◉ Group", "◯ Text", "◉ Text" ]; if(id == llGetOwner() && llListFindList(options, [ message ]) != -1) { if(message == "◯ Owner") { llSetObjectDesc(wasKeyValueSet("lock", "true", llGetObjectDesc())); } if(message == "◉ Owner") { llSetObjectDesc(wasKeyValueSet("lock", "false", llGetObjectDesc())); } if(message == "◯ Group") { llSetObjectDesc(wasKeyValueSet("group", "true", llGetObjectDesc())); } if(message == "◉ Group") { llSetObjectDesc(wasKeyValueSet("group", "false", llGetObjectDesc())); } if(message == "◯ Text") { llSetObjectDesc(wasKeyValueSet("text", "true", llGetObjectDesc())); } if(message == "◉ Text") { llSetObjectDesc(wasKeyValueSet("text", "false", llGetObjectDesc())); } options = [ "⏏ Exit" ]; message = "Here you can toggle the teleporter so it is restricted to the owner, group or free for all.\n\n"; if(wasKeyValueGet("group", llGetObjectDesc()) != "false") { message += "The teleporter is currently locked to the group.\n"; options += "◉ Group"; } if(wasKeyValueGet("group", llGetObjectDesc()) != "true") { message += "The teleporter is currently not locked to the group.\n"; options += "◯ Group"; } if(wasKeyValueGet("lock", llGetObjectDesc()) != "false") { message += "The teleporter is currently locked to the owner.\n"; options += "◉ Owner"; } if(wasKeyValueGet("lock", llGetObjectDesc()) != "true") { message += "The teleporter is currently not locked to the owner.\n"; options += "◯ Owner"; } if(wasKeyValueGet("text", llGetObjectDesc()) != "false") { message += "The teleporter will display overhead text.\n"; options += "◉ Text"; } if(wasKeyValueGet("text", llGetObjectDesc()) != "true") { message += "The teleporter will not display overhead text.\n"; options += "◯ Text"; } llDialog(sitting, message, options, channel); return; } // remenu on dud messages if(llListFindList(safe_destinationNames, (list)message) == -1) { llDialog( sitting, "Choose a destination to teleport to from the provided list of destinations or select \"✖︎ Abort\" to cancel the selection.", wasDialogMenu( safe_destinationNames, [ "⟵ Back", "◉ Options", "Next ⟶", "", "", "✖︎ Abort" ], "" ), channel ); return; } integer i = llGetListLength(destinationNames)-1; do { destinationName = llList2String(destinationNames, i); if(llSubStringIndex(destinationName, message) != -1) { destination = llList2Vector(coordinates, i); selected = TRUE; timeout = 10; vector position = llGetPos(); llWhisper(dish_channel, "DIE"); llRezObject( llGetInventoryName(INVENTORY_OBJECT, 0), , ZERO_VECTOR, ZERO_ROTATION, 0 ); llWhisper( dish_channel, wasKeyValueEncode( [ "destination", destination, "avatar", sitting ] ) ); return; } } while(--i>-1); if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText("Could not find destination.", <1, 0, 0>, 1.0); } llResetScript(); } changed(integer change) { llResetScript(); } timer() { if(selected == TRUE) { if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText(firstname + ", touch to teleport to \"" + destinationName + "\" [" + (string)timeout + "s].", <1, 1, 0>, 1.0); } llWhisper( dish_channel, wasKeyValueEncode( [ "destination", destination, "avatar", sitting ] ) ); if(--timeout == 0) { llResetScript(); } return; } if(wasKeyValueGet("text", llGetObjectDesc()) == "true") { llSetText(firstname + " is using the teleporter [" + (string)timeout + "s].", <1, 1, 0>, 1.0); } if(--timeout == 0) { llResetScript(); } } on_rez(integer num) { llResetScript(); } }