JUMP INTO JAVASCRIPT PART 12

In which actors take up more room than you'd think.

  • Trihan
  • 06/12/2021 09:21 AM
  • 2172 views
Hello sports fans! I actually managed to stick to a weekly release for once, go me! Yep, it's that time again. Time for another fun-filled episode of...


Jump into Javascript

Last week we broke down Game_Battler, now let's tear apart the classes that inherit from it: Game_Actor and Game_Enemy. And maybe a bit more if we have the time.

Game_Actor
Game_Actor is absolutely integral to every game. Without it, there'd be no characters to play as. Unsurprisingly, it inherits from Game_Battler.

Object.defineProperty(Game_Actor.prototype, 'level', {
    get: function() {
        return this._level;
    },
    configurable: true
});


I believe this is the first time we've come across Object.defineProperty, and indeed it's the only occurrence of it in rpg_objects.js. Here we're defining a property called "level" on Game_Actor's prototype which is read-only. Its get function returns the internal variable _level. configurable: true just means it can be modified or deleted from the object.

As far as I know this isn't really functionally any different from creating a function called level which returns the value of _level; either approach is valid.

Game_Actor.prototype.initialize = function(actorId) {
    Game_Battler.prototype.initialize.call(this);
    this.setup(actorId);
};


It's been a minute since we had an initialize function which did something other than just call the parent function: in this case, it takes actorId as a parameter, and after calling the parent function we call setup, passing in actorId.

Game_Actor.prototype.initMembers = function() {
    Game_Battler.prototype.initMembers.call(this);
    this._actorId = 0;
    this._name = '';
    this._nickname = '';
    this._classId = 0;
    this._level = 0;
    this._characterName = '';
    this._characterIndex = 0;
    this._faceName = '';
    this._faceIndex = 0;
    this._battlerName = '';
    this._exp = {};
    this._skills = [];
    this._equips = [];
    this._actionInputIndex = 0;
    this._lastMenuSkill = new Game_Item();
    this._lastBattleSkill  = new Game_Item();
    this._lastCommandSymbol = '';
};


initMembers is just setting up a bunch of initial values. We're setting _actorId, _classId, _level, _characterIndex, _faceIndex and _actionInputIndex to 0; _name, _nickname, _characterName, _faceName, _battlerName and _lastCommandSymbol to blank strings; _exp to an empty object; _skills and _equips to empty arrays; and _lastMenuSkill and _lastBattleSkill to a new instance of Game_Item.

Game_Actor.prototype.setup = function(actorId) {
    var actor = $dataActors[actorId];
    this._actorId = actorId;
    this._name = actor.name;
    this._nickname = actor.nickname;
    this._profile = actor.profile;
    this._classId = actor.classId;
    this._level = actor.initialLevel;
    this.initImages();
    this.initExp();
    this.initSkills();
    this.initEquips(actor.equips);
    this.clearParamPlus();
    this.recoverAll();
};


setup, on the other hand, initialises some proper values, and takes actorId as a parameter.

First we set actor to the element of $dataActors with actorId as its index, which just means we don't have to retype that reference every time we need to do something with that actor. Then we set _actorId to the passed-in value, _name to the actor's name, _nickname to the actor's nickname, _profile to the actor's profile, _classId to the actor's class ID, and _level to the result of the initialLevel function.

Then we call initImages to preload graphics, initExp to initialise the exp curve, initSkills to initialise skills, initEquips (passing in the equips array from the actor) to set up starting equipment, clearParamPlus to clear any stat bonuses and recoverAll to initialise our actor with full resources.

Game_Actor.prototype.actorId = function() {
    return this._actorId;
};


actorId is just a wrapper function to return the internal _actorId, which is obviously the ID of the actor.

Game_Actor.prototype.actor = function() {
    return $dataActors[this._actorId];
};


Used here, in this function which returns the actual actor object; we do so by returning the element of $dataActors at the index matching the return value of actorId().

Game_Actor.prototype.name = function() {
    return this._name;
};

Game_Actor.prototype.setName = function(name) {
    this._name = name;
};


These are the getter/setter functions for the actor's name. The getter returns _name, the setter takes "name" as a parameter and sets _name to the value passed in.

Game_Actor.prototype.nickname = function() {
    return this._nickname;
};

Game_Actor.prototype.setNickname = function(nickname) {
    this._nickname = nickname;
};


This is the same thing for the actor's nickname.

Game_Actor.prototype.profile = function() {
    return this._profile;
};

Game_Actor.prototype.setProfile = function(profile) {
    this._profile = profile;
};


And the same for the actor's profile.

Game_Actor.prototype.characterName = function() {
    return this._characterName;
};

Game_Actor.prototype.characterIndex = function() {
    return this._characterIndex;
};

Game_Actor.prototype.faceName = function() {
    return this._faceName;
};

Game_Actor.prototype.faceIndex = function() {
    return this._faceIndex;
};

Game_Actor.prototype.battlerName = function() {
    return this._battlerName;
};


Here we have the remaining property getter functions, for the character name, character index, face name, face index and battler name.

Game_Actor.prototype.clearStates = function() {
    Game_Battler.prototype.clearStates.call(this);
    this._stateSteps = {};
};


The new implementation of clearStates only does one extra thing on actors besides calling the parent function: we set the _stateSteps property to an empty object.

Game_Actor.prototype.eraseState = function(stateId) {
    Game_Battler.prototype.eraseState.call(this, stateId);
    delete this._stateSteps[stateId];
};


Similarly, with eraseState (which takes stateId as a parameter) we call the parent function and then delete the item in _stateSteps with a key matching the passed-in stateId.

Game_Actor.prototype.resetStateCounts = function(stateId) {
    Game_Battler.prototype.resetStateCounts.call(this, stateId);
    this._stateSteps[stateId] = $dataStates[stateId].stepsToRemove;
};


With resetStateCounts, which also takes stateId as a parameter, we call the parent function, and then set the item in _stateSteps at an index of stateId to the value of the stepsToRemove property of the element of $dataStates at index stateId.

Or to slightly unmuddle that a bit, let's say stateId is 29, which in the default data is Double Encounters. We're looking at stepsToRemove (which will contain the value in the "Remove by Walking" removal condition from the states tab of the database) from $dataStates, which will be 100, then storing the value 100 in _stateSteps. This will result in _stateSteps having a new entry of "29: 100", which will represent 100 steps for state #29.

Game_Actor.prototype.initImages = function() {
    var actor = this.actor();
    this._characterName = actor.characterName;
    this._characterIndex = actor.characterIndex;
    this._faceName = actor.faceName;
    this._faceIndex = actor.faceIndex;
    this._battlerName = actor.battlerName;
};


In initImages, first we set a variable called actor to the return value of calling actor() (this is just so we have a shorter way to refer to the actor in the following lines). Then we set the instance's _characterName, _characterIndex, _faceName, _faceIndex and _battlerName to the corresponding values from the actor object (which will reference the settings used in the actors tab of the database).

Game_Actor.prototype.expForLevel = function(level) {
    var c = this.currentClass();
    var basis = c.expParams[0];
    var extra = c.expParams[1];
    var acc_a = c.expParams[2];
    var acc_b = c.expParams[3];
    return Math.round(basis*(Math.pow(level-1, 0.9+acc_a/250))*level*
            (level+1)/(6+Math.pow(level,2)/50/acc_b)+(level-1)*extra);
};


This function gets the amount of experience the actor needs to attain a given level, taking level as a parameter. We set a variable called c to the return value of the actor's currentClass() function, then set variables called basis, extra, acc_a and acc_b to the 0, 1, 2 and 3 index of c's expParams property (this gives us the corresponding values set in the EXP curve setting in the classes tab of the database). We then return the required exp based on a mathematical formula:

