Source: Game_Battler.js

Game_Battler.js

//-----------------------------------------------------------------------------
// Game_Battler
//
// The superclass of Game_Actor and Game_Enemy. It contains methods for sprites
// and actions.
/**
 * The superclass of Game_Actor and Game_Enemy. It contains methods for sprites and actions.
 *
 * @class
 * @extends Game_BattlerBase
 */
function Game_Battler() {
    this.initialize(...arguments);
}

Game_Battler.prototype = Object.create(Game_BattlerBase.prototype);
Game_Battler.prototype.constructor = Game_Battler;

Game_Battler.prototype.initialize = function() {
    Game_BattlerBase.prototype.initialize.call(this);
};

Game_Battler.prototype.initMembers = function() {
    Game_BattlerBase.prototype.initMembers.call(this);
    this._actions = [];
    this._speed = 0;
    this._result = new Game_ActionResult();
    this._actionState = "";
    this._lastTargetIndex = 0;
    this._damagePopup = false;
    this._effectType = null;
    this._motionType = null;
    this._weaponImageId = 0;
    this._motionRefresh = false;
    this._selected = false;
    this._tpbState = "";
    this._tpbChargeTime = 0;
    this._tpbCastTime = 0;
    this._tpbIdleTime = 0;
    this._tpbTurnCount = 0;
    this._tpbTurnEnd = false;
};

/**
 * Clears the damage popup
 */
Game_Battler.prototype.clearDamagePopup = function() {
    this._damagePopup = false;
};

/**
 * Clears the weapon animation
 */
Game_Battler.prototype.clearWeaponAnimation = function() {
    this._weaponImageId = 0;
};

/**
 * Clears an effect
 */
Game_Battler.prototype.clearEffect = function() {
    this._effectType = null;
};

/**
 * Clears a motion
 */
Game_Battler.prototype.clearMotion = function() {
    this._motionType = null;
    this._motionRefresh = false;
};

/**
 * Requests an effect
 *
 * @param {string} effectType - The type of effect to request
 */
Game_Battler.prototype.requestEffect = function(effectType) {
    this._effectType = effectType;
};

/**
 * Requests a motion
 *
 * @param {string} motionType - The type of motion to request
 */
Game_Battler.prototype.requestMotion = function(motionType) {
    this._motionType = motionType;
};

/**
 * Requests a motion refresh
 */
Game_Battler.prototype.requestMotionRefresh = function() {
    this._motionRefresh = true;
};

/**
 * Cancels a motion refresh
 * @since Version 1.1.0
 */
Game_Battler.prototype.cancelMotionRefresh = function() {
    this._motionRefresh = false;
};

/**
 * Marks the battler as selected
 */
Game_Battler.prototype.select = function() {
    this._selected = true;
};

/**
 * Marks the battler as not selected
 */
Game_Battler.prototype.deselect = function() {
    this._selected = false;
};

/**
 * Check if a damage popup is requested
 *
 * @return {boolean} True if a damage popup has been requested
 */
Game_Battler.prototype.isDamagePopupRequested = function() {
    return this._damagePopup;
};

/**
 * Check if an effect is requested
 *
 * @return {boolean} True if an effect has been requested
 */
Game_Battler.prototype.isEffectRequested = function() {
    return !!this._effectType;
};

/**
 * Check if a motion is requested
 *
 * @return {boolean} True if a motion has been requested
 */
Game_Battler.prototype.isMotionRequested = function() {
    return !!this._motionType;
};

/**
 * Check if a weapon animation is requested
 *
 * @return {boolean} True if a weapon animation has been requested
 */
Game_Battler.prototype.isWeaponAnimationRequested = function() {
    return this._weaponImageId > 0;
};

/**
 * Check if a motion refresh is requested
 *
 * @return {boolean} True if a motion refresh has been requested
 */
Game_Battler.prototype.isMotionRefreshRequested = function() {
    return this._motionRefresh;
};

/**
 * Check if this is selected
 *
 * @return {boolean} True if selected
 */
Game_Battler.prototype.isSelected = function() {
    return this._selected;
};

