/**
 * @author(s): Reconx86, Cubey Terra
 * @version: N/A
 * @created: 2009.12.01
 * @date: 2016.03.22
 *
 * RCX Main Script (based on Cubey Terra's Menu for biplanes)
 *
 * @license:
 * You are allowed to share this script full-perm with others and even use it in your own projects.
 * But do not sell the script seperately nor as part of a script package
 */

/*========================================
GLOBAL VARIABLES
========================================*/
// Switches (Localy Managed Controls)
integer started;
//integer swEngine;
integer swNav;
integer swLandLight;
integer swBeacon;
integer swStrobe;
integer swParked;
integer swFeed;
integer swAbr;
integer swFlaps;
integer swNarrate = TRUE;
integer swFuel;
integer swCanopy = TRUE;
integer swSmoke = TRUE;
integer swGpws = TRUE;
integer swDebug;
integer swStairTruck;
integer taxiAngle;
integer stairEnabled;
vector stairPos;
vector stairRot;
string seat_msg;

// Rez States
integer rzDoorOpen = TRUE;

// Quick Start Switches
integer qsFeed = TRUE;

// Toggle options
list togOn = ["Off", "On"];
list togEnabled = ["Disabled", "Enabled"];
list togExtended = ["Retracted", "Extended"];
list togOpened = ["Closed", "Opened"];
list togStarted = ["Stopped", "Started"];
list togActivated = ["Deactivated", "Activated"];

//Managed Scripts (These are turned off when engine turn on)
integer totalScripts;
list managedScripts = [
    "RCX AIRCRAFT - CONF",
    "RCX AIRCRAFT - UPDATE CLIENT",
    "RCX Texture API",
    "RCX Texture Menu"
];

// Inventory items
string ivStairTruck = "Stair Truck (RCX MOD)";
string ivHud = "hud";
string ivHelp = "commands";

// Request Permission to Toggle
integer rptGear = TRUE;

// Aircraft Configuration
string acGearType;

integer vType = 0;
integer HUDchannel = 556874;// Channel 556874 should be compatible with Terra's Refuel Station
integer menuTime = 30;

// Vtype constants
integer TAXI_MODE = 0;
integer PLANE_MODE = 1;
integer BOAT_MODE = 2;

//Lockmode section
integer lockCode = 0;
list lockModes = ["Owner", "Group", "Anyone"];
integer lOwner = 0;
integer lGroup = 1;
integer lEveryone = 2;

// User keys
key owner = NULL_KEY;
key pilot = NULL_KEY;
key copilot = NULL_KEY;
key commander = NULL_KEY;// Person that issued a command
integer copilotControl;
integer touchPass;

float lastRequest;
integer fuelPerc;
integer listn1;
integer listn2;
integer dPg;

/*========================================
USER DEFINED FUNCTIONS
========================================*/
// Extracts postfix number on any string (eg: n1 results in 1)
string getCmdNr(string cmd, string prefix)
{
    return llGetSubString(cmd, llStringLength(prefix), llStringLength(cmd));
}

integer chkCmdNr(string cmd, string prefix)
{
    string number = getCmdNr(cmd, prefix);
    return number == (string)((integer)number) && llSubStringIndex(cmd, prefix) == 0;
}

engineToggle()
{
    if (started || (swFuel == FALSE || fuelPerc > 0)) {
        started = !started;
        
        //Script management: Turn off excesive scripts (update, texture, etc)
        integer i;
        
        for (i = 0; i < totalScripts; i++) {
            llSetScriptState(llList2String(managedScripts, i), !started);
        }
        
        //Feedback
        llMessageLinked(LINK_SET, started, "#engine", "");
        rcxSay("Engine " + llList2String(togStarted, started));
        
    } else if (!started) {
        //Failed start attempt
        rcxSay("Out of fuel!");
        
    }
}

