Files
gen1recomp/tests/drivers/gold_whirlpool_block_bug1862_test.lua
T

142 lines
5.5 KiB
Lua

-- #1862: the whirlpool must stay on screen for the whole surf wash.
-- DisappearWhirlpool blanks hBGMapMode before the redraw, plays the sound and
-- only then buffers the screen -- engine/events/overworld.asm:1150-1165,
-- engine/events/field_moves.asm:5-10. No POKEPORT_SPEED: audio runs on its
-- own real-time accumulator and the ordering is the whole point.
-- POKEPORT_IDENTITY=c10-gold POKEPORT_GAME=gold POKEPORT_TOUCH=0 POKEPORT_DRIVER=tests/drivers/gold_whirlpool_block_bug1862_test.lua POKEPORT_SHOT_DIR=/tmp/gold-bug1862 love .
local U = require("tests.drivers.util")
local FieldMoves = require("src.world.gen2.FieldMoves")
local Mon = require("src.battle.gen2.Mon")
local Permissions = require("src.world.gen2.Permissions")
-- data/generated/maps.lua, ROUTE_41: whirlpools at (22,12), (42,24), (6,30)
-- and (28,48). Stand one cell north of the first and face it.
local MAP = "ROUTE_41"
local WHIRL = { x = 22, y = 12 }
return function(game)
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-bug1862"
local fails, lines = 0, {}
local function claim(ok, text)
if not ok then fails = fails + 1 end
lines[#lines + 1] = (ok and "PASS " or "FAIL ") .. text
return ok
end
local function report()
for _, line in ipairs(lines) do U.log(line) end
U.log(("%d checks, %d failed"):format(#lines, fails))
end
U.wait(45)
local world = game.world
if not (world and world.map) then
U.log("FAIL the gold world never booted, nothing to drain")
while true do coroutine.yield() end
end
local vol = game.save.options and game.save.options.sfxVol
claim(vol ~= 0, ("SFX VOL is %s"):format(tostring(vol)))
if vol == 0 then
U.log("SFX VOL is ZERO, so the wash this is timed against is inaudible;")
U.log("turn it up in OPTION before judging anything by ear.")
end
local badges = game.save.player.badges or {}
game.save.player.badges = badges
for _, badge in pairs(FieldMoves.BADGE) do badges[badge] = true end
local swimmer = Mon.new(game.data, "LAPRAS", 30,
{ moves = { { id = "SURF" }, { id = "WHIRLPOOL" } } })
claim(swimmer ~= nil, "a LAPRAS that knows SURF and WHIRLPOOL")
game.save.party = { swimmer }
world:applyPlayerState(FieldMoves.PLAYER_SURF)
world:setMap(MAP, WHIRL.x, WHIRL.y - 1, "down")
U.wait(15)
world.noWildEncounters = true
local ctx = world:fieldContext()
local facing = Permissions.isWhirlpool(ctx.facingColl)
if not facing then
-- A re-import moved it: take any whirlpool with open water above it.
local def = world.maps[MAP]
for y = 1, (def.height or 0) * 2 - 1 do
for x = 0, (def.width or 0) * 2 - 1 do
if not facing and Permissions.isWhirlpool(world.map:cellCollision(x, y))
and Permissions.isWater(world.map:cellCollision(x, y - 1)) then
WHIRL.x, WHIRL.y = x, y
world:setMap(MAP, x, y - 1, "down")
world:applyPlayerState(FieldMoves.PLAYER_SURF)
U.wait(10)
ctx = world:fieldContext()
facing = Permissions.isWhirlpool(ctx.facingColl)
U.log(("note: using the whirlpool at (%d,%d)"):format(x, y))
end
end
end
end
claim(facing, ("facing the whirlpool at (%d,%d) on %s"):format(
WHIRL.x, WHIRL.y, MAP))
local blocks = world.maps[MAP] and world.maps[MAP].blocks
local index = ctx.facingBlockIndex
local before = blocks and index and blocks[index]
claim(before ~= nil, "and the block behind it is readable")
if not (facing and before) then
report()
U.log("nothing to drive; stopping rather than faking the moment")
while true do coroutine.yield() end
end
U.shot(game, out .. "/01-facing.png")
local function tap(button, gap)
table.insert(game.input.pressQueue, button)
game.input.state[button] = true
coroutine.yield()
game.input.state[button] = false
for _ = 1, (gap or 8) do coroutine.yield() end
end
-- A into the whirlpool, then A through the ask box (YES is the default) and
-- the USED WHIRLPOOL line.
for _ = 1, 24 do
if world.fieldMove and world.fieldMove.phase == "whirlpoolsfx" then break end
tap("a")
end
claim(world.fieldMove and world.fieldMove.phase == "whirlpoolsfx",
"the drain reached PlayWhirlpoolSound")
claim(blocks[index] == before,
"the whirlpool is still in the block buffer as the wash starts")
U.shot(game, out .. "/02-wash-starts.png")
local swapped, phaseFrames = nil, 0
for _ = 1, 300 do
if world.fieldMove and world.fieldMove.phase == "whirlpoolsfx" then
phaseFrames = phaseFrames + 1
if blocks[index] ~= before and not swapped then swapped = phaseFrames end
if phaseFrames == 6 then U.shot(game, out .. "/03-mid-wash.png") end
end
if not world:busy() then break end
coroutine.yield()
end
claim(swapped == nil,
"and it stayed there for every frame of the wash")
claim(blocks[index] ~= before,
"the block was swapped once the wash ended")
claim(phaseFrames > 0 and phaseFrames < 180,
("the wash ended on its own after %d frames"):format(phaseFrames))
U.wait(4)
U.shot(game, out .. "/04-drained.png")
report()
if fails > 0 then
U.log("a FAIL above means the run is not showing what it claims to")
end
U.log("what right looks like: the whirlpool keeps spinning through the whole")
U.log("surf wash and only pops out of the water when the sound has finished.")
U.log("water where the whirlpool was while the wash is still playing is the")
U.log("bug; a whirlpool still there after control comes back is the overshoot.")
U.log("the pad is yours -- the other whirlpools are further south.")
while true do coroutine.yield() end
end