Source: Game_Party.js

Game_Party.js

//-----------------------------------------------------------------------------
// Game_Party
//
// The game object class for the party. Information such as gold and items is
// included.
/**
 * The game object class for the party. Information such as gold and items is included.
 *
 * @class
 * @extends Game_Unit
 */
function Game_Party() {
    this.initialize(...arguments);
}

Game_Party.prototype = Object.create(Game_Unit.prototype);
Game_Party.prototype.constructor = Game_Party;

/** @constant
    @type {number}
    @default
*/
Game_Party.ABILITY_ENCOUNTER_HALF = 0;
/** @constant
    @type {number}
    @default
*/
Game_Party.ABILITY_ENCOUNTER_NONE = 1;
/** @constant
    @type {number}
    @default
*/
Game_Party.ABILITY_CANCEL_SURPRISE = 2;
/** @constant
    @type {number}
    @default
*/
Game_Party.ABILITY_RAISE_PREEMPTIVE = 3;
/** @constant
    @type {number}
    @default
*/
Game_Party.ABILITY_GOLD_DOUBLE = 4;
/** @constant
    @type {number}
    @default
*/
Game_Party.ABILITY_DROP_ITEM_DOUBLE = 5;

Game_Party.prototype.initialize = function() {
    Game_Unit.prototype.initialize.call(this);
    this._gold = 0;
    this._steps = 0;
    this._lastItem = new Game_Item();
    this._menuActorId = 0;
    this._targetActorId = 0;
    this._actors = [];
    this.initAllItems();
};

/**
 * Initializes the items/weapons/armors
 */
Game_Party.prototype.initAllItems = function() {
    this._items = {};
    this._weapons = {};
    this._armors = {};
};

/**
 * Check if the party exists (more than 1 actor in it)
 *
 * @return {boolean} True if exists
 */
Game_Party.prototype.exists = function() {
    return this._actors.length > 0;
};

/**
 * Get the party size
 *
 * @return {number} Number of party members
 */
Game_Party.prototype.size = function() {
    return this.members().length;
};

/**
 * Check if there are no party members
 *
 * @return {boolean} True if no party members
 */
Game_Party.prototype.isEmpty = function() {
    return this.size() === 0;
};

/**
 * Get the members of the party
 *
 * @return {Game_Actor[]} Member array
 */
Game_Party.prototype.members = function() {
    return this.inBattle() ? this.battleMembers() : this.allMembers();
};

/**
 * Get all possible party members
 *
 * @return {Game_Actor[]} All party members
 */
Game_Party.prototype.allMembers = function() {
    return this._actors.map(id => $gameActors.actor(id));
};

/**
 * Get all battle party members
 *
 * @return {Game_Actor[]} All battle party members
 */
Game_Party.prototype.battleMembers = function() {
    return this.allBattleMembers().filter(actor => actor.isAppeared());
};

/**
 * Get all hidden battle party members
 *
 * @return {Game_Actor[]} All hidden battle party members
 * @since Version 1.4.0
 */
Game_Party.prototype.hiddenBattleMembers = function() {
    return this.allBattleMembers().filter(actor => actor.isHidden());
};

/**
 * Get all possible battle party members
 *
 * @return {Game_Actor[]} All battle party members
 * @since Version 1.4.0
 */
Game_Party.prototype.allBattleMembers = function() {
    return this.allMembers().slice(0, this.maxBattleMembers());
};

/**
 * Get the maximum amount of battlers
 *
 * @return {number} Maximum amount of battle members to allow
 */
Game_Party.prototype.maxBattleMembers = function() {
    return 4;
};

/**
 * Get the party leader
 *
 * @return {Game_Actor} Party member in first position
 */
Game_Party.prototype.leader = function() {
    return this.battleMembers()[0];
};

/**
 * Remove any invalid party members (no corresponding data object)
 */
Game_Party.prototype.removeInvalidMembers = function() {
    for (const actorId of this._actors) {
        if (!$dataActors[actorId]) {
            this._actors.remove(actorId);
        }
    }
};

/**
 * Revives all dead party members
 */
