local ____lualib = require("lualib_bundle")
local __TS__ArrayMap = ____lualib.__TS__ArrayMap
local __TS__New = ____lualib.__TS__New
local ____exports = {}
local ____cachedClasses = require("core.cachedClasses")
local game = ____cachedClasses.game
local ____ReadonlySet = require("types.ReadonlySet")
local ReadonlySet = ____ReadonlySet.ReadonlySet
local ____playerIndex = require("functions.playerIndex")
local getAllPlayers = ____playerIndex.getAllPlayers
local ____types = require("functions.types")
local isFunction = ____types.isFunction
--- Helper function to throw an error (using the `error` Lua function) if the provided value is equal
-- to `undefined`.
-- 
-- This is useful to have TypeScript narrow a `T | undefined` value to `T` in a concise way.
function ____exports.assertDefined(self, value, ...)
    local ____bindingPattern0 = {...}
    local msg
    msg = ____bindingPattern0[1]
    if value == nil then
        error(msg)
    end
end
--- Helper function to throw an error (using the `error` Lua function) if the provided value is equal
-- to `null`.
-- 
-- This is useful to have TypeScript narrow a `T | null` value to `T` in a concise way.
function ____exports.assertNotNull(self, value, ...)
    local ____bindingPattern0 = {...}
    local msg
    msg = ____bindingPattern0[1]
    if value == nil then
        error(msg)
    end
