Myriad Lite Module Template

// Myriad_Lite_Module_Generator-v0.0.0-20131117.lsl
// Copyright (c) 2013 by 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 - LEVEL TITLES - should this be part of the CAREER TEMPLATE?
 
// FIXME CONVERT INCAP and DEAD to FLAG
// FIXME more RPEVENT
// FIXME more HELP
 
// CONSTANTS - DO NOT CHANGE DURING RUN
string BASENAME = "Myriad Lite Module Generator";
string VERSION = "0.0.0"; // Allen Kerensky's script version
string VERSIONDATE = "20131117"; // Allen Kerensky's script yyyymmdd
 
// Module to Module Messaging Constants
integer MODULE_GENERATOR = -12;
integer LM_SENDTOATTACHMENT = 0x80000000;
 
// RUNTIME GLOBALS - MAY CHANGE
 
 
// Prim Persistent Memory Array Support
DELETE_RECORD(string dbkey, string field) {
    //OWNERSAY("DELETE_RECORD=["+dbkey+"] FIELD=["+field+"] START");
    // scan index or prim names for empty, get number for update
    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 ( name == dbkey && desc == field ) { // record found, delete
            llSetLinkPrimitiveParamsFast(i,[PRIM_NAME,"",PRIM_DESC,"",PRIM_TEXT,"",ZERO_VECTOR,0.0]); // save to database
        }
    }
    //OWNERSAY("DELETE_RECORD=["+dbkey+"] FIELD=["+field+"] ENDS");
}
 
integer COUNT_TYPE(string type) {
    //OWNERSAY("COUNT_TYPE TYPE=["+type+"] STARTS");
    type = llToUpper(type);
    // scan index or prim names for empty, get number for update
    integer count = 0;
    integer i;
    string name = "";
    //string desc = "";
    //string text = "";
    for ( i = 2; i <= llGetNumberOfPrims(); i++) {
        name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0);
        if ( name == type ) count++;
    }
    //OWNERSAY("COUNT_TYPE TYPE=["+type+"] COUNT=["+(string)count+"]");
    return count;
}
 
DUMP_TYPE(integer chan,string type) {
    //OWNERSAY("DUMP_TYPES CHAN=["+(string)chan+"] TYPE=["+type+"] STARTS");
    type = llToUpper(type);
    // scan index or prim names for empty, get number for update
    integer i;
    string name = "";
    string desc = "";
    string text = "";
    for ( i = 2; i <= llGetNumberOfPrims(); i++) {
        name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0);
        if ( name == type ) {
            desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0);
            text = llList2String(llGetLinkPrimitiveParams(i,[PRIM_TEXT]),0);
            if ( type == "PROGRESS" ) llSay(chan,"PROGRESS|"+desc+"="+text);
            if ( type == "STAT_INCREASE" ) llSay(chan,"STAT_INCREASE|"+desc+"="+text);
            if ( type == "SKILL_INCREASE" ) llSay(chan,"SKILL_INCREASE|"+desc+"="+text);
        }
    }
    //OWNERSAY("DUMP_TYPE ENDS");
}
 
// FIXME NEEDS TO BECOME LINK MESSAGE TO MOD_CHARSHEET!
ERASE_TYPE(string type) {
    //OWNERSAY("ERASE TYPE ["+type+"] STARTS");
    // scan index or prim names for empty, get number for update
    integer i;
    string name = "";
    string desc = "";
    for ( i = 2; i <= llGetNumberOfPrims(); i++) {
        name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0);
        if ( name == type ) {
            desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0);
            DELETE_RECORD(type,desc);
        }
    }
    //OWNERSAY("ERASE_TYPE ENDS");    
}
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);
}
 
