ChangeLog

29 December 2013

  • Full re-write of the trivia machine.

9 April 2012

28 November 2012

  • Scores now display with overhead text.
  • The Levenshtein distance is now used to allow for spelling mistakes as long as the answer is not a number and the Levehnstein distance is smaller than 2.
  • Added compatibility with OpenSim (kudos to Fernanda Antwerp for asking).

Introduction

The presented item is a trivia engine based on HamFon's original TriviaBot. This trivia script uses notecards as brain files with a specific syntax allowing it to be extended depending on the number of notecards you provide. A few notecards are supplied by HamFon and others. For a complete arsenal, download the full archive of text files from imatowns.com to supply to your trivia bot.

Features

  • 1 single primitive, uses particles for holo-display and 1 single script.
  • Provides hints to players.
  • Poofs when a new question is lined up.
  • Complies to Trivia database standards.
  • Can be extended by adding notecards.
  • Can use any amount of notecards and supports any amount of questions.
  • Categorizes questions by area (Geography, History, etc…) depending on the notecards used.
  • Turns itself off when nobody is in range.
  • Is fully open-sourced (license: GNU GPLv3).
  • The machine can be started by anybody but can only be stopped by the owner.
  • Distributed by default with 10 notecards, approximatively 500 questions from various areas.
  • Keeps track of avatars answering questions and displays an overhead text with the score.

Limitations

  • A script in LSL is able to read only the first 255 bytes of a notecard. This means that if you supply a notecard that is too large, the script will not be able to read all the questions and answers. Disregarding UTF-8 (with special, decorative characters) and using the latin charset, this means that a script will be able to read the first 255 characters in a notecard.
  • If too many notecards are supplied, the script will overrun the allocated memory available to the script. Currently, a mono-compiled script is able to hold 64KB of data. If you get a stack-heap collision, the most likely you are trying to load too many questions. Consider shortening the notecards.

Setup

Place some of the notecards from the next section and name them accordingly in a primitive. After that, drop the script from this page into the prim. That's it, you should be ready to go. If memory is an issue for your SIM, simply set the primitive scripts to not running. To start again, set the scripts to running.

Notecards

The trivia brain files you place in the prim containing the trivia engine must be named after the pattern: Trivia_Brain_1 for the first notecard, Trivia_Brain_2 for the second notecard, Trivia_Brain_3 for the third notecard… Trivia_Brain_N for the Nth notecard.

FilenameFilesizeLast modified
trivia_brain_1.txt8.9 KiB2014/12/19 22:41
trivia_brain_10.txt4.9 KiB2014/12/19 22:41
trivia_brain_2.txt2.3 KiB2014/12/19 22:41
trivia_brain_3.txt4.8 KiB2014/12/19 22:41
trivia_brain_4.txt2.9 KiB2014/12/19 22:41
trivia_brain_5.txt5.1 KiB2014/12/19 22:41
trivia_brain_6.txt17.0 KiB2014/12/19 22:41
trivia_brain_7.txt4.0 KiB2014/12/19 22:41
trivia_brain_8.txt3.7 KiB2014/12/19 22:41
trivia_brain_9.txt5.3 KiB2014/12/19 22:41

Download, unpack and just paste the contents into a notecard making sure you follow the naming convention for the notecard brain files.

Notecard Syntax

If you are curious about the syntax, here is a description of the notecard syntax:

/<category>/<possible answer 1>/<possible answer 2>/.../<possible answer N>//<question>

where:

  • category represents a trivia category like Arts or Sciences. This will prefix the question that the trivia engine will ask.
  • possible answer 1 through possible answer N represent the possible answers that the trivia engine will accept as being valid for the question.
  • question is simply the question that the trivia engine will ask on the main chat.

Example:

/Valentines/good luck//A white dove, also a symbol of Valentine's Day, symbolizes what?

where:

  • Valentines is a category,
  • good luck is the right answer,
  • A white dove, also a symbol of Valentine's Day, symbolizes what? is the question that the trivia machine will ask

Code

This script was tested and works on OpenSim version 0.7.4!

trivia.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2012 - 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                              //
///////////////////////////////////////////////////////////////////////////
 
// The trivia machine pauses this number of seconds before revealing a 
// letter from the correct answer.
float TIME_PER_LETTER = 2;
 