/**
 * Get the effect type
 *
 * @return {string} The effect type
 */
Game_Battler.prototype.effectType = function() {
    return this._effectType;
};

/**
 * Get the motion type
 *
 * @return {string} The motion type
 */
Game_Battler.prototype.motionType = function() {
    return this._motionType;
};

/**
 * Get the weapon image id
 *
 * @return {number} The weapon image id
 */
Game_Battler.prototype.weaponImageId = function() {
    return this._weaponImageId;
};

/**
 * Starts the damage popup
 */
Game_Battler.prototype.startDamagePopup = function() {
    this._damagePopup = true;
};

/**
 * Check if a damage popup should appear
 *
 * @return {boolean} True if should popup damage
 */
Game_Battler.prototype.shouldPopupDamage = function() {
    const result = this._result;
    return (
        result.missed ||
        result.evaded ||
        result.hpAffected ||
        result.mpDamage !== 0
    );
};

/**
 * Starts a weapon animation of type id
 *
 * @param {number} weaponImageId - The weapon image id
 */
Game_Battler.prototype.startWeaponAnimation = function(weaponImageId) {
    this._weaponImageId = weaponImageId;
};

/**
 * Get the action at the given index
 *
 * @param {number} index - The index to get the action from
 * @return {Game_Action} The action
 */
Game_Battler.prototype.action = function(index) {
    return this._actions[index];
};

/**
 * Set an action at the given index
 *
 * @param {number} index - The index to set the action of
 * @param {Game_Action} action - The action to set
 */
Game_Battler.prototype.setAction = function(index, action) {
    this._actions[index] = action;
};

/**
 * Get the amount of actions the battler has
 *
 * @return {number} Amount of actions
 */
Game_Battler.prototype.numActions = function() {
    return this._actions.length;
};

/**
 * Clears the battler's actions
 */
Game_Battler.prototype.clearActions = function() {
    this._actions = [];
};

/**
 * Get the result of an action
 *
 * @return {Game_ActionResult} The action result
 */
Game_Battler.prototype.result = function() {
    return this._result;
};

/**
 * Clears the result of an action
 */
Game_Battler.prototype.clearResult = function() {
    this._result.clear();
};

/**
 * Clears TPB charge time
 */
Game_Battler.prototype.clearTpbChargeTime = function() {
    this._tpbState = "charging";
    this._tpbChargeTime = 0;
};

/**
 * Applies a TPB penalty
 */
Game_Battler.prototype.applyTpbPenalty = function() {
    this._tpbState = "charging";
    this._tpbChargeTime -= 1;
};

/**
 * Initialize the TPB charge time
 *
 * @param {boolean} advantageous - If charge time should be advantageous
 */
Game_Battler.prototype.initTpbChargeTime = function(advantageous) {
    const speed = this.tpbRelativeSpeed();
    this._tpbState = "charging";
    this._tpbChargeTime = advantageous ? 1 : speed * Math.random() * 0.5;
    if (this.isRestricted()) {
        this._tpbChargeTime = 0;
    }
};

/**
 * Get the TPB charge time
 *
 * @return {number} The TPB charge time
 */
Game_Battler.prototype.tpbChargeTime = function() {
    return this._tpbChargeTime;
};

/**
 * Starts TPB casting
 */
Game_Battler.prototype.startTpbCasting = function() {
    this._tpbState = "casting";
    this._tpbCastTime = 0;
};

/**
 * Starts a TPB action
 */
Game_Battler.prototype.startTpbAction = function() {
    this._tpbState = "acting";
};

/**
 * Check if TPB is in the charged state
 *
 * @return {boolean} True if charged
 */
Game_Battler.prototype.isTpbCharged = function() {
    return this._tpbState === "charged";
};

/**
 * Check if TPB is in the ready state
 *
 * @return {boolean} True if ready
 */
Game_Battler.prototype.isTpbReady = function() {
    return this._tpbState === "ready";
};

/**
 * Check if TPB is timed out
 *
 * @return {boolean} True if timed out
 */
Game_Battler.prototype.isTpbTimeout = function() {
    return this._tpbIdleTime >= 1;
};

