bluebird.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) 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);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasProgress(integer percent, integer length, list symbols) {
    percent /= (integer)((float)100.0/(length));
    string p = llList2String(symbols,0);
    integer itra = 0;
    do {
        if(itra>percent-1) p += llList2String(symbols,2);
        else p += llList2String(symbols,1);
    } while(++itra<length);
    return p + llList2String(symbols,3);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
vector wasPercentToGradient(float percent, string rgb) {
    if(llStringLength(rgb) != 2) {
        llSay(DEBUG_CHANNEL, "Assert failed, rgb parameter must consist of a pair of either r, g, or b.");
        return ZERO_VECTOR;
    }
    string a = llGetSubString(rgb, 0, 0);
    string b = llGetSubString(rgb, 1, 1);
    list col = [ "r", "g", "b" ];
    integer ax = llListFindList(col, (list)a);
    integer bx = llListFindList(col, (list)b);
    if(ax == -1 || bx == -1) {
        llSay(DEBUG_CHANNEL, "Asset failed, rgb parameters must contain either r, g, or b letters.");
        return ZERO_VECTOR;
    }
    col = llListReplaceList(col, (list)((100-percent)/100), ax, ax);
    col = llListReplaceList(col, (list)(percent/100), bx, bx);
    return 2*<llList2Float(col, 0), llList2Float(col, 1), llList2Float(col, 2)>;
}
 
ABS(key id) {
    if(id != NULL_KEY && llGetAttached() != 0) {
        vector n = llList2Vector(llGetLinkPrimitiveParams(6, [PRIM_COLOR, ALL_SIDES]), 0);
        llOwnerSay("@setenv_ambientr:" + (string)n.x + "=force");
        llOwnerSay("@setenv_ambientg:" + (string)n.y + "=force");
        llOwnerSay("@setenv_ambientb:" + (string)n.z + "=force");
        return;
    }
    llOwnerSay("@setenv_daytime:-1=force");
}
 
integer i = 0;
integer channel = 0;
key toucher = NULL_KEY;
 
default {
    state_entry() {
        // LID™ reasoning - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
        // if LID™, then login = 1
        // else login = 0 - script running | parameter undefined
        if((integer)wasKeyValueGet("login", llGetObjectDesc()) > 0) {
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            state check;
            return;
        }
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
        state check;
    }
    // LID™ reasoning - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
    // order: on_rez -> attach
    //
    // if object attached, then login := login+1
    // else login := -1
    attach(key id) {
        // attached
        if(id != NULL_KEY && llGetAttached() != 0) {
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", (string)((integer)wasKeyValueGet("login", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))+1), llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            // Reset script for llGetCreator() bugture.
            llResetScript();
        }
        // detached
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "-1", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
    }
    // login = 1 after object attached
    //       = -1 after object detached
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        llResetScript();
    }
}
 
state check {
    state_entry() {
        // alarm for seekng RLV
        llSetTimerEvent(25);
        integer channel = 10+(integer)llFrand(10);
        llListen(channel, "", llGetOwner(), "");
        llOwnerSay("@version=" + (string)channel);
    }
    timer() {
        llSetTimerEvent(0);
        // alarm triggered, we don't have RLV
        llOwnerSay("This gizmo requires a RLV-enabled viewer.");
        return;
    }
    listen(integer channel, string name, key id, string message) {
        llSetTimerEvent(0);
        // we have RLV
        state glasses;
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        llResetScript();
    }
    // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
    attach(key id) { ABS(id); }
}
 
