JUMP INTO JAVASCRIPT PART 10

In which we base some gamebattlers.

  • Trihan
  • 08/03/2020 12:02 AM
  • 4935 views
Hello sports fans! Welcome to the "it hasn't been 3 years yet, this isn't like Trihan at all!" edition of

Jump into Javascript

Now the moment you've (probably) all been waiting for, we've reached the Battler classes! This is where we start delving through the good stuff.

Game_BattlerBase
This class is the basis for all battlers, actors and enemies alike. Basically anything that can swing a sword or snap some teeth at something it wants to kill. The base class mainly sets up parameters and does parameter calculations. I'm not gonna bother with the constructor because it just calls initialize like a bunch of other classes we've already looked at.

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


Okay, so first up we set up a buttload of constants. They almost all relate to trait IDs and flags, which in turn relate to all the radio buttons you see in the "Traits" section of actor/class/weapon/armour/enemy setup. As with Game_Action before it, the numbers of the constants refer to the tab the trait is on, followed by the ID of the radio button on that tab. The flags correspond to the options under "Special Flag" in the "Other" tab. Then we have two interesting ones, ICON_BUFF_START and ICON_DEBUFF_START, which just contain the IDs of the icons the start buffs and debuffs (of which there are 16 each). If you open up your iconset and check ID 32, it's the "+MHP" buff icon, and 48 is the "-MHP" debuff icon. If you're using a custom iconset and buffs show up with unexpected icons, it's likely because this needs to be changed.

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 },
    // Magical 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 }
});


We're also setting up a number of defined object properties, which you'll note correspond to the different parameters a battler can have. The comments should explain what they all are without me having to dive into it, but one thing to note is that the "convenient" forms you're probably used to like "rec" are just wraparound properties for the appropriate param, xparam or sparam call. Param covers max HP to luck; xparam covers hit rate to TP regen rate; and sparam covers target rate to experience rate. The main difference between these three, and the reason they're separate, is how their values are calculated, which we'll see soon.

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


Pretty simple initialize function; all we're doing is calling the initMembers function.

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


Which is also pretty simple. We set instance variable _hp to 1, then _mp and _tp to 0. We set the _hidden flag to false (meaning it'll show up in battle). Then we call clearParamPlus, clearStates and clearBuffs.

Game_BattlerBase.prototype.clearParamPlus = function() {
    this._paramPlus = [0,0,0,0,0,0,0,0];
};


clearParamPlus just sets the instance variable_paramPlus to an 8-element array filled with 0s. These values correspond to the main parameters, and effectively when you add to a base parameter you just increment the appropriate index. For example, with +5 attack, _paramPlus would be [0, 0, 5, 0, 0, 0, 0, 0].

Game_BattlerBase.prototype.clearStates = function() {
    this._states = [];
    this._stateTurns = {};
};


clearStates sets the _states instance variable to an empty array, and _stateTurns to an empty hashmap. Internally, _states holds the ID number of any state the battler is afflicted/endowed with. _stateTurns is a hashmap where the key is the state ID, and the value is the number of turns left on the state. Sometimes people manipulate the _states array without doing anything to _stateTurns, which completely screws up the state processing, so don't do it. If you're doing something to one, you have to update the other.

Game_BattlerBase.prototype.eraseState = function(stateId) {
    var index = this._states.indexOf(stateId);
    if (index >= 0) {
        this._states.splice(index, 1);
    }
    delete this._stateTurns[stateId];
};


In the eraseState function, we take one parameter, stateId. First we set a var called index to the index of _states that matches stateId, then if index is greater than or equal to 0 (meaning there was a matching state in the array), we splice that index out of _states. After this, we delete the element of _stateTurns with an index of stateId.

Effectively, what this does is avoid the problem I stated above. It removes the provided state's ID from the _states array, and also gets rid of its corresponding entry in _stateTurns. Note that the delete doesn't have to be inside the if statement, because if there isn't a valid value there to delete, the line just won't do anything.

Game_BattlerBase.prototype.isStateAffected = function(stateId) {
    return this._states.contains(stateId);
};


isStateAffected is a function that determines whether the battler is affected by a given state, taking stateId as a parameter. We simply return whether the _states array contains the passed-in stateId.

In case you've forgotten how .contains works, let's say that currently our _states array is because the actor is poisoned and guarding, and we're checking for silence, which would be isStateAffected(6). 6 isn't in the array, so it would return false. However, if we were checking for poison it would be isStatedAffected(4) and 4 is in the array so it would return true.

Game_BattlerBase.prototype.isDeathStateAffected = function() {
    return this.isStateAffected(this.deathStateId());
};


Then we have the isDeathStateAffected function, which checks whether the battler has the state considered "death" or "Knockout" in the default database. We do so by calling the isStateAffected function and passing in the result of calling the deathStateId function:

Game_BattlerBase.prototype.deathStateId = function() {
    return 1;
};


In which we return 1. If you ever want to change which state is considered death, this is the place to do it.

One thing that came up in the rpgmakerweb forums the other day was implementing states like "petrify" where it's a movement restriction that never naturally expires, and obviously having an entire petrified party means you're no longer able to act. By default, the battle will just continue. If you want states like that to also result in a game over, you need to modify isDeathStateAffected to also check for those other IDs. Either that or modify deathStateId to return an array, and then in isDeathStateAffected iterate over the array. Either way would work.

Game_BattlerBase.prototype.resetStateCounts = function(stateId) {
    var state = $dataStates[stateId];
    var variance = 1 + Math.max(state.maxTurns - state.minTurns, 0);
    this._stateTurns[stateId] = state.minTurns + Math.randomInt(variance);
};


In this function, we reset the number of turns a given state will last, and again we take stateId as the single parameter.

First we set a variable called state to the element of $dataStates with an index of stateId. Then we set a variable called variance to 1 plus the maximum value between the state's maxTurns property minus the state's minTurns property, or 0. Then, we set the key of stateId in _stateTurns to be the state's minTurns property plus a random integer from 0 to variance. As with all the mathy stuff, let's demystify this with an example.

By default, the "Blind" state lasts 3-5 turns. This means variance will be 1 + Math.max(5 - 3, 0). 5 - 3 is 2, so .max will return 2 since it's higher than 0. (the reason it's done like this is just in case a developer does something like 8-5 turns, which isn't prevented in the editor; it just prevents state turns ending up being a negative number due to user error). This simplifies to 1 + 2, or 3.
So then _stateTurns is set to 3 + a random number from 0-2, resulting in a number between 3 and 5...which is what we set in the database. Maths can sometimes just be a convoluted way of doing something that looks simple in an input box. :P

Game_BattlerBase.prototype.isStateExpired = function(stateId) {
    return this._stateTurns[stateId] === 0;
};


In this function we check whether a given state has expired, taking stateId as a parameter. We simply return whether the stateId key of _stateTurns has a value of 0.

Game_BattlerBase.prototype.updateStateTurns = function() {
    this._states.forEach(function(stateId) {
        if (this._stateTurns[stateId] > 0) {
            this._stateTurns[stateId]--;
        }
    }, this);
};


This function updates the turn counts for each applicable state. We start a forEach loop on _states, passing stateId as the iteration variable. If the stateId key in _stateTurns is greater than 0 (in other words, that state has turns remaining), we decrement it by 1.

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];
};