/**
 * Update for TPB
 */
Game_Battler.prototype.updateTpb = function() {
    if (this.canMove()) {
        this.updateTpbChargeTime();
        this.updateTpbCastTime();
        this.updateTpbAutoBattle();
    }
    if (this.isAlive()) {
        this.updateTpbIdleTime();
    }
};

/**
 * Update TPB charge time
 */
Game_Battler.prototype.updateTpbChargeTime = function() {
    if (this._tpbState === "charging") {
        this._tpbChargeTime += this.tpbAcceleration();
        if (this._tpbChargeTime >= 1) {
            this._tpbChargeTime = 1;
            this.onTpbCharged();
        }
    }
};

/**
 * Update TPB cast time
 */
Game_Battler.prototype.updateTpbCastTime = function() {
    if (this._tpbState === "casting") {
        this._tpbCastTime += this.tpbAcceleration();
        if (this._tpbCastTime >= this.tpbRequiredCastTime()) {
            this._tpbCastTime = this.tpbRequiredCastTime();
            this._tpbState = "ready";
        }
    }
};

/**
 * Update TPB auto battle
 */
Game_Battler.prototype.updateTpbAutoBattle = function() {
    if (this.isTpbCharged() && !this.isTpbTurnEnd() && this.isAutoBattle()) {
        this.makeTpbActions();
    }
};

/**
 * Update TPB idle time
 */
Game_Battler.prototype.updateTpbIdleTime = function() {
    if (!this.canMove() || this.isTpbCharged()) {
        this._tpbIdleTime += this.tpbAcceleration();
    }
};

/**
 * Get the acceleration of the TPB
 *
 * @return {number} TPB acceleration
 */
Game_Battler.prototype.tpbAcceleration = function() {
    const speed = this.tpbRelativeSpeed();
    const referenceTime = $gameParty.tpbReferenceTime();
    return speed / referenceTime;
};

/**
 * Get the relative speed of the TPB
 *
 * @return {number} TPB relative speed
 */
Game_Battler.prototype.tpbRelativeSpeed = function() {
    return this.tpbSpeed() / $gameParty.tpbBaseSpeed();
};

/**
 * Get the speed of the TPB
 *
 * @return {number} TPB speed
 */
Game_Battler.prototype.tpbSpeed = function() {
    return Math.sqrt(this.agi) + 1;
};

/**
 * Get the base speed of the TPB
 *
 * @return {number} TPB base speed
 */
Game_Battler.prototype.tpbBaseSpeed = function() {
    const baseAgility = this.paramBasePlus(6);
    return Math.sqrt(baseAgility) + 1;
};

/**
 * Get the cast time of the TPB
 *
 * @return {number} TPB cast time
 */
Game_Battler.prototype.tpbRequiredCastTime = function() {
    const actions = this._actions.filter(action => action.isValid());
    const items = actions.map(action => action.item());
    const delay = items.reduce((r, item) => r + Math.max(0, -item.speed), 0);
    return Math.sqrt(delay) / this.tpbSpeed();
};

/**
 * Processing when TPB is charged
 */
Game_Battler.prototype.onTpbCharged = function() {
    if (!this.shouldDelayTpbCharge()) {
        this.finishTpbCharge();
    }
};

/**
 * Check if charging should be delayed
 *
 * @return {boolean} True if delay is needed
 */
Game_Battler.prototype.shouldDelayTpbCharge = function() {
    return !BattleManager.isActiveTpb() && $gameParty.canInput();
};

/**
 * Finishes the TPB charge
 */
Game_Battler.prototype.finishTpbCharge = function() {
    this._tpbState = "charged";
    this._tpbTurnEnd = true;
    this._tpbIdleTime = 0;
};

/**
 * Check for turn end in TPB
 *
 * @return {boolean} True if turn ended
 */
Game_Battler.prototype.isTpbTurnEnd = function() {
    return this._tpbTurnEnd;
};

/**
 * Initialize TPB turn
 */
Game_Battler.prototype.initTpbTurn = function() {
    this._tpbTurnEnd = false;
    this._tpbTurnCount = 0;
    this._tpbIdleTime = 0;
};