Let's say we're checking the required exp for level 2 in the Swordsman class (with a basis of 30, extra of 20, acc_a of 30 and acc_b of 30). Acceleration A is 30, which divided by 250 is 0.12. We add 0.9 to this for the power to apply to level minus 1, so we're taking 1 to the power of 1.02, which is 1. Base (30) is multiplied by this value, which gives us 30. Then we multiply that by level, giving us 60. That's multiplied by level plus 1 (3), giving us 180.

For the divisor, we square the level, which in this case is 4. We divide that by 50, giving us 0.08, then divide that by acceleration B, which is 30, giving us 0.00267 or thereabouts. Then we add 6 to that, giving us 6.00267. 180 / 6.00267 is 29.98665. Then we take level minus 1 (1) multiplied by extra as a multiplier, which is 20, and add that to 29.98665, giving us 49.98665. That's then rounded, and since the decimal is higher than 0.5, it gets rounded up to 50.

Now we look at level 5, and see how that changes things.

The exponent is still 1.02, since nothing has changed in that part of the calculation, but now we're taking 4 to that power, which is 4.11246. Base (30) multiplied by that value is 123.37366, multiplied by level is 616.86829, multiplied by level plus 1 is 3701.20978.

As for the divisor, level squared is 25, divided by 50 is 0.5, divided by acc_b is 0.01667, plus 6 for 6.01667. 3701.20978 / 6.01667 is 615.15918. Level minus 1 multiplied by extra is 80, and when we add those together we get 695.15918, rounded to 695. And so on and so forth.

Game_Actor.prototype.initExp = function() {
    this._exp[this._classId] = this.currentLevelExp();
};


This function initialises the actor's experience for their class. We set the key of _classId in the actor's _exp object to the return value of calling currentLevelExp(). This will set the amount of experience for the current class ID to be however much experience is required for the actor's current level. For example, if our Swordsman actor has an initial level of 3, the exp entry will be "1: 162".

Game_Actor.prototype.currentExp = function() {
    return this._exp[this._classId];
};


currentExp returns the actor's current experience in their class, and to do so we return the _classId key from _exp. For our previous Swordsman example, this will be _exp which will give us 162.

Game_Actor.prototype.currentLevelExp = function() {
    return this.expForLevel(this._level);
};


This function gets the amount of experience required to attain the actor's current level. Here we return the result of calling expForLevel passing in the value of _level.

Game_Actor.prototype.nextLevelExp = function() {
    return this.expForLevel(this._level + 1);
};


This function gets the amount of experience needed in total for the level above the actor's current one, and in this one we return the result of calling expForLevel passing in _level plus 1.

Game_Actor.prototype.nextRequiredExp = function() {
    return this.nextLevelExp() - this.currentExp();
};


This function gets the number of actual experience points needed to attain the next level. We return the result of nextLevelExp() minus the result of currentExp(). For example, if the actor is level 4 with 512 experience, the return value will be 695 - 512, or 183.

Game_Actor.prototype.maxLevel = function() {
    return this.actor().maxLevel;
};


This function gets the maximum possible level for the actor, and here we return the maxLevel property of the result from actor() (which will give us whatever was set as the "Max Level" in the Actors tab)

Game_Actor.prototype.isMaxLevel = function() {
    return this._level >= this.maxLevel();
};


This function determines whether the actor is at their maximum level. We return true if _level is greater than or equal to the return value of maxLevel(), and false otherwise.

Game_Actor.prototype.initSkills = function() {
    this._skills = [];
    this.currentClass().learnings.forEach(function(learning) {
        if (learning.level <= this._level) {
            this.learnSkill(learning.skillId);
        }
    }, this);
};


This function initialises the actor's skills. First, we set the _skills property to an empty array. Then, for each element in the current class's learnings array, we pass a function (using iteration variable "learning"). The function checks whether the level set in the learning entry is less than or equal to _level, and if so calls learnSkill passing in learning's skillId.

For example, if Swordsman learns Strong Attack at level 5 and Reid initialises at level 7, his learnings list will be { level: 5, note: "", skillId: 172 }. When this object passes through the function as "learning", learning.level wil be 5, and _level will be 7, so the condition is true and learnSkill will be called passing in 172, resulting in Reid learning Strong Attack.

Game_Actor.prototype.initEquips = function(equips) {
    var slots = this.equipSlots();
    var maxSlots = slots.length;
    this._equips = [];
    for (var i = 0; i < maxSlots; i++) {
        this._equips[i] = new Game_Item();
    }
    for (var j = 0; j < equips.length; j++) {
        if (j < maxSlots) {
            this._equips[j].setEquip(slots[j] === 1, equips[j]);
        }
    }
    this.releaseUnequippableItems(true);
    this.refresh();
};


This function initialises the actor's equipment in accordance with the database settings, and takes equips as a parameter. We set a variable called slots to the result of the equipSlots() function, giving us an array of slots and the equipment types that go into them, then a variable called maxSlots to the length of the slots array. We set _equips to an empty array.

Then we run a for loop with iteration variable i, starting at 0 and incrementing as long as i is less than maxSlots. In this loop, we set the element of _equips at index i to a new instance of the Game_Item class.

After this we run a for loop with iteration variable j, starting at 0 and incrementing as long as j is less than the length of the passed-in equips parameter. Here, if j is less than maxSlots, we call setEquip on the j index of _equips, passing in slots being equal to 1 for the isWeapon flag, and equips as the itemId argument.

After this, we call releaseUnequippableItems with the forcing flag set to true, which will remove anything the actor can't actually have on, and then refresh the actor to keep their data current.

Game_Actor.prototype.equipSlots = function() {
    var slots = [];
    for (var i = 1; i < $dataSystem.equipTypes.length; i++) {
        slots.push(i);
    }
    if (slots.length >= 2 && this.isDualWield()) {
        slots[1] = 1;
    }
    return slots;
};


This function gives us an array for each possible equip slot, with each element being the ID of the equipment type that goes in it.

We set a variable called slots to an empty array. Then we run a for loop with iteration variable i, starting at 1 and incrementing as long as i is less than the length of $dataSystem's equipTypes array (which contains the equipment types set in the database). In this loop, we simply push i to slots.

Then, if the length of slots is greater than or equal to 2 and isDualWield() returns true (the actor dual wields), we set the element of slots at index 1 to 1, which will change their second equipment slot to another weapon.

The way this has been coded basically mandates that your second equipment type always be an off-hand of some sort, otherwise dual-wielding actors will result in an equipment type replacement that's rather silly (and if you have an off-hand slot anywhere else, the actor will be able to dual wield AND equip off-hand items)

Game_Actor.prototype.equips = function() {
    return this._equips.map(function(item) {
        return item.object();
    });
};


This function gets the array of equipment objects equipped by the actor. We return a map function on _equips using iteration variable "item", with the passed-in function return the return value of item's object() function. This basically goes through an array of equipment ID numbers and gives us a new array with the actual objects representing the items for each ID.

Game_Actor.prototype.weapons = function() {
    return this.equips().filter(function(item) {
        return item && DataManager.isWeapon(item);
    });
};


This function gets an array of the actor's weapons; to do this, we run a filter on equips() using iteration variable "item", which returns any element for which item isn't null and DataManager's isWeapon function returns true with the item passed to it.

Game_Actor.prototype.armors = function() {
    return this.equips().filter(function(item) {
        return item && DataManager.isArmor(item);
    });
};


This is the same, but for armours.

Game_Actor.prototype.hasWeapon = function(weapon) {
    return this.weapons().contains(weapon);
};


This function checks whether the actor has a particular weapon, taking that weapon object as a parameter. We return true if the weapons() array contains the passed-in weapon, and false otherwise.

Game_Actor.prototype.hasArmor = function(armor) {
    return this.armors().contains(armor);
};


The same, but for armours.

Game_Actor.prototype.isEquipChangeOk = function(slotId) {
    return (!this.isEquipTypeLocked(this.equipSlots()[slotId]) &&
            !this.isEquipTypeSealed(this.equipSlots()[slotId]));
};


