"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExtraConsoleCommands = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const decorators_1 = require("../../../decorators");
const ModCallbackCustom_1 = require("../../../enums/ModCallbackCustom");
const console_1 = require("../../../functions/console");
const flag_1 = require("../../../functions/flag");
const log_1 = require("../../../functions/log");
const string_1 = require("../../../functions/string");
const utils_1 = require("../../../functions/utils");
const Feature_1 = require("../../private/Feature");
const commands = __importStar(require("./extraConsoleCommands/commands"));
const v_1 = require("./extraConsoleCommands/v");
/**
 * When you enable this feature, many custom commands will be added to the in-game console. See the
 * [dedicated command list](ExtraConsoleCommandsList) for more information about them.
 *
 * Note that in order to avoid conflicts, if two or more mods enable this feature, then the first
 * loaded one will control all of the command logic. When this occurs, a global variable of
 * `__ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE` will be created and will automatically be
 * used by the non-main instances. For this reason, if you use multiple mods with
 * `isaacscript-common` and a custom command from the standard library is not working properly, then
 * you might need to get another mod author to update their version of `isaacscript-common`.
 */
class ExtraConsoleCommands extends Feature_1.Feature {
    /** @internal */
    v = v_1.v;
    isMainFeature;
    commandFunctionMap = new Map();
    /** @internal */
    constructor() {
        super();
        // Only one instance of this feature can be instantiated across all mods.
        this.isMainFeature =
            __ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE === undefined;
        if (!this.isMainFeature) {
            return;
        }
        // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
        __ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE = this;
        this.callbacksUsed = [
            // 1
            [isaac_typescript_definitions_1.ModCallback.POST_UPDATE, this.postUpdate],
            // 8
            [
                isaac_typescript_definitions_1.ModCallback.EVALUATE_CACHE,
                this.evaluateCacheDamage,
                [isaac_typescript_definitions_1.CacheFlag.DAMAGE], // 1 << 0
            ],
            // 8
            [
                isaac_typescript_definitions_1.ModCallback.EVALUATE_CACHE,
                this.evaluateCacheFireDelay,
                [isaac_typescript_definitions_1.CacheFlag.FIRE_DELAY], // 1 << 1
            ],
            // 8
            [
                isaac_typescript_definitions_1.ModCallback.EVALUATE_CACHE,
                this.evaluateCacheSpeed,
                [isaac_typescript_definitions_1.CacheFlag.SPEED], // 1 << 4
            ],
            // 8
            [
                isaac_typescript_definitions_1.ModCallback.EVALUATE_CACHE,
                this.evaluateCacheFlying,
                [isaac_typescript_definitions_1.CacheFlag.FLYING], // 1 << 7
            ],
            // 12
            [isaac_typescript_definitions_1.ModCallback.POST_CURSE_EVAL, this.postCurseEval],
            // 22
            [isaac_typescript_definitions_1.ModCallback.EXECUTE_CMD, this.executeCmd],
            // 61
            [isaac_typescript_definitions_1.ModCallback.POST_FIRE_TEAR, this.postFireTear],
        ];
        this.customCallbacksUsed = [
            [ModCallbackCustom_1.ModCallbackCustom.ENTITY_TAKE_DMG_PLAYER, this.entityTakeDmgPlayer],
        ];
        for (const [funcName, func] of Object.entries(commands)) {
            this.commandFunctionMap.set(funcName, func);
        }
    }
    // ModCallback.POST_UPDATE (1)
    postUpdate = () => {
        if (v_1.v.persistent.spamBloodRights) {
            const player = Isaac.GetPlayer();
            player.UseActiveItem(isaac_typescript_definitions_1.CollectibleType.BLOOD_RIGHTS);
        }
    };
    // ModCallback.EVALUATE_CACHE (8)
    // CacheFlag.DAMAGE (1 << 0)
    evaluateCacheDamage = (player) => {
        if (v_1.v.persistent.damage) {
            player.Damage = v_1.v.persistent.damageAmount;
        }
    };
    // ModCallback.EVALUATE_CACHE (8)
    // CacheFlag.FIRE_DELAY (1 << 1)
    evaluateCacheFireDelay = (player) => {
        if (v_1.v.persistent.tears) {
            player.FireDelay = v_1.v.persistent.tearsAmount;
        }
    };
    // ModCallback.EVALUATE_CACHE (8)
    // CacheFlag.SPEED (1 << 4)
    evaluateCacheSpeed = (player) => {
        if (v_1.v.persistent.speed) {
            player.MoveSpeed = v_1.v.persistent.speedAmount;
        }
    };
    // ModCallback.EVALUATE_CACHE (8)
    // CacheFlag.FLYING (1 << 7)
    evaluateCacheFlying = (player) => {
        if (v_1.v.persistent.flight) {
            player.CanFly = true;
        }
    };
    // ModCallback.POST_CURSE_EVAL (12)
    postCurseEval = (curses) => {
        if (v_1.v.persistent.disableCurses) {
            return (0, flag_1.bitFlags)(isaac_typescript_definitions_1.LevelCurse.NONE);
        }
        let newCurses = curses;
        // 1
        if (v_1.v.persistent.darkness) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.DARKNESS);
        }
        // 2
        if (v_1.v.persistent.labyrinth) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.LABYRINTH);
        }
        // 3
        if (v_1.v.persistent.lost) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.LOST);
        }
        // 4
        if (v_1.v.persistent.unknown) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.UNKNOWN);
        }
        // 5
        if (v_1.v.persistent.cursed) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.CURSED);
        }
        // 6
        if (v_1.v.persistent.maze) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.MAZE);
        }
        // 7
        if (v_1.v.persistent.blind) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.BLIND);
        }
        // 8
        if (v_1.v.persistent.giant) {
            newCurses = (0, flag_1.addFlag)(newCurses, isaac_typescript_definitions_1.LevelCurse.GIANT);
        }
        return curses === newCurses ? undefined : newCurses;
    };
    // ModCallback.EXECUTE_CMD (22)
    executeCmd = (command, params) => {
        const resultTuple = (0, string_1.getMapPartialMatch)(command, this.commandFunctionMap);
        if (resultTuple === undefined) {
            // We opt to not print an error message because a non-IsaacScript mod may have configured a
            // custom console command.
            return;
        }
        const [commandName, commandFunction] = resultTuple;
        print(`Command: ${commandName}`);
        commandFunction(params);
    };
    // ModCallback.POST_FIRE_TEAR (61)
    postFireTear = (tear) => {
        if (v_1.v.persistent.chaosCardTears) {
            tear.ChangeVariant(isaac_typescript_definitions_1.TearVariant.CHAOS_CARD);
        }
    };
    // ModCallbackCustom.ENTITY_TAKE_DMG_PLAYER
    entityTakeDmgPlayer = (_player, _damageAmount, _damageFlags, _damageSource, _damageCountdownFrames) => {
        if (v_1.v.persistent.spamBloodRights) {
            return false;
        }
        return undefined;
    };
    /**
     * Helper function to add a custom console command.
     *
     * The standard library comes with [many existing console commands](ExtraConsoleCommandsList) that
     * are useful for debugging, but you can also add your own commands that are useful for your
     * particular mod. It's easier to add commands to the existing command system than to add your own
     * logic manually to the `EXECUTE_CMD` callback.
     *
     * This function is intended to be called when your mod is first loading.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.EXTRA_CONSOLE_COMMANDS`.
     *
     * @public
     */
    addConsoleCommand(commandName, commandFunction) {
        if (!this.isMainFeature) {
            (0, utils_1.assertDefined)(__ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE, "Failed to find the non-main isaacscript-common extra console commands feature in the global variable.");
            __ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE.addConsoleCommand(commandName, commandFunction);
            return;
        }
        if ((0, console_1.isVanillaConsoleCommand)(commandName)) {
            (0, log_1.logError)(`Failed to add a new console command of "${commandName}" because that name already belongs to a vanilla command. You must pick a non-colliding name.`);
            return;
        }
        if (this.commandFunctionMap.has(commandName)) {
            (0, log_1.logError)(`Failed to add a new console command of "${commandName}" because there is already an existing custom command by that name. If you want to overwrite a command from the standard library, you can use the "removeExtraConsoleCommand" function.`);
            return;
        }
        this.commandFunctionMap.set(commandName, commandFunction);
    }
    /**
     * Helper function to remove a custom console command.
     *
     * The standard library comes with [many existing console commands](ExtraConsoleCommandsList) that
     * are useful for debugging. If you want to disable one of them, use this function.
     *
     * This function is intended to be called when your mod is first loading.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.EXTRA_CONSOLE_COMMANDS`.
     *
     * @public
     */
    removeConsoleCommand(commandName) {
        if (!this.isMainFeature) {
            (0, utils_1.assertDefined)(__ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE, "Failed to find the non-main isaacscript-common extra console commands feature in the global variable.");
            __ISAACSCRIPT_COMMON_EXTRA_CONSOLE_COMMANDS_FEATURE.removeConsoleCommand(commandName);
            return;
        }
        if (!this.commandFunctionMap.has(commandName)) {
            error(`Failed to remove the console command of "${commandName}", since it does not already exist in the command map.`);
        }
        this.commandFunctionMap.delete(commandName);
    }
    /**
     * Helper function to remove all custom console commands.
     *
     * The standard library comes with [many existing console commands](ExtraConsoleCommandsList) that
     * are useful for debugging. If you want to disable all of them after this feature has already
     * been initialized, use this function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.EXTRA_CONSOLE_COMMANDS`.
     *
     * @public
     */
    removeAllConsoleCommands() {
        this.commandFunctionMap.clear();
    }
}
exports.ExtraConsoleCommands = ExtraConsoleCommands;
__decorate([
    decorators_1.Exported
], ExtraConsoleCommands.prototype, "addConsoleCommand", null);
__decorate([
    decorators_1.Exported
], ExtraConsoleCommands.prototype, "removeConsoleCommand", null);
__decorate([
    decorators_1.Exported
], ExtraConsoleCommands.prototype, "removeAllConsoleCommands", null);