Game_Party.prototype.reviveBattleMembers = function() {
    for (const actor of this.battleMembers()) {
        if (actor.isDead()) {
            actor.setHp(1);
        }
    }
};

/**
 * Get the party's items
 *
 * @return {Array} Data objects for all items
 */
Game_Party.prototype.items = function() {
    return Object.keys(this._items).map(id => $dataItems[id]);
};

/**
 * Get the party's weapons
 *
 * @return {Array} Data objects for all weapons
 */
Game_Party.prototype.weapons = function() {
    return Object.keys(this._weapons).map(id => $dataWeapons[id]);
};

/**
 * Get the party's armors
 *
 * @return {Array} Data objects for all armors
 */
Game_Party.prototype.armors = function() {
    return Object.keys(this._armors).map(id => $dataArmors[id]);
};

/**
 * Get the party's equipable items (weapons + armors)
 *
 * @return {Array} Data objects for all equipable items
 */
Game_Party.prototype.equipItems = function() {
    return this.weapons().concat(this.armors());
};

/**
 * Get the party's items, weapons, and armors
 *
 * @return {Array} Data objects for all items, weapons, armors
 */
Game_Party.prototype.allItems = function() {
    return this.items().concat(this.equipItems());
};

/**
 * Get the item container for the given item. For example, it will return the armor container if the given item is an armor.
 *
 * @param {Object} item - The item object to get the container for
 * @return {Array|null} Objects for all items of similar type, null if no container found
 */
Game_Party.prototype.itemContainer = function(item) {
    if (!item) {
        return null;
    } else if (DataManager.isItem(item)) {
        return this._items;
    } else if (DataManager.isWeapon(item)) {
        return this._weapons;
    } else if (DataManager.isArmor(item)) {
        return this._armors;
    } else {
        return null;
    }
};

/**
 * Sets up the starting party members
 */
Game_Party.prototype.setupStartingMembers = function() {
    this._actors = [];
    for (const actorId of $dataSystem.partyMembers) {
        if ($gameActors.actor(actorId)) {
            this._actors.push(actorId);
        }
    }
};

/**
 * Get the name to use for the party
 *
 * @return {string} The name of the party
 */
Game_Party.prototype.name = function() {
    const numBattleMembers = this.battleMembers().length;
    if (numBattleMembers === 0) {
        return "";
    } else if (numBattleMembers === 1) {
        return this.leader().name();
    } else {
        return TextManager.partyName.format(this.leader().name());
    }
};

/**
 * Set up performed when doing a battle test
 */
Game_Party.prototype.setupBattleTest = function() {
    this.setupBattleTestMembers();
    this.setupBattleTestItems();
};

/**
 * Set up battler members when doing battle test
 */
Game_Party.prototype.setupBattleTestMembers = function() {
    for (const battler of $dataSystem.testBattlers) {
        const actor = $gameActors.actor(battler.actorId);
        if (actor) {
            actor.changeLevel(battler.level, false);
            actor.initEquips(battler.equips);
            actor.recoverAll();
            this.addActor(battler.actorId);
        }
    }
};

/**
 * Set up items available during the battle test
 */
Game_Party.prototype.setupBattleTestItems = function() {
    for (const item of $dataItems) {
        if (item && item.name.length > 0) {
            this.gainItem(item, this.maxItems(item));
        }
    }
};

/**
 * Get the highest level of any party member
 *
 * @return {number} The highest level
 */
Game_Party.prototype.highestLevel = function() {
    return Math.max(...this.members().map(actor => actor.level));
};

/**
 * Add an actor to the party by id
 *
 * @param {number} actorId - The id of the actor to add
 */
Game_Party.prototype.addActor = function(actorId) {
    if (!this._actors.includes(actorId)) {
        this._actors.push(actorId);
        $gamePlayer.refresh();
        $gameMap.requestRefresh();
        $gameTemp.requestBattleRefresh();
        if (this.inBattle()) {
            const actor = $gameActors.actor(actorId);
            if (this.battleMembers().includes(actor)) {
                actor.onBattleStart();
            }
        }
    }
};

/**
 * Remove an actor from the party by id
 *
 * @param {number} actorId - The id of the actor to remove
 */
