Files
pfUI/modules/easteregg.lua
T
Brues df13e30e08 Add a Valentine's Day AFK scene
Hearts drawn from a turned square and two tinted minimap-mask discs float up the screen and sway, a rosy glow lines the edges, and the goblin Cupid hovers by the side.
2026-10-31 01:50:12 -05:00

404 lines
14 KiB
Lua

pfUI:RegisterModule("easteregg", function ()
local today = date("%m%d")
-- A full screen scene for the time the player is AFK on a holiday. The
-- night fades in, and a click or coming back hides it again.
local function CreateScene(name, greeting, info)
local scene = CreateFrame("Button", name, WorldFrame)
scene:SetFrameStrata("DIALOG")
scene:SetAllPoints()
scene:Hide()
scene.night = scene:CreateTexture(nil, "BACKGROUND")
scene.night:SetColorTexture(0,0,0,1)
scene.night:SetGradientAlpha("VERTICAL", 0,0,0,.5, 0,0,0,1)
scene.night:SetAllPoints()
scene.stext = scene:CreateFontString(nil, "ARTWORK", "GameFontWhite")
scene.stext:SetFont(STANDARD_TEXT_FONT, 14, "OUTLINE")
scene.stext:SetPoint("TOP", 0, -380)
scene.stext:SetText("|cff33ffccShagu|cffffffff wishes you a")
scene.text = scene:CreateFontString(nil, "ARTWORK", "GameFontWhite")
scene.text:SetFont(pfUI.media["font:BigNoodleTitling.ttf"], 38)
scene.text:SetPoint("TOP", 0, -400)
scene.text:SetText(greeting)
local exit = "|cff444444<Click> or '/afk' to exit"
scene.dtext = scene:CreateFontString(nil, "ARTWORK", "GameFontWhite")
scene.dtext:SetFont(STANDARD_TEXT_FONT, 14, "OUTLINE")
scene.dtext:SetPoint("TOP", 0, -430)
scene.dtext:SetText(info and info .. "\n\n" .. exit or exit)
-- Fade the night in by playing a fade-out backwards. The scene keeps an
-- alpha of 1, which comes back when the fade ends.
scene.dusk = scene:CreateAnimationGroup()
local fade = scene.dusk:CreateAnimation("Alpha")
fade:SetChange(-1)
fade:SetDuration(.8)
scene:SetScript("OnShow", function()
this.dusk:Play(true)
end)
-- start over on the next AFK
scene:SetScript("OnHide", function()
this:StopAnimating()
end)
scene:SetScript("OnClick", function()
this:Hide()
end)
scene:RegisterEvent("PLAYER_FLAGS_CHANGED")
scene:SetScript("OnEvent", function()
this:SetShown(UnitIsAFK('player'))
end)
return scene
end
-- happy valentine's day
if today == "0214" then
local valentine = CreateScene("pfValentine", "happy valentine's day!")
valentine.text:SetTextColor(1, .4, .6)
-- a rosy glow around the screen edges
local glow = CreateFrame("Frame", nil, valentine)
glow:SetAllPoints()
glow:SetBackdrop({ edgeFile = pfUI.media["img:glow"], edgeSize = 32 })
glow:SetBackdropBorderColor(1, .3, .5, 1)
-- A heart is a square turned onto its corner with a round lobe on each
-- upper edge. The client's minimap mask is a plain white disc, so it
-- tints into a lobe without a texture of our own. Smaller hearts are
-- farther away, so they are darker and rise slower.
local hearts = {}
for i = 1, 40 do
local width = math.random(10, 28)
local side = width / 1.7
local shade = .4 + width / 28 * .6
local r, g, b = shade, shade * math.random() * .4, shade * (.2 + math.random() * .3)
local heart = CreateFrame("Frame", nil, valentine)
heart:SetSize(width, width)
heart.width = width
local tip = heart:CreateTexture(nil, "ARTWORK")
tip:SetColorTexture(1, 1, 1)
tip:SetVertexColor(r, g, b)
tip:SetSize(side, side)
tip:SetPoint("CENTER", 0, -side * .07)
tip:SetRotation(math.pi / 4)
for _, x in ipairs({ -1, 1 }) do
local lobe = heart:CreateTexture(nil, "ARTWORK")
lobe:SetTexture("Textures\\MinimapMask")
lobe:SetVertexColor(r, g, b)
lobe:SetSize(side, side)
lobe:SetPoint("CENTER", x * side * .354, side * .28)
end
-- like the snow, but up from below the screen
heart.float = heart:CreateAnimationGroup()
heart.float:SetLooping("REPEAT")
heart.float:SetIgnoreFramerateThrottle(true)
heart.path = heart.float:CreateAnimation("Path")
heart.path:SetCurve("SMOOTH")
heart.points = {}
for point = 1, 6 do
heart.points[point] = heart.path:CreateControlPoint()
end
hearts[i] = heart
end
local function LetThemFloat()
local width, height = valentine:GetWidth(), valentine:GetHeight()
for _, heart in ipairs(hearts) do
local rise = height + heart.width
local duration = rise / (20 + heart.width * 2)
local sway = math.random(-30, 30)
heart:ClearAllPoints()
heart:SetPoint("TOP", valentine, "BOTTOMLEFT", math.random() * width, 0)
heart.path:SetDuration(duration)
heart.path:SetStartDelay(math.random() * duration)
for point, control in ipairs(heart.points) do
control:SetOffset(point % 2 == 1 and sway or -sway, rise * point / 6)
end
heart.float:Play()
end
end
-- Cupid hovers by the side, turned towards the middle
local cupid = CreateFrame("PlayerModel", nil, valentine)
cupid:SetSize(260, 260)
cupid:SetPoint("BOTTOMRIGHT", -60, 60)
cupid:SetScript("OnShow", function()
this:SetDisplayInfo(15990)
this:SetFacing(-.5)
end)
cupid:Hide()
valentine.dusk:SetScript("OnFinished", function()
LetThemFloat()
cupid:Show()
end)
valentine:HookScript("OnHide", function()
cupid:Hide()
end)
end
-- happy hallow's end
if today == "1031" then
local halloween = CreateScene("pfHallowsEnd", "happy hallow's end!")
halloween.text:SetTextColor(1, .5, 0)
-- Candlelight glows in from the screen edges. It flickers in uneven
-- steps of { duration, change } that end where they began, so the loop
-- never jumps.
local candle = CreateFrame("Frame", nil, halloween)
candle:SetAllPoints()
candle:SetBackdrop({ edgeFile = pfUI.media["img:glow"], edgeSize = 32 })
candle:SetBackdropBorderColor(1, .5, .1, 1)
candle.flicker = candle:CreateAnimationGroup()
candle.flicker:SetLooping("REPEAT")
local steps = {
{ .18, -.25 }, { .09, .1 }, { .22, -.2 }, { .14, .3 }, { .3, -.1 },
{ .11, -.15 }, { .2, .2 }, { .16, -.3 }, { .26, .25 }, { .12, .15 },
}
for order, step in ipairs(steps) do
local duration, change = unpack(step)
local fade = candle.flicker:CreateAnimation("Alpha")
fade:SetOrder(order)
fade:SetDuration(duration)
fade:SetChange(change)
fade:SetSmoothing("IN_OUT")
end
-- Once the night has fallen, undead rise along the bottom one after
-- another, a different few on every AFK. They are creature displays, so
-- they need no creature cache. A model frame aims its camera at the
-- middle of the model's bounds, so the frame size alone sets how big one
-- is. Bounds that reach far above the body, like the lich's, leave it
-- standing too low, so it is left out.
local undead = {
158, -- skeleton
201, -- green skeleton
1245, -- skeleton mage
137, -- ghoul
18114, -- white-handed ghoul
1200, -- zombie
1201, -- green zombie
1202, -- sea-green zombie
915, -- banshee
10690, -- green banshee
146, -- ghost
4629, -- shade
7533, -- gargoyle
7534, -- black gargoyle
7854, -- blue gargoyle
}
local function Rise()
this:SetDisplayInfo(this.display)
this:SetFacing(this.facing)
end
local risen = {}
local rising = halloween:CreateAnimationGroup()
for i = 1, 7 do
local size = math.random(180, 240)
local model = CreateFrame("PlayerModel", nil, halloween)
model:SetSize(size, size)
model:SetPoint("BOTTOM", halloween, "BOTTOM", (i - 4) * 150 + math.random(-20, 20), math.random(-10, 20))
model.facing = (math.random() - .5) * .8
model:SetScript("OnShow", Rise)
model:Hide()
risen[i] = model
local rise = rising:CreateAnimation()
rise:SetOrder(i)
rise:SetDuration(.3)
rise:SetScript("OnFinished", function() model:Show() end)
end
halloween.dusk:SetScript("OnFinished", function()
-- shuffle as many undead to the front as there are models
for i, model in ipairs(risen) do
local j = math.random(i, #undead)
undead[i], undead[j] = undead[j], undead[i]
model.display = undead[i]
end
candle.flicker:Play()
rising:Play()
end)
halloween:HookScript("OnHide", function()
for _, model in ipairs(risen) do
model:Hide()
end
end)
end
-- merry x-mas!
if today == "1224" or today == "1225" then
local title = (UnitFactionGroup("player") == "Horde") and PVP_RANK_18_0 or PVP_RANK_18_1
local oldflag = _G.CHAT_FLAG_AFK
local pvpking = CreateFrame("Frame", "pfPvPKing", UIParent)
pvpking:Hide()
pvpking:RegisterEvent("PLAYER_FLAGS_CHANGED")
pvpking:SetScript("OnEvent", function()
if UnitIsAFK('player') then
_G.CHAT_FLAG_AFK = title .. " "
this.time = GetTime()
this:Show()
end
end)
pvpking:SetScript("OnUpdate", function()
if this.time + 1 < GetTime() then
_G.CHAT_FLAG_AFK = oldflag
this:Hide()
end
end)
_G.MARKED_AFK = "You are now |cff33ffcc" .. title .. "|r (AFK)."
_G.MARKED_AFK_MESSAGE = "You are now |cff33ffcc" .. title .. "|r (AFK): %s"
_G.CLEARED_AFK = "You are no longer |cff33ffcc" .. title .. "|r (AFK).\n|cff33ffccShagu|cffffffff wishes you a merry christmas. Thanks for using |cff33ffccpf|cffffffffUI|cffffffff!|r"
local snow = CreateScene("pfSnowfall", "merry christmas!")
snow.text:SetTextColor(1, .25, .25)
-- Flakes fall past the screen for good and sway on the way down. Before
-- each fall a flake waits above the screen for a while, which spreads
-- them out.
local flakes = {}
for i = 1, 200 do
local flake = snow:CreateTexture(nil, "OVERLAY")
flake.fall = flake:CreateAnimationGroup()
flake.fall:SetLooping("REPEAT")
flake.fall:SetIgnoreFramerateThrottle(true)
flake.path = flake.fall:CreateAnimation("Path")
flake.path:SetCurve("SMOOTH")
flake.points = {}
for point = 1, 6 do
flake.points[point] = flake.path:CreateControlPoint()
end
flakes[i] = flake
end
local function LetItSnow()
local width, height = snow:GetWidth(), snow:GetHeight()
for _, flake in ipairs(flakes) do
-- bigger flakes are closer, so they are brighter and fall faster
local size = math.random(2, 5)
local fall = height + size
local duration = fall / (40 + size * 20)
local sway = math.random(-20, 20)
flake:SetSize(size, size)
flake:SetColorTexture(1, 1, 1, .3 + size * .14)
flake:ClearAllPoints()
flake:SetPoint("BOTTOM", snow, "TOPLEFT", math.random() * width, 0)
flake.path:SetDuration(duration)
flake.path:SetStartDelay(math.random() * duration)
for point, control in ipairs(flake.points) do
control:SetOffset(point % 2 == 1 and sway or -sway, -fall * point / 6)
end
flake.fall:Play()
end
end
-- Snow piles up at the bottom for as long as the player stays AFK. The
-- drift plays a shrink backwards, so it grows to its full height over
-- ten minutes and keeps it once the group ends.
local pile = snow:CreateTexture(nil, "ARTWORK")
pile:SetPoint("BOTTOMLEFT", 0, 0)
pile:SetPoint("BOTTOMRIGHT", 0, 0)
pile:SetHeight(120)
pile:SetColorTexture(1, 1, 1, 1)
pile:SetGradientAlpha("VERTICAL", 1,1,1,.9, 1,1,1,0)
pile:Hide()
pile.grow = pile:CreateAnimationGroup()
local grow = pile.grow:CreateAnimation("Scale")
grow:SetOrigin("BOTTOM", 0, 0)
grow:SetScale(1, .01)
grow:SetDuration(600)
snow.dusk:SetScript("OnFinished", function()
LetItSnow()
pile:Show()
pile.grow:Play(true)
end)
snow:HookScript("OnHide", function()
pile:Hide()
end)
end
-- happy new year
if today == "1231" or today == "0101" then
local fireworks = CreateScene("pfFireworks", "happy new year!",
"Another year with |cff33ffccpf|rUI has passed.\nThanks for continuing to use it!")
-- Each explosion grows by 100px and fades out over 5/3s, then goes back
-- to the pool.
local explosions = CreateTexturePool(fireworks, "OVERLAY")
local function Explode(x, y, size, r, g, b, a)
local tex = explosions:Acquire()
if not tex.burst then
tex.burst = tex:CreateAnimationGroup()
tex.burst:SetIgnoreFramerateThrottle(true)
tex.burst.grow = tex.burst:CreateAnimation("Scale")
tex.burst.grow:SetDuration(5/3)
local fade = tex.burst:CreateAnimation("Alpha")
fade:SetChange(-1)
fade:SetDuration(5/3)
tex.burst:SetScript("OnFinished", function() explosions:Release(tex) end)
end
tex:SetPoint("CENTER", fireworks, "TOPLEFT", x, y)
tex:SetSize(size, size)
tex:SetColorTexture(r, g, b, a)
tex.burst.grow:SetScale((size + 100) / size, (size + 100) / size)
tex:Show()
tex.burst:Play()
end
fireworks:HookScript("OnHide", function()
explosions:ReleaseAll()
end)
-- create random amount of fireworks at random positions
fireworks:SetScript("OnUpdate", function()
if this.dusk:IsPlaying() then return end
-- let the "happy new year" blink
local r,g,b = this.text:GetTextColor()
this.text:SetTextColor(r+(math.random()-.5)/10, g+(math.random()-.5)/10, b+(math.random()-.5)/10,1)
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + math.random() - .2 end
local x,y = math.random(1, this:GetWidth()), -1*math.random(1, this:GetHeight())
-- create the base explosion
Explode(x, y, 25, 1, 1, 1, .5)
-- create random amount of colored explosions
for i=1, math.random(20) do
Explode(x+(math.random(0,100)-50), y+(math.random(0,100)-50), 2, math.random(), math.random(), math.random(), 1)
end
end)
end
end)