/**
 * Starts TPB turn
 */
Game_Battler.prototype.startTpbTurn = function() {
    this._tpbTurnEnd = false;
    this._tpbTurnCount++;
    this._tpbIdleTime = 0;
    if (this.numActions() === 0) {
        this.makeTpbActions();
    }
};

/**
 * Makes the TPB actions
 */
Game_Battler.prototype.makeTpbActions = function() {
    this.makeActions();
    if (this.canInput()) {
        this.setActionState("undecided");
    } else {
        this.startTpbCasting();
        this.setActionState("waiting");
    }
};

/**
 * Processing for when TPB is timed out
 */
Game_Battler.prototype.onTpbTimeout = function() {
    this.onAllActionsEnd();
    this._tpbTurnEnd = true;
    this._tpbIdleTime = 0;
};

/**
 * Get the turn count
 *
 * @return {number} Turn count
 */
Game_Battler.prototype.turnCount = function() {
    if (BattleManager.isTpb()) {
        return this._tpbTurnCount;
    } else {
        return $gameTroop.turnCount() + 1;
    }
};

Game_Battler.prototype.canInput = function() {
    if (BattleManager.isTpb() && !this.isTpbCharged()) {
        return false;
    }
    return Game_BattlerBase.prototype.canInput.call(this);
};

Game_Battler.prototype.refresh = function() {
    Game_BattlerBase.prototype.refresh.call(this);
    if (this.hp === 0) {
        this.addState(this.deathStateId());
    } else {
        this.removeState(this.deathStateId());
    }
};

/**
 * Add a state to the battler by id
 *
 * @param {number} stateId - Id of state to be added
 */
Game_Battler.prototype.addState = function(stateId) {
    if (this.isStateAddable(stateId)) {
        if (!this.isStateAffected(stateId)) {
            this.addNewState(stateId);
            this.refresh();
        }
        this.resetStateCounts(stateId);
        this._result.pushAddedState(stateId);
    }
};

/**
 * Check if the state with the given id can be added to the battler
 *
 * @param {number} stateId - Id of state to check
 * @return {boolean} True if the state can be added
 */
Game_Battler.prototype.isStateAddable = function(stateId) {
    return (
        this.isAlive() &&
        $dataStates[stateId] &&
        !this.isStateResist(stateId) &&
        !this.isStateRestrict(stateId)
    );
};

/**
 * Check if the state with the given id is restricted
 *
 * @param {number} stateId - Id of state to check
 * @return {boolean} True if the state is restricted
 */
Game_Battler.prototype.isStateRestrict = function(stateId) {
    return $dataStates[stateId].removeByRestriction && this.isRestricted();
};

Game_Battler.prototype.onRestrict = function() {
    Game_BattlerBase.prototype.onRestrict.call(this);
    this.clearTpbChargeTime();
    this.clearActions();
    for (const state of this.states()) {
        if (state.removeByRestriction) {
            this.removeState(state.id);
        }
    }
};

/**
 * Remove a state to the battler by id
 *
 * @param {number} stateId - Id of state to be removed
 */
Game_Battler.prototype.removeState = function(stateId) {
    if (this.isStateAffected(stateId)) {
        if (stateId === this.deathStateId()) {
            this.revive();
        }
        this.eraseState(stateId);
        this.refresh();
        this._result.pushRemovedState(stateId);
    }
};

/**
 * Processing when there is an escape
 */
Game_Battler.prototype.escape = function() {
    if ($gameParty.inBattle()) {
        this.hide();
    }
    this.clearActions();
    this.clearStates();
    SoundManager.playEscape();
};

/**
 * Add a buff to the battler by id
 *
 * @param {number} paramId - Id of the param to buff
 * @param {number} turns - Amount of turns the buff lasts
 */
Game_Battler.prototype.addBuff = function(paramId, turns) {
    if (this.isAlive()) {
        this.increaseBuff(paramId);
        if (this.isBuffAffected(paramId)) {
            this.overwriteBuffTurns(paramId, turns);
        }
        this._result.pushAddedBuff(paramId);
        this.refresh();
    }
};

