Source: Game_BattlerBase.js

Game_BattlerBase.js

//-----------------------------------------------------------------------------
// Game_BattlerBase
//
// The superclass of Game_Battler. It mainly contains parameters calculation.
/**
 * The superclass of Game_Battler. It mainly contains parameters calculation.
 *
 * @class
 * @property {number} hp - Battler hp
 * @property {number} mp - Battler mp
 * @property {number} tp - Battler tp
 * @property {number} mhp - Battler max hp
 * @property {number} mmp - Battler max mp
 * @property {number} atk - Battler attack
 * @property {number} def - Battler defense
 * @property {number} mat - Battler magic attack
 * @property {number} mdf - Battler magic defense
 * @property {number} agi - Battler agility
 * @property {number} luk - Battler luck
 * @property {number} hit - Battler hit rate
 * @property {number} eva - Battler evasion rate
 * @property {number} cri - Battler critical rate
 * @property {number} cev - Battler critical evasion rate
 * @property {number} mev - Battler magical evation rate
 * @property {number} mrf - Battler magical reflection rate
 * @property {number} cnt - Battler counter rate
 * @property {number} hrg - Battler hp regen rate
 * @property {number} mrg - Battler mp regen rate
 * @property {number} trg - Battler tp regen rate
 * @property {number} tgr - Battler target rate
 * @property {number} grd - Battler guard effect rate
 * @property {number} rec - Battler recovery rate
 * @property {number} pha - Battler pharmacology rate
 * @property {number} mcr - Battler mp cost rate
 * @property {number} tcr - Battler tp charge rate
 * @property {number} pdr - Battler physical damage rate
 * @property {number} mdr - Battler magic damage rate
 * @property {number} fdr - Battler floor damage rate
 * @property {number} exr - Battler exp rate
 */
function Game_BattlerBase() {
    this.initialize(...arguments);
}

/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ELEMENT_RATE = 11;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_DEBUFF_RATE = 12;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_STATE_RATE = 13;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_STATE_RESIST = 14;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_PARAM = 21;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_XPARAM = 22;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_SPARAM = 23;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ATTACK_ELEMENT = 31;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ATTACK_STATE = 32;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ATTACK_SPEED = 33;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ATTACK_TIMES = 34;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ATTACK_SKILL = 35;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_STYPE_ADD = 41;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_STYPE_SEAL = 42;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_SKILL_ADD = 43;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_SKILL_SEAL = 44;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_EQUIP_WTYPE = 51;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_EQUIP_ATYPE = 52;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_EQUIP_LOCK = 53;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_EQUIP_SEAL = 54;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_SLOT_TYPE = 55;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_ACTION_PLUS = 61;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_SPECIAL_FLAG = 62;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_COLLAPSE_TYPE = 63;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.TRAIT_PARTY_ABILITY = 64;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.FLAG_ID_AUTO_BATTLE = 0;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.FLAG_ID_GUARD = 1;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.FLAG_ID_SUBSTITUTE = 2;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.FLAG_ID_PRESERVE_TP = 3;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.ICON_BUFF_START = 32;
/** @constant
    @type {number}
    @default
*/
Game_BattlerBase.ICON_DEBUFF_START = 48;

