Shortnote

I am, the Oracle.

The oracle script, part of the Project Alexandria queries all the Alexandria search scripts in the region in order to find a user-supplied search string within the notecard names.

The code then uses JumpDrive/CrossDrive to teleport the agent to the bookshelf where the query was matched. This is essentially our library teller that does all the searching of the synchronized notecards.

Code

This script was tested and works on OpenSim version 0.7.4!

oracle.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
string _searchQuery = "";
list _searchResults = [];
vector sPos = ZERO_VECTOR;
vector fPos = ZERO_VECTOR;
 
// Calculate next jump gate
vector nextJump(vector iPos, vector dPos, integer jumpDistance) {
    // We move 1/jumpDistance from the initial position
    // towards the final destination in the description.
    float dist = llVecDist(iPos, dPos);
    if(dist > jumpDistance) 
        return iPos + jumpDistance * (dPos-iPos) / dist;
    return nextJump(iPos, dPos, --jumpDistance);
}
 
default {
    state_entry() {
        llSetAlpha(1, ALL_SIDES);
        llSetPrimitiveParams([PRIM_GLOW, 0.05]);
        _searchResults = [];
        llSetClickAction(CLICK_ACTION_TOUCH);
        llSetText("I am,\nthe Oracle.", <1,1,0>, 1.0);
        state query;
    }
}
 
state query {
    touch_start(integer num) {
        key av = llDetectedKey(0);
        integer comChannel = ((integer)("0x"+llGetSubString((string)av,-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
        llListen(comChannel, "", av, "");
        llTextBox(av, "\nWhat are you seeking?", comChannel);
    }
    listen(integer channel, string name, key id, string message) {
        _searchQuery = message;
        state search;
    }
}
 
state search
{
    state_entry() {
        llListen(-183457, "", "", "");
        llRegionSay(-183456, _searchQuery);
        llSetText("Let me look, hang on please...", <1,1,0>, 1.0);
        llSetTimerEvent(5);
    }
    listen(integer channel, string name, key id, string message) {
        llSetTimerEvent(5);
        if(llGetListLength(_searchResults) == 12) return;
        list data = llParseString2List(message, ["="], []);
        string answer = llList2String(data, 1);
        if(llListFindList(_searchResults, answer) != -1) return;
        _searchResults += llList2String(data, 1);
    }
    timer() {
        if(llGetListLength(_searchResults) == 0) state notfound;
        state select;
    }
}
 
state notfound
{
    state_entry() {
        llSetText("Sorry, I was unable to find that...", <1,1,0>, 1.0);
        llSetTimerEvent(1);
    }
    timer() {
        state default;
    }
}
 
state select
{
    state_entry() {
        llSetText("Touch me to choose your destination.", <1,1,0>, 1.0);
        llSetTimerEvent(10);
    }
    touch_start(integer num) {
        integer i = llGetListLength(_searchResults)-1;
        list authors = [];
        do {
            list data = llParseString2List(llList2String(_searchResults, i), [";"], []);
            authors += llGetSubString(llList2String(data, 1), 0, 23);
        } while(--i>-1);
        key av = llDetectedKey(0);
        integer comChannel = ((integer)("0x"+llGetSubString((string)av,-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
        llListen(comChannel, "", av, "");
        llDialog(av, "I have found the following...", authors, comChannel);
    }
    listen(integer channel, string name, key id, string message) {
@next;
        string e = llList2String(_searchResults, 0);
        list data = llParseString2List(e, [";"], []);
        if(llSubStringIndex(llList2String(data, 1), message) != -1) jump found;
        _searchResults = llDeleteSubList(_searchResults, 0, 0);
        _searchResults += e;
        jump next;
@found;
        state sit;
    }
    timer() {
        state default;
    }
 
}
 
state sit {
    state_entry() {
        llSitTarget(<0,0,0.5>, ZERO_ROTATION);
        llSetClickAction(CLICK_ACTION_SIT);
        llSetText("Touch me, I will take you there...", <1,1,0>, 1.0);
        llSetTimerEvent(5);
    }
    changed(integer change) {
        if(change & CHANGED_LINK) {
            key av = llAvatarOnSitTarget();
            if(av) {
                llSetAlpha(0, ALL_SIDES);
                llSetPrimitiveParams([PRIM_GLOW, 0]);
                state move;
            }
        }
    }
    timer() {
        state default;
    }
}
 
state move
{
    state_entry() {
        // Grab local position again.
        sPos = llGetPos();
        // Grab distance from description
        fPos = ZERO_VECTOR;
        list oDesc = llParseString2List(llList2String(_searchResults, 0), ["<", ">", ","], []);
        fPos.x = llList2Float(oDesc, 0);
        fPos.y = llList2Float(oDesc, 1);
        fPos.z = llList2Float(oDesc, 2);
        // 1.175494351E-38 is the smallest float.
        llSetTimerEvent(0.01);
 
    }
    timer() {
        if(llVecDist(llGetPos(), fPos) < 5) {
            llSetTimerEvent(0);
            key a = llAvatarOnSitTarget();
            if(a) llUnSit(llAvatarOnSitTarget());
            state recall;
        }
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POSITION, nextJump(llGetPos(), fPos, 10)]);
    }
}
 
state recall
{
    state_entry() {
        llSetAlpha(1, ALL_SIDES);
        llSetPrimitiveParams([PRIM_GLOW, 0.05]);
        // 1.175494351E-38 is the smallest float.
        llSetTimerEvent(0.01);
    }
    timer() {
        if(llVecDist(llGetPos(), sPos) < 5) {
            llSetTimerEvent(0);
            state default;
        }
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POSITION, nextJump(llGetPos(), sPos, 10)]);
    }
}