Files
gen1recomp/tests/game3_directional_impassable_test.lua

181 lines
7.5 KiB
Lua

#!/usr/bin/env luajit
-- MB_IMPASSABLE_* (0x30-0x37) edge walls: pokefirered/src/metatile_behavior.c:546
-- and pokefirered/src/event_object_movement.c:4889.
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 MB = {
EAST = 0x30, WEST = 0x31, NORTH = 0x32, SOUTH = 0x33,
NORTHEAST = 0x34, NORTHWEST = 0x35, SOUTHEAST = 0x36, SOUTHWEST = 0x37,
}
print("[test] 1. the classifier keeps a directional metatile's own walkability")
local ScriptColl = require("src.core.game3.scripting.collision")
for name, beh in pairs(MB) do
local openByte = ScriptColl.fromCell(721, 0, beh, "indoor")
local shutByte = ScriptColl.fromCell(721, 1, beh, "indoor")
check(openByte ~= 0x07 and openByte ~= 0xff,
string.format("MB_IMPASSABLE_%s with mapColl 0 stays walkable (0x%02X)", name, openByte))
check(shutByte == 0x07,
string.format("MB_IMPASSABLE_%s with mapColl 1 is solid (0x%02X)", name, shutByte))
end
print("[test] 2. the four blocked-edge predicates")
local Collision = require("src.core.game3.collision")
local PREDS = {
isNorthBlocked = { MB.NORTH, MB.NORTHEAST, MB.NORTHWEST },
isSouthBlocked = { MB.SOUTH, MB.SOUTHEAST, MB.SOUTHWEST },
isEastBlocked = { MB.EAST, MB.NORTHEAST, MB.SOUTHEAST },
isWestBlocked = { MB.WEST, MB.NORTHWEST, MB.SOUTHWEST },
}
for name, want in pairs(PREDS) do
local fn = Collision[name]
if type(fn) ~= "function" then
check(false, "Collision." .. name .. " exists")
else
local set = {}
for _, beh in ipairs(want) do set[beh] = true end
local wrong = 0
for beh = 0x00, 0xFF do
if (fn(beh) and true or false) ~= (set[beh] == true) then wrong = wrong + 1 end
end
check(wrong == 0, name .. " matches pret over every behavior byte, wrong=" .. wrong)
check(fn(nil) ~= true, name .. "(nil) is false")
end
end
print("[test] 3. directionallyImpassable pairs leave-tile and enter-tile")
if type(Collision.directionallyImpassable) ~= "function" then
check(false, "Collision.directionallyImpassable exists")
else
local behs = {}
local realBehavior = Collision.behavior
Collision.behavior = function(x, y) return behs[x .. "," .. y] end
local function D(fx, fy, tx, ty, dir)
return Collision.directionallyImpassable(fx, fy, tx, ty, dir) and true or false
end
behs["1,1"] = MB.NORTH
check(D(1, 1, 1, 0, "up"), "leaving an IMPASSABLE_NORTH tile northward is blocked")
check(not D(1, 1, 1, 2, "down"), "leaving an IMPASSABLE_NORTH tile southward is allowed")
check(not D(1, 1, 2, 1, "right"), "leaving an IMPASSABLE_NORTH tile eastward is allowed")
check(not D(1, 1, 0, 1, "left"), "leaving an IMPASSABLE_NORTH tile westward is allowed")
behs = { ["1,1"] = MB.NORTH }
check(D(1, 0, 1, 1, "down"), "entering an IMPASSABLE_NORTH tile from the north is blocked")
check(not D(1, 2, 1, 1, "up"), "entering an IMPASSABLE_NORTH tile from the south is allowed")
behs = { ["1,1"] = MB.SOUTHWEST }
check(D(1, 1, 1, 2, "down"), "IMPASSABLE_SOUTHWEST blocks leaving southward")
check(D(1, 1, 0, 1, "left"), "IMPASSABLE_SOUTHWEST blocks leaving westward")
check(not D(1, 1, 1, 0, "up"), "IMPASSABLE_SOUTHWEST allows leaving northward")
check(not D(1, 1, 2, 1, "right"), "IMPASSABLE_SOUTHWEST allows leaving eastward")
behs = { ["1,1"] = MB.SOUTHWEST }
check(D(1, 0, 1, 1, "down") == false, "IMPASSABLE_SOUTHWEST does not seal its north edge")
check(D(1, 2, 1, 1, "up"), "entering an IMPASSABLE_SOUTHWEST tile from the south is blocked")
check(D(0, 1, 1, 1, "right"), "entering an IMPASSABLE_SOUTHWEST tile from the west is blocked")
behs = {}
check(not D(1, 1, 1, 0, "up"), "a plain tile blocks nothing")
check(not D(nil, nil, 1, 0, nil), "a missing direction blocks nothing")
Collision.behavior = realBehavior
end
print("[test] 4. Victory Road 1F cliff band")
local Cache = require("tests.game3_cache")
local cacheRoot = Cache.mount("scripts/events.lua", { native = true })
if not cacheRoot then
print("[skip] game3_directional_impassable_test map checks: " .. tostring(Cache.reason))
finish()
end
print("[info] FireRed cache at " .. cacheRoot)
local Dataset = require("src.core.game3.dataset")
local game = { data = {} }
Dataset.hydrate(game)
local MAP = "FR_VICTORY_ROAD_1F"
local def = game.data.maps[MAP]
check(def ~= nil, MAP .. " is in the cache")
if not def then finish() end
Collision.bindMap(game, MAP, def)
check(Collision.behavior(14, 5) == MB.NORTH, "(14,5) carries MB_IMPASSABLE_NORTH")
check(Collision.behavior(14, 4) == 0x08, "(14,4) above it is MB_CAVE")
check(Collision.behavior(14, 6) == 0x08, "(14,6) below it is MB_CAVE")
if Collision.cell(14, 5) == 0x07 then
print("[skip] the mounted cache was baked before the classifier change; "
.. "re-import to run the walkability checks")
finish()
end
check(Collision.canEnter(game, 14, 5, { fromX = 14, fromY = 6, dir = "up" }) == true,
"the player can step up onto the cliff band at (14,5)")
check(Collision.canEnter(game, 14, 6, { fromX = 14, fromY = 5, dir = "down" }) == true,
"and step back down off it")
check(Collision.canEnter(game, 15, 5, { fromX = 14, fromY = 5, dir = "right" }) == true,
"and walk along the band eastward")
local okUp, whyUp = Collision.canEnter(game, 14, 4, { fromX = 14, fromY = 5, dir = "up" })
check(okUp == false and whyUp == "tile",
"walking north off the band is refused (" .. tostring(whyUp) .. ")")
local okDown, whyDown = Collision.canEnter(game, 14, 5, { fromX = 14, fromY = 4, dir = "down" })
check(okDown == false and whyDown == "tile",
"dropping south onto the band from above is refused (" .. tostring(whyDown) .. ")")
check(Collision.canEnter(game, 14, 4, { fromX = 14, fromY = 3, dir = "down" }) == true,
"the cave floor above the band is otherwise open")
print("[test] 5. mapColl still decides which directional cells are solid")
local function tally(mapId)
local d = game.data.maps[mapId]
if not d then return nil end
Collision.bindMap(game, mapId, d)
local walk, solid = 0, 0
for y = 0, Collision._heightCells - 1 do
for x = 0, Collision._widthCells - 1 do
local beh = Collision.behavior(x, y)
if beh and beh >= 0x30 and beh <= 0x37 then
if Collision.cell(x, y) == 0x07 then solid = solid + 1 else walk = walk + 1 end
end
end
end
return walk, solid
end
local vrWalk, vrSolid = tally(MAP)
check(vrWalk == 20 and vrSolid == 19,
string.format("Victory Road 1F: 20 walkable / 19 solid, got %s / %s",
tostring(vrWalk), tostring(vrSolid)))
local emWalk, emSolid = tally("FR_MT_EMBER_SUMMIT_PATH_2F")
check(emWalk == 87 and emSolid == 177,
string.format("Mt Ember Summit Path 2F: 87 walkable / 177 solid, got %s / %s",
tostring(emWalk), tostring(emSolid)))
print("[test] 6. Mt Ember Summit Path 2F seals every north edge in the block")
local EM = "FR_MT_EMBER_SUMMIT_PATH_2F"
if game.data.maps[EM] then
Collision.bindMap(game, EM, game.data.maps[EM])
check(Collision.behavior(25, 44) == MB.NORTH, "(25,44) carries MB_IMPASSABLE_NORTH")
check(Collision.cell(25, 44) ~= 0x07, "(25,44) is walkable rock, not a wall")
check(Collision.canEnter(game, 25, 43, { fromX = 25, fromY = 44, dir = "up" }) == false,
"climbing north inside the Mt Ember block is refused")
check(Collision.canEnter(game, 26, 44, { fromX = 25, fromY = 44, dir = "right" }) == true,
"walking east along the Mt Ember block is allowed")
end
finish()