User:Allen Kerensky/Myriad Lite/Myriad Lite Module Armor-Preview6.lsl
From OpenSimulator
< User:Allen Kerensky | Myriad Lite
Revision as of 10:20, 27 July 2013 by Allen Kerensky (Talk | contribs)
Myriad_Lite_Module_Armor-Preview6.lsl
// Myriad_Lite_Module_Armor-Preview6.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/ string VERSION = "0.0.2"; string VERDATE = "20120317"; integer FLAG_DEBUG; // configure in setup key PLAYERID = NULL_KEY; // cached player UUID integer MINATTACH = 1; // min valid attach point integer MAXWEAR = 30; // max valid in-world wearable attach point integer MINARMOR = 1; // min armor defense value integer MAXARMOR = 5; // max armor defense value integer CURARMOR = 0; // highest armor value worn out of all armor worn, not a total list ARMOR = []; list ARMORPOWER = []; integer POWERARMOR; integer BATTERY; integer MAXBATTERY; integer MAXEFFECTTIME = 3; // maximum time to show armor hit/blocked effects integer EFFECTTIME; // how much time is left to show armor effects integer ARMOR_ON; // is armor "on" and protecting? // 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" ]; // 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; string DIV = "|"; // message divider //============================================================================ // SETUP - begin //============================================================================ SETUP() { FLAG_DEBUG = FALSE; // do we want debug messages ARMOR_ON = FALSE; // is armor "on" and protecting? off by default to save battery BATTERY = 3600; // start with charged battery FIXME how to save state from wear to wear MAXBATTERY = 3600; // total battery capacity when fully charged - in seconds PLAYERID = llGetOwner(); // remember the owner's UUID integer attachpoints = MAXWEAR; // counting from 0 to 30 while ( attachpoints-- ) { ARMOR = ARMOR + [0]; // create 30 empty armor slots - avoids SL stack depth error and LSLINT warning ARMORPOWER = ARMORPOWER + [FALSE]; // create 30 empty power armor flags - avoid SL stack depth and LSLINT warning } llSetTimerEvent(0.0); // stop any running timer } //============================================================================ // RESET - shut down running animations then reset the script to reload character sheet //============================================================================ RESET() { llResetScript(); // now reset } //============================================================================ // DEBUG - show errors on debug channel with wearer name for sorting //============================================================================ DEBUG(string dmessage) { if ( FLAG_DEBUG == TRUE ) llSay(DEBUG_CHANNEL,"("+llKey2Name(PLAYERID)+") MOD ARMOR: "+dmessage); } //============================================================================ // ERROR - show errors on debug channel with wearer name for sorting //============================================================================ ERROR(string emessage) { llSay(DEBUG_CHANNEL,"ERROR ("+llKey2Name(PLAYERID)+"): "+emessage); } //============================================================================ // GETVERSION //============================================================================ GETVERSION() { SENDTOHUD("VERSION="+VERSION+DIV+"VERSIONDATE="+VERDATE+DIV+llGetObjectName()); } //============================================================================ // SENDTOHUD - send reponses to HUD as Link Messages //============================================================================ SENDTOHUD(string str) { DEBUG("SENDTOHUD("+str+")"); llMessageLinked(LINK_THIS,LM_SENDTOATTACHMENT,str,PLAYERID); } //============================================================================ // WEARARMOR - Wearing a piece of armor //============================================================================ WEARARMOR(integer waattachpoint,integer waamount,integer wapower,string waname) { DEBUG("ATTACH Attachpoint=["+(string)waattachpoint+"] Amount=["+(string)waamount+"] Power=["+(string)wapower+"] Name=["+waname+"]"); if ( waattachpoint < MINATTACH || waattachpoint > MAXWEAR ) { // valid attach point? ERROR("Invalid armor attachment point "+llList2String(ATTACHPOINTS,waattachpoint)); return; } if ( waamount < MINARMOR || waamount > MAXARMOR ) { // is armor rating valid or legal? ERROR("Invalid armor amount "+(string)waamount+" out of range "+(string)MINARMOR+"-"+(string)MAXARMOR); return; } if ( wapower != TRUE && wapower != FALSE ) { ERROR("Cannot determine if worn armor is power armor."); return; } // FIXME move ARMOR and POWERARMOR into single list? ARMORPOWER = llListReplaceList(ARMORPOWER,[wapower],waattachpoint,waattachpoint); // insert armor value into armor list // FIXME move ARMOR to 3-element strided list? [attachpoint,value,name?] ARMOR = llListReplaceList(ARMOR,[waamount],waattachpoint,waattachpoint); // insert armor value into armor list llOwnerSay("Armor "+waname+" ("+(string)waamount+") attached to "+llList2String(ATTACHPOINTS,waattachpoint)); RECALCULATE_ARMOR(); // find new highest armor value } //============================================================================ // REMOVEARMOR - Removing a piece of armor //============================================================================ REMOVEARMOR(integer raattachpoint,integer raamount,integer rapower,string raname) { DEBUG("DETACH Attachpoint=["+(string)raattachpoint+"] Amount=["+(string)raamount+"] Power=["+(string)rapower+"] Name=["+raname+"]"); if ( raattachpoint < MINATTACH || raattachpoint > MAXWEAR ) { // valid attach point? ERROR("Invalid armor detachment point "+llList2String(ATTACHPOINTS,raattachpoint)); return; } if ( raamount < MINARMOR || raamount > MAXARMOR ) { // is armor rating valid or legal? ERROR("Invalid armor amount "+(string)raamount+" out of range "+(string)MINARMOR+"-"+(string)MAXARMOR); return; } if ( rapower != TRUE && rapower != FALSE ) { ERROR("Cannot determine if detached armor is power armor."); return; } // FIXME move ARMOR and POWERARMOR into single list? ARMORPOWER = llListReplaceList(ARMORPOWER,[FALSE],raattachpoint,raattachpoint); // insert armor value into armor list // FIXME move ARMOR to 3-element strided list? [attachpoint,value,name?] ARMOR = llListReplaceList(ARMOR,[0],raattachpoint,raattachpoint); // zero out the armor value in armor list llOwnerSay("Armor "+raname+" ("+(string)raamount+") detached from "+llList2String(ATTACHPOINTS,raattachpoint)); RECALCULATE_ARMOR(); // find new highest armor value } //============================================================================ // RECALCULATE_ARMOR - sets CURARMOR to highest armor value worn after attach or detach //============================================================================ RECALCULATE_ARMOR() { CURARMOR = 0; // start with zero armor POWERARMOR = FALSE; integer racount = llGetListLength(ARMOR); // how long is armor list? while (racount--) { // look at each list item from last to first integer rapoints = llList2Integer(ARMOR,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 > CURARMOR ) { // is this armor value higher than current max? CURARMOR = rapoints; // yes, save new highest amount } } else { // this is power armor in this slot. POWERARMOR = TRUE; if ( ARMOR_ON == TRUE && BATTERY > 0 && rapoints > CURARMOR ) { CURARMOR = rapoints; // yes armor is on, has power, and current value is higher, save new highest amount } } } if ( POWERARMOR == TRUE ) { llOwnerSay("Power Armor Rating is "+(string)CURARMOR); } else { llOwnerSay("Non-Power Armor Rating is "+(string)CURARMOR); } SENDTOHUD("ARMORCURRENT|"+(string)CURARMOR); // FIXME tell world too? } //============================================================================ // ARMOR ON //============================================================================ ARMORON() { //llWhisper(CHANATTACH,"ARMORON"); // tell attachment to do some inworld special effect if needed if ( BATTERY <= 0 && POWERARMOR == TRUE ) { llOwnerSay("Power armor out of power. Recharge."); return; } if ( POWERARMOR == TRUE ) { llOwnerSay("Power armor activating."); ARMOR_ON = TRUE; SENDTOHUD("ARMORON"); llSetTimerEvent(1.0); // run a battery drain timer, battery already checked > 0 } RECALCULATE_ARMOR(); } //============================================================================ // ARMOROFF //============================================================================ ARMOROFF() { //llWhisper(CHANATTACH,"ARMOROFF"); // tell attachments to do some inworld special effects if needed if ( POWERARMOR == TRUE ) { llOwnerSay("Power armor deactivated."); ARMOR_ON = FALSE; SENDTOHUD("ARMOROFF"); llSetTimerEvent(0.0); // stop battery drain timer - FIXME does this kill effect timers? return; } RECALCULATE_ARMOR(); } //============================================================================ // CHECKBATTERY //============================================================================ CHECKBATTERY() { //llWhisper(CHANATTACH,"ARMORBATTERY"); if ( POWERARMOR != TRUE ) { llOwnerSay("Cannot check battery level for non-powered armor."); return; } llOwnerSay("Armor battery level: "+(string)BATTERY+" of "+(string)MAXBATTERY+" total."); SENDTOHUD("ARMORBATTERY"); } //============================================================================ // RECHARGE //============================================================================ RECHARGE() { //llWhisper(CHANATTACH,"ARMORRECHARGE"); if ( POWERARMOR != TRUE ) { llOwnerSay("Cannot recharge non-powered armor."); return; } // TODO Partial Recharges? BATTERY = MAXBATTERY; llOwnerSay("Armor recharged."); SENDTOHUD("ARMORRECHARGE"); } //============================================================================ // EFFECTHIT() - SHOW SPECIAL ARMOR EFFECTS WHEN ARMOR HIT BUT FAILS TO BLOCK //============================================================================ EFFECTHIT() { //llWhisper(CHANATTACH,"ARMOREFFECTHIT"); SENDTOHUD("ARMOREFFECTHIT"); EFFECTTIME = MAXEFFECTTIME; // load the countdown llSetTimerEvent(1.0); // start the effect timer } //============================================================================ // EFFECTBLOCKED - CHANGE ARMOR EFFECT WHEN ARMOR HIT AND BLOCKS DAMAGE //============================================================================ EFFECTBLOCKED() { // your commands go here for armor special effect when armor BLOCKS a hit // llWhisper(CHANATTACH,"ARMOREFFECTBLOCKED"); SENDTOHUD("ARMOREFFECTBLOCKED"); EFFECTTIME = MAXEFFECTTIME; // load the countdown llSetTimerEvent(1.0); // start the effect timer } //============================================================================ // EFFECTOFF - RESET ARMOR TO NORMAL VIEW //============================================================================ EFFECTOFF() { //llWhisper(CHANATTACH,"ARMOREFFECTOFF"); SENDTOHUD("ARMOREFFECTOFF"); } //============================================================================ // COMMAND processor //============================================================================ COMMAND(string message) { list fields = llParseString2List(message,[DIV],[]); // break into list of fields based on DIVider string command = llToLower(llStringTrim(llList2String(fields,0),STRING_TRIM)); // assume the first field is a Myriad Lite command // General Myriad Module Commnads if ( command == "reset" ) { RESET(); return;} // reset when told if ( command == "version" ) { GETVERSION(); return;} // get version when needed if ( command == "debugon" ) { FLAG_DEBUG = TRUE; return;} // enable debugging if ( command == "debugoff" ) { FLAG_DEBUG = FALSE; return;} // disable debugging // Armor-Specific Module Commands 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 WEARARMOR(attachpoint,armorrating,armorpower,armorname); // add armor to set of armor worn return; } 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 REMOVEARMOR(attachpoint,armorrating,armorpower,armorname); // detach armor from set of armor worn return; } // armorcurrent skipped intentionally if ( command == "armorreset" ) { RESET(); return;} // reset HUD if ( command == "armoron" ) { ARMORON(); return;} // turn on power armor if ( command == "armoroff" ) { ARMOROFF(); return;} // turn off power armor if ( command == "armorbattery") { CHECKBATTERY(); return;} // check power armor battery if ( command == "armorrecharge" ) { RECHARGE(); return;} // recharge power armor battery if ( command == "armorcheck" ) { RECALCULATE_ARMOR(); return; } // check our current armor value if ( command == "armoreffecthit" ) { EFFECTHIT(); return;} // show SFX on hit if ( command == "armoreffectblocked" ) { EFFECTBLOCKED(); return;} // show SFX on hit if ( command == "armoreffectoff" ) { EFFECTOFF(); return;} // show SFX on hit } //============================================================================ // DEFAULT STATE //============================================================================ default { //------------------------------------------------------------------------ // STATE_ENTRY - the script starts here //------------------------------------------------------------------------ state_entry() { SETUP(); // setup defaults and go into event wait } //------------------------------------------------------------------------ // ON REZ - RESET to force through state entry //------------------------------------------------------------------------ on_rez(integer params) { params = 0; // LSLINT RESET(); } //------------------------------------------------------------------------ // ON ATTACH - RESET to force through state entry //------------------------------------------------------------------------ attach(key id) { id = NULL_KEY; // LSLINT RESET(); } //------------------------------------------------------------------------ // CHANGED - triggered for many changes to the avatar // TODO reload sim-specific settings on region change //------------------------------------------------------------------------ changed(integer changes) { if ( changes & CHANGED_INVENTORY ) { // inventory changed somehow? RESET(); } if ( changes & CHANGED_REGION || changes & CHANGED_TELEPORT ) { RESET(); } } //------------------------------------------------------------------------ // INCOMING LINK MESSSAGES //------------------------------------------------------------------------ link_message(integer sender_num,integer sending_module,string str,key id) { if ( sending_module == MODULE_ARMOR || sending_module == LM_SENDTOATTACHMENT ) return; // ignore our own messages DEBUG("link_message str=["+str+"]"); sender_num = 0; // LSLINT id = NULL_KEY; // LSLINT if ( llGetSubString(llStringTrim(llToLower(str),STRING_TRIM),0,4) == "armor" ) { // if armor command COMMAND(str); // jump to command processor return; // return here too in case we add later commands } } //------------------------------------------------------------------------ // TIMER CALLED TO TURN OFF THE SPECIAL EFFECTS AND DRAIN BATTERIES //------------------------------------------------------------------------ timer() { if ( EFFECTTIME > 0 ) { EFFECTTIME--; if ( EFFECTTIME == 0 ) { EFFECTOFF(); // turn off special effects } // timer expired, turn off effect } if ( EFFECTTIME < 0 ) { // we should never have this happen, but just in case, catch and cleanup. EFFECTTIME = 0; EFFECTOFF(); } if ( POWERARMOR == TRUE && ARMOR_ON == TRUE && BATTERY > 0 ) { BATTERY--; // remove some battery if ( BATTERY == 0 ) { llOwnerSay("Armor battery drained. Shutting down."); ARMOROFF(); // turn off armor } } if ( BATTERY < 0 ) { // we should never have this happen, but just in case, catch and cleanup BATTERY = 0; ARMOROFF(); } if ( EFFECTTIME <= 0 && ARMOR_ON == FALSE ) llSetTimerEvent(0.0); // all timers done, stop timer events } // end timer }