//
// GET_MYRIAD
// Requires a MYRIAD CONSTANT NAME
// Returns the amount of that Myriad rules constant or defaultif the player does not currently have that constant
//
integer GET_MYRIAD(string setting) {
    integer retval;
    string value = GET_VAL("MYRIAD",setting);
    if ( value == KEY_NOT_FOUND ) {
        if ( setting == "MINSTAT" ) retval = 1;
        if ( setting == "MAXSTAT" ) retval = 10;
        if ( setting == "MINSKILL" ) retval = 0;
        if ( setting == "MAXSKILL" ) retval = 7;
        if ( setting == "MINEFFECT" ) retval = 0;
        if ( setting == "MAXEFFECT" ) retval = 5;
        if ( setting == "MINRESILIENCE" ) retval = 0;
        if ( setting == "MAXRESILIENCE" ) retval = 20;
        if ( setting == "MINBOON" ) retval = 0;
        if ( setting == "MAXBOON" ) retval = 5;
        if ( setting == "MINFLAW" ) retval = 0;
        if ( setting == "MAXFLAW" ) retval = 5;
        if ( setting == "MINRP" ) retval = 0;
        if ( setting == "MAXRP" ) retval = 10;
        if ( setting == "MINITEM" ) retval = 0;
        if ( setting == "MAXITEM" ) retval = 100;
        if ( setting == "MINARMOR" ) retval = 0;
        if ( setting == "MAXARMOR" ) retval = 5;
        if ( setting == "MINDAMAGE" ) retval = 0;
        if ( setting == "MAXDAMAGE" ) retval = 5;
        SET_VAL("MYRIAD",setting,(string)retval);
        ERROR("Unable to locate Myriad setting "+setting+" returning "+(string)retval);
    } else {
        retval = (integer)value;
    }
    return retval;
}
 
// STATISTICS
integer GET_STATISTIC(string stat) {
    // FIXME how to verify stat?
    integer points = (integer)GET_VAL("STATISTIC",stat);
    integer minstat = GET_MYRIAD("MINSTAT");
    integer maxstat = GET_MYRIAD("MAXSTAT");
    if ( points < minstat ) { points = minstat; SET_STATISTIC(stat,points); }
    if ( points > maxstat ) { points = maxstat; SET_STATISTIC(stat,points); }
    return points;
}
 
SET_STATISTIC(string statname,integer statrank) {
    // FIXME how to verify stat names are valid?
    integer minstat = GET_MYRIAD("MINSTAT");
    integer maxstat = GET_MYRIAD("MAXSTAT");
    if ( statrank < minstat ) statrank = minstat;
    if ( statrank > maxstat ) statrank = maxstat;
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"SET_STATISTIC|"+statname+"="+(string)statrank,llGetOwner()); // Notify CharSheet to update statistic
}
 
// SKILLS
integer GET_SKILL(string skill) {
    integer rank = (integer)GET_VAL("SKILL",skill);
    integer minskill = GET_MYRIAD("MINSKILL");
    integer maxskill = GET_MYRIAD("MAXSKILL");
    if ( rank < minskill ) { rank = minskill; SET_SKILL(skill,rank); }
    if ( rank > maxskill ) { rank = maxskill; SET_SKILL(skill,rank); }
    return rank;
}
 
SET_SKILL(string skill,integer rank) {
    // FIXME how to verify skill names are valid?
    integer minskill = GET_MYRIAD("MINSKILL");
    integer maxskill = GET_MYRIAD("MAXSKILL");
    if ( rank < minskill ) rank = minskill;
    if ( rank > maxskill ) rank = maxskill;
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"SET_SKILL|"+skill+"="+(string)rank,llGetOwner()); // notify character sheet to update skill
}
 
// SFX
integer GET_EFFECT(string name) {
    integer rank = (integer)GET_VAL("EFFECT",name);
    integer mineffect = GET_MYRIAD("MINEFFECT");
    integer maxeffect = GET_MYRIAD("MAXEFFECT");
    if ( rank < mineffect ) { rank = mineffect; SET_EFFECT(name,rank); }
    if ( rank > maxeffect ) { rank = maxeffect; SET_EFFECT(name,rank); }
    return rank;
}
 
SET_EFFECT(string name,integer rank) {
    // FIXME how to verify effect name?
    integer mineffect = GET_MYRIAD("MINEFFECT");
    integer maxeffect = GET_MYRIAD("MAXEFFECT");
    if ( rank < mineffect ) rank = mineffect;
    if ( rank > maxeffect ) rank = maxeffect;
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"SET_EFFECT|"+name+"="+(string)rank,llGetOwner()); // notify character sheet to update effect
}
 