This function determines whether an equipment change is permitted for a particular slot, taking slotId as a parameter. We return true if the element of equipSlots() at index slotId isn't locked AND it isn't sealed.

Game_Actor.prototype.changeEquip = function(slotId, item) {
    if (this.tradeItemWithParty(item, this.equips()[slotId]) &&
            (!item || this.equipSlots()[slotId] === item.etypeId)) {
        this._equips[slotId].setObject(item);
        this.refresh();
    }
};


This function changes the item equipped in a particular slot with something else, taking slotId and replacement item as parameters.

If the result of calling tradeItemWithParty is true when we pass in item and the equipment at slotId in equips(), AND either there is no replacement item OR the equipment type ID of the replacement item is the same as the value of equipSlots() at index slotId, then we call setObject on the slotId key of _equips, passing in item, which sets the equipment object at that slot ID to the replacement item. Finally, we call refresh() on the actor.

Game_Actor.prototype.forceChangeEquip = function(slotId, item) {
    this._equips[slotId].setObject(item);
    this.releaseUnequippableItems(true);
    this.refresh();
};


This function forces an equipment change, again taking slotId and item as parameters. This is very similar to changeEquip but we don't have the tradeItemWithParty check because this is forcing an item of equipment into the slot whether the party has it or not.

So we call setObject passing in item as before. We do still have the call to releaseUnequippableItems to remove anything the actor couldn't actually have equipped, and then we call refresh().

Game_Actor.prototype.tradeItemWithParty = function(newItem, oldItem) {
    if (newItem && !$gameParty.hasItem(newItem)) {
        return false;
    } else {
        $gameParty.gainItem(oldItem, 1);
        $gameParty.loseItem(newItem, 1);
        return true;
    }
};


This function trades an equipped item with the party's inventory, taking newItem and oldItem as parameters.

If newItem exists AND the party doesn't have one, we return false, as we can only trade items we possess. Otherwise, we call $gameParty's gainItem function passing in oldItem as item and 1 as the quantity, and then loseItem passing in newItem and 1 as the quantity.

This result in the party gaining 1 of the item that was previously equipped, and losing one of the new one (since the old one has gone from equipment to inventory and the new one has gone from inventory to equipment).

Game_Actor.prototype.changeEquipById = function(etypeId, itemId) {
    var slotId = etypeId - 1;
    if (this.equipSlots()[slotId] === 1) {
        this.changeEquip(slotId, $dataWeapons[itemId]);
    } else {
        this.changeEquip(slotId, $dataArmors[itemId]);
    }
};


This function changes an item of equipment by ID, which gives us an easier way to do it than always needing a full item object. It takes two parameters, etypeId (equipment type ID) and itemId (item ID).

We set a variable called slotId to etypeId minus 1 (since slots are 0-indexed and equipment types aren't). If the element at the slotId index of equipSlots() is 1 (meaning it's a weapon), we call changeEquip passing in slotId and the itemId index of $dataWeapons. Otherwise, it's armour, so we make the same call but using $dataArmors instead.

Game_Actor.prototype.isEquipped = function(item) {
    return this.equips().contains(item);
};


This function determines whether the actor has a particular item equipped, taking item as a parameter. We return whether equips() contains the item passed in.

Game_Actor.prototype.discardEquip = function(item) {
    var slotId = this.equips().indexOf(item);
    if (slotId >= 0) {
        this._equips[slotId].setObject(null);
    }
};


This function discards a piece of equipment, taking item as a parameter. We set a variable called slotId to the result of calling indexOf on equips() passing in item (which gives us the index in the array where the passed-in item is present). If slotId is greater than or equal to 0 (meaning the item was found) we set the object of that element in _equips to null.

Game_Actor.prototype.releaseUnequippableItems = function(forcing) {
    for (;;) {
        var slots = this.equipSlots();
        var equips = this.equips();
        var changed = false;
        for (var i = 0; i < equips.length; i++) {
            var item = equips[i];
            if (item && (!this.canEquip(item) || item.etypeId !== slots[i])) {
                if (!forcing) {
                    this.tradeItemWithParty(null, item);
                }
                this._equips[i].setObject(null);
                changed = true;
            }
        }
        if (!changed) {
            break;
        }
    }
};


This function unequips anything the actor can't have equipped, and takes a forcing flag as a parameter.

Here we have an infinite for loop: it has no loop variable, no condition and no incrementor. It will, in the absence of anything inside the loop which breaks it, continue running indefinitely. It's the equivalent of while (true), and you need to be really careful using loops like this as they can lock up your game if you don't terminate them properly.

We set a variable called slots to the result of calling equipSlots(), one called equips to the result of equips(), and one called changed to false.

We then run another for loop using iteration variable i which starts at 0, and increments as long as i is less than the length of equips. In the loop, we set a variable called item to the element of equips at index i. We check if the item exists AND either canEquip returns false when we pass in the item OR the item's etypeId is not equal to the value in slots at index i, If so, we check whether forcing is false. If it is, we call tradeItemWithParty passing in null as newItem and item as oldItem. Then we set the object in _equips at index i to null, and set changed to true. After this for loop, if changed is false we break out of the outer loop.

This might look redundant, but there's actually a very good reason for it. Let's say the actor is wearing a piece of armour that allows you to equip guns, and they currently have a gun equipped. If for some reason the armour becomes unequippable, it'll be removed from the equipment but the gun's already been checked. So we need to go through the whole process again, which will remove the gun. Only when there's no unequippable items left does the infinite loop end.

Game_Actor.prototype.clearEquipments = function() {
    var maxSlots = this.equipSlots().length;
    for (var i = 0; i < maxSlots; i++) {
        if (this.isEquipChangeOk(i)) {
            this.changeEquip(i, null);
        }
    }
};


This function clears all of the actor's equipment. We set a variable called maxSlots to the length of the result from calling equipSlots(). We run a for loop using iteration variable i, incrementing as long as i is less than maxSlots. In each loop, we check whether isEquipChangeOk returns true when we pass in i, and if so we call changeEquip passing in i as slotId and null as item.

Game_Actor.prototype.optimizeEquipments = function() {
    var maxSlots = this.equipSlots().length;
    this.clearEquipments();
    for (var i = 0; i < maxSlots; i++) {
        if (this.isEquipChangeOk(i)) {
            this.changeEquip(i, this.bestEquipItem(i));
        }
    }
};


This function is called when the player chooses the "Optimize" option in the equipment scene. We set a variable called maxSlots to the length of equipSlots(), then call clearEquipments() to remove anything the actor already has on. We run a for loop with iteration variable i, incrementing as long as i is less than maxSlots. In the loop, if isEquipChangeOk returns true when i is passed in, we call changeEquip passing in i and the result of calling bestEquipItem with i passed in. This will place the best possible item from inventory in each slot (though more on that in a bit...)

Game_Actor.prototype.bestEquipItem = function(slotId) {
    var etypeId = this.equipSlots()[slotId];
    var items = $gameParty.equipItems().filter(function(item) {
        return item.etypeId === etypeId && this.canEquip(item);
    }, this);
    var bestItem = null;
    var bestPerformance = -1000;
    for (var i = 0; i < items.length; i++) {
        var performance = this.calcEquipItemPerformance(items[i]);
        if (performance > bestPerformance) {
            bestPerformance = performance;
            bestItem = items[i];
        }
    }
    return bestItem;
};


This function gets the best item of equipment for a slot, taking slotId as a parameter. We set a variable called typeId to the element of equipSlots() as index slotId, and one called items to equipItems() filtered with a function that returns any item for which its etypeId is equal to the etypeId variable AND the actor can equip the item being checked. Then we set a variable called bestItem to null and one called bestPerformance to -1000. We run a for loop with iteration variable i, incrementing as long as i is less than the length of items. In this loop, we set a variable called performance to the result of calcEquipItemPerformance() passing in the element of items at index i. If performance is greater than bestPerformance, we set bestPerformance to performance, and bestItem to the item at index i. After the for loop, we return bestItem.

