"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wouldDamageTaintedMagdaleneNonTemporaryHeartContainers = exports.setPlayerHealth = exports.removeAllPlayerHealth = exports.playerHasHealthLeft = exports.playerConvertSoulHeartsToBlackHearts = exports.playerConvertBlackHeartsToSoulHearts = exports.newPlayerHealth = exports.getTaintedMagdaleneNonTemporaryMaxHearts = exports.getPlayerSoulHearts = exports.getPlayerMaxHeartContainers = exports.getPlayerLastHeart = exports.getPlayerHearts = exports.getPlayerHealthType = exports.getPlayerHealth = exports.getPlayerBlackHearts = exports.getPlayerAvailableHeartSlots = exports.doesPlayerHaveAllSoulHearts = exports.doesPlayerHaveAllBlackHearts = exports.canPickEternalHearts = exports.addPlayerHealthType = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const constants_1 = require("../core/constants");
const HealthType_1 = require("../enums/HealthType");
const bitwise_1 = require("./bitwise");
const characters_1 = require("./characters");
const charge_1 = require("./charge");
const playerCollectibles_1 = require("./playerCollectibles");
const players_1 = require("./players");
const utils_1 = require("./utils");
function addPlayerHealthType(player, healthType, numHearts) {
    switch (healthType) {
        case HealthType_1.HealthType.RED: {
            player.AddHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.SOUL: {
            player.AddSoulHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.ETERNAL: {
            player.AddEternalHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.BLACK: {
            player.AddBlackHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.GOLDEN: {
            player.AddGoldenHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.BONE: {
            player.AddBoneHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.ROTTEN: {
            player.AddRottenHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.BROKEN: {
            player.AddBrokenHearts(numHearts);
            break;
        }
        case HealthType_1.HealthType.MAX_HEARTS: {
            player.AddMaxHearts(numHearts, false);
            break;
        }
    }
}
exports.addPlayerHealthType = addPlayerHealthType;
/**
 * Helper function to see if the provided player can pick up an eternal heart. (If a player already
 * has an eternal heart and full heart containers, they are not able to pick up any additional
 * eternal hearts.)
 *
 * This function's name matches the existing `EntityPlayer` methods.
 */
function canPickEternalHearts(player) {
    const eternalHearts = player.GetEternalHearts();
    const maxHearts = player.GetMaxHearts();
    const heartLimit = player.GetHeartLimit();
    return eternalHearts === 0 || maxHearts !== heartLimit;
}
exports.canPickEternalHearts = canPickEternalHearts;
/**
 * Returns whether all of the player's soul-heart-type hearts are black hearts.
 *
 * Note that this function does not consider red heart containers.
 *
 * For example:
 *
 * - If the player has one black heart, this function would return true.
 * - If the player has one soul heart and two black hearts, this function would return false.
 * - If the player has no black hearts, this function will return false.
 * - If the player has one red heart container and three black hearts, this function would return
 *   true.
 */
function doesPlayerHaveAllBlackHearts(player) {
    const soulHearts = getPlayerSoulHearts(player);
    const blackHearts = getPlayerBlackHearts(player);
    return blackHearts > 0 && soulHearts === 0;
}
exports.doesPlayerHaveAllBlackHearts = doesPlayerHaveAllBlackHearts;
/**
 * Returns whether all of the player's soul-heart-type hearts are soul hearts.
 *
 * Note that this function does not consider red heart containers.
 *
 * For example:
 *
 * - If the player has two soul hearts and one black heart, this function would return false.
 * - If the player has no soul hearts, this function will return false.
 * - If the player has one red heart container and three soul hearts, this function would return
 *   true.
 */
function doesPlayerHaveAllSoulHearts(player) {
    const soulHearts = getPlayerSoulHearts(player);
    const blackHearts = getPlayerBlackHearts(player);
    return soulHearts > 0 && blackHearts === 0;
}
exports.doesPlayerHaveAllSoulHearts = doesPlayerHaveAllSoulHearts;
/**
 * Returns the number of slots that the player has remaining for new heart containers, accounting
 * for broken hearts. For example, if the player is Judas and has 1 red heart containers and 2 full
 * soul hearts and 3 broken hearts, then this function would return 6 (i.e. 12 - 1 - 2 - 3).
 */
function getPlayerAvailableHeartSlots(player) {
    const maxHeartContainers = getPlayerMaxHeartContainers(player);
    const effectiveMaxHearts = player.GetEffectiveMaxHearts();
    const normalAndBoneHeartContainers = effectiveMaxHearts / 2;
    const soulHearts = player.GetSoulHearts();
    const soulHeartContainers = Math.ceil(soulHearts / 2);
    const totalHeartContainers = normalAndBoneHeartContainers + soulHeartContainers;
    const brokenHearts = player.GetBrokenHearts();
    const totalOccupiedHeartSlots = totalHeartContainers + brokenHearts;
    return maxHeartContainers - totalOccupiedHeartSlots;
}
exports.getPlayerAvailableHeartSlots = getPlayerAvailableHeartSlots;
/**
 * Returns the number of black hearts that the player has, excluding any soul hearts. For example,
 * if the player has one full black heart, one full soul heart, and one half black heart, this
 * function returns 3.
 *
 * This is different from the `EntityPlayer.GetBlackHearts` method, since that returns a bitmask.
 */
function getPlayerBlackHearts(player) {
    const blackHeartsBitmask = player.GetBlackHearts();
    const blackHeartBits = (0, bitwise_1.countSetBits)(blackHeartsBitmask);
    return blackHeartBits * 2;
}
exports.getPlayerBlackHearts = getPlayerBlackHearts;
/**
 * Helper function to get an object representing the player's health. You can use this in
 * combination with the `setPlayerHealth` function to restore the player's health back to a certain
 * configuration at a later time.
 *
 * This is based on the `REVEL.StoreHealth` function in the Revelations mod.
 */
function getPlayerHealth(player) {
    const character = player.GetPlayerType();
    let maxHearts = player.GetMaxHearts();
    let hearts = getPlayerHearts(player); // We use the helper function to remove rotten hearts
    let soulHearts = player.GetSoulHearts();
    let boneHearts = player.GetBoneHearts();
    const goldenHearts = player.GetGoldenHearts();
    const eternalHearts = player.GetEternalHearts();
    const rottenHearts = player.GetRottenHearts();
    const brokenHearts = player.GetBrokenHearts();
    const subPlayer = player.GetSubPlayer();
    const soulCharges = player.GetEffectiveSoulCharge();
    const bloodCharges = player.GetEffectiveBloodCharge();
    // The Forgotten and The Soul has special health, so we need to account for this.
    if (character === isaac_typescript_definitions_1.PlayerType.FORGOTTEN && subPlayer !== undefined) {
        // The Forgotten does not have red heart containers.
        maxHearts = boneHearts * 2;
        boneHearts = 0;
        // The Forgotten will always have 0 soul hearts; we need to get the soul heart amount from the
        // sub player.
        soulHearts = subPlayer.GetSoulHearts();
    }
    else if (character === isaac_typescript_definitions_1.PlayerType.SOUL && subPlayer !== undefined) {
        // The Soul will always have 0 bone hearts; we need to get the bone heart amount from the sub
        // player. We need to store it as "maxHearts" instead of "boneHearts".
        maxHearts = subPlayer.GetBoneHearts() * 2;
        hearts = subPlayer.GetHearts();
    }
    // This is the number of individual hearts shown in the HUD, minus heart containers.
    const extraHearts = Math.ceil(soulHearts / 2) + boneHearts;
    // Since bone hearts can be inserted anywhere between soul hearts, we need a separate counter to
    // track which soul heart we're currently at.
    let currentSoulHeart = 0;
    const soulHeartTypes = [];
    for (let i = 0; i < extraHearts; i++) {
        let isBoneHeart = player.IsBoneHeart(i);
        if (character === isaac_typescript_definitions_1.PlayerType.FORGOTTEN && subPlayer !== undefined) {
            isBoneHeart = subPlayer.IsBoneHeart(i);
        }
        if (isBoneHeart) {
            soulHeartTypes.push(isaac_typescript_definitions_1.HeartSubType.BONE);
        }
        else {
            // We need to add 1 here because only the second half of a black heart is considered black.
            let isBlackHeart = player.IsBlackHeart(currentSoulHeart + 1);
            if (character === isaac_typescript_definitions_1.PlayerType.FORGOTTEN && subPlayer !== undefined) {
                isBlackHeart = subPlayer.IsBlackHeart(currentSoulHeart + 1);
            }
            if (isBlackHeart) {
                soulHeartTypes.push(isaac_typescript_definitions_1.HeartSubType.BLACK);
            }
            else {
                soulHeartTypes.push(isaac_typescript_definitions_1.HeartSubType.SOUL);
            }
            // Move to the next heart.
            currentSoulHeart += 2;
        }
    }
    return {
        maxHearts,
        hearts,
        eternalHearts,
        soulHearts,
        boneHearts,
        goldenHearts,
        rottenHearts,
        brokenHearts,
        soulCharges,
        bloodCharges,
        soulHeartTypes,
    };
}
exports.getPlayerHealth = getPlayerHealth;
function getPlayerHealthType(player, healthType) {
    switch (healthType) {
        // 5.10.1
        case HealthType_1.HealthType.RED: {
            // We use the standard library helper function since the `EntityPlayer.GetHearts` method
            // returns a value that includes rotten hearts.
            return getPlayerHearts(player);
        }
        // 5.10.3
        case HealthType_1.HealthType.SOUL: {
            // We use the standard library helper function since the `EntityPlayer.GetSoulHearts` method
            // returns a value that includes black hearts.
            return getPlayerSoulHearts(player);
        }
        // 5.10.4
        case HealthType_1.HealthType.ETERNAL: {
            return player.GetEternalHearts();
        }
        // 5.10.6
        case HealthType_1.HealthType.BLACK: {
            // We use the standard library helper function since the `EntityPlayer.GetBlackHearts` method
            // returns a bit mask.
            return getPlayerBlackHearts(player);
        }
        // 5.10.7
        case HealthType_1.HealthType.GOLDEN: {
            return player.GetGoldenHearts();
        }
        // 5.10.11
        case HealthType_1.HealthType.BONE: {
            return player.GetBoneHearts();
        }
        // 5.10.12
        case HealthType_1.HealthType.ROTTEN: {
            return player.GetRottenHearts();
        }
        case HealthType_1.HealthType.BROKEN: {
            return player.GetBrokenHearts();
        }
        case HealthType_1.HealthType.MAX_HEARTS: {
            return player.GetMaxHearts();
        }
    }
}
exports.getPlayerHealthType = getPlayerHealthType;
/**
 * Returns the number of red hearts that the player has, excluding any rotten hearts. For example,
 * if the player has one full black heart, one full soul heart, and one half black heart, this
 * function returns 3.
 *
 * This is different from the `EntityPlayer.GetHearts` method, since that returns a value that
 * includes rotten hearts.
 */
function getPlayerHearts(player) {
    const rottenHearts = player.GetRottenHearts();
    const hearts = player.GetHearts();
    return hearts - rottenHearts * 2;
}
exports.getPlayerHearts = getPlayerHearts;
/**
 * Helper function that returns the type of the rightmost heart. This does not including golden
 * hearts or broken hearts, since they cannot be damaged directly.
 */
function getPlayerLastHeart(player) {
    const hearts = player.GetHearts();
    const effectiveMaxHearts = player.GetEffectiveMaxHearts();
    const soulHearts = player.GetSoulHearts();
    const blackHearts = player.GetBlackHearts();
    const eternalHearts = player.GetEternalHearts();
    const boneHearts = player.GetBoneHearts();
    const rottenHearts = player.GetRottenHearts();
    const soulHeartSlots = soulHearts / 2;
    const lastHeartIndex = boneHearts + soulHeartSlots - 1;
    const isLastHeartBone = player.IsBoneHeart(lastHeartIndex);
    if (isLastHeartBone) {
        const isLastContainerEmpty = hearts <= effectiveMaxHearts - 2;
        if (isLastContainerEmpty) {
            return HealthType_1.HealthType.BONE;
        }
        if (rottenHearts > 0) {
            return HealthType_1.HealthType.ROTTEN;
        }
        if (eternalHearts > 0) {
            return HealthType_1.HealthType.ETERNAL;
        }
        return HealthType_1.HealthType.RED;
    }
    if (soulHearts > 0) {
        const numBits = (0, bitwise_1.getNumBitsOfN)(blackHearts);
        const finalBit = (0, bitwise_1.getKBitOfN)(numBits - 1, blackHearts);
        const isBlack = finalBit === 1;
        if (isBlack) {
            return HealthType_1.HealthType.BLACK;
        }
        // If it is not a black heart, it must be a soul heart.
        return HealthType_1.HealthType.SOUL;
    }
    if (eternalHearts > 0) {
        return HealthType_1.HealthType.ETERNAL;
    }
    if (rottenHearts > 0) {
        return HealthType_1.HealthType.ROTTEN;
    }
    return HealthType_1.HealthType.RED;
}
exports.getPlayerLastHeart = getPlayerLastHeart;
/**
 * Returns the maximum heart containers that the provided player can have. Normally, this is 12, but
 * it can change depending on the character (e.g. Keeper) and other things (e.g. Mother's Kiss).
 * This function does not account for Broken Hearts; use the `getPlayerAvailableHeartSlots` helper
 * function for that.
 */
function getPlayerMaxHeartContainers(player) {
    const character = player.GetPlayerType();
    const characterMaxHeartContainers = (0, characters_1.getCharacterMaxHeartContainers)(character);
    // 1
    // Magdalene can increase her maximum heart containers with Birthright.
    if (character === isaac_typescript_definitions_1.PlayerType.MAGDALENE &&
        player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.BIRTHRIGHT)) {
        const extraMaxHeartContainersFromBirthright = 6;
        return characterMaxHeartContainers + extraMaxHeartContainersFromBirthright;
    }
    // 14, 33
    // Keeper and Tainted Keeper can increase their coin containers with Mother's Kiss and Greed's
    // Gullet.
    if ((0, players_1.isKeeper)(player)) {
        const numMothersKisses = player.GetTrinketMultiplier(isaac_typescript_definitions_1.TrinketType.MOTHERS_KISS);
        const hasGreedsGullet = player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.GREEDS_GULLET);
        const coins = player.GetNumCoins();
        const greedsGulletCoinContainers = hasGreedsGullet
            ? Math.floor(coins / 25)
            : 0;
        return (characterMaxHeartContainers +
            numMothersKisses +
            greedsGulletCoinContainers);
    }
    return characterMaxHeartContainers;
}
exports.getPlayerMaxHeartContainers = getPlayerMaxHeartContainers;
/**
 * Returns the number of soul hearts that the player has, excluding any black hearts. For example,
 * if the player has one full black heart, one full soul heart, and one half black heart, this
 * function returns 2.
 *
 * This is different from the `EntityPlayer.GetSoulHearts` method, since that returns the combined
 * number of soul hearts and black hearts.
 */
function getPlayerSoulHearts(player) {
    const soulHearts = player.GetSoulHearts();
    const blackHearts = getPlayerBlackHearts(player);
    return soulHearts - blackHearts;
}
exports.getPlayerSoulHearts = getPlayerSoulHearts;
/**
 * Helper function to determine how many heart containers that Tainted Magdalene has that will not
 * be automatically depleted over time. By default, this is 2, but this function will return 4 so
 * that it is consistent with the `player.GetHearts` and `player.GetMaxHearts` methods.
 *
 * If Tainted Magdalene has Birthright, she will gained an additional non-temporary heart container.
 *
 * This function does not validate whether the provided player is Tainted Magdalene; that should be
 * accomplished before invoking this function.
 */
function getTaintedMagdaleneNonTemporaryMaxHearts(player) {
    const maxHearts = player.GetMaxHearts();
    const hasBirthright = player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.BIRTHRIGHT);
    const maxNonTemporaryMaxHearts = hasBirthright ? 6 : 4;
    return Math.min(maxHearts, maxNonTemporaryMaxHearts);
}
exports.getTaintedMagdaleneNonTemporaryMaxHearts = getTaintedMagdaleneNonTemporaryMaxHearts;
/** Returns a `PlayerHealth` object with all zeros. */
function newPlayerHealth() {
    return {
        maxHearts: 0,
        hearts: 0,
        eternalHearts: 0,
        soulHearts: 0,
        boneHearts: 0,
        goldenHearts: 0,
        rottenHearts: 0,
        brokenHearts: 0,
        soulCharges: 0,
        bloodCharges: 0,
        soulHeartTypes: [],
    };
}
exports.newPlayerHealth = newPlayerHealth;
/**
 * Helper function to remove all of a player's black hearts and add the corresponding amount of soul
 * hearts.
 */
function playerConvertBlackHeartsToSoulHearts(player) {
    const playerHealth = getPlayerHealth(player);
    removeAllPlayerHealth(player);
    const newSoulHeartTypes = playerHealth.soulHeartTypes.map((soulHeartType) => soulHeartType === isaac_typescript_definitions_1.HeartSubType.BLACK ? isaac_typescript_definitions_1.HeartSubType.SOUL : soulHeartType);
    const playerHealthWithSoulHearts = {
        ...playerHealth,
        soulHeartTypes: newSoulHeartTypes,
    };
    setPlayerHealth(player, playerHealthWithSoulHearts);
}
exports.playerConvertBlackHeartsToSoulHearts = playerConvertBlackHeartsToSoulHearts;
/**
 * Helper function to remove all of a player's soul hearts and add the corresponding amount of black
 * hearts.
 */
function playerConvertSoulHeartsToBlackHearts(player) {
    const playerHealth = getPlayerHealth(player);
    removeAllPlayerHealth(player);
    const newSoulHeartTypes = playerHealth.soulHeartTypes.map((soulHeartType) => soulHeartType === isaac_typescript_definitions_1.HeartSubType.SOUL ? isaac_typescript_definitions_1.HeartSubType.BLACK : soulHeartType);
    const playerHealthWithBlackHearts = {
        ...playerHealth,
        soulHeartTypes: newSoulHeartTypes,
    };
    setPlayerHealth(player, playerHealthWithBlackHearts);
}
exports.playerConvertSoulHeartsToBlackHearts = playerConvertSoulHeartsToBlackHearts;
/**
 * Helper function to see if the player is out of health.
 *
 * Specifically, this function will return false if the player has 0 red hearts, 0 soul/black
 * hearts, and 0 bone hearts.
 */
function playerHasHealthLeft(player) {
    const hearts = player.GetHearts();
    const soulHearts = player.GetSoulHearts();
    const boneHearts = player.GetBoneHearts();
    return hearts > 0 || soulHearts > 0 || boneHearts > 0;
}
exports.playerHasHealthLeft = playerHasHealthLeft;
function removeAllPlayerHealth(player) {
    const goldenHearts = player.GetGoldenHearts();
    const eternalHearts = player.GetEternalHearts();
    const boneHearts = player.GetBoneHearts();
    const brokenHearts = player.GetBrokenHearts();
    // To avoid bugs, we have to remove the exact amount of certain types of hearts. We remove Golden
    // Hearts first so that they don't break.
    player.AddGoldenHearts(goldenHearts * -1);
    player.AddEternalHearts(eternalHearts * -1);
    player.AddBoneHearts(boneHearts * -1);
    player.AddBrokenHearts(brokenHearts * -1);
    player.AddMaxHearts(constants_1.MAX_PLAYER_HEART_CONTAINERS * -2, true);
    player.AddSoulHearts(constants_1.MAX_PLAYER_HEART_CONTAINERS * -2);
    // If we are The Soul, the `EntityPlayer.AddBoneHearts` method will not remove Forgotten's bone
    // hearts, so we need to explicitly handle this.
    if ((0, players_1.isCharacter)(player, isaac_typescript_definitions_1.PlayerType.SOUL)) {
        const forgotten = player.GetSubPlayer();
        if (forgotten !== undefined) {
            const forgottenBoneHearts = forgotten.GetBoneHearts();
            forgotten.AddBoneHearts(forgottenBoneHearts * -1);
        }
    }
}
exports.removeAllPlayerHealth = removeAllPlayerHealth;
/**
 * Helper function to set a player's health to a specific state. You can use this in combination
 * with the `getPlayerHealth` function to restore the player's health back to a certain
 * configuration at a later time.
 *
 * Based on the `REVEL.LoadHealth` function in the Revelations mod.
 */
function setPlayerHealth(player, playerHealth) {
    const character = player.GetPlayerType();
    const subPlayer = player.GetSubPlayer();
    // Before we add or remove any health, we have to take away Alabaster Box, if present. (Removing
    // soul hearts from the player will remove Alabaster Box charges.)
    const alabasterBoxDescriptions = [];
    const alabasterBoxActiveSlots = (0, playerCollectibles_1.getActiveItemSlots)(player, isaac_typescript_definitions_1.CollectibleType.ALABASTER_BOX);
    for (const activeSlot of alabasterBoxActiveSlots) {
        const totalCharge = (0, charge_1.getTotalCharge)(player, activeSlot);
        (0, playerCollectibles_1.setActiveItem)(player, isaac_typescript_definitions_1.CollectibleType.NULL, activeSlot);
        alabasterBoxDescriptions.push({ activeSlot, totalCharge });
    }
    removeAllPlayerHealth(player);
    // Add the red heart containers.
    if (character === isaac_typescript_definitions_1.PlayerType.SOUL && subPlayer !== undefined) {
        // Adding health to The Soul is a special case.
        subPlayer.AddMaxHearts(playerHealth.maxHearts, false);
    }
    else {
        player.AddMaxHearts(playerHealth.maxHearts, false);
    }
    // Add the eternal hearts.
    player.AddEternalHearts(playerHealth.eternalHearts);
    // Add the soul / black / bone hearts.
    let soulHeartsRemaining = playerHealth.soulHearts;
    for (const [i, soulHeartType] of playerHealth.soulHeartTypes.entries()) {
        const isHalf = playerHealth.soulHearts + playerHealth.boneHearts * 2 < (i + 1) * 2;
        let addAmount = 2;
        if (isHalf ||
            soulHeartType === isaac_typescript_definitions_1.HeartSubType.BONE ||
            soulHeartsRemaining < 2) {
            // Fix the bug where a half soul heart to the left of a bone heart will be treated as a full
            // soul heart.
            addAmount = 1;
        }
        switch (soulHeartType) {
            case isaac_typescript_definitions_1.HeartSubType.SOUL: {
                player.AddSoulHearts(addAmount);
                soulHeartsRemaining -= addAmount;
                break;
            }
            case isaac_typescript_definitions_1.HeartSubType.BLACK: {
                player.AddBlackHearts(addAmount);
                soulHeartsRemaining -= addAmount;
                break;
            }
            case isaac_typescript_definitions_1.HeartSubType.BONE: {
                player.AddBoneHearts(addAmount);
                break;
            }
        }
    }
    /**
     * Fill in the red heart containers.
     *
     * Rotten Hearts must be filled in first in order for this to work properly, since they conflict
     * with half red hearts.
     *
     * We multiply by two because the `EntityPlayer.GetRottenHearts` function returns the actual
     * number of rotten hearts, but the `EntityPlayer.AddRottenHearts` works like the other heart
     * functions in that a value of 1 is equivalent to a half-heart.
     */
    player.AddRottenHearts(playerHealth.rottenHearts * 2);
    if (character === isaac_typescript_definitions_1.PlayerType.MAGDALENE_B) {
        // Adding 1 heart to Tainted Magdalene will actually add two hearts.
        (0, utils_1.repeat)(playerHealth.hearts, () => {
            if (player.HasFullHearts()) {
                return;
            }
            const hearts = player.GetHearts();
            const maxHearts = player.GetMaxHearts();
            if (hearts === maxHearts - 1) {
                player.AddHearts(1);
                return;
            }
            player.AddHearts(1);
            player.AddHearts(-1);
        });
    }
    else {
        player.AddHearts(playerHealth.hearts);
    }
    player.AddGoldenHearts(playerHealth.goldenHearts);
    player.AddBrokenHearts(playerHealth.brokenHearts);
    // Set the Bethany / Tainted Bethany charges.
    if (character === isaac_typescript_definitions_1.PlayerType.BETHANY) {
        player.SetSoulCharge(playerHealth.soulCharges);
    }
    else if (character === isaac_typescript_definitions_1.PlayerType.BETHANY_B) {
        player.SetBloodCharge(playerHealth.bloodCharges);
    }
    // Re-add the Alabaster Box, if present.
    for (const { activeSlot, totalCharge } of alabasterBoxDescriptions) {
        (0, playerCollectibles_1.setActiveItem)(player, isaac_typescript_definitions_1.CollectibleType.ALABASTER_BOX, activeSlot, totalCharge);
    }
}
exports.setPlayerHealth = setPlayerHealth;
/**
 * Helper function to see if a certain damage amount would deal "permanent" damage to Tainted
 * Magdalene.
 *
 * Tainted Magdalene has "permanent" health and "temporary" health. When standing still and doing
 * nothing, all of Tainted Magdalene's temporary health will eventually go away.
 *
 * Before using this function, it is expected that you check to see if the player is Tainted
 * Magdalene first, or else it will give a nonsensical result.
 */
function wouldDamageTaintedMagdaleneNonTemporaryHeartContainers(player, damageAmount) {
    // Regardless of the damage amount, damage to a player cannot remove a soul heart and a red heart
    // at the same time.
    const soulHearts = player.GetSoulHearts();
    if (soulHearts > 0) {
        return false;
    }
    // Regardless of the damage amount, damage to a player cannot remove a bone heart and a red heart
    // at the same time.
    const boneHearts = player.GetBoneHearts();
    if (boneHearts > 0) {
        return false;
    }
    // Account for rotten hearts eating away at more red hearts than usual.
    const hearts = player.GetHearts();
    const rottenHearts = player.GetRottenHearts();
    const effectiveDamageAmount = damageAmount + Math.min(rottenHearts, damageAmount);
    const heartsAfterDamage = hearts - effectiveDamageAmount;
    const nonTemporaryMaxHearts = getTaintedMagdaleneNonTemporaryMaxHearts(player);
    return heartsAfterDamage < nonTemporaryMaxHearts;
}
exports.wouldDamageTaintedMagdaleneNonTemporaryHeartContainers = wouldDamageTaintedMagdaleneNonTemporaryHeartContainers;
