"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.texelEquals = exports.spriteEquals = exports.setSpriteOpacity = exports.newSprite = exports.getLastFrameOfAnimation = exports.clearSprite = void 0;
const constants_1 = require("../core/constants");
const color_1 = require("./color");
const kColor_1 = require("./kColor");
const utils_1 = require("./utils");
/**
 * Helper function to clear all layers or specific layers from a sprite without unloading the
 * attached anm2 file.
 *
 * This function is variadic, which means you can pass as many layer IDs as you want to clear. If no
 * specific layers are passed, the function will clear every layer.
 *
 * If you want to clear all of the layers of a sprite and don't care about unloading the attached
 * anm2 file, then use the `Sprite.Reset` method instead.
 *
 * Since there is no official API method to clear specific layers from a sprite, we work around it
 * by setting the spritesheet to a transparent PNG file corresponding to the `EMPTY_PNG_PATH`
 * constant.
 *
 * This function will still work identically if PNG file does not exist, but it will cause a
 * spurious error to appear in the "log.txt" file. If silencing these errors is desired, you can
 * create a transparent 1 pixel PNG file in your mod's resources folder at `EMPTY_PNG_PATH`.
 *
 * @allowEmptyVariadic
 */
function clearSprite(sprite, ...layerIDs) {
    if (layerIDs.length === 0) {
        const numLayers = sprite.GetLayerCount();
        layerIDs = (0, utils_1.eRange)(numLayers);
    }
    for (const layerID of layerIDs) {
        sprite.ReplaceSpritesheet(layerID, constants_1.EMPTY_PNG_PATH);
    }
    sprite.LoadGraphics();
}
exports.clearSprite = clearSprite;
/**
 * Helper function that returns the number of the final frame in a particular animation for a
 * sprite. By default, it will use the currently playing animation, but you can also specify a
 * specific animation to check.
 *
 * Note that this function is bugged with the Stop Watch or the Broken Watch, since using the
 * `Sprite.SetFrame` method will reset the internal accumulator used to slow down the playback speed
 * of the animation. (The `PlaybackSpeed` field of the sprite is not used.) Thus, it is only safe to
 * use this function on animations that are not slowed down by Stop Watch or Broken Watch, such as
 * player animations.
 */
function getLastFrameOfAnimation(sprite, animation) {
    // Record the current sprite status.
    const currentAnimation = sprite.GetAnimation();
    const currentFrame = sprite.GetFrame();
    // Get the final frame.
    if (animation !== undefined && animation !== currentAnimation) {
        sprite.SetAnimation(animation);
    }
    sprite.SetLastFrame();
    const finalFrame = sprite.GetFrame();
    // Set the sprite back to the way it was.
    if (animation !== undefined && animation !== currentAnimation) {
        sprite.Play(currentAnimation, true);
    }
    sprite.SetFrame(currentFrame);
    return finalFrame;
}
exports.getLastFrameOfAnimation = getLastFrameOfAnimation;
/**
 * Helper function to load a new sprite and play its default animation.
 *
 * @param anm2Path The path to the "anm2" file that should be loaded.
 * @param pngPath Optional. The path to a custom PNG file that should be loaded on layer 0 of the
 *                sprite.
 */
function newSprite(anm2Path, pngPath) {
    const sprite = Sprite();
    if (pngPath === undefined) {
        sprite.Load(anm2Path, true);
    }
    else {
        sprite.Load(anm2Path, false);
        sprite.ReplaceSpritesheet(0, pngPath);
        sprite.LoadGraphics();
    }
    const defaultAnimation = sprite.GetDefaultAnimation();
    sprite.Play(defaultAnimation, true);
    return sprite;
}
exports.newSprite = newSprite;
/**
 * Helper function to keep a sprite's color the same values as it already is but set the opacity to
 * a specific value.
 *
 * @param sprite The sprite to set.
 * @param alpha A value between 0 and 1 that represents the fade amount.
 */
function setSpriteOpacity(sprite, alpha) {
    const fadedColor = (0, color_1.copyColor)(sprite.Color);
    fadedColor.A = alpha;
    sprite.Color = fadedColor;
}
exports.setSpriteOpacity = setSpriteOpacity;
/**
 * Helper function to check if two sprite layers have the same sprite sheet by using the
 * `Sprite.GetTexel` method.
 *
 * Since checking every single texel in the entire sprite is very expensive, this function requires
 * that you provide a range of specific texels to check.
 */
function spriteEquals(sprite1, sprite2, layerID, xStart, xFinish, xIncrement, yStart, yFinish, yIncrement) {
    // Iterate over N texels, checking for equality at each step. The center of the sprite is equal to
    // the "pivot" point in the anm2 file.
    for (let x = xStart; x <= xFinish; x += xIncrement) {
        for (let y = yStart; y <= yFinish; y += yIncrement) {
            const position = Vector(x, y);
            if (!texelEquals(sprite1, sprite2, position, layerID)) {
                return false;
            }
        }
    }
    return true;
}
exports.spriteEquals = spriteEquals;
/** Helper function to check if two texels on a sprite are equivalent to each other. */
function texelEquals(sprite1, sprite2, position, layerID) {
    const kColor1 = sprite1.GetTexel(position, constants_1.VectorZero, 1, layerID);
    const kColor2 = sprite2.GetTexel(position, constants_1.VectorZero, 1, layerID);
    return (0, kColor_1.kColorEquals)(kColor1, kColor2);
}
exports.texelEquals = texelEquals;
