====== Myriad Lite Module Character Notecards ====== // Myriad_Lite_Module_Character_Notecards-v0.0.2-20131025.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/ // FIXME LOAD TIMEOUT // FIXME PPMA // FIXME THE ESTATE MESS // VERSION CONTROL string BASENAME = "Myriad Lite Module Character Notecards"; string VERSION = "0.0.2"; // Allen Kerensky's script version string VERSIONDATE = "20131025"; // Allen Kerensky's script yyyymmdd // MODULE TO MODULE MESSAGING CONSTANTS integer MODULE_CHARNOTES = -13; integer LM_SENDTOATTACHMENT = 0x80000000; // Runtimes string ESTATE; // what estate does this region belong to - loaded from region server 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-Preview7.txt"; // character sheet notecard integer LINE = 0; // reading line number key QUERY = NULL_KEY; // track notecard queries // CHARACTER SHEET STORAGE string CARDVERSION = "0.0.6"; // what card format version do we expect // // 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|= // PPMA: FLAG,, // LMOUT: FLAG|= // 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|= // PPMA: FLAG,, // LMOUT: SET_FLAG|= // 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); //} // CHECK_CARDVERSION 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 ( GET_FLAG("DEBUG") == TRUE ) llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"DEBUG|"+debugmsg,llGetOwner()); } ERROR(string errmsg) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"ERROR|"+errmsg,llGetOwner()); } FIND_NOTECARD() { integer count = llGetInventoryNumber(INVENTORY_NOTECARD); if ( count <= 0 ) { ERROR("No Character Sheet Notecards to Load"); return; } if ( count == 1 ) { CARD = DEFAULT; QUERY = llGetNotecardLine(CARD,LINE++); OWNERSAY("Loading default character sheet."); return; } // found > 1 cards, sort them and a do a menu CHARACTERS = []; MENU = ["Default"]; //string regionname = llGetRegionName(); 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); } // 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(string str) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"OWNERSAY|"+str,llGetOwner()); } PARSE(string message,key id) { // debugged in link message and chat events // First - handle type 1 messages that do not require breaking down string msg = llToLower(message); if ( msg == "memory" ) { GET_MEMORY(); return;} if ( msg == "reset" ) { RESET(); return; } // reset on request if ( msg == "version") { GET_VERSION(); return; } // respond with version info when requested // Set up variables to process type 2 and type 3 messages list tokens; string cmd; string data; list subtokens; string attrib; integer idata; string sdata; // Process type 3 messages CATEGORY=ATTRIBUTE,VALUE tokens = llParseString2List(message,["="],[]); cmd = llToLower(llStringTrim(llList2String(tokens,0),STRING_TRIM)); data = llList2String(tokens,1); subtokens = llCSV2List(data); attrib = llList2String(subtokens,0); idata = llList2Integer(subtokens,1); sdata = llList2String(subtokens,1); if ( cmd == "cardversion" ) { CHECK_CARDVERSION(data); return;} if ( cmd == "name" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_NAME|NAME="+data,id); return; } if ( cmd == "nickname" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_NICKNAME|NICKNAME="+data,id); return;} if ( cmd == "title" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_TITLE|TITLE="+data,id); return;} if ( cmd == "faction" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_FACTION|FACTION="+data,id); return;} if ( cmd == "specie" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_SPECIE|SPECIE="+data,id); return;} if ( cmd == "background" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_BACKGROUND|BACKGROUND="+data,id); return; } if ( cmd == "career" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_CAREER|CAREER="+data,id); return; } if ( cmd == "statistic" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_STATISTIC|"+attrib+"="+sdata,id); return; } if ( cmd == "resilience" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_RESILIENCE|"+attrib+"="+sdata,id); return;} if ( cmd == "boon" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_BOON|"+attrib+"="+sdata,id); return;} if ( cmd == "flaw" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_FLAW|"+attrib+"="+sdata,id); return;} if ( cmd == "skill" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_SKILL|"+attrib+"="+sdata,id); return;} if ( cmd == "mortal_effect" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_EFFECT|"+attrib+"="+sdata,id); return;} if ( cmd == "social_effect" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_EFFECT|"+attrib+"="+sdata,id); return;} if ( cmd == "magic_effect" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_EFFECT|"+attrib+"="+sdata,id); return;} if ( cmd == "vehicle_effect" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_EFFECT|"+attrib+"="+sdata,id); return;} if ( cmd == "stunt" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_STUNT|STUNT="+data,id); return;} if ( cmd == "quote" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_QUOTE|QUOTE="+data,id); return;} if ( cmd == "equipment" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_ITEM|"+attrib+"="+sdata,id); return;} if ( cmd == "xp" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_XP|XP="+data,id); return; } if ( cmd == "xplevel" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_XPLEVEL|XPLEVEL="+data,id); return; } if ( cmd == "gp" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_GP|GP="+data,id); return;} if ( cmd == "statpool" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_STATPOOL|STATPOOL="+data,id); return;} if ( cmd == "healthpool" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_HEALTHPOOL|HEALTHPOOL="+data,id); return; } if ( cmd == "skillpool" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_SKILLPOOL|SKILLPOOL="+data,id); return; } if ( cmd == "sfxpool" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_SFXPOOL|SFXPOOL="+data,id); return; } if ( cmd == "rp" ) { llMessageLinked(LINK_THIS,MODULE_CHARNOTES,"SET_RP|RP="+data,id); return; } if ( cmd == "character_loaded" ) { OWNERSAY("character notecard loaded."); } } RESET() { // do any final work, then reset llResetScript(); } SET_ESTATE(string anestate) { ESTATE = anestate; DEBUG("Estate: ["+ESTATE+"]"); } SETUP() { CHANOBJECT = (integer)("0x"+llGetSubString(llGetKey(),0,6)); if ( HANDOBJECT != 0 ) llListenRemove(HANDOBJECT); HANDOBJECT = llListen(CHANOBJECT,"",NULL_KEY,""); //MENU_TIMER = MENU_TIMEOUT; //llSetTimerEvent(1.0); FIND_NOTECARD(); OWNERSAY("Notecard module active."); } default { // 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(data,llGetOwner()); // parse incoming notecard line 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_CHARNOTES,"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 num,string str,key id) { if ( num == MODULE_CHARNOTES || 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 only after ignored messages DEBUG("EVENT: link_message("+(string)sender_num+","+(string)num+","+str+","+(string)id+")"); PARSE(str,id); // parse incoming message } listen(integer channel,string name,key id, string msg) { DEBUG("channel=["+(string)channel+"] name=["+name+"] id=["+(string)id+"] msg=["+msg+"]"); if ( channel == CHANOBJECT ) { list tokens = llParseString2List(msg,["|"],[]); 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)); FIND_NOTECARD(); return; } return; } PARSE(msg,id); // parse incoming chat message not REGION_SETTING or SKILL data return; } if ( channel == MENU_CHANNEL ) { if ( msg == "Default" ) { CARD = DEFAULT; } else { integer listpos = llListFindList(CHARACTERS,[msg]); if ( listpos >= 0 ) { CARD = llList2String(CHARACTERS,listpos + 1); } } DEBUG("Loading character sheet: "+CARD); llSetTimerEvent(0.0); MENU_TIMER = 0; llListenRemove(MENU_HANDLE); QUERY = llGetNotecardLine(CARD,LINE++); // ask for line from notecard and advance to next line return; } } state_entry() { SETUP(); } timer() { MENU_TIMER--; // timer still running, decrement if ( MENU_TIMER <= 0 ) { // timed out DEBUG("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