mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
183 lines
7.0 KiB
Lua
183 lines
7.0 KiB
Lua
-- Walking into grass with no useable POKeMON must black the player out, not
|
|
-- cancel the battle and hand the map back (#425). pokered core.asm:158-162
|
|
-- runs .checkAnyPartyAlive after the intro and jumps to HandlePlayerBlackOut
|
|
-- (core.asm:1145-1166, PlayerBlackedOutText2). Machine half also in
|
|
-- tests/parity_blackout_no_party.lua. Never under POKEPORT_SPEED: the wipe,
|
|
-- the theme change and the two text boxes come apart from each other.
|
|
-- POKEPORT_DRIVER=tests/drivers/blackout_no_party_bug425_test.lua POKEPORT_IDENTITY=bug425 POKEPORT_TOUCH=0 POKEPORT_VERSION=red love .
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local Music = require("src.core.Music")
|
|
local BattleState = require("src.battle.BattleState")
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local TextBox = require("src.render.TextBox")
|
|
local SHOT_DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
|
|
local MAP = "ROUTE_1"
|
|
local pass, fail = 0, 0
|
|
local function check(label, ok)
|
|
if ok then pass = pass + 1 else fail = fail + 1 end
|
|
U.log(ok and "PASS" or "FAIL", label)
|
|
return ok
|
|
end
|
|
|
|
local function waitFor(fn, limit)
|
|
for _ = 1, limit do
|
|
if fn() then return true end
|
|
U.wait(1)
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- every song request in order, so "the battle theme was never restored"
|
|
-- and "the map theme was never playing" read differently in the log
|
|
local songs = {}
|
|
local realPlay = Music.play
|
|
Music.play = function(data, song, loop, ctx)
|
|
songs[#songs + 1] = { song = song, frame = U.frame() }
|
|
U.log(("frame %d play %s"):format(U.frame(), tostring(song)))
|
|
return realPlay(data, song, loop, ctx)
|
|
end
|
|
local function playedAfter(song, frame)
|
|
for _, s in ipairs(songs) do
|
|
if s.song == song and s.frame >= frame then return s end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local opts = game.save.options
|
|
if (opts and opts.musicVol or 0) == 0 then
|
|
U.log("MUSIC VOLUME IS 0: the theme swap this bug is about is silent.")
|
|
U.log("Raise it in OPTION, quit and rerun; the log half still holds.")
|
|
end
|
|
if (opts and opts.sfxVol or 0) == 0 then
|
|
U.log("WARNING sfx volume is 0: the wipe and the text beeps will be")
|
|
U.log("silent too.")
|
|
end
|
|
|
|
-- MAGIKARP with SPLASH only would still be a battle; 0 HP is the state
|
|
-- under test, and money is the blackout's other visible half
|
|
game.save.party = { Pokemon.new(game.data, "MAGIKARP", 10) }
|
|
local mon = game.save.party[1]
|
|
local full = mon.stats.hp
|
|
mon.hp = 0
|
|
game.save.money = 3000
|
|
|
|
-- Route 1's first grass row. data/generated/maps.lua holds the tiles
|
|
-- (pokered data/maps/objects/Route1.asm has no grass in it), so the cell is
|
|
-- checked against the loaded map and rescanned if a map edit moved it.
|
|
local GRASS = { x = 10, y = 6 }
|
|
U.teleport(game, MAP, GRASS.x, GRASS.y, "down")
|
|
local ow = game.overworld
|
|
local function grassAt(cx, cy)
|
|
return ow.map:isGrassCell(cx, cy) and ow.map:isWalkableCell(cx, cy)
|
|
end
|
|
if not grassAt(GRASS.x, GRASS.y) then
|
|
local found
|
|
for y = 0, ow.map.heightCells - 1 do
|
|
for x = 0, ow.map.widthCells - 1 do
|
|
-- a neighbouring grass cell too, so the hand-off half below has
|
|
-- somewhere to step without leaving the patch
|
|
if grassAt(x, y) and grassAt(x + 1, y) then found = { x = x, y = y } break end
|
|
end
|
|
if found then break end
|
|
end
|
|
if found then
|
|
U.log(("(%d, %d) is not grass any more, standing on")
|
|
:format(GRASS.x, GRASS.y), found.x, found.y)
|
|
GRASS = found
|
|
U.teleport(game, MAP, found.x, found.y, "down")
|
|
ow = game.overworld
|
|
end
|
|
end
|
|
check("the player is standing in " .. MAP .. " grass",
|
|
grassAt(GRASS.x, GRASS.y))
|
|
|
|
local heal = ow:healPoint()
|
|
U.log("heal point:", heal.map, heal.x, heal.y)
|
|
local MAP_SONG = game.data.audio.mapSongs[MAP]
|
|
local HEAL_SONG = game.data.audio.mapSongs[heal.map]
|
|
local WILD_SONG = game.data.audio.battle.wild
|
|
U.log("songs:", tostring(MAP_SONG), tostring(WILD_SONG), tostring(HEAL_SONG))
|
|
|
|
-- the encounter OverworldState:checkEncounter would build for this cell
|
|
local encDef = game.data.encounters[MAP]
|
|
local slots = encDef and encDef.grass and encDef.grass.slots
|
|
check(MAP .. " has a grass encounter table", slots ~= nil and #slots > 0)
|
|
if not slots then
|
|
U.log("Nothing can be encountered here; rerun after a ROM re-import.")
|
|
while true do coroutine.yield() end
|
|
end
|
|
|
|
local start = U.frame()
|
|
local battle = BattleState.newWild(game, slots[1].species, slots[1].level)
|
|
check("the encounter starts out flagged dead (no healthy party)",
|
|
battle.dead == true)
|
|
local got
|
|
battle.onFinish = function(result)
|
|
got = result
|
|
ow:afterBattle(result, battle)
|
|
end
|
|
ow:pushBattle(battle)
|
|
check("the wipe started the battle theme",
|
|
waitFor(function() return playedAfter(WILD_SONG, start) ~= nil end, 120))
|
|
|
|
local function box()
|
|
local top = game.stack:top()
|
|
return getmetatable(top) == TextBox and top or nil
|
|
end
|
|
local shown = waitFor(function() return box() ~= nil end, 600)
|
|
check("the blackout text came up over the map", shown)
|
|
if shown then
|
|
local lines = {}
|
|
for _, page in ipairs(box().pages or {}) do
|
|
for _, line in ipairs(page) do lines[#lines + 1] = line end
|
|
end
|
|
local text = table.concat(lines, " / ")
|
|
U.log("box reads:", text)
|
|
check("it is PlayerBlackedOutText2, both paragraphs",
|
|
text:find("out of", 1, true) ~= nil
|
|
and text:find("blacked", 1, true) ~= nil)
|
|
U.wait(60)
|
|
U.shot(game, SHOT_DIR .. "/bug425_blackout.png")
|
|
U.log("captured", SHOT_DIR .. "/bug425_blackout.png")
|
|
end
|
|
|
|
-- page both paragraphs, then let the warp run
|
|
for _ = 1, 12 do
|
|
if not box() then break end
|
|
U.tap(game, "a")
|
|
U.wait(20)
|
|
end
|
|
local warped = waitFor(function()
|
|
return game.overworld and game.overworld.map
|
|
and game.overworld.map.id == heal.map
|
|
and not game.overworld.transitioning
|
|
end, 900)
|
|
check("the player was warped to the heal point map " .. heal.map, warped)
|
|
check("onFinish reported a loss, not a cancelled battle", got == "lose")
|
|
check("the party was revived", mon.hp == full)
|
|
check("half the money is gone (3000 -> 1500)", game.save.money == 1500)
|
|
if HEAL_SONG then
|
|
check("the heal point's own theme replaced the battle theme",
|
|
playedAfter(HEAL_SONG, start) ~= nil)
|
|
end
|
|
local stillBattle = songs[#songs] and songs[#songs].song == WILD_SONG
|
|
check("the battle theme is not what is still playing", not stillBattle)
|
|
U.log(("%d passed, %d failed"):format(pass, fail))
|
|
|
|
-- re-arm for the hand-off: same 0 HP party, back in the grass
|
|
mon.hp = 0
|
|
game.save.money = 3000
|
|
U.teleport(game, MAP, GRASS.x, GRASS.y, "down")
|
|
U.log("MAGIKARP is at 0 HP again and you are back in the Route 1 grass.")
|
|
U.log("Step around until an encounter rolls: the wipe and the battle theme,")
|
|
U.log("then the two boxes over the map with the route theme back under them,")
|
|
U.log("then the warp to Pallet Town. Landing back in the grass with the")
|
|
U.log("battle music looping, over and over, is the bug.")
|
|
|
|
while true do
|
|
coroutine.yield()
|
|
end
|
|
end
|