Animations: wire remaining effects + 2-column options panel

- Shared FX toolkit in fx-celebrate.lua: mth_shake tween type, MTH_FX_Flash
  glow helper, MTH_CelebrateRunaway red shaking banner, gold title reset.
- pet.runaway, pet.happiness, pet.loyaltyup, pet.feed
- combat.ammoswap, combat.rangedswap, combat.mmprocs
- ui.zbar, ui.stable, ui.minimapping, ui.optionsclose
- book.model, book.search
- Options > Animations panel now uses a balanced two-column layout.
- CHANGELOG Animations entry expanded (no version bump).
This commit is contained in:
DuvelCorp
2026-09-10 16:38:14 +02:00
parent d2fb04f7c5
commit 66ff1ae711
14 changed files with 343 additions and 11 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ Resurrecting on Octowow.
### Added ### Added
- **Animations**: MetaHunt now plays optional animations that make the interface feel alive. A firework-and-banner celebration bursts on screen when your pet learns a new ability or a new rank, the Great Book slides up and fades in when you open it and gently fades its list when you switch tabs, the options window slides in when opened and its tabs fade as you switch them, the minimap button pulses when clicked, collapsible zButton bars fade their buttons in as they expand, and world-map markers fade in when you locate a beast, vendor or master. Everything is optional and off-switchable: a new **Animations** tab (Options → Animations) lets you toggle each effect on its own — or disable them all at once. Powered by the PizzaSauce animation library. - **Animations**: MetaHunt now plays optional animations that make the interface feel alive. A firework-and-banner celebration bursts on screen when your pet learns a new ability or a new rank, and a red shaking banner warns you when a pet runs away for good. Your pet button flashes when its happiness changes, it gains a loyalty level, or you feed it; the ammo button flashes when Smart Ammo swaps your bullets or auto-equips after a weapon swap; and the MM Widget pulses on a Lock & Load proc. The Great Book slides up and fades in when you open it, gently fades its list when you switch tabs or run a search, fades beast models into view, and fades out when closed; stable slots flash when a pet is deposited, withdrawn or swapped. The options window slides in when opened, fades its tabs as you switch them, and fades out when closed. The minimap button pulses when clicked, minimap markers ping as beasts come into range, collapsible zButton bars fade their buttons in as they expand, the zBar fades in when enabled, and world-map markers fade in when you locate a beast, vendor or master. Everything is optional and off-switchable: a new **Animations** tab (Options → Animations) lets you toggle each effect on its own — or disable them all at once. Powered by the PizzaSauce animation library.
- **zTrack — Find Fish**: Added new spell Find Fish to the zTrack list of trackings. - **zTrack — Find Fish**: Added new spell Find Fish to the zTrack list of trackings.
+7
View File
@@ -1385,6 +1385,13 @@ function MTH_FEED_FinalizeAttempt(attemptId, payload)
if petKey ~= "" then if petKey ~= "" then
MTH_FEED_Runtime.sessionFeedsByPetId[petKey] = (tonumber(MTH_FEED_Runtime.sessionFeedsByPetId[petKey]) or 0) + 1 MTH_FEED_Runtime.sessionFeedsByPetId[petKey] = (tonumber(MTH_FEED_Runtime.sessionFeedsByPetId[petKey]) or 0) + 1
end end
if type(MTH_FX_Flash) == "function" and type(MTH_FX_IsEnabled) == "function"
and MTH_FX_IsEnabled("pet.feed") then
local target = getglobal("zButtonPet")
if target then
MTH_FX_Flash(target, 0.35, 1.00, 0.35, 0.5)
end
end
else else
petRow.totals.rejected = petRow.totals.rejected + 1 petRow.totals.rejected = petRow.totals.rejected + 1
if reason == "no-buff" then if reason == "no-buff" then
+3
View File
@@ -2791,6 +2791,9 @@ function MTH_PETS_RecordPetRunaway(source, rawMessage)
if MTH:IsMessageEnabled("petRanAway", true) then if MTH:IsMessageEnabled("petRanAway", true) then
MTH:Print("YOUR PET " .. tostring(displayName) .. " HAS RUNAWAY FOREVER :-( Try to feed it better next time.") MTH:Print("YOUR PET " .. tostring(displayName) .. " HAS RUNAWAY FOREVER :-( Try to feed it better next time.")
end end
if type(MTH_CelebrateRunaway) == "function" then
MTH_CelebrateRunaway(displayName)
end
end end
return true return true
+144
View File
@@ -33,6 +33,7 @@ MTH_FX_DBG = {
-- Sections shown, in order, in the options panel. `titleKey` localizes `title`. -- Sections shown, in order, in the options panel. `titleKey` localizes `title`.
MTH_FX_ANIM_SECTIONS = { MTH_FX_ANIM_SECTIONS = {
{ id = "pet", title = "Pet", titleKey = "ANIM_SECTION_PET" }, { id = "pet", title = "Pet", titleKey = "ANIM_SECTION_PET" },
{ id = "combat", title = "Combat", titleKey = "ANIM_SECTION_COMBAT" },
{ id = "book", title = "Book", titleKey = "ANIM_SECTION_BOOK" }, { id = "book", title = "Book", titleKey = "ANIM_SECTION_BOOK" },
{ id = "ui", title = "Interface", titleKey = "ANIM_SECTION_UI" }, { id = "ui", title = "Interface", titleKey = "ANIM_SECTION_UI" },
} }
@@ -46,6 +47,34 @@ MTH_FX_ANIM_DEFS = {
label = "Celebrate new pet abilities", labelKey = "ANIM_PET_CELEBRATE", label = "Celebrate new pet abilities", labelKey = "ANIM_PET_CELEBRATE",
tooltip = "Play a firework and a banner in the middle of the screen when your pet learns a new ability or a new rank.", tooltip = "Play a firework and a banner in the middle of the screen when your pet learns a new ability or a new rank.",
tooltipKey = "ANIM_PET_CELEBRATE_TIP" }, tooltipKey = "ANIM_PET_CELEBRATE_TIP" },
{ key = "pet.runaway", section = "pet", default = true,
label = "Warn when a pet runs away", labelKey = "ANIM_PET_RUNAWAY",
tooltip = "Flash a red, shaking banner in the middle of the screen when one of your pets runs away for good.",
tooltipKey = "ANIM_PET_RUNAWAY_TIP" },
{ key = "pet.happiness", section = "pet", default = true,
label = "Flash on happiness change", labelKey = "ANIM_PET_HAPPINESS",
tooltip = "Briefly flash the pet happiness area green when your pet cheers up, or red when it gets unhappy.",
tooltipKey = "ANIM_PET_HAPPINESS_TIP" },
{ key = "pet.loyaltyup", section = "pet", default = true,
label = "Glow on loyalty gain", labelKey = "ANIM_PET_LOYALTYUP",
tooltip = "Give a short golden glow when your pet gains a loyalty level.",
tooltipKey = "ANIM_PET_LOYALTYUP_TIP" },
{ key = "pet.feed", section = "pet", default = true,
label = "Flash when feeding your pet", labelKey = "ANIM_PET_FEED",
tooltip = "Give a short green flash when Feed-O-Matic feeds your pet.",
tooltipKey = "ANIM_PET_FEED_TIP" },
{ key = "combat.ammoswap", section = "combat", default = true,
label = "Flash on Smart Ammo swap", labelKey = "ANIM_COMBAT_AMMOSWAP",
tooltip = "Briefly highlight the zAmmo button when Smart Ammo swaps your ammo.",
tooltipKey = "ANIM_COMBAT_AMMOSWAP_TIP" },
{ key = "combat.rangedswap", section = "combat", default = true,
label = "Flash on ranged weapon swap", labelKey = "ANIM_COMBAT_RANGEDSWAP",
tooltip = "Briefly highlight the zRanged button when you hot-swap a ranged weapon.",
tooltipKey = "ANIM_COMBAT_RANGEDSWAP_TIP" },
{ key = "combat.mmprocs", section = "combat", default = true,
label = "Pulse MM Widget procs", labelKey = "ANIM_COMBAT_MMPROCS",
tooltip = "Pulse an MM Widget cell when a Lock and Load or Experimental ammo proc lights up.",
tooltipKey = "ANIM_COMBAT_MMPROCS_TIP" },
{ key = "book.open", section = "book", default = true, { key = "book.open", section = "book", default = true,
label = "Fade in the Hunter's Book", labelKey = "ANIM_BOOK_OPEN", label = "Fade in the Hunter's Book", labelKey = "ANIM_BOOK_OPEN",
tooltip = "Fade the Hunter's Book window in when you open it.", tooltip = "Fade the Hunter's Book window in when you open it.",
@@ -54,6 +83,14 @@ MTH_FX_ANIM_DEFS = {
label = "Fade Hunter's Book tab changes", labelKey = "ANIM_BOOK_TABS", label = "Fade Hunter's Book tab changes", labelKey = "ANIM_BOOK_TABS",
tooltip = "Fade the results list back in when you switch tabs inside the Hunter's Book.", tooltip = "Fade the results list back in when you switch tabs inside the Hunter's Book.",
tooltipKey = "ANIM_BOOK_TABS_TIP" }, tooltipKey = "ANIM_BOOK_TABS_TIP" },
{ key = "book.model", section = "book", default = true,
label = "Fade in beast models", labelKey = "ANIM_BOOK_MODEL",
tooltip = "Fade the beast model viewer in when it loads a new model.",
tooltipKey = "ANIM_BOOK_MODEL_TIP" },
{ key = "book.search", section = "book", default = true,
label = "Fade search results", labelKey = "ANIM_BOOK_SEARCH",
tooltip = "Fade the results list when your search filter changes.",
tooltipKey = "ANIM_BOOK_SEARCH_TIP" },
{ key = "ui.options", section = "ui", default = true, { key = "ui.options", section = "ui", default = true,
label = "Slide the options window open", labelKey = "ANIM_UI_OPTIONS", label = "Slide the options window open", labelKey = "ANIM_UI_OPTIONS",
tooltip = "Slide and fade the MetaHunt options window in when you open it.", tooltip = "Slide and fade the MetaHunt options window in when you open it.",
@@ -62,14 +99,30 @@ MTH_FX_ANIM_DEFS = {
label = "Fade options tab changes", labelKey = "ANIM_UI_OPTIONTABS", label = "Fade options tab changes", labelKey = "ANIM_UI_OPTIONTABS",
tooltip = "Fade the settings panel when you switch tabs inside the options window.", tooltip = "Fade the settings panel when you switch tabs inside the options window.",
tooltipKey = "ANIM_UI_OPTIONTABS_TIP" }, tooltipKey = "ANIM_UI_OPTIONTABS_TIP" },
{ key = "ui.optionsclose", section = "ui", default = true,
label = "Fade windows closed", labelKey = "ANIM_UI_OPTIONSCLOSE",
tooltip = "Fade the options and Hunter's Book windows out when you close them.",
tooltipKey = "ANIM_UI_OPTIONSCLOSE_TIP" },
{ key = "ui.minimap", section = "ui", default = true, { key = "ui.minimap", section = "ui", default = true,
label = "Pulse the minimap button on click", labelKey = "ANIM_UI_MINIMAP", label = "Pulse the minimap button on click", labelKey = "ANIM_UI_MINIMAP",
tooltip = "Give the minimap button a quick pulse when you click it.", tooltip = "Give the minimap button a quick pulse when you click it.",
tooltipKey = "ANIM_UI_MINIMAP_TIP" }, tooltipKey = "ANIM_UI_MINIMAP_TIP" },
{ key = "ui.minimapping", section = "ui", default = true,
label = "Ping the minimap on locate", labelKey = "ANIM_UI_MINIMAPPING",
tooltip = "Send a short ping ripple over the minimap when you locate a tracked NPC.",
tooltipKey = "ANIM_UI_MINIMAPPING_TIP" },
{ key = "ui.zbuttons", section = "ui", default = true, { key = "ui.zbuttons", section = "ui", default = true,
label = "Fade zButton bars open", labelKey = "ANIM_UI_ZBUTTONS", label = "Fade zButton bars open", labelKey = "ANIM_UI_ZBUTTONS",
tooltip = "Fade the child buttons in when a collapsible zButton bar (pet, tracking, aspects...) expands.", tooltip = "Fade the child buttons in when a collapsible zButton bar (pet, tracking, aspects...) expands.",
tooltipKey = "ANIM_UI_ZBUTTONS_TIP" }, tooltipKey = "ANIM_UI_ZBUTTONS_TIP" },
{ key = "ui.zbar", section = "ui", default = true,
label = "Fade the zBar in", labelKey = "ANIM_UI_ZBAR",
tooltip = "Fade the unified zBar buttons in when the bar becomes active.",
tooltipKey = "ANIM_UI_ZBAR_TIP" },
{ key = "ui.stable", section = "ui", default = true,
label = "Flash stable slots on change", labelKey = "ANIM_UI_STABLE",
tooltip = "Flash a stable slot in the Hunter's Book when a pet is deposited or withdrawn.",
tooltipKey = "ANIM_UI_STABLE_TIP" },
{ key = "ui.mappins", section = "ui", default = true, { key = "ui.mappins", section = "ui", default = true,
label = "Fade map markers in", labelKey = "ANIM_UI_MAPPINS", label = "Fade map markers in", labelKey = "ANIM_UI_MAPPINS",
tooltip = "Fade the world map markers in when you locate a beast, vendor or master.", tooltip = "Fade the world map markers in when you locate a beast, vendor or master.",
@@ -166,6 +219,63 @@ else
end end
MTH_FX_DBG.step = "3-after-registertype" MTH_FX_DBG.step = "3-after-registertype"
-- Register a decaying "shake" tween type: oscillates the frame around its own
-- current anchor point, with the amplitude fading to zero over the tween so it
-- always lands back exactly where it started. Used for negative events.
if Sauce and type(Sauce.RegisterType) == "function" and not Sauce.MTH_HasShake then
local ok, err = pcall(function()
Sauce.MTH_HasShake = true
Sauce:RegisterType("mth_shake", {
init = function(target)
local p, rel, rp, x, y = target:GetPoint(1)
return { p or "CENTER", rel, rp or p or "CENTER", x or 0, y or 0 }
end,
apply = function(target, from, to, t, tween)
local mag = tween.magnitude or 8
local freq = tween.freq or 34
local decay = 1 - t
local offset = math.sin(t * freq) * mag * decay
target:ClearAllPoints()
target:SetPoint(from[1], from[2], from[3], (from[4] or 0) + offset, from[5] or 0)
end,
})
end)
MTH_FX_DBG.shakeOk = ok
MTH_FX_DBG.shakeErr = err
end
-- Reusable flash: overlays a short additive colour glow on any frame/button and
-- fades it out. Safe on any frame that supports CreateTexture; silent no-op
-- otherwise. The overlay texture is cached on the frame for reuse.
function MTH_FX_Flash(frame, r, g, b, duration)
if not Sauce or not frame then
return
end
if type(frame.CreateTexture) ~= "function" then
return
end
local tex = frame.mthFxFlash
if not tex then
tex = frame:CreateTexture(nil, "OVERLAY")
tex:SetTexture("Interface\\Buttons\\CheckButtonHilight")
tex:SetBlendMode("ADD")
tex:SetAllPoints(frame)
frame.mthFxFlash = tex
end
tex:SetVertexColor(r or 1, g or 1, b or 1)
tex:SetAlpha(0)
tex:Show()
local dur = duration or 0.45
Sauce:Stop(tex)
Sauce:Sequence({
Sauce:FadeTo(tex, 0.85, dur * 0.35),
Sauce:FadeTo(tex, 0, dur * 0.65, "inQuad", {
onFinish = function() tex:Hide() end,
}),
})
end
local MTH_FX_NUM_SPARKS = 22 local MTH_FX_NUM_SPARKS = 22
local MTH_FX_Container local MTH_FX_Container
local MTH_FX_MsgFrame local MTH_FX_MsgFrame
@@ -240,6 +350,7 @@ function MTH_Celebrate(title, subtitle)
return return
end end
MTH_FX_TitleFS:SetTextColor(1, 0.82, 0)
MTH_FX_TitleFS:SetText(title or "") MTH_FX_TitleFS:SetText(title or "")
MTH_FX_SubFS:SetText(subtitle or "") MTH_FX_SubFS:SetText(subtitle or "")
@@ -305,6 +416,39 @@ function MTH_CelebratePetAbility(label)
MTH_Celebrate(MTH_FX_L("ANIM_PET_LEARNED_TITLE", "New Pet Ability!"), label) MTH_Celebrate(MTH_FX_L("ANIM_PET_LEARNED_TITLE", "New Pet Ability!"), label)
end end
-- Dramatic negative banner: a red, shaking message shown when a pet runs away
-- for good. Gated on pet.runaway. Reuses the shared message frame.
function MTH_CelebrateRunaway(petName)
if not MTH_FX_IsEnabled("pet.runaway") then
return
end
if not Sauce then
return
end
if not MTH_FX_EnsureFrames() then
return
end
MTH_FX_TitleFS:SetTextColor(1, 0.15, 0.15)
MTH_FX_TitleFS:SetText(MTH_FX_L("ANIM_PET_RUNAWAY_TITLE", "Your pet ran away!"))
MTH_FX_SubFS:SetText(petName or "")
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 = 1.6 }),
})
end
-- DEBUG: mark that the whole file finished loading and record which globals it -- DEBUG: mark that the whole file finished loading and record which globals it
-- successfully defined. TEMP diagnostic. -- successfully defined. TEMP diagnostic.
MTH_FX_DBG.step = "4-complete" MTH_FX_DBG.step = "4-complete"
+14
View File
@@ -6,6 +6,18 @@
-- Uses MTH_DS_BeastSkins[familyName] generated by .tools/generators/gen_beast_skins.py -- Uses MTH_DS_BeastSkins[familyName] generated by .tools/generators/gen_beast_skins.py
-- Skin rendering: PlayerModel:SetUnit(CreatureDisplayInfo.ID) -- Skin rendering: PlayerModel:SetUnit(CreatureDisplayInfo.ID)
local MTH_MV_Sauce = PizzaSauce
-- Fade a model frame in when a new skin is displayed, unless disabled.
local function MTH_MV_AnimateModel(model)
if not MTH_MV_Sauce or not model then return end
if type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("book.model") then return end
if type(model.SetAlpha) ~= "function" then return end
if not model:IsShown() then return end
model:SetAlpha(0)
MTH_MV_Sauce:FadeTo(model, 1, 0.30, "outQuad")
end
local MTH_MV = { local MTH_MV = {
inited = false, inited = false,
family = nil, family = nil,
@@ -51,6 +63,8 @@ local function MTH_MV_DisplayCurrent()
MTH_MV_ApplyModel(MTH_MV.previewModel, skin.id) MTH_MV_ApplyModel(MTH_MV.previewModel, skin.id)
MTH_MV_ApplyModel(MTH_MV.popupModel, skin.id) MTH_MV_ApplyModel(MTH_MV.popupModel, skin.id)
MTH_MV_AnimateModel(MTH_MV.previewModel)
MTH_MV_AnimateModel(MTH_MV.popupModel)
local indexStr = tostring(MTH_MV.index) .. " / " .. tostring(n) local indexStr = tostring(MTH_MV.index) .. " / " .. tostring(n)
if MTH_MV.popupSkinLabel then if MTH_MV.popupSkinLabel then
+11
View File
@@ -1245,6 +1245,17 @@ function MTH_BOOKTAB_RenderStableCards()
local row = slotEntry and slotEntry.row or nil local row = slotEntry and slotEntry.row or nil
MTH_BOOK_DebugTrace("Render card#" .. tostring(i) .. " petId=" .. tostring(petId) .. " hasRow=" .. tostring(type(row) == "table")) MTH_BOOK_DebugTrace("Render card#" .. tostring(i) .. " petId=" .. tostring(petId) .. " hasRow=" .. tostring(type(row) == "table"))
-- Animations: flash the slot when its occupant changes (deposit /
-- withdraw / swap), but never on the first render of this card.
if card._stableInit and card._lastStablePetId ~= petId then
if type(MTH_FX_Flash) == "function" and type(MTH_FX_IsEnabled) == "function"
and MTH_FX_IsEnabled("ui.stable") then
MTH_FX_Flash(card, 1.00, 0.82, 0.20, 0.55)
end
end
card._lastStablePetId = petId
card._stableInit = true
card:ClearAllPoints() card:ClearAllPoints()
card:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 8, y) card:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 8, y)
card:SetPoint("TOPRIGHT", ui.frame, "TOPRIGHT", -8, y) card:SetPoint("TOPRIGHT", ui.frame, "TOPRIGHT", -8, y)
+31 -2
View File
@@ -29,6 +29,34 @@ local function MTH_BOOK_AnimateTabSwitch()
Sauce:FadeIn(list, 0.25) Sauce:FadeIn(list, 0.25)
end end
-- Fade the book window out before hiding it, unless disabled (shares the
-- "fade windows closed" toggle with the options window).
local function MTH_BOOK_FadeOutWindow(frame)
if not frame then return end
if not Sauce
or (type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("ui.optionsclose")) then
if type(frame.SetAlpha) == "function" then frame:SetAlpha(1) end
frame:Hide()
return
end
Sauce:FadeOut(frame, 0.22, "inQuad", {
onFinish = function()
frame:Hide()
if type(frame.SetAlpha) == "function" then frame:SetAlpha(1) end
end,
})
end
-- Fade the results list back in after a search/filter is applied, unless disabled.
local function MTH_BOOK_AnimateSearchResults()
if not Sauce then return end
if type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("book.search") then return end
local list = getglobal("MTH_BOOK_ListBackdrop")
if not list then return end
if type(list.SetAlpha) == "function" then list:SetAlpha(0) end
Sauce:FadeIn(list, 0.22)
end
MTH_HUNTERBOOK_LOADED = true MTH_HUNTERBOOK_LOADED = true
MTH_HUNTERBOOK_TABS = MTH_HUNTERBOOK_TABS or {} MTH_HUNTERBOOK_TABS = MTH_HUNTERBOOK_TABS or {}
@@ -4719,6 +4747,7 @@ local function MTH_BOOK_ApplyInputs()
MTH_BOOK_STATE.selectedPetRankEntry = nil MTH_BOOK_STATE.selectedPetRankEntry = nil
MTH_BOOK_STATE.petRankRows = {} MTH_BOOK_STATE.petRankRows = {}
MTH_BOOK_RefreshFilter() MTH_BOOK_RefreshFilter()
MTH_BOOK_AnimateSearchResults()
end end
local function MTH_BOOK_SetQuickFilter(index) local function MTH_BOOK_SetQuickFilter(index)
@@ -5301,7 +5330,7 @@ local function MTH_BOOK_WireUI(frame)
closeButton:SetWidth(22) closeButton:SetWidth(22)
closeButton:SetHeight(22) closeButton:SetHeight(22)
closeButton:SetText("X") closeButton:SetText("X")
closeButton:SetScript("OnClick", function() this:GetParent():Hide() end) closeButton:SetScript("OnClick", function() MTH_BOOK_FadeOutWindow(this:GetParent()) end)
end end
if applyButton then applyButton:SetScript("OnClick", MTH_BOOK_ApplyInputs) end if applyButton then applyButton:SetScript("OnClick", MTH_BOOK_ApplyInputs) end
@@ -5752,7 +5781,7 @@ function MTH_ToggleHunterBook()
local frame = MTH_BOOK_EnsureWindow() local frame = MTH_BOOK_EnsureWindow()
if not frame then return end if not frame then return end
if frame:IsShown() then if frame:IsShown() then
frame:Hide() MTH_BOOK_FadeOutWindow(frame)
else else
frame:Show() frame:Show()
MTH_BOOK_FadeInWindow(frame) MTH_BOOK_FadeInWindow(frame)
+19
View File
@@ -38,6 +38,15 @@ local function MTH_Map_AnimatePin(pin)
MTH_MAP_Sauce:FadeIn(pin, 0.3) MTH_MAP_Sauce:FadeIn(pin, 0.3)
end end
-- Ping a minimap pin that just came into range. Only called for genuinely new
-- nodes (see UpdateMinimap), never every tick, to avoid strobing.
local function MTH_Map_PingMinimapPin(pin)
if not MTH_MAP_Sauce or not pin then return end
if type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("ui.minimapping") then return end
if type(pin.SetAlpha) == "function" then pin:SetAlpha(0) end
MTH_MAP_Sauce:FadeIn(pin, 0.35)
end
local MTH_MAP_MINIMAP_ZOOM = { local MTH_MAP_MINIMAP_ZOOM = {
[0] = { [0] = 300, [1] = 240, [2] = 180, [3] = 120, [4] = 80, [5] = 50 }, [0] = { [0] = 300, [1] = 240, [2] = 180, [3] = 120, [4] = 80, [5] = 50 },
[1] = { [0] = 466 + 2/3, [1] = 400, [2] = 333 + 1/3, [3] = 266 + 2/6, [4] = 200, [5] = 133 + 1/3 }, [1] = { [0] = 466 + 2/3, [1] = 400, [2] = 333 + 1/3, [3] = 266 + 2/6, [4] = 200, [5] = 133 + 1/3 },
@@ -948,6 +957,7 @@ function MTH_Map:HideMinimapPins()
for i = 1, table.getn(self.minimapPins) do for i = 1, table.getn(self.minimapPins) do
if self.minimapPins[i] then self.minimapPins[i]:Hide() end if self.minimapPins[i] then self.minimapPins[i]:Hide() end
end end
self._miniShownSet = nil
end end
function MTH_Map:HideAllPins() function MTH_Map:HideAllPins()
@@ -1161,6 +1171,8 @@ function MTH_Map:UpdateMinimap()
local xDraw = Minimap:GetWidth() / xScale / 100 local xDraw = Minimap:GetWidth() / xScale / 100
local yDraw = Minimap:GetHeight() / yScale / 100 local yDraw = Minimap:GetHeight() / yScale / 100
local shown = 0 local shown = 0
local prevShown = self._miniShownSet or {}
local nowShown = {}
for i = 1, table.getn(nodes) do for i = 1, table.getn(nodes) do
local node = nodes[i] local node = nodes[i]
@@ -1182,9 +1194,16 @@ function MTH_Map:UpdateMinimap()
pin:ClearAllPoints() pin:ClearAllPoints()
pin:SetPoint("CENTER", Minimap, "CENTER", xPos, -yPos) pin:SetPoint("CENTER", Minimap, "CENTER", xPos, -yPos)
pin:Show() pin:Show()
local nodeKey = tostring(node.name or "") .. "@" .. tostring(node.x) .. "," .. tostring(node.y)
nowShown[nodeKey] = true
if not prevShown[nodeKey] then
MTH_Map_PingMinimapPin(pin)
end
end end
end end
end end
self._miniShownSet = nowShown
for i = shown + 1, table.getn(self.minimapPins) do for i = shown + 1, table.getn(self.minimapPins) do
if self.minimapPins[i] then self.minimapPins[i]:Hide() end if self.minimapPins[i] then self.minimapPins[i]:Hide() end
+19 -7
View File
@@ -120,25 +120,37 @@ function MTH_SetupAnimationsOptions()
end) end)
end end
-- Per-animation checkboxes, grouped by section. -- Per-animation checkboxes, grouped by section, laid out in two columns.
local y = -104 -- Each whole section is placed into whichever column is currently shorter
-- (largest remaining Y), so the two columns stay balanced as defs grow.
local rowStep = 26 local rowStep = 26
local sectionGap = 12 local sectionGap = 12
local columns = {
{ headerX = 15, cbX = 28, y = -104 },
{ headerX = 300, cbX = 313, y = -104 },
}
local s = 1 local s = 1
while MTH_FX_ANIM_SECTIONS and s <= table.getn(MTH_FX_ANIM_SECTIONS) do while MTH_FX_ANIM_SECTIONS and s <= table.getn(MTH_FX_ANIM_SECTIONS) do
local sec = MTH_FX_ANIM_SECTIONS[s] local sec = MTH_FX_ANIM_SECTIONS[s]
-- Pick the shorter column (the one whose cursor is nearest the top).
local col = columns[1]
if columns[2].y > columns[1].y then
col = columns[2]
end
local header = container:CreateFontString(nil, "ARTWORK", "GameFontNormal") local header = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
header:SetPoint("TOPLEFT", container, "TOPLEFT", 15, y) header:SetPoint("TOPLEFT", container, "TOPLEFT", col.headerX, col.y)
header:SetText(MTH_ANIM_L(sec.titleKey, sec.title)) header:SetText(MTH_ANIM_L(sec.titleKey, sec.title))
header:SetTextColor(1.00, 0.82, 0.00) header:SetTextColor(1.00, 0.82, 0.00)
y = y - 22 col.y = col.y - 22
local d = 1 local d = 1
while MTH_FX_ANIM_DEFS and d <= table.getn(MTH_FX_ANIM_DEFS) do while MTH_FX_ANIM_DEFS and d <= table.getn(MTH_FX_ANIM_DEFS) do
local def = MTH_FX_ANIM_DEFS[d] local def = MTH_FX_ANIM_DEFS[d]
if def.section == sec.id then if def.section == sec.id then
local cbName = "MetaHuntOptionsAnim_" .. string.gsub(def.key, "%.", "_") local cbName = "MetaHuntOptionsAnim_" .. string.gsub(def.key, "%.", "_")
local cb = MTH_CreateCheckbox(container, cbName, MTH_ANIM_L(def.labelKey, def.label), y, 28) local cb = MTH_CreateCheckbox(container, cbName, MTH_ANIM_L(def.labelKey, def.label), col.y, col.cbX)
if cb then if cb then
cb.mthKey = def.key cb.mthKey = def.key
cb:SetChecked(MTH_FX_GetFlag(def.key)) cb:SetChecked(MTH_FX_GetFlag(def.key))
@@ -155,12 +167,12 @@ function MTH_SetupAnimationsOptions()
cb:SetScript("OnLeave", function() GameTooltip:Hide() end) cb:SetScript("OnLeave", function() GameTooltip:Hide() end)
end end
table.insert(MTH_ANIM_CTRL, cb) table.insert(MTH_ANIM_CTRL, cb)
y = y - rowStep col.y = col.y - rowStep
end end
end end
d = d + 1 d = d + 1
end end
y = y - sectionGap col.y = col.y - sectionGap
s = s + 1 s = s + 1
end end
+19 -1
View File
@@ -47,6 +47,24 @@ local function MTH_OPT_AnimateTabContent(tabKey)
end end
end end
-- Fade the options window out before hiding it, unless disabled.
local function MTH_OPT_AnimateClose()
local frame = MetaHuntOptions
if not frame then return end
if not MTH_OPT_Sauce
or (type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("ui.optionsclose")) then
frame:SetAlpha(1)
frame:Hide()
return
end
MTH_OPT_Sauce:FadeOut(frame, 0.22, "inQuad", {
onFinish = function()
frame:Hide()
frame:SetAlpha(1)
end,
})
end
local function MTH_RegisterEscClose(frameName) local function MTH_RegisterEscClose(frameName)
if not (frameName and UISpecialFrames) then if not (frameName and UISpecialFrames) then
return return
@@ -103,7 +121,7 @@ local function MTH_EnsureOptionsFrame()
closeBtn:SetWidth(MTH_OPTIONS_CONST.CLOSE_BTN_SIZE) closeBtn:SetWidth(MTH_OPTIONS_CONST.CLOSE_BTN_SIZE)
closeBtn:SetHeight(MTH_OPTIONS_CONST.CLOSE_BTN_SIZE) closeBtn:SetHeight(MTH_OPTIONS_CONST.CLOSE_BTN_SIZE)
closeBtn:SetText(MTH_OPT_L("COMMON_CLOSE_SHORT", "X")) closeBtn:SetText(MTH_OPT_L("COMMON_CLOSE_SHORT", "X"))
closeBtn:SetScript("OnClick", function() MetaHuntOptions:Hide() end) closeBtn:SetScript("OnClick", function() MTH_OPT_AnimateClose() end)
end end
MTH_BuildOptionsTree() MTH_BuildOptionsTree()
+9
View File
@@ -403,6 +403,7 @@ local lnl = {
expiresAt = 0, expiresAt = 0,
DURATION = 10, -- Lock and Load real duration (tooltip: "Lasts 10 sec or until Aimed Shot is cast") DURATION = 10, -- Lock and Load real duration (tooltip: "Lasts 10 sec or until Aimed Shot is cast")
} }
local MTH_EA_LnLWasActive = false -- for detecting the proc rising edge (animations)
-- ── Confirmed icon paths (captured in-game 2026-03-21) ──────── -- ── Confirmed icon paths (captured in-game 2026-03-21) ────────
-- Action-button spells (spellbook scan) -- Action-button spells (spellbook scan)
@@ -700,10 +701,18 @@ MTH_EA_UpdateUI = function()
cellTop.icon:SetVertexColor(1.00, 0.82, 0.00, 1) cellTop.icon:SetVertexColor(1.00, 0.82, 0.00, 1)
cellTop:SetBackdropBorderColor(1.00, 0.82, 0.00, 1) cellTop:SetBackdropBorderColor(1.00, 0.82, 0.00, 1)
cellTopCD:SetText("|cffffffff" .. secs .. "|r") cellTopCD:SetText("|cffffffff" .. secs .. "|r")
if not MTH_EA_LnLWasActive then
if type(MTH_FX_Flash) == "function" and type(MTH_FX_IsEnabled) == "function"
and MTH_FX_IsEnabled("combat.mmprocs") then
MTH_FX_Flash(cellTop, 1.00, 0.82, 0.20, 0.55)
end
MTH_EA_LnLWasActive = true
end
else else
cellTop.icon:SetVertexColor(0.28, 0.28, 0.28, 0.40) cellTop.icon:SetVertexColor(0.28, 0.28, 0.28, 0.40)
cellTop:SetBackdropBorderColor(0.25, 0.25, 0.25, 0.35) cellTop:SetBackdropBorderColor(0.25, 0.25, 0.25, 0.35)
cellTopCD:SetText("") cellTopCD:SetText("")
MTH_EA_LnLWasActive = false
end end
end end
+15
View File
@@ -221,6 +221,14 @@ local function MTHSmartAmmo_ShowFallbackWarning(previousAmmo, newAmmo)
elseif UIErrorsFrame and UIErrorsFrame.AddMessage then elseif UIErrorsFrame and UIErrorsFrame.AddMessage then
UIErrorsFrame:AddMessage(warning, 1.0, 0.15, 0.15, 1.0) UIErrorsFrame:AddMessage(warning, 1.0, 0.15, 0.15, 1.0)
end end
if type(MTH_FX_Flash) == "function" and type(MTH_FX_IsEnabled) == "function"
and MTH_FX_IsEnabled("combat.ammoswap") then
local target = getglobal("zButtonAmmo")
if target then
MTH_FX_Flash(target, 1.00, 0.75, 0.20, 0.5)
end
end
end end
local MTHSmartAmmo_FallbackCheckFrame = nil local MTHSmartAmmo_FallbackCheckFrame = nil
@@ -371,6 +379,13 @@ local function MTHSmartAmmo_HandleWeaponSwapAutoEquip(reason)
if MTHSmartAmmo_EquipAmmoFromSlot(bestAmmo.bag, bestAmmo.slot) then if MTHSmartAmmo_EquipAmmoFromSlot(bestAmmo.bag, bestAmmo.slot) then
MTH_SA_LastKnownEquippedName = bestAmmo.name MTH_SA_LastKnownEquippedName = bestAmmo.name
MTHSmartAmmo_RefreshAmmoButtonDisplay() MTHSmartAmmo_RefreshAmmoButtonDisplay()
if type(MTH_FX_Flash) == "function" and type(MTH_FX_IsEnabled) == "function"
and MTH_FX_IsEnabled("combat.rangedswap") then
local target = getglobal("zButtonAmmo")
if target then
MTH_FX_Flash(target, 0.30, 0.70, 1.00, 0.5)
end
end
end end
end end
+23
View File
@@ -5,6 +5,8 @@
local ZBAR_FRAME_NAME = "MTH_ZBar_Anchor" local ZBAR_FRAME_NAME = "MTH_ZBar_Anchor"
local ZBar_Sauce = PizzaSauce
local ZBAR_ALL_BUTTONS = { local ZBAR_ALL_BUTTONS = {
"zButtonAspect", "zButtonAspect",
"zButtonAmmo", "zButtonAmmo",
@@ -282,6 +284,26 @@ function MTH_ZBar_Release()
end end
end end
-- Animations: gentle staggered fade-in of the bar's buttons when it activates.
function MTH_ZBar_AnimateActivate()
if not ZBar_Sauce then return end
if type(MTH_FX_IsEnabled) ~= "function" or not MTH_FX_IsEnabled("ui.zbar") then
return
end
local s = MTH_ZBar_GetSaved()
local order = s.order or {}
for i = 1, table.getn(order) do
local buttonName = order[i]
if type(buttonName) == "string" then
local btn = getglobal(buttonName)
if btn and btn:IsShown() then
btn:SetAlpha(0)
ZBar_Sauce:FadeTo(btn, 1, 0.30, "outQuad", { delay = (i - 1) * 0.05 })
end
end
end
end
-- Called when the user toggles the Enable checkbox in the options. -- Called when the user toggles the Enable checkbox in the options.
function MTH_ZBar_SetEnabled(enabled) function MTH_ZBar_SetEnabled(enabled)
local s = MTH_ZBar_GetSaved() local s = MTH_ZBar_GetSaved()
@@ -289,6 +311,7 @@ function MTH_ZBar_SetEnabled(enabled)
if enabled then if enabled then
MTH_ZBar_EnsureAnchor() MTH_ZBar_EnsureAnchor()
MTH_ZBar_ApplyLayout() MTH_ZBar_ApplyLayout()
MTH_ZBar_AnimateActivate()
else else
MTH_ZBar_Release() MTH_ZBar_Release()
end end
+28
View File
@@ -312,6 +312,8 @@ local function zButtonPet_GetCorePetInfo()
return nil return nil
end end
local zButtonPet_LastLoyalty = nil
local function zButtonPet_RefreshSavedPetState(saved, corePetInfo) local function zButtonPet_RefreshSavedPetState(saved, corePetInfo)
local hasLivePet = false local hasLivePet = false
if type(UnitExists) == "function" then if type(UnitExists) == "function" then
@@ -343,8 +345,34 @@ local function zButtonPet_RefreshSavedPetState(saved, corePetInfo)
if happiness == nil and type(GetPetHappiness) == "function" then if happiness == nil and type(GetPetHappiness) == "function" then
happiness = GetPetHappiness() happiness = GetPetHappiness()
end end
local prevHappiness = saved["pet"]["happiness"]
saved["pet"]["happiness"] = happiness saved["pet"]["happiness"] = happiness
-- Animations: flash the pet button when happiness or loyalty changes.
if type(MTH_FX_Flash) == "function" and type(MTH_FX_IsEnabled) == "function" then
if MTH_FX_IsEnabled("pet.happiness")
and prevHappiness ~= nil and happiness ~= nil and happiness ~= prevHappiness then
local target = getglobal("zButtonPet")
if target then
if happiness > prevHappiness then
MTH_FX_Flash(target, 0.30, 1.00, 0.35, 0.5)
else
MTH_FX_Flash(target, 1.00, 0.30, 0.30, 0.5)
end
end
end
local loyalty = corePetInfo and tonumber(corePetInfo.loyaltyLevel) or nil
if MTH_FX_IsEnabled("pet.loyaltyup") and loyalty ~= nil then
if zButtonPet_LastLoyalty ~= nil and loyalty > zButtonPet_LastLoyalty then
local target = getglobal("zButtonPet")
if target then
MTH_FX_Flash(target, 1.00, 0.82, 0.20, 0.6)
end
end
zButtonPet_LastLoyalty = loyalty
end
end
if isDead then if isDead then
saved["pet"]["status"] = 1 saved["pet"]["status"] = 1
elseif currentHealth and currentHealthMax and currentHealthMax > 0 then elseif currentHealth and currentHealthMax and currentHealthMax > 0 then