Allen Kerensky"It seems you've been living two lives ..."

Myriad Lite Module BAM

// Myriad_Lite_Module_BAM-v0.0.6-20131026.lsl
// Copyright (c) 2013 by Baroun Tardis (OSG/SL) and Allen Kerensky (OSG/SL) All Rights Reserved.
// This work is dual-licensed under
// Creative Commons Attribution (CC BY) 3.0 Unported
// http://creativecommons.org/licenses/by/3.0/
// - or -
// Modified BSD License (3-clause)
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, 
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Neither the name of Myriad Lite nor the names of its contributors may be
//   used to endorse or promote products derived from this software without
//   specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
// NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// The Myriad RPG System was designed, written, and illustrated by Ashok Desai
// Myriad RPG System licensed under:
// Creative Commons Attribution (CC BY) 2.0 UK: England and Wales
// http://creativecommons.org/licenses/by/2.0/uk/
 
// FIXME - needs some RPEVENTS to tell others about quester's actions?
// FIXME - needs some HELP events to tell others how to use the thing
 
// CONSTANTS - DO NOT CHANGE DURING RUN
string BASENAME = "Myriad Lite Module BAM";
string VERSION = "0.0.6"; // script version
string VERSIONDATE = "20131026"; // script date
 
// Module to Module Messaging Constants
integer MODULE_BAM = -4;
integer LM_SENDTOATTACHMENT = 0x80000000;
 
string API_OFFERADV = "OfferAdv"; // Offer an adventure to HUD wearer
string API_ACCEPTADV = "AcceptAdv"; // Offer accepted player is on an adventure
string API_INADV_QUERY = "InAdv?"; // Ask a player HUD if the player is in an adventure - InAdv?
string API_INADV_RESPONSE = "InAdv"; // In Adventure Response Yes: InAdv | String AdventureName  No: InAdv | NONE
string API_TASKIP_QUERY = "TaskIP?";
string API_TASKIP_RESPONSE = "TaskIP"; // Task In Progress Reply current task in progress: TaskIP | AdventureGoal
string API_TASKCP_QUERY = "TaskCP?"; // Task Complete Query
string API_TASKCP_RESPONSE = "TaskCP"; // Task Complete Reply
string API_DONETASK = "DoneTask"; // Task Done - player achieved current goal NPC sends: DoneTask | GoalText | TaskDone Text | PlayerUUID
string API_DONEADV = "DoneAdv"; // Done Adventure reply
string API_NONE = "NONE"; // a fixed string when not in adventure - uses variable to stay consistent everywhere
string API_ADDTASK = "AddTask"; // Add a task to the Player HUD - AddTask | TaskNumber | String Describing Task
string API_ADDHINT = "AddHint"; // Add a hint for a task to the Player HUD - AddHint | TaskNumber | String Hint
string MSG_NO_ADVENTURE = "Looking for adventure...";
string MSG_CURRENT_ADVENTURE = "Adventure: ";
string MSG_CURRENT_GOAL = "Overall Goal: ";
string MSG_CURRENT_TASK = "Current Task: ";
string MSG_CURRENT_HINT = "Current Hint: ";
 
// RUNTIME GLOBALS - CAN CHANGE DURING RUN
integer CHANOBJBAM; // channel of thing we're talking to
string  STATUSMSG; // scratch space to build status messages
 
// Adventure-Specific Configuration
// Task numbers are (AdvNum*100)+task, so they don't overlap between adventures
// string  ADVNAME="NONE"; // Adventure Name
// string  ADVTEXT; // brief description
// Current Task-specific info
// string  ADVTASKTODO; // task name of the next task handed out
// integer ADVTASKTDNUM; // task number of the next task handed out
// string  ADVTASKTODOHINT; // Hint text for the next task handed out
// Previous Task-specific info
// list    ADVTCOMP; // completed task numbers (list of numbers)
 