This function clears the battler's buff list. As with _paramPlus, we're just setting _buffs to an 8-element array filled with 0s. We do the same with _buffTurns.

Game_BattlerBase.prototype.eraseBuff = function(paramId) {
    this._buffs[paramId] = 0;
    this._buffTurns[paramId] = 0;
};


This function erases a buff, taking paramId as a parameter. We simple set the paramId element of _buffs and _buffTurns to 0, which returns it to its initial value.

Game_BattlerBase.prototype.buffLength = function() {
    return this._buffs.length;
};


This function gets the length of the buffs array, and in it we literally just return the length of the _buffs array. This will almost invariably be 8.

The setTarget function takes one parameter, "targetIndex" (which is, as the name suggests, the index of the desired target) and simply sets the instance's _targetIndex property to the value passed to it.

Game_BattlerBase.prototype.buff = function(paramId) {
    return this._buffs[paramId];
};


buff is a convenience wrapper function which takes paramId as a parameter, and in it we return the element of _buffs at index paramId. This means you cal call buff(2) to get the atk buff, for example, instead of _buffs. They're functionally identical, but coding best practice prefers that we access instance variables externally using a function instead of referencing them directly.

Game_BattlerBase.prototype.isBuffAffected = function(paramId) {
    return this._buffs[paramId] > 0;
};


This function tells us whether the battler is affected by a buff for a given parameter, taking paramId as a parameter. We return the result of checking whether the element of _buffs with element paramId is greater than 0 (which means it has a positive buff applied)

Game_BattlerBase.prototype.isDebuffAffected = function(paramId) {
    return this._buffs[paramId] < 0;
};


This is just the same, but it's checking for less than 0, meaning the param is debuffed rather than buffed.

Game_BattlerBase.prototype.isBuffOrDebuffAffected = function(paramId) {
    return this._buffs[paramId] !== 0;
};


This function checks whether the battler has either a buff *or* a debuff, and again takes paramId as a parameter. This time, we return whether the element of _buffs with index paramId is not equal to 0, which means it's either greater (buff) or less than (debuff).

Game_BattlerBase.prototype.isMaxBuffAffected = function(paramId) {
    return this._buffs[paramId] === 2;
};


In this function, we check whether the battler has the maximum possible buff, taking paramId as the parameter. We return whether the element of _buffs at index paramId is equal to 2 (as you can only buff each parameter twice). If you wanted more levels of buff (and had the icons for it) this would be the place to edit it.

Game_BattlerBase.prototype.isMaxDebuffAffected = function(paramId) {
    return this._buffs[paramId] === -2;
};


And again, this is just the same thing but it checks for -2 because we want to know if the battler has the maximum debuff.

Game_BattlerBase.prototype.increaseBuff = function(paramId) {
    if (!this.isMaxBuffAffected(paramId)) {
        this._buffs[paramId]++;
    }
};


In this function, we increase the buff level for a given parameter, taking paramId as a parameter. If the battler does not have the maximum buff level for the parameter supplied, we add 1 to the _buffs array element at that index.

Game_BattlerBase.prototype.decreaseBuff = function(paramId) {
    if (!this.isMaxDebuffAffected(paramId)) {
        this._buffs[paramId]--;
    }
};


And this is just the opposite for decreasing the buff.

Note that because buffs and debuffs operate on the same sort of tug-of-war principle using the same array, increasing a level 1 debuff will just return the battler to normal, and vice versa with decreasing a level 1 buff.

Game_BattlerBase.prototype.overwriteBuffTurns = function(paramId, turns) {
    if (this._buffTurns[paramId] < turns) {
        this._buffTurns[paramId] = turns;
    }
};


In this function, we overwrite the number of turns remaining on a buff, taking paramId and turns as parameters. If the element of _buffTurns at index paramId is less than the value of the turns argument, we set it to that value. This prevents a longer buff from being overwritten by a shorter one.

Game_BattlerBase.prototype.isBuffExpired = function(paramId) {
    return this._buffTurns[paramId] === 0;
};


This is just the same as isStateExpired only for buffs instead of states. We return whether the element of _buffTurns at index paramId is equal to 0, or in other words that buff has no turns remaining.

Game_BattlerBase.prototype.updateBuffTurns = function() {
    for (var i = 0; i < this._buffTurns.length; i++) {
        if (this._buffTurns[i] > 0) {
            this._buffTurns[i]--;
        }
    }
};


And this one is the same as updateStateTurns. We start a for loop from 0 to the length of _buffTurns, then for the element of _buffTurns at index i if it's greater than 0 we reduce the value by 1.

Game_BattlerBase.prototype.die = function() {
    this._hp = 0;
    this.clearStates();
    this.clearBuffs();
};


The die function does exactly what it says on the tin. We set the _hp instance variable to 0, then call clearStates and clearBuffs. In the event that there are state or buffs you want to persist through death, this is the place to put your exceptions.

Game_BattlerBase.prototype.revive = function() {
    if (this._hp === 0) {
        this._hp = 1;
    }
};


The revive function is similarly straightforward. If the _hp variable is equal to 0, we set it to 1. This would be the function to edit if you wanted battlers to regain more than 1 HP when revived by default.