// Quick Start
fastEngineToggle()
{
    if (!swStairTruck) {
        llMessageLinked(LINK_SET, swCanopy = !started, "#canopy", "");// Open canopy
    }
    if (qsFeed) {
        llMessageLinked(LINK_SET, swFeed = started, "#feed", "");// Enable HUD-text
    }
    llMessageLinked(LINK_SET, swNav = started, "#nav", "");// Enable navligths
    llMessageLinked(LINK_SET, swStrobe = started, "#strobe", "");// Enable strobe
    llMessageLinked(LINK_SET, swBeacon = started, "#beacon", "");// Enable beacon
}

rcxHudResponse()
{
    // Send HUD response with configuration and status
    llSay(HUDchannel, llList2Json(JSON_OBJECT, [
        "msg", "hud.response",
        "engine_status", started,
        "gear_status", rptGear,
        "gear_type", acGearType
    ]));
}

string rcxGetInvItem(string invItem, integer invType)
{
    integer inventoryNumber = llGetInventoryNumber(invType);
    integer i;
    for (i = 0 ; i < inventoryNumber; ++i) {
        string itemName = llGetInventoryName(invType, i);
        if (~llSubStringIndex(llToLower(itemName), llToLower(invItem))) {
            return itemName;
        }
    }
    return "";
}

findStairs()
{
    ivStairTruck = rcxGetInvItem(ivStairTruck, INVENTORY_OBJECT);
    if (ivStairTruck) {
        swStairTruck = TRUE;
    }
}

rcxSay(string msg)
{
    if ((pilot == NULL_KEY || pilot == owner) && copilot == NULL_KEY) {
        llOwnerSay(msg);
    } else {
        llSay(0, msg);
    }
}

// TERRA FUNCTIONS
start_listen(integer on)
{
    if (listn1) {
        llListenRemove(listn1);
        listn1 = 0;
    } 
    if (on) {
        listn1 = llListen(0, "", "", "");
    }
    
    if (listn2) {
        llListenRemove(listn2);
        listn2 = 0;
    }
    
    if (on) {
        listn2 = llListen(HUDchannel, "", "", "");
    }
}

showMenu()
{
    // Dialog Page 0
    if (dPg == 0) {
        
        string txt;
        txt += "Some options only work when the engine is off\n";
        txt += "\n";
        txt += "\tLock mode: " + llList2String(lockModes, lockCode) + "\n";
        txt += "\tHovertext: " + llList2String(togOn, qsFeed) + "\n";
        txt += "\tEngine: " + llList2String(togOn, started);
        
        list buttons = [
            "Camera...",
            "Lock...",
            "Repos",
            "Cabin Door",
            "HUD",
            "Help",
            "Engine"
        ];
        
        if (commander == owner) {
            buttons += ["Update"];
        }
        if (!started && llGetListLength(managedScripts)) {
            buttons += ["Paint..."];
        }
        llDialog(commander, txt, buttons, HUDchannel);

    // Dialog Page 2
    } else if (dPg == 2) {
        if (commander == owner) {
            
            string txt;
            txt += "SET ACCESS LOCK...\n\n\t";
            txt += "Who can fly your aircraft -- owner only, group members, or anyone?\n\n\t";
            txt += "Locked mode: " + llList2String(lockModes, lockCode);
            
            llDialog(commander, txt, lockModes + ["Back..."], HUDchannel);
        }
        
    // Dailog Page 8
    } else if (dPg == 8) {
        
        string txt;
        txt += "SELECT A CAMERA ANGLE...\n\n";
        txt += "Choose which camera angle to use while flying.";
        
        list buttons;
        buttons = [
            "Cam 6",
            "Cam 7",
            "Back...",
            "Cam 3",
            "Cam 4",
            "Cam 5",
            "Cam 0",
            "Cam 1",
            "Cam 2"
        ];
        
        llDialog(pilot, txt, buttons, HUDchannel);
    }
}

