Add Animations feature + fix own-pet tooltip false positive

Animations (all optional, default on, per-effect toggles):
- New Options -> Animations tab with master switch + per-effect checkboxes
- Embed PizzaSauce animation library (api/PizzaSauce.lua)
- fx-celebrate: firework + banner when a pet learns a new ability/rank,
  triggered from core-scan-beasttraining pet-learn hook
- Hunter's Book: slide + fade on open, results list fade on tab switch
- Options window: slide + fade on open
- All new user-facing strings keyed (ANIM_* namespace)

Fixes:
- Tooltip #19: own-pet lines (mood/loyalty/happiness/XP) no longer
  misfire on party members / targets. Removed the fragile title-name
  fallback in MTH_TT_IsTooltipOnOwnPet; ownership now requires positive
  unit identity.

Temp (remove before release): /mth fx and /mth fxdebug diagnostics.
This commit is contained in:
DuvelCorp
2026-09-10 14:41:26 +02:00
parent 060fc555fe
commit 566f3f4925
12 changed files with 1992 additions and 43 deletions
+19 -18
View File
@@ -5,25 +5,31 @@ All notable changes to MetaHunt will be documented in this file.
## [2.0.0] - Unreleased
### Changed
- **Settings storage tidied into one clean layout**: The settings MetaHunt inherited from the older stand-alone addons it now replaces (Feed-O-Matic, ZHunter/zButtons, SmartAmmo, and the quest/anti-daze/auto-strip/minimap helpers) used to be scattered across many separate saved entries, several of them duplicated on disk. MetaHunt now keeps everything in one organised place, grouped per module. The clean-up runs automatically and once, the first time you log in after updating: all of your existing settings and layouts are carried over unchanged — nothing is reset — and the old duplicate copies are removed so your saved-variables file stays small and consistent.
### Fixed
- **Pets — duplicate and phantom entries in your pet collection**: MetaHunt could record the same tamed pet more than once — a fresh copy appeared after you logged out and back in, or after your pet leveled up — and a few very early pets you had long since dismissed lingered as though they were still with you. MetaHunt now recognises each pet reliably from one session to the next (and as it levels), automatically merges the duplicate entries it had already created while keeping the correct taming details (where, and at what level, you tamed each one), and tidies the leftover phantom pets away into your pet history. Your full taming history is preserved — nothing is deleted.
## [1.5.2] - 2026-09-08
Res on Octowow server.
Resurrecting on Octowow.
### 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, and the options window slides in when opened. 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.
- **DDOSers Realm Blocking**: The Addon will auto-disable itself on all Mafia's realms, we know who they are.
### Changed
- **Complete revamp of SavedVariables**: All your settings now live in one tidy place instead of being scattered around. A migration happens the first time you log in, and you shouldn't lose any settings.
### Fixed
- **Tooltips — your pet's info showing on other players**: In a party, mousing over or targeting another player could wrongly show YOUR pet's details (mood, loyalty, happiness, XP) on their tooltip. The own-pet detection no longer misfires on other units.
- **zCraft — Smelting**: Smelting was previously not appearing in zCraft because incorrectly hardcoded as "Mining", this is fixed.
- **Wrong icons on pet spells**: Fixed the Rank 0 of Bubble Barrier and Charge that had incorrect icons.
- **Fixed tracking data in Book's Stables**: Fixed an issue with pets' GUID returned by the server, that was not really unique and caused issues with pets' tracking, notably when you had several pets with the same name. Taming info was disapearing, amongst other weirdness. A migration is done on first load to fix your existing data.
- **FeedOMatic — "Set Key" button error**: Clicking **Set Key** in Options → Feed-o-Matic threw an error and wouldn't let you bind a feed key. It now works again.
- **FeedOMatic — pet left hungry when bags were full**: When your bags were full, FeedOMatic could grab a random tiny stack (like a single meat your pet won't eat) to free a bag slot, so your pet stayed hungry. It now always picks food your pet can actually eat.
@@ -32,13 +38,8 @@ Res on Octowow server.
- **Pet training — new rank of a known ability not registered**: When you trained a higher rank of an ability you already had (e.g. learning Charge Rank 2 after Rank 1), MetaHunt treated it as already known — so the "Pet ability learned and recorded" message never appeared and the pet-bar tooltip kept saying "Not learned yet" for the new rank. Learning a new rank is now recognised on its own, announces correctly, and the tooltip immediately reflects the rank you just learned.
- **Hunter's Book — missing "Unique Appearance" beasts**: The unique-appearance flag had gone missing from the beast database, so the "Unique" badge and filter in the Hunter's Book came up empty. Restored a curated list of the genuinely one-of-a-kind beasts a collector hunts for (Humar the Pridelord, Darksaber, Shar'lan, Frostsaber Pride Watcher, Mazzranache, Moonfeather, Azurebeak, Old Cliff Jumper, Rotting Agam'ar, Razzashi Serpent, Magmalash Scorpid, Spirit Fox and more), so the Unique badge and filter work again without wrongly flagging common colour-variant mobs.
- **Hunter's Book — fixed "Unique" beasts**: Restored a curated list of the one-of-a-kind beasts (Humar the Pridelord, Darksaber, Shar'lan, Frostsaber Pride Watcher, Mazzranache, Moonfeather, Azurebeak, Old Cliff Jumper, Rotting Agam'ar, Razzashi Serpent, Magmalash Scorpid, Spirit Fox and more).
- **ds-pet-spells — wrong rank 0 icons**: Rank 0 (triggered/sub-spell) entries for Bubble Barrier and Charge had incorrect icons (`Spell_Frost_FrostNova` and `Ability_Warrior_Charge` respectively) instead of matching their ranked ability icons (`spell_bubl1` and `Ability_Hunter_Pet_Boar`). Fixed in both `allSpells` and `byAbility` sections.
- **zCraft — Smelting**: Smelting was previously not appearing in zCraft because incorrectly hardcoded as "Mining", this is fixed.
- **Realm Blocking**: The Addon will auto-disable itself on all Mafia's realms.
## [1.5.1] - 2026-04-01
+34 -25
View File
@@ -1,37 +1,32 @@
# MetaHunt
MetaHunt is a Twow Hunter toolkit.
It is a modern modular addon compiling brand new features, and improving a few old hunter add-ons that were broken on twow.
It provides a bunch of useful tools for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
It is a modern modular addon compiling brand new features, and improving a few old hunter add-ons that were broken or disfunctional with twow.
It provides a bunch of useful functionalities for all huntards, wheter they are still levelling, lone-wolf, or HL raider.
You play the best class, now you have the best companion for it (and its not your pet).
### Important notes
- Altough Nampower isn't mandatory for most of the features, it is a must-have for some.
- If you were using old versions of Feed-O-Matic, ICU, zHunterMod and HunterHelper, you dont need those with MetaHunt and you should disable them to avoid conflicts.
- MetaHunt is fully compatible with QUIVER, and is not a replacement for it.
- MetaHunt don't and will never support Capycraft/Ravencraft (mafia) servers, after the DDOS attacks they conducted on other servers, to only name that. Fuck you.
- The addon purposely disable itself on all Capycraft/Ravencraft Realms, following the DDOS attacks they conducted on other servers.
## Twow Data
MetaHunt ships with large Twow datastores :
MetaHunt ships with large twow datastores, and notably:
- 100% accurate beasts' data, their locations, and the abilities they can learn you
- All Pet families, their abilities and their diet
- All pet abilities ranks
- All Ammo (Arrows and Bullets)
- All Stable, Hunter and Pet Masters
- All Ammo and ranged weapons
- All Hunter/Pet/Stable Masters
- All Ammo vendors
You can browse all the beasts in game within the Book of Huntards, but also on the github site : https://DuvelCorp.github.io/MetaHunt-Web/
Online bestiary is also available here https://DuvelCorp.github.io/MetaHunt-Web/
## The Great Book of Huntards
The Book is the main GUI of MetaHunt, it allows to display the data collected about you and your pet, and browse the addon's data to find anything a Hunter needs.
- Browse the MetaHunt datastores of NPCs (Beast, vendors, masters) and open the map to locate them like in pfQuest
- Track all info about the pet abilities that you know and don't know yet
- Track all info about your stabled pets
- Keep an history of all your pets after you abandon them or if they run away.
## Smart Ammo
@@ -40,7 +35,8 @@ You can browse all the beasts in game within the Book of Huntards, but also on t
- Auto equip the right ammo when you swap from a box/xbow to a gun and the other way around.
## MM Widget
Lets Make MM great again. Tracks the new 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock&Load procs, and has a dynamic cell that shows either Aimed Shot availability or the right shot to use following the current Experimental ammo proc if any. You can also bind it to turn it into a very efficient one-button rotation. No more excuse to not be amongst top DPS.
1.18.1 weapon of mass-destruction. The widget is composed of 5 cells, tracking the 3-state of Experimental ammo cycle (Fire → Nature → Arcane), the Lock & Load procs, and a smart dynamic cell. The smart cell shows either Aimed Shot availability or the right shot to use following the current Experimental ammo proc if any, and it bypasses the proc spell if your current target is immune to the school. You can bind the smart cell to turn the widget into a very efficient one-button rotation. Lets make MM great again !
## Tooltips
@@ -56,27 +52,27 @@ Old zHunterMod addon on steroids. Fully compatible with Twow, and enhanced with
- zAmmo : Track all your ammo Live and swap them in a click or bind
- zPet : Intelligent collapsible pet Bar regrouping all pet spells and providing a main button that always swap on the right spell to use depending on the situation
- zTrack: All your trackings in one collapsible bar
- zAspect: All your trackings in one collapsible bar
- zAspect: All your aspects in one collapsible bar
- zRanged : All the ranged weapons currently in your bags to swap them fast
- But also zCrafts, zMounts, zToys and zCompanions.
Additionally, a zBar can regroup all the zButtons above into a single bar for people that like clean and ordered stuff.
Additionally, a special _zBar_ can regroup all the zButtons above into a single bar for people that like clean and ordered stuff.
## Feed-O-Matic
Now compatible with Twow, feed your pet with one key bind, it will always pickup the best food for your pet.
Now compatible with Twow, feed your pet with one key bind, it will always pickup the best food for your pet, according to your preferences.
## Chronometer
The good old Chronometer addon, purged of non-necessary things and reconfigured for a pure hunter use.
The good old Chronometer addon, purged of non-necessary things and reconfigured for a pure hunter usage.
## ICU (I see you)
Old addon used to display Targets' enhanced information when you click on your minimap tracking things. MetaHunt offers many more customization options for it.
This old addon is mostly a PVP weapon used to display targets' enhanced information when you click on your minimap tracked things. MetaHunt offers many more customization options for it.
## Ammo labels
You can display on all ammo in your bags and/or bank their type and/or dps to instantly see which of those damn same arrows icons really are.
You can display some labels on all ammo in your bags/bank to instantly see which of those damn same arrows icons really are.
## Auto-Buy
@@ -86,10 +82,23 @@ Define your own simple rules for auto buy ammo and pet food when you open a vend
Just spam SHIFT-click on the NPC to validate quests Scorpok and Thorium arrows. Additionally you can have an enhanced tooltip that display your actual Scorpok-related items when you mouseover the Blasted Land mobs involved.
## Beast model Viewer
Display the model of all beasts in the world. Always know what you are going to tame exactly before running there ! You can also browse all skin models of the same pet family to find the best-looking pet according to your tastes.
## The Great Book of Huntards
The Book is the main GUI of MetaHunt, it allows to browse the addon's data to find anything a Hunter needs.
- Search Hunter-related NPCs (Beasts, vendors, masters) and open the map to locate them like in pfQuest.
- Beast model Viewer : Display the model of all beasts in the world. You can also browse all skin models of the same family to find the best-looking pet according to your tastes.
- Instantly find where the beasts having a specific ability are lying and plan ahead your tracking sessions.
- Get a full understanding of all Pet families.
- Display meaningfully the pet abilities that you know and don't know yet
- Get your stable's state everywhere and track all possible information about all your pets
- Keep a detailed history of all the pets you abandonned or those that ran away.
## Tune it the way you like
Metahunt option panel is huge. There are hundreds of settings you can configure in order to tweak it like a boss so it fits YOUR preferences.
Its modular architecture also allows you to completely disable any module in order to decrease the addon's memory footprint and background processes.
### Happy Hunting Fellas !
+1347
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -432,6 +432,9 @@ local function MTH_PT_ProcessLearnSystemMessage(rawMessage)
if changed then
MTH_PT_ApplyScan("learn-msg")
end
if changed and type(MTH_CelebratePetAbility) == "function" then
MTH_CelebratePetAbility(label)
end
if type(MTH_PSP_RequestScan) == "function" then
MTH_PSP_RequestScan("train-learn-msg")
end
+63
View File
@@ -325,6 +325,69 @@ function SlashCmdList.MTH(msg, editbox)
MTH_CommandBook()
elseif lowerMsg == "peers" or lowerMsg == "who" then
MTH_CommandPeers()
elseif lowerCmd == "trainscan" or lowerCmd == "petscan" then
if type(MTH_CommandTrainScan) == "function" then
MTH_CommandTrainScan()
else
MTH:Print("Train scan is not available.")
end
elseif lowerCmd == "fx" or lowerCmd == "fireworks" or lowerCmd == "celebrate" then
-- TEMP: preview the pet-ability celebration effect.
if type(MTH_Celebrate) == "function" then
local label = msg
local _, _, rest = string.find(msg, "^%S+%s+(.-)%s*$")
if rest and rest ~= "" then
MTH_Celebrate("New Pet Ability!", rest)
else
MTH_Celebrate("New Pet Ability!", "Growl (Rank 3)")
end
else
-- Self-diagnosing: report which piece failed to load so we can tell
-- a stale UI from a genuine load error.
MTH:Print("Celebration effect is not available. Diagnostics:")
MTH:Print(" PizzaSauce global: " .. type(PizzaSauce))
MTH:Print(" MTH_Celebrate: " .. type(MTH_Celebrate))
MTH:Print(" MTH_FX_IsEnabled: " .. type(MTH_FX_IsEnabled))
MTH:Print(" MTH_SetupAnimationsOptions: " .. type(MTH_SetupAnimationsOptions))
MTH:Print(" -> If these are 'nil', do /reload (your UI is running code from before the feature was added).")
end
elseif lowerCmd == "fxdebug" then
-- TEMP: dump the animation load-path tracers so we can see exactly where
-- fx-celebrate.lua / options-animations.lua aborted at load time.
MTH:Print("=== MetaHunt animation load debug ===")
MTH:Print("Globals: PizzaSauce=" .. type(PizzaSauce)
.. " CreateFrame=" .. type(CreateFrame)
.. " MTH=" .. type(MTH))
if type(MTH_FX_DBG) == "table" then
MTH:Print("fx-celebrate: step=" .. tostring(MTH_FX_DBG.step)
.. " sauceType=" .. tostring(MTH_FX_DBG.sauceType)
.. " registerOk=" .. tostring(MTH_FX_DBG.registerOk)
.. " registerSkipped=" .. tostring(MTH_FX_DBG.registerSkipped))
if MTH_FX_DBG.registerErr ~= nil then
MTH:Print("fx-celebrate: registerErr=" .. tostring(MTH_FX_DBG.registerErr))
end
MTH:Print("fx-celebrate: hasCelebrate=" .. tostring(MTH_FX_DBG.hasCelebrate)
.. " hasIsEnabled=" .. tostring(MTH_FX_DBG.hasIsEnabled)
.. " hasAnimEnabled=" .. tostring(MTH_FX_DBG.hasAnimEnabled))
else
MTH:Print("fx-celebrate: MTH_FX_DBG is " .. type(MTH_FX_DBG) .. " (file did not reach its first line)")
end
if type(MTH_ANIM_DBG) == "table" then
MTH:Print("options-animations: step=" .. tostring(MTH_ANIM_DBG.step)
.. " ready=" .. tostring(MTH_ANIM_DBG.ready)
.. " hasSetup=" .. tostring(MTH_ANIM_DBG.hasSetup))
MTH:Print("options-animations: req=" .. tostring(MTH_ANIM_DBG.reqType)
.. " getFrame=" .. tostring(MTH_ANIM_DBG.getFrameType)
.. " clear=" .. tostring(MTH_ANIM_DBG.clearType)
.. " checkbox=" .. tostring(MTH_ANIM_DBG.checkboxType))
MTH:Print("options-animations: setupCalled=" .. tostring(MTH_ANIM_DBG.setupCalled)
.. " setupResult=" .. tostring(MTH_ANIM_DBG.setupResult)
.. " containerType=" .. tostring(MTH_ANIM_DBG.containerType)
.. " fxEnabledType=" .. tostring(MTH_ANIM_DBG.fxEnabledType))
else
MTH:Print("options-animations: MTH_ANIM_DBG is " .. type(MTH_ANIM_DBG) .. " (file did not reach its first line)")
end
MTH:Print("=== end animation load debug ===")
elseif lowerMsg == "zoneinfo" then
-- Dumps all available zone data for the current zone, for adding to ds-zones / ds-minimap-sizes
pcall(SetMapToCurrentZone)
+297
View File
@@ -0,0 +1,297 @@
-- MetaHunt: center-screen celebration effect (message + firework burst).
-- Uses the embedded PizzaSauce animation library. Degrades to a silent no-op
-- when PizzaSauce or the WoW frame API are unavailable (e.g. offline tests).
-- Capture our own PizzaSauce instance now, before another addon that ships its
-- own copy can overwrite the global. This is the pattern the library requires.
local Sauce = PizzaSauce
-- Localization helper: resolve a key through MetaHunt's loc system, falling back
-- to the inline English default. Every user-facing string is keyed so the enUS
-- strings can be harvested later; the inline default is the working English.
local function MTH_FX_L(key, default)
if MTH and type(MTH.GetLocalization) == "function" then
return MTH:GetLocalization(key, default)
end
return default or key
end
-- ---------------------------------------------------------------------------
-- DEBUG: load-path tracer. Global so /mth fxdebug can dump it. Records how far
-- this file got at load time and any error from the one executable file-scope
-- block (RegisterType). TEMP diagnostic.
-- ---------------------------------------------------------------------------
MTH_FX_DBG = {
sauceType = type(PizzaSauce),
createFrameType = type(CreateFrame),
step = "1-top",
}
-- ---------------------------------------------------------------------------
-- Animation settings (shared by the effect code and the options "Animations" tab)
-- ---------------------------------------------------------------------------
-- Sections shown, in order, in the options panel. `titleKey` localizes `title`.
MTH_FX_ANIM_SECTIONS = {
{ id = "pet", title = "Pet", titleKey = "ANIM_SECTION_PET" },
{ id = "book", title = "Book", titleKey = "ANIM_SECTION_BOOK" },
{ id = "ui", title = "Interface", titleKey = "ANIM_SECTION_UI" },
}
-- Every individual animation the addon can play. Each has a stable `key`, the
-- section it belongs to, a checkbox label, an optional tooltip, and a default.
-- labelKey/tooltipKey localize label/tooltip (resolved at render time).
-- Adding a new animation = one entry here + one MTH_FX_IsEnabled("key") guard.
MTH_FX_ANIM_DEFS = {
{ key = "pet.celebrate", section = "pet", default = true,
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 = "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.",
tooltipKey = "ANIM_BOOK_OPEN_TIP" },
{ key = "book.tabs", section = "book", default = true,
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 = "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.",
tooltipKey = "ANIM_UI_OPTIONS_TIP" },
}
local function MTH_FX_Store()
if MTH and type(MTH.GetModuleSavedVariables) == "function" then
return MTH:GetModuleSavedVariables("animations")
end
return nil
end
local function MTH_FX_DefaultFor(key)
local i = 1
while i <= table.getn(MTH_FX_ANIM_DEFS) do
if MTH_FX_ANIM_DEFS[i].key == key then
return MTH_FX_ANIM_DEFS[i].default and true or false
end
i = i + 1
end
return true
end
function MTH_FX_AnimationsEnabled()
local store = MTH_FX_Store()
if not store or store.enabled == nil then
return true
end
return store.enabled and true or false
end
function MTH_FX_SetAnimationsEnabled(value)
local store = MTH_FX_Store()
if not store then return end
store.enabled = value and true or false
end
function MTH_FX_GetFlag(key)
local store = MTH_FX_Store()
if store and store.flags and store.flags[key] ~= nil then
return store.flags[key] and true or false
end
return MTH_FX_DefaultFor(key)
end
function MTH_FX_SetFlag(key, value)
local store = MTH_FX_Store()
if not store then return end
store.flags = store.flags or {}
store.flags[key] = value and true or false
end
-- Master gate every animation call site checks: false when animations are
-- globally disabled, or when this specific animation is turned off.
function MTH_FX_IsEnabled(key)
if not MTH_FX_AnimationsEnabled() then
return false
end
if key == nil then
return true
end
return MTH_FX_GetFlag(key)
end
-- Register a one-shot "ballistic" tween type: a spark that flies out from the
-- center along a velocity vector while gravity pulls it back down.
MTH_FX_DBG.step = "2-before-registertype"
if Sauce and type(Sauce.RegisterType) == "function" and not Sauce.MTH_HasBallistic then
local ok, err = pcall(function()
Sauce.MTH_HasBallistic = true
Sauce:RegisterType("mth_ballistic", {
init = function(target, from)
return from or { 0, 0 }
end,
apply = function(target, from, to, t, tween)
local dur = tween.dur or 1
local elapsed = t * dur
local vx = tween.vx or 0
local vy = tween.vy or 0
local gravity = tween.gravity or 0
local x = from[1] + vx * elapsed
local y = from[2] + vy * elapsed - 0.5 * gravity * elapsed * elapsed
local anchor = tween.anchor or UIParent
target:ClearAllPoints()
target:SetPoint("CENTER", anchor, "CENTER", x, y)
end,
})
end)
MTH_FX_DBG.registerOk = ok
MTH_FX_DBG.registerErr = err
else
MTH_FX_DBG.registerSkipped = true
end
MTH_FX_DBG.step = "3-after-registertype"
local MTH_FX_NUM_SPARKS = 22
local MTH_FX_Container
local MTH_FX_MsgFrame
local MTH_FX_TitleFS
local MTH_FX_SubFS
local MTH_FX_Sparks = {}
-- Palette for the firework sparks (r, g, b), warm celebratory tones.
local MTH_FX_Colors = {
{ 1.00, 0.82, 0.00 },
{ 1.00, 0.45, 0.10 },
{ 1.00, 0.20, 0.30 },
{ 0.35, 0.70, 1.00 },
{ 0.55, 1.00, 0.45 },
{ 0.85, 0.50, 1.00 },
}
local function MTH_FX_EnsureFrames()
if type(CreateFrame) ~= "function" then
return false
end
if MTH_FX_Container then
return true
end
MTH_FX_Container = CreateFrame("Frame", "MTH_FX_Container", UIParent)
MTH_FX_Container:SetWidth(1)
MTH_FX_Container:SetHeight(1)
MTH_FX_Container:SetPoint("CENTER", UIParent, "CENTER", 0, 40)
MTH_FX_Container:SetFrameStrata("FULLSCREEN_DIALOG")
MTH_FX_Container:Hide()
MTH_FX_MsgFrame = CreateFrame("Frame", "MTH_FX_Message", UIParent)
MTH_FX_MsgFrame:SetWidth(512)
MTH_FX_MsgFrame:SetHeight(90)
MTH_FX_MsgFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 80)
MTH_FX_MsgFrame:SetFrameStrata("FULLSCREEN_DIALOG")
MTH_FX_TitleFS = MTH_FX_MsgFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
MTH_FX_TitleFS:SetPoint("CENTER", MTH_FX_MsgFrame, "CENTER", 0, 14)
MTH_FX_TitleFS:SetTextColor(1, 0.82, 0)
MTH_FX_SubFS = MTH_FX_MsgFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
MTH_FX_SubFS:SetPoint("TOP", MTH_FX_TitleFS, "BOTTOM", 0, -8)
MTH_FX_SubFS:SetTextColor(1, 1, 1)
MTH_FX_MsgFrame:Hide()
local i = 1
while i <= MTH_FX_NUM_SPARKS do
local spark = MTH_FX_Container:CreateTexture(nil, "OVERLAY")
spark:SetTexture("Interface\\Cooldown\\star4")
spark:SetWidth(22)
spark:SetHeight(22)
spark:SetBlendMode("ADD")
spark:SetPoint("CENTER", MTH_FX_Container, "CENTER", 0, 0)
spark:Hide()
MTH_FX_Sparks[i] = spark
i = i + 1
end
return true
end
-- Public entry point: play a celebratory message + firework burst in the middle
-- of the screen. `title` and `subtitle` are optional strings.
function MTH_Celebrate(title, subtitle)
if not Sauce then
return
end
if not MTH_FX_EnsureFrames() then
return
end
MTH_FX_TitleFS:SetText(title or "")
MTH_FX_SubFS:SetText(subtitle or "")
Sauce:Stop(MTH_FX_MsgFrame)
MTH_FX_MsgFrame:SetAlpha(0)
MTH_FX_MsgFrame:Show()
Sauce:Sequence({
Sauce:Group({
Sauce:FadeTo(MTH_FX_MsgFrame, 1, 0.25),
Sauce:Pulse(MTH_FX_MsgFrame, 1.22, 0.5),
}),
Sauce:FadeOut(MTH_FX_MsgFrame, 0.6, "inQuad", { delay = 2.2 }),
})
MTH_FX_Container:Show()
local colorCount = table.getn(MTH_FX_Colors)
local colorIdx = 0
local i = 1
while i <= MTH_FX_NUM_SPARKS do
local spark = MTH_FX_Sparks[i]
local angle = (i / MTH_FX_NUM_SPARKS) * 2 * math.pi + (math.random() - 0.5) * 0.4
local speed = 150 + math.random() * 130
local vx = math.cos(angle) * speed
local vy = math.sin(angle) * speed + 70
local dur = 0.9 + math.random() * 0.4
colorIdx = colorIdx + 1
if colorIdx > colorCount then colorIdx = 1 end
local color = MTH_FX_Colors[colorIdx]
spark:SetVertexColor(color[1], color[2], color[3])
spark:SetAlpha(1)
spark:Show()
Sauce:Stop(spark)
Sauce:Group({
Sauce:Tween(spark, {
type = "mth_ballistic",
from = { 0, 0 },
duration = dur,
easing = "linear",
anchor = MTH_FX_Container,
dur = dur,
vx = vx,
vy = vy,
gravity = 300,
}),
Sauce:FadeTo(spark, 0, 0.45, "inQuad", {
delay = dur - 0.45,
onFinish = function()
spark:Hide()
end,
}),
})
i = i + 1
end
end
-- Convenience wrapper used when the hunter's pet learns a new ability/rank.
function MTH_CelebratePetAbility(label)
if not MTH_FX_IsEnabled("pet.celebrate") then
return
end
MTH_Celebrate(MTH_FX_L("ANIM_PET_LEARNED_TITLE", "New Pet Ability!"), label)
end
-- DEBUG: mark that the whole file finished loading and record which globals it
-- successfully defined. TEMP diagnostic.
MTH_FX_DBG.step = "4-complete"
MTH_FX_DBG.hasCelebrate = type(MTH_Celebrate)
MTH_FX_DBG.hasIsEnabled = type(MTH_FX_IsEnabled)
MTH_FX_DBG.hasAnimEnabled = type(MTH_FX_AnimationsEnabled)
+32
View File
@@ -1,5 +1,34 @@
-- MetaHunt standalone Hunter Book UI (XML + Lua)
-- Capture our PizzaSauce instance for opening animations (may be nil if the
-- library is unavailable; all uses are guarded).
local Sauce = PizzaSauce
-- Fade the book window in on open, unless the player disabled it in options.
local function MTH_BOOK_FadeInWindow(frame)
if not Sauce or not frame then return end
if type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("book.open") then return end
-- Hide the window's alpha THIS frame: Show() already ran, so without this the
-- book renders fully opaque for one frame before the tween's onStart snaps it
-- to 0 -- a flash that makes the fade look like it never happened.
if type(frame.SetAlpha) == "function" then frame:SetAlpha(0) end
-- Slide the whole window up into place while fading in. Position and alpha are
-- the only safe properties on a complex frame: the built-in "scale" tween
-- resizes width/height, which the child widgets do NOT follow (they clip), so
-- a slide + fade is the strongest effect that keeps the layout intact.
Sauce:SlideIn(frame, "UP", 60, 0.4, "outCubic")
end
-- Fade the results list back in when switching Hunter's Book tabs, unless disabled.
local function MTH_BOOK_AnimateTabSwitch()
if not Sauce then return end
if type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("book.tabs") 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.25)
end
MTH_HUNTERBOOK_LOADED = true
MTH_HUNTERBOOK_TABS = MTH_HUNTERBOOK_TABS or {}
@@ -4929,6 +4958,7 @@ local function MTH_BOOK_SetMode(mode)
MTH_BOOK_UpdateModeLabels()
MTH_BOOK_UpdateSectionTabs()
MTH_BOOK_RefreshFilter()
MTH_BOOK_AnimateTabSwitch()
end
function MTH_BOOK_JumpToBeastById(beastId)
@@ -5712,6 +5742,7 @@ function MTH_OpenHunterBook()
local frame = MTH_BOOK_EnsureWindow()
if not frame then return end
frame:Show()
MTH_BOOK_FadeInWindow(frame)
if MTH_BOOK_UpdateRealmGateOverlay(frame) then return end
MTH_BOOK_RefreshFilter()
end
@@ -5724,6 +5755,7 @@ function MTH_ToggleHunterBook()
frame:Hide()
else
frame:Show()
MTH_BOOK_FadeInWindow(frame)
if MTH_BOOK_UpdateRealmGateOverlay(frame) then return end
MTH_BOOK_RefreshFilter()
end
+173
View File
@@ -0,0 +1,173 @@
-- MetaHunt: "Animations" options panel.
-- Global enable/disable plus a per-animation checkbox for each effect, grouped
-- into sections (Pet, Book, ...). The animation registry lives in fx-celebrate.lua
-- (MTH_FX_ANIM_SECTIONS / MTH_FX_ANIM_DEFS) so both the effects and this panel
-- stay in sync.
local MTH_ANIM_READY = MTH_OptionsRequire and MTH_OptionsRequire("options-animations", {
"MTH_GetFrame",
"MTH_ClearContainer",
"MTH_CreateCheckbox",
})
-- DEBUG: load-path tracer, global so /mth fxdebug can dump it. TEMP diagnostic.
MTH_ANIM_DBG = {
ready = tostring(MTH_ANIM_READY),
reqType = type(MTH_OptionsRequire),
getFrameType = type(MTH_GetFrame),
clearType = type(MTH_ClearContainer),
checkboxType = type(MTH_CreateCheckbox),
step = "1-top",
}
local MTH_ANIM_LINK = "https://codeberg.org/Pizzahawaii/PizzaSauce"
local MTH_ANIM_CTRL = {}
local function MTH_ANIM_L(key, default)
if MTH and MTH.GetLocalization then
return MTH:GetLocalization(key, default)
end
return default or key
end
local function MTH_ANIM_InsertLink(url)
local link = tostring(url or "")
if link == "" then return end
if type(MTH_InsertLinkToChat) == "function" and MTH_InsertLinkToChat(link) then
if MTH and MTH.Print then
MTH:Print(MTH_ANIM_L("ANIM_LINK_INSERTED", "Link inserted in chat: ") .. link)
end
return
end
if MTH and MTH.Print then
MTH:Print(MTH_ANIM_L("ANIM_LINK_FALLBACK", "Link: ") .. link)
end
end
local function MTH_ANIM_UpdateChildStates()
local master = MTH_FX_AnimationsEnabled()
local i = 1
while i <= table.getn(MTH_ANIM_CTRL) do
local cb = MTH_ANIM_CTRL[i]
if cb then
cb:SetChecked(MTH_FX_GetFlag(cb.mthKey))
if master then
cb:Enable()
else
cb:Disable()
end
end
i = i + 1
end
end
function MTH_SetupAnimationsOptions()
MTH_ANIM_DBG.setupCalled = true
MTH_ANIM_DBG.fxEnabledType = type(MTH_FX_AnimationsEnabled)
if not MTH_ANIM_READY then
MTH_ANIM_DBG.setupResult = "abort-not-ready"
return
end
if type(MTH_FX_AnimationsEnabled) ~= "function" then
MTH_ANIM_DBG.setupResult = "abort-no-fx-globals"
return
end
local container = MTH_GetFrame("MetaHuntOptionsAnimations")
MTH_ANIM_DBG.containerType = type(container)
if not container then
MTH_ANIM_DBG.setupResult = "abort-no-container"
return
end
MTH_ClearContainer(container)
MTH_ANIM_CTRL = {}
local title = container:CreateFontString("MetaHuntOptionsAnimationsTitle", "ARTWORK", "GameFontNormal")
title:SetPoint("TOPLEFT", container, "TOPLEFT", 10, -10)
title:SetText(MTH_ANIM_L("ANIM_TITLE", "Animations"))
title:SetTextColor(1.00, 0.82, 0.00)
local credit = container:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
credit:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
credit:SetWidth(460)
credit:SetJustifyH("LEFT")
credit:SetText(MTH_ANIM_L("ANIM_CREDIT",
"Animations are powered by PizzaSauce, a WoW 1.12 animation library kindly made and shared by Pizzahawaii. Thank you!"))
credit:SetTextColor(0.93, 0.93, 0.93)
local link = CreateFrame("Button", nil, container)
link:SetPoint("TOPLEFT", credit, "BOTTOMLEFT", 0, -4)
link:SetHeight(16)
link:SetWidth(460)
local linkText = link:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
linkText:SetPoint("LEFT", link, "LEFT", 0, 0)
linkText:SetJustifyH("LEFT")
linkText:SetText(MTH_ANIM_LINK)
linkText:SetTextColor(0.40, 0.75, 1.00)
link:SetScript("OnClick", function() MTH_ANIM_InsertLink(MTH_ANIM_LINK) end)
link:SetScript("OnEnter", function() linkText:SetTextColor(0.60, 0.90, 1.00) end)
link:SetScript("OnLeave", function() linkText:SetTextColor(0.40, 0.75, 1.00) end)
-- Global master toggle.
local master = MTH_CreateCheckbox(container, "MetaHuntOptionsAnimMaster",
MTH_ANIM_L("ANIM_ENABLE_ALL", "Enable animations"), -70)
if master then
master:SetChecked(MTH_FX_AnimationsEnabled())
master:SetScript("OnClick", function()
MTH_FX_SetAnimationsEnabled(master:GetChecked())
MTH_ANIM_UpdateChildStates()
end)
end
-- Per-animation checkboxes, grouped by section.
local y = -104
local rowStep = 26
local sectionGap = 12
local s = 1
while MTH_FX_ANIM_SECTIONS and s <= table.getn(MTH_FX_ANIM_SECTIONS) do
local sec = MTH_FX_ANIM_SECTIONS[s]
local header = container:CreateFontString(nil, "ARTWORK", "GameFontNormal")
header:SetPoint("TOPLEFT", container, "TOPLEFT", 15, y)
header:SetText(MTH_ANIM_L(sec.titleKey, sec.title))
header:SetTextColor(1.00, 0.82, 0.00)
y = 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)
if cb then
cb.mthKey = def.key
cb:SetChecked(MTH_FX_GetFlag(def.key))
cb:SetScript("OnClick", function()
MTH_FX_SetFlag(cb.mthKey, cb:GetChecked())
end)
if def.tooltip and def.tooltip ~= "" then
cb.mthTooltip = MTH_ANIM_L(def.tooltipKey, def.tooltip)
cb:SetScript("OnEnter", function()
GameTooltip:SetOwner(cb, "ANCHOR_RIGHT")
GameTooltip:SetText(cb.mthTooltip, 1, 1, 1, 1, true)
GameTooltip:Show()
end)
cb:SetScript("OnLeave", function() GameTooltip:Hide() end)
end
table.insert(MTH_ANIM_CTRL, cb)
y = y - rowStep
end
end
d = d + 1
end
y = y - sectionGap
s = s + 1
end
MTH_ANIM_UpdateChildStates()
MTH_ANIM_DBG.setupResult = "ok"
end
-- DEBUG: mark that the whole file finished loading. TEMP diagnostic.
MTH_ANIM_DBG.step = "2-complete"
MTH_ANIM_DBG.hasSetup = type(MTH_SetupAnimationsOptions)
+18
View File
@@ -20,6 +20,16 @@ local function MTH_OPT_L(key, default)
return default or key
end
-- Capture our PizzaSauce instance for the options-window open animation (guarded).
local MTH_OPT_Sauce = PizzaSauce
local function MTH_OPT_AnimateOpen(frame)
if not MTH_OPT_Sauce or not frame then return end
if type(MTH_FX_IsEnabled) == "function" and not MTH_FX_IsEnabled("ui.options") then return end
-- Hide alpha this frame so there is no one-frame opaque flash before onStart.
if type(frame.SetAlpha) == "function" then frame:SetAlpha(0) end
MTH_OPT_Sauce:SlideIn(frame, "UP", 60, 0.4, "outCubic")
end
local function MTH_RegisterEscClose(frameName)
if not (frameName and UISpecialFrames) then
return
@@ -232,6 +242,13 @@ function MTH_SelectOptionsTab(tabKey)
elseif MTH and MTH.Print then
MTH:Print("ICU options setup function is not loaded", "error")
end
elseif tabKey == "Animations" then
if not MTH_OPTIONS_SETUP["Animations"] then
if type(MTH_SetupAnimationsOptions) == "function" then
MTH_SetupAnimationsOptions()
MTH_OPTIONS_SETUP["Animations"] = true
end
end
elseif tabKey == "Credits" then
local setupCredits = _G and _G["MTH_SetupCreditsOptions"]
if type(setupCredits) == "function" then
@@ -324,6 +341,7 @@ function MTH_OpenOptions(tabKey)
return
end
optionsFrame:Show()
MTH_OPT_AnimateOpen(optionsFrame)
if MTH_OPTIONS_UpdateRealmGateOverlay(optionsFrame) then return end
MTH_SelectOptionsTab(tabKey or "General")
end
+2
View File
@@ -52,6 +52,7 @@ MTH_OPTIONS_TABS = MTH_OPTIONS_TABS or {
{ key = "ChronometerClassSpells", label = "Hunter Spells", frame = "MetaHuntOptionsChronometer" },
{ key = "ChronometerClassEvents", label = "Hunter Events", frame = "MetaHuntOptionsChronometer" },
{ key = "ChronometerRacial", label = "Racial", frame = "MetaHuntOptionsChronometer" },
{ key = "Animations", label = "Animations", frame = "MetaHuntOptionsAnimations" },
{ key = "Credits", label = "Credits", frame = "MetaHuntOptionsCredits" },
}
@@ -92,6 +93,7 @@ MTH_OPTIONS_TREE = MTH_OPTIONS_TREE or {
{ label = "Racial", key = "ChronometerRacial" },
},
},
{ label = "Animations", key = "Animations" },
{ label = "Credits", key = "Credits" },
}
+1
View File
@@ -85,6 +85,7 @@
<Frame name="$parentICU" hidden="true" enableMouse="true"/>
<Frame name="$parentExpAmmo" hidden="true" enableMouse="true"/>
<Frame name="$parentChronometer" hidden="true" enableMouse="true"/>
<Frame name="$parentAnimations" hidden="true" enableMouse="true"/>
<Frame name="$parentCredits" hidden="true" enableMouse="true"/>
<!-- Top-right close button -->
+3
View File
@@ -1,7 +1,9 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Include file="..\api\PizzaSauce.lua"/>
<Include file="..\api\constants.lua"/>
<Include file="..\api\savedvariables.lua"/>
<Include file="..\api\fx-celebrate.lua"/>
<Include file="..\api\minimap-button.lua"/>
<Include file="..\api\AutoStrip.xml"/>
<Include file="..\api\AutoStrip.lua"/>
@@ -14,6 +16,7 @@
<Include file="..\api\options.lua"/>
<Include file="..\api\options-chronometer.lua"/>
<Include file="..\api\options-credits.lua"/>
<Include file="..\api\options-animations.lua"/>
<Include file="..\api\options-autobuy.lua"/>
<Include file="..\api\options-autoquest.lua"/>
<Include file="..\api\options-icu.lua"/>