Files
gen1recomp/tests/game3_stitchmap_heal_test.lua

179 lines
8.3 KiB
Lua

#!/usr/bin/env luajit
-- pokefirered/src/heal_location.c:62 SetWhiteoutRespawnWarpAndHealerNpc
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 eq(a, b, msg)
check(a == b, string.format("%s (%s == %s)", msg, tostring(a), tostring(b)))
end
local Cache = require("tests.game3_cache")
local CACHE_ROOT = Cache.mountOrSkip("stitchmap heal locations", "map_tree/census.json")
local Dataset = require("src.core.game3.dataset")
local MapCatalog = require("src.import.gba.map_catalog")
local HealLocations = require("src.core.game3.heal_locations")
-- pokefirered/src/heal_location.c:65
local PRET = {
[1] = { pret = "PalletTown_PlayersHouse_1F", x = 8, y = 5, healer = 1 },
[2] = { pret = "ViridianCity_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[3] = { pret = "PewterCity_PokemonCenter_1F", x = 7, y = 4, healer = 3 },
[4] = { pret = "CeruleanCity_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[5] = { pret = "LavenderTown_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[6] = { pret = "VermilionCity_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[7] = { pret = "CeladonCity_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[8] = { pret = "FuchsiaCity_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[9] = { pret = "CinnabarIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[10] = { pret = "IndigoPlateau_PokemonCenter_1F", x = 13, y = 12, healer = 2 },
[11] = { pret = "SaffronCity_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[12] = { pret = "Route4_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[13] = { pret = "Route10_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[14] = { pret = "OneIsland_PokemonCenter_1F", x = 5, y = 4, healer = 1 },
[15] = { pret = "TwoIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[16] = { pret = "ThreeIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[17] = { pret = "FourIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[18] = { pret = "FiveIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[19] = { pret = "SevenIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
[20] = { pret = "SixIsland_PokemonCenter_1F", x = 7, y = 4, healer = 1 },
}
local LAST_ID = 20
print("[test] 1. every heal destination is a map the cache actually has")
local maps = Dataset.buildMaps()
local missing = 0
for id = 1, LAST_ID do
local loc = HealLocations.get(id)
if type(loc) ~= "table" or type(loc.map) ~= "string" then
missing = missing + 1
check(false, "heal location " .. id .. " has no row")
elseif maps[loc.map] == nil then
missing = missing + 1
check(false, "heal location " .. id .. " loads " .. loc.map .. ", which the cache has no def for")
end
end
eq(missing, 0, "heal destinations that do not exist in the cache")
eq(HealLocations.get(0), nil, "HEAL_LOCATION_NONE has no row")
eq(HealLocations.get(LAST_ID + 1), nil, "an out-of-range heal location has no row")
print("[test] 2. the rows are pret's whiteout warp, tile and healer")
for id = 1, LAST_ID do
local want = PRET[id]
local wantMap = MapCatalog.pretToEngine(want.pret)
local loc = HealLocations.get(id) or {}
eq(loc.map, wantMap, "heal location " .. id .. " map (" .. want.pret .. ")")
eq(loc.x, want.x, "heal location " .. id .. " x")
eq(loc.y, want.y, "heal location " .. id .. " y")
eq(loc.healerLocalId, want.healer, "heal location " .. id .. " healer localId")
end
print("[test] 3. setrespawn stamps the session the whiteout reads")
local session = { healMap = "FR_PLAYERS_HOUSE_2F" }
HealLocations.normalizeSession(session)
eq(session.healMap, "FR_PLAYERS_HOUSE_1F", "the bedroom default migrates to Mom's floor")
eq(session.healX, 8, "migrated heal x")
eq(session.healY, 5, "migrated heal y")
check(HealLocations.applyToSession(session, 12), "setrespawn HEAL_LOCATION_ROUTE4 applies")
eq(session.healMap, MapCatalog.pretToEngine("Route4_PokemonCenter_1F"), "session heal map after setrespawn")
eq(session.healX, 7, "session heal x after setrespawn")
eq(session.healY, 4, "session heal y after setrespawn")
check(maps[session.healMap] ~= nil, "the whiteout map loader has a def for the session heal map")
print("[test] 4. the baked importer table wins, missing rows fall back to source")
if type(HealLocations.load) ~= "function" then
check(false, "HealLocations.load reads the baked region_map/heal_locations.lua")
else
local FIXTURE_ROOT = "tests/fixtures/stitchmap_heal"
local function cacheOf(src)
local files = src and { [FIXTURE_ROOT .. "/" .. HealLocations.BAKED_REL] = src } or {}
return {
read = function(_, rel) return files[rel] end,
exists = function(_, rel) return files[rel] ~= nil end,
}
end
local keyed = table.concat({
"return { whiteout = {",
" [2] = { map = 'FR_VIRIDIAN_CITY_POKEMON_CENTER_1F', x = 7, y = 4, healerLocalId = 1 },",
" [12] = { map = 'FR_ROUTE_4_POKEMON_CENTER_1F', x = 7, y = 4, healerLocalId = 1 },",
"} }",
}, "\n")
eq(HealLocations.load(cacheOf(keyed), FIXTURE_ROOT), 2, "baked rows installed from the cache")
local two = HealLocations.get(2)
check(two ~= HealLocations.BY_ID[2], "id 2 now comes from the baked table, not the source table")
eq(two.map, "FR_VIRIDIAN_CITY_POKEMON_CENTER_1F", "baked id 2 map")
eq(HealLocations.get(3), HealLocations.BY_ID[3], "an id the baked table omits falls back to source")
eq(HealLocations.get(12).map, "FR_ROUTE_4_POKEMON_CENTER_1F", "baked id 12 map")
local list = table.concat({
"return { whiteout = {",
" { id = 12, map = 'FR_ROUTE_4_POKEMON_CENTER_1F', x = 7, y = 4, healerLocalId = 1 },",
" { id = 3, map = 'FR_PEWTER_CITY_POKEMON_CENTER_1F', x = 7, y = 4, healerLocalId = 3 },",
"} }",
}, "\n")
eq(HealLocations.load(cacheOf(list), FIXTURE_ROOT), 2, "a list of rows carrying their own id installs")
eq(HealLocations.get(12).map, "FR_ROUTE_4_POKEMON_CENTER_1F", "list row 1 is keyed by its id, not its position")
eq(HealLocations.get(3).healerLocalId, 3, "list row 2 is keyed by its id, not its position")
eq(HealLocations.get(1), HealLocations.BY_ID[1], "list position 1 does not overwrite HEAL_LOCATION_PALLET_TOWN")
-- pokefirered/src/data/heal_locations.h:6 sHealLocations
local flyRows = table.concat({
"return {",
" [1] = { map = 'FR_PALLET_TOWN', x = 6, y = 8 },",
" [2] = { map = 'FR_VIRIDIAN_CITY', x = 26, y = 27 },",
"}",
}, "\n")
eq(HealLocations.load(cacheOf(flyRows), FIXTURE_ROOT), 0, "rows outside the whiteout key install nothing")
eq(HealLocations.get(2), HealLocations.BY_ID[2], "the outdoor fly landing never replaces the whiteout center")
local flyKeyed = table.concat({
"return { fly = {",
" [2] = { map = 'FR_VIRIDIAN_CITY', x = 26, y = 27 },",
"} }",
}, "\n")
eq(HealLocations.load(cacheOf(flyKeyed), FIXTURE_ROOT), 0, "a fly table beside the whiteout one is ignored here")
eq(HealLocations.get(2), HealLocations.BY_ID[2], "id 2 still whiteouts to the center")
eq(HealLocations.load(cacheOf(nil), FIXTURE_ROOT), 0, "a cache without the key installs nothing")
eq(HealLocations.get(2), HealLocations.BY_ID[2], "with no baked table every id comes from source")
eq(HealLocations.get(12).map, "FR_ROUTE_4_POKEMON_CENTER_1F", "the source table is the corrected one")
HealLocations.invalidate()
end
print("[test] 5. the cache's own baked table, when it has one")
if type(HealLocations.load) == "function" then
local diskCache = Cache.cache()
if not diskCache:exists(CACHE_ROOT .. "/" .. HealLocations.BAKED_REL) then
print("[skip] this cache predates the heal-location bake")
else
eq(HealLocations.load(diskCache, CACHE_ROOT), LAST_ID, "every baked row installs from the cache")
for id = 1, LAST_ID do
local want = PRET[id]
local loc = HealLocations.get(id) or {}
check(loc ~= HealLocations.BY_ID[id], "heal location " .. id .. " comes from the cache")
eq(loc.map, MapCatalog.pretToEngine(want.pret), "baked heal location " .. id .. " map")
eq(loc.x, want.x, "baked heal location " .. id .. " x")
eq(loc.y, want.y, "baked heal location " .. id .. " y")
eq(loc.healerLocalId, want.healer, "baked heal location " .. id .. " healer localId")
end
end
HealLocations.invalidate()
end
if failed == 0 then
print("ALL STITCHMAP HEAL TESTS PASSED")
os.exit(0)
end
print(failed .. " CHECK(S) FAILED")
os.exit(1)