User:Allen Kerensky/Myriad Lite Dev/Myriad Lite Module Character Sheet-v0.0.2-20120513.lsl

From OpenSimulator

Jump to: navigation, search

Myriad_Lite_Module_Character_Sheet-v0.0.2-20120513.lsl

// ===========================================================================
// Myriad_Lite_Module_Character_Sheet-v0.0.2-20120513.lsl
// Copyright (c) 2012 By Allen Kerensky (OSG/SL)
// The Myriad RPG System was designed, written, and illustrated by Ashok Desai
// Myriad RPG licensed under the Creative Commons Attribution 2.0 UK: England and Wales
// http://creativecommons.org/licenses/by/2.0/uk/
// Myriad Lite software Copyright (c) 2011-2012 by Allen Kerensky (OSG/SL)
// Baroun's Adventure Machine Copyright (c) 2008-2011 by Baroun Tardis (SL)
// Myriad Lite and Baroun's Adventure Machine licensed under the
// Creative Commons Attribution-Share Alike-Non-Commercial 3.0 Unported
// http://creativecommons.org/licenses/by-nc-sa/3.0/
// You must agree to the terms of this license before making any use of this software.
// If you do not agree to this license, simply delete these materials.
// There is no warranty, express or implied, for your use of these materials.
// ===========================================================================
 
// ===========================================================================
// VERSION CONTROL
// ===========================================================================
string VERSION = "0.0.2"; // Allen Kerensky's script version
string VERSIONDATE = "20120513"; // Allen Kerensky's script yyyymmdd
 
// ===========================================================================
// CHARACTER SHEET STORAGE
// ===========================================================================
string CARDVERSION = "0.0.4"; // what card format version do we expect
string NAME = ""; // character name
string SPECIES = ""; // species template used for character
string BACKGROUND = ""; // background template
string CAREER = ""; // career template
integer XP = 0; // 0-2320
integer XPLEVEL = 1; // 1-30
integer GP = 0; // general points for point-based character builder
integer STATPOOL = 0; // statistics point pool
integer HEALTHPOOL = 0; // resilience point pool
integer SKILLPOOL = 0; // skill point pool
integer SFXPOOL = 0; // special effect ability point pool
integer RP = 0; // resource point pool
list STATISTICS = [];
list RESILIENCES = [];
list CURRENT_RESILIENCES = [];
list BOONS = []; // boons [ string BoonName, integer BoonRank ]
list FLAWS = []; // flaws [ string FlawName, integer FlawRank ]
list SKILLS = []; // skills [ string SkillName, integer SkillRank ]
list EFFECTS = []; // special effects (SFX) [ string EffectName, integer EffectRank ]
list STUNTS = []; // pre-set martial combat stunts TODO how will this work?
list QUOTES = []; // pre-set social combat quotes TODO how will this work?
list EQUIPMENT = []; // Equipment [ string ItemName, integer NumberCarried ]
 
// ===========================================================================
// MYRIAD CONSTANTS
// ===========================================================================
integer MINXP = 0; // min experience points
integer MAXXP = 2320; // max experience points
integer MINLEVEL = 1; // min XP level
integer MAXLEVEL = 30; // max XP level
list XP_BY_LEVEL = [ 0,0,10,25,45,70,100,135,175,220,270,325,385,450,520,595,675,760,850,945,1045,1150,1260,1375,1495,1620,1750,1885,2025,2170,2320 ];
integer MINSTAT = 1; // min value for statistics
integer MAXSTAT = 5; // max human value for a statistic/attribute
integer MINRESILIENCE = 1; // min value for resilience
integer MAXRESILIENCE = 20; // max value for resilience
integer MINBOON = 1; // min value for boon rank
integer MAXBOON = 5; // max value for boon rank
integer MINFLAW = 1; // min value for flaw rank
integer MAXFLAW = 5; // max value for flaw rank
integer MINSKILL = 1; // min value for skill rank
integer MAXSKILL = 5; // max value for skill rank
integer MINEFFECT = 1; // min value for special effect
integer MAXEFFECT = 5; // max value for special effect
integer MINEQUIPPED = 1; // min number of items player can carry
integer MAXEQUIPPED = 100; // max number of items player can carry TODO: what about bullets?
//integer MINDAMAGE = 1; // min attack dice for weapon
//integer MAXDAMAGE = 5; // max attack dice for weapon
 