But there's a glaring problem with this, as we'll see in just a sec.

Game_Actor.prototype.calcEquipItemPerformance = function(item) {
    return item.params.reduce(function(a, b) {
        return a + b;
    });
};


This function calculates the "performance rating" of an item, taking item as a parameter. We return the item's params reduced, using a as the accumulator and b as the current param, and in the function return a + b, which basically gives us a cumulative total of parameter bonuses on the piece of equipment.

For example, a sword with +8 attack, +2 defence and +10 max HP will have a performance rating of 8+2+10, or 20.

And the nature of this function points to the inherent flaw with the default implementation of equipment optimisation: it takes into account parameter bonuses and only parameter bonuses. Traits are never considered. You might not think this much of an issue until you stop to think that if you have a piece of armour with 8 def which makes you immune to death, trebles max HP, adds a new heal skill, gives the user 5 extra attacks in battle and lets the actor equip a top-secret weapon type that's only usable with that armour on, and another piece of armour with 10 def, the optimize command will equip you with the latter.

This is the very problem for which I created my equipment optimisation script/plugin, which allows you to consider traits when calculating item performance. The MZ version isn't available yet, but hopefully will be soon.

Game_Actor.prototype.isSkillWtypeOk = function(skill) {
    var wtypeId1 = skill.requiredWtypeId1;
    var wtypeId2 = skill.requiredWtypeId2;
    if ((wtypeId1 === 0 && wtypeId2 === 0) ||
            (wtypeId1 > 0 && this.isWtypeEquipped(wtypeId1)) ||
            (wtypeId2 > 0 && this.isWtypeEquipped(wtypeId2))) {
        return true;
    } else {
        return false;
    }
};


This function checks whether a skill's weapon type requirements are met, taking skill as a parameter. We set a variable called wtypeId1 to the requiredWtypeId1 of the passed-in skill, and one called wtypeId2 to its requiredWtypeId2. If (both wtypeId1 AND wtypeId2 are equal to 0), OR (wtypeId1 is greater than 0 AND isWtypeEquipped returns true with wtypeId1 passed in) OR (wtypeId2 is greater than 0 AND isWtypeEquipped returns true with wtypeId2 passed in), we return true. Otherwise, we return false.

Game_Actor.prototype.isWtypeEquipped = function(wtypeId) {
    return this.weapons().some(function(weapon) {
        return weapon.wtypeId === wtypeId;
    });
};


This function checks whether the actor has a given weapon type equipped, taking wtypeId as a parameter. We return a some filter on weapons() using iteration variable "weapons", returning true if any weapon's wtypeId is equal to the passed-in wtypeId.

Game_Actor.prototype.refresh = function() {
    this.releaseUnequippableItems(false);
    Game_Battler.prototype.refresh.call(this);
};


Game_Actor's implementation of refresh first calls releaseUnequippableItems (passing in false as the forcing argument) before calling the parent function.

Game_Actor.prototype.isActor = function() {
    return true;
};


Our overwrite of isActor simply returns true, because, well, in this case it always will be.

Game_Actor.prototype.friendsUnit = function() {
    return $gameParty;
};


The overwrite for friendsUnit returns $gameParty, as that is the object representing the unit which is friendly to an actor.

Game_Actor.prototype.opponentsUnit = function() {
    return $gameTroop;
};


Consequently, opponentsunit returns $gameTroop, since that's the object representing an actor's enemies.

Game_Actor.prototype.index = function() {
    return $gameParty.members().indexOf(this);
};


This function gets the actor's index in the party, and here we return the result of calling indexOf on $gameParty's members() array passing in "this", which in this context will be the Game_Actor instance. Obviously this will only return a positive value if the actor is actually in the party, otherwise it'll return -1.

Game_Actor.prototype.isBattleMember = function() {
    return $gameParty.battleMembers().contains(this);
};


This function determines whether the actor is a battle member (that is to say, will be present in battles). For this, we return whether $gameParty's battleMembers() array contains "this", which again is the current Game_Actor instance.

Game_Actor.prototype.isFormationChangeOk = function() {
    return true;
};


This function determines whether the player can change the party order. We always return true here as by default there are no circumstances under which formation change isn't permitted unless the actual command is disabled, in which case we won't need to check this in the first place.

Game_Actor.prototype.currentClass = function() {
    return $dataClasses[this._classId];
};


This function gets the actor's current class object. We return the element of $dataClasses at an index of _classId.

Game_Actor.prototype.isClass = function(gameClass) {
    return gameClass && this._classId === gameClass.id;
};


This function determines whether the actor's class is a specified class object (as in actor job), taking gameClass as a parameter. We return the result of checking that gameClass has a value AND _classId is equal to gameClass's id. It's only used in one place: the conditional branch case that checks whether an actor has a particular class.

Game_Actor.prototype.skills = function() {

var list = [];
this._skills.concat(this.addedSkills()).forEach(function(id) {
if (!list.contains($dataSkills[id])) {
list.push($dataSkills[id]);
}
});
return list;
};


This function gets the actor's list of skills. We set a variable called list to an empty array. Then we run a forEach loop on the _skills array concatenated with the result of calling addedSkills, using iteration variable "id". In that function, if list does not contain the element of $dataSkills with index id, we push $dataSkills to list. After the forEach, we return list.

Game_Actor.prototype.usableSkills = function() {

return this.skills().filter(function(skill) {
return this.canUse(skill);
}, this);
};


This function, on the other hand, gets the list of an actor's usable skills. We return a filtered array of skills() using iteration variable "skill", where the provided function returns the result of calling canUse passing in skill. This will give us an array of skill objects which the actor is able to use.

Game_Actor.prototype.traitObjects = function() {
    var objects = Game_Battler.prototype.traitObjects.call(this);
    objects = objects.concat([this.actor(), this.currentClass()]);
    var equips = this.equips();
    for (var i = 0; i < equips.length; i++) {
        var item = equips[i];
        if (item) {
            objects.push(item);
        }
    }
    return objects;
};


This function gets an array of objects which may provide the actor with traits. We set a variable called objects to the result of calling Game_Battler's prototype's traitObjects function passing in "this", which gives us any states on the actor which provide traits. Then we set objects to itself concatenated with the actor() object and currentClass(), which adds on whatever traits the actor and their class provide. Then we set a variable called equips to the result of equips(). We run a for loop with iteration variable i, incrementing as long as i is less than the length of equips. In that loop, we set variable item to the element of equips at index i. If item exists, we push it to the objects array. And finally, we return objects.

Game_Actor.prototype.attackElements = function() {
    var set = Game_Battler.prototype.attackElements.call(this);
    if (this.hasNoWeapons() && !set.contains(this.bareHandsElementId())) {
        set.push(this.bareHandsElementId());
    }
    return set;
};


This function gets the actor's attack elements. We set variable "set" to the result of calling Game_Battler's prototype's attackElements function, passing in "this" (this gives us any "attack element" traits on any object affecting the actor). Then if hasNoWeapons() returns true AND set doesn't contain the bareHandsElementId, we push bareHandsElementId to set. Finally we return set, giving us an array of all element IDs the actor's attack will consist of.

Game_Actor.prototype.hasNoWeapons = function() {
    return this.weapons().length === 0;
};


This function determines whether the actor has no weapons equipped (is bare-handed). We return true if weapons() has a length of 0.

Game_Actor.prototype.bareHandsElementId = function() {
    return 1;
};


This function gets the element ID considered to be "bare hands". We return 1, which is always considered to be "Physical".

Game_Actor.prototype.paramMax = function(paramId) {
    if (paramId === 0) {
        return 9999;    // MHP
    }
    return Game_Battler.prototype.paramMax.call(this, paramId);
};