Game_BattlerBase.prototype.states = function() {
    return this._states.map(function(id) {
        return $dataStates[id];
    });
};


This function gets an array of state objects; we return a map of the _states array, returning the element of $dataStates with an index of the current ID.

Game_BattlerBase.prototype.stateIcons = function() {
    return this.states().map(function(state) {
        return state.iconIndex;
    }).filter(function(iconIndex) {
        return iconIndex > 0;
    });
};


This function gets an array of icon indexes for affected states; we return a map of the array returned by the states function, returning the state's iconIndex (the index of the icon chosen for it in the database), filtered to return if iconIndex is greater than 0. This excludes states that don't have an icon.

Game_BattlerBase.prototype.buffIcons = function() {
    var icons = [];
    for (var i = 0; i < this._buffs.length; i++) {
        if (this._buffs[i] !== 0) {
            icons.push(this.buffIconIndex(this._buffs[i], i));
        }
    }
    return icons;
};


This function gets the array of icon indexes for buffs. We start with an empty array called icons, then run a for loop from 0 to the length of _buffs. If the element of _buffs at index i is not 0, we push the result of calling buffIconIndex passing in that element and i. Following the loop, we return the icons array.

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;
    }
};


In the buffIconIndex function, which as we've just seen by the call to it takes buffLevel and paramId as parameters, we check whether buffLevel is greater than 0. If so, we return the value of the ICON_BUFF_START constant, plus buffLevel minus 1, multiplied by 8 plus the paramId.

Otherwise, if the buff level is less than 0, we return the value of the ICON_DEBUFF_START constant, plus the negative of buffLevel minus 1, multiplied by 8 plus the paramId.

Example time!

So let's say we're checking the icon index for the agi buff, and it's currently at +1. The return value becomes

ICON_BUFF_START + (1 - 1) * 8 + 6 = 32 + 0 * 8 + 6 = 38

And indeed, if you look at icon #38 it's the +1 agi icon.

Let's say we have a double max MP debuff:

ICON_DEBUFF_START + (2 - 1) * 8 + 1 = 48 + 1 * 8 + 1 = 57

Do why is it done like this? Well obviously we start with the icon ID the constant gives us. There are 8 different stats that can be buffed or debuffed, so if we multiply 1 less than the buff level by 8 we get the icon for the next level up of the set, and then adding paramId gives us the correct icon in that set.

Game_BattlerBase.prototype.allIcons = function() {
    return this.stateIcons().concat(this.buffIcons());
};


This function gets an array of all icons affecting the battler, both states and buffs. We return the result of calling stateIcons concatenated with the result of calling buffIcons. .concat is an array function that joins two arrays together.

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


This function gives us an array of all objects adding traits to the battler. In this one, we simply return the result of calling the states function. Later battler classes will add to this in their function overwrites.

Game_BattlerBase.prototype.allTraits = function() {
    return this.traitObjects().reduce(function(r, obj) {
        return r.concat(obj.traits);
    }, []);
};


This function gets all traits applicable to the battler. We return a reduce on the result of calling traitObjects, using "r" as the accumulator variable and "obj" as the current object variable, and return r concatenated with obj's traits property.

To better explain this, consider that right now traitObjects is returning the battler's states. So let's say the battler has Poison. The call to reduce will concatenate the poison state's traits (HP regen -10%) into the returned array.

Game_BattlerBase.prototype.traits = function(code) {
    return this.allTraits().filter(function(trait) {
        return trait.code === code;
    });
};


In the traits function, which takes one parameter, "code", we return a filter on the result of allTraits, using "trait" as the current object and returning true if the trait's code matches the value we passed to it. This will get all traits of a particular type. For example, if we did traits(21) that would give us an array of all traits on the battler which affect params.

Game_BattlerBase.prototype.traitsWithId = function(code, id) {
    return this.allTraits().filter(function(trait) {
        return trait.code === code && trait.dataId === id;
    });
};


This function is similar but takes an addition parameter, "id". We have an almost identical filter, but it adds an AND condition of the trait's dataId matching the id value passed in. For example, traitsWithId(21, 2) would give us an array of all traits on the battler which affect attack power.

Game_BattlerBase.prototype.traitsPi = function(code, id) {
    return this.traitsWithId(code, id).reduce(function(r, trait) {
        return r * trait.value;
    }, 1);
};


traitsPi is a somewhat misleading name for this function, IMO, as it doesn't really have anything to do with pi. What it does is returns a multiplicative total for percentage-based traits. To do so, we return a reduce on traitsWithId, passing in the arguments supplied to the original function, and in that block (using "r" as the accumulator and "trait" as the current object) we return r multiplied by the trait's value. The 1 at the end is the value the accumulator starts at.

