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

Myriad Lite Module Character Sheet

// Myriad_Lite_Module_Character_Sheet-v0.0.10-20131019.lsl
// Copyright (c) 2012-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/
 
// VERSION CONTROL
string BASENAME = "Myriad Lite Module Character Sheet";
string VERSION = "0.0.10"; // Allen Kerensky's script version
string VERSIONDATE = "20131019"; // Allen Kerensky's script yyyymmdd
 
// MODULE TO MODULE MESSAGING CONSTANTS
integer MODULE_CHARSHEET = -2;
integer LM_SENDTOATTACHMENT = 0x80000000; // FIXME move to SENDTOATTACH|<message>
 
//
// 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");
}
 
DUMP_RECORDS() {
    //OWNERSAY("DUMP_RECORDS STARTS");
    // 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);
        desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0);
        if ( name != "" && desc != "" ) {
            text = llList2String(llGetLinkPrimitiveParams(i,[PRIM_TEXT]),0);
            OWNERSAY("RECORD=["+(string)i+"] NAME=["+name+"] DESC=["+desc+"] TEXT=["+text+"]");
        }
    }
    //OWNERSAY("DUMP_RECORDS ENDS");
}
 
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 == "CHARACTER" ) llSay(chan,"CHARACTER|"+desc+"="+text);
            if ( type == "STATISTIC" ) llSay(chan,"STATISTIC|NAME="+desc+"|"+text);
            if ( type == "SKILL" ) llSay(chan,"SKILL|NAME="+desc+"|"+text);
            if ( type == "EFFECT" ) llSay(chan,"EFFECT|NAME="+desc+"|"+text);            
            if ( type == "RESILIENCE" ) llSay(chan,"RESILIENCE|NAME="+desc+"|"+text);
            if ( type == "BOON" ) llSay(chan,"BOON|NAME="+desc+"|"+text);
            if ( type == "FLAW" ) llSay(chan,"FLAW|NAME="+desc+"|"+text);
            if ( type == "CAMPAIGN" ) llSay(chan,"CAMPAIGN|NAME="+desc+"|"+text);
            if ( type == "SPECIE" ) llSay(chan,"SPECIE|NAME="+desc+"|"+text);
            if ( type == "BACKGROUND" ) llSay(chan,"BACKGROUND|NAME="+desc+"|"+text);
            if ( type == "CAREER" ) llSay(chan,"CAREER|NAME="+desc+"|"+text);            
            if ( type == "ITEM" ) llSay(chan,"ITEM|NAME="+desc+"|"+text);
            if ( type == "STUNT" ) llSay(chan,"STUNT|NAME="+desc+"|"+text);
            if ( type == "QUOTE" ) llSay(chan,"QUOTE|NAME="+desc+"|"+text);
        }
    }
    //OWNERSAY("DUMP_TYPE ENDS");
}
 
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");    
}
 
FORMAT_DB() {
    //OWNERSAY("FORMATTING DATABASE");
    integer i;
    for ( i = 2; i <= llGetNumberOfPrims(); i++ ) {
        if ( llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0) != "" ) {
            llSetLinkPrimitiveParamsFast(i,[PRIM_NAME,"",PRIM_DESC,"",PRIM_TEXT,"",ZERO_VECTOR,0.0]);
        }
    }
    //OWNERSAY("DATABASE FORMAT COMPLETE");
}
 
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;
}
 
LIST_TYPE(key id,string type) {
    integer chan = (integer)("0x"+llGetSubString(id,0,6));
    type = llToUpper(type);
    // scan index or prim names for empty, get number for update
    integer i;
    string name = "";
    string desc = "";
    list out = [];
    for ( i = 2; i <= llGetNumberOfPrims(); i++) {
        name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0);
        if ( name == type ) {
            desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0);
            out = out + [desc];
        }
    }
    out = llListSort(out,1,TRUE);
    if ( type == "STATISTIC" ) llSay(chan,"STATISTICS|"+llList2CSV(out));
    if ( type == "SKILL" ) llSay(chan,"SKILLS|"+llList2CSV(out));
    if ( type == "EFFECT" ) llSay(chan,"EFFECTS|"+llList2CSV(out));
    if ( type == "RESILIENCE" ) llSay(chan,"RESILIENCES|"+llList2CSV(out));
    if ( type == "BOON" ) llSay(chan,"BOONS|"+llList2CSV(out));
    if ( type == "FLAW" ) llSay(chan,"FLAWS|"+llList2CSV(out));
    if ( type == "CAMPAIGN" ) llSay(chan,"CAMPAIGNS|"+llList2CSV(out));
    if ( type == "SPECIE" ) llSay(chan,"SPECIES|"+llList2CSV(out));
    if ( type == "BACKGROUND" ) llSay(chan,"BACKGROUNDS|"+llList2CSV(out));
    if ( type == "CAREER" ) llSay(chan,"CAREERS|"+llList2CSV(out));
    if ( type == "ITEM" ) llSay(chan,"ITEMS|"+llList2CSV(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
// 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 = 1;
        if ( setting == "MAXDAMAGE" ) retval = 5;
        ERROR("Unable to locate Myriad setting "+setting+" returning "+(string)retval);
    } else {
        retval = (integer)value;
    }
    return retval;
}
 