//
// PPMA GET_VAL
//
string KEY_NOT_FOUND = "[KEY_NOT_FOUND]";
string GET_VAL(string dbkey,string field) {
    //OWNERSAY("GET_VAL KEY=["+dbkey+"] FIELD=["+field+"]");
    string out = KEY_NOT_FOUND;
    integer i;
    string name;
    string desc;
    for ( i = 2; i <= llGetNumberOfPrims(); i++ ) {
        name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0);
        desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0);
        if ( llToLower(name) == llToLower(dbkey) && llToLower(desc) == llToLower(field) ) {
            out = llList2String(llGetLinkPrimitiveParams(i,[PRIM_TEXT]),0);
            //DEBUG("GET_VAL RETURN=["+out+"]");
            return out; // bail on first match?
        }
    }
    //OWNERSAY("GET_VAL RETURN=["+out+"]");
    return out;
}
 
SET_VAL(string dbkey, string field, string val) {
    //OWNERSAY("SET_VAL KEY=["+dbkey+"] FIELD=["+field+"] VAL=["+val+"]");
    integer i;
    string name;
    string desc;
    integer written = FALSE;
    for ( i = 2; i <= llGetNumberOfPrims(); i++ ) {
        name = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0),STRING_TRIM);
        desc = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0),STRING_TRIM);
        if ( ( llToLower(name) == llToLower(dbkey) && llToLower(desc) == llToLower(field) ) && written == FALSE ) {
            //OWNERSAY("SET_VAL UPDATE RECORD=["+(string)i+"] DBKEY=["+dbkey+"] DESC=["+field+"] VAL=["+val+"]");
            llSetLinkPrimitiveParamsFast(i,[PRIM_NAME,dbkey,PRIM_DESC,field,PRIM_TEXT,val,ZERO_VECTOR,0.0]);
            written = TRUE; // we did an update, remember it
        }    
    }
    if ( written == TRUE ) {
        //OWNERSAY("SET_VAL UPDATE COMPLETE.");
        return;
    }
    // data hasn't been written, scan for free prim
    for ( i = 2; i <= llGetNumberOfPrims(); i++ ) {
        name = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0),STRING_TRIM);
        desc = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0),STRING_TRIM);
        if ( ( name == "" && desc == "" ) && written == FALSE ) {
            //OWNERSAY("SET_VAL INSERT RECORD=["+(string)i+"] DBKEY=["+dbkey+"] DESC=["+field+"] VAL=["+val+"]");
            llSetLinkPrimitiveParamsFast(i,[PRIM_NAME,dbkey,PRIM_DESC,field,PRIM_TEXT,val,ZERO_VECTOR,0.0]);
            written = TRUE; // we did an update, remember it
        }
    }
    if ( written == TRUE ) {
        //OWNERSAY("SET_VAL INSERT COMPLETED.");
        return;
    }
    //OWNERSAY("SET_VAL NO FREE RECORD FOUND TO INSERT INTO! DATA LOST");
}
 
//////////////////////////////////////////////////////////////////////////////
// FLAG FUNCTIONS
// INCAPACITATED - lost wounds
// DEAD - lost critical wounds
// DEBUG - show debug messages or not
// IDEA: INDECISION - lost resolve?
 
// LMIM: SET_FLAG|<name>=<TRUE|FALSE>
// PPMA: FLAG,<flagname>,<TRUE|FALSE>
// LMOUT: FLAG|<flagname>=<TRUE|FALSE>
// LMERR: FIXME
integer GET_FLAG(string flag) {
    string val = GET_VAL("FLAG",llToUpper(flag));
    if ( val == KEY_NOT_FOUND ) {
        ERROR("Flag ["+flag+"] does not exist.");
    }
    if ( val != "0" && val != "1") {
        ERROR("Flag: "+flag+" invalid value ["+val+"]");
    }
    integer bool = (integer)val;
    return bool;
}
 