Okay, so let's take something percentage-based, like...pharmacology. Pharmacology is sparam 3, so the call for this would be traitsPi(23, 3). Let's say our actor has a class Pharmacology rate of 110% (he's a chemist), a weapon equipped that gives 120% Pharmacology, and is currently endowed with a state that doubles Pha. traitsWithId would return 3 elements, each of which is a hashmap: a trait consists of a code, a dataId and a value. So our elements would be {code: 23, dataId: 3, value: 1.1}, {code: 23, dataId: 3, value: 1.2} and {code: 23, dataId: 3, value: 2}.

When we run the reduce on this, we start with a value of 1. The first time through, trait.value is 1.1, so we have 1 * 1.1 which gives us an accumulated value of 1.1.

The second time through, the value is 1.2, so we have 1.1 * 1.2, which gives us 1.32.

The third time through, value is 2, so we have 1.32 * 2, giving us 2.64. Or in other words, healing will be 164% more effective when used by this character.

Game_BattlerBase.prototype.traitsSum = function(code, id) {
    return this.traitsWithId(code, id).reduce(function(r, trait) {
        return r + trait.value;
    }, 0);
};


In traitsSum, we do a similar thing, but rather than multiplying the value we're adding it to the accumulator.

For our worked example, let's take critical rate, which is xparam 2 (ID 22). Our actor has a class crit of 4% and a weapon that gives +10% crit. So traitsWithId(22, 2) should give us {code: 22, traitId: 2, value: 0.04} and {code: 22, traitId: 2, value: 0.1}. Unlike with traitsPi, the accumulator here starts at 0.

The first time through, trait.value is 0.04, so we have 0 + 0.04 for an accumulated value of 0.04.

The second time through, trait.value is 0.1, so we have 0.04 + 0.1 for a value of 0.14. In other words, the actor will have a 14% chance to crit.

Game_BattlerBase.prototype.traitsSumAll = function(code) {
    return this.traits(code).reduce(function(r, trait) {
        return r + trait.value;
    }, 0);
};


This function is almost identical to the last one, except it doesn't take id as a parameter. What this means is that it adds up all traits matching a particular code. This is mainly used for traits that only have a code and a value, like attack speed and attack times +.

Game_BattlerBase.prototype.traitsSet = function(code) {
    return this.traits(code).reduce(function(r, trait) {
        return r.concat(trait.dataId);
    }, []);
};


In the traitsSet function, we again just take code as a parameter. This time, we start the accumulator as an empty array, and in the reduce function we concatenate the trait's data ID into r. This is used for traits that want an array of IDs, like attack elements and state resists.

Game_BattlerBase.prototype.paramBase = function(paramId) {
    return 0;
};


In the paramBase function, we return the base parameter value for the given paramId. In the BattlerBase class, we simply return 0; this is because actors get their param base values from their class, but enemies don't have classes. These values will be further streamlined in their respective child classes soon.

Game_BattlerBase.prototype.paramPlus = function(paramId) {
    return this._paramPlus[paramId];
};


The paramPlus function is just a wrapper for the _paramPlus array. It takes paramId as a parameter and in it we simply return the element of _paramPlus with the index matching our argument value.

Game_BattlerBase.prototype.paramMin = function(paramId) {
    if (paramId === 1) {
        return 0;   // MMP
    } else {
        return 1;
    }
};


This function determines the minimum possible value for a given param, again taking paramId as a parameter. If the supplied value is 1 (meaning max MP) we return 0, as some characters/enemies have no MP at all. Otherwise, we return 1, as no other param can be less than that.

Game_BattlerBase.prototype.paramMax = function(paramId) {
    if (paramId === 0) {
        return 999999;  // MHP
    } else if (paramId === 1) {
        return 9999;    // MMP
    } else {
        return 999;
    }
};


Whereas this function defines the maximum possible value of a given parameter. If the argument value is 0 (meaning max HP), we return 999,999. Otherwise if it's 1 (max MP), we return 9,999. Otherwise, we return 999.

If you ever want to change the upper limits of stats in your game, this is where to do it. Be aware, though, that changing the max in code doesn't mean you'll be able to enter a higher value in the editor, as these max limit are also hardcoded into the input boxes. For example, you can't enter a value higher than 9999 for the HP of a class at any level, even though the code technically allows HP values for actors to exceed that. To properly increase limits like this, you'll have to use or write a plugin.

Game_BattlerBase.prototype.paramRate = function(paramId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_PARAM, paramId);
};


This function determines the overall percentage a given param should be at, taking paramId as a parameter. We return the result of calling traitsPi passing in TRAIT_PARAM as the code and paramId as the traitId.

For example, let's say the user has a state that adds 50% defence, but has just been afflicted with another state that cuts defence by 25%. We'd have {code: 21, traitId: 3, value: 1.5} and {code: 21, traitId: 3, value: 0.75} So first time round our accumulator is 1 * 1.5 = 1.5, then the next iteration is 1.5 * 0.75 = 1.125. In other words, our defence ends up being increased by 12.5%.

Game_BattlerBase.prototype.paramBuffRate = function(paramId) {
    return this._buffs[paramId] * 0.25 + 1.0;
};


This function determines the rate of a param added by buffs, taking paramId as a parameter. We return the element of _buffs at index paramId multiplied by 0.25 plus 1.0, which will give us an additive +25% per buff level. For example, if we had two buffs in magic defence and did paramBuffRate(5) the return value would be 2 * 0.25 + 1.0 = 1.5. In other words, our magic defence would be raised by 50%.

Game_BattlerBase.prototype.param = function(paramId) {
    var value = this.paramBase(paramId) + this.paramPlus(paramId);
    value *= this.paramRate(paramId) * this.paramBuffRate(paramId);
    var maxValue = this.paramMax(paramId);
    var minValue = this.paramMin(paramId);
    return Math.round(value.clamp(minValue, maxValue));
};


And here we have the culmination of a bunch of the functions we've just looked at. This is the one that actually gets the value of a given param, taking paramId as a parameter.

We set a variable called value to the result of calling paramBase added to the result of calling paramPlus, passing in paramId to each function. We then multiply that by the result of paramRate multiplied by paramBuffRate, again passing in paramId. We set maxValue to the result of calling paramMax, and minValue to the result of calling paramMin. Finally, we return the value clamped to minValue and maxValue, rounded down.

clamp is a helper function added in MV which checks a value and if it's below a minimum or above a maximum, it either raises it to min or reduces it to max. We'll see the implementation of this when we come to look at rpg_core.js.

Game_BattlerBase.prototype.xparam = function(xparamId) {
    return this.traitsSum(Game_BattlerBase.TRAIT_XPARAM, xparamId);
};


The function for getting an xparam is simpler, taking xparamId as a parameter. We just return the result of calling traitsSum, passing in the TRAIT_XPARAM constant and xparamId. This tells us that xparams are additive. And indeed, if you look at the percentage input box under Ex-Parameter, it has a + to show this.

Game_BattlerBase.prototype.sparam = function(sparamId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_SPARAM, sparamId);
};


Conversely, all of the sparams are multiplicative, so for those we call traitsPi, which is still oddly-named and I will die on that hill.

Game_BattlerBase.prototype.elementRate = function(elementId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_ELEMENT_RATE, elementId);
};


Element rates are also multiplicative, so we once again get the rate for a given elementId by calling traitsPi, passing in the TRAIT_ELEMENT_RATE constant as the code and elementId as the traitId.

Game_BattlerBase.prototype.debuffRate = function(paramId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_DEBUFF_RATE, paramId);
};


Same thing for debuffRate, which is multiplicative...

Game_BattlerBase.prototype.stateRate = function(stateId) {
    return this.traitsPi(Game_BattlerBase.TRAIT_STATE_RATE, stateId);
};


...as is stateRate.