state glasses {
    state_entry() {
        if(wasKeyValueGet("auto", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "on") llSensorRepeat("", "", AGENT, 3, TWO_PI, 3);
        ABS(llGetOwner());
        if(toucher == NULL_KEY) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2\n\nAuto Tilt: " + wasKeyValueGet("auto", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)), ["⬆ Up", "⬇ Down", "⎙ Options"], channel);
    }
    touch_start(integer total_number) {
        toucher = llDetectedKey(0);
        channel = (integer)("0x8" + llGetSubString(toucher, 0, 6));
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2\n\nAuto Tilt: " + wasKeyValueGet("auto", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)), ["⬆ Up", "⬇ Down", "⎙ Options"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⬆ Up") {
            if(wasKeyValueGet("status", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "up") return;
            llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
            llSetTimerEvent(.5);
            llListenRemove(i);
            return;
        }
        if(message == "⬇ Down") {
            if(wasKeyValueGet("status", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "down") return;
            llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
            llSetTimerEvent(.5);
            llListenRemove(i);
            return;
        }
// REGION: OWNER
        if(toucher != llGetOwner()) {
            llInstantMessage(toucher, "Sorry, this option is restricted to the owner.");
            llListenRemove(i);
            return;
        }
        if(message == "⎙ Options") state options;
// REGION: OWNER
    }
    sensor(integer num) {
        if(wasKeyValueGet("status", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "up") return;
        llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
        llSetTimerEvent(.5);
    }
    no_sensor() {
        if(wasKeyValueGet("status", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "down") return;
        llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
        llSetTimerEvent(.5);
    }
    run_time_permissions(integer perm) {
        if(!(perm & PERMISSION_TRIGGER_ANIMATION)) return;
        if(llGetInventoryType("Glasses") != INVENTORY_ANIMATION) return;
        llStartAnimation("Glasses");
    }
    timer() {
        if(wasKeyValueGet("status", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)) == "up") {
            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, ZERO_ROTATION, PRIM_POS_LOCAL, llGetLocalPos() - (vector)(wasKeyValueGet("tilt", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)))]);
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("status", "down", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            jump reset;
        }
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, llEuler2Rot(<0,-50,0>*DEG_TO_RAD), PRIM_POS_LOCAL, llGetLocalPos() + (vector)(wasKeyValueGet("tilt", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)))]);
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("status", "up", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
@reset;
        llResetScript();
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state options {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "⎙ Color", "⎙ Opacity", "⎙ Bright", "⎙ Glow", "⎙ Size", "⎙ Adjust Tilt", "⎙ Auto Tilt"], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "⎙ Color", "⎙ Opacity", "⎙ Bright", "⎙ Glow", "⎙ Size", "⎙ Adjust Tilt", "⎙ Auto Tilt"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⏏ Exit") state glasses;
        if(message == "⎙ Color") state color;
        if(message == "⎙ Opacity") state opacity;
        if(message == "⎙ Bright") state bright;
        if(message == "⎙ Glow") state glow;
        if(message == "⎙ Size") state size;
        if(message == "⎙ Adjust Tilt") state tilt;
        if(message == "⎙ Auto Tilt") state auto;
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state color {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["R ▼", "G ▼", "B ▼", "R ▲", "G ▲", "B ▲", "⏏ Exit"], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["R ▼", "G ▼", "B ▼", "R ▲", "G ▲", "B ▲", "⏏ Exit"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⏏ Exit") state options;
        list params = llGetLinkPrimitiveParams(7, [PRIM_COLOR, ALL_SIDES]);
        vector color = llList2Vector(params, 0);
        float alpha = llList2Float(params, 1);
        vector n = ZERO_VECTOR;
        if(message == "R ▼") {
            n = color-<.1,0,0>;
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            jump menu;
        }
        if(message == "R ▲") {
            n = color+<.1,0,0>;
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            jump menu;
        }
        if(message == "G ▼") {
            n = color-<0,.1,0>;
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            jump menu;
        }
        if(message == "G ▲") {
            n = color+<0,.1,0>;
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            jump menu;
        }
        if(message == "B ▼") {
            n = color-<0,0,.1>;
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            jump menu;
        }
        if(message == "B ▲") {
            n = color+<0,0,.1>;
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, n, alpha]);
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, n, alpha]);
        }
@menu;
        llOwnerSay("@setenv_ambientr:" + (string)n.x + "=force");
        llOwnerSay("@setenv_ambientg:" + (string)n.y + "=force");
        llOwnerSay("@setenv_ambientb:" + (string)n.z + "=force");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["R ▼", "G ▼", "B ▼", "R ▲", "G ▲", "B ▲", "⏏ Exit"], channel);
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state opacity {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "Opacity ▼", "Opacity ▲"], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "Opacity ▼", "Opacity ▲"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⏏ Exit") state options;
        list params = llGetLinkPrimitiveParams(7, [PRIM_COLOR, ALL_SIDES]);
        vector color = llList2Vector(params, 0);
        float alpha = llList2Float(params, 1);
        if(message == "Opacity ▼") {
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, color, alpha-.1]);
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, color, alpha-.1]);
            jump menu;
        }
        if(message == "Opacity ▲") {
            llSetLinkPrimitiveParamsFast(7, [PRIM_COLOR, ALL_SIDES, color, alpha+.1]);
            llSetLinkPrimitiveParamsFast(6, [PRIM_COLOR, ALL_SIDES, color, alpha+.1]);
            jump menu;
        }