///////////////////
// ASPECTS
///////////////////
 
// STATISTICS
// LMIN: GET_STATISTIC|<name>
// PPMA: STATISTIC,<name>,<rank>
// LMOUT: STATISTIC|<name>=<rank>
// LMERR: FIXME
integer GET_STATISTIC(string stat) {
    // FIXME how to verify stat?
    integer rank = (integer)GET_VAL("STATISTIC",stat);
    if ( rank < GET_MYRIAD("MINSTAT") ) { rank = GET_MYRIAD("MINSTAT"); SET_STATISTIC(stat,rank); }
    if ( rank > GET_MYRIAD("MAXSTAT") ) { rank = GET_MYRIAD("MAXSTAT"); SET_STATISTIC(stat,rank); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"STATISTIC|"+stat+"="+(string)rank,llGetOwner()); // REMOVEME
    return rank;
}
 
// LMIN: SET_STATISTIC|<name>=<rank>
// PPMA: STATISTIC,<name>,<rank>
// LMOUT: SET_STATISTIC|<name>,<rank>
// LMERR: FIXME
SET_STATISTIC(string stat,integer rank) {
    // FIXME how to verify stat names are valid?
    if ( rank < GET_MYRIAD("MINSTAT") ) rank = GET_MYRIAD("MINSTAT");
    if ( rank > GET_MYRIAD("MAXSTAT") ) rank = GET_MYRIAD("MAXSTAT");
    SET_VAL("STATISTIC",stat,(string)rank);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_STATISTIC|"+stat+"="+(string)rank,llGetOwner()); // REMOVEME
}
 