Game_BattlerBase.prototype.stateResistSet = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_STATE_RESIST);
};


This is the first function where we're calling traitsSet, and it's the one for the set of states the battler resists (is completely immune to). There's occasionally been some confusion between state resist and state *resistance*. In engine terms, resisting a state means that it will have no effect whatsoever, and that's the one you select from the dropdown box of state names with no percentage input. Being resistant to a state is a different thing; it's basically where the trait is "state rate" but the percentage is less than 100. This reduces the chance of being afflicted with the state, but still means the battler is susceptible to it.

Game_BattlerBase.prototype.isStateResist = function(stateId) {
    return this.stateResistSet().contains(stateId);
};


This function checks whether the battler resists a given stateId; we take the return value of stateResistSet and return whether it contains the passed-in stateId.

Game_BattlerBase.prototype.attackElements = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_ELEMENT);
};


This function gets the battler's attack elements; we return the result of calling traitsSet passing in the TRAIT_ATTACK_ELEMENT constant as the code.

Game_BattlerBase.prototype.attackStates = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_STATE);
};


This one's just the same, but for attack states, using the TRAIT_ATTACK_STATE constant.

Game_BattlerBase.prototype.attackStatesRate = function(stateId) {

return this.traitsSum(Game_BattlerBase.TRAIT_ATTACK_STATE, stateId);
};


This function gives us the percentage chance of the battler inflicting a given state when attacking, taking stateId as a parameter. We return the result of traitsSum, passing in the TRAIT_ATTACK_STATE constant as the code and stateId as the traitId.

Game_BattlerBase.prototype.attackSpeed = function() {

return this.traitsSumAll(Game_BattlerBase.TRAIT_ATTACK_SPEED);
};


This function gets the final attack speed modifier on the battler; we return the result of calling traitsSumAll passing in the TRAIT_ATTACK_SPEED constant.

Game_BattlerBase.prototype.attackTimesAdd = function() {
    return Math.max(this.traitsSumAll(Game_BattlerBase.TRAIT_ATTACK_TIMES), 0);
};


This function gets the number of additional attacks the battler can make. We return the maximum value between the result of traitsSumAll passing in the TRAIT_ATTACK_TIMES constant, and 0. This prevents the value from being a negative, which would make no sense.

Game_BattlerBase.prototype.addedSkillTypes = function() {
    return this.traitsSet(Game_BattlerBase.TRAIT_STYPE_ADD);
};


This function gets the list of added skill types the battler has access to; we return the result of calling traitsSet passing in the TRAIT_STYPE_ADD constant.

Game_BattlerBase.prototype.isSkillTypeSealed = function(stypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_STYPE_SEAL).contains(stypeId);
};


Similarly, this function gets the list of sealed skill types, the ones the battler can't use. We do this by returning the result of checking that traitsSet with the TRAIT_STYPE_SEAL constant contains the stypeId parameter passed to it.

Game_BattlerBase.prototype.isSkillSealed = function(skillId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_SKILL_SEAL).contains(skillId);
};


This is pretty much the same thing but for individual sealed skills, so uses the TRAIT_SKILL_SEAL constant.

Game_BattlerBase.prototype.isEquipWtypeOk = function(wtypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_WTYPE).contains(wtypeId);
};


And the same thing for whether any traits allow for equipping a given weapon type using the TRAIT_EQUIP_WTYPE constant...

Game_BattlerBase.prototype.isEquipAtypeOk = function(atypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_ATYPE).contains(atypeId);
};


And the same thing but for armour using the TRAIT_EQUIP_ATYPE constant...

Game_BattlerBase.prototype.isEquipTypeLocked = function(etypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_LOCK).contains(etypeId);
};


...aaaand the same thing checking for whether a given equipment type is locked (unable to remove or change what's already equipped there) by any traits, using the TRAIT_EQUIP_LOCK constant...

Game_BattlerBase.prototype.isEquipTypeSealed = function(etypeId) {
    return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_SEAL).contains(etypeId);
};


And the same thing again for checking whether a given equipment type is sealed (unable to equip anything to the type slot) using TRAIT_EQUIP_SEAL.

Game_BattlerBase.prototype.slotType = function() {
    var set = this.traitsSet(Game_BattlerBase.TRAIT_SLOT_TYPE);
    return set.length > 0 ? Math.max.apply(null, set) : 0;
};


Finally, a tiny bit of variance! This one gets the set of slot type traits; by default, there's only one (Dual Wield). So we set a variable called "set" to the result of traitsSet passing in the TRAIT_SLOT_TYPE constant, then if the set's length is greater than 0 we return the maximum value between null and set, or 0. The reason for using apply here is that set is an array (we've covered this before), and the null value is just to have something there for the first parameter; it doesn't actually do anything, but the function needs it. The end result is that we get the maximum value of the array of slot type traits, which will end up either being 0 or 1. Presumably it was coded like this so that slot types are expandable via plugins (or maybe there were plans to add more slot types later that never came to fruition)

Game_BattlerBase.prototype.isDualWield = function() {
    return this.slotType() === 1;
};


This function gets whether the battler is a dual wielder or not; we return whether the result of calling slotType is equal to 1, in which case they have a "dual wield" trait somewhere.

Game_BattlerBase.prototype.actionPlusSet = function() {
    return this.traits(Game_BattlerBase.TRAIT_ACTION_PLUS).map(function(trait) {
        return trait.value;
    });
};


This function gets the array of "action times +" percentages; we return a map of the result of calling the traits function (passing in TRAIT_ACTION_PLUS as the code) and in the map block return the trait's value, which will be the percentage set in the database.

The reason for this is that action plus traits are calculated separately, and each one gives a chance of the battler receiving an extra action in battle.

Game_BattlerBase.prototype.specialFlag = function(flagId) {
    return this.traits(Game_BattlerBase.TRAIT_SPECIAL_FLAG).some(function(trait) {
        return trait.dataId === flagId;
    });
};


This function gets whether any of the battler's traits include a given flagId (which will be Auto Battle, Guard, Substitute or Preserve TP); we return a .some call on the result of traits passing in TRAIT_SPECIAL_FLAG, and in the some block return whether the trait's dataId is equal to the passed-in flagId.

This is because only one trait with a special flag is needed for the battler to qualify as possessing that trait, multiples don't change anything.

Game_BattlerBase.prototype.collapseType = function() {
    var set = this.traitsSet(Game_BattlerBase.TRAIT_COLLAPSE_TYPE);
    return set.length > 0 ? Math.max.apply(null, set) : 0;
};


This function gets the set of applicable collapse types in the same way as we did dual wield. Collapse types are treated as a hierarchy, so the lower down in the dropdown list the type is, the more priority it will have when present. If your battler has all four (Normal, Boss, Instant and No Disappear) they'll be considered to have a collapse type of "no disappear".

Game_BattlerBase.prototype.partyAbility = function(abilityId) {
    return this.traits(Game_BattlerBase.TRAIT_PARTY_ABILITY).some(function(trait) {
        return trait.dataId === abilityId;
    });
};


This function is similar to the special flag one, but checks for party abilities instead using TRAIT_PARTY_ABILITY. This covers Encounter Half, Encounter None, Cancel Surprise, Raise Preemptive, Gold Double and Drop Item Double.

Game_BattlerBase.prototype.isAutoBattle = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_AUTO_BATTLE);
};

