mirror of
https://codeberg.org/Duvelcorp/MetaHunt.git
synced 2026-09-24 08:36:06 +00:00
314 lines
10 KiB
Lua
314 lines
10 KiB
Lua
-- 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" },
|
|
{ key = "ui.optiontabs", section = "ui", default = true,
|
|
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.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.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.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.",
|
|
tooltipKey = "ANIM_UI_MAPPINS_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)
|