Files
gen1recomp/tests/drivers/crystal_fly_flash_bug2020_test.lua
T

251 lines
7.6 KiB
Lua

-- ../pokecrystal/engine/pokemon/mon_menu.asm:609
-- ../pokecrystal/engine/events/overworld.asm:556
-- ../pokecrystal/engine/pokegear/pokegear.asm:2026
-- ../pokecrystal/home/map.asm:1927
-- POKEPORT_IDENTITY=crystal-aug31 POKEPORT_GAME=crystal POKEPORT_TOUCH=0 \
-- POKEPORT_DRIVER=tests/drivers/crystal_fly_flash_bug2020_test.lua \
-- POKEPORT_SHOT_DIR=/tmp/crystal-fly2020
local U = require("tests.drivers.util")
local FieldMoves = require("src.world.gen2.FieldMoves")
local Mon = require("src.battle.gen2.Mon")
local FLY_SPECIES = "PIDGEOTTO"
return function(game)
local out = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/crystal-fly2020"
local fails = 0
local function ok(cond, msg)
if cond then
print("[fly2020] ok " .. msg)
else
fails = fails + 1
print("[fly2020] FAIL " .. msg)
end
return cond
end
local function tap(btn) U.tap(game, btn) U.wait(3) end
local function top() return game.stack:top() end
local function topId()
local state = top()
return state and state.screenId or nil
end
U.wait(45)
local world = game.world
local save, data = game.save, game.data
if not ok(world and world.map, "booted into the overworld") then
error("fly2020: no world")
end
save.player = save.player or {}
if type(save.player.badges) ~= "table" then save.player.badges = {} end
save.player.badges.STORM = true
save.engineFlags = save.engineFlags or {}
for _, row in ipairs(FieldMoves.FLYPOINTS) do
save.engineFlags[row.flag] = true
end
local flyer = Mon.new(data, FLY_SPECIES, 24)
table.remove(flyer.moves, 1)
Mon.learnMove(flyer, "FLY", data)
save.party = { flyer }
world.mapScenes = world.mapScenes or {}
world.mapScenes.NEW_BARK_TOWN = 1
world:setMap("NEW_BARK_TOWN", 9, 8, "down")
U.wait(15)
ok(world.map.id == "NEW_BARK_TOWN", "standing in New Bark Town")
for _ = 1, 240 do
if not world:busy() then break end
U.wait(2)
end
local function waitFor(id, limit)
for _ = 1, limit or 120 do
if topId() == id then return true end
U.wait(1)
end
return topId() == id
end
local function openFlyRow()
waitFor(nil, 240)
local menu
for _ = 1, 10 do
tap("start")
menu = top()
if menu and menu.screenId == "Gen2StartMenu" then break end
U.wait(6)
end
if not ok(menu and menu.screenId == "Gen2StartMenu",
"START opened the menu") then
error("fly2020: no start menu")
end
for _ = 1, 10 do
if menu.list:current().value == "pokemon" then break end
tap("down")
end
tap("a")
waitFor("Gen2PartyMenu", 90)
local party = top()
if not ok(party and party.screenId == "Gen2PartyMenu",
"POKeMON opened the party list") then
error("fly2020: no party list")
end
tap("a")
local sub = party.submenu
if not ok(sub ~= nil, "A opened the action submenu") then
error("fly2020: no submenu")
end
local flyRow
for index, item in ipairs(sub.items) do
if item.id == "FLY" then flyRow = index end
end
if not ok(flyRow ~= nil, "which lists FLY") then
error("fly2020: the submenu has no FLY row")
end
for _ = 1, #sub.items do
if sub.index == flyRow then break end
tap("down")
end
return party
end
local party = openFlyRow()
U.tap(game, "a")
local empties, blankFrames, seenBlank, shotBlank = 0, 0, false, false
local underneath = true
for _ = 1, 90 do
U.wait(1)
local id = topId()
if id == nil then empties = empties + 1 end
if id == "Gen2BlankScreen" then
seenBlank = true
blankFrames = blankFrames + 1
local states = game.stack.states or {}
if states[#states - 1] ~= party then underneath = false end
if not shotBlank then
shotBlank = true
U.shot(game, out .. "/01-blank-in.png")
end
end
if id == "Gen2Pokegear" then break end
end
ok(seenBlank, ("_FlyMap blanked to white first (%d frame(s))")
:format(blankFrames))
ok(empties == 0,
("no live overworld frame leaked on the way in (%d empty stack frame(s))")
:format(empties))
ok(underneath, "and the party list stayed underneath the blank")
local picker = top()
if not ok(picker and picker.screenId == "Gen2Pokegear" and picker.fly,
"then the destination map took over") then
error("fly2020: no picker")
end
U.wait(6)
U.shot(game, out .. "/02-fly-map.png")
tap("b")
-- engine/pokegear/pokegear.asm:2062-2078
for _ = 1, 120 do
if topId() == "Gen2PartyMenu" then break end
U.wait(1)
end
ok(topId() == "Gen2PartyMenu", ("B returned to the party list (top is %s)")
:format(tostring(topId())))
ok(world.queuedFieldMove == nil, "with no fly queued behind it")
U.shot(game, out .. "/03-b-back-to-party.png")
for _ = 1, 6 do
if topId() == nil then break end
tap("b")
waitFor(nil, 60)
end
U.wait(10)
party = openFlyRow()
U.tap(game, "a")
for _ = 1, 90 do
U.wait(1)
if topId() == "Gen2Pokegear" then break end
end
if not ok(topId() == "Gen2Pokegear", "the picker is back up") then
error("fly2020: no picker on the second pass")
end
tap("up")
U.wait(6)
U.tap(game, "a")
local held, whiteHeld, sawRamp, shotWhite, shotRamp = 0, 0, false, false, false
local leaked, startedEarly, sawHold = 0, false, false
for _ = 1, 240 do
U.wait(1)
if topId() ~= nil then leaked = leaked + 1 end
local ms = world.mapSetup
if ms and ms.phase == "in" and (ms.wait or 0) > 2 then sawHold = true end
if world.fade == "white" and (world.fadeLevel or 0) >= 1 then
whiteHeld = whiteHeld + 1
if world.flyAnim then startedEarly = true end
if not shotWhite then
shotWhite = true
U.shot(game, out .. "/04-exit-white.png")
end
end
if ms and ms.phase == "in" and (ms.step or 9) < 4 then
sawRamp = true
if not shotRamp and (ms.step or 9) <= 2 then
shotRamp = true
U.shot(game, out .. "/05-fade-in.png")
end
end
held = held + 1
if world.flyAnim then break end
end
ok(leaked == 0,
("the menus were gone the moment the spawn was taken (%d menu frame(s))")
:format(leaked))
ok(whiteHeld > 0 and sawHold,
("ExitAllMenus put the white up and held it (%d frame(s))")
:format(whiteHeld))
ok(not startedEarly, "and FlyFromAnim waited for it")
ok(sawRamp, "FadeInFromWhite ramped back in")
ok(world.flyAnim ~= nil and world.flyAnim.phase == "from",
("then the take-off ran, %d frame(s) after the press"):format(held))
U.shot(game, out .. "/06-takeoff.png")
for _ = 1, 1800 do
U.wait(1)
if world.flyAnim == nil and world.map.id ~= "NEW_BARK_TOWN" then break end
end
U.wait(20)
ok(world.map.id ~= "NEW_BARK_TOWN",
("landed on %s"):format(tostring(world.map.id)))
U.shot(game, out .. "/07-landed.png")
U.log("flew out of New Bark Town from the party list (#2020). judge these:")
U.log("01-blank-in.png -- a WHITE screen, edge to edge, on the way into the")
U.log("town map. no overworld tiles, no sliver of the party list.")
U.log("03-b-back-to-party.png -- B on the town map must land back on the")
U.log("party list, not in the overworld.")
U.log("04-exit-white.png and 05-fade-in.png -- the exit is white again and")
U.log("then fades in; the bird only lifts off after that (06-takeoff.png).")
U.log("shots are in " .. out .. ".")
if fails > 0 then
U.log(("%d assertion(s) failed above -- read those before the pictures.")
:format(fails))
end
U.log("the party still holds a flyer and the badge, so FLY again whenever")
U.log("you want another look. the controls are yours.")
while true do
coroutine.yield()
end
end