// SKILLS
// LMIN: GET_SKILL|<name>
// PPMA: SKILL,<name>,<rank>
// LMOUT: SKILL|<name>=<rank>
// LMERR: FIXME
integer GET_SKILL(string skill) {
    integer rank = (integer)GET_VAL("SKILL",skill);
    if ( rank < GET_MYRIAD("MINSKILL") ) { rank = GET_MYRIAD("MINSKILL"); SET_SKILL(skill,rank); }
    if ( rank > GET_MYRIAD("MAXSKILL") ) { rank = GET_MYRIAD("MAXSKILL"); SET_SKILL(skill,rank); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SKILL|"+skill+"="+(string)rank,llGetOwner()); // REMOVEME
    return rank;
}
 
// LMIN: SET_SKILL|<name>=<rank>
// PPMA: SKILL,<name>,<rank>
// LMOUT: SET_SKILL|<name>=<rank>
// LMERR: FIXME
SET_SKILL(string skill,integer rank) {
    // TODO how to verify skill names are valid?
    if ( rank < GET_MYRIAD("MINSKILL") ) rank = GET_MYRIAD("MINSKILL");
    if ( rank > GET_MYRIAD("MAXSKILL") ) rank = GET_MYRIAD("MAXSKILL");
    SET_VAL("SKILL",skill,(string)rank);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_SKILL|"+skill+"="+(string)rank,llGetOwner()); // REMOVEME
}
 
// SFX
// LMIN: GET_EFFECT|<name>
// PPMA: EFFECT,<name>,<rank>
// LMOUT: EFFECT|<name>=<rank>
// LMERR: FIXME
integer GET_EFFECT(string name) {
    integer rank = (integer)GET_VAL("EFFECT",name);
    if ( rank < GET_MYRIAD("MINEFFECT") ) { rank = GET_MYRIAD("MINEFFECT"); SET_EFFECT(name,rank); }
    if ( rank > GET_MYRIAD("MAXEFFECT") ) { rank = GET_MYRIAD("MAXEFFECT"); SET_EFFECT(name,rank); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"EFFECT|"+name+"="+(string)rank,llGetOwner()); // REMOVEME    
    return rank;
}
 
// LMIN: SET_EFFECT|<name>=<rank>
// PPMA: EFFECT,<name>,<rank>
// LMOUT: SET_EFFECT|<name>=<rank>
// LMERR: FIXME
SET_EFFECT(string name,integer rank) {
    // TODO how to verify effect name?
    if ( rank < GET_MYRIAD("MINEFFECT") ) rank = GET_MYRIAD("MINEFFECT");
    if ( rank > GET_MYRIAD("MAXEFFECT") ) rank = GET_MYRIAD("MAXEFFECT");
    SET_VAL("EFFECT",name,(string)rank);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_EFFECT|"+name+"="+(string)rank,llGetOwner()); // REMOVEME
}
 
// RESILIENCES
// LMIN: GET_RESILIENCE|<name>
// PPMA: RESILIENCE,<name>,<amount>
// LMOUT: RESILIENCE|<name>=<amount>
// LMERR: FIXME
integer GET_RESILIENCE(string name) {
    integer amount = (integer)GET_VAL("RESILIENCE",name);
    if ( amount < GET_MYRIAD("MINRESILIENCE") ) { amount = GET_MYRIAD("MINRESILIENCE"); SET_RESILIENCE(name,amount); }
    if ( amount > GET_MYRIAD("MAXRESILIENCE") ) { amount = GET_MYRIAD("MAXRESILIENCE"); SET_RESILIENCE(name,amount); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"RESILIENCE|"+name+"="+(string)amount,llGetOwner()); // REMOVEME
    return amount;
}
 
// LMIN: SET_RESILIENCE|<name>=<amount>
// PPMA: RESILIENCE,<name>,<amount>
// LMOUT: SET_RESILIENCE|<name>=<amount>
// LMERR: FIXME
SET_RESILIENCE(string name,integer amount) {
    // TODO how to verify resilience names are valid?
    if ( amount < GET_MYRIAD("MINRESILIENCE") ) amount = GET_MYRIAD("MINRESILIENCE");
    if ( amount > GET_MYRIAD("MAXRESILIENCE") ) amount = GET_MYRIAD("MAXRESILIENCE");
    SET_VAL("RESILIENCE",name,(string)amount);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_RESILIENCE|"+name+"="+(string)amount,llGetOwner()); // REMOVEME
}
 
// BOONS
// LMIN: GET_BOON|<name>
// PPMA: BOON,<name>,<rank>
// LMOUT: BOON|<name>=<rank>
// LMERR: FIXME
integer GET_BOON(string boon) {
    integer rank = (integer)GET_VAL("BOON",boon);
    if ( rank < GET_MYRIAD("MINBOON") ) { rank = GET_MYRIAD("MINBOON"); SET_BOON(boon,rank); }
    if ( rank > GET_MYRIAD("MAXBOON") ) { rank = GET_MYRIAD("MAXBOON"); SET_BOON(boon,rank); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"BOON|"+boon+"="+(string)rank,llGetOwner()); // REMOVEME
    return rank;
}
 
// LMIN: SET_BOON|<name>=<rank>
// PPMA: BOON,<name>,<rank>
// LMOUT: SET_BOON|<name>=<rank>
// LMERR: FIXME
SET_BOON(string boon,integer rank) {
    // TODO how to verify boon names are valid?
    if ( rank < GET_MYRIAD("MINBOON") ) rank = GET_MYRIAD("MINBOON");
    if ( rank > GET_MYRIAD("MAXBOON") ) rank = GET_MYRIAD("MAXBOON");
    SET_VAL("BOON",boon,(string)rank);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_BOON|"+boon+"="+(string)rank,llGetOwner()); // REMOVEME
}
 
// FLAWS
// LMIN: GET_FLAW|<name>
// PPMA: FLAW,<name>,<rank>
// LMOUT: FLAW|<name>=<rank>
// LMERR: FIXME
integer GET_FLAW(string flaw) {
    integer rank = (integer)GET_VAL("FLAW",flaw);
    if ( rank < GET_MYRIAD("MINFLAW") ) { rank = GET_MYRIAD("MINFLAW"); SET_FLAW(flaw,rank); }
    if ( rank > GET_MYRIAD("MAXFLAW") ) { rank = GET_MYRIAD("MAXFLAW"); SET_FLAW(flaw,rank); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"FLAW|"+flaw+"="+(string)rank,llGetOwner()); // REMOVEME
    return rank;
}
 
// LMIN: SET_FLAW|<name>=<rank>
// PPMA: FLAW,<name>,<rank>
// LMOUT: SET_FLAW|<name>=<rank>
// LMERR: FIXME
SET_FLAW(string flaw,integer rank) {
    // TODO how to verify flaw names are valid?
    if ( rank < GET_MYRIAD("MINFLAW") ) rank = GET_MYRIAD("MINFLAW");
    if ( rank > GET_MYRIAD("MAXFLAW") ) rank = GET_MYRIAD("MAXFLAW");        
    SET_VAL("FLAW",flaw,(string)rank);        
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_FLAW|"+flaw+"="+(string)rank,llGetOwner());
}
 
// SPECIES
// LMIN: GET_SPECIE|<name>
// PPMA: SPECIE,<name>,<data>
// LMOUT: SPECIE|<name>=<data>
// LMERR: FIXME
string GET_SPECIE(string name) {
    // FIXME how to verify requested species name?
    string speciedata = GET_VAL("SPECIE",name);
    if ( speciedata == KEY_NOT_FOUND ) speciedata = "None";
    // FIXME how to verify species data
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SPECIE|"+name+"="+speciedata,llGetOwner()); // REMOVEME
    return speciedata;
}
 
// FIXME LIST_SPECIES
//string LIST_SPECIES() {
//    return "";
//}
 
// LMIN: SET_SPECIE|<name>=<data>
// PPMA: SPECIE,<name>,<data>
// LMOUT: SET_SPECIE|<name>=<data>
// LMERR: FIXME
SET_SPECIE(string aspecies,string data) {
    // FIXME how to verify a good species name?
    // FIXME how to verify data
    SET_VAL("SPECIE",aspecies,data);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_SPECIE|"+aspecies+"="+data,llGetOwner()); // REMOVEME
}
 
// BACKGROUND
// LMIN: GET_BACKGROUND|<name>=<data>
// PPMA: BACKGROUND,<name>,<data>
// LMOUT: BACKGROUND|<name>=<data>
// LMERR: FIXME
string GET_BACKGROUND(string name) {
    string bkgnddata = GET_VAL("BACKGROUND",name);
    if ( bkgnddata == KEY_NOT_FOUND ) bkgnddata = "None";
    // FIXME how to verify background data?
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"BACKGROUND|"+name+"="+bkgnddata,llGetOwner());
    return bkgnddata;
}
 
