Files
gen1recomp/tests/drivers/game3_field_dotted_hole.lua
bryanthaboi dee935a4ea CLOSES #2430
2026-09-23 11:58:32 -04:00

221 lines
7.6 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_field_dotted_hole"
-- pokefirered/src/field_specials.c:2296 CutMoveRuinValleyCheck
local RUIN_VALLEY = "FR_SIX_ISLAND_RUIN_VALLEY"
local DOTTED_1F = "FR_SIX_ISLAND_DOTTED_HOLE_1F"
local SAPPHIRE_ROOM = "FR_SIX_ISLAND_DOTTED_HOLE_SAPPHIRE_ROOM"
-- pokefirered/include/constants/flags.h:766
local FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE = 0x2E3
-- pokefirered/include/constants/metatile_labels.h:206
local DOOR_CLOSED, DOOR_OPEN = 0x357, 0x358
local DESCENT = {
{ map = DOTTED_1F, from = { 6, 9 }, hole = { 6, 5 } },
{ map = "FR_SIX_ISLAND_DOTTED_HOLE_B1F", hole = { 6, 1 } },
{ map = "FR_SIX_ISLAND_DOTTED_HOLE_B2F", hole = { 1, 5 } },
{ map = "FR_SIX_ISLAND_DOTTED_HOLE_B3F", hole = { 11, 5 } },
{ map = "FR_SIX_ISLAND_DOTTED_HOLE_B4F", hole = { 6, 9 } },
}
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 field_dotted_hole")
love.event.quit(0)
else
print("FAIL field_dotted_hole failures=" .. failures)
love.event.quit(1)
end
end
return function(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 Space = require("src.core.game3.scripting.space")
local Flags = require("src.core.game3.scripting.flags")
local Player = require("src.core.game3.player")
local Field = require("src.core.game3.field")
local Collision = require("src.core.game3.collision")
local FieldMoves = require("src.core.game3.field_moves")
local session = Runtime.getSession()
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
local function ctx() return Space.vm and Space.vm.ctx end
local function place(x, y, facing)
Player.moving = false
Player.progress = 0
Player.cellX, Player.cellY = x, y
Player.px, Player.py = x * 16, y * 16
Player.targetX, Player.targetY = x, y
Player.facing = facing
if game.session then
game.session.x, game.session.y, game.session.facing = x, y, facing
end
end
local function goTo(id, x, y, facing)
Map.load(nil, game, id, { x = x, y = y, facing = facing or "down" })
place(x, y, facing or "down")
U.wait(60)
end
local function walk(dir)
local sx, sy = Player.cellX, Player.cellY
for _ = 1, 30 do
U.hold(game, dir, 1)
if Player.moving then break end
end
for _ = 1, 90 do
if not Player.moving then break end
U.wait(1)
end
U.wait(2)
return Player.cellX ~= sx or Player.cellY ~= sy
end
local function walkTo(tx, ty, limit)
local startMap = Space.mapId
local detour = "left"
for _ = 1, limit or 60 do
if Space.mapId ~= startMap then return false end
if Player.cellX == tx and Player.cellY == ty then return true end
local primary, secondary
if Player.cellY ~= ty then
primary = (Player.cellY < ty) and "down" or "up"
if Player.cellX ~= tx then secondary = (Player.cellX < tx) and "right" or "left" end
else
primary = (Player.cellX < tx) and "right" or "left"
end
local moved = walk(primary)
if not moved and secondary then moved = walk(secondary) end
if not moved then
moved = walk(detour)
detour = (detour == "left") and "right" or "left"
end
if not moved and Space.mapId == startMap then return false end
if Space.vm and Space.vm:isRunning() then U.wait(30) end
end
return Player.cellX == tx and Player.cellY == ty
end
local function midAt(mapId, x, y)
local def = game.data and game.data.maps and game.data.maps[mapId]
local layout = def and def.midLayout
return layout and layout:midAt(x, y) or nil
end
local party = session.party
if type(party) == "table" and type(party[1]) == "table" then
party[1].level = 50
party[1].moves = { 15 }
end
Flags.setFlag(Space.store, ctx(), FieldMoves.BADGE_FLAGS.CUT, true)
-- pokefirered/data/maps/FourIsland_IcefallCave_Back/scripts.inc:83
Flags.setFlag(Space.store, ctx(), 0x8E, true)
session.repelSteps = 250
goTo(RUIN_VALLEY, 24, 26, "up")
result(Space.mapId == RUIN_VALLEY, "stood in Ruin Valley, map=" .. tostring(Space.mapId))
result(Flags.getFlag(Space.store, ctx(), FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE) == false,
"FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE starts clear")
result(midAt(RUIN_VALLEY, 24, 24) == DOOR_CLOSED, "the Dotted Hole door starts shut")
result(Collision.isWalkable(24, 24) == false, "and blocks the way in")
U.shot(game, DIR .. "/field_dotted_hole_01_door_shut.png")
result(walk("up"), "walked onto the braille tile at (24,25)")
result(Player.cellX == 24 and Player.cellY == 25,
"standing at (" .. Player.cellX .. "," .. Player.cellY .. ") facing " .. Player.facing)
if Space.vm and Space.vm:isRunning() then
for _ = 1, 40 do
U.tap(game, "a")
U.wait(6)
if not (Space.vm and Space.vm:isRunning()) then break end
end
place(24, 25, "up")
end
-- pokefirered/src/fldeff_cut.c:118 SetUpFieldMove_Cut
local res = FieldMoves.fromMenu("CUT", {
party = session.party,
store = Space.store,
session = session,
})
result(res ~= nil and res.action == "dotted_hole",
"Cut here is the dotted-hole arm (" .. tostring(res and res.action) .. ")")
Field.executeFieldMove(res)
for _ = 1, 1200 do
U.wait(1)
if not Field.locked then break end
end
print("[driver] after cut locked=" .. tostring(Field.locked) .. " flag=" ..
tostring(Flags.getFlag(Space.store, ctx(), FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE)))
for _ = 1, 30 do
U.tap(game, "a")
U.wait(4)
local Message = package.loaded["src.ui.game3.message"]
if not (Message and Message.isOpen and Message.isOpen()) then break end
end
result(Flags.getFlag(Space.store, ctx(), FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE) == true,
"the braille flag is set")
result(midAt(RUIN_VALLEY, 24, 24) == DOOR_OPEN, "the door metatile is the open one")
result(Collision.isWalkable(24, 24) == true, "the doorway is walkable")
U.shot(game, DIR .. "/field_dotted_hole_02_door_open.png")
result(walk("up"), "walked into the doorway")
for _ = 1, 60 do
U.wait(4)
if Space.mapId == DOTTED_1F then break end
end
result(Space.mapId == DOTTED_1F, "the warp led into the Dotted Hole, map=" .. tostring(Space.mapId))
U.wait(120)
U.shot(game, DIR .. "/field_dotted_hole_03_inside.png")
for i, floor in ipairs(DESCENT) do
if Space.mapId ~= floor.map then
result(false, "expected to be on " .. floor.map .. ", am on " .. tostring(Space.mapId))
break
end
local reached = walkTo(floor.hole[1], floor.hole[2], 30)
if not reached then
U.log("could not reach the hole on " .. floor.map ..
", stopped at (" .. Player.cellX .. "," .. Player.cellY .. ")")
end
for _ = 1, 90 do
U.wait(4)
if Space.mapId ~= floor.map then break end
end
result(Space.mapId ~= floor.map,
"fell out of " .. floor.map .. " into " .. tostring(Space.mapId))
if i == #DESCENT then
result(Space.mapId == SAPPHIRE_ROOM,
"the last hole drops into the Sapphire room (" .. tostring(Space.mapId) .. ")")
end
end
if Space.mapId == SAPPHIRE_ROOM then
walkTo(7, 8, 20)
U.wait(20)
U.shot(game, DIR .. "/field_dotted_hole_04_sapphire.png")
end
finish()
end