mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
197 lines
7.4 KiB
Lua
197 lines
7.4 KiB
Lua
local U = require("tests.drivers.util")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_importer_round2"
|
|
|
|
local failures = 0
|
|
local function result(ok, label)
|
|
print((ok and "PASS " or "FAIL ") .. label)
|
|
if not ok then failures = failures + 1 end
|
|
return ok
|
|
end
|
|
|
|
local function finish()
|
|
if failures == 0 then
|
|
print("PASS game3_importer_round2")
|
|
love.event.quit(0)
|
|
else
|
|
print("FAIL game3_importer_round2 failures=" .. failures)
|
|
love.event.quit(1)
|
|
end
|
|
end
|
|
|
|
local function is_hidden(ev)
|
|
return ev.type == "hidden_item" or ev.kind == 7
|
|
end
|
|
|
|
-- pokefirered/src/itemfinder.c:354
|
|
local function find_edge_item(game)
|
|
local maps = game.data and game.data.maps or {}
|
|
local Map = require("src.core.game3.map")
|
|
local names = {}
|
|
for id in pairs(maps) do names[#names + 1] = id end
|
|
table.sort(names)
|
|
for _, id in ipairs(names) do
|
|
local def = maps[id]
|
|
for _, conn in ipairs(require("src.core.game3.connections").each(def)) do
|
|
local dir = conn.dir
|
|
local nid = conn.map
|
|
local ndef = maps[nid]
|
|
if ndef and (dir == "north" or dir == "up") then
|
|
for _, ev in ipairs(ndef.bgEvents or {}) do
|
|
if is_hidden(ev) and not ev.underfoot then
|
|
local L = Map.ensureMidLayout(game, nid, ndef)
|
|
local off = tonumber(conn.offset) or 0
|
|
local fromBottom = L and (L.height - 1 - ev.y)
|
|
if fromBottom and fromBottom <= 2 then
|
|
return id, nid, ev, ev.x + off, fromBottom
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function run(game)
|
|
for _ = 1, 900 do
|
|
if game.phase == "boot" and game.boot then break end
|
|
U.wait(1)
|
|
end
|
|
game:_handleBootAction({ action = "new_game", name = "RED" })
|
|
U.wait(240)
|
|
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Map = require("src.core.game3.map")
|
|
local Player = require("src.core.game3.player")
|
|
local Field = require("src.core.game3.field")
|
|
local Message = require("src.ui.game3.message")
|
|
local Itemfinder = require("src.core.game3.itemfinder")
|
|
local Audio = require("src.core.game3.audio")
|
|
local Pokemon = require("src.core.game3.pokemon")
|
|
local Party = require("src.core.game3.party")
|
|
local HallOfFame = require("src.ui.game3.hall_of_fame")
|
|
local RomText = require("src.core.game3.rom_text")
|
|
|
|
local session = Runtime.getSession()
|
|
if not result(session ~= nil, "new game reached the field") then return end
|
|
|
|
local ses = {}
|
|
local playSe = Audio.playSe
|
|
Audio.playSe = function(id, ...) ses[#ses + 1] = id return playSe(id, ...) end
|
|
|
|
result(RomText.plain("gText_PlayerScurriedToCenter", { playerName = "RED" })
|
|
:find("RED scurried to a POKéMON CENTER,", 1, true) ~= nil, "whiteout text comes from the ROM cache")
|
|
result(Runtime and require("src.core.game3.scripting.space").ensureBundle().scripts.EventScript_AfterWhiteOutHeal ~= nil,
|
|
"EventScript_AfterWhiteOutHeal is a ROM script")
|
|
|
|
local mapId, nid, ev, itemX, fromBottom = find_edge_item(game)
|
|
if result(mapId ~= nil, "found a hidden item just across a north map connection") then
|
|
local px, py = itemX, 1
|
|
Map.load(nil, game, mapId, { x = px, y = py, facing = "up" })
|
|
Player.cellX, Player.cellY, Player.targetX, Player.targetY = px, py, px, py
|
|
Player.px, Player.py, Player.facing = px * 16, py * 16, "up"
|
|
session.x, session.y, session.map = px, py, mapId
|
|
U.wait(60)
|
|
local ok, _, _, info = Field.useItemfinder(session, true)
|
|
result(ok and info and info.y < 0, string.format("itemfinder answers for %s item in %s (dy=%s)",
|
|
tostring(ev.item), tostring(nid), tostring(info and info.y)))
|
|
U.wait(6)
|
|
result(#Itemfinder.sprites() > 0, "itemfinder arrow sprite is up")
|
|
result(ses[#ses] == 65, "SE_ITEMFINDER played")
|
|
U.shot(game, DIR .. "/r2_itemfinder_arrow_connected_map.png")
|
|
local shown = false
|
|
for _ = 1, 300 do
|
|
if Message.isOpen() and tostring(Message.currentPage()):find("ITEMFINDER's responding", 1, true) then
|
|
shown = true
|
|
break
|
|
end
|
|
U.wait(1)
|
|
end
|
|
for _ = 1, 300 do
|
|
if not shown or Message.isWaiting() then break end
|
|
U.wait(1)
|
|
end
|
|
result(shown and Message.isWaiting(), "gText_ItemfinderResponding printed after the dings")
|
|
if shown and Message.isWaiting() then U.shot(game, DIR .. "/r2_itemfinder_responding_text.png") end
|
|
for _ = 1, 600 do
|
|
if not Message.isOpen() then break end
|
|
if Message.isWaiting() then U.tap(game, "a") else U.wait(1) end
|
|
end
|
|
U.wait(2)
|
|
result(not Message.isOpen() and not Field.locked and not Itemfinder.isActive(),
|
|
"field unlocked after the itemfinder message")
|
|
end
|
|
|
|
do
|
|
local Objects = require("src.core.game3.objects")
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local FieldMoves = require("src.core.game3.field_moves")
|
|
local FieldEffects = require("src.core.game3.field_effects")
|
|
Map.load(nil, game, "FR_SEAFOAM_ISLANDS_B3F", { x = 6, y = 16, facing = "down" })
|
|
session.x, session.y, session.facing = 6, 16, "down"
|
|
Player.moving = false
|
|
Player.cellX, Player.cellY, Player.targetX, Player.targetY = 6, 16, 6, 16
|
|
Player.px, Player.py, Player.facing = 6 * 16, 16 * 16, "down"
|
|
U.wait(60)
|
|
Flags.setFlag(Space.store, Space.vm and Space.vm.ctx, FieldMoves.SYS_FLAGS.USE_STRENGTH, true)
|
|
for _ = 1, 20 do
|
|
U.hold(game, "down", 1)
|
|
if Player.boulderPush then break end
|
|
end
|
|
result(Player.boulderPush ~= nil, "boulder push started")
|
|
U.wait(3)
|
|
local dust
|
|
for _, a in ipairs(FieldEffects._anims or {}) do
|
|
if a.kind == "dust" then dust = a end
|
|
end
|
|
result(dust ~= nil and FieldEffects.loadSheet("ground_impact_dust", 16, 8, 3) ~= nil,
|
|
"boulder push dust uses the ROM ground_impact_dust sheet")
|
|
U.shot(game, DIR .. "/r2_boulder_push_dust.png")
|
|
for _ = 1, 60 do
|
|
if not Player.boulderPush then break end
|
|
U.wait(1)
|
|
end
|
|
end
|
|
|
|
session.party = {}
|
|
local tid = (tonumber(session.trainerId) or 0) % 65536
|
|
local sid = (tonumber(session.secretId) or 0) % 65536
|
|
Party.giveMon(session, 6, 62)
|
|
Party.giveMon(session, 201, 40)
|
|
local shinyMon, unownD = session.party[1], session.party[2]
|
|
shinyMon.personality = bit.bxor(tid, sid) * 65536
|
|
shinyMon.isShiny = nil
|
|
unownD.personality = 0xFC000003
|
|
unownD.isShiny = nil
|
|
result(Pokemon.isShiny(shinyMon), "the Charizard is shiny for this trainer")
|
|
result(not Pokemon.isShiny(unownD), "the Unown is not shiny")
|
|
result(Pokemon.monPicSpecies(unownD) == 415, "Unown personality 0xFC000003 picks SPECIES_UNOWN_D")
|
|
local shinyPic = Pokemon.monFrontPic(shinyMon)
|
|
local plainPic = Pokemon.frontPic(6)
|
|
result(shinyPic and plainPic and shinyPic.image ~= plainPic.image, "shiny Charizard uses the shiny front pic")
|
|
result(Pokemon.monIcon(unownD) ~= Pokemon.icon(201), "Unown D uses its own menu icon")
|
|
|
|
HallOfFame.start({ session = session, dontSave = true, warp = false })
|
|
local applause = false
|
|
for _ = 1, 4000 do
|
|
if HallOfFame.phase() == "applause" and #(HallOfFame._confetti or {}) >= 20 then
|
|
applause = true
|
|
break
|
|
end
|
|
U.wait(1)
|
|
end
|
|
result(applause, "Hall of Fame applause spawned confetti sprites")
|
|
U.shot(game, DIR .. "/r2_hof_confetti_shiny_unown.png")
|
|
HallOfFame.close()
|
|
U.wait(10)
|
|
|
|
Audio.playSe = playSe
|
|
end
|
|
|
|
return function(game)
|
|
local ok, err = pcall(run, game)
|
|
if not ok then result(false, "driver error: " .. tostring(err)) end
|
|
finish()
|
|
end
|