@menu;
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "Opacity ▼", "Opacity ▲"], channel);
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state bright {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "◉ ON", "◯ OFF"], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "◉ ON", "◯ OFF"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⏏ Exit") state options;
        if(message == "◉ ON") {
            llSetLinkPrimitiveParamsFast(7, [PRIM_FULLBRIGHT, ALL_SIDES, TRUE]);
            llSetLinkPrimitiveParamsFast(6, [PRIM_FULLBRIGHT, ALL_SIDES, TRUE]);
            jump menu;
        }
        if(message == "◯ OFF") {
            llSetLinkPrimitiveParamsFast(7, [PRIM_FULLBRIGHT, ALL_SIDES, FALSE]);
            llSetLinkPrimitiveParamsFast(6, [PRIM_FULLBRIGHT, ALL_SIDES, FALSE]);
        }
@menu;
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "◉ ON", "◯ OFF"], channel);
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state glow {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "Glow ▼", "Glow ▲"], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "Glow ▼", "Glow ▲"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⏏ Exit") state options;
        list params = llGetLinkPrimitiveParams(7, [PRIM_GLOW, ALL_SIDES]);
        float glow = llList2Float(params, 0);
        if(message == "Glow ▼") {
            if(glow - .01 < 0) jump menu;
            llSetLinkPrimitiveParamsFast(7, [PRIM_GLOW, ALL_SIDES, glow-.01]);
            llSetLinkPrimitiveParamsFast(6, [PRIM_GLOW, ALL_SIDES, glow-.01]);
            jump menu;
        }
        if(message == "Glow ▲") {
            if(glow + .01 > 1) jump menu;
            llSetLinkPrimitiveParamsFast(7, [PRIM_GLOW, ALL_SIDES, glow+.01]);
            llSetLinkPrimitiveParamsFast(6, [PRIM_GLOW, ALL_SIDES, glow+.01]);
            jump menu;
        }
@menu;
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["⏏ Exit", "Glow ▼", "Glow ▲"], channel);
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state size {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["-.01", "-.02", "-.05", "+.01", "+.02", "+.05", "⏏ Exit"], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["-.01", "-.02", "-.05", "+.01", "+.02", "+.05", "⏏ Exit"], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "⏏ Exit") state options;
        if((float)message == 0) return;
        float scale = 1 + (float)message;
        integer i = llGetNumberOfPrims();
        do {
            vector linkScale = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]), 0);
            vector linkPos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POS_LOCAL]), 0);
            llSetLinkPrimitiveParamsFast(i, [PRIM_SIZE, scale * linkScale, PRIM_POSITION, scale * linkPos]);
        } while(--i>1);
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2", ["-.01", "-.02", "-.05", "+.01", "+.02", "+.05", "⏏ Exit"], channel);
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state tilt {
    state_entry() {
        llListen(channel, "", toucher, "");
        llTextBox(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2\n\n This menu lets you adjust the displacement vector when the glasses are put up. Current tilt adjustment vector: " + (string)((vector)(wasKeyValueGet("tilt", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0)))), channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        state options;
    }
    listen(integer channel, string name, key toucher, string message) {
        vector tilt = (vector)message;
        if(tilt == ZERO_VECTOR) {
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("tilt", "<.02,0,.04>", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            jump main;
        }
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("tilt", (string)tilt, llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
@main;
        state glasses;
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}
 
state auto {
    state_entry() {
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2\n\nTurning this option on will automatically tilt the glasses up once you are standing close to an avatar and put them back down again when you move away from avatars.", ["⏏ Exit", "◉ ON", "◯ OFF" ], channel);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llListen(channel, "", toucher, "");
        llDialog(toucher, "\n            Welcome to the Bluebird Glasses.\nCreated in 2014 by Wizardry and Steamworks\n                 9 May 2014: Version: 1.2\n\nTurning this option on will automatically tilt the glasses up once you are standing close to an avatar and put them back down again when you move away from avatars.", ["⏏ Exit", "◉ ON", "◯ OFF" ], channel);
    }
    listen(integer channel, string name, key toucher, string message) {
        if(message == "◉ ON") {
            llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("auto", "on", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
            jump options;
        }
        if(message == "◯ OFF") llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("auto", "off", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
@options;
        state options;
    }
    on_rez(integer num) {
        llResetScript();
    }
 
    attach(key id) { ABS(id); }
}