// RESILIENCES
integer GET_RESILIENCE(string name) {
    integer cr = (integer)GET_VAL("RESILIENCE",name);
    integer minres = GET_MYRIAD("MINRESILIENCE");
    integer maxres = GET_MYRIAD("MAXRESILIENCE");
    if ( cr < minres ) { cr = minres; SET_RESILIENCE(name,cr); }
    if ( cr > maxres ) { cr = maxres; SET_RESILIENCE(name,cr); }
    return cr;
}
 
SET_RESILIENCE(string resname,integer resrank) {
    // FIXME how to verify resilience names are valid?
    integer minres = GET_MYRIAD("MINRESILIENCE");
    integer maxres = GET_MYRIAD("MAXRESILIENCE");
    if ( resrank < minres ) resrank = minres;
    if ( resrank > maxres ) resrank = maxres;
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"SET_RESILIENCE|"+resname+"="+(string)resrank,llGetOwner()); //notify character sheet to update resilience
}
 
/////////////
// UTILITY //
/////////////
 
//
// DEBUG - show debug chat with wearer name for sorting
//
DEBUG(string dmessage) {
    if ( GET_FLAG("DEBUG") == TRUE ) llMessageLinked(LINK_THIS,MODULE_GENERATOR,"DEBUG|"+dmessage,llGetOwner());
}
 
//
// ERROR - show errors on debug channel with wearer name for sorting
//
ERROR(string emessage) {
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"ERROR|"+emessage,llGetOwner());
}
 
//
// GET_MEMORY
//
GET_MEMORY() {
    OWNERSAY(BASENAME+" free memory: "+(string)llGetFreeMemory()); // show this module's free memory info
}
 
//
// GET_VERSION
//
GET_VERSION() {
    OWNERSAY(BASENAME+" v"+VERSION+"-"+VERSIONDATE); // show this module's version info
}
 
//
// OWNERSAY
//
OWNERSAY(string msg) {
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"OWNERSAY|"+msg,llGetOwner());
}
 
//
// PARSE
//
PARSE(string message,key id) {
    // No need for debug - only link messages to this module and debug is done there
    // First - handle type 1 messages that do not require breaking down
    list tokens = llParseString2List(message,["|"],[]);
    string cmd = llToLower(llStringTrim(llList2String(tokens,0),STRING_TRIM));    
    string data = llList2String(tokens,1);
    list subtokens = llParseString2List(data,["="],[]);
    string attrib = llList2String(subtokens,0);
    integer idata = llList2Integer(subtokens,1);
    string sdata = llList2String(subtokens,1);
 
    if ( cmd == "memory" ) { GET_MEMORY(); return; }        
    if ( cmd == "reset" ) { RESET(); return; }
    if ( cmd == "version" ) { GET_VERSION(); return;} // show version info
 
}
 
//
// RESET - shut down running animations then reset the script to reload character sheet
//
RESET() {
    llResetScript(); // now reset
}
 
//
// RPEVENT
//
RPEVENT(string rpevent) {
    llMessageLinked(LINK_THIS,MODULE_GENERATOR,"RPEVENT|"+rpevent,llGetOwner());
}
 
//
// SETUP - begin bringing the HUD online
//
SETUP() {
    OWNERSAY("Generator module active.");
}
 
//
// DEFAULT STATE
//
default {
 
    link_message(integer sender_num,integer sender,string message,key id) {
        if ( sender == MODULE_GENERATOR || sender == LM_SENDTOATTACHMENT ) return; // ignore link messages not sent to us specifically
 
        // First - handle type 1 messages that do not require breaking down
        list tokens = llParseString2List(message,["|"],[]);
        string cmd = llToLower(llStringTrim(llList2String(tokens,0),STRING_TRIM));
 
        if ( cmd == "debug" || cmd == "error" || cmd == "help" || cmd == "ownersay" || cmd == "rpevent" ) return; // ignore WELL commands
        // only debug when its module specific 
        DEBUG("EVENT: link_message("+(string)sender_num+","+(string)sender+","+message+","+(string)id+")");        
        PARSE(message,id); // parse incoming message
    } // end of link_message event
 
    // STATE ENTRY - called on Reset
    state_entry() {
        SETUP(); // show credits and start character sheet load
    }
} // end state
// END