///////////////////////////////////////////////////////////////////////////
//                              INTERNALS                                //
///////////////////////////////////////////////////////////////////////////
 
list cards = [];
string card = "";
integer cardIterator = 0;
integer lineIterator = 0;
 
list categories = [];
string selectedCategory = "";
string category = "";
string question = "";
string clue = "";
 
list store = [];
string topDisplay = "";
 
vector qC = ZERO_VECTOR;
 
list scores = [];
list names = [];
 
integer seconds = 0;
 
integer comHandle = 0;
integer shutdown = 10;
 
list mem = [];
integer memCacheHit = 0;
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list wasDualQuicksort(list a, list b) {
    if(llGetListLength(a) <= 1) return a+b;
 
    integer pivot_a = llList2Integer(a, 0);
    a = llDeleteSubList(a, 0, 0);
    string pivot_b = llList2String(b, 0);
    b = llDeleteSubList(b, 0, 0);
 
    list less = [];
    list less_b = [];
    list more = [];
    list more_b = [];
 
    do {
        if(llList2Integer(a, 0) > pivot_a) {
            less += llList2List(a, 0, 0);
            less_b += llList2List(b, 0, 0);
            jump continue;
        }
        more += llList2List(a, 0, 0);
        more_b += llList2List(b, 0, 0);
@continue;
        a = llDeleteSubList(a, 0, 0);
        b = llDeleteSubList(b, 0, 0);
    } while(llGetListLength(a));
    return wasDualQuicksort(less, less_b) + [ pivot_a ] + [ pivot_b ] + wasDualQuicksort(more, more_b);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2012 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
integer wasLevenshteinDistance(string a, string b) {
    integer cost = 0;
    if(llGetSubString(a, 0, 0) != llGetSubString(b, 0, 0)) cost = 1;
    integer len_a = llStringLength(a);
    integer len_b = llStringLength(b);
    a = llDeleteSubString(a, 0, 0);
    b = llDeleteSubString(b, 0, 0);
    if(len_a == 0) return cost;
    if(len_b == 0) return cost;
    return cost + wasLevenshteinDistance(a, b);
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list wasDialogMenu(list input, list actions, string direction) {
    integer cut = 11-wasListCountExclude(actions, [""]);
    integer wasMenuIndex = (integer)wasKeyValueGet("index", llGetObjectDesc());
    if(direction == ">" &&  (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) {
        ++wasMenuIndex;
        llSetObjectDesc(wasKeyValueSet("index", (string)wasMenuIndex, llGetObjectDesc()));
        jump slice;
    }
    if(direction == "<" && wasMenuIndex-1 >= 0) {
        --wasMenuIndex;
        llSetObjectDesc(wasKeyValueSet("index", (string)wasMenuIndex, llGetObjectDesc()));
        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) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string var, string kvp) {
    list dVars = llParseString2List(kvp, ["%"], []);
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k != var) jump continue;
        return llList2String(data, 1);
@continue;
        dVars = llDeleteSubList(dVars, 0, 0);
    } while(llGetListLength(dVars));
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueSet(string var, string val, string kvp) {
    list dVars = llParseString2List(kvp, ["%"], []);
    if(llGetListLength(dVars) == 0) return var + "=" + val;
    list result = [];
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k == "") jump continue;
        if(k == var && val == "") jump continue;
        if(k == var) {
            result += k + "=" + val;
            val = "";
            jump continue;
        }
        string v = llList2String(data, 1);
        if(v == "") jump continue;
        result += k + "=" + v;
@continue;
        dVars = llDeleteSubList(dVars, 0, 0);
    } while(llGetListLength(dVars));
    if(val != "") result += var + "=" + val;
    return llDumpList2String(result, "%");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueDelete(string var, string kvp) {
    list dVars = llParseString2List(kvp, ["%"], []);
    list result = [];
    list added = [];
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k == var) jump continue;
        string v = llList2String(data, 1);
        if(v == "") jump continue;
        if(llListFindList(added, (list)k) != -1) jump continue;
        result += k + "=" + v;
        added += k;
@continue;
        dVars = llDeleteSubList(dVars, 0 ,0);
    } while(llGetListLength(dVars));
    return llDumpList2String(result, "%");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