Object.defineProperties(Game_BattlerBase.prototype, {
    // Hit Points
    hp: {
        get: function() {
            return this._hp;
        },
        configurable: true
    },
    // Magic Points
    mp: {
        get: function() {
            return this._mp;
        },
        configurable: true
    },
    // Tactical Points
    tp: {
        get: function() {
            return this._tp;
        },
        configurable: true
    },
    // Maximum Hit Points
    mhp: {
        get: function() {
            return this.param(0);
        },
        configurable: true
    },
    // Maximum Magic Points
    mmp: {
        get: function() {
            return this.param(1);
        },
        configurable: true
    },
    // ATtacK power
    atk: {
        get: function() {
            return this.param(2);
        },
        configurable: true
    },
    // DEFense power
    def: {
        get: function() {
            return this.param(3);
        },
        configurable: true
    },
    // Magic ATtack power
    mat: {
        get: function() {
            return this.param(4);
        },
        configurable: true
    },
    // Magic DeFense power
    mdf: {
        get: function() {
            return this.param(5);
        },
        configurable: true
    },
    // AGIlity
    agi: {
        get: function() {
            return this.param(6);
        },
        configurable: true
    },
    // LUcK
    luk: {
        get: function() {
            return this.param(7);
        },
        configurable: true
    },
    // HIT rate
    hit: {
        get: function() {
            return this.xparam(0);
        },
        configurable: true
    },
    // EVAsion rate
    eva: {
        get: function() {
            return this.xparam(1);
        },
        configurable: true
    },
    // CRItical rate
    cri: {
        get: function() {
            return this.xparam(2);
        },
        configurable: true
    },
    // Critical EVasion rate
    cev: {
        get: function() {
            return this.xparam(3);
        },
        configurable: true
    },
    // Magic EVasion rate
    mev: {
        get: function() {
            return this.xparam(4);
        },
        configurable: true
    },
    // Magic ReFlection rate
    mrf: {
        get: function() {
            return this.xparam(5);
        },
        configurable: true
    },
    // CouNTer attack rate
    cnt: {
        get: function() {
            return this.xparam(6);
        },
        configurable: true
    },
    // Hp ReGeneration rate
    hrg: {
        get: function() {
            return this.xparam(7);
        },
        configurable: true
    },
    // Mp ReGeneration rate
    mrg: {
        get: function() {
            return this.xparam(8);
        },
        configurable: true
    },
    // Tp ReGeneration rate
    trg: {
        get: function() {
            return this.xparam(9);
        },
        configurable: true
    },
    // TarGet Rate
    tgr: {
        get: function() {
            return this.sparam(0);
        },
        configurable: true
    },
    // GuaRD effect rate
    grd: {
        get: function() {
            return this.sparam(1);
        },
        configurable: true
    },
    // RECovery effect rate
    rec: {
        get: function() {
            return this.sparam(2);
        },
        configurable: true
    },
    // PHArmacology
    pha: {
        get: function() {
            return this.sparam(3);
        },
        configurable: true
    },
    // Mp Cost Rate
    mcr: {
        get: function() {
            return this.sparam(4);
        },
        configurable: true
    },
    // Tp Charge Rate
    tcr: {
        get: function() {
            return this.sparam(5);
        },
        configurable: true
    },
    // Physical Damage Rate
    pdr: {
        get: function() {
            return this.sparam(6);
        },
        configurable: true
    },
    // Magic Damage Rate
    mdr: {
        get: function() {
            return this.sparam(7);
        },
        configurable: true
    },
    // Floor Damage Rate
    fdr: {
        get: function() {
            return this.sparam(8);
        },
        configurable: true
    },
    // EXperience Rate
    exr: {
        get: function() {
            return this.sparam(9);
        },
        configurable: true
    }
});

/**
 * Initializes the class
 */
Game_BattlerBase.prototype.initialize = function() {
    this.initMembers();
};

/**
 * Initialize class variables
 */
Game_BattlerBase.prototype.initMembers = function() {
    this._hp = 1;
    this._mp = 0;
    this._tp = 0;
    this._hidden = false;
    this.clearParamPlus();
    this.clearStates();
    this.clearBuffs();
};

/**
 * Clears param bonus effects
 */
Game_BattlerBase.prototype.clearParamPlus = function() {
    this._paramPlus = [0, 0, 0, 0, 0, 0, 0, 0];
};

/**
 * Clears states affecting the battler
 */
Game_BattlerBase.prototype.clearStates = function() {
    this._states = [];
    this._stateTurns = {};
};

/**
 * Erases a state by id
 *
 * @param {number} stateId - The id of the state to erase
 */
Game_BattlerBase.prototype.eraseState = function(stateId) {
    this._states.remove(stateId);
    delete this._stateTurns[stateId];
};

/**
 * Check if the battler is affected by a state by id
 *
 * @param {number} stateId - The id of the state to check
 * @return {boolean} True if the battler is affected by the state
 */
Game_BattlerBase.prototype.isStateAffected = function(stateId) {
    return this._states.includes(stateId);
};

/**
 * Check if the battler is affected by the death state
 *
 * @return {boolean} True if the battler is affected by the state
 */
Game_BattlerBase.prototype.isDeathStateAffected = function() {
    return this.isStateAffected(this.deathStateId());
};

/**
 * Get the state id for the death state
 *
 * @return {number} The id of the death state
 */
Game_BattlerBase.prototype.deathStateId = function() {
    return 1;
};

/**
 * Resets a state's turn counter by id
 *
 * @param {number} stateId - The id of the state to reset
 */
Game_BattlerBase.prototype.resetStateCounts = function(stateId) {
    const state = $dataStates[stateId];
    const variance = 1 + Math.max(state.maxTurns - state.minTurns, 0);
    this._stateTurns[stateId] = state.minTurns + Math.randomInt(variance);
};

/**
 * Check if a state is expired
 *
 * @param {number} stateId - The id of the state to check
 * @return {boolean} True if the state is expired
 */
Game_BattlerBase.prototype.isStateExpired = function(stateId) {
    return this._stateTurns[stateId] === 0;
};

/**
 * Update state turns
 */
Game_BattlerBase.prototype.updateStateTurns = function() {
    for (const stateId of this._states) {
        if (this._stateTurns[stateId] > 0) {
            this._stateTurns[stateId]--;
        }
    }
};

/**
 * Clear buffs
 */
Game_BattlerBase.prototype.clearBuffs = function() {
    this._buffs = [0, 0, 0, 0, 0, 0, 0, 0];
    this._buffTurns = [0, 0, 0, 0, 0, 0, 0, 0];
};

/**
 * Erase a buff by param id
 *
 * @param {number} paramId - The id of the param to erase buffs for
 */
