"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.playChargeSoundEffect = exports.isActiveSlotDoubleCharged = exports.getUsableActiveItemSlots = exports.getTotalCharge = exports.getChargesAwayFromMax = exports.addRoomClearCharges = exports.addRoomClearChargeToSlot = exports.addRoomClearCharge = exports.addCharge = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const cachedClasses_1 = require("../core/cachedClasses");
const collectibles_1 = require("./collectibles");
const playerCollectibles_1 = require("./playerCollectibles");
const playerIndex_1 = require("./playerIndex");
const roomShape_1 = require("./roomShape");
/**
 * Helper function to add a charge to the player's active item. Will flash the HUD and play the
 * appropriate sound effect, depending on whether the charge is partially full or completely full.
 *
 * If the player's active item is already fully charged, then this function will return 0 and not
 * flash the HUD or play a sound effect.
 *
 * This function will take the following things into account:
 * - The Battery
 * - AAA Battery
 *
 * @param player The player to grant the charges to.
 * @param activeSlot Optional. The slot to grant the charges to. Default is `ActiveSlot.PRIMARY`.
 * @param numCharges Optional. The amount of charges to grant. Default is 1.
 * @param playSoundEffect Optional. Whether to play a charge-related sound effect. Default is true.
 * @returns The amount of charges that were actually granted. For example, if the active item was
 *          only one away from a full charge, but the `numCharges` provided to this function was 2,
 *          then this function would return 1.
 */
function addCharge(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY, numCharges = 1, playSoundEffect = true) {
    const hud = cachedClasses_1.game.GetHUD();
    // Ensure that there is enough space on the active item to store these amount of charges. (If we
    // add too many charges, it will grant orange "battery" charges, even if the player does not have
    // The Battery.)
    const chargesAwayFromMax = getChargesAwayFromMax(player, activeSlot);
    const chargesToAdd = numCharges > chargesAwayFromMax ? chargesAwayFromMax : numCharges;
    // The AAA Battery trinket might grant an additional charge.
    const modifiedChargesToAdd = getChargesToAddWithAAAModifier(player, activeSlot, chargesToAdd);
    const totalCharge = getTotalCharge(player, activeSlot);
    const newCharge = totalCharge + modifiedChargesToAdd;
    if (newCharge === totalCharge) {
        return 0;
    }
    player.SetActiveCharge(newCharge, activeSlot);
    hud.FlashChargeBar(player, activeSlot);
    if (playSoundEffect) {
        playChargeSoundEffect(player, activeSlot);
    }
    return modifiedChargesToAdd;
}
exports.addCharge = addCharge;
/**
 * Helper function to add a charge to a player's active item(s), emulating what happens when a room
 * is cleared.
 *
 * This function will take the following things into account:
 * - 2x2 rooms and L rooms granting a double charge
 * - The Battery
 * - AAA Battery
 * - Not charging active items with `chargetype="special"`
 *
 * @param player The player to grant the charges to.
 * @param bigRoomDoubleCharge Optional. If set to false, it will treat the current room as a 1x1
 *                            room for the purposes of calculating how much charge to grant. Default
 *                            is true.
 * @param playSoundEffect Optional. Whether to play a charge-related sound effect. Default is true.
 */
function addRoomClearCharge(player, bigRoomDoubleCharge = true, playSoundEffect = true) {
    for (const activeSlot of [
        isaac_typescript_definitions_1.ActiveSlot.PRIMARY,
        isaac_typescript_definitions_1.ActiveSlot.SECONDARY,
        isaac_typescript_definitions_1.ActiveSlot.POCKET,
    ]) {
        addRoomClearChargeToSlot(player, activeSlot, bigRoomDoubleCharge, playSoundEffect);
    }
}
exports.addRoomClearCharge = addRoomClearCharge;
/**
 * Helper function to add a charge to one of a player's active items, emulating what happens when a
 * room is cleared.
 *
 * This function will take the following things into account:
 * - L rooms and 2x2 rooms granting a double charge
 * - The Battery
 * - AAA Battery
 * - Not charging active items with `chargetype="special"`
 *
 * @param player The player to grant the charges to.
 * @param activeSlot Optional. The active item slot to grant the charges to. Default is
 *                   `ActiveSlot.PRIMARY`.
 * @param bigRoomDoubleCharge Optional. If set to false, it will treat the current room as a 1x1
 *                            room for the purposes of calculating how much charge to grant. Default
 *                            is true.
 * @param playSoundEffect Optional. Whether to play a charge-related sound effect. Default is true.
 */
