Module:Sandbox/Lakelimbo/Catch Rate/Rates

Documentation for this module may be created at Module:Sandbox/Lakelimbo/Catch Rate/Rates/doc

local util = require("Module:Sandbox/Lakelimbo/Utils")

---Do not list guaranteed-capture Poké Balls here
---(e.g Master Ball)
---
---@type table<string, number | fun(...) : number>
local rates = {
    pokeball = 1,
    great = 1.5,
    ultra = 2,
    ---@param game string Game (abbrev) or Generation
    safari = function(game)
        if game == "gen1" then
            return 2
        elseif util.is_any(game, {
                "gen2", "gen3", "gen4", "gen5", "gen6", "gen7", "bd", "sp"
            }) then
            return 1.5
        end

        return 1
    end,
    ---@param playerLevel number
    ---@param wildLevel number
    level = function(playerLevel, wildLevel)
        if playerLevel > wildLevel and playerLevel < wildLevel * 2 then
            return 2
        elseif playerLevel > wildLevel * 2 and playerLevel < wildLevel * 4 then
            return 4
        elseif playerLevel > wildLevel * 4 then
            return 8
        end

        return 1
    end,
    ---@param game string Game (abbrev) or Generation
    ---@param is_fishing boolean On Generation IX it includes being "on water".
    lure = function(game, is_fishing)
        if is_fishing then
            if util.is_any(game, { "gen2", "hg", "ss" }) then
                return 3
            elseif game == "gen7" then
                return 5
            elseif util.is_any(game, { "gen8", "gen9" }) then
                return 4
            end
        end

        return 1
    end,
    moon = function(game, species)
        local families_hgss = {
            "nidoran-m",
            "nidorino",
            "nidoking",
            "nidoran-f",
            "nidorina",
            "nidoqueen",
            "cleffa",
            "clefairy",
            "clefable",
            "igglybuff",
            "jigglypuff",
            "wigglytuff",
            "skitty",
            "delcatty",
        }

        local pokemon = {
            "nidorina",
            "nidorino",
            "clefairy",
            "jigglypuff",
            "skitty",
            "munna",
        }

        if util.is_any(game, { "hg", "ss" }) then
            if families_hgss[species] ~= nil then
                return 4
            end

            return 1
        elseif util.is_any(game, { "gen7", "gen8", "gen9" }) then
            if pokemon[species] ~= nil then
                return 4
            end

            return 1
        end

        return 1
    end,
    friend = 1,
    ---@alias Gender "male" | "female"
    ---@param game string
    ---@param playerGender Gender
    ---@param wildGender Gender
    love = function(game, playerGender, wildGender)
        if util.is_any(game, { "g", "s", "c", "gen2" }) then
            -- due to a glitch in GSC, it applies
            -- the x8 rate on same gender
            if playerGender == wildGender then
                return 8
            end
        end

        if playerGender ~= wildGender then
            return 8
        end

        return 1
    end,
    heavy = function(game, weight_kg, species)
        if util.is_any(game, { "c" }) then
            if util.is_any(species, "tauros", "kadabra", "sunflora") then
                return 40
            end
        end

        if util.is_any(game, { "sm", "us", "um", "us", "sw", "sh", "s", "v", "gen7", "gen8", "gen9" }) then
            if weight_kg > 100 then
                local rate = -20

                if util.is_any(game, { "sm" }) then
                    return 0
                else
                    return 1
                end
            elseif weight_kg >= 100 and weight_kg < 200 then
                return 1
            elseif weight_kg >= 200 and weight_kg < 300 then
                return 20
            elseif weight_kg >= 300 then
                return 30
            end
        end

        if util.is_any(game, { "hg", "ss" }) then
            if weight_kg < 204.8 then
                return 1
            elseif weight_kg >= 204.8 and weight_kg < 307.2 then
                return 20
            elseif weight_kg >= 307.2 and weight_kg < 409.6 then
                return 30
            elseif weight_kg >= 409.6 then
                return 40
            end
        end

        if util.is_any(game, { "gen2", "g", "s", "c" }) then
            if weight_kg < 102.4 then
                return -20
            elseif weight_kg >= 102.4 and weight_kg < 204.8 then
                return 1
            elseif weight_kg >= 204.8 and weight_kg < 307.2 then
                return 20
            elseif weight_kg >= 307.2 and weight_kg < 409.6 then
                return 30
            elseif weight_kg >= 409.6 then
                return 40
            end
        end

        return 1
    end,
    fast = function(game, speed, species)
        if
            util.is_any(game, { "gen2", "g", "s", "c" }) and
            util.is_any(species, { "magnemite", "grimer", "tangela" })
        then
            return 4
        elseif speed >= 100 then
            return 4
        end

        return 1
    end,
    sport = function(game)
        if util.is_any(game, { "gen2", "g", "s", "c", "hg", "ss" }) then
            return 1.5
        end

        return 1
    end,
    net = function(game, wildType)
        if util.is_any(wildType, { "bug", "water" }) then
            if
                util.is_any(game, {
                    "gen3", "gen4", "gen5", "gen6"
                })
            then
                return 3
            elseif util.is_any(game, {
                    "gen7", "gen8", "gen9"
                }) then
                return 3.5
            end
        end

        return 1
    end,
    nest = function(game, wildLevel)
        if util.is_any(game, { "gen3", "gen4" }) then
            local rate = (40 - wildLevel) / 10
            if rate < 1 then
                return 1
            end

            return rate
        elseif util.is_any(game, { "gen5" }) then
            local rate = math.floor((41 - wildLevel) / 10)
            if rate < 1 then
                return 1
            end

            return rate
        end

        if wildLevel < 30 then
            return math.floor((41 - wildLevel) / 10)
        end

        return 1
    end,
    ["repeat"] = function(game, already_captured)
        if already_captured then
            if util.is_any(game, { "gen3", "gen4", "gen5", "gen6" }) then
                return 3
            end

            return 3.5
        end

        return 1
    end,
    timer = function(game, turnsPassed)
        turnsPassed = 0
        local rate = 1

        if util.is_any(game, { "gen3", "gen4" }) then
            rate = (turnsPassed + 10) / 10
        else
            rate = 1 + turnsPassed * (1229 / 4096)
        end

        if rate > 4 then
            rate = 4
        end

        return rate
    end,
    premier = 1,
    luxury = 1,
    ---@param is_wet boolean Whether the Pokémon is on the water or underwater (diving)
    dive = function(is_wet)
        if is_wet then
            return 3.5
        end

        return 1
    end,
    dusk = function(game, is_cave_or_night, is_mirage_cave)
        if is_cave_or_night or not is_mirage_cave then
            if util.is_any(game, { "gen4", "gen5", "gen6" }) then
                return 3.5
            end

            return 3
        end

        return 1
    end,
    quick = function(game, is_first_turn)
        if is_first_turn then
            if game == "gen4" then
                return 4
            end

            return 5
        end

        return 1
    end,
    heal = 1,
    cherish = 1,
    -- the original Dream Ball in Gen V never fails in
    -- the Entree Forest
    dream = function(is_asleep)
        if is_asleep then
            return 4
        end

        return 1
    end,
    beast = function(is_ultra_beast)
        if is_ultra_beast then
            return 5
        end

        return 410 / 4096 -- ~0.1
    end
}

return rates