//-----------------------------------------------------------------------------
// Game_Enemy
//
// The game object class for an enemy.
/**
 * The game object class for an enemy.
 *
 * @class
 * @extends Game_Battler
 */
function Game_Enemy() {
    this.initialize(...arguments);
}
Game_Enemy.prototype = Object.create(Game_Battler.prototype);
Game_Enemy.prototype.constructor = Game_Enemy;
/**
 * Initialize the enemy
 *
 * @param {number} enemyId - The enemy's id
 * @param {number} x - The enemy's screen x coordinate
 * @param {number} y - The enemy's screen y coordinate
 */
Game_Enemy.prototype.initialize = function(enemyId, x, y) {
    Game_Battler.prototype.initialize.call(this);
    this.setup(enemyId, x, y);
};
Game_Enemy.prototype.initMembers = function() {
    Game_Battler.prototype.initMembers.call(this);
    this._enemyId = 0;
    this._letter = "";
    this._plural = false;
    this._screenX = 0;
    this._screenY = 0;
};
/**
 * Setup the enemy
 *
 * @param {number} enemyId - The enemy's id
 * @param {number} x - The enemy's screen x coordinate
 * @param {number} y - The enemy's screen y coordinate
 */
Game_Enemy.prototype.setup = function(enemyId, x, y) {
    this._enemyId = enemyId;
    this._screenX = x;
    this._screenY = y;
    this.recoverAll();
};
/**
 * Check if this is an enemy. When called from Game_Enemy, this is always true
 *
 * @return {boolean} True if this is an enemy
 */
Game_Enemy.prototype.isEnemy = function() {
    return true;
};
/**
 * Get the friendly unit in battle. For Game_Enemy, this is Game_Troop
 *
 * @return {Game_Party|Game_Troop} The friendly unit in battle
 */
Game_Enemy.prototype.friendsUnit = function() {
    return $gameTroop;
};
/**
 * Get the enemy unit in battle. For Game_Enemy, this is Game_Party
 *
 * @return {Game_Party|Game_Troop} The enemy unit in battle
 */
Game_Enemy.prototype.opponentsUnit = function() {
    return $gameParty;
};
/**
 * Get the enemy's index in battle
 *
 * @return {number} The enemy's index in battle
 */
Game_Enemy.prototype.index = function() {
    return $gameTroop.members().indexOf(this);
};
/**
 * Check if this is a battle member
 *
 * @return {boolean} True if this is a battle member
 */
Game_Enemy.prototype.isBattleMember = function() {
    return this.index() >= 0;
};
/**
 * Get the enemy's id
 *
 * @return {number} The enemy's id
 */
Game_Enemy.prototype.enemyId = function() {
    return this._enemyId;
};
/**
 * Get the enemy's data object
 *
 * @return {Object} The enemy's data object
 */
Game_Enemy.prototype.enemy = function() {
    return $dataEnemies[this._enemyId];
};
Game_Enemy.prototype.traitObjects = function() {
    return Game_Battler.prototype.traitObjects.call(this).concat(this.enemy());
};
/**
 * Get a base param value
 *
 * @param {number} paramId - The id of the param to get
 * @return {number} The base param value
 */
Game_Enemy.prototype.paramBase = function(paramId) {
    return this.enemy().params[paramId];
};
/**
 * Get the enemy's exp
 *
 * @return {number} The enemy's exp
 */
Game_Enemy.prototype.exp = function() {
    return this.enemy().exp;
};
/**
 * Get the enemy's gold
 *
 * @return {number} The enemy's gold
 */
Game_Enemy.prototype.gold = function() {
    return this.enemy().gold;
};
/**
 * Make a list of drop items the enemy actually dropped
 *
 * @return {Array} Array of drop items
 */
Game_Enemy.prototype.makeDropItems = function() {
    const rate = this.dropItemRate();
    return this.enemy().dropItems.reduce((r, di) => {
        if (di.kind > 0 && Math.random() * di.denominator < rate) {
            return r.concat(this.itemObject(di.kind, di.dataId));
        } else {
            return r;
        }
    }, []);
};
/**
 * Get the rate for item drops
 *
 * @return {number} The drop item rate
 */