/**
 * Add a debuff to the battler by id
 *
 * @param {number} paramId - Id of the param to debuff
 * @param {number} turns - Amount of turns the debuff lasts
 */
Game_Battler.prototype.addDebuff = function(paramId, turns) {
    if (this.isAlive()) {
        this.decreaseBuff(paramId);
        if (this.isDebuffAffected(paramId)) {
            this.overwriteBuffTurns(paramId, turns);
        }
        this._result.pushAddedDebuff(paramId);
        this.refresh();
    }
};

/**
 * Remove a buff to the battler by id
 *
 * @param {number} paramId - Id of the param to remove buffs for
 */
Game_Battler.prototype.removeBuff = function(paramId) {
    if (this.isAlive() && this.isBuffOrDebuffAffected(paramId)) {
        this.eraseBuff(paramId);
        this._result.pushRemovedBuff(paramId);
        this.refresh();
    }
};

/**
 * Remove states that end after battle
 */
Game_Battler.prototype.removeBattleStates = function() {
    for (const state of this.states()) {
        if (state.removeAtBattleEnd) {
            this.removeState(state.id);
        }
    }
};

/**
 * Remove all buffs
 */
Game_Battler.prototype.removeAllBuffs = function() {
    for (let i = 0; i < this.buffLength(); i++) {
        this.removeBuff(i);
    }
};

/**
 * Remove states set to auto remove
 *
 * @param {number} timing - The timing to check against for auto removal
 */
Game_Battler.prototype.removeStatesAuto = function(timing) {
    for (const state of this.states()) {
        if (
            this.isStateExpired(state.id) &&
            state.autoRemovalTiming === timing
        ) {
            this.removeState(state.id);
        }
    }
};

/**
 * Remove buffs when they expire
 */
Game_Battler.prototype.removeBuffsAuto = function() {
    for (let i = 0; i < this.buffLength(); i++) {
        if (this.isBuffExpired(i)) {
            this.removeBuff(i);
        }
    }
};

/**
 * Remove states that are removed by damage
 */
Game_Battler.prototype.removeStatesByDamage = function() {
    for (const state of this.states()) {
        if (
            state.removeByDamage &&
            Math.randomInt(100) < state.chanceByDamage
        ) {
            this.removeState(state.id);
        }
    }
};


/**
 * Make the action times
 *
 * @return {number} The action times
 */
Game_Battler.prototype.makeActionTimes = function() {
    const actionPlusSet = this.actionPlusSet();
    return actionPlusSet.reduce((r, p) => (Math.random() < p ? r + 1 : r), 1);
};

/**
 * Make the battler's actions
 */
Game_Battler.prototype.makeActions = function() {
    this.clearActions();
    if (this.canMove()) {
        const actionTimes = this.makeActionTimes();
        this._actions = [];
        for (let i = 0; i < actionTimes; i++) {
            this._actions.push(new Game_Action(this));
        }
    }
};

/**
 * Get the battler's speed
 *
 * @return {number} The battler's speed
 */
Game_Battler.prototype.speed = function() {
    return this._speed;
};

/**
 * Make the battler's speed
 */
Game_Battler.prototype.makeSpeed = function() {
    this._speed = Math.min(...this._actions.map(action => action.speed())) || 0;
};

/**
 * Get the current action
 *
 * @return {Game_Action} The current action
 */
Game_Battler.prototype.currentAction = function() {
    return this._actions[0];
};

/**
 * Removes the current action
 */
Game_Battler.prototype.removeCurrentAction = function() {
    this._actions.shift();
};

/**
 * Set the last target
 *
 * @param {Game_Enemy|Game_Actor} target - The last target
 */
Game_Battler.prototype.setLastTarget = function(target) {
    this._lastTargetIndex = target ? target.index() : 0;
};

/**
 * Force an action
 *
 * @param {number} skillId - The skill id
 * @param {number} targetIndex - The target index
 */