list spinChars = [ "↑", "↗", "→", "↘", "↓", "↙", "←" ];
string spin() {
    string text = llList2String(llGetLinkPrimitiveParams(LINK_THIS, [PRIM_TEXT]), 0);
    do {
        string tok = llGetSubString(text, llStringLength(text)-1, llStringLength(text)-1);
        if(!~llListFindList(spinChars, (list)tok) && tok != "\n" && tok != "[" && tok != "]") jump show;
        text = llDeleteSubString(text, llStringLength(text)-1, llStringLength(text)-1);
    } while(llStringLength(text));
@show;
    string next = llList2String(spinChars,  0);
    spinChars = llDeleteSubList(spinChars, 0, 0);
    spinChars += next;
    return "[" + next + "]";
}
 
///////////////////////////////////////////////////////////////////////////
//    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) 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) 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)>;
}
 
default {
    state_entry() {
        llSetObjectDesc(wasKeyValueSet("index", "0", llGetObjectDesc()));
        llSetTextureAnim(ANIM_ON | SMOOTH | LOOP, ALL_SIDES,1,1,1,1,0.1);
        llSetText("-=:[ Please wait, reading brains... ]:=-\n", <1,1,0>, 1);
        integer i = llGetInventoryNumber(INVENTORY_NOTECARD)-1;
        do {
            list bCard = llParseString2List(llGetInventoryName(INVENTORY_NOTECARD, i), ["_"], [""]);
            if(llList2String(bCard, 0) != "Trivia" || llList2String(bCard, 1) != "Brain") jump continue;
            cards += llGetInventoryName(INVENTORY_NOTECARD, i);
@continue;
        } while(--i>-1);
        if(llGetListLength(cards) != 0) state categorize;
        llSay(DEBUG_CHANNEL, "Failed to find any Trivia brains.");
    }
    on_rez(integer param) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
}
 
state categorize {
    state_entry() {
        cardIterator = llGetListLength(cards)-1;
        card = llList2String(cards, cardIterator);
        llSetText("-=:[ Please wait, categorizing brains... ]:=-\nBrain: " + card + " " + spin(), <1,1,0>, 1);
        lineIterator = 0;
        llGetNotecardLine(card, lineIterator);
    }
    dataserver(key id, string data) {
        if(data == EOF) {
            if(cardIterator-- == 0) state start;
            card = llList2String(cards, cardIterator);
            lineIterator = 0;
            llGetNotecardLine(card, lineIterator);
            return;
        }
        if(data == "") jump continue;
        string category = llList2String(
                            llParseString2List(
                                llList2String(
                                    llParseString2List(data, ["//"], [""]), 0), ["/"], [""]), 0);
        if(llListFindList(categories, (list)category) != -1) jump continue;
        categories += category;
@continue;
        llSetText("-=:[ Please wait, categorizing brains... ]:=-\nBrain: " + card + " " + spin(), <1,1,0>, 1);
        llGetNotecardLine(card, ++lineIterator);
    }
 
}
 
state start {
    state_entry() {
        qC = <llFrand(1), llFrand(1), llFrand(1)>;
        llParticleSystem([PSYS_SRC_TEXTURE,llGetInventoryName(0,0),PSYS_PART_START_SCALE,<.2,.3,0>,6,<.2,.3,0>,PSYS_PART_START_COLOR,
qC,PSYS_PART_END_COLOR,qC,PSYS_PART_START_ALPHA,.05,PSYS_PART_END_ALPHA,.05,PSYS_SRC_BURST_PART_COUNT,0x7FFFFFFF,PSYS_PART_MAX_AGE,1,PSYS_SRC_MAX_AGE,0,PSYS_SRC_PATTERN,(integer)4,PSYS_SRC_BURST_SPEED_MIN,0,PSYS_SRC_BURST_SPEED_MAX,0,PSYS_SRC_ANGLE_BEGIN,
(float)0.03*3.141593,PSYS_SRC_ANGLE_END,(float)0*3.141593,8,
ZERO_VECTOR,PSYS_PART_FLAGS,(integer)(0|1|PSYS_PART_EMISSIVE_MASK)]);
        llSetText("-=:[ Touch to Start Trivia ]:=-", <1,1,0>, 1);
    }
    touch_start(integer num) {
        llSetText("", <0,0,0>, 1);
        // only for owner
        if(llDetectedKey(0) != llGetOwner()) state proximity;
        // fallthrough user
        state configure;
    }
    on_rez(integer param) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
}
 
