About

This is a control Heads-Up Display (HUD) for the Corrade scripted agent featuring some of the more common movement controls that allow you to control Corrade as a drone. The HUD is designed for the bleeding-edge (most recent version of Corrade) such that you will need a Corrade progressive scripted agent installed.

The configured group should have the following permissions enabled:

  • movement
  • grooming
  • notifications
  • interact

and the following notifications:

- permission - dialog

enabled using the bundled Configurator program for Corrade.

Note that the HUD is not exhaustive in functions - currently Corrade features an application programmer interface (API) spanning a few hundred commands. Instead, the HUD is provided as a template for programmers as a reference on how to create scripts for Corrade. The HUD also generally focuses on "movement" actions such as: sit, walk, patrol, teleport, etc… With a a few exceptions. In any case, we hope that the scripts within the HUD provide a good starting point for scripters to make their own scripts and create other items based on them.

Marketplace Item

Setting Up

After receiving the item from Marketplace, right-click the object and attach it to your HUD. You will end up with a single icon on your screen featuring a zeppelin. Right-click and edit the icon and then go to the "Contents" tab on the pop-up edit pane. Inside you will find a "configuration" notecard. Double-click the notecard and configure the settings to your liking. Note that the options:

  • "corrade"
  • "group"
  • "password"

have to be set in order for the HUD to work with your Corrade and should correspond with the settings you have made using the Configurator and present in the Corrade.ini file. All the other options should be safe as they are.

Usage

Once you save the "configuration" notecard, the main HUD script should restart and pick-up the changes you have made. In case your Corrade bot is online, and given that the configuration you have made is correct, you should be able to click the zeppelin icon in order to have the other icons unfold on your screen. If you touch the zeppelin icon and the other icons do not unfold then it means that there was a problem connecting to your Corrade bot and you should check your settings or contact support for help.

Every icon on the HUD except the icon with the zeppelin logo represents an action that you can make Corrade perform. Please see the attached screenshot, or the project's page, for a short explanation on what function each icon performs.

The HUD will fold once Corrade is not online anymore - you can also click the zeppelin icon to hide all the other buttons from view and then press the icon again to reveal them. In case you have activated buttons, you can still fold the other icons on the HUD and they will still work in the background such that it is not necessary to always have all the buttons showing on your screen.

Making the HUD Shut Up

Since this is a developer's item, all the debug messages are turned on such that the HUD will be very chatty on local chat. In order to make the HUD silent, you will have to edit the scripts and remove the debug information. In order to do that, for all icons, open the script and then find lines similar to the following:

// DEBUG 
llOwnerSay ... etc ...

and delete or comment out those two lines for every script.

Scripts

All scripts are presented on separate pages with the exception of the main controller script that is responsible for reading the configuration notecard and then sending it to the various other buttons:

///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2016 - License: CC BY 2.0      //
///////////////////////////////////////////////////////////////////////////
//
// A template HUD script for Corrade that reads a configuration notecard
// and then feeds that configuration to various other components of the HUD
// that request the configuration. Additionally, this HUD is programmed to
// "fold" and "unfold" depending on whether Corrade is online or not. For 
// more information on the Corrade scripted agent please see the URL:
// http://grimore.org/secondlife/scripted_agents/corrade
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    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 = llParseString2List(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: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
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, "&");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0    //
///////////////////////////////////////////////////////////////////////////
// escapes a string in conformance with RFC1738
string wasURLEscape(string i) {
    string o = "";
    do {
        string c = llGetSubString(i, 0, 0);
        i = llDeleteSubString(i, 0, 0);
        if(c == "") jump continue;
        if(c == " ") {
            o += "+";
            jump continue;
        }
        if(c == "\n") {
            o += "%0D" + llEscapeURL(c);
            jump continue;
        }
        o += llEscapeURL(c);
@continue;
    } while(i != "");
    return o;
}
 
// for notecard reading
integer line = 0;
 
// key-value data will be read into this list
list tuples = [];
// Corrade's online status.
integer online = FALSE;
integer open = FALSE;
string URL = "";
 