Game_BattlerBase.prototype.eraseBuff = function(paramId) {
    this._buffs[paramId] = 0;
    this._buffTurns[paramId] = 0;
};

/**
 * Get the amount of possible params to buff
 *
 * @return {number} Amount of buffs possible
 */
Game_BattlerBase.prototype.buffLength = function() {
    return this._buffs.length;
};

/**
 * Get a buff for a parameter by id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The buff that parameter has
 */
Game_BattlerBase.prototype.buff = function(paramId) {
    return this._buffs[paramId];
};

/**
 * Check if there is a buff for a parameter by id
 *
 * @param {number} paramId - The id of the param to check
 * @return {boolean} True if that parameter has a buff
 */
Game_BattlerBase.prototype.isBuffAffected = function(paramId) {
    return this._buffs[paramId] > 0;
};

/**
 * Check if there is a debuff for a parameter by id
 *
 * @param {number} paramId - The id of the param to check
 * @return {boolean} True if that parameter has a debuff
 */
Game_BattlerBase.prototype.isDebuffAffected = function(paramId) {
    return this._buffs[paramId] < 0;
};

/**
 * Check if there is a buff or debuff for a parameter by id
 *
 * @param {number} paramId - The id of the param to check
 * @return {boolean} True if that parameter has a buff or debuff
 */
Game_BattlerBase.prototype.isBuffOrDebuffAffected = function(paramId) {
    return this._buffs[paramId] !== 0;
};

/**
 * Check if the maximum buff is on the parameter
 *
 * @param {number} paramId - The id of the param to check
 * @return {boolean} True if that parameter has a maximum buff
 */
Game_BattlerBase.prototype.isMaxBuffAffected = function(paramId) {
    return this._buffs[paramId] === 2;
};

/**
 * Check if the maximum debuff is on the parameter
 *
 * @param {number} paramId - The id of the param to check
 * @return {boolean} True if that parameter has a maximum debuff
 */
Game_BattlerBase.prototype.isMaxDebuffAffected = function(paramId) {
    return this._buffs[paramId] === -2;
};

/**
 * Increase the buff for a parameter
 *
 * @param {number} paramId - The id of the param to buff
 */
Game_BattlerBase.prototype.increaseBuff = function(paramId) {
    if (!this.isMaxBuffAffected(paramId)) {
        this._buffs[paramId]++;
    }
};

/**
 * Decrease the buff for a parameter
 *
 * @param {number} paramId - The id of the param to debuff
 */
Game_BattlerBase.prototype.decreaseBuff = function(paramId) {
    if (!this.isMaxDebuffAffected(paramId)) {
        this._buffs[paramId]--;
    }
};

/**
 * Overwrite a buff's turns remaining
 *
 * @param {number} paramId - The id of the param to overwrite buff turns for
 * @param {number} turns - The new amount of turns the buff will last for
 */
Game_BattlerBase.prototype.overwriteBuffTurns = function(paramId, turns) {
    if (this._buffTurns[paramId] < turns) {
        this._buffTurns[paramId] = turns;
    }
};

/**
 * Check if buff is expired by id
 *
 * @param {number} paramId - The id of the param to check for expired buff
 * @return {boolean} True if the buff is expired
 */
Game_BattlerBase.prototype.isBuffExpired = function(paramId) {
    return this._buffTurns[paramId] === 0;
};

/**
 * Update buff turn counts
 */
Game_BattlerBase.prototype.updateBuffTurns = function() {
    for (let i = 0; i < this._buffTurns.length; i++) {
        if (this._buffTurns[i] > 0) {
            this._buffTurns[i]--;
        }
    }
};

/**
 * Kills the battler
 */
Game_BattlerBase.prototype.die = function() {
    this._hp = 0;
    this.clearStates();
    this.clearBuffs();
};

/**
 * Revives the battler
 */
Game_BattlerBase.prototype.revive = function() {
    if (this._hp === 0) {
        this._hp = 1;
    }
};

/**
 * Get states affecting the battler
 *
 * @return {Array} Array of state data objects
 */
Game_BattlerBase.prototype.states = function() {
    return this._states.map(id => $dataStates[id]);
};

/**
 * Get state icons for states affecting the battler
 *
 * @return {Array} Array of state icon indexes
 */
Game_BattlerBase.prototype.stateIcons = function() {
    return this.states()
        .map(state => state.iconIndex)
        .filter(iconIndex => iconIndex > 0);
};

/**
 * Get buff icons for buffs the battler has
 *
 * @return {Array} Array of buff icon indexes
 */
Game_BattlerBase.prototype.buffIcons = function() {
    const icons = [];
    for (let i = 0; i < this._buffs.length; i++) {
        if (this._buffs[i] !== 0) {
            icons.push(this.buffIconIndex(this._buffs[i], i));
        }
    }
    return icons;
};

/**
 * Get a buff icon a specific buff
 *
 * @param {number} buffLevel - The buff level of the parameter
 * @param {number} paramId - The id of the parameter
 * @return {number} The buff icon index
 */
