local S = core.get_translator(core.get_current_modname())

-- Effects that repeat as well as their interval
local repeaters = {
    ["yams_effects:poison"] = 4,
    ["yams_effects:health_regen_small"] = 10,
    ["yams_effects:health_regen_medium"] = 8,
    ["yams_effects:health_regen_large"] = 6,
}

local negative_effects = {
    ["yams_effects:poison"] = true,
    ["yams_effects:plague"] = true,
    ["yams_effects:speed_down_small"] = true,
    ["yams_effects:speed_down_medium"] = true,
    ["yams_effects:speed_down_large"] = true,
    ["yams_effects:attack_down_small"] = true,
    ["yams_effects:attack_down_medium"] = true,
    ["yams_effects:attack_down_large"] = true,
    ["yams_effects:defense_down_small"] = true,
    ["yams_effects:defense_down_medium"] = true,
    ["yams_effects:defense_down_large"] = true,
    ["yams_effects:mana_sap"] = true,
}

-- Callback signature is function(player, effect)
-- effect = the effect name
yams.on_player_status_effect_callbacks = {}
-- Alias for local use
local effect_cbs = yams.on_player_status_effect_callbacks

function yams.register_on_player_status_effect(callback)
    table.insert(effect_cbs, callback)
end

-- The apply function only changes the HUD bar when the damage is applied, but
-- we want to change the health bar's color at the moment poison is applied to
-- the player
local function update_health_bar(player)
    local name = player:get_player_name()
    -- Poison gets priority since it is actively inflicting damage
    if playereffects.has_effect_type(name, "yams_effects:poison") then
        hb.change_hudbar(player, "health", nil, nil,
                         "hbhunger_icon_health_poison.png", nil,
                         "hbhunger_bar_health_poison.png")
    elseif playereffects.has_effect_type(name, "yams_effects:plague") then
        hb.change_hudbar(player, "health", nil, nil,
                     "hudbars_icon_health_plague.png", nil,
                     "hudbars_bar_health_plague.png")
    else
        hb.change_hudbar(player, "health", nil, nil,
                         "hudbars_icon_health.png", nil, "hudbars_bar_health.png")
    end
end

local function poison_apply(player)
    update_health_bar(player)

    local base_hp_max = yams.get_base_max_hp(player)
    local meta = player:get_meta()
    -- 0 if the key doesn't exist
    local carryover = meta:get_float("yams_effects:poison_leftover")

    -- Scale to the player's maximum HP, ignoring plague
    local raw_amount = base_hp_max / 20
    local dmg = math.floor(raw_amount + carryover)
    local leftover = raw_amount - dmg

    -- Do not kill the player if they are at 1 HP
    local new_hp = math.max(1, player:get_hp() - dmg)
    if new_hp ~= player:get_hp() then
        -- YAMS-TODO: temporary 'cause' so that shields don't block it
        local reason = {type = "set_hp", cause = "stamina:starve"}
        player:set_hp(new_hp, reason)
    else
        -- Make sure that natural health regen is stifled
        meta:set_float("stamina:heal_cooldown", 5)
    end

    meta:set_float("yams_effects:poison_leftover", leftover)
end

local function poison_cancel(effect, player)
    local meta = player:get_meta()
    meta:set_float("yams_effects:poison_leftover", 0.0)

    -- Set it to nil because otherwise the below call will not change the health
    -- bar since poison would still be considered active
    playereffects.effects[effect.effect_id] = nil
    update_health_bar(player)
end

playereffects.register_effect_type("yams_effects:poison", S("Poison"),
    "hbhunger_icon_health_poison.png", {"poison"}, poison_apply, poison_cancel,
    false, true, 4)

local function poisonous_food_callback(player, ticks, interval)
    stamina.change_saturation(player, -ticks)
    
    -- Immediately stop health regeneration
    local meta = player:get_meta()
    meta:set_float("stamina:heal_cooldown", 5)

    playereffects.apply_effect_type("yams_effects:poison", ticks, player)
    update_health_bar(player)

    for _, cb in pairs(effect_cbs) do
        cb(player, "yams_effects:poison")
    end

    return true  -- Override what the 'stamina' mod does
end