Game_Battler.prototype.forceAction = function(skillId, targetIndex) {
    this.clearActions();
    const action = new Game_Action(this, true);
    action.setSkill(skillId);
    if (targetIndex === -2) {
        action.setTarget(this._lastTargetIndex);
    } else if (targetIndex === -1) {
        action.decideRandomTarget();
    } else {
        action.setTarget(targetIndex);
    }
    if (action.item()) {
        this._actions.push(action);
    }
};

/**
 * Use the given item
 *
 * @param {Object} item - The item/skill object to use
 */
Game_Battler.prototype.useItem = function(item) {
    if (DataManager.isSkill(item)) {
        this.paySkillCost(item);
    } else if (DataManager.isItem(item)) {
        this.consumeItem(item);
    }
};

/**
 * Consumes the given item
 *
 * @param {Object} item - The item object to consume
 */
Game_Battler.prototype.consumeItem = function(item) {
    $gameParty.consumeItem(item);
};

/**
 * Gains an amount of hp
 *
 * @param {number} value - The amount of hp to gain
 */
Game_Battler.prototype.gainHp = function(value) {
    this._result.hpDamage = -value;
    this._result.hpAffected = true;
    this.setHp(this.hp + value);
};

/**
 * Gains an amount of mp
 *
 * @param {number} value - The amount of mp to gain
 */
Game_Battler.prototype.gainMp = function(value) {
    this._result.mpDamage = -value;
    this.setMp(this.mp + value);
};

/**
 * Gains an amount of tp
 *
 * @param {number} value - The amount of tp to gain
 */
Game_Battler.prototype.gainTp = function(value) {
    this._result.tpDamage = -value;
    this.setTp(this.tp + value);
};

/**
 * Gains an amount of tp without adding it to the action result
 *
 * @param {number} value - The amount of tp to gain
 */
Game_Battler.prototype.gainSilentTp = function(value) {
    this.setTp(this.tp + value);
};

/**
 * Initialize tp
 */
Game_Battler.prototype.initTp = function() {
    this.setTp(Math.randomInt(25));
};

/**
 * Clears tp
 */
Game_Battler.prototype.clearTp = function() {
    this.setTp(0);
};

/**
 * Gains tp based on damage
 *
 * @param {number} damageRate - The damage rate to base tp gain off
 */
Game_Battler.prototype.chargeTpByDamage = function(damageRate) {
    const value = Math.floor(50 * damageRate * this.tcr);
    this.gainSilentTp(value);
};

/**
 * Regenerates hp
 */
Game_Battler.prototype.regenerateHp = function() {
    const minRecover = -this.maxSlipDamage();
    const value = Math.max(Math.floor(this.mhp * this.hrg), minRecover);
    if (value !== 0) {
        this.gainHp(value);
    }
};

/**
 * Get the maximum amount for slip damage
 *
 * @return {number} Maximum slip damage amount
 */
Game_Battler.prototype.maxSlipDamage = function() {
    return $dataSystem.optSlipDeath ? this.hp : Math.max(this.hp - 1, 0);
};

/**
 * Regenerates mp
 */
Game_Battler.prototype.regenerateMp = function() {
    const value = Math.floor(this.mmp * this.mrg);
    if (value !== 0) {
        this.gainMp(value);
    }
};

/**
 * Regenerates tp
 */
Game_Battler.prototype.regenerateTp = function() {
    const value = Math.floor(100 * this.trg);
    this.gainSilentTp(value);
};

/**
 * Regenerates everything (hp/mp/tp)
 */
Game_Battler.prototype.regenerateAll = function() {
    if (this.isAlive()) {
        this.regenerateHp();
        this.regenerateMp();
        this.regenerateTp();
    }
};

/**
 * Processing when a battle starts
 *
 * @param {boolean} advantageous - If the battle is advantageous
 */
Game_Battler.prototype.onBattleStart = function(advantageous) {
    this.setActionState("undecided");
    this.clearMotion();
    this.initTpbChargeTime(advantageous);
    this.initTpbTurn();
    if (!this.isPreserveTp()) {
        this.initTp();
    }
};

/**
 * Processing when all actions are over
 */
Game_Battler.prototype.onAllActionsEnd = function() {
    this.clearResult();
    this.removeStatesAuto(1);
    this.removeBuffsAuto();
};

