mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 05:32:07 -04:00
174 lines
6.3 KiB
Lua
174 lines
6.3 KiB
Lua
#!/usr/bin/env luajit
|
|
-- pokefirered/src/field_specials.c:2296 CutMoveRuinValleyCheck
|
|
-- pokefirered/src/field_specials.c:2310 CutMoveOpenDottedHoleDoor
|
|
-- pokefirered/src/fldeff_cut.c:118 SetUpFieldMove_Cut
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local failed = 0
|
|
local function check(cond, msg)
|
|
if cond then
|
|
print("[ok] " .. msg)
|
|
else
|
|
failed = failed + 1
|
|
print("[FAIL] " .. msg)
|
|
end
|
|
end
|
|
|
|
local function finish()
|
|
if failed > 0 then
|
|
print("[test] FAILED " .. failed)
|
|
os.exit(1)
|
|
end
|
|
print("[test] all passed")
|
|
os.exit(0)
|
|
end
|
|
|
|
local GameVersion = require("src.core.GameVersion")
|
|
GameVersion.set("firered")
|
|
|
|
local FieldMoves = require("src.core.game3.field_moves")
|
|
|
|
print("[test] 1. CutMoveRuinValleyCheck, ROM-free")
|
|
local RV = FieldMoves.RUIN_VALLEY
|
|
check(RV.map == "FR_SIX_ISLAND_RUIN_VALLEY", "the check is keyed on Six Island Ruin Valley")
|
|
check(RV.x == 24 and RV.y == 25 and RV.facing == "up", "at (24,25) facing north")
|
|
check(RV.flag == 0x2E3, "FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE is 0x2E3")
|
|
check(RV.doorX == 24 and RV.doorY == 24, "the door cell is map (24,24), MapGrid (31,31) less MAP_OFFSET")
|
|
check(RV.doorOpen == 0x358, "METATILE_SeviiIslands67_DottedHoleDoor_Open is 0x358")
|
|
|
|
local function rvCtx(over)
|
|
local ctx = { mapId = RV.map, x = RV.x, y = RV.y, facing = RV.facing, session = { flags = {} } }
|
|
for k, v in pairs(over or {}) do ctx[k] = v end
|
|
return ctx
|
|
end
|
|
|
|
check(FieldMoves.ruinValleyCutCheck(rvCtx()) == true, "standing on the braille tile passes")
|
|
check(FieldMoves.ruinValleyCutCheck(rvCtx({ facing = "down" })) == false, "facing south fails")
|
|
check(FieldMoves.ruinValleyCutCheck(rvCtx({ x = 23 })) == false, "one cell west fails")
|
|
check(FieldMoves.ruinValleyCutCheck(rvCtx({ y = 26 })) == false, "one cell south fails")
|
|
check(FieldMoves.ruinValleyCutCheck(rvCtx({ mapId = "FR_PALLET_TOWN" })) == false,
|
|
"another map fails")
|
|
check(FieldMoves.ruinValleyCutCheck(rvCtx({ session = { flags = { [0x2E3] = true } } })) == false,
|
|
"the flag already set fails")
|
|
|
|
local Cache = require("tests.game3_cache")
|
|
local cacheRoot = Cache.mount("scripts/events.lua", { native = true })
|
|
if not cacheRoot then
|
|
print("[skip] game3_field_cut_test (cache-backed sections): " .. tostring(Cache.reason))
|
|
finish()
|
|
end
|
|
print("[info] FireRed cache at " .. cacheRoot)
|
|
|
|
local Dataset = require("src.core.game3.dataset")
|
|
local Collision = require("src.core.game3.collision")
|
|
local Objects = require("src.core.game3.objects")
|
|
local Player = require("src.core.game3.player")
|
|
local Field = require("src.core.game3.field")
|
|
local Space = require("src.core.game3.scripting.space")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local FieldEffects = require("src.core.game3.field_effects")
|
|
local Runtime = require("src.core.game3.runtime")
|
|
|
|
local game = { data = {} }
|
|
Dataset.hydrate(game)
|
|
local session = { map = nil, flags = {}, vars = {}, party = {} }
|
|
game.session = session
|
|
Runtime.session = session
|
|
|
|
local function enterMap(mapId)
|
|
local def = game.data.maps[mapId]
|
|
if not def then return nil end
|
|
Field._game = game
|
|
Field._session = session
|
|
session.map = mapId
|
|
Field.running = true
|
|
Field.locked = false
|
|
Field.clearMetatiles()
|
|
Space.activate(nil, mapId, game, nil)
|
|
Collision.bindMap(game, mapId, def)
|
|
Objects.loadMap(game, mapId, def)
|
|
Space.runOnLoad(mapId)
|
|
return def
|
|
end
|
|
|
|
local function pumpVm(limit)
|
|
local vm = Space.vm
|
|
local n = 0
|
|
while vm and vm:isRunning() and n < (limit or 512) do
|
|
vm:tick()
|
|
n = n + 1
|
|
end
|
|
end
|
|
|
|
local function standAt(x, y, facing)
|
|
Player.moving = false
|
|
Player.progress = 0
|
|
Player.surfing = false
|
|
Player.cellX, Player.cellY = x, y
|
|
Player.targetX, Player.targetY = x, y
|
|
Player.px, Player.py = x * 16, y * 16
|
|
Player.facing = facing or "down"
|
|
end
|
|
|
|
print("[test] 2. the Dotted Hole door starts shut on Six Island Ruin Valley")
|
|
local def = enterMap(RV.map)
|
|
check(def ~= nil, RV.map .. " is in the cache")
|
|
if not def then finish() end
|
|
pumpVm()
|
|
local layout = def.midLayout
|
|
check(layout:midAt(RV.doorX, RV.doorY) == 0x357,
|
|
"(24,24) is METATILE_SeviiIslands67_DottedHoleDoor_Closed")
|
|
check(Collision.isWalkable(RV.doorX, RV.doorY) == false, "the shut door is impassable")
|
|
local warp
|
|
for _, w in ipairs(def.warps or {}) do
|
|
if w.x == RV.doorX and w.y == RV.doorY then warp = w end
|
|
end
|
|
check(warp ~= nil and tostring(warp.destMap or warp.dest) == "FR_SIX_ISLAND_DOTTED_HOLE_1F",
|
|
"the warp behind it leads to the Dotted Hole")
|
|
|
|
print("[test] 3. Cut on the braille tile picks the dotted-hole arm")
|
|
standAt(RV.x, RV.y, "up")
|
|
session.party = { { species = 1, level = 30, moves = { 15 }, hp = 30, maxHp = 30 } }
|
|
Flags.setFlag(Space.store, Space.vm and Space.vm.ctx, FieldMoves.BADGE_FLAGS.CUT, true)
|
|
local ctx = {
|
|
party = session.party,
|
|
store = Space.store,
|
|
session = session,
|
|
hasCuttableGrass = true,
|
|
}
|
|
local res = FieldMoves.fromMenu("CUT", ctx)
|
|
check(res ~= nil and res.ok == true, "Cut is allowed here")
|
|
check(res and res.action == "dotted_hole",
|
|
"the action is dotted_hole, not cut_grass (got " .. tostring(res and res.action) .. ")")
|
|
|
|
standAt(RV.x, RV.y, "down")
|
|
local res2 = FieldMoves.fromMenu("CUT", ctx)
|
|
check(res2 and res2.action == "cut_grass",
|
|
"facing south it is an ordinary Cut again (got " .. tostring(res2 and res2.action) .. ")")
|
|
|
|
print("[test] 4. executing it opens the door")
|
|
standAt(RV.x, RV.y, "up")
|
|
Field.executeFieldMove(FieldMoves.fromMenu("CUT", ctx))
|
|
check(Field.locked == true, "the field locks for the animation")
|
|
for _ = 1, 200 do FieldEffects.step() end
|
|
check(Field.locked == false, "the field unlocks when the animation ends")
|
|
local override = Field.metatileOverrideAt(RV.map, RV.doorX, RV.doorY)
|
|
check(override ~= nil and override.metatile == RV.doorOpen, "(24,24) became the open door")
|
|
check(layout:midAt(RV.doorX, RV.doorY) == RV.doorOpen, "the live layout shows the open door")
|
|
check(Collision.isWalkable(RV.doorX, RV.doorY) == true, "the doorway is now walkable")
|
|
check(Flags.getFlag(Space.store, Space.vm and Space.vm.ctx, RV.flag) == true,
|
|
"FLAG_USED_CUT_ON_RUIN_VALLEY_BRAILLE is set")
|
|
check(FieldMoves.ruinValleyCutCheck(ctx) == false, "a second Cut does not re-trigger")
|
|
|
|
print("[test] 5. the door stays open across a map reload")
|
|
enterMap("SEVII_SIX_ISLAND")
|
|
pumpVm()
|
|
local def2 = enterMap(RV.map)
|
|
pumpVm()
|
|
check(def2.midLayout:midAt(RV.doorX, RV.doorY) == RV.doorOpen,
|
|
"ON_LOAD re-opened the door from the flag")
|
|
check(Collision.isWalkable(RV.doorX, RV.doorY) == true, "and it is still walkable")
|
|
|
|
finish()
|