local function plague_apply(player)
    -- The code is wrapped in a core.after() call to make sure that the
    -- 'yams_rpg' mod sets the max HP first after logging back in
    -- Additionally, this makes sure that damage from the mob is performed
    -- first before the max HP reduction is performed
    core.after(0, function()
        if yams.is_player(player) then
            local meta = player:get_meta()
            -- 0 if the key doesn't exist
            local stacks = meta:get_int("yams_effects:plague_stacks")

            -- Do not decrease max HP if the effect is being re-applied due to
            -- the player having logged out while being plagued
            if meta:get_int("yams_effects:login_reapply") == 0 then
                stacks = stacks + 1
            else
                meta:set_int("yams_effects:login_reapply", 0)
            end

            local base_hp_max = yams.get_base_max_hp(player)
            -- Take 10% of max health per stack
            local reduction = math.ceil((base_hp_max / 10) * stacks)
            local new_hp_max = math.max(1, base_hp_max - reduction)
            player:set_properties({hp_max = new_hp_max})

            meta:set_int("yams_effects:plague_stacks", stacks)
        end
    end)
end

local function plague_cancel(effect, player)
    -- Only remove if it expired naturally or through death and not re-inflicted
    core.after(0, function()
        if yams.is_player(player) then
            local n = player:get_player_name()
            if not playereffects.has_effect_type(n, "yams_effects:plague") then
                local base_hp_max = yams.get_base_max_hp(player)
                player:set_properties({hp_max = base_hp_max})

                local meta = player:get_meta()
                meta:set_int("yams_effects:plague_stacks", 0)

                -- Same reason as in poison_cancel()
                playereffects.effects[effect.effect_id] = nil
                update_health_bar(player)
            end
        end
    end)
end

-- Crappy fix to ensure that the effects from plague are applied correctly
-- when the player logs back in
local function plague_login_fix(player)
    local name = player:get_player_name()
    if playereffects.has_effect_type(name, "yams_effects:plague") then
        local meta = player:get_meta()
        meta:set_int("yams_effects:login_reapply", 1)
    end
end

playereffects.register_effect_type("yams_effects:plague", S("Plague"),
    "hudbars_icon_health_plague.png", {"plague"}, plague_apply, plague_cancel,
    false, true)

local function health_regen_apply(player)
    -- Plague is not ignored; we use the current maximum HP
    local hp_max = player:get_properties().hp_max
    local meta = player:get_meta()

    -- 0 if the key doesn't exist
    local carryover = meta:get_float("yams_effects:regen_leftover")

    local raw_amount = hp_max / 10
    local heal_amount = math.floor(raw_amount + carryover)
    local leftover = raw_amount - heal_amount

    local cur_hp = player:get_hp()
    if cur_hp ~= hp_max then
        local new_hp = math.min(cur_hp + heal_amount, hp_max)
        player:set_hp(new_hp)
        meta:set_float("yams_effects:regen_leftover", leftover)
    else
        meta:set_float("yams_effects:regen_leftover", 0.0)
    end
end

local function health_regen_cancel(effect, player)
    local meta = player:get_meta()
    meta:set_float("yams_effects:regen_leftover", 0.0)
end

playereffects.register_effect_type("yams_effects:health_regen_small",
    S("Health Regen S"), "", {"health_regen"}, health_regen_apply,
    health_regen_cancel, false, true, 10)

playereffects.register_effect_type("yams_effects:health_regen_medium",
    S("Health Regen M"), "", {"health_regen"}, health_regen_apply,
    health_regen_cancel, false, true, 8)

playereffects.register_effect_type("yams_effects:health_regen_large",
    S("Health Regen L"), "", {"health_regen"}, health_regen_apply,
    health_regen_cancel, false, true, 6)