function addRoomClearChargeToSlot(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY, bigRoomDoubleCharge = true, playSoundEffect = true) {
    const activeItem = player.GetActiveItem(activeSlot);
    if (activeItem === isaac_typescript_definitions_1.CollectibleType.NULL) {
        return;
    }
    // Certain collectibles have special charge mechanisms and are not charged upon a room being
    // cleared.
    const chargeType = (0, collectibles_1.getCollectibleChargeType)(activeItem);
    if (chargeType === isaac_typescript_definitions_1.ItemConfigChargeType.SPECIAL) {
        return;
    }
    const room = cachedClasses_1.game.GetRoom();
    const roomShape = room.GetRoomShape();
    // Big rooms grant two charges and normal rooms grant one charge.
    let numCharges = bigRoomDoubleCharge ? (0, roomShape_1.getRoomShapeCharges)(roomShape) : 1;
    // Handle the special case of a timed item. When clearing a room with a timed item, it should
    // become fully charged.
    if (chargeType === isaac_typescript_definitions_1.ItemConfigChargeType.TIMED) {
        // The charges will become clamped to the proper amount in the `addCharge` function. (If the
        // item is at 50% charge and the player has The Battery, it should go to 150% charged.)
        numCharges = (0, collectibles_1.getCollectibleMaxCharges)(activeItem);
    }
    addCharge(player, activeSlot, numCharges, playSoundEffect);
}
exports.addRoomClearChargeToSlot = addRoomClearChargeToSlot;
/**
 * The AAA Battery should grant an extra charge when the active item is one away from being fully
 * charged.
 */
function getChargesToAddWithAAAModifier(player, activeSlot, chargesToAdd) {
    const hasAAABattery = player.HasTrinket(isaac_typescript_definitions_1.TrinketType.AAA_BATTERY);
    if (!hasAAABattery) {
        return chargesToAdd;
    }
    const chargesAwayFromMax = getChargesAwayFromMax(player, activeSlot);
    const AAABatteryShouldApply = chargesToAdd === chargesAwayFromMax - 1;
    return AAABatteryShouldApply ? chargesToAdd + 1 : chargesToAdd;
}
/**
 * Helper function to add a charge to every player's active item, emulating what happens when a room
 * is cleared.
 *
 * This function will take the following things into account:
 * - L rooms and 2x2 rooms granting a double charge
 * - The Battery
 * - AAA Battery
 *
 * @param bigRoomDoubleCharge Optional. If set to false, it will treat the current room as a 1x1
 *                            room for the purposes of calculating how much charge to grant. Default
 *                            is true.
 */
function addRoomClearCharges(bigRoomDoubleCharge = true) {
    for (const player of (0, playerIndex_1.getPlayers)()) {
        addRoomClearCharge(player, bigRoomDoubleCharge);
    }
}
exports.addRoomClearCharges = addRoomClearCharges;
/**
 * Helper function to get the amount of charges away from the maximum charge that a particular
 * player is.
 *
 * This function accounts for The Battery. For example, if the player has 2/6 charges on a D6, this
 * function will return 10 (because there are 4 charges remaining on the base charge and 6 charges
 * remaining on The Battery charge).
 *
 * @param player The player to get the charges from.
 * @param activeSlot Optional. The slot to get the charges from. Default is `ActiveSlot.PRIMARY`.
 */