// Function to trim insignificant zeros
string fixedPrecision(float input, integer precision)
{
    precision = precision - 7 - (precision < 1);
    if (precision < 0) {
        return llGetSubString((string)input, 0, precision);
    }
    return (string)input;
}
// END OF TERRA FUNCTIONS

loadLocalConf(string localConf)
{
    // Load JSON settings
    acGearType = llJsonGetValue(localConf, ["gear.type"]);
    rzDoorOpen = llJsonGetValue(localConf, ["door.open"]) == JSON_TRUE;
    swNarrate = llJsonGetValue(localConf, ["narrate"]) == JSON_TRUE;
    swGpws = llJsonGetValue(localConf, ["gpws"]) == JSON_TRUE;
    stairEnabled = llJsonGetValue(localConf, ["stair.enabled"]) == JSON_TRUE;
    stairRot = (vector)llJsonGetValue(localConf, ["stair.rot"]);
    stairPos = (vector)llJsonGetValue(localConf, ["stair.pos"]);
    taxiAngle = (integer)llJsonGetValue(localConf, ["taxi_angle"]);
    seat_msg = llJsonGetValue(localConf, ["seat.message"]);
    
    // Post loaded settings to other scripts
    llMessageLinked(LINK_SET, swDebug, "#debug", "");
    llMessageLinked(LINK_SET, swFuel, "#fuel.enabled", "");// Disable fuel system
    llMessageLinked(LINK_SET, swCanopy = rzDoorOpen, "#canopy", "");// Open canopy
    llMessageLinked(LINK_SET, swFeed, "#feed", "");// Disable hudtext
    llMessageLinked(LINK_SET, swNarrate, "#narrate", "");// Enable thrust
    llMessageLinked(LINK_SET, swNav, "#nav", "");// Disable navlights
    llMessageLinked(LINK_SET, swStrobe, "#strobe", "");// Disable strobe
    llMessageLinked(LINK_SET, swBeacon, "#beacon", "");// Disable beacon
    llMessageLinked(LINK_SET, swSmoke, "#smoke", "");// Enable exhaust smoke
    llMessageLinked(LINK_SET, taxiAngle, "#taxi_angle", "");
    llMessageLinked(LINK_SET, swParked, "#park", "");
    llMessageLinked(LINK_SET, swGpws, "#gpws", "");// Load GPWS status
    llMessageLinked(LINK_SET, lockCode, "#lockCode", "");
    rcxSay("Local Configuration Loaded");
}