// FIXME LIST_BACKGROUNDS
//string LIST_BACKGROUNDS() {
//    return "";
//}
 
// LMIN: SET_BACKGROUND|<name>=<data>
// PPMA: BACKGROUND,<name>,<data>
// LMOUT: SET_BACKGROUND|<name>,<data>
// LMERR: FIXME
SET_BACKGROUND(string abkgnd,string data) {
    // FIXME how to verify background?
    SET_VAL("BACKGROUND",abkgnd,data);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_BACKGROUND|"+abkgnd+"="+data,llGetOwner()); // REMOVEME
}
 
// CAREER
// LMIN: GET_CAREER|<name>
// PPMA: CAREER,<name>,<data>
// LMOUT: CAREER|<name>=<data>
// LMERR: FIXME
string GET_CAREER(string name) {
    string careerdata = GET_VAL("CAREER",name);
    if ( careerdata == KEY_NOT_FOUND ) careerdata = "None";
    // FIXME how to verify career?
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"CAREER|"+name+"="+careerdata,llGetOwner());
    return careerdata;
}
 
// FIXME LIST_CAREERS
//string LIST_CAREERS() {
//    return "";
//}
 
// LMIN: SET_CAREER|<name>=<data>
// PPMA: CAREER,<name>,<data>
// LMOUT: SET_CAREER|<name>=<data>
// LMERR: FIXME
SET_CAREER(string acareer,string data) {
    // FIXME how to verify name
    // FIXME how to verify data
    SET_VAL("CAREER",acareer,data);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_CAREER|"+acareer+"="+data,llGetOwner());
}
 
// EQUIPMENT
// LMIN: GET_ITEM|<name>
// PPMA: ITEM,<name>,<amount>
// LMOUT: ITEM|<name>=<amount>
// LMERR: FIXME
integer GET_ITEM(string name) {
    // FIXME verify equipment name is valid?
    integer amt = (integer)GET_VAL("ITEM",name);
    if ( amt < GET_MYRIAD("MINITEM") ) { amt = GET_MYRIAD("MINITEM"); SET_ITEM(name,amt); }
    if ( amt > GET_MYRIAD("MAXITEM") ) { amt = GET_MYRIAD("MAXITEM"); SET_ITEM(name,amt); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"ITEM|"+name+"="+(string)amt,llGetOwner());        
    return amt;
}
 
// LMIN: SET_ITEM|<name>=<amount>
// PPMA: ITEM,<name>,<amount>
// LMOUT: SET_ITEM|<name>=<amount>
// LMERR: FIXME
SET_ITEM(string name,integer amt) {
    // TODO how to verify the equipment name is valid?
    if ( amt < GET_MYRIAD("MINITEM") ) amt = GET_MYRIAD("MINITEM");
    if ( amt > GET_MYRIAD("MAXITEM") ) amt = GET_MYRIAD("MAXITEM");
    SET_VAL("ITEM",name,(string)amt);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_ITEM|"+name+"="+(string)amt,llGetOwner());        
}
 
///////////
/// Player Only aspects
///////////
 