default {
    state_entry() {
        if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
            llOwnerSay("Sorry, could not find a configuration inventory notecard.");
            return;
        }
        // DEBUG
        llOwnerSay("Reading configuration file...");
        llGetNotecardLine("configuration", line);
    }
    dataserver(key id, string data) {
        if(data == EOF) {
            // invariant, length(tuples) % 2 == 0
            if(llGetListLength(tuples) % 2 != 0) {
                llOwnerSay("Error in configuration notecard.");
                return;
            }
            key CORRADE = llList2Key(
                tuples,
                llListFindList(
                    tuples, 
                    [
                        "corrade"
                    ]
                )
            +1);
            if(CORRADE == NULL_KEY) {
                llOwnerSay("Error in configuration notecard: corrade");
                return;
            }
            string GROUP = llList2String(
                tuples,
                llListFindList(
                    tuples, 
                    [
                        "group"
                    ]
                )
            +1);
            if(GROUP == "") {
                llOwnerSay("Error in configuration notecard: group");
                return;
            }
            string PASSWORD = llList2String(
                tuples,
                llListFindList(
                    tuples, 
                    [
                        "password"
                    ]
                )
            +1);
            if(PASSWORD == "") {
                llOwnerSay("Error in configuration notecard: password");
                return;
            }
            string VERSION = llList2String(
                tuples,
                llListFindList(
                    tuples, 
                    [
                        "version"
                    ]
                )
            +1);
            if(VERSION == "") {
                llOwnerSay("Error in configuration notecard: version");
                return;
            }
            // DEBUG
            llOwnerSay("Read configuration notecard...");
            state configuration;
        }
        if(data == "") jump continue;
        integer i = llSubStringIndex(data, "#");
        if(i != -1) data = llDeleteSubString(data, i, -1);
        list o = llParseString2List(data, ["="], []);
        // get rid of starting and ending quotes
        string k = llDumpList2String(
            llParseString2List(
                llStringTrim(
                    llList2String(
                        o, 
                        0
                    ), 
                STRING_TRIM), 
            ["\""], []
        ), "\"");
        string v = llDumpList2String(
            llParseString2List(
                llStringTrim(
                    llList2String(
                        o, 
                        1
                    ), 
                STRING_TRIM), 
            ["\""], []
        ), "\"");
        if(k == "" || v == "") jump continue;
        tuples += k;
        tuples += v;
@continue;
        llGetNotecardLine("configuration", ++line);
    }
    attach(key id) {
        llResetScript();
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
            llResetScript();
        }
    }
}
 
state configuration {
    state_entry() {
        // DEBUG
        llOwnerSay("Configuration ready...");
        llMessageLinked(LINK_SET, 0, "retract", NULL_KEY);
        llSetTimerEvent(1);
    }
    timer() {
        llRequestAgentData(
            (key)wasKeyValueGet(
                "corrade", 
                wasKeyValueEncode(tuples)
            ),
            DATA_ONLINE
        );
        llSetTimerEvent(5);
    }
    dataserver(key id, string data) {
        if(data != "1") {
            if(online == TRUE) {
                // DEBUG
                llOwnerSay("Corrade is not online, shutting down...");
                llMessageLinked(LINK_SET, 0, "retract", NULL_KEY);
                online = FALSE;
            }
            return;
        }
        online = TRUE;
    }
    touch_start(integer total_number) {
        if(!open && online) {
            // DEBUG
            llOwnerSay("Getting URL...");
            llRequestURL();
            return;
        }
        llMessageLinked(LINK_SET, 0, "retract", NULL_KEY);
        open = FALSE;
    }
    http_request(key id, string method, string body) {
        llHTTPResponse(id, 200, "OK");
        llReleaseURL(URL);
        string configuration = wasKeyValueEncode(tuples);
        if(method == URL_REQUEST_GRANTED) {
            llOwnerSay("Checking version...");
 
            URL = body;
            llInstantMessage(
                wasKeyValueGet(
                    "corrade",
                    configuration
                ),
                wasKeyValueEncode(
                    [
                        "command", "version",
                        "group", wasURLEscape(
                            wasKeyValueGet(
                                "group", 
                                configuration
                            )
                        ),
                        "password", wasURLEscape(
                            wasKeyValueGet(
                                "password", 
                                configuration
                            )
                        ),
                        "callback", wasURLEscape(URL)
                     ]
                )
            );
            return;
        }
        if(wasKeyValueGet("command", body) != "version" ||
            wasKeyValueGet("success", body) != "True") {
            llOwnerSay("Version check failed...");
            return;
        }
        list corradeVersion = llParseString2List(
            wasKeyValueGet(
                "data",
                body
            ),
            ["."],
            []
        );
        //integer receivedVersion = (integer)(llList2String(v, 0) + llList2String(v, 1));
        list notecardVersion = llParseString2List(
            wasKeyValueGet(
                "version",
                configuration
            ),
            ["."],
            []
        );
        //llOwnerSay((string)receivedVersion);
        //integer notecardVersion = (integer)(llList2String(v, 0) + llList2String(v, 1));
        if(llList2Integer(corradeVersion, 0) >= llList2Integer(notecardVersion, 0) || llList2Integer(corradeVersion, 1) >= llList2Integer(notecardVersion, 1)) {
            llOwnerSay("Version is compatible. Deploying HUD...");
            llMessageLinked(LINK_SET, 0, "deploy", NULL_KEY);
            open = TRUE;
            return;
        }
        llOwnerSay("HUD version is incompatible! You need a Corrade of at least version: " +
            wasKeyValueGet(
                "version",
                configuration
            ) +
            " for this HUD."
        );
        llMessageLinked(LINK_SET, 0, "retract", NULL_KEY);
        open = FALSE;
        return;
    }
    link_message(integer sender, integer num, string message, key id) {
        if(message != "configuration") return;
        llMessageLinked(sender, 0, wasKeyValueEncode(tuples), "configuration");
    }
    attach(key id) {
        llResetScript();
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
            llResetScript();
        }
    }
}

Index


secondlife/scripted_agents/corrade/projects/in_world/movmement_heads-up_display.txt · Last modified: 2022/11/24 07:45 by 127.0.0.1

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.