state proximity {
    state_entry() {
        qC = <llFrand(1), llFrand(1), llFrand(1)>;
        llParticleSystem([PSYS_SRC_TEXTURE,llGetInventoryName(0,0),PSYS_PART_START_SCALE,<.2,.3,0>,6,<.2,.3,0>,PSYS_PART_START_COLOR,
qC,PSYS_PART_END_COLOR,qC,PSYS_PART_START_ALPHA,.05,PSYS_PART_END_ALPHA,.05,PSYS_SRC_BURST_PART_COUNT,0x7FFFFFFF,PSYS_PART_MAX_AGE,1,PSYS_SRC_MAX_AGE,0,PSYS_SRC_PATTERN,(integer)4,PSYS_SRC_BURST_SPEED_MIN,0,PSYS_SRC_BURST_SPEED_MAX,0,PSYS_SRC_ANGLE_BEGIN,
(float)0.03*3.141593,PSYS_SRC_ANGLE_END,(float)0*3.141593,8,
ZERO_VECTOR,PSYS_PART_FLAGS,(integer)(0|1|PSYS_PART_EMISSIVE_MASK)]);
        shutdown = 10;
        llSensorRepeat("", "", AGENT, 64, TWO_PI, 1);
    }
    touch_start(integer num) {
        // abort, only for owner
        if(llDetectedKey(0) != llGetOwner()) return;
        state configure;
    }
    sensor(integer num) {
        shutdown = 10;
        state select;
    }
    no_sensor() {
        if(--shutdown > 0) return;
        state start;
    }
}
 
state select {
    state_entry() {
        if(cardIterator < 0) cardIterator = llGetListLength(cards)-1;
        card = llList2String(cards, cardIterator);
        llGetNumberOfNotecardLines(card);
    }
    touch_start(integer num) {
        // abort, only for owner
        if(llDetectedKey(0) != llGetOwner()) return;
        state configure;
    }
    dataserver(key id, string data) {
        lineIterator = (integer)data-1;
        state search;
    }
    on_rez(integer param) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
}
 
state search {
    state_entry() {
        card = llList2String(cards, cardIterator);
        llGetNotecardLine(card, lineIterator);
    }
    touch_start(integer num) {
        // abort, only for owner
        if(llDetectedKey(0) != llGetOwner()) return;
        state configure;
    }
    dataserver(key id, string data) {
        if(data == EOF) {
            --cardIterator;
            state select;
        }
        if(data == "") jump continue;
        list qaSplit = llParseString2List(data, ["//"], [""]);
        list caSplit = llParseString2List(llList2String(qaSplit, 0), ["/"], [""]);
        string selectedCategory = wasKeyValueGet("category", llGetObjectDesc());
        if(selectedCategory != "" && selectedCategory != llList2String(caSplit, 0)) jump continue;
        category = llList2String(caSplit, 0);
        question = llList2String(qaSplit, 1);
        caSplit = llDeleteSubList(caSplit, 0, 0);
        string head = llList2String(caSplit, 0);
        if(llGetFreeMemory() < 2048) {
            memCacheHit = 0;
            mem = [];
        }
        if(llListFindList(mem, (list)head) != -1) {
            if(++memCacheHit > 4) state start;
            jump continue;
        }
        memCacheHit = 0;
        integer s = llStringLength(head)-1;
        clue = "";
        do {
            clue += "-";
        } while(--s>-1);
        mem += [ head ];
        store = [ head ];
        do {
            store += llList2String(caSplit, 0);
            caSplit = llDeleteSubList(caSplit, 0, 0);
        } while(llGetListLength(caSplit) != 0);
        state ask;
@continue;
        string text = "-=:[ Searching question... ]:=-\n" + "Brain: " + card + " " + spin();
        if(llStringLength(topDisplay) != 0) text += "\n\n\n-=:[ Top ]:=-\n" + topDisplay;
        llSetText(text, <1,1,0>, 1);
        llGetNotecardLine(card, --lineIterator);
    }
    on_rez(integer param) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
}
 