// ===========================================================================
// MODULE TO MODULE MESSAGING CONSTANTS
// ===========================================================================
//integer MODULE_HUD = -1;
integer MODULE_CHARSHEET = -2;
//integer MODULE_ARMOR = -3;
//integer MODULE_BAM = -4;
//integer MODULE_RUMORS = -5;
//integer LM_SENDTOATTACHMENT = 0x80000000;
 
// Runtimes
integer FLAG_DEBUG;
key PLAYERID;
string DIV="|";
string ESTATE; // what estate does this region belong to - loaded from region server
integer CHANMYRIAD = -999;
integer CHANOBJECT;
integer HANDOBJECT;
 
// Menu Handling
integer MENU_TIMER;
integer MENU_TIMEOUT = 30;
integer MENU_CHANNEL;
integer MENU_HANDLE; 
list MENU;
 
// ===========================================================================
// NOTECARD HANDLING
// ===========================================================================
list CHARACTERS;
string CARD;
string DEFAULT = "Myriad_Lite_Character_Sheet-v0.0.4-20120424.txt"; // character sheet notecard
integer LINE = 0; // reading line number
key QUERY = NULL_KEY; // track notecard queries
 
// ===========================================================================
// ===========================================================================
ADD_RESILIENCE(string resname,integer resrank) {
    // TODO how to verify resilience names are valid?
    if ( resrank >= MINRESILIENCE && resrank <= MAXRESILIENCE ) { // rank valid?
        RESILIENCES = [resname,resrank] + RESILIENCES; // add resilience to list
        CURRENT_RESILIENCES = [resname,resrank] + CURRENT_RESILIENCES; // add to current list too
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_RESILIENCE|"+resname+"="+(string)resrank,llGetOwner());
    } else { // invalid, report it
        ERROR("RESILIENCE "+resname+" rank "+(string)resrank+" value out of allowed range: "+(string)MINRESILIENCE+"-"+(string)MAXRESILIENCE);
    }
}
 
// ===========================================================================
// ===========================================================================
CALCULATE_LEVEL_BY_XP() {
    integer i;
    for ( i=1; i < llGetListLength(XP_BY_LEVEL); i++ ) {
        integer basexp = llList2Integer(XP_BY_LEVEL,i);
        if ( XP >= basexp ) {
            SET_XPLEVEL(i);
        }
    }
}
 
// ===========================================================================
// ===========================================================================
CHECK_CARDVERSION(string ncversion) {
    if ( ncversion != CARDVERSION ) {
        ERROR("Character sheet format "+ncversion+" found. Format version "+CARDVERSION+" expected. Please update character sheets to newer versions.");
    }
}
 
// ===========================================================================
// ===========================================================================
DEBUG(string debugmsg) {
    if ( FLAG_DEBUG == TRUE ) { // are we debugging?
        llSay(DEBUG_CHANNEL,"("+llKey2Name(PLAYERID)+") MODULE CHARSHEET DEBUG: "+debugmsg);
    }
}
 
// ===========================================================================
// ===========================================================================
ERROR(string errmsg) {
    llSay(DEBUG_CHANNEL,"("+llKey2Name(PLAYERID)+") MODULE CHARSHEET ERROR: "+errmsg);
}
 