local function speed_up(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        player_monoids.speed:add_change(player, value, "yams_effects:speed_up")
    end
end

local function speed_down(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        player_monoids.speed:add_change(player, value, "yams_effects:speed_down")
    end
end

local function speed_cancel(effect, player)
    -- Probably slightly better to just have separate functions for buffs and
    -- debuffs but whatever
    if string.find(effect.effect_type_id, "speed_down") then
        player_monoids.speed:del_change(player, "yams_effects:speed_down")
    elseif string.find(effect.effect_type_id, "speed_up") then
        player_monoids.speed:del_change(player, "yams_effects:speed_up")
    else
        assert(false, "speed_cancel - should not get here")
    end
end

playereffects.register_effect_type("yams_effects:speed_up_small",
    S("Speed Up S"), "", {"speed"}, speed_up(1.1), speed_cancel, false, true)

playereffects.register_effect_type("yams_effects:speed_up_medium",
    S("Speed Up M"), "", {"speed"}, speed_up(1.25), speed_cancel, false, true)

playereffects.register_effect_type("yams_effects:speed_up_large",
    S("Speed Up L"), "", {"speed"}, speed_up(1.5), speed_cancel, false, true)

playereffects.register_effect_type("yams_effects:speed_down_small",
    S("Speed Down S"), "", {"speed"}, speed_down(0.9), speed_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:speed_down_medium",
    S("Speed Down M"), "", {"speed"}, speed_down(0.75), speed_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:speed_down_large",
    S("Speed Down L"), "", {"speed"}, speed_down(0.5), speed_cancel,
    false, true)

local function high_jump(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        player_monoids.jump:add_change(player, value, "yams_effects:high_jump")
    end
end

local function high_jump_cancel(effect, player)
    player_monoids.jump:del_change(player, "yams_effects:high_jump")
end

playereffects.register_effect_type("yams_effects:high_jump_small",
    S("High Jump S"), "", {"jump"}, high_jump(1.4), high_jump_cancel,
    false, true)

local function attack_up(value)  -- Really a multiplier on damage dealt
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.damage_given_monoid:add_change(player, value, "yams_effects:attack_up")
    end
end

local function attack_down(value)  -- Really a multiplier on damage dealt
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.damage_given_monoid:add_change(player, value, "yams_effects:attack_down")
    end
end

local function attack_cancel(effect, player)
    if string.find(effect.effect_type_id, "attack_down") then
        yams.damage_given_monoid:del_change(player, "yams_effects:attack_down")
    elseif string.find(effect.effect_type_id, "attack_up") then
        yams.damage_given_monoid:del_change(player, "yams_effects:attack_up")
    else
        assert(false, "attack_cancel - should not get here")
    end
end

playereffects.register_effect_type("yams_effects:attack_up_small",
    S("Attack Up S"), "", {"attack"}, attack_up(1.1), attack_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:attack_up_medium",
    S("Attack Up M"), "", {"attack"}, attack_up(1.25), attack_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:attack_up_large",
    S("Attack Up L"), "", {"attack"}, attack_up(1.5), attack_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:attack_down_small",
    S("Attack Down S"), "", {"attack"}, attack_down(0.9), attack_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:attack_down_medium",
    S("Attack Down M"), "", {"attack"}, attack_down(0.75), attack_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:attack_down_large",
    S("Attack Down L"), "", {"attack"}, attack_down(0.5), attack_cancel,
    false, true)

local function defense_up(value)  -- Really a multiplier on damage taken
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.damage_taken_monoid:add_change(player, value, "yams_effects:defense_up")
    end
end

local function defense_down(value)  -- Really a multiplier on damage taken
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.damage_taken_monoid:add_change(player, value, "yams_effects:defense_down")
    end
end

local function defense_cancel(effect, player)
    if string.find(effect.effect_type_id, "defense_down") then
        yams.damage_taken_monoid:del_change(player, "yams_effects:defense_down")
    elseif string.find(effect.effect_type_id, "defense_up") then
        yams.damage_taken_monoid:del_change(player, "yams_effects:defense_up")
    else
        assert(false, "defense_cancel - should not get here")
    end
end

playereffects.register_effect_type("yams_effects:defense_up_small",
    S("Defense Up S"), "", {"defense"}, defense_up(0.9), defense_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:defense_up_medium",
    S("Defense Up M"), "", {"defense"}, defense_up(0.75), defense_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:defense_up_large",
    S("Defense Up L"), "", {"defense"}, defense_up(0.5), defense_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:defense_down_small",
    S("Defense Down S"), "", {"defense"}, defense_down(1.25), defense_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:defense_down_medium",
    S("Defense Down M"), "", {"defense"}, defense_down(1.5), defense_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:defense_down_large",
    S("Defense Down L"), "", {"defense"}, defense_down(2.0), defense_cancel,
    false, true)

-- There probably will not be more than one variant of this status effect
local function tough_skin_apply(player)
    yams.tough_skin_monoid:add_change(player, 1, "yams_effects:tough_skin")
end

local function tough_skin_cancel(effect, player)
    yams.tough_skin_monoid:del_change(player, "yams_effects:tough_skin")
end

playereffects.register_effect_type("yams_effects:tough_skin", S("Tough Skin"),
    "", {"tough_skin"}, tough_skin_apply, tough_skin_cancel, false, true)

local function mana_regen(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.mana_regen_monoid:add_change(player, value, "yams_effects:mana_regen")
    end
end

local function mana_regen_cancel(effect, player)
    yams.mana_regen_monoid:del_change(player, "yams_effects:mana_regen")
end

playereffects.register_effect_type("yams_effects:mana_regen_small",
    S("Mana Regen S"), "", {"mana_regen"}, mana_regen(1.5), mana_regen_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:mana_regen_medium",
    S("Mana Regen M"), "", {"mana_regen"}, mana_regen(2.0), mana_regen_cancel,
    false, true)

local function mana_sap_apply(player)
    yams.mana_regen_monoid:add_change(player, -0.5, "yams_effects:mana_sap")
end

local function mana_sap_cancel(effect, player)
    yams.mana_regen_monoid:del_change(player, "yams_effects:mana_sap")
end

playereffects.register_effect_type("yams_effects:mana_sap", S("Mana Sap"), "",
    {"mana_regen", "mana_sap"}, mana_sap_apply, mana_sap_cancel, false, true)

local function stamina_regen(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.stamina_regen_monoid:add_change(player, value, "yams_effects:stamina_regen")
    end
end

local function stamina_regen_cancel(effect, player)
    yams.stamina_regen_monoid:del_change(player, "yams_effects:stamina_regen")
end

playereffects.register_effect_type("yams_effects:stamina_regen_small",
    S("Stamina Regen S"), "", {"stamina_regen"}, stamina_regen(1.5),
    stamina_regen_cancel, false, true)

playereffects.register_effect_type("yams_effects:stamina_regen_medium",
    S("Stamina Regen M"), "", {"stamina_regen"}, stamina_regen(2.0),
    stamina_regen_cancel, false, true)

local function well_fed(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.exp_gain_monoid:add_change(player, value, "yams_effects:well_fed")
    end
end

local function well_fed_cancel(effect, player)
    yams.exp_gain_monoid:del_change(player, "yams_effects:well_fed")
end

playereffects.register_effect_type("yams_effects:well_fed_small",
    S("Well Fed S"), "", {"well_fed"}, well_fed(0.10), well_fed_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:well_fed_medium",
    S("Well Fed M"), "", {"well_fed"}, well_fed(0.25), well_fed_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:well_fed_large",
    S("Well Fed L"), "", {"well_fed"}, well_fed(0.5), well_fed_cancel,
    false, true)

local function insight(value)
    -- Returns a closure; core.item_eat does the same thing
    return function (player)
        yams.exp_gain_monoid:add_change(player, value, "yams_effects:insight")
    end
end

local function insight_cancel(effect, player)
    yams.exp_gain_monoid:del_change(player, "yams_effects:insight")
end

playereffects.register_effect_type("yams_effects:insight_small",
    S("Insight S"), "", {"insight"}, insight(0.25), insight_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:insight_medium",
    S("Insight M"), "", {"insight"}, insight(0.5), insight_cancel,
    false, true)

playereffects.register_effect_type("yams_effects:insight_large",
    S("Insight L"), "", {"insight"}, insight(1.0), insight_cancel,
    false, true)

local function morale_apply(player)
    yams.morale_monoid:add_change(player, true, "yams_effects:morale")
end

local function morale_cancel(effect, player)
    yams.morale_monoid:del_change(player, "yams_effects:morale")
end

playereffects.register_effect_type("yams_effects:morale", S("Morale"), "",
    {"morale"}, morale_apply, morale_cancel, false, true)

local function ailment_ward_apply(player)
    local name = player:get_player_name()
    local statuses = playereffects.get_player_effects(name)
    for _, status in pairs(statuses) do
        if negative_effects[status.effect_type_id] then
            playereffects.cancel_effect(status.effect_id)
        end
    end
end

playereffects.register_effect_type("yams_effects:ailment_ward",
    S("Ailment Ward"), "", {"ailment_ward"}, ailment_ward_apply, nil,
    false, true)

local function check_ailment_ward(player)
    local name = player:get_player_name()
    if playereffects.has_effect_type(name, "yams_effects:ailment_ward") then
        -- There's only one status effect that does this
        playereffects.cancel_effect_group("ailment_ward", name)
        return true
    end

    return false
end

local function poison_ward_apply(player)
    local name = player:get_player_name()
    if playereffects.has_effect_type(name, "yams_effects:poison") then
        -- There's only one status effect that does this
        playereffects.cancel_effect_group("poison", name)
    end
end

playereffects.register_effect_type("yams_effects:poison_ward",
    S("Poison Ward"), "", {"poison_ward"}, poison_ward_apply, nil,
    false, true)

local function sap_ward_apply(player)
    local name = player:get_player_name()
    if playereffects.has_effect_type(name, "yams_effects:mana_sap") then
        -- There's only one status effect that does this
        playereffects.cancel_effect_group("mana_sap", name)
    end
end

playereffects.register_effect_type("yams_effects:sap_ward", S("Sap Ward"), "",
    {"sap_ward"}, sap_ward_apply, nil, false, true)

local function check_other_wards(player, effect_name)
    local name = player:get_player_name()
    if playereffects.has_effect_type(name, "yams_effects:poison_ward") and
            effect_name == "yams_effects:poison" then
        -- There's only one status effect that does this
        playereffects.cancel_effect_group("poison_ward", name)
        return true
    elseif playereffects.has_effect_type(name, "yams_effects:sap_ward") and
            effect_name == "yams_effects:mana_sap" then
        -- There's only one status effect that does this
        playereffects.cancel_effect_group("sap_ward", name)
        return true
    end

    return false
end

local function apply_enemy_effects(player, hp_change, reason)
    -- Do not apply effects if not damaged
    if hp_change >= 0 then
        return
    end

    if reason.type == "punch" and reason.object then
        local ent = reason.object:get_luaentity()
        if ent then
            local effect_table = nil
            if ent._cmi_is_mob and ent.yams_melee_effects then
                effect_table = ent.yams_melee_effects
            elseif ent._yams_mob_projectile and ent.yams_arrow_effects then
                effect_table = ent.yams_arrow_effects
            end

            -- We'll assume that all status effects dealt by monsters are
            -- negative effects
            local has_ailment_ward = nil
            for _, effect in pairs(effect_table) do
                if math.random(1, 100) <= effect.chance then
                    local name = effect.name
                    local time = effect.duration / (repeaters[name] or 1)
                    local warded = check_other_wards(player, effect.name)

                    -- Only check for ailment ward once and if the player has
                    -- it, block all status effects from the same attack
                    -- Only do this if the more specific wards did not block
                    -- anything
                    if not warded and has_ailment_ward == nil then
                        has_ailment_ward = check_ailment_ward(player)
                    end

                    if has_ailment_ward then
                        warded = true
                    end

                    if not warded then
                        playereffects.apply_effect_type(name, time, player)

                        for _, cb in pairs(effect_cbs) do
                            cb(player, name)
                        end

                        if name == "yams_effects:poison" then
                            update_health_bar(player)
                            -- Immediately stop health regeneration
                            local meta = player:get_meta()
                            meta:set_float("stamina:heal_cooldown", 5)
                        elseif name == "yams_effects:plague" then
                            update_health_bar(player)
                        end
                    end
                end
            end
        end
    end
end

local function apply_food_effects(hp_change, replace, itemstack, user, pt)
    if not yams.is_player(user) or not itemstack then
        return
    end

    -- Do not apply effects if the player is full unless they wanted to eat it
    -- anyway
    local force_eat = user:get_player_control().sneak
    local level = stamina.get_saturation(user) or 0
    if level >= 30 and hp_change > 0 and not force_eat then
        return
    end

    local def = core.registered_items[itemstack:get_name()]
    if def and def._yams_food_effects then
        for _, effect in pairs(def._yams_food_effects) do
            local name = effect.name

            -- Not a real "effect" but good enough
            if name == "yams_effects:clear_all" then
                local pname = user:get_player_name()
                local statuses = playereffects.get_player_effects(pname)
                for _, status in pairs(statuses) do
                    playereffects.cancel_effect(status.effect_id)
                end
            else
                local duration = effect.duration / (repeaters[name] or 1)
                playereffects.apply_effect_type(name, duration, user)

                for _, cb in pairs(effect_cbs) do
                    cb(user, name)
                end
            end
        end
    end
    if def and def._yams_mana_restore then
        local pname = user:get_player_name()
        local max_mana = mana.getmax(pname)
        local amount = math.ceil(max_mana * def._yams_mana_restore)
        mana.add_up_to(pname, amount)
    end
end

stamina.register_on_poison(poisonous_food_callback)
core.register_on_joinplayer(update_health_bar)
core.register_on_joinplayer(plague_login_fix)
core.register_on_player_hpchange(apply_enemy_effects, false)
core.register_on_item_eat(apply_food_effects)

-- Work around a possible bug in the latest version of the 'player_monoids' mod
-- I think it is related to the order in which the join player callbacks are
-- registered and run; if the 'playereffects' mod is loaded before the
-- 'player_monoids' mod, the callback of the latter will undo any application
-- of status effects that the former did, causing status effects that affect
-- the player's speed or jump height to not be restored properly when the player
-- quits and reloads the game while affected by those effects
-- It is okay to do this because the 'player_monoids' mod is very good at making
-- sure that the needed data structures are present if they are not
local needed_monoids = {"speed", "jump", "gravity"}
for _, name in pairs(needed_monoids) do
    local old_init = player_monoids[name].init_branches
    player_monoids[name].init_branches = function(self, player_name)
        if not self.player_map[player_name] then
            old_init(self, player_name)
        end
    end
end

-- Remove potions from the 'gadgets_consumables' mod because we are going to
-- replace them with our own implementation
local old_potions = {
    "gadgets_consumables:potion_speed_01",
    "gadgets_consumables:potion_speed_02",
    "gadgets_consumables:potion_speed_03",
    "gadgets_consumables:potion_jump_01",
    "gadgets_consumables:potion_jump_02",
    "gadgets_consumables:potion_jump_03",
    "gadgets_consumables:potion_gravity_01",
    "gadgets_consumables:potion_gravity_02",
    "gadgets_consumables:potion_gravity_03",
    "gadgets_consumables:potion_water_breath_01",
    "gadgets_consumables:potion_water_breath_02",
    "gadgets_consumables:potion_fire_shield_01",
    "gadgets_consumables:potion_fire_shield_02",
    "gadgets_consumables:potion_health_regen_01",
    "gadgets_consumables:potion_health_regen_02",
    "gadgets_consumables:potion_mana_regen_01",
    "gadgets_consumables:potion_mana_regen_02",
    "gadgets_consumables:potion_stamina_regen_01",
    "gadgets_consumables:potion_stamina_regen_02",
    "gadgets_consumables:potion_dispel",
    "gadgets_consumables:potion_teleport",
}

for _, name in pairs(old_potions) do
    core.clear_craft({output = name})
    core.unregister_item(name)
end

-- Add a recipe for the water bottle that uses the wooden bucket
core.register_craft({
    output = "gadgets_consumables:water_bottle 6",
    recipe = {
        {"vessels:glass_bottle", "vessels:glass_bottle", "vessels:glass_bottle"},
        {"vessels:glass_bottle", "vessels:glass_bottle", "vessels:glass_bottle"},
        {"", "wooden_bucket:bucket_wood_water", ""}
    },
    replacements = {{"wooden_bucket:bucket_wood_water", "wooden_bucket:bucket_wood_empty"}}
})

core.register_craftitem("yams_effects:potion_health_regen_medium", {
    description = "Potion of Health Regen",
    inventory_image = "gadgets_consumables_potion_health_regen.png",
    on_use = function(itemstack, user, pointed_thing)
        local t = 120 / repeaters["yams_effects:health_regen_medium"]
        playereffects.apply_effect_type("yams_effects:health_regen_medium", t, user)

        core.sound_play("gadgets_consumables_potion_drink", {
            object = user,
            gain = 1.0,
            max_hear_distance = 16
        })

        itemstack:take_item()
        return itemstack
    end,
    _yams_tt_effect_descs = {
        {
            name = S("Health Regen M"),
            desc = S("Every 8 seconds, restore 10% of maximum") .. "\n" ..
                   S("health. Taking damage does not interrupt") .. "\n" ..
                   S("this effect. Lasts two minutes.")
        },
    }
})

core.register_craft({
    type = "shaped",
    output = "yams_effects:potion_health_regen_medium",
    recipe = {
        {"tmw_slimes:ocean_goo", "magic_materials:magic_flower", "farming:melon_slice"},
        {"", "yams_farming:obsidian_wart", ""},
        {"", "gadgets_consumables:water_bottle", ""},
    }
})

print("yams_effects loaded")