/**
 * Processing when a turn ends
 */
Game_Battler.prototype.onTurnEnd = function() {
    this.clearResult();
    this.regenerateAll();
    this.updateStateTurns();
    this.updateBuffTurns();
    this.removeStatesAuto(2);
};

/**
 * Processing when a battle ends
 */
Game_Battler.prototype.onBattleEnd = function() {
    this.clearResult();
    this.removeBattleStates();
    this.removeAllBuffs();
    this.clearActions();
    if (!this.isPreserveTp()) {
        this.clearTp();
    }
    this.appear();
};

/**
 * Processing when damage occurs
 *
 * @param {number} value - Amount of damage taken
 */
Game_Battler.prototype.onDamage = function(value) {
    this.removeStatesByDamage();
    this.chargeTpByDamage(value / this.mhp);
};

/**
 * Set the action state
 *
 * @param {string} actionState - The new action state
 */
Game_Battler.prototype.setActionState = function(actionState) {
    this._actionState = actionState;
    this.requestMotionRefresh();
};

/**
 * Check if the action state is undecided
 *
 * @return {boolean} True if undecided
 */
Game_Battler.prototype.isUndecided = function() {
    return this._actionState === "undecided";
};

/**
 * Check if the action state is inputting
 *
 * @return {boolean} True if inputting
 */
Game_Battler.prototype.isInputting = function() {
    return this._actionState === "inputting";
};

/**
 * Check if the action state is waiting
 *
 * @return {boolean} True if waiting
 */
Game_Battler.prototype.isWaiting = function() {
    return this._actionState === "waiting";
};

/**
 * Check if the action state is acting
 *
 * @return {boolean} True if acting
 */
Game_Battler.prototype.isActing = function() {
    return this._actionState === "acting";
};

/**
 * Check if the battler is chanting
 *
 * @return {boolean} True if chanting
 */
Game_Battler.prototype.isChanting = function() {
    if (this.isWaiting()) {
        return this._actions.some(action => action.isMagicSkill());
    }
    return false;
};

/**
 * Check if the battler is guarding
 *
 * @return {boolean} True if guarding
 */
Game_Battler.prototype.isGuardWaiting = function() {
    if (this.isWaiting()) {
        return this._actions.some(action => action.isGuard());
    }
    return false;
};

/**
 * Start an action
 *
 * @param {Game_Action} action - The action to start
 */
Game_Battler.prototype.performActionStart = function(action) {
    if (!action.isGuard()) {
        this.setActionState("acting");
    }
};

/**
 * Perform an action. When called from Game_Battler, this does nothing.
 */
Game_Battler.prototype.performAction = function(/*action*/) {
    //
};

/**
 * Perform an action end. When called from Game_Battler, this does nothing.
 */
Game_Battler.prototype.performActionEnd = function() {
    //
};

/**
 * Perform a damage. When called from Game_Battler, this does nothing.
 */
Game_Battler.prototype.performDamage = function() {
    //
};

/**
 * Perform a miss
 */
Game_Battler.prototype.performMiss = function() {
    SoundManager.playMiss();
};

/**
 * Perform a recovery
 */
Game_Battler.prototype.performRecovery = function() {
    SoundManager.playRecovery();
};

/**
 * Perform an evasion
 */
Game_Battler.prototype.performEvasion = function() {
    SoundManager.playEvasion();
};

/**
 * Perform a magic evasion
 */
Game_Battler.prototype.performMagicEvasion = function() {
    SoundManager.playMagicEvasion();
};

/**
 * Perform a counter
 */
Game_Battler.prototype.performCounter = function() {
    SoundManager.playEvasion();
};

/**
 * Perform a reflection
 */
Game_Battler.prototype.performReflection = function() {
    SoundManager.playReflection();
};

/**
 * Perform a substitute. When called from Game_Battler, this does nothing.
 */
Game_Battler.prototype.performSubstitute = function(/*target*/) {
    //
};

/**
 * Perform a collapse. When called from Game_Battler, this does nothing.
 */
Game_Battler.prototype.performCollapse = function() {
    //
};