Game_BattlerBase.prototype.isGuard = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_GUARD) && this.canMove();
};

Game_BattlerBase.prototype.isSubstitute = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_SUBSTITUTE) && this.canMove();
};

Game_BattlerBase.prototype.isPreserveTp = function() {
    return this.specialFlag(Game_BattlerBase.FLAG_ID_PRESERVE_TP);
};


This set of functions test for whether the battler has a given special flag, calling the specialFlag function for Auto Battle, Guard, Substitute and Preserve TP respectively. Note that isGuard and isSubstitute also check for canMove because their function relies on the battler being able to act (it wouldn't make sense for a battler to substitute for allies while stunned).

Game_BattlerBase.prototype.addParam = function(paramId, value) {
    this._paramPlus[paramId] += value;
    this.refresh();
};


This function is the one via which we apply temporary stat bonuses to battlers, taking paramId and value as parameters. We add the number passed in "value" to the element of the _paramPlus array with an index of paramId, then call the battler's refresh function.

Game_BattlerBase.prototype.setHp = function(hp) {
    this._hp = hp;
    this.refresh();
};

Game_BattlerBase.prototype.setMp = function(mp) {
    this._mp = mp;
    this.refresh();
};

Game_BattlerBase.prototype.setTp = function(tp) {
    this._tp = tp;
    this.refresh();
};


These functions let us set the battler's HP, MP and TP respectively. In each case we set the respective instance variable to the passed-in value then call refresh.

Game_BattlerBase.prototype.maxTp = function() {
    return 100;
};


This function defines the maximum amount of TP a battler can have, in which we simply return 100. If you want to change the TP maximum in your game this is where to do it.

Game_BattlerBase.prototype.refresh = function() {
    this.stateResistSet().forEach(function(stateId) {
        this.eraseState(stateId);
    }, this);
    this._hp = this._hp.clamp(0, this.mhp);
    this._mp = this._mp.clamp(0, this.mmp);
    this._tp = this._tp.clamp(0, this.maxTp());
};


The refresh function basically just makes sure the battler isn't afflicted with any states it's immune to and that its primary stats don't exceed their maximums or go below 0.

We start a forEach loop for the result of calling stateResistSet, passing in a function where we use the iteration variable stateId, then call eraseState passing in stateId. This loops through the states the battler resists, and gets rid of them. Interestingly, this means that technically the state is applied, it just gets removed immediately.

Then set set _hp to the result of calling the clamp function on its own value, passing in 0 and the battler's mhp (maximum HP). We do the same for MP and TP. This keeps their values at 0 or more and below whatever their maximum is.

Game_BattlerBase.prototype.recoverAll = function() {
    this.clearStates();
    this._hp = this.mhp;
    this._mp = this.mmp;
};


This function is used to completely recover a battler. We call the clearStates function, which as we've seen removes any state affecting them. Then we set _hp to the battler's mhp and _mp to their mmp. Interestingly, because there's nothing in the engine to differentiate negative states from positive ones, full recovery will also get rid of good states like regen or haste.

Game_BattlerBase.prototype.hpRate = function() {
    return this.hp / this.mhp;
};

Game_BattlerBase.prototype.mpRate = function() {
    return this.mmp > 0 ? this.mp / this.mmp : 0;
};

Game_BattlerBase.prototype.tpRate = function() {
    return this.tp / this.maxTp();
};


This set of functions gets the percentage of HP, MP and TP the battler is currently at, simply by dividing the current by the maximum. In the case of MP we also check whether it's greater than 0 first, because obviously dividing by 0 would cause an error and if that's not the case we just return a flat 0 instead.

Game_BattlerBase.prototype.hide = function() {
    this._hidden = true;
};

Game_BattlerBase.prototype.appear = function() {
    this._hidden = false;
};


This set of functions provides a convenient wrapped for manipulating the _hidden flag. In the hide function, we set _hidden to true, and in appear we set _hidden to false. Simples!

Game_BattlerBase.prototype.isHidden = function() {
    return this._hidden;
};

Game_BattlerBase.prototype.isAppeared = function() {
    return !this.isHidden();
};


Similarly, in isHidden we determine whether the battler is currently hidden by returning the value of _hidden, and isAppeared checks whether the battler has appeared in battle by returning the negative of the result from calling isHidden.

Game_BattlerBase.prototype.isDead = function() {
    return this.isAppeared() && this.isDeathStateAffected();
};

Game_BattlerBase.prototype.isAlive = function() {
    return this.isAppeared() && !this.isDeathStateAffected();
};


To check whether a battler is dead in the isDead function, we return true if isAppeared returns true AND the isDeathStateAffected function returns true (meaning the battler appeared in battle and has the death state). Conversely, in isAlive, we return true if isAppeared returns true AND isDeathStateAffected does *not* return true. Obviously a battler that hasn't appeared yet can be neither alive nor dead.

Game_BattlerBase.prototype.isDying = function() {
    return this.isAlive() && this._hp < this.mhp / 4;
};


This function determines whether a battler is dying; we return true if isAlive returns true AND the battler's _hp is less than its mhp divided by 4. In other words, a battler is considered to be dying if it's at a quarter of max HP or less. If you want to change the criteria under which a battler is considered to be dying, this is where to do it.

Game_BattlerBase.prototype.isRestricted = function() {
    return this.isAppeared() && this.restriction() > 0;
};


This function determines whether a battler is restricted; we return true if isAppeared returns true AND the result of the restriction function is greater than 0. This will mean the battler is afflicted with a state with "attack an enemy", "attack anyone", "attack an ally" or "cannot move".

Game_BattlerBase.prototype.canInput = function() {
    return this.isAppeared() && !this.isRestricted() && !this.isAutoBattle();
};


This function determines whether a battler can input actions; we return true if isAppeared returns true AND isRestricted does not return true AND isAutoBattle does not return true. In other words, the battler has appeared in battle, has no action restrictions, and isn't set to auto battle.

Game_BattlerBase.prototype.canMove = function() {
    return this.isAppeared() && this.restriction() < 4;
};


This function determines whether the battler is capable of movement; we return true if isAppeared returns true AND the result of calling the restriction function is less than 4 (a value of 4 would mean a state with "cannot move" is present).

Game_BattlerBase.prototype.isConfused = function() {
    return this.isAppeared() && this.restriction() >= 1 && this.restriction() <= 3;
};


This function determines whether the battler is confused; we return true if isAppeared returns true AND restriction returns a value greater than or equal to 1 AND a value less than or equal to 3. In other words, their restriction is either "attack an enemy", "attack anyone", or "attack an ally".

Game_BattlerBase.prototype.confusionLevel = function() {
    return this.isConfused() ? this.restriction() : 0;
};


This function determines the confusion level of the enemy, since the restriction dropdown in the states tab works on a hierarchy where the higher the number, the more of a priority the restriction has. Attacking an enemy is better than attacking anyone is better than attacking an ally is better than being unable to move entirely.

Game_BattlerBase.prototype.isActor = function() {
    return false;
};

Game_BattlerBase.prototype.isEnemy = function() {
    return false;
};


The isActor and isEnemy functions determine whether the battler is an actor or enemy, respectively. Here we're just returning false, because a BattlerBase is neither. The child classes will overwrite this to return the correct value from their perspective.

Game_BattlerBase.prototype.sortStates = function() {
    this._states.sort(function(a, b) {
        var p1 = $dataStates[a].priority;
        var p2 = $dataStates[b].priority;
        if (p1 !== p2) {
            return p2 - p1;
        }
        return a - b;
    });
};


This function sorts the battler's states. The sort function, by default, sorts alphabetically/numerically, but you can pass a function to it to customise how the sorting works. In this case, we're passing it a function that will take two states, represented by "a" and "b", and determine what order to put them in.

So we set a variable called p1 to the priority property of $dataStates at index a, and p2 to the priority property of $dataStates at index b. If p1 is not equal to p2, we return p2 minus p1. Otherwise, we return a minus b.

Effectively, what this does is says "If a given state has a higher priority than any other, place it first in the list. If two states have the same priority, order them by state ID."

Game_BattlerBase.prototype.restriction = function() {
    return Math.max.apply(null, this.states().map(function(state) {
        return state.restriction;
    }).concat(0));
};


This function determines the restriction level currently affecting the battler; we return the result of calling Math.max.apply passing in null and a map of the result of the states function using iteration variable "state" returning the state's restriction value, concatenated with 0.

...wait, what?

Okay, so we should know what the map is doing; it's just taking the array of states and turning it into an array of the restriction values of those states. Math.max.apply then takes the array and gets the maximum value, so far so good. Why the concat(0)? Well if the battler has no states, Math.max will have nothing to check the array against, so we concatenate a 0 so there's at least one value there. If we didn't do this, the function would return -Infinity, which would give us all sorts of janky problems when checking restriction values later.

Game_BattlerBase.prototype.addNewState = function(stateId) {

if (stateId === this.deathStateId()) {
this.die();
}
var restricted = this.isRestricted();
this._states.push(stateId);
this.sortStates();
if (!restricted && this.isRestricted()) {
this.onRestrict();
}
};


This function adds a new state to the battler, taking stateId as a parameter. If the passed-in stateId is equal to the result of calling deathStateId, we call the die function because, well, the battler's dead.

We then set a variable called restricted to the result of calling isRestricted, push the stateId to the _states array, call sortStates to resort the list, and then if restricted is false AND isRestricted returns true, we call the onRestrict function.

This might seem confusing, but it's less so than it looks. We're checking whether the battler is currently restricted, then pushing the state, then checking *again* and if they weren't restricted before and are now, we call the onRestrict event handler function. This ensures that we only process onRestrict in cases where the battler wasn't already; it won't be called if the battler is restricted and then ends up moreso.

Game_BattlerBase.prototype.onRestrict = function() {
};


onRestrict is rather unexciting for the BattlerBase class in that it does literally nothing; it'll be overwritten by child classes, which we'll see later.

Game_BattlerBase.prototype.mostImportantStateText = function() {
    var states = this.states();
    for (var i = 0; i < states.length; i++) {
        if (states[i].message3) {
            return states[i].message3;
        }
    }
    return '';
};


This function gets the persistence text of the most important state affecting the battler.

We set a variable called states to the result of the states function, then run a for loop with loop variable i starting at 0 and ending when i is equal to the length of the states array. Inside that loop, if the message3 property of the element of states at index i is not an empty string, we return it. After the for loop, we return a blank string since no message has been found.

Game_BattlerBase.prototype.stateMotionIndex = function() {
    var states = this.states();
    if (states.length > 0) {
        return states[0].motion;
    } else {
        return 0;
    }
};


Similarly, this function gets the side view motion to apply to the battler, by taking the array of states and then if its length is greater than 0 we return the motion property of the one at index 0 (the first one). If the length is 0, we just return 0. This property corresponds to the "normal", "abnormal", "sleep" and "dead" options in the [SV] Motion: dropdown in the states tab.

Game_BattlerBase.prototype.stateOverlayIndex = function() {
    var states = this.states();
    if (states.length > 0) {
        return states[0].overlay;
    } else {
        return 0;
    }
};


This one gets the index for the state overlay, in a similar fashion to the motion index but using the overlay property instead. This corresponds to the [SV] Overlay: dropdown, where the index points to its respective row in the States.png file in the img/system folder.

Game_BattlerBase.prototype.isSkillWtypeOk = function(skill) {
    return true;
};


This function determines whether a skill is usable with the battler's weapon type, taking skill as a parameter. In the base function, we simply return true. This will be overwritten for actors later.

Game_BattlerBase.prototype.skillMpCost = function(skill) {
    return Math.floor(skill.mpCost * this.mcr);
};


This function gets the MP cost of a skill, taking skill as a parameter. We return the floor of the skill's mpCost property multiplied by the battler's mcr value (MP Cost Rate).

Game_BattlerBase.prototype.skillTpCost = function(skill) {
    return skill.tpCost;
};


This function gets the TP cost of a skill, taking skill as a parameter. We simply return the skill's tpCost property, since there is no parameter affecting TP cost rate.

Game_BattlerBase.prototype.canPaySkillCost = function(skill) {
    return this._tp >= this.skillTpCost(skill) && this._mp >= this.skillMpCost(skill);
};


This function determines whether the battler can pay a skill's cost, taking skill as a parameter. We return true if the battler's _tp is greater than or equal to the result of skillTpCost passing in skill AND the battler's _mp is greater than or equal to the result of skillMpCost passing in skill. In other words, the battler has enough TP and MP to pay the costs set for the skill in the database.

Game_BattlerBase.prototype.paySkillCost = function(skill) {
    this._mp -= this.skillMpCost(skill);
    this._tp -= this.skillTpCost(skill);
};


This function pays the cost of a skill, taking skill as a parameter. We reduce _mp by the result of skillMpCost, and _tp by the result of skillTpCost, each time passing in the skill argument.

Game_BattlerBase.prototype.isOccasionOk = function(item) {
    if ($gameParty.inBattle()) {
        return item.occasion === 0 || item.occasion === 1;
    } else {
        return item.occasion === 0 || item.occasion === 2;
    }
};


This function determines whether the a skill or item's "Occasion" setting allows for it to be used.

If the inBattle function of $gameParty returns true (the party is in battle) we return true if the item's occasion property is equal to 0 OR if it's equal to 1 ("Always" or "Battle Screen"). Otherwise, we return true if the occasion is 0 OR 2 ("Always" or "Menu Screen"). We don't need a separate check for "Never" because then occasion will be 3, which isn't covered by the if or the else and so will return false anyway.

Game_BattlerBase.prototype.meetsUsableItemConditions = function(item) {
    return this.canMove() && this.isOccasionOk(item);
};


This function determines whether the battler meets the conditions for using a given skill or item, taking item as a parameter. We return true if canMove returns true AND isOccasionOk returns true.

Game_BattlerBase.prototype.meetsSkillConditions = function(skill) {
    return (this.meetsUsableItemConditions(skill) &&
            this.isSkillWtypeOk(skill) && this.canPaySkillCost(skill) &&
            !this.isSkillSealed(skill.id) && !this.isSkillTypeSealed(skill.stypeId));
};


This function determines whether the battler meets the conditions for a given skill, taking skill as a parameter. We return true if meetsUsableItemConditions returns true AND isSkillWtypeOk returns true AND canPaySkillCost returns true AND isSkillSealed returns false AND isSkillTypeSealed returns false, when we pass in skill, skill, skill, the skill's ID and the skill's type ID respectively.

Game_BattlerBase.prototype.meetsItemConditions = function(item) {
    return this.meetsUsableItemConditions(item) && $gameParty.hasItem(item);
};


This function determines whether the battler meets the conditions for a given item, taking item as a parameter. We return true if meetsUsableItemConditions returns true AND the hasItem function of $gameParty returns true, when we pass in item to each. In other words, the battler is able to move, the item's occasion is met, and the party possesses at least one of the item in question.

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;
    }
};