Game_BattlerBase.prototype.buffIconIndex = function(buffLevel, paramId) {
    if (buffLevel > 0) {
        return Game_BattlerBase.ICON_BUFF_START + (buffLevel - 1) * 8 + paramId;
    } else if (buffLevel < 0) {
        return (
            Game_BattlerBase.ICON_DEBUFF_START + (-buffLevel - 1) * 8 + paramId
        );
    } else {
        return 0;
    }
};

/**
 * Get state and buff icons
 *
 * @return {Array} Array of state and buff icon indexes
 */
Game_BattlerBase.prototype.allIcons = function() {
    return this.stateIcons().concat(this.buffIcons());
};

/**
 * Get an array of all objects that have traits
 *
 * @return {Array} Array of all objects that have traits
 */
Game_BattlerBase.prototype.traitObjects = function() {
    // Returns an array of the all objects having traits. States only here.
    return this.states();
};

/**
 * Get an array of all traits from all trait objects
 *
 * @return {Array} Array of all traits
 */
Game_BattlerBase.prototype.allTraits = function() {
    return this.traitObjects().reduce((r, obj) => r.concat(obj.traits), []);
};

/**
 * Get an array of all traits from all trait objects that match the given code
 *
 * @param {number} code - The trait code to check for
 * @return {Array} Array of traits with given code
 */
Game_BattlerBase.prototype.traits = function(code) {
    return this.allTraits().filter(trait => trait.code === code);
};

/**
 * Get an array of all traits from all trait objects that match the given code and id
 *
 * @param {number} code - The trait code to check for
 * @param {number} id - The trait data id to check for
 * @return {Array} Array of traits with given code
 */
Game_BattlerBase.prototype.traitsWithId = function(code, id) {
    return this.allTraits().filter(
        trait => trait.code === code && trait.dataId === id
    );
};

/**
 * Get multiplicative value of all traits with given code and id
 *
 * @param {number} code - The trait code
 * @param {number} id - The trait data id
 * @return {number} Value of the traits
 */
Game_BattlerBase.prototype.traitsPi = function(code, id) {
    return this.traitsWithId(code, id).reduce((r, trait) => r * trait.value, 1);
};

/**
 * Get additive value of all traits with given code and id
 *
 * @param {number} code - The trait code
 * @param {number} id - The trait data id
 * @return {number} Value of the traits
 */
Game_BattlerBase.prototype.traitsSum = function(code, id) {
    return this.traitsWithId(code, id).reduce((r, trait) => r + trait.value, 0);
};

/**
 * Get additive value of all traits with given code
 *
 * @param {number} code - The trait code
 * @return {number} Value of the traits
 */
Game_BattlerBase.prototype.traitsSumAll = function(code) {
    return this.traits(code).reduce((r, trait) => r + trait.value, 0);
};

/**
 * Get array all trait data ids with given code
 *
 * @param {number} code - The trait code
 * @return {Array} Trait data ids
 */
Game_BattlerBase.prototype.traitsSet = function(code) {
    return this.traits(code).reduce((r, trait) => r.concat(trait.dataId), []);
};

/**
 * Get the base param.
 *
 * @return {number} The base param
 */
Game_BattlerBase.prototype.paramBase = function(/*paramId*/) {
    return 0;
};

/**
 * Get the parameter bonus by id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The parameter bonus
 */
Game_BattlerBase.prototype.paramPlus = function(paramId) {
    return this._paramPlus[paramId];
};

/**
 * Get the parameter base + plus by id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The parameter base added to parameter plus
 */
Game_BattlerBase.prototype.paramBasePlus = function(paramId) {
    return Math.max(0, this.paramBase(paramId) + this.paramPlus(paramId));
};

/**
 * Get the minimum a parameter can be
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The minimum valid value for this parameter
 */
Game_BattlerBase.prototype.paramMin = function(paramId) {
    if (paramId === 0) {
        return 1; // MHP
    } else {
        return 0;
    }
};

/**
 * Get the maximum a parameter can be
 *
 * @return {number} The maximum valid value for this parameter
 */
Game_BattlerBase.prototype.paramMax = function(/*paramId*/) {
    return Infinity;
};

/**
 * Get the parameter rate by id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The parameter rate
 */
Game_BattlerBase.prototype.paramRate = function(paramId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_PARAM, paramId);
};

/**
 * Get the parameter buff rate by id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The parameter buff rate
 */
Game_BattlerBase.prototype.paramBuffRate = function(paramId) {
    return this._buffs[paramId] * 0.25 + 1.0;
};

/**
 * Get the final parameter value id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The parameter value
 */
Game_BattlerBase.prototype.param = function(paramId) {
    const value =
        this.paramBasePlus(paramId) *
        this.paramRate(paramId) *
        this.paramBuffRate(paramId);
    const maxValue = this.paramMax(paramId);
    const minValue = this.paramMin(paramId);
    return Math.round(value.clamp(minValue, maxValue));
};