Game_Party.prototype.removeActor = function(actorId) {
    if (this._actors.includes(actorId)) {
        const actor = $gameActors.actor(actorId);
        const wasBattleMember = this.battleMembers().includes(actor);
        this._actors.remove(actorId);
        $gamePlayer.refresh();
        $gameMap.requestRefresh();
        $gameTemp.requestBattleRefresh();
        if (this.inBattle() && wasBattleMember) {
            actor.onBattleEnd();
        }
    }
};

/**
 * Get the party's gold amount
 *
 * @return {number} Amount of gold the party has
 */
Game_Party.prototype.gold = function() {
    return this._gold;
};

/**
 * Gains gold
 *
 * @param {number} amount - The amount of gold to gain
 */
Game_Party.prototype.gainGold = function(amount) {
    this._gold = (this._gold + amount).clamp(0, this.maxGold());
};

/**
 * Loses gold
 *
 * @param {number} amount - The amount of gold to lose
 */
Game_Party.prototype.loseGold = function(amount) {
    this.gainGold(-amount);
};

/**
 * Get the maximum amount of gold allowed
 *
 * @return {number} Max allowed amount of gold
 */
Game_Party.prototype.maxGold = function() {
    return 99999999;
};

/**
 * Get the party's step count
 *
 * @return {number} Amount of steps taken
 */
Game_Party.prototype.steps = function() {
    return this._steps;
};

/**
 * Increase the step counter by one
 */
Game_Party.prototype.increaseSteps = function() {
    this._steps++;
};

/**
 * Get the amount of the given item the party has
 *
 * @param {Object} item - The item to check
 * @return {number} The amount of the given item the party has
 */
Game_Party.prototype.numItems = function(item) {
    const container = this.itemContainer(item);
    return container ? container[item.id] || 0 : 0;
};

/**
 * Get the maximum amount of items allowed
 *
 * @return {number} Max allowed amount of any item
 */
Game_Party.prototype.maxItems = function(/*item*/) {
    return 99;
};

/**
 * Check if the party has the maximum allowed amount of the given item
 *
 * @param {Object} item - The item to check
 * @return {boolean} True if already has max items
 */
Game_Party.prototype.hasMaxItems = function(item) {
    return this.numItems(item) >= this.maxItems(item);
};

/**
 * Check if the party has any of the given item
 *
 * @param {Object} item - The item to check
 * @param {boolean} includeEquip - If should check actor equips too
 * @return {boolean} True if the party has the given item
 */
Game_Party.prototype.hasItem = function(item, includeEquip) {
    if (this.numItems(item) > 0) {
        return true;
    } else if (includeEquip && this.isAnyMemberEquipped(item)) {
        return true;
    } else {
        return false;
    }
};

/**
 * Check if any party member has the given item equipped
 *
 * @param {Object} item - The item to check
 * @return {boolean} True if any party member has the item equipped
 */
Game_Party.prototype.isAnyMemberEquipped = function(item) {
    return this.members().some(actor => actor.equips().includes(item));
};

/**
 * Gains items
 *
 * @param {Object} item - The item to gain
 * @param {number} amount - The amount of the item to gain
 * @param {boolean} includeEquip - If party member equips should be discarded when amount is negative
 */
Game_Party.prototype.gainItem = function(item, amount, includeEquip) {
    const container = this.itemContainer(item);
    if (container) {
        const lastNumber = this.numItems(item);
        const newNumber = lastNumber + amount;
        container[item.id] = newNumber.clamp(0, this.maxItems(item));
        if (container[item.id] === 0) {
            delete container[item.id];
        }
        if (includeEquip && newNumber < 0) {
            this.discardMembersEquip(item, -newNumber);
        }
        $gameMap.requestRefresh();
    }
};

/**
 * Discards equipment from party members
 *
 * @param {Object} item - The equip item to discard
 * @param {number} amount - The amount of that item to discard
 */
Game_Party.prototype.discardMembersEquip = function(item, amount) {
    let n = amount;
    for (const actor of this.members()) {
        while (n > 0 && actor.isEquipped(item)) {
            actor.discardEquip(item);
            n--;
        }
    }
};