// NAME
// LMIN: GET_NAME
// PPMA: CHARACTER,NAME,<firstname> <lastname>
// LMOUT: NONE
// LMERR: Undefined
// RSOUT: CHARACTER|NAME=<firstname> <lastname>
// RSERR: Undefined
// RETURN: NONE
GET_NAME(key id) {
    string name = GET_VAL("CHARACTER","NAME");
    if ( name == KEY_NOT_FOUND ) {
        OWNERSAY("Name not found. Resetting to default name Myriad Player");
        name = "Myriad Player"; // set a default name if none is in the database
        SET_NAME(name);
    }
    string out = "CHARACTER|NAME="+name;
    if ( id != NULL_KEY ) {
        integer chan = (integer)("0x"+llGetSubString(id,0,6));
        llRegionSay(chan,out);
    }
    // FIXME how to verify good name?
    //llMessageLinked(LINK_THIS,MODULE_CHARSHEET,out,llGetOwner()); // REMOVEME
    //return name;
}
 
// LMIN: SET_NAME|NAME=<firstname> <lastname>
// PPMA: CHARACTER,NAME,<firstname> <lastname>
// LMOUT: SET_CHARACTER|NAME=<firstname> <lastname>
// LMERR: Undefined
SET_NAME(string aname) {
    if ( aname == "" ) { // set NAME empty = delete
        SET_VAL("CHARACTER","NAME","Myriad Player");
        OWNERSAY("Name deleted. Resetting name to Myriad Player.");
        return;
    }
    // FIXME how to verify a good name?
    SET_VAL("CHARACTER","NAME",aname);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_CHARACTER|NAME="+aname,llGetOwner()); // REMOVEME
}
 
// NICKNAME
// LMIN: GET_NICKNAME
// PPMA: CHARACTER,NICKNAME,<nickname>
// LMOUT: NONE
// LMERR: Undefined
// RSOUT: CHARACTER|NICKNAME=<nickname>
// RSERR: Undefined
// RETURN: NONE
GET_NICKNAME(key id) {
    string nickname = GET_VAL("CHARACTER","NICKNAME");
    string out = "CHARACTER|NICKNAME="+nickname;
    if ( id != NULL_KEY ) {
        integer chan = (integer)("0x"+llGetSubString(id,0,6));
        llRegionSay(chan,out);
    }
    // FIXME how to verify good name?
    //llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"CHARACTER|NICKNAME="+nickname,llGetOwner()); // REMOVEME
    //return nickname;
}
 
// LMIN: SET_CHARACTER|NICKNAME=<nickname>
// PPMA: CHARACTER,NICKNAME,<nickname>
// LMOUT: SET_CHARACTER|NICKNAME=<nickname>
// LMERR: Undefined
SET_NICKNAME(string anick) {
    if ( anick == "" ) { // set NICK empty = delete
        DELETE_RECORD("CHARACTER","NICKNAME");
        OWNERSAY("Nickname deleted");
        return;
    }
    // FIXME how to verify a good name?
    SET_VAL("CHARACTER","NICKNAME",anick);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_CHARACTER|NICKNAME="+anick,llGetOwner()); // REMOVEME
}
 
// TITLE
// LMIN: GET_TITLE
// PPMA: CHARACTER,TITLE,<title>
// LMOUT: NONE
// LMERR: Undefined
// RSOUT: CHARACTER|TITLE=<title>
// RSERR: Undefined
// RETURN: NONE
GET_TITLE(key id) {
    string title = GET_VAL("CHARACTER","TITLE");
    string out = "CHARACTER|TITLE="+title;
    if ( id != NULL_KEY ) {
        integer chan = (integer)("0x"+llGetSubString(id,0,6));
        llRegionSay(chan,out);
    }
    // FIXME how to verify good name?
    //llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"CHARACTER|TITLE="+title,llGetOwner()); // REMOVEME
    //return title;
}
 
// LMIN: SET_TITLE|TITLE=<title>
// PPMA: CHARACTER,TITLE,<title>
// LMOUT: SET_CHARACTER|TITLE=<title>
// LMERR: Undefined
SET_TITLE(string atitle) {
    if ( atitle == "" ) { // set TITLE empty = delete
        DELETE_RECORD("CHARACTER","TITLE");
        OWNERSAY("Title deleted");
        return;
    }
    // FIXME how to verify a good name?
    SET_VAL("CHARACTER","TITLE",atitle);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_CHARACTER|TITLE="+atitle,llGetOwner()); // REMOVEME
}
 
// FACTION
// LMIN: GET_FACTION
// PPMA: CHARACTER,FACTION,<factionname>
// LMOUT: NONE
// LMERR: Undefined
// RSOUT: CHARACTER|FACTION=<factionname>
// RSERR: Undefined
// RETURN: NONE
GET_FACTION(key id) {
    string faction = GET_VAL("CHARACTER","FACTION");
    // FIXME how to verify good faction name?
    string out = "CHARACTER|FACTION="+faction;
    if ( id != NULL_KEY ) {
        integer chan = (integer)("0x"+llGetSubString(id,0,6));
        llRegionSay(chan,out);
    }
    //llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"CHARACTER|FACTION="+faction,llGetOwner()); // REMOVEME
    //return faction;
}
 
