mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
162 lines
5.4 KiB
Lua
162 lines
5.4 KiB
Lua
-- Manual check that Oak's NIDORINO keeps its mirrored front sprite across the
|
|
-- _OakSpeechText2A -> _OakSpeechText2B page break (#397). OakSpeechText2 is one
|
|
-- PrintText over one flipped pic (pokered engine/movie/oak_speech/oak_speech.asm
|
|
-- :80-85, :172-177); advance() used to clear picFlip on the pic-less next step.
|
|
-- SHOT_DIR=/tmp/bug397 POKEPORT_DRIVER=tests/drivers/oak_nidorino_flip_bug397_test.lua POKEPORT_IDENTITY=bug397 POKEPORT_TOUCH=0 POKEPORT_VERSION=red love .
|
|
-- Do not set POKEPORT_SPEED: fast-forward desynchronizes the cry from the wipe.
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local TextBox = require("src.render.TextBox")
|
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
|
|
local function check(label, ok)
|
|
U.log(ok and "PASS" or "FAIL", label)
|
|
return ok
|
|
end
|
|
|
|
local function top() return game.stack:top() end
|
|
local function isBox(s) return getmetatable(s) == TextBox end
|
|
|
|
local function speechState()
|
|
for _, s in ipairs(game.stack.states or {}) do
|
|
if s.demoPic ~= nil or (s.steps and s.answers) then return s end
|
|
end
|
|
end
|
|
|
|
local function boxText(s)
|
|
if not isBox(s) then return "" end
|
|
local out = {}
|
|
for _, page in ipairs(s.pages or {}) do
|
|
for _, line in ipairs(page) do out[#out + 1] = line end
|
|
end
|
|
return table.concat(out, " / ")
|
|
end
|
|
|
|
local function stepId(speech)
|
|
local cur = speech.steps and speech.steps[speech.step]
|
|
return cur and (cur.id or cur.kind) or "?"
|
|
end
|
|
|
|
-- boot flow: attract movie -> title -> menu. With a save on disk NEW GAME is
|
|
-- the second row, so land on it the same way silly_oak_intro_test does.
|
|
U.wait(5)
|
|
U.tap(game, "start")
|
|
U.wait(15)
|
|
U.tap(game, "a")
|
|
U.wait(8)
|
|
local ok, saved = pcall(function()
|
|
return require("src.core.SaveData").load() ~= nil
|
|
end)
|
|
if ok and saved then
|
|
U.tap(game, "down")
|
|
U.wait(5)
|
|
end
|
|
U.tap(game, "a")
|
|
U.wait(20)
|
|
|
|
local speech
|
|
for _ = 1, 90 do
|
|
speech = speechState()
|
|
if speech then break end
|
|
U.wait(1)
|
|
end
|
|
if not check("NEW GAME entered Oak's speech", speech ~= nil) then
|
|
U.log("top is", tostring(top()), "-- CONTINUE was picked instead")
|
|
while true do coroutine.yield() end
|
|
end
|
|
|
|
local demoIdx
|
|
for i, s in ipairs(speech.steps or {}) do
|
|
if (s.kind or "say") == "demo" then demoIdx = i break end
|
|
end
|
|
check("the step list still has a demo beat", demoIdx ~= nil)
|
|
check("the show-off front sprite loaded (" ..
|
|
tostring(speech.demoSpecies) .. ")", speech.demoPic ~= nil)
|
|
|
|
local vol = game.save and game.save.options and game.save.options.sfxVol
|
|
if vol == 0 then
|
|
U.log("sfxVol is 0: the NIDORINO cry will be silent, raise it in OPTION")
|
|
else
|
|
U.log("sfxVol", tostring(vol), "-- the cry plays as the sprite wipes in")
|
|
end
|
|
|
|
if not demoIdx then
|
|
while true do coroutine.yield() end
|
|
end
|
|
|
|
-- mash only up to the demo beat, then let the wipe finish on its own
|
|
for _ = 1, 300 do
|
|
if speech.step >= demoIdx then break end
|
|
U.tap(game, "a")
|
|
U.wait(3)
|
|
end
|
|
for _ = 1, 180 do
|
|
if speech.step == demoIdx and not speech.picReveal and isBox(top()) then
|
|
break
|
|
end
|
|
U.wait(1)
|
|
end
|
|
|
|
check("_OakSpeechText2A is up on the demo beat",
|
|
speech.step == demoIdx and isBox(top()))
|
|
local textA = boxText(top())
|
|
U.log("page A reads:", textA)
|
|
check("the mirrored pic is on screen (picFlip set, demo pic)",
|
|
speech.picFlip == true and speech.pic == speech.demoPic)
|
|
U.shot(game, DIR .. "/oak_nido_2a.png")
|
|
|
|
-- one A per page of 2A; picFlip must survive every one of them. The page
|
|
-- count is not fixed (an A during the typewriter only finishes the line), so
|
|
-- keep turning until the step moves on rather than budgeting presses.
|
|
local held = true
|
|
for _ = 1, 60 do
|
|
U.tap(game, "a")
|
|
U.wait(12)
|
|
if speech.picFlip ~= true or speech.pic ~= speech.demoPic then
|
|
held = false
|
|
break
|
|
end
|
|
if speech.step > demoIdx then break end
|
|
end
|
|
check("picFlip and pic unchanged after the page break", held)
|
|
check("the speech moved on to the pic-less step (" .. stepId(speech) .. ")",
|
|
speech.step > demoIdx)
|
|
local textB = boxText(top())
|
|
U.log("page B reads:", textB)
|
|
check("a second page is up and it is not page A",
|
|
isBox(top()) and textB ~= "" and textB ~= textA)
|
|
U.shot(game, DIR .. "/oak_nido_2b.png")
|
|
U.log("shots in", DIR)
|
|
|
|
-- put the beat back so the page break can be watched live: pop the box and
|
|
-- rewind the step counter. The wipe and the cry are both skipped on the way
|
|
-- back in -- the sprite is already standing there and it already called once,
|
|
-- so replaying them reads as NIDORINO entering twice -- leaving just page A.
|
|
for _ = 1, 8 do
|
|
if top() == speech then break end
|
|
game.stack:pop()
|
|
end
|
|
if top() == speech then
|
|
local Sound = require("src.core.Sound")
|
|
local realReveal, realCry = speech.revealPic, Sound.playCry
|
|
speech.revealPic = function(self, _, next)
|
|
self.picReveal = nil
|
|
if next then next() end
|
|
end
|
|
Sound.playCry = function() end
|
|
speech.step = demoIdx
|
|
speech:runStep(speech.steps[demoIdx])
|
|
speech.revealPic, Sound.playCry = realReveal, realCry
|
|
U.wait(30)
|
|
end
|
|
|
|
U.log("NIDORINO is standing where the wipe left it, facing LEFT with its horn")
|
|
U.log("toward screen-left, and page A is back up. Press A to turn the page:")
|
|
U.log("the sprite must not move or mirror, it stays facing left until the")
|
|
U.log("screen fades to white for the naming beat.")
|
|
|
|
while true do
|
|
coroutine.yield()
|
|
end
|
|
end
|