/**
 * Get the x-parameter value by id
 *
 * @param {number} xparamId - The id of the parameter
 * @return {number} The parameter value
 */
Game_BattlerBase.prototype.xparam = function(xparamId) {
    return this.traitsSum(Game_BattlerBase.TRAIT_XPARAM, xparamId);
};

/**
 * Get the s-parameter value by id
 *
 * @param {number} sparamId - The id of the parameter
 * @return {number} The parameter value
 */
Game_BattlerBase.prototype.sparam = function(sparamId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_SPARAM, sparamId);
};

/**
 * Get the element rate by id
 *
 * @param {number} elementId - The id of the element
 * @return {number} The element rate
 */
Game_BattlerBase.prototype.elementRate = function(elementId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_ELEMENT_RATE, elementId);
};

/**
 * Get the debuff rate by id
 *
 * @param {number} paramId - The id of the parameter
 * @return {number} The debuff rate
 */
Game_BattlerBase.prototype.debuffRate = function(paramId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_DEBUFF_RATE, paramId);
};

/**
 * Get the state rate by id
 *
 * @param {number} stateId - The id of the state
 * @return {number} The state rate
 */
Game_BattlerBase.prototype.stateRate = function(stateId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_STATE_RATE, stateId);
};

/**
 * Get the state resist trait set
 *
 * @return {Array} Array of state resist trait data ids
 */
Game_BattlerBase.prototype.stateResistSet = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_STATE_RESIST);
};

/**
 * Check if a state is resisted
 *
 * @param {number} stateId - The id of the state to check
 * @return {boolean} True if resisted
 */
Game_BattlerBase.prototype.isStateResist = function(stateId) {
    return this.stateResistSet().includes(stateId);
};

/**
 * Get the attack elements trait set
 *
 * @return {Array} Array of attack element trait data ids
 */
Game_BattlerBase.prototype.attackElements = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_ELEMENT);
};

/**
 * Get the attack state trait set
 *
 * @return {Array} Array of attack state trait data ids
 */
Game_BattlerBase.prototype.attackStates = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_STATE);
};

/**
 * Get the attack state rate for a given state id
 *
 * @param {number} stateId - The state id
 * @return {number} The state rate
 */
Game_BattlerBase.prototype.attackStatesRate = function(stateId) {
    return this.traitsSum(Game_BattlerBase.TRAIT_ATTACK_STATE, stateId);
};

/**
 * Get the attack speed
 *
 * @return {number} The attack speed
 */
Game_BattlerBase.prototype.attackSpeed = function() {
    return this.traitsSumAll(Game_BattlerBase.TRAIT_ATTACK_SPEED);
};

/**
 * Get the attack times
 *
 * @return {number} The attack times
 */
Game_BattlerBase.prototype.attackTimesAdd = function() {
    return Math.max(this.traitsSumAll(Game_BattlerBase.TRAIT_ATTACK_TIMES), 0);
};

/**
 * Get the attack skill id
 *
 * @return {number} The attack skill id
 */
Game_BattlerBase.prototype.attackSkillId = function() {
    const set = this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_SKILL);
    return set.length > 0 ? Math.max(...set) : 1;
};

/**
 * Get the added skill types
 *
 * @return {Array} The added skill types
 */
Game_BattlerBase.prototype.addedSkillTypes = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_STYPE_ADD);
};

/**
 * Check if a skill type is sealed
 *
 * @param {number} stypeId - The skill type to check
 * @return {boolean} True if sealed
 */
Game_BattlerBase.prototype.isSkillTypeSealed = function(stypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_STYPE_SEAL).includes(stypeId);
};

/**
 * Get the added skills
 *
 * @return {Array} The added skills
 */
Game_BattlerBase.prototype.addedSkills = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_SKILL_ADD);
};

/**
 * Check if a skill is sealed
 *
 * @param {number} skillId - The skill to check
 * @return {boolean} True if sealed
 */
Game_BattlerBase.prototype.isSkillSealed = function(skillId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_SKILL_SEAL).includes(skillId);
};

/**
 * Check if a weapon type is ok to equip
 *
 * @param {number} wtypeId - The weapon type to check
 * @return {boolean} True if ok to equip
 */
Game_BattlerBase.prototype.isEquipWtypeOk = function(wtypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_WTYPE).includes(wtypeId);
};

/**
 * Check if an armor type is ok to equip
 *
 * @param {number} atypeId - The armor type to check
 * @return {boolean} True if ok to equip
 */
Game_BattlerBase.prototype.isEquipAtypeOk = function(atypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_ATYPE).includes(atypeId);
};

/**
 * Check if an equip type is locked
 *
 * @param {number} etypeId - The equip type to check
 * @return {boolean} True if locked
 */
Game_BattlerBase.prototype.isEquipTypeLocked = function(etypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_LOCK).includes(etypeId);
};

/**
 * Check if an equip type is sealed
 *
 * @param {number} etypeId - The equip type to check
 * @return {boolean} True if sealed
 */
Game_BattlerBase.prototype.isEquipTypeSealed = function(etypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_SEAL).includes(etypeId);
};