Game_Enemy.prototype.dropItemRate = function() {
    return $gameParty.hasDropItemDouble() ? 2 : 1;
};
/**
 * Get the item object from a kind id and the data id
 *
 * @param {number} kind - The kind of item to get, 1 = item, 2 = weapon, 3 = armor
 * @param {number} dataId - The item's id to get
 * @return {Object|null} The item object, or null if invalid kind id
 */
Game_Enemy.prototype.itemObject = function(kind, dataId) {
    if (kind === 1) {
        return $dataItems[dataId];
    } else if (kind === 2) {
        return $dataWeapons[dataId];
    } else if (kind === 3) {
        return $dataArmors[dataId];
    } else {
        return null;
    }
};
/**
 * Check if the battler sprite should be visible. For Game_Enemy, this always returns true
 *
 * @return {boolean} True if the battler sprite should be visible
 */
Game_Enemy.prototype.isSpriteVisible = function() {
    return true;
};
/**
 * Get the enemy's screen x coordinate
 *
 * @return {number} The enemy's screen x coordinate
 */
Game_Enemy.prototype.screenX = function() {
    return this._screenX;
};
/**
 * Get the enemy's screen y coordinate
 *
 * @return {number} The enemy's screen y coordinate
 */
Game_Enemy.prototype.screenY = function() {
    return this._screenY;
};
/**
 * Get the enemy's battler name
 *
 * @return {string} The enemy's battler name
 */
Game_Enemy.prototype.battlerName = function() {
    return this.enemy().battlerName;
};
/**
 * Get the enemy's battler hue
 *
 * @return {number} The enemy's battler hue
 */
Game_Enemy.prototype.battlerHue = function() {
    return this.enemy().battlerHue;
};
/**
 * Get the enemy's original name
 *
 * @return {string} The enemy's original name
 */
Game_Enemy.prototype.originalName = function() {
    return this.enemy().name;
};
/**
 * Get the enemy's name
 *
 * @return {string} The enemy's name
 */
Game_Enemy.prototype.name = function() {
    return this.originalName() + (this._plural ? this._letter : "");
};
/**
 * Check if the enemy's letter is empty
 *
 * @return {boolean} True if the enemy's letter is empty
 */
Game_Enemy.prototype.isLetterEmpty = function() {
    return this._letter === "";
};
/**
 * Set the enemy's letter
 *
 * @param {string} letter - The enemy's new letter
 */
Game_Enemy.prototype.setLetter = function(letter) {
    this._letter = letter;
};
/**
 * Set the enemy's plural status (if there are multiple of the enemy)
 *
 * @param {boolean} plural - The enemy's new plural status
 */
Game_Enemy.prototype.setPlural = function(plural) {
    this._plural = plural;
};
Game_Enemy.prototype.performActionStart = function(action) {
    Game_Battler.prototype.performActionStart.call(this, action);
    this.requestEffect("whiten");
};
Game_Enemy.prototype.performAction = function(action) {
    Game_Battler.prototype.performAction.call(this, action);
};
Game_Enemy.prototype.performActionEnd = function() {
    Game_Battler.prototype.performActionEnd.call(this);
};
Game_Enemy.prototype.performDamage = function() {
    Game_Battler.prototype.performDamage.call(this);
    SoundManager.playEnemyDamage();
    this.requestEffect("blink");
};
Game_Enemy.prototype.performCollapse = function() {
    Game_Battler.prototype.performCollapse.call(this);
    switch (this.collapseType()) {
        case 0:
            this.requestEffect("collapse");
            SoundManager.playEnemyCollapse();
            break;
        case 1:
            this.requestEffect("bossCollapse");
            SoundManager.playBossCollapse1();
            break;
        case 2:
            this.requestEffect("instantCollapse");
            break;
    }
};
/**
 * Transform the enemy
 *
 * @param {number} enemyId - The new enemy's id
 */
