mission_control.lsl
///////////////////////////////////////////////////////////////////////////
//  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) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueEncode(list data) {
    list k = llList2ListStrided(data, 0, -1, 2);
    list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
    data = [];
    do {
        data += llList2String(k, 0) + "=" + llList2String(v, 0);
        k = llDeleteSubList(k, 0, 0);
        v = llDeleteSubList(v, 0, 0);
    } while(llGetListLength(k) != 0);
    return llDumpList2String(data, "&");
}
 
integer k;
integer script = 8;
list scanMenu = ["• AGENT", "• PASSIVE", "• ACTIVE", "◦ SCRIPTED", "Main Menu"];
string scanName = "";
key scanKey = "";
integer comChannel = 0;
key owner = NULL_KEY;
 
default {
    state_entry() {
        llSetTimerEvent(0);
        owner = llGetOwner();
        comChannel = (integer)("0x8" + llGetSubString(owner, 0, 6));
        llListen(comChannel, "", "", "");
    }
    touch_start(integer num) {
        string objectNames = "ANY";
        if(scanName != "") objectNames = scanName;
        string objectKey = "ANY";
        if(scanKey != "") objectKey = scanKey;
        string objectTypes = llDumpList2String(llDeleteSubList(scanMenu, -1, -1), ", ");
        llDialog(llDetectedKey(0), "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n" + "\nObject or avatar name: " + objectNames + "\nObject or avatar key: " + objectKey + "\nScanning mode: " + objectTypes + "\n", [" ", "⌠ Go! ⌡", " ", "⌠ ⌘ Type ⌡", "⌠ ⎀ Name ⌡", "⌠ ⎀ Key ⌡"], comChannel);
    }
    listen(integer channel, string name, key id, string message) {
        // Scan menu
        if(message == "⌠ ⌘ Type ⌡") {
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        // agent
        if(message == "◦ AGENT") {
            scanMenu = llListReplaceList(scanMenu, (list)"• AGENT", 0, 0);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        if(message == "• AGENT") {
            scanMenu = llListReplaceList(scanMenu, (list)"◦ AGENT", 0, 0);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        // passive
        if(message == "◦ PASSIVE") {
            scanMenu = llListReplaceList(scanMenu, (list)"• PASSIVE", 1, 1);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        if(message == "• PASSIVE") {
            scanMenu = llListReplaceList(scanMenu, (list)"◦ PASSIVE", 1, 1);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        // active
        if(message == "◦ ACTIVE") {
            scanMenu = llListReplaceList(scanMenu, (list)"• ACTIVE", 2, 2);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        if(message == "• ACTIVE") {
            scanMenu = llListReplaceList(scanMenu, (list)"◦ ACTIVE", 2, 2);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        // scripted
        if(message == "◦ SCRIPTED") {
            scanMenu = llListReplaceList(scanMenu, (list)"• SCRIPTED", 3, 3);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
        if(message == "• SCRIPTED") {
            scanMenu = llListReplaceList(scanMenu, (list)"◦ SCRIPTED", 3, 3);
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", scanMenu, comChannel);
            return;
        }
 
        // scan for name
        if(message == "⌠ ⎀ Name ⌡") {
            llTextBox(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", channel+1);
            llListen(channel+1, "", "", "");
            return;
        }
        if(channel == comChannel + 1) {
            scanName = message;
            string objectNames = "ANY";
            if(scanName != "") objectNames = scanName;
            string objectKey = "ANY";
            if(scanKey != "") objectKey = scanKey;
            string objectTypes = llDumpList2String(llDeleteSubList(scanMenu, -1, -1), ", ");
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n" + "\nObject or avatar name: " + objectNames + "\nObject or avatar key: " + objectKey + "\nScanning mode: " + objectTypes + "\n", [" ", "⌠ Go! ⌡", " ", "⌠ ⌘ Type ⌡", "⌠ ⎀ Name ⌡", "⌠ ⎀ Key ⌡"], comChannel);
            return;
        }
        if(message == "⌠ ⎀ Key ⌡") {
            llTextBox(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n", channel-1);
            llListen(channel-1, "", "", "");
            return;
        }
        if(channel == comChannel - 1) {
            scanKey = message;
            string objectNames = "ANY";
            if(scanName != "") objectNames = scanName;
            string objectKey = "ANY";
            if(scanKey != "") objectKey = scanKey;
            string objectTypes = llDumpList2String(llDeleteSubList(scanMenu, -1, -1), ", ");
            llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n" + "\nObject or avatar name: " + objectNames + "\nObject or avatar key: " + objectKey + "\nScanning mode: " + objectTypes + "\n", [" ", "⌠ Go! ⌡", " ", "⌠ ⌘ Type ⌡", "⌠ ⎀ Name ⌡", "⌠ ⎀ Key ⌡"], comChannel);
            return;
        }
 
        // start scan
        if(message == "⌠ Go! ⌡") state scan;
 
        // main menu
        if(message != "Main Menu" && message != "") return;
        string objectNames = "ANY";
        if(scanName != "") objectNames = scanName;
        string objectKey = "ANY";
        if(scanKey != "") objectKey = scanKey;
        string objectTypes = llDumpList2String(llDeleteSubList(scanMenu, -1, -1), ", ");
        llDialog(id, "\n            Welcome to the Region Scanner.\nCreated in 2014 by Wizardry and Steamworks\n                 16 April 2014: Version: 1.0\n\n" + "\nObject or avatar name: " + objectNames + "\nObject or avatar key: " + objectKey + "\nScanning mode: " + objectTypes + "\n", [" ", "⌠ Go! ⌡", " ", "⌠ ⌘ Type ⌡", "⌠ ⎀ Name ⌡", "⌠ ⎀ Key ⌡"], comChannel);
    }
    on_rez(integer num) {
        llResetScript();
    }
}
 
state scan {
    state_entry() {
        llSetTimerEvent(0);
        llInstantMessage(owner, "Starting scan... Please wait or touch to abort...");
        script = 8;
        list mp = [ 42.5,  42.5, 127.5,  42.5, 212.5, 42.5,
                    42.5, 127.5, 127.5, 127.5, 212.5, 127.5,
                    42.5, 212.5, 127.5, 212.5, 212.5, 212.5 ];
        do {
            llRezObject("p",
                llGetPos() + <0, 0, 1.5>,
                ZERO_VECTOR,
                ZERO_ROTATION,
                llList2Integer(mp, 0) << 16 | llList2Integer(mp, 1)
            );
            mp = llDeleteSubList(mp, 0, 1);
        } while(llGetListLength(mp));
        integer scanMask = 0;
        if(llList2String(scanMenu, 0) == "• AGENT") scanMask = scanMask | AGENT;
        if(llList2String(scanMenu, 1) == "• PASSIVE") scanMask = scanMask | PASSIVE;
        if(llList2String(scanMenu, 2) == "• ACTIVE") scanMask = scanMask | ACTIVE;
        if(llList2String(scanMenu, 3) == "• SCRIPTED") scanMask = scanMask | SCRIPTED;
        list scanData = [ "scan", (string)scanMask ];
        if(scanName != "") scanData += [ "name", scanName ];
        if(scanKey != "") scanData += [ "uuid", scanKey ];
        k = comChannel/2;
        llListen(comChannel, "", "", "");
        llRegionSay((integer)("0x8" + llGetSubString(owner, 0, 6)), wasKeyValueEncode(scanData));
        llSetTimerEvent(60);
    }
    listen(integer channel, string name, key id, string message) {
        vector o = (vector)wasKeyValueGet("position", message);
        llMessageLinked(LINK_THIS, 
            script-- << 16 | k--, 
            (string)(llGetPos() + <0.99*o.x/255.0 - 0.495, 0.99*o.y/255.0 - 0.495, o.z/4096.0 + 0.01>), 
            message
        );
        if(script < 1) script = 8;
    }
    touch_start(integer num) {
        llInstantMessage(owner, "Scan aborted...");
        llRegionSay((integer)("0x8" + llGetSubString(owner, 0, 6)), "die");
        state default;
    }
    timer() {
        llInstantMessage(owner, "Scan complete...");
        state default;
    }
    on_rez(integer num) {
        llResetScript();
    }
}