function getChargesAwayFromMax(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY) {
    const totalCharge = getTotalCharge(player, activeSlot);
    const activeItem = player.GetActiveItem(activeSlot);
    const hasBattery = player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.BATTERY);
    const maxCharges = (0, collectibles_1.getCollectibleMaxCharges)(activeItem);
    const effectiveMaxCharges = hasBattery ? maxCharges * 2 : maxCharges;
    return effectiveMaxCharges - totalCharge;
}
exports.getChargesAwayFromMax = getChargesAwayFromMax;
/**
 * Helper function to get the combined normal charge and the battery charge for the player's active
 * item. This is useful because you have to add these two values together when setting the active
 * charge.
 *
 * @param player The player to get the charges from.
 * @param activeSlot Optional. The slot to get the charges from. Default is `ActiveSlot.PRIMARY`.
 */
function getTotalCharge(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY) {
    const activeCharge = player.GetActiveCharge(activeSlot);
    const batteryCharge = player.GetBatteryCharge(activeSlot);
    return activeCharge + batteryCharge;
}
exports.getTotalCharge = getTotalCharge;
/**
 * Helper function to find the active slots that the player has the corresponding collectible type
 * in and have enough charge to be used. Returns an empty array if the player does not have the
 * collectible in any active slot or does not have enough charges.
 */
function getUsableActiveItemSlots(player, collectibleType) {
    const maxCharges = (0, collectibles_1.getCollectibleMaxCharges)(collectibleType);
    const activeSlots = (0, playerCollectibles_1.getActiveItemSlots)(player, collectibleType);
    return activeSlots.filter((activeSlot) => {
        const totalCharge = getTotalCharge(player, activeSlot);
        return totalCharge >= maxCharges;
    });
}
exports.getUsableActiveItemSlots = getUsableActiveItemSlots;
/**
 * Helper function to check if a player's active item is "double charged", meaning that it has both
 * a full normal charge and a full charge from The Battery.
 *
 * @param player The player to check.
 * @param activeSlot Optional. The slot to check. Default is `ActiveSlot.PRIMARY`.
 */
function isActiveSlotDoubleCharged(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY) {
    const collectibleType = player.GetActiveItem(activeSlot);
    const batteryCharge = player.GetBatteryCharge(activeSlot);
    const maxCharges = (0, collectibles_1.getCollectibleMaxCharges)(collectibleType);
    return batteryCharge >= maxCharges;
}
exports.isActiveSlotDoubleCharged = isActiveSlotDoubleCharged;
/**
 * Helper function to play the appropriate sound effect for a player after getting one or more
 * charges on their active item. (There is a different sound depending on whether the item is fully
 * charged.)
 *
 * @param player The player to play the sound effect for.
 * @param activeSlot Optional. The slot that was just charged. Default is `ActiveSlot.PRIMARY`.
 */
function playChargeSoundEffect(player, activeSlot = isaac_typescript_definitions_1.ActiveSlot.PRIMARY) {
    for (const soundEffect of [
        isaac_typescript_definitions_1.SoundEffect.BATTERY_CHARGE,
        isaac_typescript_definitions_1.SoundEffect.BEEP, // 171
    ]) {
        cachedClasses_1.sfxManager.Stop(soundEffect);
    }
    const chargeSoundEffect = shouldPlayFullRechargeSound(player, activeSlot)
        ? isaac_typescript_definitions_1.SoundEffect.BATTERY_CHARGE
        : isaac_typescript_definitions_1.SoundEffect.BEEP;
    cachedClasses_1.sfxManager.Play(chargeSoundEffect);
}
exports.playChargeSoundEffect = playChargeSoundEffect;
function shouldPlayFullRechargeSound(player, activeSlot) {
    const activeItem = player.GetActiveItem(activeSlot);
    const activeCharge = player.GetActiveCharge(activeSlot);
    const batteryCharge = player.GetBatteryCharge(activeSlot);
    const hasBattery = player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.BATTERY);
    const maxCharges = (0, collectibles_1.getCollectibleMaxCharges)(activeItem);
    // If we do not have The Battery, play the full recharge sound if we are now fully charged.
    if (!hasBattery) {
        // We cannot use the `EntityPlayer.NeedsCharge` method because it does not work properly for
        // items with `chargetype="special"`.
        return activeCharge === maxCharges;
    }
    // If we do have The Battery, play the full recharge sound if we are exactly double charged or
    // exactly single charged.
    return (batteryCharge === maxCharges ||
        (activeCharge === maxCharges && batteryCharge === 0));
}