Game_Enemy.prototype.transform = function(enemyId) {
    const name = this.originalName();
    this._enemyId = enemyId;
    if (this.originalName() !== name) {
        this._letter = "";
        this._plural = false;
    }
    this.refresh();
    if (this.numActions() > 0) {
        this.makeActions();
    }
};
/**
 * Check if an action's condition is met
 *
 * @param {Object} action - The action object to check
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsCondition = function(action) {
    const param1 = action.conditionParam1;
    const param2 = action.conditionParam2;
    switch (action.conditionType) {
        case 1:
            return this.meetsTurnCondition(param1, param2);
        case 2:
            return this.meetsHpCondition(param1, param2);
        case 3:
            return this.meetsMpCondition(param1, param2);
        case 4:
            return this.meetsStateCondition(param1);
        case 5:
            return this.meetsPartyLevelCondition(param1);
        case 6:
            return this.meetsSwitchCondition(param1);
        default:
            return true;
    }
};
/**
 * Check if an action's turn condition is met
 *
 * @param {number} param1 - The first turn condition param
 * @param {number} param2 - The second turn condition param
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsTurnCondition = function(param1, param2) {
    const n = this.turnCount();
    if (param2 === 0) {
        return n === param1;
    } else {
        return n > 0 && n >= param1 && n % param2 === param1 % param2;
    }
};
/**
 * Check if an action's hp condition is met
 *
 * @param {number} param1 - The first hp condition param
 * @param {number} param2 - The second hp condition param
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsHpCondition = function(param1, param2) {
    return this.hpRate() >= param1 && this.hpRate() <= param2;
};
/**
 * Check if an action's mp condition is met
 *
 * @param {number} param1 - The first mp condition param
 * @param {number} param2 - The second mp condition param
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsMpCondition = function(param1, param2) {
    return this.mpRate() >= param1 && this.mpRate() <= param2;
};
/**
 * Check if an action's state condition is met
 *
 * @param {number} param - The state to check for
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsStateCondition = function(param) {
    return this.isStateAffected(param);
};
/**
 * Check if an action's party level condition is met
 *
 * @param {number} param - The party level to check for
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsPartyLevelCondition = function(param) {
    return $gameParty.highestLevel() >= param;
};
/**
 * Check if an action's switch condition is met
 *
 * @param {number} param - The switch id to check
 * @return {boolean} True if the condition is met
 */
Game_Enemy.prototype.meetsSwitchCondition = function(param) {
    return $gameSwitches.value(param);
};
/**
 * Check if an action is valid
 *
 * @param {Object} action - The action object to check
 * @return {boolean} True if the action is valid
 */
Game_Enemy.prototype.isActionValid = function(action) {
    return (
        this.meetsCondition(action) && this.canUse($dataSkills[action.skillId])
    );
};
/**
 * Select an action
 *
 * @param {Array} actionList - List of possible action objects
 * @param {number} ratingZero - The minimum rating of the action
 * @return {Object|null} The action object, or null if none selected
 */
Game_Enemy.prototype.selectAction = function(actionList, ratingZero) {
    const sum = actionList.reduce((r, a) => r + a.rating - ratingZero, 0);
    if (sum > 0) {
        let value = Math.randomInt(sum);
        for (const action of actionList) {
            value -= action.rating - ratingZero;
            if (value < 0) {
                return action;
            }
        }
    } else {
        return null;
    }
};
/**
 * Select all actions
 *
 * @param {Array} actionList - List of possible action objects
 */
Game_Enemy.prototype.selectAllActions = function(actionList) {
    const ratingMax = Math.max(...actionList.map(a => a.rating));
    const ratingZero = ratingMax - 3;
    actionList = actionList.filter(a => a.rating > ratingZero);
    for (let i = 0; i < this.numActions(); i++) {
        this.action(i).setEnemyAction(
            this.selectAction(actionList, ratingZero)
        );
    }
};
Game_Enemy.prototype.makeActions = function() {
    Game_Battler.prototype.makeActions.call(this);
    if (this.numActions() > 0) {
        const actionList = this.enemy().actions.filter(a =>
            this.isActionValid(a)
        );
        if (actionList.length > 0) {
            this.selectAllActions(actionList);
        }
    }
    this.setActionState("waiting");
};