/**
 * Get the slot type
 *
 * @return {number} The slot type
 */
Game_BattlerBase.prototype.slotType = function() {
    const set = this.traitsSet(Game_BattlerBase.TRAIT_SLOT_TYPE);
    return set.length > 0 ? Math.max(...set) : 0;
};

/**
 * Check if the battler is dual wield type
 *
 * @return {boolean} True if dual wield
 */
Game_BattlerBase.prototype.isDualWield = function() {
    return this.slotType() === 1;
};

/**
 * Get action plus traits set
 *
 * @return {Array} Trait values for action plus
 */
Game_BattlerBase.prototype.actionPlusSet = function() {
    return this.traits(Game_BattlerBase.TRAIT_ACTION_PLUS).map(
        trait => trait.value
    );
};

/**
 * Check if there are traits with a special flag id
 *
 * @param {number} flagId - The flag id to check
 * @return {boolean} True if traits exist for the flag id
 */
Game_BattlerBase.prototype.specialFlag = function(flagId) {
    return this.traits(Game_BattlerBase.TRAIT_SPECIAL_FLAG).some(
        trait => trait.dataId === flagId
    );
};

/**
 * Get collapse type
 *
 * @return {number} The collapse type
 */
Game_BattlerBase.prototype.collapseType = function() {
    const set = this.traitsSet(Game_BattlerBase.TRAIT_COLLAPSE_TYPE);
    return set.length > 0 ? Math.max(...set) : 0;
};

/**
 * Check if there are traits with a party ability id
 *
 * @param {number} abilityId - The ability id to check
 * @return {boolean} True if traits exist for the ability id
 */
Game_BattlerBase.prototype.partyAbility = function(abilityId) {
    return this.traits(Game_BattlerBase.TRAIT_PARTY_ABILITY).some(
        trait => trait.dataId === abilityId
    );
};

/**
 * Check if the battler has the auto battle special flag
 *
 * @return {boolean} True if auto battle
 */
Game_BattlerBase.prototype.isAutoBattle = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_AUTO_BATTLE);
};

/**
 * Check if the battler has the guard special flag
 *
 * @return {boolean} True if guard
 */
Game_BattlerBase.prototype.isGuard = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_GUARD) && this.canMove();
};

/**
 * Check if the battler has the substitute special flag
 *
 * @return {boolean} True if substitute
 */
Game_BattlerBase.prototype.isSubstitute = function() {
    return (
        this.specialFlag(Game_BattlerBase.FLAG_ID_SUBSTITUTE) && this.canMove()
    );
};

/**
 * Check if the battler has the preserve tp special flag
 *
 * @return {boolean} True if preserve tp
 */
Game_BattlerBase.prototype.isPreserveTp = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_PRESERVE_TP);
};

/**
 * Adds a bonus to a parameter by id
 *
 * @param {number} paramId - The parameter id to add to
 * @param {number} value - The amount to add
 */
Game_BattlerBase.prototype.addParam = function(paramId, value) {
    this._paramPlus[paramId] += value;
    this.refresh();
};

/**
 * Sets the battler's hp to the given value
 *
 * @param {number} hp - The new hp value
 */
Game_BattlerBase.prototype.setHp = function(hp) {
    this._hp = hp;
    this.refresh();
};

/**
 * Sets the battler's mp to the given value
 *
 * @param {number} mp - The new mp value
 */
Game_BattlerBase.prototype.setMp = function(mp) {
    this._mp = mp;
    this.refresh();
};

/**
 * Sets the battler's tp to the given value
 *
 * @param {number} tp - The new tp value
 */
Game_BattlerBase.prototype.setTp = function(tp) {
    this._tp = tp;
    this.refresh();
};

/**
 * Get the max tp the battler can have
 *
 * @return {number} Maximum tp value
 */
Game_BattlerBase.prototype.maxTp = function() {
    return 100;
};

/**
 * Refresh the battler
 */
Game_BattlerBase.prototype.refresh = function() {
    for (const stateId of this.stateResistSet()) {
        this.eraseState(stateId);
    }
    this._hp = this._hp.clamp(0, this.mhp);
    this._mp = this._mp.clamp(0, this.mmp);
    this._tp = this._tp.clamp(0, this.maxTp());
};

/**
 * Recover all for the battler
 */
Game_BattlerBase.prototype.recoverAll = function() {
    this.clearStates();
    this._hp = this.mhp;
    this._mp = this.mmp;
};

/**
 * Get the battler's hp rate (hp / max hp)
 *
 * @return {number} The hp rate
 */
Game_BattlerBase.prototype.hpRate = function() {
    return this.hp / this.mhp;
};

/**
 * Get the battler's mp rate (mp / max mp)
 *
 * @return {number} The mp rate
 */
Game_BattlerBase.prototype.mpRate = function() {
    return this.mmp > 0 ? this.mp / this.mmp : 0;
};

/**
 * Get the battler's tp rate (tp / max tp)
 *
 * @return {number} The tp rate
 */