// SET_FLAG
// LMIM: SET_FLAG|<flagname>=<TRUE|FALSE>
// PPMA: FLAG,<flagname>,<TRUE|FALSE>
// LMOUT: SET_FLAG|<flagname>=<TRUE|FALSE>
// LMERR: FIXME
SET_FLAG(string flag,integer value) {
    if ( flag == "" ) return; // FIXME add error
    if ( value != TRUE && value != FALSE ) return; // FIXME add err
    SET_VAL("FLAG",llToUpper(flag),(string)value);
}
 
// Adventure-Specific Configuration
// Adventure Name
string GET_ADVNAME() {
    string advname = GET_VAL("BAM","ADVENTURENAME");
    if ( advname == KEY_NOT_FOUND ) return API_NONE;
    return advname;
}
 
SET_ADVNAME(string name) {
    // FIXME RANGE CHECKS
    SET_VAL("BAM","ADVENTURENAME",name);
}
 
// Adventure brief description
string GET_ADVTEXT() {
    string advtext = GET_VAL("BAM","ADVENTURETEXT");
    if ( advtext == KEY_NOT_FOUND ) return "";
    return advtext;    
}
 
SET_ADVTEXT(string text) {
    // FIXME RANGE CHECKS
    SET_VAL("BAM","ADVENTURETEXT",text);
}
 
// task name of the next task handed out
string GET_ADVTASKTODO() {
    string todo = GET_VAL("BAM","ADVENTURENEXT");
    if ( todo == KEY_NOT_FOUND ) return "";
    return todo;
}
 
SET_ADVTASKTODO(string todo) {
    // FIXME RANGE CHECKS
    SET_VAL("BAM","ADVENTURETODO",todo);
}
 
// Task numbers are (AdvNum*100)+task, so they don't overlap between adventures
// task number of the next task handed out
integer GET_ADVTASKTODONUMBER() {
    string todonum = GET_VAL("BAM","ADVENTURETODONUMBER");
    if ( todonum == KEY_NOT_FOUND ) return 0;
    return (integer)todonum;
}
 
SET_ADVTASKTODONUMBER(integer todonumber) {
    // FIXME RANGE CHECKS
    if ( todonumber < 0 ) {
        ERROR("Adventure next task number less than zero - ignoring");
        return;
    }
    SET_VAL("BAM","ADVENTURENEXT",(string)todonumber);
}
 
// Hint text for the next task handed out
string GET_ADVTASKTODOHINT() {
    string hint = GET_VAL("BAM","ADVENTURETODOHINT");
    if ( hint == KEY_NOT_FOUND ) hint = "";
    return hint;
}
 
SET_ADVTASKTODOHINT(string hint) {
    // FIXME RANGE CHECKS
    SET_VAL("BAM","ADVENTURETODOHINT",hint);
}
 
// numerically sorted list of completed task numbers
list GET_ADVTASKCOMP() {
    string tasksdone = GET_VAL("BAM","ADVENTURETASKSCOMPLETE");
    if ( tasksdone == KEY_NOT_FOUND ) return [];
    return llListSort(llCSV2List(tasksdone),1,TRUE);
}
 
SET_ADVTASKCOMP(list done) {
    // FIXME RANGE CHECKS
    SET_VAL("BAM","ADVENTURETASKSCOMPLETE",llList2CSV(llListSort(done,1,TRUE)));
}
 
//============================================================================
// DEBUG - show errors on debug channel with wearer name for sorting
//============================================================================
DEBUG(string debugmsg) {
    if ( GET_FLAG("DEBUG") == TRUE ) llMessageLinked(LINK_THIS,MODULE_BAM,"DEBUG|"+debugmsg,llGetOwner());
}
 
//
// ERROR
//
ERROR(string msg) {
    llMessageLinked(LINK_THIS,MODULE_BAM,"ERROR|"+msg,llGetOwner());
}
 
// MEMORY
GET_MEMORY() {
    OWNERSAY(BASENAME+" free memory: "+(string)llGetFreeMemory()); // show this module's free memory info
}
 