This function gets the maximum value for a parameter (a game parameter, not a code parameter), taking paramId as a parameter (a code parameter, not a game parameter). If paramId is 0 (meaning it's Max HP) we return 9999. Otherwise, we return the result of calling Game_Battler's prototype's paramMax function (which will return 9999 for max MP or 999 for any other parameter).

Game_Actor.prototype.paramBase = function(paramId) {
    return this.currentClass().params[paramId][this._level];
};


This function determines the base parameter value for a parameter, taking paramId as a (code) parameter. We return a 2D array reference from the params array of currentClass(), using paramId as the first index and _level as the second.

A 2D array, quite simply, is just having an array inside an array. The more arrays are nested, the more indexes are required to reference them. So if we have an array called example containing [, , ], example will return and example will return 4.

params, as I covered in my primer on data class mapping on the rpgmakerweb forums, contains 8 elements, one for each parameter, and each element is a 99-element array containing the value for that parameter for each game level the actor can be. So for example, if currentClass() is Swordsman, _level is 5 and paramId is 2 (attack power), the return value will be $dataClasses.params, which evaluates to 27.

Now this may appear confusing since the index for $dataClasses used the actual ID for the class, whereas both elements in params started at 0 rather than 1. This is just because of how the engine stores database entries; the 0 element is always null so that the references to database objects use the same indexes as the database itself does.

Game_Actor.prototype.paramPlus = function(paramId) {
    var value = Game_Battler.prototype.paramPlus.call(this, paramId);
    var equips = this.equips();
    for (var i = 0; i < equips.length; i++) {
        var item = equips[i];
        if (item) {
            value += item.params[paramId];
        }
    }
    return value;
};


This function gets the actor's parameter bonuses for a given parameter, taking paramId as a (code) parameter.

We set variable "value" to the result of Game_Battler's prototype's paramPlus function, passing in paramId, which gives us the value in the _paramPlus array at index paramId. Then we set variable "equips" to equips(). We run a for loop using iteration variable i, incrementing as long as i is less than the length of equips. We set variable "item" to the element of equips at index i, and if an item exists we add the element of the item's params at index paramId to value. Finally, we return value.

Example time!

Let's say the actor got +20 defence from an item effect, and they have have a shield that gives 15 def, a piece of armour that gives 22 def and an accessory that provides 10. If we call paramPlus(3) the return value will end up being 67.

Game_Actor.prototype.attackAnimationId1 = function() {
    if (this.hasNoWeapons()) {
        return this.bareHandsAnimationId();
    } else {
        var weapons = this.weapons();
        return weapons[0] ? weapons[0].animationId : 0;
    }
};


This function gets the actor's first attack animation. If hasNoWeapons() returns true, we return the result of bareHandsAnimationId, otherwise we set variable "weapons" to weapons() and then return weapons's animationId if there is a weapon at index 0, or 0 otherwise.

Game_Actor.prototype.attackAnimationId2 = function() {
    var weapons = this.weapons();
    return weapons[1] ? weapons[1].animationId : 0;
};


This function gets the actor's second attack animation. We set variable "weapons" to weapons(), and then return weapons's animationId if there is a weapon at index 1, or 0 otherwise.

The reason we have 2 of these functions is to allow for dual wielding, since each equipped weapon might have a different animation associated with it.

Game_Actor.prototype.bareHandsAnimationId = function() {
    return 1;
};


This function gets the "bare hands" animation ID, and we simply return 1. This will cause a bare hands attack to use the "Hit Physical" animation.

Game_Actor.prototype.changeExp = function(exp, show) {
    this._exp[this._classId] = Math.max(exp, 0);
    var lastLevel = this._level;
    var lastSkills = this.skills();
    while (!this.isMaxLevel() && this.currentExp() >= this.nextLevelExp()) {
        this.levelUp();
    }
    while (this.currentExp() < this.currentLevelExp()) {
        this.levelDown();
    }
    if (show && this._level > lastLevel) {
        this.displayLevelUp(this.findNewSkills(lastSkills));
    }
    this.refresh();
};


This function changes the actor's experience to a specified value, taking as parameters exp (the total exp count to set the actor to) and show (a binary flag determining whether the game will display a message if the actor levels up).

We set the key of _exp at _classId to the maximum value between the passed-in exp value and 0. We also set variables lastLevel to _level and lastSkills to the actor's skills() array. While isMaxLevel returns false AND currentExp() returns a value greater than or equal to nextLevelExp() (meaning the actor has enough experience to reach the level above their current one) we call the levelUp() function. Then, while currentExp() is less than currentLevelExp() (meaning the actual has less exp than the current level requires) we call levelDown(). This is needed because exp can be a negative number. Then, if show is true AND _level is greater than lastLevel, we call displayLevelUp, passing in the result of calling findNewSkills with lastSkills as the argument. That's a pretty big line to parse, but suffice to say it will basically add any skills available to the actor at their new level which they didn't already have. And finally, we refresh the actor.

Game_Actor.prototype.levelUp = function() {
    this._level++;
    this.currentClass().learnings.forEach(function(learning) {
        if (learning.level === this._level) {
            this.learnSkill(learning.skillId);
        }
    }, this);
};


This function levels the actor up. We increment _level by 1, then run a forEach loop on the currentClass()'s learnings list, using iteration variable "learning"; if the level of the learning object is equal to _level, we call learnSkill passing in learning's skillId. In other words, if the new level is high enough to learn a skill, the actor will learn it.

Game_Actor.prototype.levelDown = function() {
    this._level--;
};


This function levels the actor down. Here we decrement _level by 1. Note that an actor won't lose any skills they already learned from higher levels, a level decrease will only affect parameters.

Game_Actor.prototype.findNewSkills = function(lastSkills) {
    var newSkills = this.skills();
    for (var i = 0; i < lastSkills.length; i++) {
        var index = newSkills.indexOf(lastSkills[i]);
        if (index >= 0) {
            newSkills.splice(index, 1);
        }
    }
    return newSkills;
};


This function gets any new skills the actor should have that they don't already. It takes lastSkills as a parameter, which as we saw just a minute ago is an array of the skills the actor had before the level changed.

We set variable "newSkills" to skills() (which will now be current for the actor's level). Then we run a for loop using iteration variable i, starting at 0 and incrementing as long as i is less than the length of lastSkills. Inside the loop, we set "index" to the indexOf in newSkills which matches the i index element of lastSkills (in other words, get the index of newSkills which contains the previous skill in the list in each run of the loop). If index is greater than or equal to 0, meaning there was a match, we splice 1 element out of newSkills starting at "index", which removes the matched skill from the list. Finally we return newSkills.

As may be apparent, this process will leave us with an array of skills which were *not* matched in lastSkills, which means they're skills the actor didn't have before the actor's level changed.

Game_Actor.prototype.displayLevelUp = function(newSkills) {
    var text = TextManager.levelUp.format(this._name, TextManager.level, this._level);
    $gameMessage.newPage();
    $gameMessage.add(text);
    newSkills.forEach(function(skill) {
        $gameMessage.add(TextManager.obtainSkill.format(skill.name));
    });
};


This function displays a level up message for the actor, and takes newSkills as a parameter. We set "text" to the levelUp string in TextManager, formatted to replace the first wildcard with _name, the second with the level string from TextManager, and the third with _level. This will give us a string like "Reid is now Level 3!" Then we call the newPage() function in $gameMessage, which gives us a new message page, and add() passing in text, which will display the text in a game message window. Finally, we run a forEach loop on newSkills with iteration variable "skill", adding to $gameMessage another formatted string: this one is TextManager.obtainSkill, formatted to replace the first wildcard with the skill's name. This gives us something like "Strong Attack learned!".

Game_Actor.prototype.gainExp = function(exp) {
    var newExp = this.currentExp() + Math.round(exp * this.finalExpRate());
    this.changeExp(newExp, this.shouldDisplayLevelUp());
};


This function increases an actor's exp by a certain amount, or decreases if the argument is negative. It takes exp as a parameter.

We set variable "newExp" to the result of currentExp() plus the rounded result of exp multiplied by finalExpRate(). Basically all this does is modifies the passed-in value based on the actor's experience rate parameter, as we'll see in a second. Then when we have the modified value, we call changeExp passing in the newExp value as the exp argument and the result of shouldDisplayLevelUp() as the show argument.

Game_Actor.prototype.finalExpRate = function() {
    return this.exr * (this.isBattleMember() ? 1 : this.benchMembersExpRate());
};


This function is the one called above where we calculate what the modification rate for exp should be. Here we're returning the actor's exr property multiplied by either 1 if the actor is a battle member, or the result of benchMembersExpRate() otherwise.

Game_Actor.prototype.benchMembersExpRate = function() {
    return $dataSystem.optExtraExp ? 1 : 0;
};


This function calculates the rate at which non-battle party members should gain exp. We either return 1 if optExtraExp in $dataSystem is true, or 0 if it isn't (this maps to the "EXP for Reserve Members" checkbox in the System 1 database tab).

Game_Actor.prototype.shouldDisplayLevelUp = function() {
    return true;
};


This function determines whether levelling up should be displayed in a message. We just return true here, because we always want to do that for actors.

Game_Actor.prototype.changeLevel = function(level, show) {
    level = level.clamp(1, this.maxLevel());
    this.changeExp(this.expForLevel(level), show);
};


This function changes the actor's level to a specified value. It takes level and show as parameters.

We set level to itself, clamped to 1 and maxLevel(), which will ensure it is never below or above those values. Then we call changeExp(), passing in the result of expForLevel() passing in level, and show as the show argument.

Game_Actor.prototype.learnSkill = function(skillId) {
    if (!this.isLearnedSkill(skillId)) {
        this._skills.push(skillId);
        this._skills.sort(function(a, b) {
            return a - b;
        });
    }
};


This function teaches a particular skill to the actor, and takes skillId as a parameter. If isLearnedSkill returns false when skillId is passed in, we push its value to _skills, then call sort on _skills passing in a function with a and b as function variables, and in that function return a - b. This will sort our skill list in order of how they're listed in the database (since they're sorted by ID).

Game_Actor.prototype.forgetSkill = function(skillId) {
    var index = this._skills.indexOf(skillId);
    if (index >= 0) {
        this._skills.splice(index, 1);
    }
};


This function removes a skill from the actor's list, again taking skillId as a parameter. We set variable "index" to the indexOf in _skills containing skillId, then if index is greater than or equal to 0 (meaning the actor has that skill ID in their list), we splice 1 element from _skills starting at index, which removes that ID.

Game_Actor.prototype.isLearnedSkill = function(skillId) {
    return this._skills.contains(skillId);
};


This function determines whether the actor knows a skill, taking skillId as a parameter. We return whether _skills contains the passed-in value.

Note that this will only take into account skills which the actor learns naturally via their class. It will NOT return true if the skill was given to them by a trait, be that an innate actor trait, or from their class, or from equipment. For that you'll need...

Game_Actor.prototype.hasSkill = function(skillId) {
    return this.skills().contains($dataSkills[skillId]);
};


This function determines whether the actor *has* a skill, taking skillId as a parameter We return whether skills() contains the element of $dataSkills at index skillId. This *will* include any skills taught by traits on the actor/class/equipment, as skills() includes added skills from said traits while _skills does not.

Game_Actor.prototype.changeClass = function(classId, keepExp) {
    if (keepExp) {
        this._exp[classId] = this.currentExp();
    }
    this._classId = classId;
    this.changeExp(this._exp[this._classId] || 0, false);
    this.refresh();
};


This function changes the actor's class, taking classId and keepExp as parameters. If keepExp is true, we set the key of classId in _exp to the result of currentExp(), which sets the exp for the new class to that of the old one. Then we set _classId to the passed-in classId, and call changeExp passing in the key value for _classId in _exp or 0 if that value doesn't exist yet, and false for the "show" argument. Finally, we refresh the actor.

Note that while keepExp retains the exp *value*, the new class may have a different experience curve from the old one, resulting in the actor's level in that class being lower or higher than it was before.

Game_Actor.prototype.setCharacterImage = function(characterName, characterIndex) {
    this._characterName = characterName;
    this._characterIndex = characterIndex;
};

Game_Actor.prototype.setFaceImage = function(faceName, faceIndex) {
    this._faceName = faceName;
    this._faceIndex = faceIndex;
};

Game_Actor.prototype.setBattlerImage = function(battlerName) {
    this._battlerName = battlerName;
};


This set of functions serve to set the various graphic files and indexes for the actor's walking graphic, face image and battler image respectively. They simply take filenames/indexes as parameters and set their respective internal variables to the values passed in.

Game_Actor.prototype.isSpriteVisible = function() {
    return $gameSystem.isSideView();
};


This function determines whether the actor's sprite will be visible in battle. Here we return the result of isSideView() in $gameSystem, which will return true if the Battle Screen setting in System 1 is "Side-View", and false otherwise.

Game_Actor.prototype.startAnimation = function(animationId, mirror, delay) {
    mirror = !mirror;
    Game_Battler.prototype.startAnimation.call(this, animationId, mirror, delay);
};


This function begins the process of playing an animation on the actor. It takes animationId, mirror and delay as parameters. First we set mirror to the negated form of mirror (so if it's true it becomes false, and if it's false it becomes true) and then we call the parent function passing in the same parameters.

Game_Actor.prototype.performActionStart = function(action) {
    Game_Battler.prototype.performActionStart.call(this, action);
};


This function performs the start of an action, taking action as a parameter. All we're doing here is calling the parent function, so honestly this isn't needed as it doesn't do anything the function in Game_Battler didn't.

Game_Actor.prototype.performAction = function(action) {
    Game_Battler.prototype.performAction.call(this, action);
    if (action.isAttack()) {
        this.performAttack();
    } else if (action.isGuard()) {
        this.requestMotion('guard');
    } else if (action.isMagicSkill()) {
        this.requestMotion('spell');
    } else if (action.isSkill()) {
        this.requestMotion('skill');
    } else if (action.isItem()) {
        this.requestMotion('item');
    }
};


This function performs the motion associated with a given action type, taking action as a parameter. First we call the parent function, but then we actually do new stuff!

If isAttack() returns true on action, indicating that it's a standard attack command, we call performAttack(). Otherwise, if isGuard() returns true, indicating that it's a guard command, we call requestMotion passing in 'guard'. Otherwise, if isMagicSkill() returns true, indicating that the action's skill type is included in the "Magic Skills" setting of the System 2 tab, we call requestMotion passing in 'spell'. Otherwise, if isSkill() returns true, indicating that the action is a skill, we call requestMotion passing in 'skill. Finally, if all else fails an isItem() returns true, indicating that the player is using an item, we call requestMotion passing in 'item'.

Game_Actor.prototype.performActionEnd = function() {
    Game_Battler.prototype.performActionEnd.call(this);
};


This function performs the end of an action, and all it does is call the parent function. Again, it doesn't need to do this, as it already has access to the one from Game_Battler via its prototype.

Game_Actor.prototype.performAttack = function() {
    var weapons = this.weapons();
    var wtypeId = weapons[0] ? weapons[0].wtypeId : 0;
    var attackMotion = $dataSystem.attackMotions[wtypeId];
    if (attackMotion) {
        if (attackMotion.type === 0) {
            this.requestMotion('thrust');
        } else if (attackMotion.type === 1) {
            this.requestMotion('swing');
        } else if (attackMotion.type === 2) {
            this.requestMotion('missile');
        }
        this.startWeaponAnimation(attackMotion.weaponImageId);
    }
};


This function performs the standard attack motion for the actor.

We set variable "weapons" to weapons(), giving us an array of the weapons the character has equipped, and wtypeId to the wtypeId of the 0-index element of weapons if there is one, or 0 otherwise. Then we set variable "attackMotion" to the element of $dataSystem's attackMotions array at index wtypeId. For example, if the actor's first weapon is a sword, the wtypeId will be 2, and $dataSystem.attackMotions will give us {type: 1, weaponImageId: 2}.

If attackMotion returns data, we check its type property. If it's 0, we call requestMotion passing in 'thrust'. If it's 1, we pass in 'swing', and if it's 2 we pass in 'missile'. In our example, this means sword-type weapons will perform a swinging motion. We then call startWeaponAnimation passing in the attackMotion's weaponImageId, which will display the weapon graphic alongside the actor's motion.

Interesting to note is that in the event a dual wielding actor has two different weapon types equipped, you won't see a graphic or motion for the second one; the actor will perform a single attack motion using the settings for their first weapon.

Game_Actor.prototype.performDamage = function() {
    Game_Battler.prototype.performDamage.call(this);
    if (this.isSpriteVisible()) {
        this.requestMotion('damage');
    } else {
        $gameScreen.startShake(5, 5, 10);
    }
    SoundManager.playActorDamage();
};


This function performs the effect of the actor taking damage. First we call the parent function. Then, if isSpriteVisible() returns true, we call requestMotion passing in 'damage'. Otherwise, we call startShake() in $gameScreen, passing in 5 for power, 5 for speed and 10 for duration (giving us a 5-power, 5-speed shake for 10 frames). Then we call playActorDamage() in SoundManager to play the actor damage sound effect.

Game_Actor.prototype.performEvasion = function() {
    Game_Battler.prototype.performEvasion.call(this);
    this.requestMotion('evade');
};


This function performs an evade effect. First we call the parent function, then requestMotion passing in 'evade'.

Game_Actor.prototype.performMagicEvasion = function() {
    Game_Battler.prototype.performMagicEvasion.call(this);
    this.requestMotion('evade');
};


This function performs a magic evade effect. It's functionally identical to performEvasion besides the parent call as there's no graphical variation between evading magic and evading anything else; the only difference is the sound effect.

Game_Actor.prototype.performCounter = function() {
    Game_Battler.prototype.performCounter.call(this);
    this.performAttack();
};


This function performs a counterattack effect. First we call the parent function, and then performAttack() as a counterattack is just a standard attack in response to being hit.

Game_Actor.prototype.performCollapse = function() {
    Game_Battler.prototype.performCollapse.call(this);
    if ($gameParty.inBattle()) {
        SoundManager.playActorCollapse();
    }
};


This function performs the collapse effect when the actor dies. First we call the parent function, then if $gameParty's inBattle() function returns true, we call playActorCollapse() in SoundManager, which plays the actor death SE (theoretically there was no reason to call the function from Game_Battler's prototype, as it does nothing).

