Files
gen1recomp/tests/game3_field_safari_test.lua

235 lines
9.4 KiB
Lua

#!/usr/bin/env luajit
-- pokefirered/src/safari_zone.c:26 EnterSafariMode
-- pokefirered/src/safari_zone.c:41 SafariZoneTakeStep
-- pokefirered/data/scripts/safari_zone.inc:7 SafariZone_EventScript_Exit
-- pokefirered/src/field_control_avatar.c:677 TryStartStepCountScript
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 Safari = require("src.core.game3.safari")
local Rules = require("src.core.game3.battle.rules")
print("[test] 1. the constants are pret's")
check(Safari.BALLS == 30, "30 SAFARI BALLS")
check(Safari.STEPS == 600, "600 steps")
check(Safari.BALLS == Rules.safari.BALLS and Safari.STEPS == Rules.safari.STEPS,
"the overworld and the battle side agree")
check(Safari.FLAG_SYS_SAFARI_MODE == 0x800, "FLAG_SYS_SAFARI_MODE is 0x800")
check(Safari.VAR_ENTRANCE_SCENE == 0x406E,
"VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE is 0x406E")
check(Safari.EXIT_MAP == "FR_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE"
and Safari.EXIT_X == 4 and Safari.EXIT_Y == 1,
"the exit warp is the Fuchsia entrance at (4,1)")
local Cache = require("tests.game3_cache")
local cacheRoot = Cache.mount("scripts/events.lua", { native = true })
if not cacheRoot then
print("[skip] game3_field_safari_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 StepEvents = require("src.core.game3.step_events")
local Warp = require("src.core.game3.warp")
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
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
Space.activate(nil, mapId, game, nil)
Collision.bindMap(game, mapId, def)
Objects.loadMap(game, mapId, def)
return def
end
print("[test] 2. the Safari Zone maps and the entrance warp exist")
local center = enterMap("FR_SAFARI_ZONE_CENTER")
check(center ~= nil, "FR_SAFARI_ZONE_CENTER is in the cache")
local entrance = game.data.maps[Safari.EXIT_MAP]
check(entrance ~= nil, Safari.EXIT_MAP .. " is in the cache")
if not (center and entrance) then finish() end
print("[test] 3. EnterSafariMode arms the session")
check(Safari.isActive(session) == false, "safari mode starts off")
check(Safari.enter(session) == true, "EnterSafariMode")
check(Safari.isActive(session) == true, "FLAG_SYS_SAFARI_MODE is set")
check(Flags.getFlag(Space.store, nil, Safari.FLAG_SYS_SAFARI_MODE) == true,
"and the script store sees it")
check(Safari.balls(session) == 30, "30 balls on the session")
check(Safari.steps(session) == 600, "600 steps on the session")
check(session.safari.balls == 30, "the battle side reads session.safari.balls")
print("[test] 4. every step burns one of the 600")
session.party = { { species = 1, level = 10, hp = 20, maxHp = 20 } }
for _ = 1, 10 do StepEvents.onStepTaken(session, game) end
check(Safari.steps(session) == 590, "10 steps left 590 (" .. Safari.steps(session) .. ")")
print("[test] 5. a step outside safari mode burns nothing")
Safari.exit(session)
check(Safari.isActive(session) == false, "ExitSafariMode cleared the flag")
check(Safari.balls(session) == 0, "and zeroed the balls")
local before = Safari.steps(session)
StepEvents.onStepTaken(session, game)
check(Safari.steps(session) == before, "SafariZoneTakeStep is a no-op when off")
print("[test] 6. the last step ends the game and ejects to the entrance")
Safari.enter(session)
session.safari.steps = 2
Warp.clear()
StepEvents.onStepTaken(session, game)
check(Safari.steps(session) == 1, "599 of 600 gone, one step left")
check(Safari.isActive(session) == true, "still in the Safari Zone")
StepEvents.onStepTaken(session, game)
check(Safari.steps(session) == 0, "the counter hits zero")
check(Safari.isActive(session) == false, "the PA announcement ran ExitSafariMode")
check(session.vars[Safari.VAR_ENTRANCE_SCENE] == 1,
"VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE is 1 for the exit cutscene")
check(Flags.getVar(Space.store, nil, Safari.VAR_ENTRANCE_SCENE) == 1,
"the script store sees the same var")
local pending = Warp._pending
check((pending ~= nil and pending.mapId == Safari.EXIT_MAP and pending.x == 4 and pending.y == 1)
or session.map == Safari.EXIT_MAP,
"the player is on the way to the Fuchsia entrance at (4,1)")
Warp.clear()
print("[test] 7. retiring early ejects the same way")
enterMap("FR_SAFARI_ZONE_CENTER")
Safari.enter(session)
check(Safari.retirePrompt(session, game) == true, "the retire prompt ran")
check(Safari.isActive(session) == false, "retiring left safari mode")
check(session.vars[Safari.VAR_ENTRANCE_SCENE] == 1, "and set the entrance scene var")
Warp.clear()
print("[test] 8. out of balls ends it too")
enterMap("FR_SAFARI_ZONE_CENTER")
Safari.enter(session)
session.safari.balls = 0
check(Safari.outOfBalls(session, game) == true, "the out-of-balls announcement ran")
check(Safari.isActive(session) == false, "out of balls leaves safari mode")
Warp.clear()
print("[test] 9. Continue inside the zone does not eject on the first step")
local Schema = require("src.core.game3.save_schema_firered")
enterMap("FR_SAFARI_ZONE_CENTER")
Safari.enter(session)
session.safari.steps = 500
Space.persistSession(nil, game)
local save = Schema.toSaveTable(session)
check(save.safari == nil,
"gNumSafariBalls / gSafariZoneStepCounter are EWRAM, so no save block carries them")
check(save.flags[tostring(Safari.FLAG_SYS_SAFARI_MODE)] == true,
"but FLAG_SYS_SAFARI_MODE rides the saved flag store")
local loaded = Schema.fromSaveTable(save)
check(loaded.safari == nil, "the loaded session has no counters")
game.session = loaded
Runtime.session = loaded
Field._session = loaded
Space.deactivate(nil)
Space.activate(nil, "FR_SAFARI_ZONE_CENTER", game, nil)
-- pokefirered/src/overworld.c:1695 CB2_ContinueSavedGame
check(Safari.isActive(loaded) == false, "ResetSafariZoneFlag_ clears the flag on Continue")
check(Flags.getFlag(Space.store, nil, Safari.FLAG_SYS_SAFARI_MODE) == false,
"and the script store agrees")
loaded.party = { { species = 1, level = 10, hp = 20, maxHp = 20 } }
Warp.clear()
StepEvents.onStepTaken(loaded, game)
check(Warp._pending == nil, "the first step after Continue does not eject the player")
check((loaded.vars[Safari.VAR_ENTRANCE_SCENE] or 0) ~= 1, "and does not run the exit script")
game.session = session
Runtime.session = session
Field._session = session
session.flags[Safari.FLAG_SYS_SAFARI_MODE] = nil
session.safari = nil
Space.deactivate(nil)
Space.activate(nil, "FR_SAFARI_ZONE_CENTER", game, nil)
print("[test] 10. zero balls ejects on return to the field, with no step needed")
enterMap("FR_SAFARI_ZONE_CENTER")
Safari.enter(session)
check(Field.pollSafariBalls(game) == false, "with balls left the field poll does nothing")
session.safari.balls = 0
Warp.clear()
-- pokefirered/src/safari_zone.c:60 CB2_EndSafariBattle
check(Field.pollSafariBalls(game) == true, "at zero balls the poll runs the PA announcement")
check(Safari.isActive(session) == false, "which leaves safari mode")
check(session.vars[Safari.VAR_ENTRANCE_SCENE] == 1, "and sets the entrance scene var")
check(Warp._pending ~= nil and Warp._pending.mapId == Safari.EXIT_MAP,
"with a warp to the Fuchsia entrance")
Warp.clear()
print("[test] 11. a step at zero balls ejects too, before the step counter")
enterMap("FR_SAFARI_ZONE_CENTER")
Safari.enter(session)
session.safari.balls = 0
Warp.clear()
StepEvents.onStepTaken(session, game)
check(Safari.isActive(session) == false, "walking with an empty bag of balls ends the game")
check(Warp._pending ~= nil and Warp._pending.mapId == Safari.EXIT_MAP, "same eject")
Warp.clear()
print("[test] 12. RETIRE asks before it ejects")
enterMap("FR_SAFARI_ZONE_CENTER")
Safari.enter(session)
Warp.clear()
local asked, answer, closed = nil, false, false
Safari.presenter = {
message = function(text, onDone) asked = text; onDone() end,
yesNo = function(onPick) onPick(answer) end,
close = function() closed = true end,
}
check(Safari.retirePrompt(session, game) == true, "the retire prompt ran")
check(type(asked) == "string" and asked:find("exit the SAFARI", 1, true) ~= nil,
"it asks SafariZone_Text_WouldYouLikeToExit")
check(Safari.isActive(session) == true, "NO keeps the SAFARI GAME going")
check(closed == true, "and closes the box")
check(Warp._pending == nil, "warping nowhere")
answer = true
check(Safari.retirePrompt(session, game) == true, "asked again")
check(Safari.isActive(session) == false, "YES ends the SAFARI GAME")
check(Warp._pending ~= nil and Warp._pending.mapId == Safari.EXIT_MAP,
"and warps to the Fuchsia entrance")
Safari.presenter = nil
Warp.clear()
finish()