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
+7
View File
@@ -1385,6 +1385,13 @@ function MTH_FEED_FinalizeAttempt(attemptId, payload)
if petKey ~= "" then
MTH_FEED_Runtime.sessionFeedsByPetId[petKey] = (tonumber(MTH_FEED_Runtime.sessionFeedsByPetId[petKey]) or 0) + 1
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
petRow.totals.rejected = petRow.totals.rejected + 1
if reason == "no-buff" then
+3
View File
@@ -2791,6 +2791,9 @@ function MTH_PETS_RecordPetRunaway(source, rawMessage)
if MTH:IsMessageEnabled("petRanAway", true) then
MTH:Print("YOUR PET " .. tostring(displayName) .. " HAS RUNAWAY FOREVER :-( Try to feed it better next time.")
end
if type(MTH_CelebrateRunaway) == "function" then
MTH_CelebrateRunaway(displayName)
end
end
return true
+144
View File
@@ -33,6 +33,7 @@ MTH_FX_DBG = {
-- Sections shown, in order, in the options panel. `titleKey` localizes `title`.
MTH_FX_ANIM_SECTIONS = {
{ 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 = "ui", title = "Interface", titleKey = "ANIM_SECTION_UI" },
}
@@ -46,6 +47,34 @@ MTH_FX_ANIM_DEFS = {
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.",
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,
label = "Fade in the Hunter's Book", labelKey = "ANIM_BOOK_OPEN",
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",
tooltip = "Fade the results list back in when you switch tabs inside the Hunter's Book.",
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,
label = "Slide the options window open", labelKey = "ANIM_UI_OPTIONS",
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",
tooltip = "Fade the settings panel when you switch tabs inside the options window.",
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,
label = "Pulse the minimap button on click", labelKey = "ANIM_UI_MINIMAP",
tooltip = "Give the minimap button a quick pulse when you click it.",
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,
label = "Fade zButton bars open", labelKey = "ANIM_UI_ZBUTTONS",
tooltip = "Fade the child buttons in when a collapsible zButton bar (pet, tracking, aspects...) expands.",
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,
label = "Fade map markers in", labelKey = "ANIM_UI_MAPPINS",
tooltip = "Fade the world map markers in when you locate a beast, vendor or master.",
@@ -166,6 +219,63 @@ else
end
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_Container
local MTH_FX_MsgFrame
@@ -240,6 +350,7 @@ function MTH_Celebrate(title, subtitle)
return
end
MTH_FX_TitleFS:SetTextColor(1, 0.82, 0)
MTH_FX_TitleFS:SetText(title 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)
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
-- successfully defined. TEMP diagnostic.
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
-- 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 = {
inited = false,
family = nil,
@@ -51,6 +63,8 @@ local function MTH_MV_DisplayCurrent()
MTH_MV_ApplyModel(MTH_MV.previewModel, 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)
if MTH_MV.popupSkinLabel then
+11
View File
@@ -1245,6 +1245,17 @@ function MTH_BOOKTAB_RenderStableCards()
local row = slotEntry and slotEntry.row or nil
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:SetPoint("TOPLEFT", ui.frame, "TOPLEFT", 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)
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_TABS = MTH_HUNTERBOOK_TABS or {}
@@ -4719,6 +4747,7 @@ local function MTH_BOOK_ApplyInputs()
MTH_BOOK_STATE.selectedPetRankEntry = nil
MTH_BOOK_STATE.petRankRows = {}
MTH_BOOK_RefreshFilter()
MTH_BOOK_AnimateSearchResults()
end
local function MTH_BOOK_SetQuickFilter(index)
@@ -5301,7 +5330,7 @@ local function MTH_BOOK_WireUI(frame)
closeButton:SetWidth(22)
closeButton:SetHeight(22)
closeButton:SetText("X")
closeButton:SetScript("OnClick", function() this:GetParent():Hide() end)
closeButton:SetScript("OnClick", function() MTH_BOOK_FadeOutWindow(this:GetParent()) end)
end
if applyButton then applyButton:SetScript("OnClick", MTH_BOOK_ApplyInputs) end
@@ -5752,7 +5781,7 @@ function MTH_ToggleHunterBook()
local frame = MTH_BOOK_EnsureWindow()
if not frame then return end
if frame:IsShown() then
frame:Hide()
MTH_BOOK_FadeOutWindow(frame)
else
frame:Show()
MTH_BOOK_FadeInWindow(frame)
+19
View File
@@ -38,6 +38,15 @@ local function MTH_Map_AnimatePin(pin)
MTH_MAP_Sauce:FadeIn(pin, 0.3)
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 = {
[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 },
@@ -948,6 +957,7 @@ function MTH_Map:HideMinimapPins()
for i = 1, table.getn(self.minimapPins) do
if self.minimapPins[i] then self.minimapPins[i]:Hide() end
end
self._miniShownSet = nil
end
function MTH_Map:HideAllPins()
@@ -1161,6 +1171,8 @@ function MTH_Map:UpdateMinimap()
local xDraw = Minimap:GetWidth() / xScale / 100
local yDraw = Minimap:GetHeight() / yScale / 100
local shown = 0
local prevShown = self._miniShownSet or {}
local nowShown = {}
for i = 1, table.getn(nodes) do
local node = nodes[i]
@@ -1182,9 +1194,16 @@ function MTH_Map:UpdateMinimap()
pin:ClearAllPoints()
pin:SetPoint("CENTER", Minimap, "CENTER", xPos, -yPos)
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
self._miniShownSet = nowShown
for i = shown + 1, table.getn(self.minimapPins) do
if self.minimapPins[i] then self.minimapPins[i]:Hide() end
+19 -7
View File
@@ -120,25 +120,37 @@ function MTH_SetupAnimationsOptions()
end)
end
-- Per-animation checkboxes, grouped by section.
local y = -104
-- Per-animation checkboxes, grouped by section, laid out in two columns.
-- 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 sectionGap = 12
local columns = {
{ headerX = 15, cbX = 28, y = -104 },
{ headerX = 300, cbX = 313, y = -104 },
}
local s = 1
while MTH_FX_ANIM_SECTIONS and s <= table.getn(MTH_FX_ANIM_SECTIONS) do
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")
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:SetTextColor(1.00, 0.82, 0.00)
y = y - 22
col.y = col.y - 22
local d = 1
while MTH_FX_ANIM_DEFS and d <= table.getn(MTH_FX_ANIM_DEFS) do
local def = MTH_FX_ANIM_DEFS[d]
if def.section == sec.id then
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
cb.mthKey = def.key
cb:SetChecked(MTH_FX_GetFlag(def.key))
@@ -155,12 +167,12 @@ function MTH_SetupAnimationsOptions()
cb:SetScript("OnLeave", function() GameTooltip:Hide() end)
end
table.insert(MTH_ANIM_CTRL, cb)
y = y - rowStep
col.y = col.y - rowStep
end
end
d = d + 1
end
y = y - sectionGap
col.y = col.y - sectionGap
s = s + 1
end
+19 -1
View File
@@ -47,6 +47,24 @@ local function MTH_OPT_AnimateTabContent(tabKey)
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)
if not (frameName and UISpecialFrames) then
return
@@ -103,7 +121,7 @@ local function MTH_EnsureOptionsFrame()
closeBtn:SetWidth(MTH_OPTIONS_CONST.CLOSE_BTN_SIZE)
closeBtn:SetHeight(MTH_OPTIONS_CONST.CLOSE_BTN_SIZE)
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
MTH_BuildOptionsTree()