Game_Actor.prototype.performVictory = function() {
    if (this.canMove()) {
        this.requestMotion('victory');
    }
};


This function performs the victory effect when the party is victorious in battle. If canMove() returns true, we call requestMotion passing in 'victory'. It would be pretty funny if we didn't have that if statement because dead and disabled characters would start cheering otherwise!

Game_Actor.prototype.performEscape = function() {
    if (this.canMove()) {
        this.requestMotion('escape');
    }
};


This function performs the escape effect when the party scarpers absconds or gets the frock out of there. Again if canMove() returns true we call requestMotion passing in 'escape'. And again, this check is to avoid dead characters suddenly getting up and starting to run, which would be silly.

Game_Actor.prototype.makeActionList = function() {
    var list = [];
    var action = new Game_Action(this);
    action.setAttack();
    list.push(action);
    this.usableSkills().forEach(function(skill) {
        action = new Game_Action(this);
        action.setSkill(skill.id);
        list.push(action);
    }, this);
    return list;
};


This function gives us a list of actions the actor could possibly take, for the purposes of the "Auto Battle" command. We set variable "list" to an empty array, and "action" to a new instance of Game_Action passing in the actor instance as the actor argument. We call setAttack() on the action to initialise it as a standard attack, and push that action to the list array. Then, we run a forEach loop on usableSkills(), using "skill" as our function variable. In the passed function, we reassign action as a new instance of Game_Action, again passing in the actor instance as our actor argument, and setSkill passing in skill's id, then push that action to list. Finally, we return list, which in the end will be an array of Game_Action objects representing every possible skill the actor is capable of using at the time.