Game_BattlerBase.prototype.tpRate = function() {
    return this.tp / this.maxTp();
};

/**
 * Hides the battler
 */
Game_BattlerBase.prototype.hide = function() {
    this._hidden = true;
};

/**
 * Shows the battler
 */
Game_BattlerBase.prototype.appear = function() {
    this._hidden = false;
};

/**
 * Check if the battler is hidden
 *
 * @return {boolean} True if hidden
 */
Game_BattlerBase.prototype.isHidden = function() {
    return this._hidden;
};

/**
 * Check if the battler is appeared (not hidden)
 *
 * @return {boolean} True if appeared
 */
Game_BattlerBase.prototype.isAppeared = function() {
    return !this.isHidden();
};

/**
 * Check if the battler is dead
 *
 * @return {boolean} True if dead
 */
Game_BattlerBase.prototype.isDead = function() {
    return this.isAppeared() && this.isDeathStateAffected();
};

/**
 * Check if the battler is alive
 *
 * @return {boolean} True if alive
 */
Game_BattlerBase.prototype.isAlive = function() {
    return this.isAppeared() && !this.isDeathStateAffected();
};

/**
 * Check if the battler is low on hp
 *
 * @return {boolean} True if low on hp
 */
Game_BattlerBase.prototype.isDying = function() {
    return this.isAlive() && this._hp < this.mhp / 4;
};

/**
 * Check if the battler is restricted
 *
 * @return {boolean} True if restricted
 */
Game_BattlerBase.prototype.isRestricted = function() {
    return this.isAppeared() && this.restriction() > 0;
};

/**
 * Check if the battler can input
 *
 * @return {boolean} True if can input
 */
Game_BattlerBase.prototype.canInput = function() {
    // prettier-ignore
    return this.isAppeared() && this.isActor() &&
            !this.isRestricted() && !this.isAutoBattle();
};

/**
 * Check if the battler can move
 *
 * @return {boolean} True if can move
 */
Game_BattlerBase.prototype.canMove = function() {
    return this.isAppeared() && this.restriction() < 4;
};

/**
 * Check if the battler is confused
 *
 * @return {boolean} True if confused
 */
Game_BattlerBase.prototype.isConfused = function() {
    return (
        this.isAppeared() && this.restriction() >= 1 && this.restriction() <= 3
    );
};

/**
 * Determine the confusion level of the battler
 *
 * @return {number} Confusion level
 */
Game_BattlerBase.prototype.confusionLevel = function() {
    return this.isConfused() ? this.restriction() : 0;
};

/**
 * Check if the battler is an actor type
 *
 * @return {boolean} True if actor
 */
Game_BattlerBase.prototype.isActor = function() {
    return false;
};

/**
 * Check if the battler is an enemy type
 *
 * @return {boolean} True if enemy
 */
Game_BattlerBase.prototype.isEnemy = function() {
    return false;
};

/**
 * Sort the states affecting the battler by their priority
 */
Game_BattlerBase.prototype.sortStates = function() {
    this._states.sort((a, b) => {
        const p1 = $dataStates[a].priority;
        const p2 = $dataStates[b].priority;
        if (p1 !== p2) {
            return p2 - p1;
        }
        return a - b;
    });
};

/**
 * Get the highest restriction on the battler
 *
 * @return {number} The greatest restriction on the battler
 */
Game_BattlerBase.prototype.restriction = function() {
    const restrictions = this.states().map(state => state.restriction);
    return Math.max(0, ...restrictions);
};

/**
 * Adds a new state to the battler by id
 *
 * @param {number} stateId - The state id to add
 */
Game_BattlerBase.prototype.addNewState = function(stateId) {
    if (stateId === this.deathStateId()) {
        this.die();
    }
    const restricted = this.isRestricted();
    this._states.push(stateId);
    this.sortStates();
    if (!restricted && this.isRestricted()) {
        this.onRestrict();
    }
};

/**
 * Processing when a restriction is added
 */
Game_BattlerBase.prototype.onRestrict = function() {
    //
};

/**
 * Get the most important state's text (persists message)
 *
 * @return {string} The most important state's persist message
 */
Game_BattlerBase.prototype.mostImportantStateText = function() {
    for (const state of this.states()) {
        if (state.message3) {
            return state.message3;
        }
    }
    return "";
};

/**
 * Get the state motion index
 *
 * @return {number} The state motion index
 */
Game_BattlerBase.prototype.stateMotionIndex = function() {
    const states = this.states();
    if (states.length > 0) {
        return states[0].motion;
    } else {
        return 0;
    }
};

/**
 * Get the state overlay index
 *
 * @return {number} The state overlay index
 */
Game_BattlerBase.prototype.stateOverlayIndex = function() {
    const states = this.states();
    if (states.length > 0) {
        return states[0].overlay;
    } else {
        return 0;
    }
};

/**
 * Check if skill Wtype is ok
 *
 * @return {boolean} True if skill wtype is ok
 */