// LMIN: SET_FACTION|FACTION=<factionname>
// PPMA: CHARACTER,FACTION,<factionname>
// LMOUT: SET_CHARACTER|FACTION=<factionname>
// LMERR: Undefined
SET_FACTION(string afaction) {
    if ( afaction == "" ) { // set FACTION empty = delete
        DELETE_RECORD("CHARACTER","FACTION");
        OWNERSAY("Faction deleted");
        return;
    }
    // FIXME how to verify a good name?
    SET_VAL("CHARACTER","FACTION",afaction);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_CHARACTER|FACTION="+afaction,llGetOwner()); // REMOVEME
}
 
 
// RP - GENERATOR POINTBUY
// LMIN:
// PPMA:
// LMOUT:
// LMERR:
integer GET_RP() {
    integer rp = (integer)GET_VAL("CHARACTER","RP");
    if ( rp < GET_MYRIAD("MINRP") ) { rp = GET_MYRIAD("MINRP"); SET_RP(rp); }
    if ( rp > GET_MYRIAD("MAXRP") ) { rp = GET_MYRIAD("MAXRP"); SET_RP(rp); }
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"PROGRESS|RP="+(string)rp,llGetOwner()); // REMOVEME
    return rp;
}
 
// LMIN:
// PPMA:
// LMOUT:
// LMERR:
SET_RP(integer rpamt) {
    if ( rpamt < GET_MYRIAD("MINRP") ) rpamt = GET_MYRIAD("MINRP");
    if ( rpamt > GET_MYRIAD("MAXRP") ) rpamt = GET_MYRIAD("MAXRP");
    SET_VAL("CHARACTER","RP",(string)rpamt);    
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"PROGRESS|RP="+(string)rpamt,llGetOwner()); // REMOVEME    
}
 
// STUNTS
// LMIN:
// PPMA:
// LMOUT:
// LMERR:
string GET_STUNT(string name) {
    string stunt = GET_VAL("STUNT",name);
    // TODO how to verify stunt?
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"STUNT|"+name+"="+stunt,llGetOwner()); // REMOVEME
    return stunt;
}
 
// LMIN:
// PPMA:
// LMOUT:
// LMERR:
SET_STUNT(string name,string stunt) {
    // TODO how to verify stunt?
    SET_VAL("STUNT",name,stunt);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_STUNT|"+name+"="+stunt,llGetOwner());
}
 
// QUOTES
// LMIN:
// PPMA:
// LMOUT:
// LMERR:
string GET_QUOTE(string name) {
    string quote = GET_VAL("QUOTE",name);
    // TODO how to verify quote?
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"QUOTE|"+name+"="+quote,llGetOwner()); // REMOVEME
    return quote;
}
 
// LMIN:
// PPMA:
// LMOUT:
// LMERR:
SET_QUOTE(string name,string quote) {
    // TODO how to verify quote?
    SET_VAL("QUOTE",name,quote);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_QUOTE|"+name+"="+quote,llGetOwner());
}
 
 
DEBUG(string debugmsg) {
    if ( GET_FLAG("DEBUG") == TRUE ) llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"DEBUG|"+debugmsg,llGetOwner());
}
 
 
DUMP_SHEET(key id) { // dump current character sheet
    key objectowner = llList2Key(llGetObjectDetails(id,[OBJECT_OWNER]),0);
    key regionowner = llList2Key(llGetParcelDetails(<0,0,0>,[PARCEL_DETAILS_OWNER]),0);
    if ( objectowner != regionowner ) {
        ERROR("DUMP_SHEET called by object or player who is not region owner. ["+(string)objectowner+"]["+(string)regionowner+"]");
        return;
    }
    DEBUG("Dumping character sheet to "+llKey2Name(id)+" ("+(string)id+")");
    integer chan = (integer)("0x"+llGetSubString((string)id,0,6));
    DUMP_TYPE(chan,"CHARACTER"); // FIXME
    DUMP_TYPE(chan,"STATISTIC"); // dump list of stats and values
    DUMP_TYPE(chan,"RESILIENCE"); // dump list of resiliences and values
    DUMP_TYPE(chan,"BOON"); // dump list of boons and values
    DUMP_TYPE(chan,"FLAW"); // dump list of flaws and values 
    DUMP_TYPE(chan,"EFFECT"); // dump list of mortal sfx and values
    DUMP_TYPE(chan,"SKILL"); // dump list of skills and values
    DUMP_TYPE(chan,"ITEM"); // dump list of equipment
    DUMP_TYPE(chan,"STUNT"); // dump list of stunts
    DUMP_TYPE(chan,"QUOTE"); // dump list of quotes
    llSay(chan,"CHARACTER_LOADED");   
}
 