state ask {
    state_entry() {
        comHandle = llListen(0, "", "", "");
        llSay(0, "[" + category + "]: " + question);
        seconds = llStringLength(clue);
        llSetTimerEvent(TIME_PER_LETTER);
    }
    touch_start(integer num) {
        // abort, only for owner
        if(llDetectedKey(0) != llGetOwner()) return;
        state configure;
    }
    listen(integer chan,string name,key id,string mes) {
        // if it's a number, we want a perfect match
        if((integer)mes > 0 && llListFindList(store, (list)llToLower(mes)) == -1) return;
        integer i = llGetListLength(store)-1;
        do {
            string answer = llList2String(store, i);
            if(llStringLength(answer) != llStringLength(mes)) jump continue;
            if(wasLevenshteinDistance(llToLower(answer), llToLower(mes)) >= 2) jump continue;
            // lock
            llListenRemove(comHandle);
            llSetTimerEvent(0);
            jump correct;
@continue;
        } while(--i>-1);
        return;
@correct;
        llSay(0, name + "'s answer is correct! " + llList2String(store, 0) + ", is the correct answer!");
        integer idx = llListFindList(names, (list)name);
        if(idx == -1) {
            names = llListInsertList(names, (list)name, 0);
            scores = llListInsertList(scores, (list)1, 0);
            jump compute;
        }
        integer score = llList2Integer(scores, idx)+1;
        scores=llListReplaceList(scores, (list)score, idx, idx);
@compute;
        list sort = wasDualQuicksort(scores, names);
        topDisplay = "";
        integer count = 0;
        do {
            topDisplay += llList2String(sort, 1);
            topDisplay += " -> ";
            topDisplay += llList2String(sort, 0);
            topDisplay += "\n";
            sort = llDeleteSubList(sort, 0, 0);
            sort = llDeleteSubList(sort, 0, 0);
            if(++count==5) jump show;
        } while(llGetListLength(sort) != 0);
@show;
        llSetText("-=:[ Top ]:=-\n" + topDisplay, <1,1,0>, 1);
        state proximity;
    }
    timer() {
        llParticleSystem([
           PSYS_SRC_TEXTURE, llGetInventoryName(INVENTORY_TEXTURE, 0), 
           PSYS_PART_START_SCALE, <.01, .014, 0>, PSYS_PART_END_SCALE, <.1, .14, 0>, 
           PSYS_PART_START_COLOR, qC,    PSYS_PART_END_COLOR, <.5 + qC.x,.5 + qC.y, .5 + qC.z>,
           PSYS_SRC_BURST_PART_COUNT, 0x7FFFFFFF,
           PSYS_PART_MAX_AGE, 1.25,
           PSYS_SRC_MAX_AGE, 1.25,
           PSYS_SRC_PATTERN, 8,
           PSYS_SRC_BURST_SPEED_MIN, (float)1,   PSYS_SRC_BURST_SPEED_MAX, (float)1.2, 
           PSYS_SRC_ANGLE_BEGIN, 0,    PSYS_SRC_ANGLE_END, TWO_PI,       
           PSYS_PART_FLAGS, ( 0 | PSYS_PART_INTERP_SCALE_MASK
                                | PSYS_PART_INTERP_COLOR_MASK    
                                | PSYS_PART_EMISSIVE_MASK     
                            )                  
        ]);
        string answer = llList2String(store, 0);
        integer i = (integer)llFrand(llStringLength(answer));
        do {
            --i;
            if(i < 0) i = llStringLength(answer);
        } while(llGetSubString(clue, i, i) != "-");
        clue = llDeleteSubString(clue, i, i);
        clue = llInsertString(clue, i, llGetSubString(answer, i, i));
        string text = "Clue: " + "[" + clue +  "]";
        integer progress;
        i = llStringLength(clue)-1;
        do {
            if(llGetSubString(answer, i, i) != "-") ++progress;
        } while(--i>-1);
        if(llStringLength(topDisplay) != 0) text += "\n\n\n-=:[ Top ]:=-\n" + topDisplay;
        llSetText(text, wasPercentToGradient(100*progress/llStringLength(clue), "rg"), 1.0);
        if(--seconds == 0) {
            llSay(0, "A correct answer would have been: " + answer + ".");
            state proximity;
        }
    }
    on_rez(integer param) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
}
 