// GETVERSION
GET_VERSION() {
    OWNERSAY(BASENAME+" v"+VERSION+"-"+VERSIONDATE); // show this module's version info
}
 
//
// OWNERSAY
//
OWNERSAY(string msg) {
    llMessageLinked(LINK_THIS,MODULE_BAM,"OWNERSAY|"+msg,llGetOwner());
}
 
// RESET - shut down running animations then reset the script to reload character sheet
RESET() {
    llResetScript(); // now reset
}
 
//============================================================================
// SETUP - begin bringing the HUD online
//============================================================================
SETUP() {
    llSetText("",<0,0,0>,0); // clear any previous hovertext
    if ( llGetAttached() >= 31 && llGetAttached() <= 38 ) { // are we attached to a HUD slot?
        SET_FLAG("BAMSTATUS",TRUE); // turn on HUD hovertext
    } else {
        SET_FLAG("BAMSTATUS",FALSE); // turn off body attached hovertext
    }
    STATUS();
    OWNERSAY("Baroun's Adventure Machine module active.");
}
 
//============================================================================
// STATUS() - update adventure data on HUD
//============================================================================
STATUS() {
    if ( GET_ADVNAME() == API_NONE ) { // is player in an adventure?
        STATUSMSG = MSG_NO_ADVENTURE; // nope
    } else { // yep, build the status
        STATUSMSG = MSG_CURRENT_ADVENTURE + GET_ADVNAME() + "\n" +
        MSG_CURRENT_GOAL + GET_ADVTEXT() + "\n" +
        MSG_CURRENT_TASK + GET_ADVTASKTODO() + "\n" +
        MSG_CURRENT_HINT + GET_ADVTASKTODOHINT();
    }
    OWNERSAY(STATUSMSG);
    if ( GET_FLAG("BAMSTATUS") == TRUE ) { // if attached to body, use chat output
        llSetText(STATUSMSG,<1,1,1>,1.0);
    }
}
 
