/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2014 - 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) 2015 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// 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: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// 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 cut = 11-wasListCountExclude(actions, [""]); if(direction == ">" && (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) { ++wasMenuIndex; jump slice; } if(direction == "<" && wasMenuIndex-1 >= 0) { --wasMenuIndex; jump slice; } @slice; integer multiple = wasMenuIndex*cut; input = llList2List(input, multiple+wasMenuIndex, multiple+cut+wasMenuIndex); input = wasListMerge(input, actions, ""); return input; } /////////////////////////////////////////////////////////////////////////// // 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); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// list wasListMerge(list l, list m, string merge) { if(llGetListLength(l) == 0 && llGetListLength(m) == 0) return []; string a = llList2String(m, 0); if(a != merge) return [ a ] + wasListMerge(l, llDeleteSubList(m, 0, 0), merge); return [ llList2String(l, 0) ] + wasListMerge(llDeleteSubList(l, 0, 0), llDeleteSubList(m, 0, 0), merge); } list names = []; list safe_names = []; list coord = []; key sit = NULL_KEY; string firstname = ""; string selected = "false"; integer line = 0; string destName = ""; vector dest = ZERO_VECTOR; integer seconds = 30; default { state_entry() { // set the origin llSetObjectDesc(wasKeyValueSet("origin", (string)llGetPos(), llGetObjectDesc())); // clear sit position and action llSetClickAction(CLICK_ACTION_NONE); llSitTarget(ZERO_VECTOR,ZERO_ROTATION); // read the destination notecard if(llGetInventoryType("destinations") != INVENTORY_NOTECARD) { llOwnerSay("Failed to find destinations notecard in inventory.\nPlease add a notecard containing the destinations"); return; } llSetText("Reading destinations.", <1, 1, 0>, 1.0); llGetNotecardLine("destinations", line); } dataserver(key id, string data) { if(data == EOF) { llSetText("Read destinations.", <1, 0, 0>, 1.0); // check for consistency if(llGetListLength(names) != llGetListLength(coord)) { llSetText("Error reading destinations.", <1, 0, 0>, 1.0); llSetTimerEvent(1); return; } state select; return; } if(data == "") jump next_line; list dc = llParseString2List(data, ["#"], []); names += llList2String(dc, 0); coord += (vector)llList2String(dc, 1); @next_line; llGetNotecardLine("destinations", ++line); } timer() { llResetScript(); } changed(integer change) { llResetScript(); } on_rez(integer num) { llResetScript(); } } state select { state_entry() { llSetText("Touch me to select a destination.", <0, 1, 0>, 1.0); } touch_start(integer total_numer) { key click = llDetectedKey(0); // check if the teleport is locked to owner or unlocked if(wasKeyValueGet("lock", llGetObjectDesc()) == "true" && click != llGetOwner()) return; // block if teleporter is in use if(sit != NULL_KEY && click != sit) return; // grab user key and name sit = click; firstname = llList2String(llParseString2List(llDetectedName(0), [" "], []), 0); // display overhead text and set the countdown llSetText(firstname + " is using the teleporter (" + (string)seconds + ").", <1, 1, 0>, 1.0); llSetTimerEvent(1); // generate the list of destinations and send the dialog integer channel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6)); llListen(channel, "", sit, ""); integer i = llGetListLength(names)-1; safe_names = []; do { safe_names += llGetSubString(llList2String(names, i), 0, 8); } while(--i>-1); llDialog(sit, "Choose a destination to teleport to from the provided list of destinations.", wasDialogMenu(safe_names, ["⟵ Back", "◉ Options", "Next ⟶"], ""), channel); } listen(integer channel, string name, key id, string message) { if(message == "⟵ Back") { llDialog(sit, "Choose a destination to teleport to from the provided list of destinations.", wasDialogMenu(safe_names, ["⟵ Back", "◉ Options", "Next ⟶"], "<"), channel); return; } if(message == "Next ⟶") { llDialog(sit, "Choose a destination to teleport to from the provided list of destinations.", wasDialogMenu(safe_names, ["⟵ Back", "◉ Options", "Next ⟶"], ">"), channel); return; } if(message == "◉ Options") { message = "Here you can toggle the teleporter so it is restricted to the owner or not."; if(wasKeyValueGet("lock", llGetObjectDesc()) != "false") { message += "\n\nThe teleporter is currently locked to the owner."; jump set_message; } message += "\n\nThe teleporter is currently unlocked."; @set_message; llDialog(sit, message, ["✗ Lock", "✔ Unlock", "⏏ Exit"], channel); return; } if(message == "✗ Lock") { llSetObjectDesc(wasKeyValueSet("lock", "true", llGetObjectDesc())); llDialog(sit, "Here you can toggle the teleporter so it is restricted to the owner or not.\n\nThe teleporter is currently locked to the owner.", ["✗ Lock", "✔ Unlock", "⏏ Exit"], channel); return; } if(message == "✔ Unlock") { llSetObjectDesc(wasKeyValueSet("lock", "false", llGetObjectDesc())); llDialog(sit, "Here you can toggle the teleporter so it is restricted to the owner or not.\n\nThe teleporter is currently unlocked.", ["✗ Lock", "✔ Unlock", "⏏ Exit"], channel); return; } if(message == "⏏ Exit") { llDialog(sit, "Choose a destination to teleport to from the provided list of destinations.", wasDialogMenu(safe_names, ["⟵ Back", "◉ Options", "Next ⟶"], ""), channel); return; } do { destName = llList2String(names, 0); if(llSubStringIndex(destName, message) != -1) { dest = llList2Vector(coord, 0); jump ready; } names = llDeleteSubList(names, 0, 0); coord = llDeleteSubList(coord, 0, 0); } while(llGetListLength(names) != 0); llSetText("Could not find destination.", <1, 0, 0>, 1.0); seconds = 1; return; @ready; selected = "true"; seconds = 10; llSitTarget(<0,0,1>,ZERO_ROTATION); llSetClickAction(CLICK_ACTION_SIT); } changed(integer change) { if(change & CHANGED_LINK) { key a = llAvatarOnSitTarget(); if(a) if(a == sit) state teleport; llUnSit(a); return; } llResetScript(); } timer() { if(selected == "true") { llSetText(firstname + ", touch to teleport to " + destName + " (" + (string)seconds + ").", <1, 1, 0>, 1.0); jump continue; } if(selected == "false") { llSetText(firstname + " is using the teleporter (" + (string)seconds + ").", <1, 1, 0>, 1.0); jump continue; } @continue; if(--seconds == 0) llResetScript(); } on_rez(integer num) { llResetScript(); } } state teleport { state_entry() { // set timeout llSetTimerEvent(10); // clear sit position and action llSetRegionPos(dest); // request to set camera llRequestPermissions(sit, PERMISSION_CONTROL_CAMERA); } run_time_permissions(integer perm) { // set the camera so the viewer follows the agent // this works if the viewer is not zoomed-in on // the teleport pad if(perm & PERMISSION_CONTROL_CAMERA) { llSetCameraParams([ CAMERA_ACTIVE, 1, CAMERA_BEHINDNESS_ANGLE, 45.0, CAMERA_BEHINDNESS_LAG, 0.5, CAMERA_DISTANCE, 8.0, CAMERA_FOCUS_LAG, 0.05 , CAMERA_FOCUS_LOCKED, TRUE, CAMERA_FOCUS_THRESHOLD, 0.0, CAMERA_PITCH, 20.0, CAMERA_POSITION_LAG, 0.1, CAMERA_POSITION_LOCKED, TRUE, CAMERA_POSITION_THRESHOLD, 0.0, CAMERA_FOCUS_OFFSET, <3,0,2> ]); llReleaseCamera(sit); } llSetTimerEvent(0.05); } timer() { key a = llAvatarOnSitTarget(); if(a) llUnSit(a); llSetRegionPos((vector)wasKeyValueGet("origin", llGetObjectDesc())); } on_rez(integer num) { llSetRegionPos((vector)wasKeyValueGet("origin", llGetObjectDesc())); llResetScript(); } changed(integer change) { llSetRegionPos((vector)wasKeyValueGet("origin", llGetObjectDesc())); llResetScript(); } }