feat: expose stable overworld checkpoints to mods

This commit is contained in:
MaxTomahawk
2026-08-07 14:49:45 +02:00
parent 0399ad040f
commit 6e94625f2a
6 changed files with 568 additions and 15 deletions
+19 -15
View File
@@ -206,7 +206,7 @@ function OverworldState.computeNeighbors(maps, rootId, hops, reachW, reachH)
return out
end
function OverworldState:enter(mapId, x, y, facing)
function OverworldState:enter(mapId, x, y, facing, opts)
Game = require("src.core.Game")
Game.overworld = self
Collision.load(Game.data) -- tile-pair (elevation) collisions
@@ -227,7 +227,7 @@ function OverworldState:enter(mapId, x, y, facing)
-- survives save/load: a loaded game may start inside a building whose
-- exit mat is a LAST_MAP warp
self.lastOutdoor = Game.save.lastOutdoor
self:setMap(mapId, x, y, facing, { via = "boot" })
self:setMap(mapId, x, y, facing, opts or { via = "boot" })
-- boot/load: derive the flag from the tile the save left us standing on,
-- like MapEntryAfterBattle's IsPlayerStandingOnWarp, so a game saved on a
-- door mat can still walk straight back out (issue #378)
@@ -282,7 +282,7 @@ end
function OverworldState:setMap(mapId, x, y, facing, opts)
local fromMapId = self.map and self.map.id
if fromMapId then
if fromMapId and not (opts and opts.checkpoint) then
Runtime.emit("map.exited", { mapId = fromMapId, toMapId = mapId })
end
-- ambient choreography is per-map: parallel runners die here, and the
@@ -460,13 +460,13 @@ function OverworldState:setMap(mapId, x, y, facing, opts)
-- (home/overworld.asm) -- a warp can land directly on one (the Route
-- 16/18 gate exits), and the scripted door-mat walkout that follows
-- suppresses onStepComplete, so waiting for a plain step never mounts
self:checkForcedMovement()
if not (opts and opts.checkpoint) then self:checkForcedMovement() end
-- Seafoam B4F's map script pushes off the B3F stair warps every frame
-- while the upper plugs are out (SeafoamIslandsB4FDefaultScript); the
-- B3F/B4F force-surf mouths also arm their MOVE_OBJECT current scripts
-- from CheckForceBikeOrSurf. Re-check here so a warp-in does not sit
-- idle on those cells waiting for a player step.
self:checkSeafoamCurrent()
if not (opts and opts.checkpoint) then self:checkSeafoamCurrent() end
-- snap the camera immediately: the overworld doesn't update while a
-- Transition is on top, so a stale camera would show the new map at
@@ -476,27 +476,31 @@ function OverworldState:setMap(mapId, x, y, facing, opts)
-- fires before the onEnter chain so a listener sees the map in the same
-- state the map script does
Runtime.emit("map.entered", {
mapId = mapId, map = self.map, fromMapId = fromMapId,
via = (opts and opts.via)
or (opts and opts.seamless and "connection")
or (fromMapId and "warp" or "boot"),
})
if not (opts and opts.checkpoint) then
Runtime.emit("map.entered", {
mapId = mapId, map = self.map, fromMapId = fromMapId,
via = (opts and opts.via)
or (opts and opts.seamless and "connection")
or (fromMapId and "warp" or "boot"),
})
end
-- map-enter hooks (hand-ported map scripts, e.g. Victory Road barriers).
-- fromMapId lets elevators seed a valid walk-out floor when the ROM
-- car warps still point at a missing map (Silph's UNUSED_MAP_ED) and
-- the player B-cancels the floor menu without .UpdateWarp.
local hooks = mapScripts.get(mapId)
if hooks and hooks.onEnter then
hooks.onEnter(Game, self, fromMapId)
if not (opts and opts.checkpoint) then
local hooks = mapScripts.get(mapId)
if hooks and hooks.onEnter then
hooks.onEnter(Game, self, fromMapId)
end
end
self:rebuildNeighbors()
Logger.info("map: %s at (%d,%d)", mapId, x, y)
-- Route22Gate_Script rewrites wLastMap from the player's Y on entry
-- too (not only on step), so a save/load mid-gate keeps exits correct
self:syncLastMapRewrite()
if not (opts and opts.checkpoint) then self:syncLastMapRewrite() end
end
-- Neighbor maps drawn at the composed connection offsets: at least the