HT.Dexterity = {}

HT.Dexterity.enableUnlimitedEquipment = false

HT.Dexterity.enableMoveSpeedMultiplier = false
HT.Dexterity.enableThrowDistanceMultiplier = false
HT.Dexterity.enableFireRateMultiplier = false
HT.Dexterity.enableDamageMultiplier = false

HT.Dexterity.moveSpeedMultiplier = 1
HT.Dexterity.throwDistanceMultiplier = 1
HT.Dexterity.fireRateMultiplier = 1
HT.Dexterity.damageMultiplier = 1

HT.Dexterity.tweakDataCarryTypes = nil
HT.Dexterity.godModeReset = false

HT.Dexterity.enableNoclip = false
HT.Dexterity.noclipSpeedMultiplier = 2
HT.Dexterity.noclipAxisMove = { x = 0, y = 0, z = 0 }

function HT.Dexterity:setGodMode(value, --[[optional]]showAlert)
    if value == nil then
        return
    end

    HT:setSetting("enable_god_mode", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_god_mode", value)
    
    if managers.player
    and managers.player.player_unit
    and managers.player:player_unit().character_damage
    and managers.player:player_unit():character_damage().set_god_mode then
        managers.player:player_unit():character_damage():set_god_mode(value)
    end

    if showAlert == false then
        return
    end

    if value then
        HT:addAlert("ut_alert_god_mode_enabled", HT.colors.success)
    else
        HT:addAlert("ut_alert_god_mode_disabled", HT.colors.success)
    end
end

function HT.Dexterity:resetGodMode()
    local player = managers.player and managers.player:player_unit()
    if player and alive(player) and player.character_damage and player:character_damage().set_god_mode then
        player:character_damage():set_god_mode(false)
    end
end

function HT.Dexterity:setInfiniteStamina(value)
    HT:setSetting("enable_infinite_stamina", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_infinite_stamina", value)
    
    _G.CloneClass(PlayerMovement)
    if value then
        function PlayerMovement:_change_stamina() end

        function PlayerMovement:is_stamina_drained() return false end
    else
        PlayerMovement._change_stamina = PlayerMovement.orig._change_stamina
        PlayerMovement.is_stamina_drained = PlayerMovement.orig.is_stamina_drained
    end
end

function HT.Dexterity:setNoclip(value, isUpdate, --[[optional]]showAlert)
    HT.Dexterity.enableNoclip = value
    if not isUpdate then
        HT:setSetting("enable_noclip", value)
        HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_noclip", value)
    end

    local player = managers.player and managers.player:player_unit()
    if not player or not alive(player) then
        HT.Dexterity.noclipAxisMove = { x = 0, y = 0, z = 0 }
        if showAlert == false then return end
        return
    end

    local keyboard = Input:keyboard()
    local keyboardDown = keyboard.down
    local camera = player:camera()
    if not camera then
        HT.Dexterity.noclipAxisMove = { x = 0, y = 0, z = 0 }
        if showAlert == false then return end
        return
    end
    local cameraRotation = camera:rotation()
    local speed = HT.Dexterity.noclipSpeedMultiplier or 2
    if value then
        HT.Dexterity.noclipAxisMove.x = keyboardDown(keyboard, Idstring("w")) and speed or keyboardDown(keyboard, Idstring("s")) and -speed or 0
        HT.Dexterity.noclipAxisMove.y = keyboardDown(keyboard, Idstring("d")) and speed or keyboardDown(keyboard, Idstring("a")) and -speed or 0
        HT.Dexterity.noclipAxisMove.z = keyboardDown(keyboard, Idstring("space")) and speed or keyboardDown(keyboard, Idstring("left ctrl")) and -speed or 0
        local moveDir = cameraRotation:x() * HT.Dexterity.noclipAxisMove.y + cameraRotation:y() * HT.Dexterity.noclipAxisMove.x + cameraRotation:z() * HT.Dexterity.noclipAxisMove.z
        local moveDelta = moveDir * 10
        local newPos = player:position() + moveDelta
        managers.player:warp_to(newPos, cameraRotation, 1, Rotation(0, 0, 0))
    else
        HT.Dexterity.noclipAxisMove = { x = 0, y = 0, z = 0 }
    end

    local isNotUpdate = isUpdate == nil or isUpdate == false

    if showAlert == false then
        return
    end

    if value and isNotUpdate then
        HT:addAlert("ut_alert_noclip_enabled", HT.colors.success)
    elseif isNotUpdate then
        HT:addAlert("ut_alert_noclip_disabled", HT.colors.success)
    end
end

function HT.Dexterity:setRunInAllDirections(value)
    HT:setSetting("enable_run_in_all_directions", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_run_in_all_directions", value)
    
    _G.CloneClass(PlayerStandard)
    if value then
        function PlayerStandard:_can_run_directional() return true end
    else
        PlayerStandard._can_run_directional = PlayerStandard.orig._can_run_directional
    end
end

function HT.Dexterity:setCanRunWithAnyBag(value)
    HT:setSetting("enable_can_run_with_any_bag", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_can_run_with_any_bag", value)

    HT.Dexterity.tweakDataCarryTypes = HT.Dexterity.tweakDataCarryTypes or deep_clone(tweak_data.carry.types)
    if value then
        for carry_type, data in pairs(tweak_data.carry.types) do
            if type(data) == "table" then
                tweak_data.carry.types[carry_type].can_run = true
            end
        end
    else
        for carry_type, data in pairs(HT.Dexterity.tweakDataCarryTypes) do
            if tweak_data.carry.types[carry_type] and type(data) == "table" then
                tweak_data.carry.types[carry_type].can_run = data.can_run
            end
        end
    end
end

function HT.Dexterity:setFastMask(value)
    HT:setSetting("enable_fast_mask", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_fast_mask", value)

    HT.Dexterity.tweakDataPlayerPutOnMaskTime = HT.Dexterity.tweakDataPlayerPutOnMaskTime or tweak_data.player.put_on_mask_time
    if value then
        tweak_data.player.put_on_mask_time = 0.25
    else
        tweak_data.player.put_on_mask_time = HT.Dexterity.tweakDataPlayerPutOnMaskTime
    end
end

function HT.Dexterity:setNoCarryCooldown(value)
    HT:setSetting("enable_no_carry_cooldown", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_no_carry_cooldown", value)
    
    _G.CloneClass(PlayerManager)
    if value then
        function PlayerManager:carry_blocked_by_cooldown() return false end
    else
        PlayerManager.carry_blocked_by_cooldown = PlayerManager.orig.carry_blocked_by_cooldown
    end
end

function HT.Dexterity:setNoFlashbangs(value)
    HT:setSetting("enable_no_flashbangs", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_no_flashbangs", value)

    _G.CloneClass(CoreEnvironmentControllerManager)
    if value then
        function CoreEnvironmentControllerManager:set_flashbang() end
    else
        CoreEnvironmentControllerManager.set_flashbang = CoreEnvironmentControllerManager.orig.set_flashbang
    end
end

function HT.Dexterity:setInstantSwap(value)
    HT:setSetting("enable_instant_swap", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_instant_swap", value)

    _G.CloneClass(PlayerStandard)
    if value then
        function PlayerStandard:_get_swap_speed_multiplier() return 1000 end
    else
        PlayerStandard._get_swap_speed_multiplier = PlayerStandard.orig._get_swap_speed_multiplier
    end
end

function HT.Dexterity:setInstantReload(value)
    HT:setSetting("enable_instant_reload", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_instant_reload", value)

    _G.CloneClass(RaycastWeaponBase)
    _G.CloneClass(NewRaycastWeaponBase)
    if value then
        function RaycastWeaponBase:reload_speed_multiplier() return 1000 end
        function NewRaycastWeaponBase:reload_speed_multiplier() return 1000 end
    else
        RaycastWeaponBase.reload_speed_multiplier = RaycastWeaponBase.orig.reload_speed_multiplier
        NewRaycastWeaponBase.reload_speed_multiplier = NewRaycastWeaponBase.orig.reload_speed_multiplier
    end
end

function HT.Dexterity:setShootThroughWalls(value, --[[optional]]showAlert)
    HT:setSetting("enable_shoot_through_walls", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_shoot_through_walls", value)

    -- FIX (1.152.269): the firing code builds its setup_data from the METHODS
    -- self:can_shoot_through_wall()/_shield()/_enemy() (raycastweaponbase.lua
    -- ~798), which return per-instance fields set from each weapon's tweak_data
    -- in init(). The old code set the class FIELD, which every weapon instance
    -- immediately overwrote on spawn -> no effect. Overriding the METHODS on the
    -- base class makes every weapon (current and future) penetrate.
    _G.CloneClass(RaycastWeaponBase)
    _G.CloneClass(NewRaycastWeaponBase)
    if value then
        function RaycastWeaponBase:can_shoot_through_wall() return true end
        function RaycastWeaponBase:can_shoot_through_shield() return true end
        function RaycastWeaponBase:can_shoot_through_enemy() return true end
        function RaycastWeaponBase:armor_piercing_chance() return 1 end
        function RaycastWeaponBase:has_armor_piercing() return true end
        function NewRaycastWeaponBase:can_shoot_through_wall() return true end
        function NewRaycastWeaponBase:can_shoot_through_shield() return true end
        function NewRaycastWeaponBase:can_shoot_through_enemy() return true end
        function NewRaycastWeaponBase:armor_piercing_chance() return 1 end
        function NewRaycastWeaponBase:has_armor_piercing() return true end
    else
        RaycastWeaponBase.can_shoot_through_wall   = RaycastWeaponBase.orig.can_shoot_through_wall
        RaycastWeaponBase.can_shoot_through_shield = RaycastWeaponBase.orig.can_shoot_through_shield
        RaycastWeaponBase.can_shoot_through_enemy  = RaycastWeaponBase.orig.can_shoot_through_enemy
        RaycastWeaponBase.armor_piercing_chance    = RaycastWeaponBase.orig.armor_piercing_chance
        RaycastWeaponBase.has_armor_piercing       = RaycastWeaponBase.orig.has_armor_piercing
        NewRaycastWeaponBase.can_shoot_through_wall   = NewRaycastWeaponBase.orig.can_shoot_through_wall
        NewRaycastWeaponBase.can_shoot_through_shield = NewRaycastWeaponBase.orig.can_shoot_through_shield
        NewRaycastWeaponBase.can_shoot_through_enemy  = NewRaycastWeaponBase.orig.can_shoot_through_enemy
        NewRaycastWeaponBase.armor_piercing_chance    = NewRaycastWeaponBase.orig.armor_piercing_chance
        NewRaycastWeaponBase.has_armor_piercing       = NewRaycastWeaponBase.orig.has_armor_piercing
    end

    -- Apply immediately to the currently-equipped weapons via the game's own
    -- override_shoot_through(wall, shield, enemy) helper.
    pcall(function()
        local player = managers.player and managers.player:player_unit()
        local inv = player and alive(player) and player.inventory and player:inventory()
        local selections = inv and inv._available_selections
        if selections then
            for _, selection in pairs(selections) do
                local base = selection and selection.unit and alive(selection.unit) and selection.unit:base()
                if base and base.override_shoot_through then
                    base:override_shoot_through(value, value, value)
                end
            end
        end
    end)

    if showAlert == false then
        return
    end

    if value then
        HT:addAlert("ut_alert_shoot_through_walls_enabled", HT.colors.success)
    else
        HT:addAlert("ut_alert_shoot_through_walls_disabled", HT.colors.success)
    end
end

function HT.Dexterity:setNoRecoil(value)
    HT:setSetting("enable_no_recoil", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_no_recoil", value)

    _G.CloneClass(NewRaycastWeaponBase)
    if value then
        function NewRaycastWeaponBase:recoil_multiplier() return 0 end
    else
        NewRaycastWeaponBase.recoil_multiplier = NewRaycastWeaponBase.orig.recoil_multiplier
    end
end

function HT.Dexterity:setNoSpread(value)
    HT:setSetting("enable_no_spread", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_no_spread", value)

    _G.CloneClass(NewRaycastWeaponBase)
    if value then
        function NewRaycastWeaponBase:spread_multiplier() return 0 end
    else
        NewRaycastWeaponBase.spread_multiplier = NewRaycastWeaponBase.orig.spread_multiplier
    end
end

function HT.Dexterity:setUnlimitedAmmo(value)
    HT:setSetting("enable_unlimited_ammo", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_unlimited_ammo", value)

    _G.CloneClass(RaycastWeaponBase)
    _G.CloneClass(NewRaycastWeaponBase)
    _G.CloneClass(SawWeaponBase)
    if value then
        function RaycastWeaponBase:ammo_usage() return 0 end
        function NewRaycastWeaponBase:ammo_usage() return 0 end
        function SawWeaponBase:fire(...)
            local clip = self:get_ammo_remaining_in_clip()
            local total = self:get_ammo_total()
            local result = SawWeaponBase.orig.fire(self, ...)
            self:set_ammo_remaining_in_clip(clip)
            self:set_ammo_total(total)
            return result
        end
    else
        RaycastWeaponBase.ammo_usage = RaycastWeaponBase.orig.ammo_usage
        NewRaycastWeaponBase.ammo_usage = NewRaycastWeaponBase.orig.ammo_usage
        SawWeaponBase.fire = SawWeaponBase.orig.fire
    end
end

function HT.Dexterity:setInstantInteraction(value)
    HT:setSetting("enable_instant_interaction", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_instant_interaction", value)
    
    _G.CloneClass(BaseInteractionExt)
    if value then
        function BaseInteractionExt:_get_timer() return 0.001 end
    else
        BaseInteractionExt._get_timer = BaseInteractionExt.orig._get_timer
    end
end

function HT.Dexterity:setInstantDeployment(value)
    HT:setSetting("enable_instant_deployment", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_instant_deployment", value)

    _G.CloneClass(PlayerManager)
    if value then
        function PlayerManager:selected_equipment_deploy_timer() return 0.001 end
    else
        PlayerManager.selected_equipment_deploy_timer = PlayerManager.orig.selected_equipment_deploy_timer
    end
end

function HT.Dexterity:setUnlimitedEquipment(value)
    HT:setSetting("enable_unlimited_equipment", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_unlimited_equipment", value)
    
    HT.Dexterity.enableUnlimitedEquipment = value
    -- "Unlimited" = never consume the deployable/special you ALREADY have (ECM,
    -- body bags, ammo/doc bags, trip mines, sentries, etc.). We intentionally do
    -- NOT override BaseInteractionExt.can_interact / _has_required_deployable:
    -- forcing those true lets you trigger a mission-door device placement (drill,
    -- saw, keycard) for a deployable you don't own, and the host then calls
    -- PlayerManager:remove_equipment on nil equipment -> hard crash
    -- (playermanager.lua:4619). Only blocking consumption is both safe and what
    -- "unlimited equipment" actually means.
    _G.CloneClass(PlayerManager)
    if value then
        function PlayerManager:on_used_body_bag() end

        function PlayerManager:remove_equipment(equipment_id, slot)
            -- keep the deployable; nil-safe because it does nothing
        end

        function PlayerManager:remove_special(name) end

        -- The no-op above only STOPS depletion; if you'd already used your
        -- deployables (amount 0) before enabling, use_selected_equipment bails on
        -- amount==0 and you still can't deploy. So top the amounts back up now.
        -- (This is why it "only worked on some heists" before.)
        HT.Dexterity:refillEquipment()

        -- Deploying past the legal limit (which unlimited equipment lets you do)
        -- trips NetworkPeer:verify_deployable -> mark_cheater on every machine,
        -- including your own. That's why the cheater tag showed up specifically
        -- with this feature on. Auto-engage the anti-cheat bypass so YOUR client
        -- never self-flags. (The tag other UNMODDED players see when you deploy
        -- more than possible is inherent to over-deploying and can't be hidden
        -- from their machines -- but yours, and any modded lobby's, stay clean.)
        if HT.AntiCheat and not HT:getSetting("enable_disable_anti_cheat") then
            pcall(function() HT.AntiCheat:setEnabled(true, false) end)
            HT:addAlert("Anti-cheat bypass auto-enabled (needed for unlimited equipment)", HT.colors.success, false)
        end
    else
        PlayerManager.on_used_body_bag = PlayerManager.orig.on_used_body_bag
        PlayerManager.remove_equipment = PlayerManager.orig.remove_equipment
        PlayerManager.remove_special = PlayerManager.orig.remove_special
    end
end

-- Refill every equipped deployable/special to a high amount, and refresh the HUD.
function HT.Dexterity:refillEquipment()
    pcall(function()
        local pm = managers.player
        if not pm or not pm._equipment or not pm._equipment.selections then return end
        for index, selection in ipairs(pm._equipment.selections) do
            if selection.amount then
                for slot = 1, #selection.amount do
                    selection.amount[slot] = Application:digest_value(99, true)
                end
                pcall(function() managers.hud:set_item_amount(index, 99) end)
                pcall(function() pm:update_deployable_equipment_amount_to_peers(selection.equipment, 99) end)
            end
        end
    end)
    -- Specials (body bags, cable ties) don't need refilling: their consumption is
    -- already no-op'd (on_used_body_bag / remove_special) while unlimited is on.
end

function HT.Dexterity:setMoveSpeedMultiplier(value, multiplier)
    if value and type(multiplier) ~= "number" then
        return
    end

    HT:setSetting("enable_move_speed_multiplier", value)
    HT:setSetting("move_speed_multiplier", multiplier)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_move_speed_multiplier", value)
    
    _G.CloneClass(PlayerManager)
    if value then
        function PlayerManager:movement_speed_multiplier(...)
            return PlayerManager.orig.movement_speed_multiplier(self, ...) * multiplier
        end
    else
        PlayerManager.movement_speed_multiplier = PlayerManager.orig.movement_speed_multiplier
    end
end

function HT.Dexterity:setThrowDistanceMultiplier(value, multiplier)
    if value and type(multiplier) ~= "number" then
        return
    end

    HT:setSetting("enable_throw_distance_multiplier", value)
    HT:setSetting("throw_distance_multiplier", multiplier)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_throw_distance_multiplier", value)
    
    HT.Dexterity.tweakDataCarryTypes = HT.Dexterity.tweakDataCarryTypes or deep_clone(tweak_data.carry.types)
    if value then
        for carry_type, data in pairs(tweak_data.carry.types) do
            if type(data) == "table" then
                tweak_data.carry.types[carry_type].throw_distance_multiplier = multiplier
            end
        end
    else
        for carry_type, data in pairs(HT.Dexterity.tweakDataCarryTypes) do
            if tweak_data.carry.types[carry_type] and type(data) == "table" then
                tweak_data.carry.types[carry_type].throw_distance_multiplier = data.throw_distance_multiplier
            end
        end
    end
end

function HT.Dexterity:setFireRateMultiplier(value, multiplier)
    if value and type(multiplier) ~= "number" then
        return
    end

    HT:setSetting("enable_fire_rate_multiplier", value)
    HT:setSetting("fire_rate_multiplier", multiplier)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_fire_rate_multiplier", value)

    _G.CloneClass(NewRaycastWeaponBase)
    if value then
        function NewRaycastWeaponBase:fire_rate_multiplier(...)
            return NewRaycastWeaponBase.orig.fire_rate_multiplier(self, ...) * multiplier
        end
    else
        NewRaycastWeaponBase.fire_rate_multiplier = NewRaycastWeaponBase.orig.fire_rate_multiplier
    end
end

function HT.Dexterity:setDamageMultiplier(value, multiplier)
    if value and type(multiplier) ~= "number" then
        return
    end

    HT:setSetting("enable_damage_multiplier", value)
    HT:setSetting("damage_multiplier", multiplier)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_damage_multiplier", value)

    _G.CloneClass(CopDamage)
    if value or HT:getSetting("enable_one_shot_kill") then
        function CopDamage:damage_bullet(attack_data)
            if attack_data and attack_data.attacker_unit == managers.player:player_unit() then
                if HT:getSetting("enable_one_shot_kill") then
                    attack_data.damage = 1000000
                elseif HT.Dexterity.enableDamageMultiplier then
                    attack_data.damage = attack_data.damage * HT.Dexterity.damageMultiplier
                end
            end
            return CopDamage.orig.damage_bullet(self, attack_data)
        end

        function CopDamage:damage_melee(attack_data)
            if attack_data and attack_data.attacker_unit == managers.player:player_unit() then
                if HT:getSetting("enable_one_shot_kill") then
                    attack_data.damage = 1000000
                elseif HT.Dexterity.enableDamageMultiplier then
                    attack_data.damage = attack_data.damage * HT.Dexterity.damageMultiplier
                end
            end
            return CopDamage.orig.damage_melee(self, attack_data)
        end
    else
        CopDamage.damage_bullet = CopDamage.orig.damage_bullet
        CopDamage.damage_melee = CopDamage.orig.damage_melee
    end
end

function HT.Dexterity:setNoFallDamage(value)
    HT:setSetting("enable_no_fall_damage", value)
    _G.CloneClass(PlayerDamage)
    if value then
        function PlayerDamage:damage_fall() end
    else
        PlayerDamage.damage_fall = PlayerDamage.orig.damage_fall
    end
    if value then
        HT:addAlert("No fall damage enabled", HT.colors.success, false)
    else
        HT:addAlert("No fall damage disabled", HT.colors.success, false)
    end
end

-- Melee range and melee damage are applied directly on the melee-weapon
-- tweak_data stats (backing up originals as old_*), the same conflict-free
-- approach the reference trainer uses for range. This deliberately avoids the
-- CopDamage hook so it never fights with Damage Multiplier / One Shot Kill.
function HT.Dexterity:setMeleeRange(value)
    HT:setSetting("enable_melee_range", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_melee_range", value)

    local melee = tweak_data and tweak_data.blackmarket and tweak_data.blackmarket.melee_weapons
    if melee then
        for _, tweak in pairs(melee) do
            local stats = tweak.stats
            if type(stats) == "table" and stats.range then
                if value then
                    stats.old_range = stats.old_range or stats.range
                    stats.range = 20000
                elseif stats.old_range then
                    stats.range = stats.old_range
                end
            end
        end
    end

    HT:addAlert(value and "Long melee range enabled" or "Long melee range disabled", HT.colors.success, false)
end

function HT.Dexterity:setMeleeDamageMultiplier(value, multiplier, --[[optional]]showAlert)
    if value and type(multiplier) ~= "number" then
        return
    end
    HT:setSetting("enable_melee_damage_multiplier", value)
    HT:setSetting("melee_damage_multiplier", multiplier)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_melee_damage_multiplier", value)

    local melee = tweak_data and tweak_data.blackmarket and tweak_data.blackmarket.melee_weapons
    if melee then
        for _, tweak in pairs(melee) do
            local stats = tweak.stats
            if type(stats) == "table" then
                for _, field in ipairs({ "min_damage", "max_damage", "damage" }) do
                    if stats[field] then
                        local backup = "old_" .. field
                        stats[backup] = stats[backup] or stats[field]
                        if value then
                            stats[field] = stats[backup] * multiplier
                        else
                            stats[field] = stats[backup]
                        end
                    end
                end
            end
        end
    end

    if showAlert ~= false then
        HT:addAlert(value and "Melee damage boosted" or "Melee damage reset", HT.colors.success, false)
    end
end

function HT.Dexterity:setOneShotKill(value)
    HT:setSetting("enable_one_shot_kill", value)
    HT:updateJsonValue("dexterity", "ut_item_dexterity_toggle_one_shot_kill", value)
    HT.Dexterity:setDamageMultiplier(
        HT:getSetting("enable_damage_multiplier") == true,
        tonumber(HT:getSetting("damage_multiplier")) or HT.Dexterity.damageMultiplier
    )
    if value then
        HT:addAlert("One Shot Kill enabled", HT.colors.success, false)
    else
        HT:addAlert("One Shot Kill disabled", HT.colors.success, false)
    end
end
    HT.Dexterity.enableMoveSpeedMultiplier = value
    HT.Dexterity.moveSpeedMultiplier = multiplier or HT.Dexterity.moveSpeedMultiplier
    HT.Dexterity.enableThrowDistanceMultiplier = value
    HT.Dexterity.throwDistanceMultiplier = multiplier or HT.Dexterity.throwDistanceMultiplier
    HT.Dexterity.enableFireRateMultiplier = value
    HT.Dexterity.fireRateMultiplier = multiplier or HT.Dexterity.fireRateMultiplier
    HT.Dexterity.enableDamageMultiplier = value
    HT.Dexterity.damageMultiplier = multiplier or HT.Dexterity.damageMultiplier
