Files
MetaHunt/modules/smartammo/engine.lua
T

823 lines
24 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()
if saved["enabled"] == nil then
return true
end
return saved["enabled"] and true or false
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 function MTHSmartAmmo_IsWeaponSwapEnabled()
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" and moduleStore.weaponSwapEnabled ~= nil then
return moduleStore.weaponSwapEnabled and true or false
end
local saved = MTHSmartAmmo_GetSaved()
if saved["weaponSwap"] == nil then
return true
end
return saved["weaponSwap"] and true or false
end
local MTHSmartAmmo_InitializeHooks
MTHSmartAmmo_EnsureHooks = nil
local MTH_SA_SPELL_EVENTS = {
"START_AUTOREPEAT_SPELL",
"STOP_AUTOREPEAT_SPELL",
"SPELLCAST_INTERRUPTED",
"SPELLCAST_FAILED",
"SPELLCAST_STOP",
"SPELLCAST_DELAYED",
}
function MTHSmartAmmo_SetSmartEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["enabled"] = 1
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
evFrame:RegisterEvent(ev)
end
end
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
local evFrame = getglobal("MTH_SA_EventFrame")
if evFrame then
for _, ev in ipairs(MTH_SA_SPELL_EVENTS) do
evFrame:UnregisterEvent(ev)
end
end
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
function MTHSmartAmmo_SetWeaponSwapEnabled(enabled, silent)
local saved = MTHSmartAmmo_GetSaved()
if enabled then
saved["weaponSwap"] = 1
else
saved["weaponSwap"] = false
end
local moduleStore = MTHSmartAmmo_GetModuleStore()
if type(moduleStore) == "table" then
moduleStore.weaponSwapEnabled = enabled and true or false
end
if not silent and DEFAULT_CHAT_FRAME then
MTH_SA_Print("Smart Ammo weapon-swap auto-equip " .. (enabled and "Enabled." or "Disabled."))
end
end
function MTHSmartAmmo_GetWeaponSwapEnabled()
return MTHSmartAmmo_IsWeaponSwapEnabled() and true or false
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
if CastSpell == MTHSmartAmmo_OriginalCastSpell or MTH_SA_CastSpell == nil then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
end
end
if type(MTHSmartAmmo_UseAction_Hook) == "function" and UseAction ~= MTHSmartAmmo_UseAction_Hook then
if UseAction == MTHSmartAmmo_OriginalUseAction or MTH_SA_UseAction == nil then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
end
end
if type(MTHSmartAmmo_CastSpellByName_Hook) == "function" and CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
if CastSpellByName == MTHSmartAmmo_OriginalCastSpellByName or MTH_SA_CastSpellByName == nil then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
end
end
end
MTH_SA = {}
MTH_SA_List = {}
MTH_SA_LastCheck = 0
MTH_SA_Tooltip = getglobal("MTH_SA_AmmoProbe") or CreateFrame("GameTooltip", "MTH_SA_AmmoProbe", nil, "GameTooltipTemplate")
MTH_SA_TooltipTextLeft1 = getglobal("MTH_SA_AmmoProbeTextLeft1")
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 }
MTH_SA_LastKnownWeaponAmmoType = nil
MTH_SA_LastWeaponCheck = 0
MTH_SA_StartupProtectUntil = (GetTime() or 0) + 2.0
MTH_SA_StartupPrimed = nil
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 MTHSmartAmmo_FallbackCheckFrame = nil
local function MTHSmartAmmo_HandleFallbackResult(previousAmmo)
if not MTHSmartAmmo_FallbackCheckFrame then
MTHSmartAmmo_FallbackCheckFrame = CreateFrame("Frame", "MTH_SA_FallbackCheck")
if not MTHSmartAmmo_FallbackCheckFrame then
return
end
end
local checkFrame = MTHSmartAmmo_FallbackCheckFrame
checkFrame.elapsed = 0
checkFrame._previousAmmo = previousAmmo
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(this._previousAmmo, equippedNow)
this:SetScript("OnUpdate", nil)
this:Hide()
end)
checkFrame:Show()
end
local function MTHSmartAmmo_TryFallbackEquip(reason)
local now = GetTime() or 0
if now < (MTH_SA_StartupProtectUntil or 0) then
return
end
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
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
if MTH_SA_Check() or MTH_SA_FindAmmo() then
MTH_SA_EquipAmmo()
MTHSmartAmmo_HandleFallbackResult(previousAmmo)
end
end
local function MTHSmartAmmo_FindBestAmmoForType(ammoType)
if not ammoType then
return nil
end
local rankMap = (ammoType == "Bullets" and MTH_AMMO_BULLET_RANK) or MTH_AMMO_ARROW_RANK or {}
local best = nil
for bag = 4, 0, -1 do
for slot = GetContainerNumSlots(bag), 1, -1 do
local itemName = MTH_SA_GetContainerItemName(bag, slot)
if itemName then
local value = rankMap[itemName]
if value and (not best or value > best.value) then
best = {
name = itemName,
value = value,
bag = bag,
slot = slot,
}
end
end
end
end
return best
end
local function MTHSmartAmmo_EquipAmmoFromSlot(bag, slot)
if not bag or not slot then
return false
end
PickupContainerItem(bag, slot)
if CursorHasItem and CursorHasItem() then
EquipCursorItem(0)
end
if CursorHasItem and CursorHasItem() then
if ClearCursor then
ClearCursor()
end
return false
end
return true
end
local function MTHSmartAmmo_HandleWeaponSwapAutoEquip(reason)
local now = GetTime() or 0
if now < (MTH_SA_StartupProtectUntil or 0) then
return
end
if not MTH_SA_IsModuleEnabled() then
return
end
if not MTHSmartAmmo_IsWeaponSwapEnabled() then
return
end
local weaponAmmoType = MTH_SA_GetEquippedWeaponAmmoType()
if not weaponAmmoType then
MTH_SA_LastKnownWeaponAmmoType = nil
MTH_SA_StartupPrimed = true
return
end
if not MTH_SA_StartupPrimed then
MTH_SA_LastKnownWeaponAmmoType = weaponAmmoType
MTH_SA_StartupPrimed = true
return
end
if MTH_SA_LastKnownWeaponAmmoType == weaponAmmoType then
return
end
MTH_SA_LastKnownWeaponAmmoType = weaponAmmoType
local bestAmmo = MTHSmartAmmo_FindBestAmmoForType(weaponAmmoType)
if not bestAmmo then
return
end
local equippedNow = MTH_SA_GetEquippedAmmoName()
if equippedNow and equippedNow == bestAmmo.name then
return
end
if MTHSmartAmmo_EquipAmmoFromSlot(bestAmmo.bag, bestAmmo.slot) then
MTH_SA_LastKnownEquippedName = bestAmmo.name
MTHSmartAmmo_RefreshAmmoButtonDisplay()
end
end
local frame = getglobal("MTH_SA_EventFrame") or CreateFrame("Frame", "MTH_SA_EventFrame")
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:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:SetScript("OnEvent", function()
if event == "START_AUTOREPEAT_SPELL" then
if MTHSmartAmmo_EnsureHooks then
MTHSmartAmmo_EnsureHooks("EVENT:START_AUTOREPEAT_SPELL")
end
MTH_SA_AutoShot = 1
MTHSmartAmmo_TryFallbackEquip("START_AUTOREPEAT_SPELL")
elseif event == "STOP_AUTOREPEAT_SPELL" then
MTH_SA_AutoShot = nil
elseif event == "PLAYER_ENTERING_WORLD" then
local now = GetTime() or 0
MTH_SA_StartupProtectUntil = now + 2.0
MTH_SA_StartupPrimed = nil
MTH_SA_LastKnownWeaponAmmoType = MTH_SA_GetEquippedWeaponAmmoType()
MTH_SA_LastKnownEquippedName = MTH_SA_GetEquippedAmmoName()
MTH_SA_LastWeaponCheck = now
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
if MTH_SA_IsWaitingSwapJunk then
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTH_SA_EquipAmmo()
end
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
end)
local MTH_SA_OnUpdateElapsed = 0
frame:SetScript("OnUpdate", function()
local dt = arg1 or 0
MTHSmartAmmo_HookEnsureElapsed = MTHSmartAmmo_HookEnsureElapsed + dt
MTH_SA_OnUpdateElapsed = MTH_SA_OnUpdateElapsed + dt
if MTH_SA_OnUpdateElapsed < 0.10 then
return
end
MTH_SA_OnUpdateElapsed = 0
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
if MTH_SA_IsWaitingSwapJunk then
MTH_SA_EquipAmmo(1)
elseif MTH_SA_IsWaitingSwapGood then
MTH_SA_EquipAmmo()
end
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
MTH_SA_LastSpell = nil
end
local now = GetTime() or 0
if (now - (MTH_SA_LastWeaponCheck or 0)) >= 0.25 then
MTH_SA_LastWeaponCheck = now
MTHSmartAmmo_HandleWeaponSwapAutoEquip("OnUpdate-weapon-check")
end
end)
function MTH_SA_CountEquippedAmmo()
local ammo = GetInventoryItemCount("player", 0)
local equippedName = MTH_SA_GetEquippedAmmoName()
if equippedName and equippedName ~= "" then
if equippedName ~= MTH_SA_LastKnownEquippedName then
MTH_SA_LastKnownEquippedName = equippedName
MTHSmartAmmo_RefreshAmmoButtonDisplay()
end
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)
if not MTH_SA_AmmoLastSwitch then MTH_SA_AmmoLastSwitch = GetTime() end
if not (MTH_SA_Check() or MTH_SA_FindAmmo()) then
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
return
end
end
bag, slot = MTH_SA.junkbag, MTH_SA.junkslot
else
bag, slot = MTH_SA.curbag, MTH_SA.curslot
end
--UseContainerItem(bag, slot)
PickupContainerItem(bag,slot)
EquipCursorItem(0)
if junk then
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = 1
else
MTH_SA_IsWaitingSwapJunk = nil
MTH_SA_IsWaitingSwapGood = nil
end
--PickupInventoryItem(0)
--AutoEquipCursorItem()
--EquipCursorItem(0)
MTH_SA_AmmoLastSwitch = GetTime()
end
function MTH_SA_FindAmmo()
MTH_SA = {}
MTH_SA_List = {}
local ammotype = MTH_SA_GetEquippedWeaponAmmoType()
if not ammotype then
return
end
local curammo = MTH_SA_GetEquippedAmmoName()
if not curammo and not MTHSmartAmmo_IsReloadEnabled() then
return
end
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
MTH_SA.error = 1
return
end
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
if name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
if MTH_SA_Check() or MTH_SA_FindAmmo() then
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
local _actionText = GetActionText(slot)
local _smart = MTHSmartAmmo_IsSmartEnabled()
if not _actionText and _smart then
MTH_SA_Tooltip:SetOwner(UIParent, "ANCHOR_NONE")
MTH_SA_Tooltip:SetAction(slot)
local name = MTH_SA_TooltipTextLeft1:GetText()
MTH_SA_LastSpell = name
local _inSet = name and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name]
if _inSet then
if MTH_SA_Check() or MTH_SA_FindAmmo() then
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
if name and MTHSmartAmmo_IsSmartEnabled() and MTH_AMMO_JUNKSHOT_SET and MTH_AMMO_JUNKSHOT_SET[name] then
if MTH_SA_Check() or MTH_SA_FindAmmo() then
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
return
end
-- Only install a hook if vanilla is on top (first-time install) or MetaHunt
-- is already on top. If another addon (e.g. Quiver) is on top, it has already
-- captured MetaHunt's hook as its super — reinstalling would create a double
-- invocation and break addons that rely on IsCurrentAction after their super call.
if CastSpell ~= MTHSmartAmmo_CastSpell_Hook then
if CastSpell == MTHSmartAmmo_OriginalCastSpell or MTH_SA_CastSpell == nil then
MTH_SA_CastSpell = CastSpell
CastSpell = MTHSmartAmmo_CastSpell_Hook
end
end
if UseAction ~= MTHSmartAmmo_UseAction_Hook then
if UseAction == MTHSmartAmmo_OriginalUseAction or MTH_SA_UseAction == nil then
MTH_SA_UseAction = UseAction
UseAction = MTHSmartAmmo_UseAction_Hook
end
end
if CastSpellByName ~= MTHSmartAmmo_CastSpellByName_Hook then
if CastSpellByName == MTHSmartAmmo_OriginalCastSpellByName or MTH_SA_CastSpellByName == nil then
MTH_SA_CastSpellByName = CastSpellByName
CastSpellByName = MTHSmartAmmo_CastSpellByName_Hook
end
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