/**
 * Loses items
 *
 * @param {Object} item - The item to lose
 * @param {number} amount - The amount of the item to lose
 * @param {boolean} includeEquip - If party member equips should be discarded if there are not enough items in the inventory to lose
 */
Game_Party.prototype.loseItem = function(item, amount, includeEquip) {
    this.gainItem(item, -amount, includeEquip);
};

/**
 * Consumes an item
 *
 * @param {Object} item - The item to consume
 */
Game_Party.prototype.consumeItem = function(item) {
    if (DataManager.isItem(item) && item.consumable) {
        this.loseItem(item, 1);
    }
};

/**
 * Check if the given item can be used
 *
 * @param {Object} item - The item to check
 * @return {boolean} True if any party member can use the item
 */
Game_Party.prototype.canUse = function(item) {
    return this.members().some(actor => actor.canUse(item));
};

/**
 * Check if any party members can input
 *
 * @return {boolean} True if any party member can input
 */
Game_Party.prototype.canInput = function() {
    return this.members().some(actor => actor.canInput());
};

Game_Party.prototype.isAllDead = function() {
    if (Game_Unit.prototype.isAllDead.call(this)) {
        return this.inBattle() || !this.isEmpty();
    } else {
        return false;
    }
};

/**
 * Check if the party escaped
 *
 * @param {*} item - Unused
 * @return {boolean} True if escaped
 * @since Version 1.4.0
 */
Game_Party.prototype.isEscaped = function(item) {
    return this.isAllDead() && this.hiddenBattleMembers().length > 0;
};

/**
 * Processing when the player is walking
 */
Game_Party.prototype.onPlayerWalk = function() {
    for (const actor of this.members()) {
        actor.onPlayerWalk();
    }
};

/**
 * Get the menu actor
 *
 * @return {Game_Actor} The menu actor
 */
Game_Party.prototype.menuActor = function() {
    let actor = $gameActors.actor(this._menuActorId);
    if (!this.members().includes(actor)) {
        actor = this.members()[0];
    }
    return actor;
};

/**
 * Set the menu actor
 *
 * @param {Game_Actor} actor - The new menu actor
 */
Game_Party.prototype.setMenuActor = function(actor) {
    this._menuActorId = actor.actorId();
};

/**
 * Make the next menu actor
 */
Game_Party.prototype.makeMenuActorNext = function() {
    let index = this.members().indexOf(this.menuActor());
    if (index >= 0) {
        index = (index + 1) % this.members().length;
        this.setMenuActor(this.members()[index]);
    } else {
        this.setMenuActor(this.members()[0]);
    }
};

/**
 * Make the previous menu actor
 */
Game_Party.prototype.makeMenuActorPrevious = function() {
    let index = this.members().indexOf(this.menuActor());
    if (index >= 0) {
        index = (index + this.members().length - 1) % this.members().length;
        this.setMenuActor(this.members()[index]);
    } else {
        this.setMenuActor(this.members()[0]);
    }
};

/**
 * Get the target actor
 *
 * @return {Game_Actor} The target actor
 */
Game_Party.prototype.targetActor = function() {
    let actor = $gameActors.actor(this._targetActorId);
    if (!this.members().includes(actor)) {
        actor = this.members()[0];
    }
    return actor;
};

/**
 * Set the menu actor
 *
 * @param {Game_Actor} actor - The new target actor
 */
Game_Party.prototype.setTargetActor = function(actor) {
    this._targetActorId = actor.actorId();
};

/**
 * Get the last item
 *
 * @return {Object} The last item data object
 */
Game_Party.prototype.lastItem = function() {
    return this._lastItem.object();
};

/**
 * Set the last item
 *
 * @param {Object} The new last item
 */
Game_Party.prototype.setLastItem = function(item) {
    this._lastItem.setObject(item);
};

/**
 * Swap two member's positions in the party
 *
 * @param {number} index1 - The first index to swap
 * @param {number} index2 - The second index to swap
 */
Game_Party.prototype.swapOrder = function(index1, index2) {
    const temp = this._actors[index1];
    this._actors[index1] = this._actors[index2];
    this._actors[index2] = temp;
    $gamePlayer.refresh();
};

