Files
MetaHunt/modules/smartammo/engine.lua
T
2026-02-24 23:00:59 +01:00

672 lines
22 KiB
Lua

local function MTHSmartAmmo_GetSaved()
return MTH_SA_GetSavedTable("MTHSmartAmmo")
end
local function MTHSmartAmmo_GetModuleStore()
if MTH and MTH.GetModuleCharSavedVariables then
return MTH:GetModuleCharSavedVariables("smartammo")
end
return nil
end
local function MTHSmartAmmo_IsSmartEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.smartEnabled ~= nil then
return moduleStore.smartEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
return saved["enabled"]
end
local function MTHSmartAmmo_IsReloadEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.reloadEnabled ~= nil then
return moduleStore.reloadEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
if saved["reload"] == nil then
return true
end
return saved["reload"] and true or false
end
local MTHSmartAmmo_InitializeHooks
MTHSmartAmmo_EnsureHooks = nil
function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["enabled"] = 1
if MTHSmartAmmo_InitializeHooks then
MTHSmartAmmo_InitializeHooks()
end
if MTHSmartAmmo_EnsureHooks then
MTHSmartAmmo_EnsureHooks("SetSmartEnabled")
end
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo Enabled.")
end
else
saved["enabled"] = false
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo Disabled.")
end
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.smartEnabled = enabled and true or false
end
end
function MTHSmartAmmo_GetSmartEnabled()
return MTHSmartAmmo_IsSmartEnabled() and true or false
end
function MTHSmartAmmo_SetReloadEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["reload"] = 1
else
saved["reload"] = false
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.reloadEnabled = enabled and true or false
end
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo reload fallback " .. (enabled and "Enabled." or "Disabled."))
end
end
function MTHSmartAmmo_GetReloadEnabled()
return MTHSmartAmmo_IsReloadEnabled() and true or false
end
local function MTHSmartAmmo_Log(msg)
return
end
local MTHSmartAmmo_CastSpell_Hook
local MTHSmartAmmo_UseAction_Hook
local MTHSmartAmmo_CastSpellByName_Hook
local MTHSmartAmmo_HookEnsureElapsed = 0
local MTHSmartAmmo_InCastSpellHook = false
local MTHSmartAmmo_InUseActionHook = false
local MTHSmartAmmo_InCastSpellByNameHook = false
local MTHSmartAmmo_OriginalCastSpell = CastSpell
local MTHSmartAmmo_OriginalUseAction = UseAction
local MTHSmartAmmo_OriginalCastSpellByName = CastSpellByName
local function MTHSmartAmmo_AreHooksInstalled()
return CastSpell == MTHSmartAmmo_CastSpell_Hook,
UseAction == MTHSmartAmmo_UseAction_Hook,
CastSpellByName == MTHSmartAmmo_CastSpellByName_Hook
end
local function MTHSmartAmmo_ForceHookGlobals()
if type(MTHSmartAmmo_CastSpell_Hook) == "function" and CastSpell ~= MTHSmartAmmo_CastSpell_Hook then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
end
if type(MTHSmartAmmo_UseAction_Hook) == "function" and UseAction ~= MTHSmartAmmo_UseAction_Hook then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
end
if type(MTHSmartAmmo_CastSpellByName_Hook) == "function" and CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
end
end
MTH_SA = {}
MTH_SA_List = {}
MTH_SA_LastCheck = 0
MTH_SA_Tooltip = CreateFrame("GameTooltip", "MTH_SA_Tooltip", nil, "GameTooltipTemplate")
MTH_SA_Tooltip:Hide()
local _, class = UnitClass("player")
if class ~= "HUNTER" then
return
end
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_AutoShot = nil
MTH_SA_LastSpell = nil
MTH_SA_UpdateInterval = 0.1
MTH_SA_Quantity = 0
MTH_SA_LastFallbackAttempt = 0
MTH_SA_LastKnownEquippedName = nil
MTH_SA_LastFallbackNotice = { key = nil, time = 0 }
local function MTHSmartAmmo_RefreshAmmoButtonDisplay()
local createButtons = getglobal("zButtonAmmo_CreateButtons")
local setupSizeAndPosition = getglobal("zButtonAmmo_SetupSizeAndPosition")
local ammoButton = getglobal("zButtonAmmo")
if type(createButtons) == "function" and ammoButton then
createButtons()
if type(setupSizeAndPosition) == "function" then
setupSizeAndPosition()
end
end
end
local function MTHSmartAmmo_ShowFallbackWarning(previousAmmo, newAmmo)
if not previousAmmo or previousAmmo == "" or not newAmmo or newAmmo == "" then
return
end
if previousAmmo == newAmmo then
return
end
local now = GetTime() or 0
local key = tostring(previousAmmo) .. "=>" .. tostring(newAmmo)
if MTH_SA_LastFallbackNotice.key == key and (now - (MTH_SA_LastFallbackNotice.time or 0)) < 1.0 then
return
end
MTH_SA_LastFallbackNotice.key = key
MTH_SA_LastFallbackNotice.time = now
local warning = "YOU RAN OUT OF " .. tostring(previousAmmo) .. ", I EQUIPPED " .. tostring(newAmmo) .. " !"
if MTH_SA_Print then
MTH_SA_Print(warning)
elseif DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.AddMessage then
DEFAULT_CHAT_FRAME:AddMessage(warning)
end
if RaidWarningFrame and RaidNotice_AddMessage and ChatTypeInfo and ChatTypeInfo["RAID_WARNING"] then
RaidNotice_AddMessage(RaidWarningFrame, warning, ChatTypeInfo["RAID_WARNING"])
elseif UIErrorsFrame and UIErrorsFrame.AddMessage then
UIErrorsFrame:AddMessage(warning, 1.0, 0.15, 0.15, 1.0)
end
end
local function MTHSmartAmmo_HandleFallbackResult(previousAmmo)
local checkFrame = CreateFrame("Frame")
if not checkFrame then
return
end
checkFrame.elapsed = 0
checkFrame:SetScript("OnUpdate", function()
this.elapsed = (this.elapsed or 0) + (arg1 or 0)
if this.elapsed < 0.2 then
return
end
local equippedNow = MTH_SA_GetEquippedAmmoName()
if equippedNow and equippedNow ~= "" then
MTH_SA_LastKnownEquippedName = equippedNow
end
MTHSmartAmmo_RefreshAmmoButtonDisplay()
MTHSmartAmmo_ShowFallbackWarning(previousAmmo, equippedNow)
this:SetScript("OnUpdate", nil)
this:Hide()
end)
end
local function MTHSmartAmmo_TryFallbackEquip(reason)
if not MTH_SA_IsModuleEnabled() then
return
end
if not MTHSmartAmmo_IsSmartEnabled() then
return
end
if not MTHSmartAmmo_IsReloadEnabled() then
return
end
if MTH_SA_GetEquippedAmmoName() then
return
end
local now = GetTime() or 0
if MTH_SA_LastFallbackAttempt and (now - MTH_SA_LastFallbackAttempt) < 0.5 then
return
end
MTH_SA_LastFallbackAttempt = now
local previousAmmo = MTH_SA_GetEquippedAmmoName() or MTH_SA_LastKnownEquippedName
MTHSmartAmmo_Log("Fallback equip attempt reason=" .. tostring(reason or "unknown"))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTH_SA_EquipAmmo()
MTHSmartAmmo_HandleFallbackResult(previousAmmo)
end
end
local frame = CreateFrame("Frame")
frame:RegisterEvent("START_AUTOREPEAT_SPELL")
frame:RegisterEvent("STOP_AUTOREPEAT_SPELL")
frame:RegisterEvent("SPELLCAST_INTERRUPTED")
frame:RegisterEvent("SPELLCAST_FAILED")
frame:RegisterEvent("SPELLCAST_STOP")
frame:RegisterEvent("SPELLCAST_DELAYED")
frame:SetScript("OnEvent", function()
if event == "START_AUTOREPEAT_SPELL" then
if MTHSmartAmmo_EnsureHooks then
MTHSmartAmmo_EnsureHooks("EVENT:START_AUTOREPEAT_SPELL")
end
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTHSmartAmmo_Log("EVENT START_AUTOREPEAT_SPELL smart=" .. tostring(MTHSmartAmmo_IsSmartEnabled()) .. " module=" .. tostring(MTH_SA_IsModuleEnabled()) .. " hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
MTH_SA_AutoShot = 1
MTHSmartAmmo_TryFallbackEquip("START_AUTOREPEAT_SPELL")
elseif event == "STOP_AUTOREPEAT_SPELL" then
MTHSmartAmmo_Log("EVENT STOP_AUTOREPEAT_SPELL")
MTH_SA_AutoShot = nil
elseif event == "SPELLCAST_START" then
--DEFAULT_CHAT_FRAME:AddMessage("SPELLCAST_START ", 0, 1, 1)
elseif event == "SPELLCAST_STOP" or event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" or event == "SPELLCAST_DELAYED" then
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTHSmartAmmo_Log("EVENT " .. tostring(event) .. " waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood) .. " lastSpell=" .. tostring(MTH_SA_LastSpell) .. " smart=" .. tostring(MTHSmartAmmo_IsSmartEnabled()) .. " module=" .. tostring(MTH_SA_IsModuleEnabled()) .. " hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
if MTH_SA_IsWaitingSwapJunk then
MTHSmartAmmo_Log("EVENT swap request -> JUNK equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " current=" .. tostring(MTH_SA.curname))
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_Log("EVENT swap request -> GOOD equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " current=" .. tostring(MTH_SA.curname))
MTH_SA_EquipAmmo()
end
MTHSmartAmmo_Log("EVENT clear pending flags")
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
end)
frame:SetScript("OnUpdate", function(self, elapsed)
MTHSmartAmmo_HookEnsureElapsed = MTHSmartAmmo_HookEnsureElapsed + (elapsed or 0)
if MTHSmartAmmo_HookEnsureElapsed >= 0.5 then
MTHSmartAmmo_HookEnsureElapsed = 0
if MTH_SA_IsModuleEnabled() then
MTHSmartAmmo_InitializeHooks()
end
end
MTH_SA_CountEquippedAmmo()
if MTH_SA_Quantity == 0 and not MTH_SA_IsWaitingSwapJunk and not MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_TryFallbackEquip("OnUpdate-quantity-zero")
end
if MTH_SA_AmmoLastSwitch and (GetTime()-MTH_SA_AmmoLastSwitch > 0.5) and (MTH_SA_IsWaitingSwapJunk or MTH_SA_IsWaitingSwapGood) then
MTHSmartAmmo_Log("OnUpdate pending swap elapsed>0.5 equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood))
if MTH_SA_IsWaitingSwapJunk then
MTHSmartAmmo_Log("OnUpdate swap request -> JUNK")
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTHSmartAmmo_Log("OnUpdate swap request -> GOOD")
MTH_SA_EquipAmmo()
end
MTHSmartAmmo_Log("OnUpdate clear pending flags")
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
end)
function MTH_SA_CountEquippedAmmo()
local ammo = GetInventoryItemCount("player", 0)
local equippedName = MTH_SA_GetEquippedAmmoName()
if equippedName and equippedName ~= "" then
MTH_SA_LastKnownEquippedName = equippedName
end
if not ammo then
MTH_SA_Quantity=0
return
elseif ammo ~= MTH_SA_Quantity then
MTH_SA_Quantity = ammo
end
end
function MTH_SA_GetEquippedWeaponAmmoType()
local itemlink = GetInventoryItemLink("player", 18)
if not itemlink then return end
local _, _, itemid = string.find(itemlink, "item:(%d+)")
if not itemid then return end
local _, _, _, _, _, wpntype = GetItemInfo(itemid)
if wpntype == MTH_WEAPON_BOWS or wpntype == MTH_WEAPON_CROSSBOWS then
return "Arrows"
elseif wpntype == MTH_WEAPON_GUNS then
return "Bullets"
end
end
function MTH_SA_GetEquippedAmmoName()
MTH_SA_Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
if MTH_SA_Tooltip:SetInventoryItem("player", 0) then
return MTH_SA_TooltipTextLeft1:GetText()
end
return nil
end
function MTH_SA_GetContainerItemName(bag, slot)
if not (bag and slot) then return nil end
local item = GetContainerItemLink(bag, slot)
local _, _, name = string.find(item or "", "%[(.+)%]")
return name
end
function MTH_SA_EquipAmmo(junk)
MTHSmartAmmo_Log("EquipAmmo enter junk=" .. tostring(junk) .. " equipped=" .. tostring(MTH_SA_GetEquippedAmmoName()) .. " cur=" .. tostring(MTH_SA.curname) .. " junk=" .. tostring(MTH_SA.junkname))
if not MTH_SA_AmmoLastSwitch then MTH_SA_AmmoLastSwitch = GetTime() end
if not (MTH_SA_Check() or MTH_SA_FindAmmo()) then
MTHSmartAmmo_Log("EquipAmmo abort: cache invalid and FindAmmo failed")
return
end
local bag, slot
if junk then
--DEFAULT_CHAT_FRAME:AddMessage("Time= " .. GetTime()-MTH_SA_AmmoLastSwitch , 0, 1, 1)
if GetTime()-MTH_SA_AmmoLastSwitch > 0.5 then
--DEFAULT_CHAT_FRAME:AddMessage("JUNK ! GetTime > 0.5 | Equipped=" .. MTH_SA_GetEquippedAmmoName() .. ' | Current=' .. MTH_SA.curname , 0, 1, 1)
else
--DEFAULT_CHAT_FRAME:AddMessage("JUNK ! GetTime <= 0.5 | Equipped=" .. MTH_SA_GetEquippedAmmoName() .. ' | Current=' .. MTH_SA.curname , 0, 1, 1)
end
if MTH_SA_GetEquippedAmmoName() ~= MTH_SA.curname and GetTime()-MTH_SA_AmmoLastSwitch > 0.5 then
if not MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("EquipAmmo abort: AMMO NOT FOUND during junk swap")
return
end
end
bag, slot = MTH_SA.junkbag, MTH_SA.junkslot
MTHSmartAmmo_Log("Swap GOOD->JUNK bag=" .. tostring(bag) .. " slot=" .. tostring(slot) .. " cur=" .. tostring(MTH_SA.curname) .. " curSlot=" .. tostring(MTH_SA.curslot) .. " junk=" .. tostring(MTH_SA.junkname) .. " junkSlot=" .. tostring(MTH_SA.junkslot))
else
bag, slot = MTH_SA.curbag, MTH_SA.curslot
MTHSmartAmmo_Log("Swap JUNK->GOOD bag=" .. tostring(bag) .. " slot=" .. tostring(slot) .. " cur=" .. tostring(MTH_SA.curname) .. " curSlot=" .. tostring(MTH_SA.curslot) .. " junk=" .. tostring(MTH_SA.junkname) .. " junkSlot=" .. tostring(MTH_SA.junkslot))
end
--UseContainerItem(bag, slot)
PickupContainerItem(bag,slot)
EquipCursorItem(0)
MTHSmartAmmo_Log("EquipCursorItem applied bag=" .. tostring(bag) .. " slot=" .. tostring(slot))
if junk then
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = 1
else
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
end
MTHSmartAmmo_Log("Pending flags set waitJunk=" .. tostring(MTH_SA_IsWaitingSwapJunk) .. " waitGood=" .. tostring(MTH_SA_IsWaitingSwapGood))
--PickupInventoryItem(0)
--AutoEquipCursorItem()
--EquipCursorItem(0)
MTH_SA_AmmoLastSwitch = GetTime()
end
function MTH_SA_FindAmmo()
MTHSmartAmmo_Log("FindAmmo start")
MTH_SA = {}
MTH_SA_List = {}
local ammotype = MTH_SA_GetEquippedWeaponAmmoType()
if not ammotype then
MTHSmartAmmo_Log("FindAmmo abort: no ranged weapon ammo type")
return
end
local curammo = MTH_SA_GetEquippedAmmoName()
if not curammo and not MTHSmartAmmo_IsReloadEnabled() then
MTHSmartAmmo_Log("FindAmmo abort: no equipped ammo and reload disabled")
return
end
MTHSmartAmmo_Log("FindAmmo type=" .. tostring(ammotype) .. " equipped=" .. tostring(curammo))
local ammolist = (ammotype == "Bullets" and MTH_AMMO_BULLET_RANK) or MTH_AMMO_ARROW_RANK or {}
MTH_SA_List = ammolist
local item, value
local junkvalue = 999
local goodvalue
for bag=4, 0, -1 do
for slot=GetContainerNumSlots(bag), 1, -1 do
item = MTH_SA_GetContainerItemName(bag, slot)
if item then
--DEFAULT_CHAT_FRAME:AddMessage("item = " .. item .. " | value = " .. ammolist[item], 0, 1, 1)
value = ammolist[item]
if value then
if not goodvalue and item == curammo then
MTH_SA.curvalue = value
MTH_SA.curname = item
MTH_SA.curbag = bag
MTH_SA.curslot = slot
goodvalue = value
--DEFAULT_CHAT_FRAME:AddMessage("goodvalue A = " .. value , 0, 1, 1)
if junkvalue == 1 then
return 1
end
end
if value < junkvalue then
MTH_SA.junkvalue = item
MTH_SA.junkname = item
MTH_SA.junkbag = bag
MTH_SA.junkslot = slot
junkvalue = value
--DEFAULT_CHAT_FRAME:AddMessage("junkvalue A = " .. value , 0, 1, 1)
if not curammo then
MTH_SA.curvalue = value
MTH_SA.curname = item
MTH_SA.curbag = bag
MTH_SA.curslot = slot
goodvalue = value
--DEFAULT_CHAT_FRAME:AddMessage("goodvalue B = " .. value , 0, 1, 1)
end
if junkvalue == 1 and goodvalue then
return 1
end
end
end
end
end
end
if not goodvalue or junkvalue > goodvalue then
MTHSmartAmmo_Log("FindAmmo failed: goodvalue=" .. tostring(goodvalue) .. " junkvalue=" .. tostring(junkvalue))
MTH_SA.error = 1
return
end
MTHSmartAmmo_Log("FindAmmo selected cur=" .. tostring(MTH_SA.curname) .. " junk=" .. tostring(MTH_SA.junkname) .. " curValue=" .. tostring(MTH_SA.curvalue) .. " junkValue=" .. tostring(junkvalue))
return 1
end
function MTH_SA_Check()
if not MTH_SA.error and MTH_SA.curname and MTH_SA.junkname then
if MTH_SA.curname == MTH_SA_GetContainerItemName(MTH_SA.curbag, MTH_SA.curslot) and
MTH_SA.junkname == MTH_SA_GetContainerItemName(MTH_SA.junkbag, MTH_SA.junkslot) then
return 1
end
end
end
MTHSmartAmmo_CastSpell_Hook = function(spell, tab)
if MTHSmartAmmo_InCastSpellHook then
if MTHSmartAmmo_OriginalCastSpell then
return MTHSmartAmmo_OriginalCastSpell(spell, tab)
end
return
end
MTHSmartAmmo_InCastSpellHook = true
if MTHSmartAmmo_IsSmartEnabled() then
local name = GetSpellName(spell, tab)
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK CastSpell name=" .. tostring(name))
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK CastSpell junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK CastSpell pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
end
local result
local original = MTH_SA_CastSpell
if original == MTHSmartAmmo_CastSpell_Hook or original == nil then
original = MTHSmartAmmo_OriginalCastSpell
end
if original then
result = original(spell, tab)
end
MTHSmartAmmo_InCastSpellHook = false
return result
end
MTHSmartAmmo_UseAction_Hook = function(slot, checkCursor, onSelf)
if MTHSmartAmmo_InUseActionHook then
if MTHSmartAmmo_OriginalUseAction then
return MTHSmartAmmo_OriginalUseAction(slot, checkCursor, onSelf)
end
return
end
MTHSmartAmmo_InUseActionHook = true
if not GetActionText(slot) and MTHSmartAmmo_IsSmartEnabled() then
MTH_SA_Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
MTH_SA_Tooltip:SetAction(slot)
local name = MTH_SA_TooltipTextLeft1:GetText()
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK UseAction slot=" .. tostring(slot) .. " name=" .. tostring(name))
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK UseAction junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK UseAction pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
end
local result
local original = MTH_SA_UseAction
if original == MTHSmartAmmo_UseAction_Hook or original == nil then
original = MTHSmartAmmo_OriginalUseAction
end
if original then
result = original(slot, checkCursor, onSelf)
end
MTHSmartAmmo_InUseActionHook = false
return result
end
MTHSmartAmmo_CastSpellByName_Hook = function(spell, onSelf)
if MTHSmartAmmo_InCastSpellByNameHook then
if MTHSmartAmmo_OriginalCastSpellByName then
return MTHSmartAmmo_OriginalCastSpellByName(spell, onSelf)
end
return
end
MTHSmartAmmo_InCastSpellByNameHook = true
local _, _, name = string.find(spell or "", "([%w%'%s]+)")
MTH_SA_LastSpell = name
MTHSmartAmmo_Log("HOOK CastSpellByName name=" .. tostring(name))
if name and MTHSmartAmmo_IsSmartEnabled() and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
MTHSmartAmmo_Log("HOOK CastSpellByName junk-shot detected name=" .. tostring(name))
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTHSmartAmmo_Log("HOOK CastSpellByName pre-swap -> junk")
MTH_SA_EquipAmmo(1)
end
end
local result
local original = MTH_SA_CastSpellByName
if original == MTHSmartAmmo_CastSpellByName_Hook or original == nil then
original = MTHSmartAmmo_OriginalCastSpellByName
end
if original then
result = original(spell, onSelf)
end
MTHSmartAmmo_InCastSpellByNameHook = false
return result
end
-- Defer hooking until after tables are initialized
MTHSmartAmmo_InitializeHooks = function()
if not MTH_SA_IsModuleEnabled() then
MTHSmartAmmo_Log("InitializeHooks skip: module disabled")
return
end
if CastSpell ~= MTHSmartAmmo_CastSpell_Hook then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
MTHSmartAmmo_Log("InitializeHooks: CastSpell hook installed")
end
if UseAction ~= MTHSmartAmmo_UseAction_Hook then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
MTHSmartAmmo_Log("InitializeHooks: UseAction hook installed")
end
if CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
MTHSmartAmmo_Log("InitializeHooks: CastSpellByName hook installed")
end
end
MTHSmartAmmo_EnsureHooks = function(reason)
if not MTH_SA_IsModuleEnabled() then
return false
end
if not MTHSmartAmmo_IsSmartEnabled() then
return false
end
if MTHSmartAmmo_InitializeHooks then
local ok, err = pcall(MTHSmartAmmo_InitializeHooks)
if not ok then end
end
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
if castHook and actionHook and byNameHook then
return true
end
MTHSmartAmmo_ForceHookGlobals()
castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
return castHook and actionHook and byNameHook
end
-- Initialize hooks on module load
if not MTH_SA_MANAGED_HOOKS then
MTHSmartAmmo_InitializeHooks()
end
SLASH_MTHSmartAmmo1 = "/smartammo"
SlashCmdList["MTHSmartAmmo"] = function(msg)
if not MTH_SA_IsModuleEnabled() then
MTH_SA_Print("Smart Ammo is disabled while module 'smartammo' is disabled.")
return
end
local saved = MTHSmartAmmo_GetSaved()
if msg == "status" then
local castHook, actionHook, byNameHook = MTHSmartAmmo_AreHooksInstalled()
MTH_SA_Print("Smart Ammo status: smart=" .. tostring(saved["enabled"] and true or false) .. ", module=" .. tostring(MTH_SA_IsModuleEnabled()) .. ", hooks=" .. tostring(castHook) .. "/" .. tostring(actionHook) .. "/" .. tostring(byNameHook))
return
end
if saved["enabled"] then
MTHSmartAmmo_SetSmartEnabled(nil)
else
MTHSmartAmmo_SetSmartEnabled(1)
end
end