ERASE_SHEET(key id) { // erase current character sheet
    key objectowner = llList2Key(llGetObjectDetails(id,[OBJECT_OWNER]),0);
    key regionowner = llList2Key(llGetParcelDetails(<0,0,0>,[PARCEL_DETAILS_OWNER]),0);
    if ( objectowner != regionowner || objectowner != llGetOwner() || id != llGetOwner()  ) {
        ERROR("ERASE_SHEET called by object or player who is not player or region owner. ["+(string)objectowner+"]["+(string)regionowner+"]");
        return;
    }
    DEBUG("Eraseing character sheet");
    ERASE_TYPE("CHARACTER"); // FIXME
    ERASE_TYPE("STATISTIC"); // dump list of stats and values
    ERASE_TYPE("RESILIENCE"); // dump list of resiliences and values
    ERASE_TYPE("BOON"); // dump list of boons and values
    ERASE_TYPE("FLAW"); // dump list of flaws and values 
    ERASE_TYPE("EFFECT"); // dump list of mortal sfx and values
    ERASE_TYPE("SKILL"); // dump list of skills and values
    ERASE_TYPE("ITEM"); // dump list of equipment
    ERASE_TYPE("STUNT"); // dump list of stunts
    ERASE_TYPE("QUOTE"); // dump list of quotes
    OWNERSAY("Character Sheet erased.");   
}
 
ERROR(string errmsg) {
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"ERROR|"+errmsg,llGetOwner());
}
 
// MEMORY
GET_MEMORY() {
    OWNERSAY(BASENAME+" free memory: "+(string)llGetFreeMemory());
}
 
// GETVERSION
GET_VERSION() {
    OWNERSAY(BASENAME+" v"+VERSION+"-"+VERSIONDATE);
}
 
OWNERSAY(string msg) {
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"OWNERSAY|"+msg,llGetOwner());
}
 
PARSE(string message,key id) {
    // debugged in chat and link message events
    // 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);
    // REMOVEME all GET_* command blocks once PPMA is integrated in all HUD scripts    
    if ( cmd == "memory" ) { GET_MEMORY(); return;} // dump script memory
    if ( cmd == "reset" ) { RESET(); } // reset on request
    if ( cmd == "version") { GET_VERSION(); return; } // respond with version info when requested
    if ( cmd == "get_status" ) { GET_STATUS(id); return; } // respond to character sheet status requests
    if ( cmd == "set_status" ) { SET_STATUS(sdata); return; } // save character status
    if ( cmd == "dump_sheet" ) { DUMP_SHEET(id); return; } // id is UUID of character builder, sent over from HUD script
    if ( cmd == "dump_records") { DUMP_RECORDS(); return; } // dump prim persistent memory array
    if ( cmd == "erase_sheet" ) { ERASE_SHEET(id); return;} // erase character sheet
    if ( cmd == "format_db" ) { FORMAT_DB(); return;}
    if ( cmd == "region_setting" && llToLower(attrib) == "progression" ) { SET_PROGRESSION(sdata); return;}
    // ASPECTS
    if ( cmd == "get_statistic" ) { GET_STATISTIC(attrib); return;}
    if ( cmd == "set_statistic" ) { SET_STATISTIC(attrib,idata); return;}
    if ( cmd == "get_skill" ) { GET_SKILL(attrib); return;}
    if ( cmd == "set_skill" ) { SET_SKILL(attrib,idata); return;}
    if ( cmd == "get_effect" ) { GET_EFFECT(attrib); return;}
    if ( cmd == "set_effect" ) { SET_EFFECT(attrib,idata); return;}
    if ( cmd == "get_resilience" ) { GET_RESILIENCE(attrib); return;}
    if ( cmd == "set_resilience" ) { SET_RESILIENCE(attrib,idata); return;}
    if ( cmd == "get_boon" ) { GET_BOON(attrib); return;}
    if ( cmd == "set_boon" ) { SET_BOON(attrib,idata); return;}
    if ( cmd == "get_flaw" ) { GET_FLAW(attrib); return;}
    if ( cmd == "set_flaw" ) { SET_FLAW(attrib,idata); return;}
    if ( cmd == "get_specie" ) { GET_SPECIE(attrib); return;}
    if ( cmd == "set_specie" ) { SET_SPECIE(attrib,sdata); return;}
    if ( cmd == "get_background" ) { GET_BACKGROUND(attrib); return;}
    if ( cmd == "set_background" ) { SET_BACKGROUND(attrib,sdata); return;}        
    if ( cmd == "get_career" ) { GET_CAREER(attrib); return;}
    if ( cmd == "set_career" ) { SET_CAREER(attrib,sdata); return;}
    if ( cmd == "get_item" ) { GET_ITEM(attrib); return;}
    if ( cmd == "set_item" ) { SET_ITEM(attrib,idata); return;}
 
    if ( cmd == "get_name" ) { GET_NAME(id); return;}
    if ( cmd == "set_name" ) { SET_NAME(sdata); return;}
    if ( cmd == "get_nickname" ) { GET_NICKNAME(id); return;}
    if ( cmd == "set_nickname" ) { SET_NICKNAME(sdata); return;}
    if ( cmd == "get_title" ) { GET_TITLE(id); return;}
    if ( cmd == "set_title" ) { SET_TITLE(sdata); return;}
    if ( cmd == "get_faction") { GET_FACTION(id); return;}
    if ( cmd == "set_faction" ) { SET_FACTION(sdata); return;}
    if ( cmd == "get_stunt" ) { GET_STUNT(sdata); return;}
    if ( cmd == "set_stunt" ) { SET_STUNT(attrib,sdata); return;}
    if ( cmd == "get_quote" ) { GET_QUOTE(sdata); return;}
    if ( cmd == "set_quote" ) { SET_QUOTE(attrib,sdata); return;}
    if ( cmd == "get_rp" ) { GET_RP(); return;}        
    if ( cmd == "set_rp" ) { SET_RP(idata); return;}        
 
    // LIST FUNCTIONS
    if ( cmd == "list_statistics" ) { LIST_TYPE(id,"STATISTIC"); return;}
    if ( cmd == "list_skills" ) { LIST_TYPE(id,"SKILL"); return;}
    if ( cmd == "list_effects" ) { LIST_TYPE(id,"EFFECT"); return;}
    if ( cmd == "list_resiliences" ) { LIST_TYPE(id,"RESILIENCE"); return;}
    if ( cmd == "list_boons" ) { LIST_TYPE(id,"BOON"); return;}
    if ( cmd == "list_flaws" ) { LIST_TYPE(id,"FLAW"); return;}
    if ( cmd == "list_species" ) { LIST_TYPE(id,"SPECIE"); return;}
    if ( cmd == "list_backgrounds" ) { LIST_TYPE(id,"BACKGROUND"); return;}
    if ( cmd == "list_careers" ) { LIST_TYPE(id,"CAREER"); return;}
    if ( cmd == "list_items" ) { LIST_TYPE(id,"ITEM"); return;}
}
 