This function determines whether a given item can be used by the battler, taking item as a parameter. If the item is null, we return false as you can't use an item that doesn't exist obviously. Otherwise, if the isSkill function of DataManager returns true, we return the result of meetsSkillConditions with item passed in. Otherwise, if the isItem function of DataManager returns true, we return the result of meetsItemConditions with item passed in. And in any other case, we return false.

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;
    }
};


This is the equipment version of the function we just looked at, and determines whether a given item can be equipped by the battler rather than used. Again if item is null we return false. Otherwise, if DataManager's isWeapon returns true we return the result of canEquipWeapon. Otherwise, if DataManager's isArmor returns true, we return the result of canEquipArmor. In any other case, we return false.

Game_BattlerBase.prototype.canEquipWeapon = function(item) {
    return this.isEquipWtypeOk(item.wtypeId) && !this.isEquipTypeSealed(item.etypeId);
};

Game_BattlerBase.prototype.canEquipArmor = function(item) {
    return this.isEquipAtypeOk(item.atypeId) && !this.isEquipTypeSealed(item.etypeId);
};


The functions for checking whether a battler can equip a given weapon or armour are very similar. The only difference is that one is checking isEquipWtypeOk against the item argument's wtypeId, and the other is checking isEquipAtypeOk against the item argument's atypeId. Both also check that isEquipTypeSealed returns false with the item's etypeId passed to it.

Game_BattlerBase.prototype.attackSkillId = function() {
    return 1;
};

Game_BattlerBase.prototype.guardSkillId = function() {
    return 2;
};


These functions determine the IDs of the skills that will be considered a normal attack and guard action for the battler respectively. For attackSkillId, we return 1, and for guardSkillId we return 2. If you ever want to change which skill is considered an attack/guard, this is where to do it.

Game_BattlerBase.prototype.canAttack = function() {
    return this.canUse($dataSkills[this.attackSkillId()]);
};

Game_BattlerBase.prototype.canGuard = function() {
    return this.canUse($dataSkills[this.guardSkillId()]);
};


These functions determine whether a battler is able to attack or guard; we call canUse, and pass in the element of $dataSkills with an index of the result from attackSkillId and guardSkillId respectively.

That's everything for the BattlerBase class! I was going to forge ahead and cover Game_Battler in the same article, but the wait from the last one is getting a bit long and this was a long class to begin with, so I'm going to cut it there and hit the ground running next time with Game_Battler, Game_Actor and Game_Enemy.

Until next time!