// ===========================================================================
// ===========================================================================
FIND_NOTECARD() {
    CHARACTERS = [];
    MENU = ["Default"];
    //string regionname = llGetRegionName();
    integer count = llGetInventoryNumber(INVENTORY_NOTECARD);
    while (count--) {
        string currentcard = llGetInventoryName(INVENTORY_NOTECARD,count);
        list tokens = llParseString2List(currentcard,["@"],[]);
        string cardname = llList2String(tokens,0);
        string cardestate = llList2String(tokens,1);
        if ( cardname != DEFAULT && cardestate == ESTATE ) {
            CHARACTERS = [cardname,currentcard] + CHARACTERS;
            MENU = [cardname] + MENU;
            DEBUG("Found estate-specific character sheet "+cardname+"@"+cardestate);
        }
    }
    MENU_CHANNEL = (integer)llFrand(9999.0) * -1;
    MENU_HANDLE = llListen(MENU_CHANNEL,"",llGetOwner(),"");
    llDialog(llGetOwner(),"Choose your character",MENU,MENU_CHANNEL);
    MENU_TIMER = MENU_TIMEOUT;
    llSetTimerEvent(1.0);
}
 
// ===========================================================================
// ===========================================================================
integer GET_MAXRESILIENCE(string name) {
    integer pos = llListFindList(RESILIENCES,[name]);
    if ( pos >= 0 ) {
        return llList2Integer(RESILIENCES,pos + 1);
    }
    return 0;
}
 
// ===========================================================================
// ===========================================================================
integer GET_RESILIENCE(string name) {
    integer pos = llListFindList(CURRENT_RESILIENCES,[name]);
    if ( pos >= 0 ) {
        return llList2Integer(CURRENT_RESILIENCES,pos + 1);
    }
    return 0;
}
 
// ===========================================================================
// ===========================================================================
integer GET_STAT(string name) {
    integer pos = llListFindList(STATISTICS,[name]);
    if ( pos >= 0 ) {
        return llList2Integer(STATISTICS,pos + 1);
    }
    return 0;
}
 
// ===========================================================================
// ===========================================================================
GET_VERSION() {
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"VERSION_INFO"+DIV+"NAME="+llGetScriptName()+DIV+"VERSION="+VERSION+DIV+"VERSIONDATE="+VERSIONDATE,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
integer GET_XP() {
    if ( XP >= MINXP && XP <= MAXXP) {
        // inform all other modules that might need to track XPLEVEL
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"GET_XP|XP="+(string)XP,llGetOwner());
        return XP;
    } else {
        ERROR("GET_XP("+(string)XP+") AMOUNT OUT OF RANGE "+(string)MINXP+"-"+(string)MAXXP+"! RESETTING");
    }
    RESET();
    return 0;
}
 
// ===========================================================================
// ===========================================================================
integer GET_XPLEVEL() {
    if ( XPLEVEL >= MINLEVEL && XPLEVEL <= MAXLEVEL) {
        // inform all other modules that might need to track XPLEVEL
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"GET_XPLEVEL|XPLEVEL="+(string)XPLEVEL,llGetOwner());
        return XPLEVEL;
    } else {
        ERROR("GET_XPLEVEL ["+(string)XPLEVEL+"] AMOUNT OUT OF RANGE "+(string)MINLEVEL+"-"+(string)MAXLEVEL+"! RESETTING");
    }
    RESET();
    return 0;
}
 
// ===========================================================================
// ===========================================================================
RESET() {
    // do any final work, then reset
    llResetScript();
}
 
