mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-22 13:36:14 +02:00
c23f82efdd
CLOSES #1663, CLOSES #1664, CLOSES #1665, CLOSES #1666, CLOSES #1667, CLOSES #1668, CLOSES #1670, CLOSES #1672
134 lines
5.2 KiB
Lua
134 lines
5.2 KiB
Lua
-- home/overworld.asm:690-703 (PlayMapChangeSound tail-calls GBFadeOutToBlack)
|
|
-- and home/fade.asm:43-46: the map-change fade has no matching fade in, so the
|
|
-- warp shape ends in the same frame its midpoint runs. The midpoint is where
|
|
-- setMap opens things (the Cycling Road refusal box, a map script's onEnter),
|
|
-- and a fade that popped the top of the stack after that ate them and then
|
|
-- finished a second time (#1663).
|
|
-- luajit tests/engine/transition_identity_pop_bug1663.lua
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
love = love or require("tests.love_stub")
|
|
|
|
local StateStack = require("src.core.StateStack")
|
|
local Transition = require("src.render.Transition")
|
|
local Timing = require("src.core.Timing")
|
|
|
|
local function overworld() return { name = "overworld", isOpaque = true } end
|
|
|
|
-- ------------------------------------------------ the warp shape (#1663)
|
|
|
|
do
|
|
StateStack:init()
|
|
local ow = overworld()
|
|
StateStack:push(ow)
|
|
|
|
local box = { name = "refusal" }
|
|
local entered, depthAtMidpoint, topAtMidpoint = 0, nil, nil
|
|
function box:enter() entered = entered + 1 end
|
|
local dones = 0
|
|
local fade
|
|
fade = Transition.new({ stack = StateStack }, function()
|
|
depthAtMidpoint = #StateStack.states
|
|
topAtMidpoint = StateStack:top()
|
|
StateStack:push(box)
|
|
end, function() dones = dones + 1 end, true)
|
|
StateStack:push(fade)
|
|
|
|
local finishedOn
|
|
for frame = 1, 120 do
|
|
StateStack:update(1 / 60)
|
|
if dones > 0 and not finishedOn then finishedOn = frame end
|
|
end
|
|
|
|
eq(finishedOn, Timing.WARP_FADE_OUT, "the warp hands back at the end of the fade")
|
|
eq(dones, 1, "and hands back exactly once")
|
|
eq(depthAtMidpoint, 1, "the fade is off the stack before the midpoint runs")
|
|
check(topAtMidpoint == ow, "so the map switch sees the overworld on top")
|
|
eq(entered, 1, "the state the midpoint pushed entered once")
|
|
eq(#StateStack.states, 2, "the fade is gone and the pushed state is not")
|
|
check(StateStack.states[1] == ow, "the overworld is still the base")
|
|
check(StateStack:top() == box, "the box the midpoint opened owns the screen")
|
|
end
|
|
|
|
-- a midpoint that pushes nothing still leaves exactly the overworld behind
|
|
do
|
|
StateStack:init()
|
|
local ow = overworld()
|
|
StateStack:push(ow)
|
|
local mids, dones = 0, 0
|
|
local fade = Transition.new({ stack = StateStack },
|
|
function() mids = mids + 1 end,
|
|
function() dones = dones + 1 end, true)
|
|
StateStack:push(fade)
|
|
for _ = 1, 120 do StateStack:update(1 / 60) end
|
|
eq(mids, 1, "the map switched once")
|
|
eq(dones, 1, "the plain warp still hands back exactly once")
|
|
eq(#StateStack.states, 1, "and pops nothing but itself")
|
|
check(StateStack:top() == ow, "leaving the overworld on top")
|
|
end
|
|
|
|
-- ------------------------------------------ the script fade is unchanged
|
|
|
|
-- ViridianGym.asm .afterBeat / RocketHideoutB4F BeatGiovanniScript bracket
|
|
-- their HideObject with GBFadeOutToBlack -> GBFadeInFromBlack, so those keep
|
|
-- a real fade in and wait under whatever the midpoint opened.
|
|
do
|
|
StateStack:init()
|
|
local ow = overworld()
|
|
StateStack:push(ow)
|
|
|
|
local box = { name = "script box" }
|
|
local dones = 0
|
|
local fade = Transition.new({ stack = StateStack },
|
|
function() StateStack:push(box) end,
|
|
function() dones = dones + 1 end, false)
|
|
StateStack:push(fade)
|
|
|
|
for _ = 1, Timing.WARP_FADE_OUT + 8 do StateStack:update(1 / 60) end
|
|
eq(dones, 0, "a fade with a fade-in waits under what its midpoint opened")
|
|
check(StateStack:top() == box, "the pushed state is on top")
|
|
check(StateStack.states[2] == fade, "with the fade still underneath it")
|
|
|
|
StateStack:pop()
|
|
for _ = 1, Timing.FADE_IN_FROM_BLACK + 8 do StateStack:update(1 / 60) end
|
|
eq(dones, 1, "and finishes once the box is gone")
|
|
eq(#StateStack.states, 1, "leaving the overworld alone on the stack")
|
|
check(StateStack:top() == ow, "and nothing else came off with it")
|
|
end
|
|
|
|
-- ------------------------------------------------- finish is idempotent
|
|
|
|
do
|
|
StateStack:init()
|
|
local ow = overworld()
|
|
StateStack:push(ow)
|
|
local dones = 0
|
|
local fade = Transition.new({ stack = StateStack }, nil,
|
|
function() dones = dones + 1 end, true)
|
|
StateStack:push(fade)
|
|
fade:finish()
|
|
fade:finish()
|
|
eq(dones, 1, "a second finish does not hand back a second time")
|
|
eq(#StateStack.states, 1, "and takes nothing else off the stack")
|
|
check(StateStack:top() == ow, "the overworld survives the second call")
|
|
end
|
|
|
|
-- a mod record may still ask a warp for a fade in; framesIn 0 is truthy in
|
|
-- Lua, so the built-in warp keeps its 0 and the retimed one keeps its own
|
|
do
|
|
local retimed = { transitions = { warp_fade = { kind = "fade", frames = 32,
|
|
framesIn = 16 } } }
|
|
local fade = Transition.new({ data = retimed, stack = StateStack }, nil,
|
|
nil, true)
|
|
eq(fade.framesIn, 16, "a retimed warp record keeps its fade in")
|
|
local vanilla = Transition.new({ stack = StateStack }, nil, nil, true)
|
|
eq(vanilla.framesIn, Timing.WARP_FADE_IN, "the built-in warp has none")
|
|
end
|
|
|
|
StateStack:clear()
|
|
|
|
T.finish("transition_identity_pop_bug1663")
|