Game_Actor.prototype.makeAutoBattleActions = function() {
    for (var i = 0; i < this.numActions(); i++) {
        var list = this.makeActionList();
        var maxValue = Number.MIN_VALUE;
        for (var j = 0; j < list.length; j++) {
            var value = list[j].evaluate();
            if (value > maxValue) {
                maxValue = value;
                this.setAction(i, list[j]);
            }
        }
    }
    this.setActionState('waiting');
};


This function creates a list of autobattle actions for the actor to take when that option is selected. We run a for loop using loop variable i, starting at 0 and incrementing as long as i is less than the return value of numActions(). We set variable "list" to the result of makeActionList(), and maxValue to the MIN_VALUE property of the Number class. Then we run an inner for loop using variable j, which also starts at 0 and increments as long as j is less than the length of list. We set variable "value" to the result of calling evaluate() on the element of list at index j, which will test out the skill and see how it performs. If the value returned is greater than maxValue, we set maxValue to value and setAction passing in i as the action index and the action at index j in list as the action. Note that because we initially set maxValue to the minimum possible value for a Number, the first loop will always return true here, ensuring that the actor will at least choose "attack".

Game_Actor.prototype.makeConfusionActions = function() {
    for (var i = 0; i < this.numActions(); i++) {
        this.action(i).setConfusion();
    }
    this.setActionState('waiting');
};


This function makes the action list for the actor when they're confused. We run a for loop using variable i, starting at 0 and incrementing as long as i is less than numActions(). In each iteration, we call setConfusion on a call to the action() function, passing in i. After the for loop, we call setActionState, passing in 'waiting'.

Functionally, this queues up a standard attack for each potential action the actor can take, and tells the engine that they're waiting for a turn to start.

Game_Actor.prototype.makeActions = function() {
    Game_Battler.prototype.makeActions.call(this);
    if (this.numActions() > 0) {
        this.setActionState('undecided');
    } else {
        this.setActionState('waiting');
    }
    if (this.isAutoBattle()) {
        this.makeAutoBattleActions();
    } else if (this.isConfused()) {
        this.makeConfusionActions();
    }
};


In our overwrite to makeActions, first we call the parent function. Then if numActions() is greater than 0, we set the actor's action state to 'undecided'. Otherwise, we set it to 'waiting'. Then, if isAutoBattle() returns true, we call makeAutoBattleActions(), and otherwise, if isConfused() returns true, we call makeConfusionActions().

This will result in the actor being undecided if they have more than 0 actions to select, and waiting if they have no actions. If they're set to auto battle, their actions will be decided for them, and if they're confused all of their action slots will be filled with a standard attack action.

Game_Actor.prototype.onPlayerWalk = function() {
    this.clearResult();
    this.checkFloorEffect();
    if ($gamePlayer.isNormal()) {
        this.turnEndOnMap();
        this.states().forEach(function(state) {
            this.updateStateSteps(state);
        }, this);
        this.showAddedStates();
        this.showRemovedStates();
    }
};


This function is called when the player takes a step. We call clearResult() and then checkFloorEffect(), which clears the actor's action results object and looks to see if the actor is on a damage-type floor tile. Then, if $gamePlayer's isNormal() function returns true (which it will if the player is not in a vehicle or currently in a forced move route) we call turnEndOnMap(), then run a forEach loop on states() calling updateStateSteps for each state, then call showAddedStates() and showRemovedStates(). This will update each state's step count and display any states added/removed by the process.

Game_Actor.prototype.updateStateSteps = function(state) {
    if (state.removeByWalking) {
        if (this._stateSteps[state.id] > 0) {
            if (--this._stateSteps[state.id] === 0) {
                this.removeState(state.id);
            }
        }
    }
};


This function updates the steps for a state, taking the state as a parameter. If the state's removeByWalking flag is true, we check whether the element of _stateSteps at an index of the state's ID is greater than 0. If so, we check whether decrementing that element of _stateSteps results in 0, and if so we call removeState passing in the state's ID.