// ===========================================================================
// ===========================================================================
SET_BACKGROUND(string abackground) {
    BACKGROUND = abackground;
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_BACKGROUND|BACKGROUND="+BACKGROUND,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
SET_BOON(string boonname,integer boonrank) {
    // TODO how to verify boon names are valid?
    if ( boonrank >= MINBOON && boonrank <= MAXBOON ) { // rank valid?
        BOONS = [boonname,boonrank] + BOONS; // add boon to list
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_BOON|"+boonname+"="+(string)boonrank,llGetOwner());
    } else { // invalid, report it
        ERROR("BOON "+boonname+" rank "+(string)boonrank+" value out of allowed range: "+(string)MINBOON+"-"+(string)MAXBOON);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_CAREER(string acareer) {
    CAREER = acareer;
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_CAREER|CAREER="+CAREER,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
SET_EFFECT(string effectname,integer effectrank) {
    // TODO how to verify effect name?
    if ( effectrank >= MINEFFECT && effectrank <= MAXEFFECT ) { // effect rank valid?
        EFFECTS = [effectname,effectrank] + EFFECTS; // add effect to list
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_EFFECT|"+effectname+"="+(string)effectrank,llGetOwner());
    } else { // invalid, report it
        ERROR("EFFECT "+effectname+" rank "+(string)effectrank+" value out of allowed range: "+(string)MINEFFECT+"-"+(string)MAXEFFECT);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_EQUIPMENT(string equipmentname,integer equipmentamount) {
    // TODO how to verify the equipment name is valid?
    if ( equipmentamount >= MINEQUIPPED && equipmentamount <= MAXEQUIPPED ) { // amount valid?
        EQUIPMENT = [equipmentname,equipmentamount] + EQUIPMENT; // add equipment to list
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_EQUIPMENT|"+equipmentname+"="+(string)equipmentamount,llGetOwner());        
    } else { // invalid, report it
        ERROR("EQUIPMENT "+equipmentname+" amount "+(string)equipmentamount+" value out of allowed range: "+(string)MINEQUIPPED+"-"+(string)MAXEQUIPPED);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_ESTATE(string anestate) {
    ESTATE = anestate;
    DEBUG("Estate: ["+ESTATE+"]");
}
 
// ===========================================================================
// ===========================================================================
SET_FLAW(string flawname,integer flawrank) {
    // TODO how to verify flaw names are valid?
    if ( flawrank >= MINFLAW && flawrank <= MAXFLAW ) { // rank valid?
        FLAWS = [flawname,flawrank] + FLAWS; // add flaw to list
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_FLAW|"+flawname+"="+(string)flawrank,llGetOwner());
    } else { // invalid, report it
        ERROR("FLAW "+flawname+" rank "+(string)flawrank+" value out of allowed range: "+(string)MINFLAW+"-"+(string)MAXFLAW);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_GP(integer gpamt) {
    if ( gpamt >= 0 ) {
        GP = gpamt;
    } else {
        ERROR("SET_GP("+(string)gpamt+") REQUESTED AMOUNT OUT OF RANGE: LESS THAN ZERO");
    }
}
 
// ===========================================================================
// ===========================================================================
SET_HEALTHPOOL(integer healthamt) {
    if ( healthamt >= 0 ) {
        HEALTHPOOL = healthamt;
    } else {
        ERROR("SET_HEALTHPOOL("+(string)healthamt+") REQUESTED AMOUNT OUT OF RANGE: LESS THAN ZERO");
    }
}
 
// ===========================================================================
// ===========================================================================
SET_NAME(string aname) {
    NAME = aname;
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_NAME|NAME="+NAME,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
SET_QUOTE(string quotename) {
    // TODO how to verify quote?
    QUOTES = [quotename] + QUOTES; // add quote to list
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_QUOTE|QUOTE="+quotename,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
SET_RESILIENCE(string name,integer value) {
    if ( value < 0 ) { return;} // out of range
    if ( value > 20 ) { return; } // out of range
    integer curpos = llListFindList(CURRENT_RESILIENCES,[name]);
    integer curval;
    integer maxval;
    if ( curpos >= 0 ) {
        curval = llList2Integer(CURRENT_RESILIENCES,curpos + 1);
    } else { // resilience not found
            return;
    }
    integer maxpos = llListFindList(RESILIENCES,[name]);
    if ( maxpos >=0 ) {
        maxval = llList2Integer(RESILIENCES,maxpos + 1);
    } else { // resilience not found
            return;
    }
    if ( value <= maxval) {
        CURRENT_RESILIENCES = llListReplaceList(CURRENT_RESILIENCES,[value],curpos + 1, curpos + 1);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_RP(integer rpamt) {
    if ( rpamt >= 0 ) {
        RP = rpamt;
    } else {
        ERROR("SET_RP("+(string)rpamt+") REQUESTED AMOUNT OUT OF RANGE: LESS THAN ZERO");
    }
}
 
// ===========================================================================
// ===========================================================================
SET_SPECIES(string aspecies) {
    SPECIES = aspecies;
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_SPECIES|SPECIES="+SPECIES,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
SET_SFXPOOL(integer sfxamt) {
    if ( sfxamt >= 0 ) {
        SFXPOOL = sfxamt;
    } else {
        ERROR("SET_SFXPOOL("+(string)sfxamt+") REQUESTED AMOUNT OUT OF RANGE: LESS THAN ZERO");
    }
}
 
// ===========================================================================
// ===========================================================================
SET_SKILL(string skillname,integer skillrank) {
    // TODO how to verify skill names are valid?
    if ( skillrank >= MINSKILL && skillrank <= MAXSKILL ) { // skill rank valid?
        SKILLS = [skillname,skillrank] + SKILLS; // add skill to list
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_SKILL|"+skillname+"="+(string)skillrank,llGetOwner());
    } else { // invalid, report it
        ERROR("SKILL "+skillname+" rank "+(string)skillrank+" value out of allowed range: "+(string)MINSKILL+"-"+(string)MAXSKILL);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_SKILLPOOL(integer skillamt) {
    if ( skillamt >= 0 ) {
        SKILLPOOL = skillamt;
    } else {
        ERROR("SET_SKILLPOOL("+(string)skillamt+") REQUESTED AMOUNT OUT OF RANGE: LESS THAN ZERO");
    }
}
 
// ===========================================================================
// ===========================================================================
SET_STAT(string statname,integer statrank) {
    // TODO how to verify stat names are valid?
    if ( statrank >= MINSTAT && statrank <= MAXSTAT ) { // rank valid?
        integer statpos = llListFindList(STATISTICS,[statrank]);
        if ( statpos >= 0 ) {
            STATISTICS = [statname,statrank] + STATISTICS; // add statistic to list
 
        } else {
            STATISTICS = llListReplaceList(STATISTICS,[statrank],statpos + 1,statpos + 1);
        }
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_STATISTIC|"+statname+"="+(string)statrank,llGetOwner());
 
    } else { // invalid, report it
        ERROR("STATISTIC "+statname+" rank "+(string)statrank+" value out of allowed range: "+(string)MINSTAT+"-"+(string)MAXSTAT);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_STATPOOL(integer statamt) {
    if ( statamt >= 0 ) {
        STATPOOL = statamt;
    } else {
        ERROR("SET_STATPOOL("+(string)statamt+") REQUESTED AMOUNT OUT OF RANGE: LESS THAN ZERO");
    }
}
 
// ===========================================================================
// ===========================================================================
SET_STUNT(string stuntname) {
    // TODO how to verify stunt?
    STUNTS = [stuntname] + STUNTS; // add stunt to list
    llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_STUNT|STUNT="+stuntname,llGetOwner());
}
 
// ===========================================================================
// ===========================================================================
SET_XP(integer xpamt) {
    if ( xpamt >= MINXP && xpamt <= MAXXP ) {
        XP = xpamt;
        CALCULATE_LEVEL_BY_XP();
        // inform all other modules that might need to track XP
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_XP|XP="+(string)XP,llGetOwner());
    } else {
        ERROR("SET_XP("+(string)xpamt+") REQUESTED AMOUNT OF RANGE: "+(string)MINXP+"-"+(string)MAXXP);
    }
}
 
// ===========================================================================
// ===========================================================================
SET_XPLEVEL(integer xplevelamt) {
    if ( xplevelamt >= MINLEVEL && xplevelamt <= MAXLEVEL ) {
        XPLEVEL = xplevelamt; // save local state
        llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"SET_XPLEVEL|XPLEVEL="+(string)XPLEVEL,llGetOwner());
    } else {
        ERROR("SET_XPLEVEL("+(string)xplevelamt+") REQUESTED AMOUNT OUT OF RANGE: "+(string)MINLEVEL+"-"+(string)MAXLEVEL);
    }    
}
 
// ===========================================================================
// ===========================================================================
SETUP() {
    FLAG_DEBUG = FALSE;
    PLAYERID = llGetOwner();
    CHANOBJECT = (integer)("0x"+llGetSubString(llGetKey(),0,6));
    if ( HANDOBJECT != 0 ) llListenRemove(HANDOBJECT);
    HANDOBJECT = llListen(CHANOBJECT,"",NULL_KEY,"");
    llRegionSay(CHANMYRIAD,"GET_REGION_SETTING|ESTATE");
    MENU_TIMER = MENU_TIMEOUT;
    llSetTimerEvent(1.0);
}
 
// ===========================================================================
// ===========================================================================
default {
 
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    //attach(key attached) {
    //    attached = NULL_KEY; // LSLINT
    //    RESET(); // reset to force script through the state_entry event
    //}
 
    //------------------------------------------------------------------------
    // dataserver called for each line of notecard requested - process character sheet
    //------------------------------------------------------------------------
    dataserver(key queryid,string data) {
        if ( queryid == QUERY ) { // ataserver gave us line we asked for?
            if ( data != EOF ) { // we're not at end of notecard file?
                if ( llGetSubString(data,0,0) == "#" ) { // does this line start with comment mark?
                    QUERY = llGetNotecardLine(CARD,LINE++); // ignore comment and ask for the next line
                    return;
                }
                // Parse non-comment lines in keyword = value[,value,...] format
                list FIELDS = llParseString2List(data,["="],[]); // break line of text into = delimited fields
                string CMD = llStringTrim(llList2String(FIELDS,0),STRING_TRIM); // field zero is the "command"
                string DATA = llStringTrim(llList2String(FIELDS,1),STRING_TRIM); // field one is the data
                list SUBFIELDS = llParseString2List(DATA,[","],[]); // break data field into comma-delimited subfields if needed
                if ( CMD == "VERSION")      { CHECK_CARDVERSION(DATA); }
                if ( CMD == "NAME" )        { SET_NAME(DATA); } // TODO verify names are appropriate
                if ( CMD == "SPECIES" )     { SET_SPECIES(DATA); } // TODO verify valid species template name
                if ( CMD == "BACKGROUND" )  { SET_BACKGROUND(DATA); } // TODO verify valid background template name
                if ( CMD == "CAREER" )      { SET_CAREER(DATA); } // TODO verify valid career template name
                if ( CMD == "XP" )          { SET_XP((integer)DATA); }
                if ( CMD == "XPLEVEL" )     { SET_XPLEVEL((integer)DATA); }
                if ( CMD == "GP" )          { SET_GP((integer)DATA);}
                if ( CMD == "STATPOOL" )    { SET_STATPOOL((integer)DATA);}
                if ( CMD == "HEALTHPOOL" )  { SET_HEALTHPOOL((integer)DATA);}
                if ( CMD == "SKILLPOOL" )   { SET_SKILLPOOL((integer)DATA);}
                if ( CMD == "SFXPOOL" )     { SET_SFXPOOL((integer)DATA);}
                if ( CMD == "RP" )          { SET_RP((integer)DATA);}
                if ( CMD == "STATISTIC" )   { SET_STAT(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                if ( CMD == "RESILIENCE" )  { ADD_RESILIENCE(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                if ( CMD == "BOON" )        { SET_BOON(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                if ( CMD == "FLAW" )        { SET_FLAW(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                if ( CMD == "SKILL" )       { SET_SKILL(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                if ( CMD == "EFFECT" )      { SET_EFFECT(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                if ( CMD == "STUNT" )       { SET_STUNT(llList2String(SUBFIELDS,0)); } // TODO how to handle stunts with commas?
                if ( CMD == "QUOTE" )       { SET_QUOTE(llList2String(SUBFIELDS,0)); } // TODO how to handle quotes with commas?
                if ( CMD == "EQUIPMENT" )   { SET_EQUIPMENT(llList2String(SUBFIELDS,0),llList2Integer(SUBFIELDS,1)); }
                QUERY = llGetNotecardLine(CARD,LINE++); // finished with known keywords, get next line
            } else { // end of notecard
                // TODO how to verify entire character sheet was completed and loaded?
                llMessageLinked(LINK_THIS,MODULE_CHARSHEET,"CHARACTER_LOADED",llGetOwner()); // done loading
                DEBUG("Character Sheet Loaded.");
            } // end if data not equal eof
        } // end if query id equal
    } // end if data server event
 
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    link_message(integer sender_num,integer module_num,string message,key id) {
        sender_num = 0; // LSLint
        id = NULL_KEY; // LSLint
        if ( module_num == MODULE_CHARSHEET ) return; // ignore link messages not sent to us specifically
        if ( message == "DEBUG_OFF" ) { FLAG_DEBUG=FALSE; } // turn off debugging on request
        if ( message == "DEBUG_ON" ) { FLAG_DEBUG=TRUE; } // turn on debugging on request
        if ( message == "GET_VERSION") { GET_VERSION(); } // respond with version info when requested
        if ( message == "RESET" || message == "BAMRESET" || message == "ARMORRESET" ) { RESET(); } // reset on request
        //
        list tokens = llParseString2List(message,[DIV],[]);
        string command = llList2String(tokens,0);
        string data = llList2String(tokens,1);
        list subtokens = llParseString2List(data,["="],[]);
        string attrib = llList2String(subtokens,0);
        integer ivalue = llList2Integer(subtokens,1);
        //string svalue = llList2String(subtokens,1);
        //if ( command == "SET_ESTATE" ) { SET_ESTATE(svalue); return;}
        if ( command == "GET_XP" ) { GET_XP(); return; }
        if ( command == "SET_XP" ) { SET_XP(ivalue); return; }
        if ( command == "GET_XPLEVEL" ) { GET_XPLEVEL(); return; }
        if ( command == "SET_XPLEVEL" ) { SET_XPLEVEL(ivalue); return; }
        if ( command == "GET_STAT" ) { GET_STAT(attrib); return; }
        if ( command == "GET_RESILIENCE" ) { GET_RESILIENCE(attrib); return; }        
        if ( command == "GET_MAXRESILIENCE" ) { GET_MAXRESILIENCE(attrib);  return; }
        if ( command == "SET_RESILIENCE" ) { SET_RESILIENCE(attrib,ivalue); return; }
    }
 
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    listen(integer channel,string name,key id, string msg) {
        name = ""; // LSLint
        id = NULL_KEY; // LSLint
        if ( channel == CHANOBJECT ) {
            list tokens = llParseString2List(msg,[DIV],[]);
            string command = llToLower(llStringTrim(llList2String(tokens,0),STRING_TRIM));
            if ( command == "region_setting" ) {
                list sublist = llParseString2List(llList2String(tokens,1),["="],[]);
                if ( llToLower(llStringTrim(llList2String(sublist,0),STRING_TRIM)) == "estate" ) {
                    SET_ESTATE(llList2String(sublist,1));
                    DEBUG("Estate set to: "+ESTATE);
                    FIND_NOTECARD();
                }
                return;
            }
            return;
        }
        if ( channel == MENU_CHANNEL ) {
            if ( msg == "Default" ) {
                CARD = DEFAULT;
            } else {
                integer listpos = llListFindList(CHARACTERS,[msg]);
                if ( listpos >= 0 ) {
                    CARD = llList2String(CHARACTERS,listpos + 1);
                }
            }
            llSetTimerEvent(0.0);
            MENU_TIMER = 0;
            llListenRemove(MENU_HANDLE);
            QUERY = llGetNotecardLine(CARD,LINE++); // ask for line from notecard and advance to next line
            return;
        }
    }
 
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    on_rez(integer start_param) {
        start_param = 0; // LSLINT
        RESET(); // reset to force script through the state_entry event
    }
 
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    state_entry() {
        SETUP();
    }
 
    //------------------------------------------------------------------------
    //------------------------------------------------------------------------
    timer() {
        MENU_TIMER--; // timer still running, decrement
        if ( MENU_TIMER <= 0 ) { // timed out
            llOwnerSay("Character Sheet Menu timed out. Using default character sheet."); // tell the owner
            llListenRemove(MENU_HANDLE); // remove the listener
            MENU_TIMER = 0;
            llSetTimerEvent(0.0); // stop the timer
            CARD = DEFAULT;
            QUERY = llGetNotecardLine(CARD,LINE++);
        }
    }
}
//============================================================================
// END
//============================================================================
Personal tools
General
About This Wiki