"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.topStreakTextStart = exports.streakTextGetShaderParams = exports.streakTextPostRender = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const cachedEnumValues_1 = require("../../../../cachedEnumValues");
const cachedClasses_1 = require("../../../../core/cachedClasses");
const constants_1 = require("../../../../core/constants");
const UIStreakAnimation_1 = require("../../../../enums/private/UIStreakAnimation");
const frames_1 = require("../../../../functions/frames");
const ui_1 = require("../../../../functions/ui");
const v_1 = require("./v");
/** Corresponds to "resources/gfx/ui/ui_streak.anm2". */
const UI_STREAK_ANIMATION_END_FRAMES = {
    [UIStreakAnimation_1.UIStreakAnimation.NONE]: 0,
    [UIStreakAnimation_1.UIStreakAnimation.TEXT]: 69,
    [UIStreakAnimation_1.UIStreakAnimation.TEXT_STAY]: 1,
};
/** This must match the name of the shader in "shaders.xml". */
const EMPTY_SHADER_NAME = "IsaacScript-RenderAboveHUD";
/**
 * The frame of the "Text" animation that corresponds to when it reaches the center of the screen
 * and stays put.
 */
const TEXT_STAY_FRAME = 8;
/** The frame of the "Text" animation that corresponds to when it starts to move right. */
const TEXT_OUT_FRAME = 60;
/** This matches the offset that the vanilla game uses; determined via trial and error. */
const STREAK_SPRITE_TOP_OFFSET = Vector(0, 47);
/** This matches the offset that the vanilla game uses; determined via trial and error. */
const STREAK_SPRITE_BOTTOM_OFFSET = Vector(0, -48.25);
/**
 * The offset from the bottom of the sprite that the rendered text should go; determined via trial
 * and error.
 */
const STREAK_TEXT_BOTTOM_Y_OFFSET = -9;
/**
 * Corresponds to the vanilla value; determined via trial and error.
 *
 * 8 is too little and 9 has the vanilla text come out just slightly ahead, so we go with 9.
 */
const NUM_RENDER_FRAMES_MAP_HELD_BEFORE_STREAK_TEXT = 11;
/** Taken from StageAPI. */
const TEXT_IN_ADJUSTMENTS = [-800, -639, -450, -250, -70, 10, 6, 3];
/** Taken from StageAPI. */
const TEXT_OUT_ADJUSTMENTS = [
    0, -5, -10, -15, -20, 144, 308, 472, 636, 800,
];
/** Taken from StageAPI. */
const TEXT_IN_SCALES = [
    Vector(3, 0.2),
    Vector(2.6, 0.36),
    Vector(2.2, 0.52),
    Vector(1.8, 0.68),
    Vector(1.4, 0.84),
    Vector(0.95, 1.05),
    Vector(0.97, 1.03),
    Vector(0.98, 1.02),
];
/** Taken from StageAPI. */
const TEXT_OUT_SCALES = [
    Vector(1, 1),
    Vector(0.99, 1.03),
    Vector(0.98, 1.05),
    Vector(0.96, 1.08),
    Vector(0.95, 1.1),
    Vector(1.36, 0.92),
    Vector(1.77, 0.74),
    Vector(2.18, 0.56),
    Vector(2.59, 0.38),
    Vector(3, 0.2),
];
// ModCallback.POST_RENDER (2)
function streakTextPostRender() {
    // The top streak only plays when the player arrives on the floor (or continues a game from the
    // main menu.)
    checkEndTopStreakText();
    // The bottom streak only plays when the player holds down the map button.
    trackMapInputPressed();
    checkStartBottomStreakText();
    checkEndBottomStreakText();
}
exports.streakTextPostRender = streakTextPostRender;
function checkEndTopStreakText() {
    if (v_1.v.run.topStreakTextStartedRenderFrame === null ||
        v_1.v.run.topStreakText.animation !== UIStreakAnimation_1.UIStreakAnimation.TEXT_STAY) {
        return;
    }
    const elapsedFrames = (0, frames_1.getElapsedRenderFramesSince)(v_1.v.run.topStreakTextStartedRenderFrame);
    if (elapsedFrames >= 115) {
        v_1.v.run.topStreakText.animation = UIStreakAnimation_1.UIStreakAnimation.TEXT;
        // We adjust by the frame backwards by an arbitrary amount to roughly align with the speed of
        // the vanilla animation.
        v_1.v.run.topStreakText.frame = TEXT_OUT_FRAME - 2;
    }
}
function trackMapInputPressed() {
    const gameFrameCount = cachedClasses_1.game.GetFrameCount();
    for (const controllerIndex of cachedEnumValues_1.CONTROLLER_INDEX_VALUES) {
        const oldPushedMapFrame = v_1.v.run.controllerIndexPushingMapRenderFrame.get(controllerIndex);
        const isPushingMap = Input.IsActionPressed(isaac_typescript_definitions_1.ButtonAction.MAP, controllerIndex);
        if (isPushingMap) {
            if (oldPushedMapFrame === undefined) {
                v_1.v.run.controllerIndexPushingMapRenderFrame.set(controllerIndex, gameFrameCount);
            }
        }
        else {
            v_1.v.run.controllerIndexPushingMapRenderFrame.delete(controllerIndex);
        }
    }
}
/**
 * If the map input has been pressed down for long enough, play the animation where the level streak
 * slides in from the left.
 */