//============================================================================
// DEFAULT STATE - load character sheet
//============================================================================
default {
    //------------------------------------------------------------------------
    // LINK MESSAGE - commands to and from other prims in HUD
    //------------------------------------------------------------------------
    link_message(integer sender,integer sending_module,string message, key speakerid) {
        if ( sending_module == MODULE_BAM || sending_module == LM_SENDTOATTACHMENT ) return; // ignore our own messages
 
        // break down the commands and messages into units we can work with
        list fields = llParseString2List(message,["|"],[]); // break into list of fields based on "|"ider
        string command = llToUpper(llList2String(fields,0)); // assume the first field is a Myriad Lite command
 
        if ( command == "DEBUG" || command == "ERROR" || command == "HELP" || command == "OWNERSAY" || command == "RPEVENT" ) return;
 
        if ( command == "MEMORY" ) { GET_MEMORY(); return;} // get memory info
        if ( command == "RESET" ) { RESET(); return;} // reset on command
        if ( message == "VERSION" ) { GET_VERSION(); return; } // dump the version and date on request
 
        DEBUG("EVENT link_message("+(string)sender+","+(string)sending_module+","+message+","+(string)speakerid+")");
 
        if ( message == "BAMSTATUS" ) { STATUS(); return;} // show status when specifically requested
 
        // calculate BAM dynamic channel of item/player talking to us
        CHANOBJBAM = (integer)("0x" + llGetSubString((string)speakerid,-7,-1));
 
        // process the rest of the fields for multi-field commands
        string data1   = llList2String(fields,1);
        string data2   = llList2String(fields,2);
        string data3   = llList2String(fields,3);
 
        // We're asked what adventure we're in
        if ( command == API_INADV_QUERY ) {
            llSay(CHANOBJBAM,API_INADV_RESPONSE + "|" + GET_ADVNAME()); // reply with In Adventure and Adventure Name
            STATUS();
            return; // command done, return early
        }
 
        // We're asked our current task in progress
        if ( command == API_TASKIP_QUERY ) { // what task in progress?
            // respond with task in progress
            llSay(CHANOBJBAM, API_TASKIP_RESPONSE + "|" + (string)GET_ADVTASKTODONUMBER()); // Reply with current task in progress and number
            STATUS();
            return; // command done, return early
        }
 
        // Get list of completed tasks
        if ( command == API_TASKCP_QUERY ) { // what tasks complete?
            llSay(CHANOBJBAM, API_TASKCP_RESPONSE + "|" + llList2CSV(GET_ADVTASKCOMP())); // reply with current task complete list as CSV
            STATUS();
            return; // command done, return early
        }
 
        // player is offered an adventure
        if ( command == API_OFFERADV ) { // want adventure?
            // FIXME need to add dialog box to accept/decline later
            SET_ADVNAME(data1); // name of the adventure
            SET_ADVTEXT(data2); // description of the adventure
            SET_ADVTASKCOMP([]); // clear the completed task list and start new one
            SET_ADVTASKTODO(""); // clear the next task name
            SET_ADVTASKTODONUMBER(0); // clear the next task number
            llSay(CHANOBJBAM, API_ACCEPTADV + "|" +data1); // accept the adventure
            STATUS();
            return; // command done, return early
        }
 
        // add the next task to complete
        if ( command == API_ADDTASK ) { // add a task
            SET_ADVTASKTODONUMBER((integer)data1); // next task number
            SET_ADVTASKTODO(data2); // next task name
            OWNERSAY(data2); // tell player the next task name
            STATUS();
            return; // command done, return early
        }
 
        // add a hint for the next task to complete
        if( ( command == API_ADDHINT ) && ( (integer)data1 == GET_ADVTASKTODONUMBER()) ) {
            SET_ADVTASKTODOHINT(data2); // next task hint
            OWNERSAY(data2); // tell that player the next task hint
            STATUS();
            return; // command done, return early
        }
 
        // is player done with this task of the adventure?
        if ( ( command == API_DONETASK ) && ( (integer)data1 == GET_ADVTASKTODONUMBER()) ) {
            list temp = GET_ADVTASKCOMP();
            SET_ADVTASKCOMP([(integer)data1] + temp); // add this task number to completed list
            SET_ADVTASKTODONUMBER(0); // clear out the task number we're working on since its done now
            SET_ADVTASKTODO(""); // clear out the task name
            SET_ADVTASKTODOHINT(""); // clear out the task hint
            OWNERSAY(data2); // tell player task is complete
            if ( data3 != "" ) llPlaySound(data3,0.5); // play sound if one was defined
            STATUS();
            return; // command done, return early
        }
 
        // is player done with the entire adventure?
        if ( ( command == API_DONEADV ) && ( data1 == GET_ADVNAME() ) ) {
            SET_ADVTASKCOMP([]); // clear out adventure tasks - we're done
            SET_ADVTASKTODONUMBER(0); // clear out next task number
            SET_ADVTASKTODO(""); // clear out name of next task
            SET_ADVTASKTODOHINT(""); // clear out next task hint
            SET_ADVNAME(API_NONE); // set current adventure name to none
            SET_ADVTEXT(MSG_NO_ADVENTURE); // set the current adventure name to
            OWNERSAY(data2); // tell player adventure is complete
            if ( data3 != "" ) llPlaySound(data3,0.5); // play sound if one was defined
            STATUS();
            return; // command done, return early
        }
    } // end link message
 
    //------------------------------------------------------------------------
    // STATE ENTRY - called on Reset
    //------------------------------------------------------------------------
    state_entry() {
        SETUP(); // show credits and start character sheet load
    }
 
    //------------------------------------------------------------------------
    // TOUCH_START - touch HUD for adventure update
    //------------------------------------------------------------------------
    touch_start(integer total_number) {
        total_number = 0; // LSLINT
        STATUS();
    }
} // end state running
// END
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
DokuWiki