mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-29 07:00:55 -04:00
250 lines
9.9 KiB
Lua
250 lines
9.9 KiB
Lua
local U = require("tests.drivers.util")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/em_field_objects"
|
|
|
|
local failures = 0
|
|
local function check(ok, label)
|
|
print((ok and "PASS " or "FAIL ") .. label)
|
|
if not ok then failures = failures + 1 end
|
|
return ok
|
|
end
|
|
|
|
local function finish()
|
|
print((failures == 0 and "PASS" or "FAIL") .. " em_field_objects failures=" .. failures)
|
|
love.event.quit(failures == 0 and 0 or 1)
|
|
end
|
|
|
|
local function try(label, fn)
|
|
local ok, err = xpcall(fn, debug.traceback)
|
|
if not ok then print("[driver] " .. label .. " error: " .. tostring(err)) end
|
|
return ok
|
|
end
|
|
|
|
return function(game)
|
|
for _ = 1, 900 do
|
|
if game.phase == "boot" and game.boot then break end
|
|
U.wait(1)
|
|
end
|
|
if not check(game.boot ~= nil, "boot reached") then return finish() end
|
|
try("new_game", function()
|
|
game:_handleBootAction({ action = "new_game", name = "BRENDAN", gender = 0 })
|
|
end)
|
|
U.wait(30)
|
|
|
|
local Runtime = require("src.core.game3.runtime")
|
|
local Map = require("src.core.game3.map")
|
|
local Player = require("src.core.game3.player")
|
|
local Warp = require("src.core.game3.warp")
|
|
local Message = require("src.ui.game3.message")
|
|
local Objects = require("src.core.game3.objects")
|
|
local OwSprites = require("src.core.game3.ow_sprites")
|
|
local FieldEffects = require("src.core.game3.field_effects")
|
|
local Doors = require("src.core.game3.doors")
|
|
local Collision = require("src.core.game3.collision")
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local Field = require("src.core.game3.field")
|
|
local Encounters = require("src.core.game3.encounters")
|
|
local Audio = require("src.core.game3.audio")
|
|
local SE = require("src.core.game3.se_ids")
|
|
local C = require("src.core.game3.constants").of("emerald")
|
|
local T = Flags.forVersion("emerald")
|
|
|
|
local session = Runtime.getSession()
|
|
if not check(session ~= nil and session.version == "emerald", "Emerald session is live") then return finish() end
|
|
Encounters.onStep = function() return nil end
|
|
|
|
local played = {}
|
|
local playSe = Audio.playSe
|
|
Audio.playSe = function(id, ...)
|
|
played[#played + 1] = id
|
|
return playSe(id, ...)
|
|
end
|
|
|
|
local function mapNow()
|
|
local s = Runtime.getSession()
|
|
return s and s.map
|
|
end
|
|
|
|
local function settle(frames)
|
|
for _ = 1, frames or 600 do
|
|
local busy = Warp.isBusy() or (Message.isOpen and Message.isOpen())
|
|
if not busy then break end
|
|
if Message.isOpen and Message.isOpen() then U.tap(game, "b") end
|
|
U.wait(1)
|
|
end
|
|
end
|
|
|
|
local function goTo(mapId, x, y, facing)
|
|
settle()
|
|
local ok = try("Map.load " .. mapId, function()
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = facing })
|
|
end)
|
|
local s = Runtime.getSession()
|
|
if s then s.x, s.y, s.facing = x, y, facing end
|
|
Player.reset(x, y, facing)
|
|
U.wait(40)
|
|
return ok
|
|
end
|
|
|
|
local VARS = T.VAR_IDS
|
|
Flags.setVar(Space.store, nil, VARS.VAR_LITTLEROOT_TOWN_STATE, 4)
|
|
Flags.setVar(Space.store, nil, VARS.VAR_ROUTE101_STATE, 3)
|
|
Flags.setFlag(Space.store, nil, T.IDS.FLAG_RESCUED_BIRCH, true)
|
|
|
|
goTo("EM_LITTLEROOT_TOWN", 14, 12, "up")
|
|
check(mapNow() == "EM_LITTLEROOT_TOWN", "Littleroot Town loads")
|
|
local avatars = OwSprites.avatars()
|
|
check(avatars ~= nil and OwSprites.playerGraphicsId(game) == OwSprites.avatarGraphicsId("NORMAL", false),
|
|
"player draws Brendan from sPlayerAvatarGfxIds (gfx " .. tostring(OwSprites.playerGraphicsId(game)) .. ")")
|
|
local kid = Objects.find(1)
|
|
check(kid ~= nil and kid.movement == "WALK", "Littleroot kid (localId 1) wanders (" .. tostring(kid and kid.movement) .. ")")
|
|
check(kid ~= nil and OwSprites.get(kid.graphicsId) ~= nil,
|
|
"kid sprite is Emerald gfx " .. tostring(kid and kid.graphicsId))
|
|
local momFlag = Objects._byId[4] and Objects._byId[4].flag or 752
|
|
Flags.setFlag(Space.store, nil, momFlag, false)
|
|
Objects.syncFlagVisibility(momFlag, false)
|
|
U.wait(4)
|
|
local mom = Objects.find(4)
|
|
check(mom ~= nil and mom.visible and not mom.hidden, "Mom (localId 4) shows once her flag clears")
|
|
local seen, start = {}, kid and (kid.cellX .. "," .. kid.cellY .. kid.facing)
|
|
local changed = false
|
|
for _ = 1, 420 do
|
|
U.wait(1)
|
|
if kid then
|
|
local key = kid.cellX .. "," .. kid.cellY .. kid.facing
|
|
if key ~= start then changed = true end
|
|
if kid.moving and not seen.moving then
|
|
seen.moving = true
|
|
U.still(game, DIR .. "/01_littleroot_kid_walking.png")
|
|
end
|
|
end
|
|
end
|
|
check(changed, "Littleroot kid wandered (" .. tostring(start) .. " -> " .. tostring(kid and (kid.cellX .. "," .. kid.cellY .. kid.facing)) .. ")")
|
|
U.still(game, DIR .. "/02_littleroot_mom_kid.png")
|
|
Flags.setFlag(Space.store, nil, momFlag, true)
|
|
Objects.syncFlagVisibility(momFlag, true, true)
|
|
|
|
goTo("EM_LITTLEROOT_TOWN", 5, 9, "up")
|
|
local entry = Doors.getDoorEntryAt("EM_LITTLEROOT_TOWN", 5, 8)
|
|
check(entry and entry.tile == "littleroot" and entry.file == "littleroot__petalburg.rgba",
|
|
"door manifest resolves the Littleroot door by tileset pair (" .. tostring(entry and entry.file) .. ")")
|
|
for i = #played, 1, -1 do played[i] = nil end
|
|
local shots = {}
|
|
U.hold(game, "up", 1)
|
|
for _ = 1, 120 do
|
|
local a = Doors._activeAnim
|
|
if a and a.tile and not shots[a.frame] and (a.frame == 1 or a.frame == 2) then
|
|
shots[a.frame] = true
|
|
U.still(game, DIR .. string.format("/03_door_open_frame%d.png", a.frame))
|
|
end
|
|
if mapNow() ~= "EM_LITTLEROOT_TOWN" then break end
|
|
U.wait(1)
|
|
end
|
|
local sheet = Doors._sheets["littleroot__petalburg.rgba"]
|
|
check(type(sheet) == "table" and sheet.frames == 3, "Littleroot door sheet loaded (3 frames)")
|
|
check(shots[1] and shots[2], "door animated through frames 1 and 2")
|
|
local door = false
|
|
for _, id in ipairs(played) do if id == C:song("SE_DOOR") then door = true end end
|
|
check(door, "door open played SE_DOOR by name (" .. tostring(C:song("SE_DOOR")) .. ")")
|
|
settle()
|
|
U.wait(30)
|
|
check(mapNow() == "EM_LITTLEROOT_TOWN_BRENDANS_HOUSE_1F", "door warp lands in Brendan's house (" .. tostring(mapNow()) .. ")")
|
|
|
|
goTo("EM_OLDALE_TOWN", 10, 10, "up")
|
|
local n, drawn = 0, 0
|
|
for _, eo in ipairs(Objects.forDraw()) do
|
|
n = n + 1
|
|
if OwSprites.get(eo.graphicsId) then drawn = drawn + 1 end
|
|
end
|
|
check(n >= 3 and drawn == n, string.format("Oldale NPCs draw Emerald sprites (%d/%d)", drawn, n))
|
|
U.wait(60)
|
|
U.still(game, DIR .. "/04_oldale_npcs.png")
|
|
|
|
goTo("EM_ROUTE102", 15, 10, "left")
|
|
local gx, gy
|
|
local L = Collision._mapDef and Collision._mapDef.midLayout
|
|
for y = 1, (L and L.height or 20) - 2 do
|
|
for x = 1, (L and L.width or 20) - 2 do
|
|
if not gx and Collision.isGrass(x, y) and not Collision.isGrass(x, y + 1)
|
|
and Collision.canEnter(game, x, y + 1, {}) and not Objects.at(x, y + 1) and not Objects.at(x, y) then
|
|
gx, gy = x, y
|
|
end
|
|
end
|
|
end
|
|
check(gx ~= nil, "found a tall grass cell on Route 102 (" .. tostring(gx) .. "," .. tostring(gy) .. ")")
|
|
if gx then
|
|
goTo("EM_ROUTE102", gx, gy + 1, "up")
|
|
U.hold(game, "up", 1)
|
|
U.wait(7)
|
|
local fx = FieldEffects._fx
|
|
check(fx and fx.cx == gx and fx.cy == gy, "stepping into grass starts the tall grass effect")
|
|
check(type(FieldEffects._sheets.tall_grass) == "table", "tall grass sheet loaded from field_effects/objects.lua")
|
|
U.still(game, DIR .. "/05_route102_tall_grass_rustle.png")
|
|
U.wait(30)
|
|
U.still(game, DIR .. "/06_route102_in_grass.png")
|
|
end
|
|
|
|
Flags.setFlag(Space.store, nil, T.IDS.FLAG_SYS_B_DASH, true)
|
|
goTo("EM_ROUTE101", 10, 10, "up")
|
|
local zig = Objects.find(4)
|
|
local zx, zy, stepped = zig and zig.cellX, zig and zig.cellY, 0
|
|
for _ = 1, 40 do
|
|
U.wait(1)
|
|
if zig and zig.moving then stepped = stepped + 1 end
|
|
end
|
|
check(zig and zig.movement == "IN_PLACE" and zig.facing == "left" and stepped > 20
|
|
and zig.cellX == zx and zig.cellY == zy,
|
|
string.format("Route 101 Zigzagoon jogs in place left (%s %s, %d moving frames)",
|
|
tostring(zig and zig.movement), tostring(zig and zig.facing), stepped))
|
|
check(Player.canDash(), "B-dash allowed on Route 101 with FLAG_SYS_B_DASH")
|
|
game.input.state.b = true
|
|
U.hold(game, "up", 5)
|
|
local runFrame = Player.runPose and Player.runPose()
|
|
local sprite = OwSprites.get(OwSprites.playerGraphicsId(game))
|
|
local frame = sprite and OwSprites.pose(sprite, Player.facing, 1, Player.stepFlip, { running = runFrame })
|
|
check(Player.running and Player.stepFrames == 8, "running step is 8 frames")
|
|
check(frame == 14 or frame == 15 or frame == 10, "Emerald run north frame (" .. tostring(frame) .. ")")
|
|
U.still(game, DIR .. "/07_route101_running.png")
|
|
game.input.state.b = false
|
|
U.wait(20)
|
|
|
|
session.party = {}
|
|
local Party = require("src.core.game3.party")
|
|
Party.giveMon(session, C:id("species", "SPECIES_TREECKO"), 5)
|
|
local trainerKey
|
|
goTo("EM_ROUTE102", 25, 13, "down")
|
|
local spotted, approached, started
|
|
for _ = 1, 400 do
|
|
U.wait(1)
|
|
local t = Objects.find(3)
|
|
for _, a in ipairs(FieldEffects._anims) do
|
|
if a.kind == "emote" and a.rse and not spotted and a.timer >= 12 then
|
|
spotted = true
|
|
U.still(game, DIR .. "/08_route102_trainer_exclamation.png")
|
|
end
|
|
end
|
|
if t and t.moving and spotted and not approached then
|
|
approached = true
|
|
U.still(game, DIR .. "/09_route102_trainer_approach.png")
|
|
end
|
|
trainerKey = trainerKey or (Space.vm and Space.vm:isRunning() and Space.vm._scriptKey)
|
|
if trainerKey and not started then
|
|
started = true
|
|
U.wait(30)
|
|
U.still(game, DIR .. "/10_route102_trainer_intro.png")
|
|
break
|
|
end
|
|
end
|
|
local tr = Objects.find(3)
|
|
check(spotted, "Route 102 trainer (localId 3) shows the Emerald ! icon")
|
|
check(approached, "trainer walks toward the player")
|
|
check(tr and tr.cellY == 14, "trainer stops next to the player (" .. tostring(tr and tr.cellY) .. ")")
|
|
check(trainerKey == tr.scriptKey, "trainer script starts (" .. tostring(trainerKey) .. " want " .. tostring(tr and tr.scriptKey) .. ")")
|
|
if Space.vm and Space.vm:isRunning() then
|
|
Space.vm:halt(true)
|
|
Field.unlock()
|
|
end
|
|
|
|
finish()
|
|
end
|