function checkStartBottomStreakText() {
    if (v_1.v.run.bottomStreakText.animation !== UIStreakAnimation_1.UIStreakAnimation.NONE) {
        return;
    }
    const pushedMapFrames = [
        ...v_1.v.run.controllerIndexPushingMapRenderFrame.values(),
    ];
    if (pushedMapFrames.length === 0) {
        return;
    }
    const earliestFrame = Math.min(...pushedMapFrames);
    const elapsedFrames = (0, frames_1.getElapsedGameFramesSince)(earliestFrame);
    if (elapsedFrames >= NUM_RENDER_FRAMES_MAP_HELD_BEFORE_STREAK_TEXT) {
        v_1.v.run.bottomStreakText.animation = UIStreakAnimation_1.UIStreakAnimation.TEXT;
        v_1.v.run.bottomStreakText.frame = 0;
    }
}
/**
 * If the map input has been released, play the animation where the level streak slides out to the
 * right.
 */
function checkEndBottomStreakText() {
    if (v_1.v.run.bottomStreakText.animation !== UIStreakAnimation_1.UIStreakAnimation.TEXT_STAY) {
        return;
    }
    const pushedMapFrames = [
        ...v_1.v.run.controllerIndexPushingMapRenderFrame.values(),
    ];
    if (pushedMapFrames.length === 0) {
        v_1.v.run.bottomStreakText.animation = UIStreakAnimation_1.UIStreakAnimation.TEXT;
        // We adjust by the frame backwards by an arbitrary amount to roughly align with the speed of
        // the vanilla animation.
        v_1.v.run.bottomStreakText.frame = TEXT_OUT_FRAME - 2;
    }
}
// ModCallback.GET_SHADER_PARAMS (22)
function streakTextGetShaderParams(customStage, shaderName) {
    if (shaderName !== EMPTY_SHADER_NAME) {
        return;
    }
    const topCenterPos = (0, ui_1.getScreenTopCenterPos)();
    const topStreakPosition = topCenterPos.add(STREAK_SPRITE_TOP_OFFSET);
    renderStreakText(customStage, v_1.v.run.topStreakText, topStreakPosition);
    const bottomCenterPos = (0, ui_1.getScreenBottomCenterPos)();
    const bottomStreakPosition = bottomCenterPos.add(STREAK_SPRITE_BOTTOM_OFFSET);
    renderStreakText(customStage, v_1.v.run.bottomStreakText, bottomStreakPosition);
}
exports.streakTextGetShaderParams = streakTextGetShaderParams;
function renderStreakText(customStage, streakText, position) {
    if (streakText.animation === UIStreakAnimation_1.UIStreakAnimation.NONE) {
        return;
    }
    if (streakText.animation !== UIStreakAnimation_1.UIStreakAnimation.TEXT_STAY) {
        const { pauseFrame } = streakText;
        streakText.pauseFrame = !streakText.pauseFrame;
        if (!pauseFrame) {
            streakText.frame++;
        }
    }
    const endFrame = UI_STREAK_ANIMATION_END_FRAMES[streakText.animation];
    if (streakText.frame > endFrame) {
        streakText.animation = UIStreakAnimation_1.UIStreakAnimation.NONE;
        streakText.frame = 0;
        return;
    }
    if (streakText.animation === UIStreakAnimation_1.UIStreakAnimation.TEXT &&
        streakText.frame === TEXT_STAY_FRAME) {
        streakText.animation = UIStreakAnimation_1.UIStreakAnimation.TEXT_STAY;
        streakText.frame = 0;
    }
    const isPaused = cachedClasses_1.game.IsPaused();
    if (isPaused) {
        return;
    }
    const font = cachedClasses_1.fonts.upheaval;
    const { name } = customStage;
    const numberSuffix = v_1.v.run.firstFloor ? "I" : "II";
    const nameWithNumberSuffix = `${name} ${numberSuffix}`;
    const length = font.GetStringWidthUTF8(nameWithNumberSuffix);
    const centeredX = position.X - length / 2;
    let adjustment = 0;
    let scale = constants_1.VectorOne;
    if (streakText.animation === UIStreakAnimation_1.UIStreakAnimation.TEXT) {
        if (streakText.frame < TEXT_STAY_FRAME) {
            adjustment = TEXT_IN_ADJUSTMENTS[streakText.frame] ?? 0;
            scale = TEXT_IN_SCALES[streakText.frame] ?? constants_1.VectorOne;
        }
        else {
            const adjustedFrame = streakText.frame - TEXT_OUT_FRAME;
            adjustment = TEXT_OUT_ADJUSTMENTS[adjustedFrame] ?? 0;
            scale = TEXT_OUT_SCALES[adjustedFrame] ?? constants_1.VectorOne;
        }
    }
    const adjustedX = centeredX + adjustment;
    const adjustedY = position.Y + STREAK_TEXT_BOTTOM_Y_OFFSET;
    font.DrawStringScaled(nameWithNumberSuffix, adjustedX, adjustedY, scale.X, scale.Y, constants_1.KColorDefault);
}
function topStreakTextStart() {
    const level = cachedClasses_1.game.GetLevel();
    const renderFrameCount = Isaac.GetFrameCount();
    // Show the vanilla streak text, which will have a blank name because of the -1 floor.
    level.ShowName(false);
    // Initiate the animation for the custom text.
    v_1.v.run.topStreakText.animation = UIStreakAnimation_1.UIStreakAnimation.TEXT;
    v_1.v.run.topStreakText.frame = 0;
    v_1.v.run.topStreakTextStartedRenderFrame = renderFrameCount;
}
exports.topStreakTextStart = topStreakTextStart;