Game_BattlerBase.prototype.isSkillWtypeOk = function(/*skill*/) {
    return true;
};

/**
 * Get the skill mp cost
 *
 * @param {Object} skill - The skill object
 * @return {number} Skill mp cost
 */
Game_BattlerBase.prototype.skillMpCost = function(skill) {
    return Math.floor(skill.mpCost * this.mcr);
};

/**
 * Get the skill tp cost
 *
 * @param {Object} skill - The skill object
 * @return {number} Skill tp cost
 */
Game_BattlerBase.prototype.skillTpCost = function(skill) {
    return skill.tpCost;
};

/**
 * Check if skill costs are payable
 *
 * @param {Object} skill - The skill object
 * @return {boolean} True if costs can be paid
 */
Game_BattlerBase.prototype.canPaySkillCost = function(skill) {
    return (
        this._tp >= this.skillTpCost(skill) &&
        this._mp >= this.skillMpCost(skill)
    );
};

/**
 * Pay the skill costs
 *
 * @param {Object} skill - The skill object
 */
Game_BattlerBase.prototype.paySkillCost = function(skill) {
    this._mp -= this.skillMpCost(skill);
    this._tp -= this.skillTpCost(skill);
};

/**
 * Check if an item's occasion is met
 *
 * @param {Object} item - The item object
 * @return {boolean} True if the occasion is met
 */
Game_BattlerBase.prototype.isOccasionOk = function(item) {
    if ($gameParty.inBattle()) {
        return item.occasion === 0 || item.occasion === 1;
    } else {
        return item.occasion === 0 || item.occasion === 2;
    }
};

/**
 * Check if an item's usable conditions are met
 *
 * @param {Object} item - The item object
 * @return {boolean} True if the conditions are met
 */
Game_BattlerBase.prototype.meetsUsableItemConditions = function(item) {
    return this.canMove() && this.isOccasionOk(item);
};

/**
 * Check if a skill's conditions are met
 *
 * @param {Object} skill - The skill object
 * @return {boolean} True if the conditions are met
 */
Game_BattlerBase.prototype.meetsSkillConditions = function(skill) {
    return (
        this.meetsUsableItemConditions(skill) &&
        this.isSkillWtypeOk(skill) &&
        this.canPaySkillCost(skill) &&
        !this.isSkillSealed(skill.id) &&
        !this.isSkillTypeSealed(skill.stypeId)
    );
};

/**
 * Check if an item's conditions are met
 *
 * @param {Object} item - The item object
 * @return {boolean} True if the conditions are met
 */
Game_BattlerBase.prototype.meetsItemConditions = function(item) {
    return this.meetsUsableItemConditions(item) && $gameParty.hasItem(item);
};

/**
 * Check if an item or skill can be used
 *
 * @param {Object} item - The item/skill object
 * @return {boolean} True if the item/skill can be used
 */
Game_BattlerBase.prototype.canUse = function(item) {
    if (!item) {
        return false;
    } else if (DataManager.isSkill(item)) {
        return this.meetsSkillConditions(item);
    } else if (DataManager.isItem(item)) {
        return this.meetsItemConditions(item);
    } else {
        return false;
    }
};

/**
 * Check if an item can be equipped
 *
 * @param {Object} item - The weapon/armor object
 * @return {boolean} True if the weapon/armor can be equipped
 */
Game_BattlerBase.prototype.canEquip = function(item) {
    if (!item) {
        return false;
    } else if (DataManager.isWeapon(item)) {
        return this.canEquipWeapon(item);
    } else if (DataManager.isArmor(item)) {
        return this.canEquipArmor(item);
    } else {
        return false;
    }
};

/**
 * Check if a weapon can be equipped
 *
 * @param {Object} item - The weapon object
 * @return {boolean} True if the weapon can be equipped
 */
Game_BattlerBase.prototype.canEquipWeapon = function(item) {
    return (
        this.isEquipWtypeOk(item.wtypeId) &&
        !this.isEquipTypeSealed(item.etypeId)
    );
};

/**
 * Check if an armor can be equipped
 *
 * @param {Object} item - The armor object
 * @return {boolean} True if the armor can be equipped
 */
Game_BattlerBase.prototype.canEquipArmor = function(item) {
    return (
        this.isEquipAtypeOk(item.atypeId) &&
        !this.isEquipTypeSealed(item.etypeId)
    );
};

/**
 * Get the guard skill's id
 *
 * @return {number} The guard skill's id
 */
Game_BattlerBase.prototype.guardSkillId = function() {
    return 2;
};

/**
 * Check if the battler can attack
 *
 * @return {boolean} True if the battler can attack
 */
Game_BattlerBase.prototype.canAttack = function() {
    return this.canUse($dataSkills[this.attackSkillId()]);
};

/**
 * Check if the battler can guard
 *
 * @return {boolean} True if the battler can guard
 */
Game_BattlerBase.prototype.canGuard = function() {
    return this.canUse($dataSkills[this.guardSkillId()]);
};