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

134 lines
5.6 KiB
Lua

#!/usr/bin/env luajit
-- pokefirered/src/region_map.c:828 sMapFlyDestinations
-- pokefirered/src/region_map.c:4022 SetFlyWarpDestination
package.path = "./?.lua;./?/init.lua;" .. package.path
package.loaded["src.core.game3.rom_text"] = {
plain = function(key) return key end, box = function(key) return key end,
ascii = function(key) return key end, has = function() return true end,
key = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
at = function(n, i, j) return j and (n .. "[" .. i .. "][" .. j .. "]") or (n .. "[" .. i .. "]") end,
count = function() return 0 end, list = function() return {} end,
lazy = function(map) return setmetatable({}, { __index = function(_, k) return map[k] end }) end,
}
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 Field = require("src.core.game3.field")
local FieldMoves = require("src.core.game3.field_moves")
-- pokefirered/src/region_map.c:829
local FLYABLE = {
"MAPSEC_PALLET_TOWN", "MAPSEC_VIRIDIAN_CITY", "MAPSEC_PEWTER_CITY",
"MAPSEC_CERULEAN_CITY", "MAPSEC_LAVENDER_TOWN", "MAPSEC_VERMILION_CITY",
"MAPSEC_CELADON_CITY", "MAPSEC_FUCHSIA_CITY", "MAPSEC_CINNABAR_ISLAND",
"MAPSEC_INDIGO_PLATEAU", "MAPSEC_SAFFRON_CITY", "MAPSEC_ROUTE_4_POKECENTER",
"MAPSEC_ROUTE_10_POKECENTER", "MAPSEC_ONE_ISLAND", "MAPSEC_TWO_ISLAND",
"MAPSEC_THREE_ISLAND", "MAPSEC_FOUR_ISLAND", "MAPSEC_FIVE_ISLAND",
"MAPSEC_SIX_ISLAND", "MAPSEC_SEVEN_ISLAND",
}
print("[test] 2. the menu arm")
local outdoors = { mapType = FieldMoves.MAP_TYPES.CITY, party = {}, store = { flags = {} } }
outdoors.store.flags[FieldMoves.BADGE_FLAGS.FLY] = true
local res = FieldMoves.fromMenu("FLY", outdoors)
check(res.ok == true and res.action == "fly", "Fly outdoors returns action fly")
local indoors = { mapType = FieldMoves.MAP_TYPES.INDOOR, party = {}, store = outdoors.store }
check(FieldMoves.fromMenu("FLY", indoors).ok == false, "Fly indoors is refused")
local noBadge = { mapType = FieldMoves.MAP_TYPES.CITY, party = {}, store = { flags = {} } }
check(FieldMoves.fromMenu("FLY", noBadge).ok == false, "Fly without the THUNDERBADGE is refused")
local Cache = require("tests.game3_cache")
local cacheRoot = Cache.mount("scripts/events.lua", { native = true })
if not cacheRoot then
print("[skip] game3_field_fly_test (cache-backed sections): " .. tostring(Cache.reason))
finish()
end
print("[info] FireRed cache at " .. cacheRoot)
print("[test] 1. the fly table is the twenty heal locations")
local n = Field.loadFlyDestinations()
check(n == 20, "twenty fly destinations (" .. n .. ")")
for _, sec in ipairs(FLYABLE) do
local d = Field.flyDestination(sec)
check(d ~= nil and type(d.map) == "string" and d.x ~= nil and d.y ~= nil,
sec .. " has a destination")
end
check(Field.flyDestination("MAPSEC_ROUTE_1") == nil, "a plain route is not flyable")
check(Field.flyDestination(nil) == nil, "nil is not flyable")
-- pokefirered/src/region_map.c:4023
local MapSections = require("src.import.gba.map_sections_extract")
local viridianId = MapSections.ID_TO_SECTION["MAPSEC_VIRIDIAN_CITY"]
check(tonumber(viridianId) ~= nil, "MAPSEC_VIRIDIAN_CITY has a numeric id")
check(Field.flyDestination(viridianId) == Field.flyDestination("MAPSEC_VIRIDIAN_CITY"),
"the numeric mapsec resolves to the same destination")
check(Field.flyDestination(999) == nil, "an unknown numeric mapsec is not flyable")
local pallet = Field.flyDestination("MAPSEC_PALLET_TOWN")
check(pallet.map == "FR_PALLET_TOWN" and pallet.x == 6 and pallet.y == 8,
"Pallet Town lands outside the house at (6,8)")
local indigo = Field.flyDestination("MAPSEC_INDIGO_PLATEAU")
check(indigo.map == "FR_INDIGO_PLATEAU_EXTERIOR" and indigo.x == 11 and indigo.y == 7,
"Indigo Plateau lands on the exterior at (11,7)")
local Dataset = require("src.core.game3.dataset")
local Collision = require("src.core.game3.collision")
local Player = require("src.core.game3.player")
local Runtime = require("src.core.game3.runtime")
local game = { data = {} }
Dataset.hydrate(game)
local session = { map = nil, flags = {}, vars = {}, party = {}, name = "RED" }
game.session = session
Runtime.session = session
Field._game = game
Field._session = session
Field.running = true
print("[test] 3. every destination is a real cell you can stand on")
for _, sec in ipairs(FLYABLE) do
local d = Field.flyDestination(sec)
local def = game.data.maps[d.map]
check(def ~= nil, d.map .. " is in the cache")
if def then
Collision.bindMap(game, d.map, def)
check(Collision.isWalkable(d.x, d.y) == true,
string.format("%s (%d,%d) is walkable", d.map, d.x, d.y))
end
end
print("[test] 4. flying moves the player")
local dest = Field.flyDestination("MAPSEC_PEWTER_CITY")
session.map = "FR_PALLET_TOWN"
Collision.bindMap(game, "FR_PALLET_TOWN", game.data.maps["FR_PALLET_TOWN"])
Player.cellX, Player.cellY = 6, 8
check(pcall(Field.flyTo, "MAPSEC_NOWHERE") == false, "an unknown section raises")
check(Player.cellX == 6 and Player.cellY == 8, "and does not move the player")
check(Field.flyTo("MAPSEC_PEWTER_CITY") == true, "flying to Pewter City is accepted")
check(Player.cellX == dest.x and Player.cellY == dest.y,
string.format("the player stands at (%d,%d), got (%d,%d)",
dest.x, dest.y, Player.cellX, Player.cellY))
check(session.map == dest.map, "on " .. dest.map .. " (" .. tostring(session.map) .. ")")
finish()