state configure {
    state_entry() {
        qC = <llFrand(1), llFrand(1), llFrand(1)>;
        llParticleSystem([PSYS_SRC_TEXTURE,llGetInventoryName(0,0),PSYS_PART_START_SCALE,<.2,.3,0>,6,<.2,.3,0>,PSYS_PART_START_COLOR,
qC,PSYS_PART_END_COLOR,qC,PSYS_PART_START_ALPHA,.05,PSYS_PART_END_ALPHA,.05,PSYS_SRC_BURST_PART_COUNT,0x7FFFFFFF,PSYS_PART_MAX_AGE,1,PSYS_SRC_MAX_AGE,0,PSYS_SRC_PATTERN,(integer)4,PSYS_SRC_BURST_SPEED_MIN,0,PSYS_SRC_BURST_SPEED_MAX,0,PSYS_SRC_ANGLE_BEGIN,
(float)0.03*3.141593,PSYS_SRC_ANGLE_END,(float)0*3.141593,8,
ZERO_VECTOR,PSYS_PART_FLAGS,(integer)(0|1|PSYS_PART_EMISSIVE_MASK)]);
        llSetText("-=:[ Configuring... ]:=-", <1,1,0>, 1);
        integer comChannel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
        llListen(comChannel, "", llGetOwner(), "");
        llDialog(llGetOwner(), "Select a category for the Trivia machine from the following options:\n", wasDialogMenu(categories, ["⟵ Back", "⦡ Any", "Next ⟶", "◯ STOP", "", "◉ START"], ""), comChannel);
        seconds = 30;
        llSetTimerEvent(1);
    }
    touch_start(integer num) {
        if(llDetectedKey(0) != llGetOwner()) return;
        llSetText("-=:[ Configuring... ]:=-", <1,1,0>, 1);
        integer comChannel = (integer)("0x8" + llGetSubString(llGetKey(), 0, 6));
        llListen(comChannel, "", llGetOwner(), "");
        llDialog(llGetOwner(), "Select a category for the Trivia machine from the following options:\n", wasDialogMenu(categories, ["⟵ Back", "⦡ Any", "Next ⟶", "◯ STOP", "", "◉ START"], ""), comChannel);
        seconds = 30;
        llSetTimerEvent(1);
    }
    listen(integer channel, string name, key id, string message) {
        if(message == "◉ START") state proximity;
        if(message == "◯ STOP") state start;
        seconds = 30;
        if(message == "⟵ Back") {
            llDialog(id, "Select a category for the Trivia machine from the following options:\n", wasDialogMenu(categories, ["⟵ Back", "⦡ Any", "Next ⟶", "◯ STOP", "", "◉ START"], "<"), channel);
            return;
        }
        if(message == "Next ⟶") {
            llDialog(id, "Select a category for the Trivia machine from the following options:\n", wasDialogMenu(categories, ["⟵ Back", "⦡ Any", "Next ⟶", "◯ STOP", "", "◉ START"], ">"), channel);
            return;
        }
        if(message == "⦡ Any") {
            llSetObjectDesc(wasKeyValueDelete("category", llGetObjectDesc()));
            llDialog(id, "Select a category for the Trivia machine from the following options:\n", wasDialogMenu(categories, ["⟵ Back", "⦡ Any", "Next ⟶", "◯ STOP", "", "◉ START"], ""), channel);
            return;
        }
        llSetObjectDesc(wasKeyValueSet("category", message, llGetObjectDesc()));
        llDialog(id, "Select a category for the Trivia machine from the following options:\n", wasDialogMenu(categories, ["⟵ Back", "⦡ Any", "Next ⟶", "◯ STOP", "", "◉ START"], ""), channel);
    }
    timer() {
        if(seconds <= 0) state start;
        integer progress = 100*(seconds--)/30;
        string text = "-=:[ Configuring... ]:=-\n" + wasProgress(progress, 10, ["[", "#", "o", "]"]);
        if(llStringLength(topDisplay) != 0) text += "\n\n-=:[ Top ]:=-\n" + topDisplay;
        llSetText(text, wasPercentToGradient(progress, "rg"), 1);
    }
    on_rez(integer param) {
        llResetScript();
    }
    changed(integer change) {
        if(change & CHANGED_INVENTORY) llResetScript();
    }
}

secondlife/trivia.txt · Last modified: 2022/11/24 07:46 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.