/**
 * Get character info for save file
 *
 * @return {Array} Character info for the save file
 */
Game_Party.prototype.charactersForSavefile = function() {
    return this.battleMembers().map(actor => [
        actor.characterName(),
        actor.characterIndex()
    ]);
};

/**
 * Get face info for save file
 *
 * @return {Array} Face info for the save file
 */
Game_Party.prototype.facesForSavefile = function() {
    return this.battleMembers().map(actor => [
        actor.faceName(),
        actor.faceIndex()
    ]);
};

/**
 * Check if any battle member has the party ability by id
 *
 * @param {number} abilityId - The party ability id to check for
 * @return {boolean} True if party ability found
 */
Game_Party.prototype.partyAbility = function(abilityId) {
    return this.battleMembers().some(actor => actor.partyAbility(abilityId));
};

/**
 * Check if the party has encounter half ability
 *
 * @return {boolean} True if encounter half
 */
Game_Party.prototype.hasEncounterHalf = function() {
    return this.partyAbility(Game_Party.ABILITY_ENCOUNTER_HALF);
};

/**
 * Check if the party has encounter none ability
 *
 * @return {boolean} True if encounter none
 */
Game_Party.prototype.hasEncounterNone = function() {
    return this.partyAbility(Game_Party.ABILITY_ENCOUNTER_NONE);
};

/**
 * Check if the party has cancel surprise ability
 *
 * @return {boolean} True if cancel surprise
 */
Game_Party.prototype.hasCancelSurprise = function() {
    return this.partyAbility(Game_Party.ABILITY_CANCEL_SURPRISE);
};

/**
 * Check if the party has raise preemptive ability
 *
 * @return {boolean} True if raise preemptive
 */
Game_Party.prototype.hasRaisePreemptive = function() {
    return this.partyAbility(Game_Party.ABILITY_RAISE_PREEMPTIVE);
};

/**
 * Check if the party has gold double ability
 *
 * @return {boolean} True if gold double
 */
Game_Party.prototype.hasGoldDouble = function() {
    return this.partyAbility(Game_Party.ABILITY_GOLD_DOUBLE);
};

/**
 * Check if the party has drop item double ability
 *
 * @return {boolean} True if drop item double
 */
Game_Party.prototype.hasDropItemDouble = function() {
    return this.partyAbility(Game_Party.ABILITY_DROP_ITEM_DOUBLE);
};

/**
 * Get the preemptive rate
 *
 * @param {number} troopAgi - The troop's agility
 * @return {number} The preemptive rate
 */
Game_Party.prototype.ratePreemptive = function(troopAgi) {
    let rate = this.agility() >= troopAgi ? 0.05 : 0.03;
    if (this.hasRaisePreemptive()) {
        rate *= 4;
    }
    return rate;
};

/**
 * Get the surprise rate
 *
 * @param {number} troopAgi - The troop's agility
 * @return {number} The surprise rate
 */
Game_Party.prototype.rateSurprise = function(troopAgi) {
    let rate = this.agility() >= troopAgi ? 0.03 : 0.05;
    if (this.hasCancelSurprise()) {
        rate = 0;
    }
    return rate;
};

/**
 * Perform victory for each member
 */
Game_Party.prototype.performVictory = function() {
    for (const actor of this.members()) {
        actor.performVictory();
    }
};

/**
 * Perform escape for each member
 */
Game_Party.prototype.performEscape = function() {
    for (const actor of this.members()) {
        actor.performEscape();
    }
};

/**
 * Remove member battle states
 */
Game_Party.prototype.removeBattleStates = function() {
    for (const actor of this.members()) {
        actor.removeBattleStates();
    }
};

/**
 * Request motion refresh for members
 */
Game_Party.prototype.requestMotionRefresh = function() {
    for (const actor of this.members()) {
        actor.requestMotionRefresh();
    }
};

/**
 * Handling when escape fails
 */
Game_Party.prototype.onEscapeFailure = function() {
    for (const actor of this.members()) {
        actor.onEscapeFailure();
    }
};