====== Myriad Lite Module Armor ====== // Myriad_Lite_Module_Armor-v0.0.4-20130621.lsl // Copyright (c) 2012 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/ // =========================================================================== // TODO - Armor, PowerArmor, Shield, PowerShield // =========================================================================== // FIXME add some RPEVENT? // FIXME add some HELP? // How to receive ARMOR SFX from attached ARMOR // How to store ARMOR SFX into PPMA // How to process/apply ARMOR SFX especially with Skill Combat modules // How to flag ARMOR_ENCUMBERANCE from Region Server // How to manage Armor battery max per piece - send from attach? store? // How to have Armor USES - each point of damage absorbed wears armor or battery? // How to handle armor ablation - X points that wear off Armor Resilience? // =========================================================================== // INTERNAL CONSTANTS - should not change during runtime // =========================================================================== string BASENAME = "Myriad Lite Module Armor"; string VERSION = "0.0.4"; string VERSIONDATE = "20130621"; // Module to Module Messaging Constants integer MODULE_ARMOR = -3; integer LM_SENDTOATTACHMENT = 0x80000000; // string names for each attach point - waste of memory? list ATTACHPOINTS = ["INVALID","chest","head","left shoulder","right shoulder","left hand","right hand","left foot","right foot","back","pelvis","mouth","chin","left ear","right ear","left eye","right eye","nose","right upper arm","right lower arm","left upper arm","left lower arm","right hip","right upper leg","right lower leg","left hip","left upper leg","left lower leg","stomach","left pectoral","right pectoral","HUD Center 2","HUD Top Right","HUD Top","HUD Top Left","HUD Center","HUD Bottom Left","HUD Bottom","HUD Bottom Right", "neck", "root" ]; // =========================================================================== // GLOBAL RUNTIMES - expected to change at runtime // =========================================================================== // list ARMOR; // list of armor amount (1-5) on each attachpoint from 0 (unused) to 30 // list ARMOR_POWER; // list of true/false flags for each attachpoint from 0 (unused) to 30 if power armor or not integer ARMOR_ON; // is armor "on" and protecting? integer ARMOR_CURRENT; // highest armor value worn out of all armor worn, not a total integer ARMOR_POWERED; integer ARMOR_BATTERY; integer ARMOR_BATTERY_MAX; // maximum power armor battery life - all armor powered equally integer ARMOR_EFFECT_TIME; // how much time is left to show armor effects integer ARMOR_EFFECT_MAX; // maximum time to show armor hit/blocked effects // =========================================================================== // PPMA // =========================================================================== 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"); } ERASE_TYPE(string type) { //OWNERSAY("ERASE TYPE ["+type+"] STARTS"); // scan index or prim names for empty, get number for update integer i; string name = ""; string desc = ""; for ( i = 2; i <= llGetNumberOfPrims(); i++) { name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0); if ( name == type ) { desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0); DELETE_RECORD(type,desc); } } //OWNERSAY("ERASE_TYPE ENDS"); } string KEY_NOT_FOUND = "[KEY_NOT_FOUND]"; string GET_VAL(string dbkey,string field) { //OWNERSAY("GET_VAL KEY=["+dbkey+"] FIELD=["+field+"]"); string out = KEY_NOT_FOUND; integer i; string name; string desc; for ( i = 2; i <= llGetNumberOfPrims(); i++ ) { name = llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0); desc = llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0); if ( llToLower(name) == llToLower(dbkey) && llToLower(desc) == llToLower(field) ) { out = llList2String(llGetLinkPrimitiveParams(i,[PRIM_TEXT]),0); //DEBUG("GET_VAL RETURN=["+out+"]"); return out; // bail on first match? } } //OWNERSAY("GET_VAL RETURN=["+out+"]"); return out; } SET_VAL(string dbkey, string field, string val) { //OWNERSAY("SET_VAL KEY=["+dbkey+"] FIELD=["+field+"] VAL=["+val+"]"); integer i; string name; string desc; integer written = FALSE; for ( i = 2; i <= llGetNumberOfPrims(); i++ ) { name = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0),STRING_TRIM); desc = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0),STRING_TRIM); if ( ( llToLower(name) == llToLower(dbkey) && llToLower(desc) == llToLower(field) ) && written == FALSE ) { //OWNERSAY("SET_VAL UPDATE RECORD=["+(string)i+"] DBKEY=["+dbkey+"] DESC=["+field+"] VAL=["+val+"]"); llSetLinkPrimitiveParamsFast(i,[PRIM_NAME,dbkey,PRIM_DESC,field,PRIM_TEXT,val,ZERO_VECTOR,0.0]); written = TRUE; // we did an update, remember it } } if ( written == TRUE ) { //OWNERSAY("SET_VAL UPDATE COMPLETE."); return; } // data hasn't been written, scan for free prim for ( i = 2; i <= llGetNumberOfPrims(); i++ ) { name = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_NAME]),0),STRING_TRIM); desc = llStringTrim(llList2String(llGetLinkPrimitiveParams(i,[PRIM_DESC]),0),STRING_TRIM); if ( ( name == "" && desc == "" ) && written == FALSE ) { //OWNERSAY("SET_VAL INSERT RECORD=["+(string)i+"] DBKEY=["+dbkey+"] DESC=["+field+"] VAL=["+val+"]"); llSetLinkPrimitiveParamsFast(i,[PRIM_NAME,dbkey,PRIM_DESC,field,PRIM_TEXT,val,ZERO_VECTOR,0.0]); written = TRUE; // we did an update, remember it } } if ( written == TRUE ) { //OWNERSAY("SET_VAL INSERT COMPLETED."); return; } //OWNERSAY("SET_VAL NO FREE RECORD FOUND TO INSERT INTO! DATA LOST"); } ////////////////////////////////////////////////////////////////////////////// // FLAG FUNCTIONS // INCAPACITATED - lost wounds // DEAD - lost critical wounds // DEBUG - show debug messages or not // IDEA: INDECISION - lost resolve? // LMIM: SET_FLAG|= // 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); } // // 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; } // =========================================================================== // ARMOR // =========================================================================== integer ATTACH_MIN = 1; // min valid attach point integer ATTACH_MIN_HUD = 31; // lower HUD attach point number integer ATTACH_MAX_HUD = 38; // upper HUD attach point number integer ATTACH_MAX = 40; // max valid in-world wearable attach point integer GET_ARMOR(integer attachpoint) { if ( attachpoint < ATTACH_MIN || ( attachpoint >= ATTACH_MIN_HUD && attachpoint <= ATTACH_MAX_HUD ) || attachpoint > ATTACH_MAX ) { ERROR("Invalid armor attachment point: "+(string)attachpoint); return 0; } string csv = GET_VAL("ARMOR","RATINGS"); integer armor = llList2Integer(llCSV2List(csv),attachpoint); if ( armor < GET_MYRIAD("MINARMOR") ) { armor = GET_MYRIAD("MINARMOR"); SET_ARMOR(attachpoint,GET_MYRIAD("MINARMOR")); } if ( armor > GET_MYRIAD("MAXARMOR") ) { armor = GET_MYRIAD("MAXARMOR"); SET_ARMOR(attachpoint,GET_MYRIAD("MAXARMOR")); } // FIXME llMessageLinked(...) return armor; } SET_ARMOR(integer attachpoint,integer armor) { if ( attachpoint < ATTACH_MIN || ( attachpoint >= ATTACH_MIN_HUD && attachpoint <= ATTACH_MAX_HUD ) || attachpoint > ATTACH_MAX ) { ERROR("Invalid armor attachment point: "+(string)attachpoint); return; } if ( armor < GET_MYRIAD("MINARMOR") ) armor = GET_MYRIAD("MINARMOR"); if ( armor > GET_MYRIAD("MAXARMOR") ) armor = GET_MYRIAD("MAXARMOR"); string csv = GET_VAL("ARMOR","RATINGS"); list armorcsv = llCSV2List(csv); armorcsv = llListReplaceList(armorcsv,[armor],attachpoint,attachpoint); csv = llList2CSV(armorcsv); SET_VAL("ARMOR","RATINGS",csv); // FIXME llMessageLinked(...) } integer POWER_ARMOR_MIN = 0; integer POWER_ARMOR_MAX = 86400; integer GET_POWERARMOR(integer attachpoint) { if ( attachpoint < ATTACH_MIN || ( attachpoint >= ATTACH_MIN_HUD && attachpoint <= ATTACH_MAX_HUD ) || attachpoint > ATTACH_MAX ) { ERROR("Invalid armor attachment point: "+(string)attachpoint); return 0; } string csv = GET_VAL("ARMOR","POWER"); integer power = llList2Integer(llCSV2List(csv),attachpoint); if ( power < POWER_ARMOR_MIN ) { power = POWER_ARMOR_MIN; SET_POWERARMOR(attachpoint,POWER_ARMOR_MIN); } if ( power > POWER_ARMOR_MAX ) { power = POWER_ARMOR_MAX; SET_POWERARMOR(attachpoint,POWER_ARMOR_MAX); } // FIXME llMessageLinked(...) return power; } SET_POWERARMOR(integer attachpoint,integer power) { if ( attachpoint < ATTACH_MIN || ( attachpoint >= ATTACH_MIN_HUD && attachpoint <= ATTACH_MAX_HUD ) || attachpoint > ATTACH_MAX ) { ERROR("Invalid armor attachment point: "+(string)attachpoint); return; } if ( power < POWER_ARMOR_MIN ) power = POWER_ARMOR_MIN; if ( power > POWER_ARMOR_MAX ) power = POWER_ARMOR_MAX; string csv = GET_VAL("ARMOR","RATINGS"); list powercsv = llCSV2List(csv); powercsv = llListReplaceList(powercsv,[power],attachpoint,attachpoint); csv = llList2CSV(powercsv); SET_VAL("ARMOR","POWER",csv); // FIXME llMessageLinked(...) } //============================================================================ // ARMORATTACH - Wearing a piece of armor // ARMORATTACH|ARMORRATING|ARMOR_POWERED?|ARMORATTACHPOINT|ARMORNAME // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMORATTACH(integer waamount,integer wapower,integer waattachpoint,string waname) { DEBUG("ARMORATTACH Amount=["+(string)waamount+"] Power=["+(string)wapower+"] AttachPoint=["+(string)waattachpoint+"] Name=["+waname+"]"); if ( waattachpoint < ATTACH_MIN || ( waattachpoint >= ATTACH_MIN_HUD && waattachpoint <= ATTACH_MAX_HUD ) || waattachpoint > ATTACH_MAX ) { // valid attach point? ERROR("Invalid armor attachment point: "+(string)waattachpoint); return; } if ( waamount < GET_MYRIAD("MINARMOR") || waamount > GET_MYRIAD("MAXARMOR") ) { // is armor rating valid or legal? ERROR("Invalid armor amount "+(string)waamount+" out of range "+(string)GET_MYRIAD("MINARMOR")+"-"+(string)GET_MYRIAD("MAXARMOR")); return; } if ( wapower != TRUE && wapower != FALSE ) { ERROR("Cannot determine if worn armor is power armor."); return; } // FIXME move ARMOR and ARMOR_POWERED into single list? if ( wapower == TRUE ) SET_POWERARMOR(waattachpoint,TRUE); // insert armor value into armor list // FIXME move ARMOR to 3-element strided list? [attachpoint,value,name?] SET_ARMOR(waattachpoint,waamount); // insert armor value into armor PPMA OWNERSAY("Armor "+waname+" ("+(string)waamount+") attached to "+llList2String(ATTACHPOINTS,waattachpoint)); ARMORCHECK(); // find new highest armor value } //============================================================================ // ARMORBATTERY // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMORBATTERY() { //llWhisper(CHANATTACH,"ARMORBATTERY"); if ( ARMOR_POWERED != TRUE ) { OWNERSAY("Cannot check battery level for non-powered armor."); return; } OWNERSAY("Armor battery level: "+(string)ARMOR_BATTERY+" of "+(string)ARMOR_BATTERY_MAX+" total."); SENDTOATTACH("ARMORBATTERY"); } //============================================================================ // ARMORCHECK - sets ARMOR_CURRENT to highest armor value worn after attach or detach // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMORCHECK() { ARMOR_CURRENT = 0; // start with zero armor ARMOR_POWERED = FALSE; integer racount = ATTACH_MAX; // how long is armor list? string csv1 = GET_VAL("ARMOR","RATINGS"); string csv2 = GET_VAL("ARMOR","POWER"); list armorratings = llCSV2List(csv1); list armorpower = llCSV2List(csv2); while (racount--) { // look at each list item from last to first integer rapoints = llList2Integer(armorratings,racount); // what is armor value at this point in list? integer pa = llList2Integer(armorpower,racount); if ( pa == FALSE ) { // not power armor in this slot, so do check regardless of power state if ( rapoints > ARMOR_CURRENT ) { // is this armor value higher than current max? ARMOR_CURRENT = rapoints; // yes, save new highest amount } } else { // this is power armor in this slot. ARMOR_POWERED = TRUE; if ( ARMOR_ON == TRUE && ARMOR_BATTERY > 0 && rapoints > ARMOR_CURRENT ) { ARMOR_CURRENT = rapoints; // yes armor is on, has power, and current value is higher, save new highest amount } } } if ( ARMOR_POWERED == TRUE ) { OWNERSAY("Power Armor Rating is "+(string)ARMOR_CURRENT); } else { OWNERSAY("Non-Power Armor Rating is "+(string)ARMOR_CURRENT); } SENDTOATTACH("ARMORCURRENT|"+(string)ARMOR_CURRENT); // FIXME send new ARMORCURRENT with RATING, POWERED?, ATTACHPOINT, ARMORNAME, ARMOR_BATTERY_MAX, CURRENTBATTERY? // FIXME tell world too? } //============================================================================ // ARMORDETACH - Removing a piece of armor // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMORDETACH(integer raamount,integer rapower,integer raattachpoint,string raname) { DEBUG("DETACH Amount=["+(string)raamount+"] Power=["+(string)rapower+"] Attachpoint=["+(string)raattachpoint+"] Name=["+raname+"]"); if ( raattachpoint < ATTACH_MIN || ( raattachpoint >= ATTACH_MIN_HUD && raattachpoint <= ATTACH_MAX_HUD ) || raattachpoint > ATTACH_MAX ) { // valid attach point? ERROR("Invalid armor detachment point: "+(string)raattachpoint); return; } if ( raamount < GET_MYRIAD("MINARMOR") || raamount > GET_MYRIAD("MAXARMOR") ) { // is armor rating valid or legal? ERROR("Invalid armor amount "+(string)raamount+" out of range "+(string)GET_MYRIAD("MINARMOR")+"-"+(string)GET_MYRIAD("MAXARMOR")); return; } if ( rapower != TRUE && rapower != FALSE ) { ERROR("Cannot determine if detached armor is power armor."); return; } // FIXME move ARMOR and ARMOR_POWERED into single list? if ( rapower == FALSE ) SET_POWERARMOR(raattachpoint,FALSE); // insert armor value into armor list // FIXME move ARMOR to 3-element strided list? [attachpoint,value,name?] SET_ARMOR(raattachpoint,0); // zero out the armor value in armor PPMA OWNERSAY("Armor "+raname+" ("+(string)raamount+") detached from "+llList2String(ATTACHPOINTS,raattachpoint)); ARMORCHECK(); // find new highest armor value } //============================================================================ // ARMOREFFECTBLOCKED - CHANGE ARMOR EFFECT WHEN ARMOR HIT AND BLOCKS DAMAGE // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMOREFFECTBLOCKED() { // your commands go here for armor special effect when armor BLOCKS a hit // llWhisper(CHANATTACH,"ARMOREFFECTBLOCKED"); SENDTOATTACH("ARMOREFFECTBLOCKED"); ARMOR_EFFECT_TIME = ARMOR_EFFECT_MAX; // load the countdown llSetTimerEvent(1.0); // start the effect timer } //============================================================================ // ARMOREFFECTHIT() - SHOW SPECIAL ARMOR EFFECTS WHEN ARMOR HIT BUT FAILS TO BLOCK // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMOREFFECTHIT() { //llWhisper(CHANATTACH,"ARMOREFFECTHIT"); SENDTOATTACH("ARMOREFFECTHIT"); ARMOR_EFFECT_TIME = ARMOR_EFFECT_MAX; // load the countdown llSetTimerEvent(1.0); // start the effect timer } //============================================================================ // ARMOREFFECTOFF - RESET ARMOR TO NORMAL VIEW // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMOREFFECTOFF() { //llWhisper(CHANATTACH,"ARMOREFFECTOFF"); SENDTOATTACH("ARMOREFFECTOFF"); } //============================================================================ // ARMOROFF // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMOROFF() { //llWhisper(CHANATTACH,"ARMOROFF"); // tell attachments to do some inworld special effects if needed if ( ARMOR_POWERED == TRUE ) { OWNERSAY("Power armor deactivated."); ARMOR_ON = FALSE; SENDTOATTACH("ARMOROFF"); llSetTimerEvent(0.0); // stop battery drain timer - FIXME does this kill effect timers? return; } ARMORCHECK(); } //============================================================================ // ARMOR ON // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMORON() { //llWhisper(CHANATTACH,"ARMORON"); // tell attachment to do some inworld special effect if needed if ( ARMOR_BATTERY <= 0 && ARMOR_POWERED == TRUE ) { OWNERSAY("Power armor out of power. Recharge."); return; } if ( ARMOR_POWERED == TRUE ) { OWNERSAY("Power armor activating."); ARMOR_ON = TRUE; SENDTOATTACH("ARMORON"); llSetTimerEvent(1.0); // run a battery drain timer, battery already checked > 0 } ARMORCHECK(); } //============================================================================ // ARMORRECHARGE // FIXME - Medieval, Modern, Futuristic // FIXME - Armor, Power Armor, Shield, PowerShield //============================================================================ ARMORRECHARGE() { //llWhisper(CHANATTACH,"ARMORRECHARGE"); if ( ARMOR_POWERED != TRUE ) { OWNERSAY("Cannot recharge non-powered armor."); return; } // TODO Partial Recharges? ARMOR_BATTERY = ARMOR_BATTERY_MAX; OWNERSAY("Armor recharged."); SENDTOATTACH("ARMORRECHARGE"); } //============================================================================ // COMMAND processor //============================================================================ COMMAND(string message) { // debugged in link message list fields = llParseString2List(message,["|"],[]); // break into list of fields based on "|"ider string command = llToLower(llStringTrim(llList2String(fields,0),STRING_TRIM)); // assume the first field is a Myriad Lite command // General Myriad Module Commnads if ( command == "memory" ) { GET_MEMORY(); return;} // get memory when needed if ( command == "reset" ) { RESET(); return;} // reset when told if ( command == "version" ) { GET_VERSION(); return;} // get version when needed // Armor-Specific Module Commands in alphabetical order by command if ( command == "armorattach" ) { // player attached armor somewhere integer armorrating = llList2Integer(fields,1); // get armor value integer armorpower = llList2Integer(fields,2); // get power armor or not integer attachpoint = llList2Integer(fields,3); // get armor location string armorname = llList2String(fields,4); // get armor's name ARMORATTACH(armorrating,armorpower,attachpoint,armorname); // add armor to set of armor worn return; } if ( command == "armorbattery") { ARMORBATTERY(); return;} // check power armor battery if ( command == "armorcheck" ) { ARMORCHECK(); return; } // check our current armor value // armorcurrent skipped intentionally if ( command == "armordetach" ) { // player attached armor somewhere integer armorrating = llList2Integer(fields,1); // get armor value integer armorpower = llList2Integer(fields,2); // get power armor or not integer attachpoint = llList2Integer(fields,3); // get armor location string armorname = llList2String(fields,4); // get armor's name ARMORDETACH(armorrating,armorpower,attachpoint,armorname); // detach armor from set of armor worn return; } if ( command == "armoreffecthit" ) { ARMOREFFECTHIT(); return;} // show SFX on hit if ( command == "armoreffectblocked" ) { ARMOREFFECTBLOCKED(); return;} // show SFX on hit if ( command == "armoreffectoff" ) { ARMOREFFECTOFF(); return;} // show SFX on hit if ( command == "armoron" ) { ARMORON(); return;} // turn on power armor if ( command == "armoroff" ) { ARMOROFF(); return;} // turn off power armor if ( command == "armorrecharge" ) { ARMORRECHARGE(); return;} // recharge power armor battery } //============================================================================ // DEBUG - show errors on debug channel with wearer name for sorting //============================================================================ DEBUG(string dmessage) { if ( GET_FLAG("DEBUG") == TRUE ) llMessageLinked(LINK_THIS,MODULE_ARMOR,"DEBUG|"+dmessage,llGetOwner()); } //============================================================================ // ERROR - show errors on debug channel with wearer name for sorting //============================================================================ ERROR(string emessage) { llMessageLinked(LINK_THIS,MODULE_ARMOR,"ERROR|"+emessage,llGetOwner()); } // MEMORY GET_MEMORY() { OWNERSAY(BASENAME+" free memory: "+(string)llGetFreeMemory()); } // GETVERSION GET_VERSION() { OWNERSAY(BASENAME+" v"+VERSION+"-"+VERSIONDATE); } // // OWNERSAY // OWNERSAY(string msg) { llMessageLinked(LINK_THIS,MODULE_ARMOR,"OWNERSAY|"+msg,llGetOwner()); } //============================================================================ // RESET - shut down running animations then reset the script to reload character sheet //============================================================================ RESET() { llResetScript(); // now reset } //============================================================================ // SENDTOATTACH - send reponses to HUD as Link Messages //============================================================================ SENDTOATTACH(string str) { DEBUG("SENDTOATTACH("+str+")"); llMessageLinked(LINK_THIS,LM_SENDTOATTACHMENT,str,llGetOwner()); } //============================================================================ // SETUP - begin //============================================================================ SETUP() { ARMOR_ON = FALSE; // is armor "on" and protecting? off by default to save battery ARMOR_BATTERY_MAX = 3600; // total battery capacity when fully charged - in seconds ARMOR_BATTERY = ARMOR_BATTERY_MAX; // start with charged battery FIXME how to save state from wear to wear ARMOR_EFFECT_MAX = 3; // show armor effects for how long in seconds? DELETE_RECORD("ARMOR","RATINGS"); // delete existing armor on reset - will be reloaded when armor checks in during attach or register SET_VAL("ARMOR","RATINGS","0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"); // create blank record DELETE_RECORD("ARMOR","POWER"); // delete existing armor power on reset SET_VAL("ARMOR","POWER","0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"); // create blank record //integer attachpoints = ATTACH_MAX; // counting from 0 to 40 //while ( attachpoints-- ) { //SET_ARMOR(attachpoints,0); // create empty armor slots - avoids SL stack depth error and LSLINT warning //ARMOR_POWER = ARMOR_POWER + [FALSE]; // create 30 empty power armor flags - avoid SL stack depth and LSLINT warning //} llSetTimerEvent(0.0); // stop any running timer OWNERSAY("Armor module active."); } //============================================================================ // TIMER_HEARTBEAT - code called each time a timer event fires // CALLED TO TURN OFF THE ARMOR SPECIAL EFFECTS AND DRAIN POWER ARMOR BATTERIES //============================================================================ TIMER_HEARTBEAT() { if ( ARMOR_EFFECT_TIME > 0 ) { // if there is still time to show armor special effects inworld, decrement counter ARMOR_EFFECT_TIME--; } if ( ARMOR_EFFECT_TIME <= 0 ) { // once armor effect timer counts down, cleanup. ARMOR_EFFECT_TIME = 0; // force to zero if somehow it went less than zero ARMOREFFECTOFF(); // send message to shut off special effects } if ( ARMOR_POWERED == TRUE && ARMOR_ON == TRUE && ARMOR_BATTERY > 0 ) { // if power armor on, decrement battery counter ARMOR_BATTERY--; // remove some battery } if ( ARMOR_POWERED == TRUE && ARMOR_ON == TRUE && ARMOR_BATTERY <= 0 ) { // power armor battery drained, cleanup OWNERSAY("Power armor battery drained. Shutting down."); ARMOR_BATTERY = 0; ARMOROFF(); } if ( ARMOR_EFFECT_TIME <= 0 && ARMOR_ON == FALSE ) llSetTimerEvent(0.0); // all timers done, stop timer events } // =========================================================================== // DEFAULT state // =========================================================================== default { // ----------------------------------------------------------------------- // LINK_MESSAGE - note: NUM field is the number of the sending module // ----------------------------------------------------------------------- link_message(integer sender_num,integer num,string str,key id) { if ( num == MODULE_ARMOR || num == LM_SENDTOATTACHMENT ) return; // ignore our own messages list fields = llParseString2List(str,["|"],[]); // break into list of fields based on "|"ider string cmd = llToLower(llStringTrim(llList2String(fields,0),STRING_TRIM)); // assume the first field is a Myriad Lite command if ( cmd == "debug" || cmd == "error" || cmd == "help" || cmd == "ownersay" || cmd == "rpevent" ) return; // ignore WELL messages // show debug only when not ignoring other commands DEBUG("EVENT: link_message("+(string)sender_num+","+(string)num+","+str+","+(string)id+")"); COMMAND(str); // jump to command processor } // ----------------------------------------------------------------------- // STATE_ENTRY // ----------------------------------------------------------------------- state_entry() { DEBUG("EVENT: state_entry()"); SETUP(); // setup defaults and go into event wait } //------------------------------------------------------------------------ // TIMER //------------------------------------------------------------------------ timer() { DEBUG("EVENT: timer()"); TIMER_HEARTBEAT(); } }