From f3af63926ec6a918c5014714856f7850cb2b301a Mon Sep 17 00:00:00 2001 From: DuvelCorp Date: Sat, 12 Sep 2026 12:08:54 +0200 Subject: [PATCH] Fix SmartAmmo low-ammo warnings - Remove infinite tail-recursion threshold getter that hard-froze the client on /rl - Fix double-count (equipped ammo was added to the bag total) - Make it true crossing-only: warn only when the total drops across the threshold, never on cold baseline or restock - Use the shaking warning banner instead of a celebration, with sarcastic chat/banner copy - Options: fix legacy EditBox HasFocus error on the threshold input; move Pet Auto-Teach to the right column --- CHANGELOG.md | 2 +- api/fx-celebrate.lua | 38 +++++++++++++++++++++++++++++++++--- api/options-zbuttons.lua | 28 +++++++++++++------------- modules/smartammo/engine.lua | 26 +++++++++++++++++------- 4 files changed, 69 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6a517a..886703b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Resurrecting on Octowow. ### Added -- **SmartAmmo — low-ammo alerts**: SmartAmmo now monitors the total matching arrows or bullets in your bags and equipped slot. Choose a warning threshold (default: 200), with chat and optional center-screen alerts for low stock and a sarcastic warning when you run out entirely. +- **SmartAmmo — low-ammo alerts**: SmartAmmo can now monitors the total matching arrows or bullets in your bags and equipped slot, choose a warning threshold (default: 200), and MetaHunt will ouput a chat and centered-screen alert when you reach it. - **New spell datastore**: Metahunt now have a datastore of all twow 1.18.1 hunter and pet spells. And you can browse them with new pages in the Book. diff --git a/api/fx-celebrate.lua b/api/fx-celebrate.lua index 0147ea3..238f821 100644 --- a/api/fx-celebrate.lua +++ b/api/fx-celebrate.lua @@ -794,16 +794,48 @@ function MTH_CelebrateAmmoFallback(previousAmmo, newAmmo) }) end -function MTH_CelebrateLowAmmo(ammoType, total, threshold) +function MTH_CelebrateLowAmmo(ammoType, total) if not MTH_FX_IsEnabled("combat.lowammo") or not Sauce or not MTH_FX_EnsureFrames() then return end - MTH_Celebrate("Low " .. tostring(ammoType or "ammo") .. "!", tostring(total or 0) .. " left.", "fanfare", 5) MTH_FX_TitleFS:SetTextColor(1, 0.55, 0.10) + MTH_FX_TitleFS:SetText("Running low on " .. tostring(ammoType or "ammo") .. "!") + MTH_FX_SubFS:SetText(tostring(total or 0) .. " left before you're reduced to harsh language.") + + Sauce:Stop(MTH_FX_MsgFrame) + MTH_FX_MsgFrame:SetAlpha(0) + MTH_FX_MsgFrame:Show() + Sauce:Sequence({ + Sauce:FadeTo(MTH_FX_MsgFrame, 1, 0.18), + Sauce:Tween(MTH_FX_MsgFrame, { + type = "mth_shake", + duration = 0.55, + easing = "linear", + magnitude = 11, + freq = 42, + }), + Sauce:FadeOut(MTH_FX_MsgFrame, 0.7, "inQuad", { delay = 5 }), + }) end function MTH_CelebrateAmmoZero(ammoType) if not MTH_FX_IsEnabled("combat.ammozero") or not Sauce or not MTH_FX_EnsureFrames() then return end - MTH_Celebrate("No " .. tostring(ammoType or "ammo") .. " left!", "Excellent planning. Your ranged weapon is now decorative.", "victory", 5) MTH_FX_TitleFS:SetTextColor(1, 0.15, 0.15) + MTH_FX_TitleFS:SetText("Out of " .. tostring(ammoType or "ammo") .. "!") + MTH_FX_SubFS:SetText("Your ranged weapon is now a very expensive club. Well done.") + + Sauce:Stop(MTH_FX_MsgFrame) + MTH_FX_MsgFrame:SetAlpha(0) + MTH_FX_MsgFrame:Show() + Sauce:Sequence({ + Sauce:FadeTo(MTH_FX_MsgFrame, 1, 0.18), + Sauce:Tween(MTH_FX_MsgFrame, { + type = "mth_shake", + duration = 0.55, + easing = "linear", + magnitude = 11, + freq = 42, + }), + Sauce:FadeOut(MTH_FX_MsgFrame, 0.7, "inQuad", { delay = 5 }), + }) end -- DEBUG: mark that the whole file finished loading and record which globals it diff --git a/api/options-zbuttons.lua b/api/options-zbuttons.lua index 1847111..e7cbad6 100644 --- a/api/options-zbuttons.lua +++ b/api/options-zbuttons.lua @@ -1348,7 +1348,7 @@ function MTH_SetupGeneralOptions() local lowAmmoInput = smartBox:EditRow("MetaHuntGeneralSmartAmmoLowThresholdLabel", "Low-ammo threshold:", "MetaHuntGeneralSmartAmmoLowThreshold", 48, { numeric = true, onChange = function() - if this:HasFocus() and type(MTHSmartAmmo_SetLowAmmoThreshold) == "function" then + if type(MTHSmartAmmo_SetLowAmmoThreshold) == "function" then MTHSmartAmmo_SetLowAmmoThreshold(this:GetText()) end end, @@ -1398,19 +1398,6 @@ function MTH_SetupGeneralOptions() }) antiBox:Note("MetaHuntGeneralAntiDazeHelp", "Cancels Cheetah/Pack when dazed.") - -- ===== LEFT: Pet Auto-Teach ===== - local petTeachBox = panel:Box("left", "MetaHuntGeneralPetTeachBox", "Pet Auto-Teach") - local growlEnabled = (type(MTH_Growl_IsEnabled) == "function" and MTH_Growl_IsEnabled()) or false - petTeachBox:Checkbox("MetaHuntGeneralPetTeachGrowlToggle", "Activate Auto-Teach of Growl (Max rank)", { - checked = growlEnabled, - onClick = function() - if type(MTH_Growl_SetEnabled) == "function" then - MTH_Growl_SetEnabled(this:GetChecked() == 1) - end - end, - }) - petTeachBox:Note("MetaHuntGeneralPetTeachGrowlHelp", "When you tame a beast, offers to teach it the best Growl rank for its level.") - -- ===== RIGHT: Tooltips ===== local tooltipsBox = panel:Box("right", "MetaHuntGeneralTooltipsBox", "Tooltips") local tooltipsStore = MTH and MTH.GetModuleCharSavedVariables and MTH:GetModuleCharSavedVariables("tooltips") @@ -1546,5 +1533,18 @@ function MTH_SetupGeneralOptions() }) bagsBox:Note("MetaHuntGeneralBagDmgHelp", "Damage is heat-coloured from red (7.5) to green (20.5).") + -- ===== RIGHT: Pet Auto-Teach ===== + local petTeachBox = panel:Box("right", "MetaHuntGeneralPetTeachBox", "Pet Auto-Teach") + local growlEnabled = (type(MTH_Growl_IsEnabled) == "function" and MTH_Growl_IsEnabled()) or false + petTeachBox:Checkbox("MetaHuntGeneralPetTeachGrowlToggle", "Activate Auto-Teach of Growl (Max rank)", { + checked = growlEnabled, + onClick = function() + if type(MTH_Growl_SetEnabled) == "function" then + MTH_Growl_SetEnabled(this:GetChecked() == 1) + end + end, + }) + petTeachBox:Note("MetaHuntGeneralPetTeachGrowlHelp", "When you tame a beast, offers to teach it the best Growl rank for its level.") + panel:Finish() end diff --git a/modules/smartammo/engine.lua b/modules/smartammo/engine.lua index 480ef09..c8380a9 100644 --- a/modules/smartammo/engine.lua +++ b/modules/smartammo/engine.lua @@ -48,7 +48,7 @@ local function MTHSmartAmmo_IsLowAmmoWarningEnabled() return MTHSmartAmmo_ReadFlag("lowAmmoWarningEnabled") end -local function MTHSmartAmmo_GetLowAmmoThreshold() +local function MTHSmartAmmo_ReadLowAmmoThreshold() local settings = MTHSmartAmmo_GetSettings() local threshold = tonumber(settings and settings.lowAmmoThreshold) or 200 if threshold < 1 then threshold = 1 end @@ -145,7 +145,7 @@ function MTHSmartAmmo_SetLowAmmoThreshold(value) end function MTHSmartAmmo_GetLowAmmoThreshold() - return MTHSmartAmmo_GetLowAmmoThreshold() + return MTHSmartAmmo_ReadLowAmmoThreshold() end local MTHSmartAmmo_CastSpell_Hook @@ -275,9 +275,9 @@ local function MTHSmartAmmo_ShowAmmoStockWarning(ammoType, total, threshold) local isZero = total <= 0 local warning if isZero then - warning = "YOU HAVE NO " .. string.upper(ammoType) .. " LEFT!" + warning = "Out of " .. ammoType .. "! Your ranged weapon is now a very expensive club." else - warning = "LOW " .. string.upper(ammoType) .. ": " .. tostring(total) .. " LEFT (WARNING AT " .. tostring(threshold) .. ")." + warning = "Running low on " .. ammoType .. " — only " .. tostring(total) .. " left. Restock before you're just angrily pointing at things." end if MTH_SA_Print then MTH_SA_Print(warning) @@ -298,6 +298,8 @@ end local function MTHSmartAmmo_CountAmmoStock(ammoType) local rankMap = (ammoType == "Bullets" and MTH_AMMO_BULLET_RANK) or MTH_AMMO_ARROW_RANK or {} + -- Bag scan already covers the quiver/ammo pouch; GetInventoryItemCount("player", 0) + -- returns the bag copies of the loaded ammo, so adding it would double-count. local total = 0 for bag = 4, 0, -1 do for slot = GetContainerNumSlots(bag), 1, -1 do @@ -308,7 +310,15 @@ local function MTHSmartAmmo_CountAmmoStock(ammoType) end end end - return total + (tonumber(GetInventoryItemCount("player", 0)) or 0) + return total +end + +-- ready < low < zero; a warning fires only when severity INCREASES (a real +-- downward crossing during play), never on the cold baseline or on restock. +local function MTHSmartAmmo_StockSeverity(state) + if state == "zero" then return 2 end + if state == "low" then return 1 end + return 0 end local function MTHSmartAmmo_CheckAmmoStock() @@ -319,9 +329,11 @@ local function MTHSmartAmmo_CheckAmmoStock() return end local total = MTHSmartAmmo_CountAmmoStock(ammoType) - local threshold = MTHSmartAmmo_GetLowAmmoThreshold() + local threshold = MTHSmartAmmo_ReadLowAmmoThreshold() local state = total <= 0 and "zero" or (total <= threshold and "low" or "ready") - if state ~= MTH_SA_AmmoStockState and state ~= "ready" then + + local prev = MTH_SA_AmmoStockState + if prev ~= nil and MTHSmartAmmo_StockSeverity(state) > MTHSmartAmmo_StockSeverity(prev) then MTHSmartAmmo_ShowAmmoStockWarning(ammoType, total, threshold) end MTH_SA_AmmoStockState = state