// 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|<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);
//}
// 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