/*========================================
DEFAULT STATE
========================================*/
default
{
    /*========================================
    STATE ENTRY
    ========================================*/
    state_entry()
    {
        llSetText("", ZERO_VECTOR, FALSE);
        owner = llGetOwner();
        findStairs();
        
        totalScripts = llGetListLength(managedScripts);
        
        //Search for scripts
        integer i;
        list foundScripts;
        for (i = 0; i < totalScripts; ++i) {
            string itemName = llList2String(managedScripts, i);
            itemName = rcxGetInvItem(itemName, INVENTORY_SCRIPT);
            if (itemName) {
                foundScripts += [itemName];
            }
        }
        managedScripts = foundScripts;
        totalScripts = llGetListLength(managedScripts);
        
        llMessageLinked(LINK_ROOT, 0, "#main.state_entry", "");
        llOwnerSay("Main Reset");
    }
    
    /*========================================
    ON REZ
    ========================================*/
    on_rez(integer num)
    {
        pilot = NULL_KEY;
        copilot = NULL_KEY;
        findStairs();
        llMessageLinked(LINK_SET, swDebug, "#debug", "");
        llMessageLinked(LINK_SET, started = FALSE, "#engine", "");
        llMessageLinked(LINK_SET, swFuel, "#fuel.enabled", "");// Disable fuel system
        llMessageLinked(LINK_SET, swCanopy = rzDoorOpen, "#canopy", "");// Open canopy
        llMessageLinked(LINK_SET, swFeed, "#feed", "");// Disable HUD-text
        llMessageLinked(LINK_SET, swNarrate, "#narrate", "");// Enable thrust narration
        llMessageLinked(LINK_SET, swNav, "#nav", "");// Disable navlights
        llMessageLinked(LINK_SET, swStrobe, "#strobe", "");// Disable strobe
        llMessageLinked(LINK_SET, swBeacon, "#beacon", "");// Disable beacon
        llMessageLinked(LINK_SET, swFlaps = FALSE, "#flaps", "");// Reload Flap Config
        llMessageLinked(LINK_SET, swSmoke, "#smoke", "");// Enable exhaust smoke
    }
    
    /*========================================
    TOUCH EVENT
    ========================================*/
    touch_end(integer num)
    {
        commander = llDetectedKey(num - 1);
        
        if (commander == owner && (pilot != owner || !started) ) {
            if (!touchPass) {
                listn2 = llListen(HUDchannel, "", commander, "");
                start_listen(TRUE);
                llOwnerSay("Menu options enabled for " + (string)menuTime + " seconds");
                touchPass = TRUE;
            }
            dPg = 0;
            showMenu();
            llSetTimerEvent(menuTime);
        }
    }
    
    timer()
    {
        llSetTimerEvent(0);
        touchPass = FALSE;
        if (pilot != owner && copilot != owner) {
            start_listen(FALSE);
            llOwnerSay("Menu timed out");
        }
    }
    
    /*========================================
    LINK MESSAGES
    ========================================*/
    link_message(integer sender_num, integer num, string msg, key id)
    {
        if (msg == "#main.status_request") {
            float request = llGetTime();
            if (lastRequest + 0.5 < request) {
                llMessageLinked(LINK_SET, started = FALSE, "#engine", "");
                fastEngineToggle();
                
                //response mainly for engine script
                llMessageLinked(LINK_SET, 0, "#pilot", pilot);
                llMessageLinked(LINK_SET, 0, "#copilot", copilot);
                llMessageLinked(LINK_SET, swFuel, "#fuel.enabled" , "");
                llMessageLinked(LINK_SET, swNarrate, "#narrate", "");
                
                //response mainly for ANIM script
                llMessageLinked(LINK_SET, swCanopy, "#canopy" , "");
                llMessageLinked(LINK_SET, rptGear, "#gear" , "");
            }
            
        } else if (msg == "#fuel") {
            fuelPerc = num;
            
        } else if (msg == "#pilot") {
            pilot = id;
            
            if (pilot != NULL_KEY) {
                integer eject = TRUE;
                
                if (pilot == owner) {
                    eject = FALSE;
                    
                } else if (lockCode == 1 && llSameGroup(pilot)) {
                    eject = FALSE;
                    
                } else if (lockCode == 2) {
                    eject = FALSE;
                }
                
                if (eject) {
                    llMessageLinked(LINK_SET, 0, "#pilot.eject", "");
                    rcxSay("You are not authorized to fly this aircraft");
                    
                } else {
                    start_listen(TRUE);
                    rcxSay(seat_msg);
                }
            }
            
            if (started && (pilot == NULL_KEY && !copilotControl)) {
                engineToggle();
                fastEngineToggle();
                start_listen(FALSE);
            }
        
        } else if (msg == "#copilot") {
            copilot = id;
            if (copilot != NULL_KEY) {
                rcxSay(seat_msg);
                
            } else if (copilot == NULL_KEY && copilotControl) {
                copilotControl = FALSE;
                rcxSay("Copilot abondend the aircraft");
            }
            if (started && pilot == NULL_KEY && copilot == NULL_KEY) {
                engineToggle();
                fastEngineToggle();
            }

        } else if (msg == "#menu") {
            dPg = 0;
            showMenu();
            
        } else if (msg == "#vType") {
            vType = num;
            if (vType == PLANE_MODE) {
                llMessageLinked(LINK_SET, swCanopy = FALSE, "#canopy", "");
            }
            
        } else if (msg == "#canopy.touched") {
            if (vType == PLANE_MODE && !swCanopy) {
                rcxSay("Sorry, can't open the canopy at this time.");
            } else {
                llMessageLinked(LINK_SET, swCanopy = !swCanopy, "#canopy", "");
                rcxSay("Canopy " + llList2String(togOpened, swCanopy));
            }
            
        } else if (msg == "#strobe") { 
            swStrobe = num;
            
        } else if (msg == "#beacon") { 
            swBeacon = num;
            
        } else if (msg == "#nav") { 
            swNav = num;
            
        } else if (msg == "#landLight") {
            swLandLight = num;
            
        } else if (msg == "#canopy") { 
            swCanopy = num;
         
        } else if (msg == "#narrate") { 
            swNarrate = num;
            
        } else if (msg == "#gear") { 
            llSay(HUDchannel, llList2Json(JSON_ARRAY, [msg, rptGear = num]));
            
        } else {
            if (llJsonGetValue(msg, ["msg"]) != JSON_INVALID) {
                string jMsg = llJsonGetValue(msg, ["msg"]);
                if (jMsg == "conf.main") {
                    loadLocalConf(msg);
                }
            }
        }
    }

    /*========================================
    LISTEN (channel 0 and 556874)
    ========================================*/
    listen(integer channel, string name, key id, string msg)
    {
        //Pre-formatting parameters
        msg = llToLower(msg);
        commander = llGetOwnerKey(id);
        
        //Calculate other parameters
        integer dialog = (channel == HUDchannel && id == owner);
        integer HUD = channel == HUDchannel && id != owner;
        integer crew = commander == pilot || (commander == copilot && copilotControl);
        
        //Both pilots are allowed to use following command
        if (crew || touchPass) {
            
            //Only owner is allowed to use these commands
            if (commander == owner) {
                if (msg == "update") { // Update
                    llOwnerSay("Checking for updates...");
                    llMessageLinked(LINK_SET, 0, "#update", id);
                    dialog = FALSE;
                }
            }
            
            //Only pilot is allowed to use these commands
            if (commander == pilot) {
                
                if (msg == "cmd" || msg == "copilot") {
                    if (copilot != NULL_KEY) {
                        llMessageLinked(LINK_SET, copilotControl = !copilotControl, "#copilot.control", "");
                        rcxSay("Copilot Controls " + llList2String(togEnabled, copilotControl));
                    } else {
                        rcxSay("No copilot available");
                    }
                    
                } else if (msg == "eject") {
                    llMessageLinked(LINK_SET, 0, "#eject", "");
                }
            }
            
            // HUD and Menu only commands
            if (HUD) {
                if (msg == "hud.attached") {// If HUD is attached
                    rcxHudResponse();
                }
            }
                
            // TERRA COMMANDS
            if (dialog) {
                if (dPg == 0) {
                
                    if (msg == "lock...") {
                        if (commander == owner) {
                            dPg = 2;
                            
                        } else {
                            rcxSay("Sorry, only owner can set the lock.");
                        }
                        
                    } else if (msg == "paint...") {
                        llMessageLinked(LINK_SET, 0, "#paint menu", "");
                        dialog = FALSE;
                        
                    } else if (msg == "camera...") {
                        dPg = 8;
                        
                    }
                    
                } else {
                    if (msg == "back...") {
                        dPg = 0;
                    }
                }
                // END OF TERRA COMMANDS
            }
            
            // If cam 1 - cam 9
            if (msg == "cam") {
                llMessageLinked(LINK_SET, 0, "#cam++", "");
            
            } else if (llSubStringIndex(msg, "c") == 0 && chkCmdNr(msg, "c")) {
                integer camNum = (integer)(llGetSubString(msg, 1, llStringLength(msg)));
                llMessageLinked(LINK_SET, camNum, "#cam", "");
                rcxSay("Camera " + (string)camNum + " set");
            
            } else if (llSubStringIndex(msg, "cam ") == 0 && chkCmdNr(msg, "cam ")) {
                integer camNum = (integer)(llGetSubString(msg, 4, llStringLength(msg) ));
                llMessageLinked(LINK_SET, camNum, "#cam", "");
                rcxSay("Camera " + (string)camNum + " set");
                
            } else if (msg == "g" || msg == "gear") {
                if (vType == TAXI_MODE && rptGear) {
                    rcxSay("Unable to retract gear in taxi-mode");
                } else {
                    llMessageLinked(LINK_SET, rptGear = !rptGear, "#gear.set", "");
                    // The feedback message is provided by the engine
                }
                
            } else if (msg == "p" || msg == "park" || msg == "br" || msg == "brake" || msg == "brakes") {
                llMessageLinked(LINK_SET, swParked = !swParked, "#park", "");
                // The feedback message is provided by the engine
                
            } else if (msg == "abr") {
                llMessageLinked(LINK_SET, swAbr = !swAbr, "#abr", "");
                // The feedback message is provided by the engine
                
            } else if (msg == "gpws") {
                llMessageLinked(LINK_SET, swGpws = !swGpws, "#gpws", "");
                rcxSay("Ground Proximity Warning " + llList2String(togEnabled, swGpws));
                
            } else if (msg == "start" && !started) {
                engineToggle();
                
            } else if (msg == "stop" && started) {
                engineToggle();
                
            } else if (msg == "s" || msg == "engine") {
                engineToggle();
                fastEngineToggle();
                
            } else if (msg == "menu") {
                dPg = 0;
                showMenu();

            } else if (msg == "c" || msg == "cc" || msg == "cabin door") {
            
                if (!swCanopy && (vType == PLANE_MODE)) {
                    rcxSay("Sorry, can't open the canopy at this time.");
                    return;
                }
                llMessageLinked(LINK_SET, swCanopy = !swCanopy, "#canopy", "");
                rcxSay("Canopy " + llList2String(togOpened, swCanopy));
                if (stairEnabled && swStairTruck) {
                    if (swCanopy) {
                        rotation rootRot = llGetRootRotation();
                        llRezAtRoot(
                            ivStairTruck, //item
                            llGetPos() + stairPos * rootRot, //pos
                            ZERO_VECTOR, //velocity
                            llEuler2Rot(stairRot * DEG_TO_RAD) * rootRot, //rot
                            TRUE //start param
                        );
                        
                    } else {
                        llSay(HUDchannel, "truck.derez");
                    }
                }
                
            } else if (msg == "repos") {
                if (started) {
                    engineToggle();
                    fastEngineToggle();
                }
                llMessageLinked(LINK_SET, swCanopy = FALSE, "#canopy", "");
                llMessageLinked(LINK_SET, swLandLight = FALSE, "#landLight", "");
                while (llGetStatus(STATUS_PHYSICS));//Wait while physics is on
                llSetRot(llEuler2Rot(<0.0, -taxiAngle, 0.0> * DEG_TO_RAD));
                rcxSay("Aircraft Reposition");
            
            } else if (chkCmdNr(msg, "n") || chkCmdNr(msg, "n ")) {
                integer throttle = (integer)getCmdNr(msg, "n");
                llMessageLinked(LINK_SET, throttle, "#throttle.set", "");
                rcxSay("Throttle set to " + (string)throttle + "%");
                
            } else if (msg == "f" || msg == "flap"|| msg == "flaps") {
                llMessageLinked(LINK_SET, swFlaps = !swFlaps, "#flaps", "");
                rcxSay("Flaps " + llList2String(["Up", "Down"], swFlaps));
                
            } else if (msg == "nav") {
                llMessageLinked(LINK_SET, swNav = !swNav, "#nav", "");
                rcxSay("Navigation Lights " + llList2String(togOn, swNav));
                
            } else if (msg == "ll") {
                llMessageLinked(LINK_SET, swLandLight = !swLandLight, "#landLight", "");
                rcxSay("Landing Lights " + llList2String(togOn, swLandLight));
                
            } else if (msg == "strobe") {
                llMessageLinked(LINK_SET, swStrobe = !swStrobe, "#strobe", "");
                rcxSay("Strobe Lights " + llList2String(togOn, swStrobe));
            
            } else if (msg == "beacon") {
                llMessageLinked(LINK_SET, swBeacon = !swBeacon, "#beacon", "");
                rcxSay("Beacon Lights " + llList2String(togOn, swBeacon));
                
            } else if (msg == "feed" || msg == "hovertext") {
                llMessageLinked(LINK_SET, swFeed = !swFeed, "#feed", "");
                qsFeed = swFeed;
                rcxSay("Data Feed " + llList2String(togOn, swFeed));
              
            } else if (msg == "nar" || msg =="narrate") {
                llMessageLinked(LINK_SET, swNarrate = !swNarrate, "#narrate", "");
                rcxSay("Thrust Narration " + llList2String(togOn, swNarrate));
                
            } else if (msg == "fuel") {
                llMessageLinked(LINK_SET, swFuel = !swFuel, "#fuel.enabled", "");
                rcxSay("Fuel System " + llList2String(togOn, swFuel));
            
            } else if (msg == "refuel") {
                key fuelCan = id;
                llMessageLinked(LINK_SET, 0, "#refuel", fuelCan);
                llSay(HUDchannel, (string)fuelCan + "refueled");
            
            } else if (msg == "smoke") {
                llMessageLinked(LINK_SET, swSmoke = !swSmoke, "#smoke", "");
                rcxSay("Exhaust Smoke " + llList2String(togEnabled, swSmoke));
            
            } else if (msg == "hud") {
                ivHud = rcxGetInvItem(ivHud, INVENTORY_OBJECT);
                if (ivHud) {
                    llGiveInventory(owner, ivHud);
                } else {
                    rcxSay("Item not found, please contact developper");
                }
                dialog = FALSE;
                
            } else if (msg == "help") {
                ivHelp = rcxGetInvItem(ivHelp, INVENTORY_OBJECT);
                if (ivHelp) {
                    llGiveInventory(owner, ivHelp);
                } else {
                    rcxSay("Item not found, please contact developper");
                }
                dialog = FALSE;
            
            } else {
                integer lockSet;
                if (msg == "lock" || msg == "owner") {
                    lockCode = 0;
                    lockSet = TRUE;
                    
                } else if (msg == "group") {
                    lockCode = 1;
                    lockSet = TRUE;
                    
                } else if (msg == "guest" || msg == "anyone") {
                    lockCode = 2;
                    lockSet = TRUE;
                    
                }
                
                if (lockSet) {
                    llMessageLinked(LINK_SET, lockCode, "#lockCode", "");
                    list details = llGetObjectDetails(owner, [OBJECT_POS]);
                    float distance = llVecDist(llGetPos(), llList2Vector(details, 0));
                    string msg = "Lock set to " + llList2String(lockModes, lockCode) + ".";
                    if (distance > 20) {
                        llOwnerSay(msg);
                    }
                    llSay(0, msg);
                }
            }
        }
        
        if (dialog) {
            showMenu();
        }
    }
    
    attach(key agent)
    {
        if (agent != NULL_KEY) {
            llRequestPermissions(owner, PERMISSION_ATTACH);
        }
    }
    
    run_time_permissions(integer perm) 
    {
        if (perm & PERMISSION_ATTACH) {
            llSay(0, "Please drag this vehicle onto the ground -- Don't attach it to your body");
            llDetachFromAvatar();
        }
    }
    
    changed(integer change)
    {
        if (change & CHANGED_OWNER) {
            llResetScript();
        }
        if (change & CHANGED_INVENTORY) {
            findStairs();
        }
        if (change & CHANGED_LINK) {
            rcxHudResponse();
        }
    }
}