Table of Contents

About

Part of the Global Health activities consist in letting students discover various areas where they can interact with objects. In order to help them to find their way, we created an information heads-up display (HUD) that scans for various objects in range and displays some pre-defined text.

Setup

name=Tree&info=That is a tree...
name=KittyCats - jojo&info=That's one large pussy!

in this example, when the HUD senses an object named "Tree", it will display the text: "That is a treeā€¦". If it detects an object named "KittyCats - jojo" it will display the text "That's one large pussy!". Note that the name of the object to detect in the notecard must be exact or else the script will not find the object.

Each object is listed the same way line-by-line in the notecard info (remember that a blank line at the end of the notecard is necessary for the dataserver to read the notecard properly).

Code

This script was tested and works on OpenSim version 0.7.4!

infohud.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.        //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//                            CONFIGURATION                              //
///////////////////////////////////////////////////////////////////////////
 
// distance in meters to detect an information spot
float SCAN_RANGE = 5;
// break text on column number
integer BREAK_COLUMN = 30;
 
///////////////////////////////////////////////////////////////////////////
//                              INTERNALS                                //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2014 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(a, [ k ]);
    if (i != -1) return llList2String(a, i + 1);
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    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) >;
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
// Requires: a string txt, a delimiter, a column number
// Provides: a string split at the first space after column
//////////////////////////////////////////////////////////
string wasSpaceWrap(string txt, string delimiter, integer column) {
    string ret = llGetSubString(txt, 0, 0);
    integer len = llStringLength(txt);
    integer itra = 1;
    integer itrb = 1;
    do {
        if (itrb % column == 0) {
            while (llGetSubString(txt, itra, itra) != " ") {
                ret += llGetSubString(txt, itra, itra);
                if (++itra > len) return ret;
            }
            ret += delimiter;
            itrb = 1;
            jump next;
        }
        ret += llGetSubString(txt, itra, itra);
        ++itrb;
        @next;
    } while (++itra < len);
    return ret;
}
 
list info = [];
list name = [];
integer line = 0;
 
default {
    state_entry() {
        llSetText("", ZERO_VECTOR, 0);
        if (llGetInventoryType("info") != INVENTORY_NOTECARD) {
            llSay(DEBUG_CHANNEL, "Failed to find a notecard named info in the primitive's inventory.");
            return;
        }
        llGetNotecardLine("info", line);
    }
    dataserver(key id, string data) {
        if (data == EOF) {
            state scan;
        }
        if (data == "") jump continue;
        string n = wasKeyValueGet("name", data);
        if (n == "") jump continue;
        string i = wasKeyValueGet("info", data);
        if (i == "") jump continue;
        info += i;
        name += n;
@continue;
        llGetNotecardLine("info", ++line);
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        llResetScript();
    }
}
 
state scan {
    state_entry() {
        llSensorRepeat("", "", ACTIVE | PASSIVE, SCAN_RANGE, TWO_PI, 1);
    }
    sensor(integer num) {
        --num;
        do {
            integer i = llListFindList(name, (list)llDetectedName(num));
            if (i == -1) jump continue;
            llSetText(
                wasSpaceWrap(llList2String(info, i), "\n", BREAK_COLUMN),
                wasPercentToGradient(
                    100 * llVecDist(llDetectedPos(num), llGetPos()) / SCAN_RANGE,
                    "rg"
                    ),
                1);
            llSetTimerEvent(2);
@continue;
        } while (--num > -1);
    }
    timer() {
        llSetText("", ZERO_VECTOR, 0);
    }
    on_rez(integer num) {
        llResetScript();
    }
    changed(integer change) {
        llResetScript();
    }
}