User:Allen Kerensky/Myriad Lite/Myriad Lite Module Armor-Preview6.lsl

From OpenSimulator

Jump to: navigation, search

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
}
Personal tools
General
About This Wiki