RESET() { // do any final work, then reset
    llResetScript();
}
 
string PROGRESSION; // Progression Method: LEVEL, GRADUAL, or RANDOM
 
GET_PROGRESSION() {
    integer CHANMYRIAD = -999; // REMOVEME
    llRegionSay(CHANMYRIAD,"GET_REGION_SETTING|PROGRESSION"); // ask for this first, asking for estate triggers find_notecard function    
}
 
SET_PROGRESSION(string method) {
    method = llToUpper(method);
    if ( method == "LEVEL-BASED" || method == "GRADUAL" || method == "RANDOM" ) {
        PROGRESSION = method;
        DEBUG("Character progression method set to: "+method);
    } else {
        ERROR("Unknown progression method: "+method+"! Roleplay progress will not be counted.");
    }
}
 
GET_STATUS(key id) {
    DEBUG("Sending character sheet status to "+llKey2Name(id)+" ("+(string)id+")");
    integer chan = (integer)("0x"+llGetSubString((string)id,0,6));
    string status = GET_VAL("CHARACTER","STATUS");
    if ( status != "NONE" && status != "DRAFT" && status != "COMPLETE" ) {
        status = "NONE";
    }
    llSay(chan,"CHARACTER|STATUS="+status);
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"CHARACTER|STATUS="+status,llGetOwner());
}
 
SET_STATUS(string status) {
    if ( status == "NONE" || status == "DRAFT" || status == "COMPLETE" ) {
        SET_VAL("CHARACTER","STATUS",status);
    } else {
        ERROR("SET_STATUS: Invalid character status: "+status);
    }
}
 
SETUP() {
 
    GET_PROGRESSION();
    OWNERSAY("Character Sheet module active.");
}
 
default {
 
    link_message(integer sender_num,integer num,string str,key id) {
        if ( num == MODULE_CHARSHEET || num == LM_SENDTOATTACHMENT ) return; // ignore link messages not sent to us specifically
        list tokens = llParseString2List(str,["|"],[]);
        string cmd = llToLower(llStringTrim(llList2String(tokens,0),STRING_TRIM));
        if ( cmd == "debug" || cmd == "error" || cmd == "help" || cmd == "ownersay" || cmd == "rpevent" ) return; // ignore WELL commands
        // debug after message we're ignoring
        DEBUG("EVENT link_message sender_num=["+(string)sender_num+"] num=["+(string)num+"] str=["+str+"] id=["+(string)id+"]");        
        PARSE(str,id); // parse incoming message
    }
 
    state_entry() {
        SETUP();
    }
}
// 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