mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 16:31:05 +02:00
149 lines
5.9 KiB
Lua
149 lines
5.9 KiB
Lua
-- Manual check that the Surfing Pikachu minigame background is the
|
|
-- ROM's metatile scroller, not the old procedural stand-in (#726).
|
|
-- The stand-in tiled wave-face foam tiles ($02/$07) over the whole sea
|
|
-- and drew the swell as two LOVE ellipses, which read as zigzag noise
|
|
-- with white blobs. The fix ports SurfingMinigame_BGMetatileTable, the
|
|
-- WavePattern columns and the .WaveFunctions state table from
|
|
-- ../pokeyellow/engine/minigame/surfing_pikachu.asm; this driver
|
|
-- machine-checks the transcribed tables and the ride heights, then
|
|
-- parks a human in front of the water for the part only eyes can judge.
|
|
-- Needs a Yellow cache in the active identity (a sandboxed
|
|
-- POKEPORT_IDENTITY starts empty and would sit on the launcher).
|
|
-- SHOT_DIR=/tmp/shots POKEPORT_VERSION=yellow POKEPORT_TOUCH=0 POKEPORT_DRIVER=tests/drivers/surfing_bg_bug726_test.lua love .
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local SurfingMinigame = require("src.ui.SurfingMinigame")
|
|
|
|
local function check(label, ok)
|
|
U.log(ok and "PASS" or "FAIL", label)
|
|
return ok
|
|
end
|
|
|
|
-- table integrity first, it needs no ROM state at all. surf_1a is
|
|
-- ripped as 65 tiles (src/import/RomExtractor.lua), so every tile id
|
|
-- a metatile names must be 0..64, every pattern entry must name a
|
|
-- metatile, and every wave state must name a pattern with plausible
|
|
-- ride heights (the asm range is FLAT_WATER_Y $74 down to -6 tiles).
|
|
local ok = true
|
|
for id, mt in pairs(SurfingMinigame.BG_METATILES) do
|
|
for i = 1, 4 do
|
|
if type(mt[i]) ~= "number" or mt[i] < 0 or mt[i] > 64 then
|
|
U.log("metatile", id, "slot", i, "has bad tile id", tostring(mt[i]))
|
|
ok = false
|
|
end
|
|
end
|
|
end
|
|
check("every metatile tile id lands inside the 65-tile surf_1a sheet", ok)
|
|
|
|
ok = true
|
|
for id, pat in pairs(SurfingMinigame.WAVE_PATTERNS) do
|
|
if #pat ~= 8 then ok = false U.log("pattern", id, "is not 8 rows") end
|
|
for i = 1, 8 do
|
|
if not SurfingMinigame.BG_METATILES[pat[i]] then
|
|
U.log("pattern", id, "row", i, "names missing metatile",
|
|
tostring(pat[i]))
|
|
ok = false
|
|
end
|
|
end
|
|
end
|
|
check("every wave pattern row names a real metatile", ok)
|
|
|
|
ok = true
|
|
for id, step in pairs(SurfingMinigame.WAVE_STEPS) do
|
|
if not SurfingMinigame.WAVE_PATTERNS[step[1]] then
|
|
U.log("wave state", id, "names missing pattern", tostring(step[1]))
|
|
ok = false
|
|
end
|
|
for i = 2, 3 do
|
|
if step[i] < 116 - 6 * 8 or step[i] > 116 then
|
|
U.log("wave state", id, "ride height", step[i], "out of range")
|
|
ok = false
|
|
end
|
|
end
|
|
end
|
|
check("every wave state names a real pattern with sane ride heights", ok)
|
|
|
|
-- pokeyellow data/maps/objects/SummerBeachHouse.asm: the Surfin' Dude
|
|
-- is object_event 2, 3, so (2, 2) facing down talks to him. He only
|
|
-- offers the run to a party Pikachu that knows SURF.
|
|
game.save.party = { Pokemon.new(game.data, "PIKACHU", 50) }
|
|
game.save.party[1].moves = { { id = "SURF", pp = 15 } }
|
|
U.teleport(game, "SUMMER_BEACH_HOUSE", 2, 2, "down")
|
|
U.wait(5)
|
|
|
|
-- mash A through the pitch and the YES into the game itself
|
|
local mg
|
|
for _ = 1, 300 do
|
|
local top = game.stack:top()
|
|
if top and top.seaY then mg = top break end
|
|
U.tap(game, "a")
|
|
U.wait(4)
|
|
end
|
|
check("the minigame opened", mg ~= nil)
|
|
if not mg then
|
|
U.log("could not reach the minigame; nothing more to show")
|
|
while true do coroutine.yield() end
|
|
end
|
|
|
|
-- the run opens on prefilled flat water: every visible column should
|
|
-- be the open-water pattern, whose bottom rows are metatile $01
|
|
-- (tile $0b everywhere), and Pikachu should sit on the flat waterline
|
|
ok = true
|
|
for c = 0, 10 do
|
|
local col = mg.cols[c]
|
|
if not (col and col.pat[8] == 0x01 and col.hl == 116) then ok = false end
|
|
end
|
|
check("the opening sea is flat open water, pattern 00 all the way", ok)
|
|
check("Pikachu's ride line starts on the flat waterline",
|
|
mg:seaY(68) == 100)
|
|
U.shot(game, DIR .. "/bug726_1_flat.png")
|
|
|
|
-- paddle up and ride until the generator has rolled some swells; the
|
|
-- chooser leaves flat water only on a nonzero roll, so give it room
|
|
for _ = 1, 8 do U.tap(game, "a") U.wait(3) end
|
|
local sawSwell, seaTracks = false, true
|
|
for _ = 1, 1500 do
|
|
if mg.phase ~= "ride" and mg.phase ~= "air" then break end
|
|
for c, col in pairs(mg.cols) do
|
|
if col.hl < 116 then sawSwell = true end
|
|
end
|
|
-- the ride height must always come from the column under Pikachu
|
|
local tile = math.floor((mg.distance + 68) / 8)
|
|
local col = mg.cols[math.floor(tile / 2)]
|
|
if col then
|
|
local want = (tile % 2 == 0 and col.hl or col.hr) - 16
|
|
if mg:seaY(68) ~= want then seaTracks = false end
|
|
end
|
|
if sawSwell and mg.distance > 400 then break end
|
|
U.wait(1)
|
|
if (U.frame() % 5) == 0 then U.tap(game, "a") end
|
|
end
|
|
check("the wave generator produced swells (ride heights above flat)",
|
|
sawSwell)
|
|
check("seaY always follows the generated column heights", seaTracks)
|
|
U.shot(game, DIR .. "/bug726_2_swell.png")
|
|
|
|
-- one jump for the air shot, then hand it over
|
|
if mg.phase == "ride" then
|
|
U.tap(game, "up")
|
|
U.hold(game, "right", 20)
|
|
U.shot(game, DIR .. "/bug726_3_air.png")
|
|
end
|
|
|
|
U.log("shots in", DIR, "- bug726_1_flat, bug726_2_swell, bug726_3_air")
|
|
U.log("What to look for: the open sea is the flat speckled water tile,")
|
|
U.log("not a diagonal zigzag field; no white ellipse blobs and no loose")
|
|
U.log("blue squares floating on the surface; swells build from the left,")
|
|
U.log("crest with foam and flatten out again; Pikachu sits on the wave")
|
|
U.log("at every point of the swell; the HP strip sits in the bottom band")
|
|
U.log("over unbroken white. The game is still live: keep riding to the")
|
|
U.log("goal and the sand should slide in under the coast-in before the")
|
|
U.log("results card.")
|
|
|
|
while true do
|
|
coroutine.yield()
|
|
end
|
|
end
|