"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PostCursedTeleport = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const cachedClasses_1 = require("../../core/cachedClasses");
const ModCallbackCustom_1 = require("../../enums/ModCallbackCustom");
const flag_1 = require("../../functions/flag");
const frames_1 = require("../../functions/frames");
const playerDataStructures_1 = require("../../functions/playerDataStructures");
const players_1 = require("../../functions/players");
const shouldFire_1 = require("../../shouldFire");
const CustomCallback_1 = require("../private/CustomCallback");
const v = {
    run: {
        playersDamageFrameMap: new Map(),
    },
    level: {
        numSacrifices: 0,
    },
};
class PostCursedTeleport extends CustomCallback_1.CustomCallback {
    v = v;
    shouldFire = shouldFire_1.shouldFirePlayer;
    constructor() {
        super();
        this.customCallbacksUsed = [
            [ModCallbackCustom_1.ModCallbackCustom.ENTITY_TAKE_DMG_PLAYER, this.entityTakeDmgPlayer],
            [
                ModCallbackCustom_1.ModCallbackCustom.POST_PLAYER_RENDER_REORDERED,
                this.postPlayerRenderReorderedPlayer,
                [isaac_typescript_definitions_1.PlayerVariant.PLAYER], // Co-op babies cannot perform Cursed Eye teleports.
            ],
        ];
    }
    // ModCallbackCustom.ENTITY_TAKE_DMG_PLAYER
    entityTakeDmgPlayer = (player, _amount, damageFlags, _source, _countdownFrames) => {
        this.incrementNumSacrifices(damageFlags); // Has to be before setting the damage frame.
        this.setDamageFrame(player, damageFlags);
        return undefined;
    };
    incrementNumSacrifices(damageFlags) {
        const room = cachedClasses_1.game.GetRoom();
        const roomType = room.GetType();
        const isSpikeDamage = (0, flag_1.hasFlag)(damageFlags, isaac_typescript_definitions_1.DamageFlag.SPIKES);
        if (roomType === isaac_typescript_definitions_1.RoomType.SACRIFICE && isSpikeDamage) {
            v.level.numSacrifices++;
        }
    }
    setDamageFrame(player, damageFlags) {
        const gameFrameCount = cachedClasses_1.game.GetFrameCount();
        // Don't do anything if we already activated the callback on this frame.
        const trackingArray = (0, playerDataStructures_1.mapGetPlayer)(v.run.playersDamageFrameMap, player);
        if (trackingArray !== undefined) {
            const [lastDamageFrame, callbackFiredOnThisFrame] = trackingArray;
            if (lastDamageFrame === gameFrameCount && callbackFiredOnThisFrame) {
                return;
            }
        }
        // Don't do anything if this could be a Sacrifice Room teleport.
        if (this.isPotentialNaturalTeleportFromSacrificeRoom(damageFlags)) {
            return;
        }
        const newTrackingArray = [gameFrameCount, false];
        (0, playerDataStructures_1.mapSetPlayer)(v.run.playersDamageFrameMap, player, newTrackingArray);
    }
    isPotentialNaturalTeleportFromSacrificeRoom(damageFlags) {
        const room = cachedClasses_1.game.GetRoom();
        const roomType = room.GetType();
        const isSpikeDamage = (0, flag_1.hasFlag)(damageFlags, isaac_typescript_definitions_1.DamageFlag.SPIKES);
        // Don't record the frame if we are potentially going to the Angel Room or the Dark Room from a
        // Sacrifice Room.
        return (roomType === isaac_typescript_definitions_1.RoomType.SACRIFICE &&
            isSpikeDamage &&
            (v.level.numSacrifices === 6 || v.level.numSacrifices >= 12));
    }
    // ModCallbackCustom.POST_PLAYER_RENDER_REORDERED
    // PlayerVariant.PLAYER (0)
    postPlayerRenderReorderedPlayer = (player, _renderOffset) => {
        // Retrieve information about this player.
        const trackingArray = (0, playerDataStructures_1.mapGetPlayer)(v.run.playersDamageFrameMap, player);
        if (trackingArray === undefined) {
            return;
        }
        const [lastDamageFrame, callbackActivatedOnThisFrame] = trackingArray;
        if (!this.playerIsTeleportingFromCursedTeleport(player, lastDamageFrame)) {
            return;
        }
        // Do nothing if the callback already fired on this frame.
        if (callbackActivatedOnThisFrame) {
            return;
        }
        const gameFrameCount = cachedClasses_1.game.GetFrameCount();
        const newTrackingArray = [gameFrameCount, true];
        (0, playerDataStructures_1.mapSetPlayer)(v.run.playersDamageFrameMap, player, newTrackingArray);
        this.fire(player);
    };
    playerIsTeleportingFromCursedTeleport(player, lastDamageFrame) {
        // Check to see if this is the frame that we last took damage.
        if (!(0, frames_1.onGameFrame)(lastDamageFrame)) {
            return false;
        }
        // Check to see if this is the 1st frame that we are teleporting.
        const sprite = player.GetSprite();
        if (!sprite.IsPlaying("TeleportUp") ||
            sprite.GetFrame() !== 1 // The 0th frame never fires
        ) {
            return false;
        }
        if (player.HasCollectible(isaac_typescript_definitions_1.CollectibleType.CURSED_EYE)) {
            return true;
        }
        const numHitsRemaining = (0, players_1.getPlayerNumHitsRemaining)(player);
        if (player.HasTrinket(isaac_typescript_definitions_1.TrinketType.CURSED_SKULL) && numHitsRemaining === 1) {
            return true;
        }
        return false;
    }
}
exports.PostCursedTeleport = PostCursedTeleport;