end
--- Helper function to return an array of integers with the specified range, inclusive on the lower
-- end and exclusive on the high end. (The "e" in the function name stands for exclusive.) Thus,
-- this function works in a similar way as the built-in `range` function from Python.
-- 
-- If the end is lower than the start, an empty array will be returned.
-- 
-- For example:
-- 
-- - `eRange(2)` returns `[0, 1]`.
-- - `eRange(3)` returns `[0, 1, 2]`.
-- - `eRange(-3)` returns `[0, -1, -2]`.
-- - `eRange(1, 3)` returns `[1, 2]`.
-- - `eRange(2, 5)` returns `[2, 3, 4]`.
-- - `eRange(5, 2)` returns `[]`.
-- - `eRange(3, 3)` returns `[]`.
-- 
-- @param start The integer to start at.
-- @param end Optional. The integer to end at. If not specified, then the start will be 0 and the
-- first argument will be the end.
-- @param increment Optional. The increment to use. Default is 1.
function ____exports.eRange(self, start, ____end, increment)
    if increment == nil then
        increment = 1
    end
    if ____end == nil then
        return ____exports.eRange(nil, 0, start, increment)
    end
    local array = {}
    do
        local i = start
        while i < ____end do
            array[#array + 1] = i
            i = i + increment
        end
    end
    return array
end
--- Helper function to log what is happening in functions that recursively move through nested data
-- structures.
function ____exports.getTraversalDescription(self, key, traversalDescription)
    if traversalDescription ~= "" then
        traversalDescription = traversalDescription .. " --> "
    end
    traversalDescription = traversalDescription .. tostring(key)
    return traversalDescription
end
--- Helper function to return an array of integers with the specified range, inclusive on both ends.
-- (The "i" in the function name stands for inclusive.)
-- 
-- If the end is lower than the start, an empty array will be returned.
-- 
-- For example:
-- 
-- - `iRange(2)` returns `[0, 1, 2]`.
-- - `iRange(3)` returns `[0, 1, 2, 3]`.
-- - `iRange(-3)` returns `[0, -1, -2, -3]`.
-- - `iRange(1, 3)` returns `[1, 2, 3]`.
-- - `iRange(2, 5)` returns `[2, 3, 4, 5]`.
-- - `iRange(5, 2)` returns `[]`.
-- - `iRange(3, 3)` returns `[3]`.
-- 
-- @param start The integer to start at.
-- @param end Optional. The integer to end at. If not specified, then the start will be 0 and the
-- first argument will be the end.
-- @param increment Optional. The increment to use. Default is 1.
function ____exports.iRange(self, start, ____end, increment)
    if increment == nil then
        increment = 1
    end
    if ____end == nil then
        return ____exports.iRange(nil, 0, start, increment)
    end
    local exclusiveEnd = ____end + 1
    return ____exports.eRange(nil, start, exclusiveEnd, increment)
end
--- Helper function to check if a variable is within a certain range, inclusive on both ends.
-- 
-- - For example, `inRange(1, 1, 3)` will return `true`.
-- - For example, `inRange(0, 1, 3)` will return `false`.
-- 
-- @param num The number to check.
-- @param start The start of the range to check.
-- @param end The end of the range to check.
function ____exports.inRange(self, num, start, ____end)
    return num >= start and num <= ____end
end
--- Helper function to detect if there is two or more players currently playing.
-- 
-- Specifically, this function looks for unique `ControllerIndex` values across all players.
-- 
-- This function is not safe to use in the `POST_PLAYER_INIT` callback, because the
-- `ControllerIndex` will not be set properly. As a workaround, you can use it in the
-- `POST_PLAYER_INIT_FIRST` callback (or some other callback like `POST_UPDATE`).
function ____exports.isMultiplayer(self)
    local players = getAllPlayers(nil)
    local controllerIndexes = __TS__ArrayMap(
        players,
        function(____, player) return player.ControllerIndex end
    )
    local controllerIndexesSet = __TS__New(ReadonlySet, controllerIndexes)
    return controllerIndexesSet.size > 1
end
--- Helper function to check if the player has the Repentance DLC installed.
-- 
-- This function should always be used over the `REPENTANCE` constant, since the latter is not safe.
-- 
-- Specifically, this function checks for the `Sprite.GetAnimation` method:
-- https://bindingofisaacrebirth.fandom.com/wiki/V1.06.J818#Lua_Changes
function ____exports.isRepentance(self)
    local metatable = getmetatable(Sprite)
    ____exports.assertDefined(nil, metatable, "Failed to get the metatable of the Sprite global table.")
    local classTable = metatable.__class
    ____exports.assertDefined(nil, classTable, "Failed to get the \"__class\" key of the Sprite metatable.")
    local getAnimation = classTable.GetAnimation
    return isFunction(nil, getAnimation)
end
--- Helper function to check if the player has the Repentance+ DLC installed.
-- 
-- This function should always be used over the `REPENTANCE_PLUS` constant, since the latter is not
-- safe.
-- 
-- Specifically, this function checks for `Room:DamageGridWithSource` method:
-- https://bindingofisaacrebirth.wiki.gg/wiki/The_Binding_of_Isaac:_Repentance%2B#Modding_Changes
function ____exports.isRepentancePlus(self)
    local room = game:GetRoom()
    local metatable = getmetatable(room)
    ____exports.assertDefined(nil, metatable, "Failed to get the metatable of the room class.")
    local damageGridWithSource = metatable.DamageGridWithSource
    return isFunction(nil, damageGridWithSource)
end
--- Helper function to check if the player is using REPENTOGON, an exe-hack which expands the modding
-- API.
-- 
-- Although REPENTOGON has a `REPENTOGON` global to check if it's present, it is not safe to use as
-- it can be overwritten by other mods.
-- 
-- Specifically, this function checks for the `Sprite.Continue` method:
-- https://repentogon.com/Sprite.html#continue
function ____exports.isRepentogon(self)
    local metatable = getmetatable(Sprite)
    ____exports.assertDefined(nil, metatable, "Failed to get the metatable of the Sprite global table.")
    local classTable = metatable.__class
    ____exports.assertDefined(nil, classTable, "Failed to get the \"__class\" key of the Sprite metatable.")
    local getAnimation = classTable.Continue
    return isFunction(nil, getAnimation)
end
--- Helper function to repeat code N times. This is faster to type and cleaner than using a for loop.
-- 
-- For example:
-- 
-- ```ts
-- const player = Isaac.GetPlayer();
-- repeat(10, () => {
--   player.AddCollectible(CollectibleType.STEVEN);
-- });
-- ```
-- 
-- The repeated function is passed the index of the iteration, if needed:
-- 
-- ```ts
-- repeat(3, (i) => {
--   print(i); // Prints "0", "1", "2"
-- });
-- ```
____exports["repeat"] = function(self, num, func)
    do
        local i = 0
        while i < num do
            func(nil, i)
            i = i + 1
        end
    end
end
--- Helper function to signify that the enclosing code block is not yet complete. Using this function
-- is similar to writing a "TODO" comment, but it has the benefit of preventing ESLint errors due to
-- unused variables or early returns.
-- 
-- When you see this function, it simply means that the programmer intends to add in more code to
-- this spot later.
-- 
-- This function is variadic, meaning that you can pass as many arguments as you want. (This is
-- useful as a means to prevent unused variables.)
-- 
-- This function does not actually do anything. (It is an "empty" function.)
-- 
-- @allowEmptyVariadic
function ____exports.todo(self, ...)
end
return ____exports