Note that --this._stateSteps is NOT the same thing as this._stateSteps--. The former will decrement the value before the comparison, the latter will decrement it after. So if the -- were on the other side, this condition would actually return false at the point where the value becomes 0. Just an interesting tidbit.

Game_Actor.prototype.showAddedStates = function() {
    this.result().addedStateObjects().forEach(function(state) {
        if (state.message1) {
            $gameMessage.add(this._name + state.message1);
        }
    }, this);
};

Game_Actor.prototype.showRemovedStates = function() {
    this.result().removedStateObjects().forEach(function(state) {
        if (state.message4) {
            $gameMessage.add(this._name + state.message4);
        }
    }, this);
};


Lumping these two together as they're almost identical. These functions show added/removed states on the actor. We run a forEach loop on the appropriate state objects function, and if the state's add/remove message is not null, we add the actor's name and the appropriate state message to $gameMessage.

Game_Actor.prototype.stepsForTurn = function() {
    return 20;
};


This function determines how many map steps are considered a "turn", and we're just returning 20. This means that every 20 steps is considered equivalent to a turn in combat. So if an actor has a state which lasts for 5 turns, they need to walk 100 steps to remove it.

Game_Actor.prototype.turnEndOnMap = function() {
    if ($gameParty.steps() % this.stepsForTurn() === 0) {
        this.onTurnEnd();
        if (this.result().hpDamage > 0) {
            this.performMapDamage();
        }
    }
};


This function processes the end of a map "turn".

If $gameParty's steps() function modulus stepsForTurn() is equal to 0, we call onTurnEnd(), and if the result()'s hpDamage property is greater than 0, we call performMapDamage().

As stepsForTurn() returns a static 20, the main if statement here will return true every 20 steps, as that is the only point at which the modulo operation will return no remainder. At that point, we'll process any regeneration effects and if the actor took damage we'll flash the screen red.

Game_Actor.prototype.checkFloorEffect = function() {
    if ($gamePlayer.isOnDamageFloor()) {
        this.executeFloorDamage();
    }
};


This function determines whether the actor is subject to a floor effect. If $gamePlayer's isOnDamageFloor() returns true (which it will if the player is currently on a tile marked "Damage Floor" in the Tilesets tab) we all executeFloorDamage().

Game_Actor.prototype.executeFloorDamage = function() {
    var damage = Math.floor(this.basicFloorDamage() * this.fdr);
    damage = Math.min(damage, this.maxFloorDamage());
    this.gainHp(-damage);
    if (damage > 0) {
        this.performMapDamage();
    }
};


This function is what actually executes the floor damage. We set variable "damage" to the floor of basicFloorDamage() multiplied by the actor's fdr property (Floor Damage Rate). Then we set damage to the minimum between itself and maxFloorDamage(). We call gainHp passing in the negative of damage, and then if damage is greater than 0 we call performMapDamage.

Game_Actor.prototype.basicFloorDamage = function() {
    return 10;
};


This function gets the base floor damage an actor will take when the player walks on a damage floor. We simply return 10. Yep, each time you step on a damaging tile, your party members will take 10 damage. As we see from the multiplication by .fdr above, this value will be raised or lowered depending on the actor's floor damage rate property.

Game_Actor.prototype.maxFloorDamage = function() {
    return $dataSystem.optFloorDeath ? this.hp : Math.max(this.hp - 1, 0);
};


This function gets the maximum possible damage the actor can take from a damage floor. We either return the value of hp if $dataSystem's optFloorDeath flag is true, or the maximum value between 1 less than hp or 0 otherwise.

Basically, if the "Death by Floor Damage" checkbox is unchecked, the actor can't go any lower than 1 HP.

Game_Actor.prototype.performMapDamage = function() {
    if (!$gameParty.inBattle()) {
        $gameScreen.startFlashForDamage();
    }
};


This function performs the map damage effect. If $gameParty's inBattle() function returns false, we call $gameScreen's startFlashForDamage() function. Which will basically flash the screen red to show damage has been taken.

Game_Actor.prototype.clearActions = function() {
    Game_Battler.prototype.clearActions.call(this);
    this._actionInputIndex = 0;
};


In the overwrite of the parent clearActions function, first we call the parent (obviously) and then set _actionInputIndex to 0 ready for action input.

Game_Actor.prototype.inputtingAction = function() {
    return this.action(this._actionInputIndex);
};


This function gets the object of the action currently being selected. We return the result of calling action() passing in _actionInputIndex.

Game_Actor.prototype.selectNextCommand = function() {
    if (this._actionInputIndex < this.numActions() - 1) {
        this._actionInputIndex++;
        return true;
    } else {
        return false;
    }
};


This function selects the actor's next command. If _actionInputIndex is less than 1 less than numActions(), we increment _actionInputIndex and return true. Otherwise, we return false.

In English, if our action input index is not yet equal to the number of action slots the actor has (0-indexed), we move to the next index. Either way, we return a boolean value that will allow the calling function to determine whether the move to the next command was successful or not.

Game_Actor.prototype.selectPreviousCommand = function() {
    if (this._actionInputIndex > 0) {
        this._actionInputIndex--;
        return true;
    } else {
        return false;
    }
};


This function selects the actor's previous command, for the purposes of cancelling one we've already chosen. If _actionInputIndex is greater than 0, we decrement it and return true. Otherwise, we return false. It stands to reason that we wouldn't want the index to go past 0, as it isn't possible to have fewer than 0 actions.

Game_Actor.prototype.lastMenuSkill = function() {
    return this._lastMenuSkill.object();
};

Game_Actor.prototype.setLastMenuSkill = function(skill) {
    this._lastMenuSkill.setObject(skill);
};

Game_Actor.prototype.lastBattleSkill = function() {
    return this._lastBattleSkill.object();
};

Game_Actor.prototype.setLastBattleSkill = function(skill) {
    this._lastBattleSkill.setObject(skill);
};

Game_Actor.prototype.lastCommandSymbol = function() {
    return this._lastCommandSymbol;
};

Game_Actor.prototype.setLastCommandSymbol = function(symbol) {
    this._lastCommandSymbol = symbol;
};


These functions get and set the "last" data for menu skill, battle skill and command symbol respectively. At this point, they're hopefully self-explanatory enough to not need an individual breakdown; they're fairly standard getters/setters now.

Game_Actor.prototype.testEscape = function(item) {
    return item.effects.some(function(effect, index, ar) {
        return effect && effect.code === Game_Action.EFFECT_SPECIAL;
    });
};


This function checks whether a given item posseses an "escape" effect, and takes item as a parameter. Our return value is a "some" function executed on the item's effects: the function passed to some uses "effect" as the current element, "index" as the index of the iteration, and "ar" as the array itself, which isn't used here. Inside that function, we return true if effect exists AND the effect's code is equal to the EFFECT_SPECIAL constant in Game_Action.

In other words, this will return true if any of the item's effects are "Escape".

Game_Actor.prototype.meetsUsableItemConditions = function(item) {
    if ($gameParty.inBattle() && !BattleManager.canEscape() && this.testEscape(item)) {
        return false;
    }
    return Game_BattlerBase.prototype.meetsUsableItemConditions.call(this, item);
};


This function determines whether the actor meets the conditions to use a given item, taking item as a parameter.

If $gameParty's inBattle() function returns true AND BattleManager's canEscape() returns false AND testEscape returns true with item passed in, we return false. Otherwise, we return the result of the parent function.

In other words, the actor will not meet usable item conditions if the party is in battle, the item has an escape effect, and the party isn't currently able to escape battles.

Phew! That was a doozy. I had intended to include both Game_Actor and Game_Enemy in one episode, but I'm already more than twice over my usual line limit and although Game_Enemy is a smaller class, it's still fairly meaty, so it'll have to wait until next week. Thanks for sticking with me, though! Hopefully now you have a better understanding of how actors tick.

Until next time!