mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
197 lines
8.7 KiB
Lua
197 lines
8.7 KiB
Lua
-- ESCAPE ROPE and DIG have to come out of the door that was walked in, not the
|
|
-- last door that happened to bank a triple.
|
|
--
|
|
-- GOLD_CACHE=".../gold" luajit tests/gen2_dig_warp_test.lua
|
|
--
|
|
-- home/map.asm EnterMapWarp calls `.SaveDigWarp` on EVERY warp: if the map
|
|
-- being left is outdoor (CheckOutdoorMap -- ROUTE or TOWN) and the one being
|
|
-- entered is indoor (CheckIndoorMap -- INDOOR, CAVE, DUNGEON or GATE), the
|
|
-- warp stepped on and the map left go into wDigWarpNumber / wDigMapGroup /
|
|
-- wDigMapNumber, and EscapeRopeOrDig's `.CheckCanDig` reads them straight back.
|
|
-- MOUNT_MOON_SQUARE and TIN_TOWER_ROOF are the routine's own exceptions:
|
|
-- outdoor maps sitting inside indoor ones, which the rope must never land on.
|
|
--
|
|
-- The port had only the -1 writer (the POKECENTER_2F / elevator contract in
|
|
-- tests/gen2_pokecenter_stairs_test.lua), so a cave entered by an ordinary
|
|
-- door banked nothing and the rope paid out to whatever was banked last. DARK
|
|
-- CAVE has a Route 31 mouth and a Route 46 mouth, which is exactly the case
|
|
-- that tells the two apart.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local S = require("tests.harness").suite("gen2 dig warp")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local World = require("src.world.gen2.World")
|
|
local Map = require("src.world.gen2.Map")
|
|
|
|
local cache = os.getenv("GOLD_CACHE")
|
|
if not cache then
|
|
local home = os.getenv("HOME") or ""
|
|
cache = home .. "/Library/Application Support/LOVE/gold-dev/gold"
|
|
end
|
|
local probe = io.open(cache .. "/data/generated/maps.lua", "r")
|
|
if not probe then
|
|
check(true, "gold cache absent (SKIP)")
|
|
S.finish()
|
|
return
|
|
end
|
|
probe:close()
|
|
|
|
local function loadLua(rel) return assert(loadfile(cache .. "/" .. rel))() end
|
|
local maps = loadLua("data/generated/maps.lua")
|
|
local tilesets = loadLua("data/generated/tilesets.lua")
|
|
|
|
-- The map data the whole rule reads: the environments the two Check routines
|
|
-- compare against, straight out of the extracted headers.
|
|
eq(maps.ROUTE_31.environment, "ROUTE", "Route 31 is an outdoor map")
|
|
eq(maps.DARK_CAVE_VIOLET_ENTRANCE.environment, "CAVE",
|
|
"and DARK CAVE's Violet side is a cave")
|
|
eq(maps.ROUTE_31.warps[3].destMap, "DARK_CAVE_VIOLET_ENTRANCE",
|
|
"Route 31's third warp is the cave mouth")
|
|
eq(maps.ROUTE_46.warps[3].destMap, "DARK_CAVE_VIOLET_ENTRANCE",
|
|
"and Route 46's third warp is the other one")
|
|
|
|
-- A World over the real defs. setMap is recorded rather than run (baking a
|
|
-- map image needs a graphics device); everything around it -- takeWarp,
|
|
-- recordWarpBackup, escapeRopeTarget, runEscapeWarp -- is the shipped code.
|
|
local function world(mapId)
|
|
local game = { data = { audio = { sfxOrder = {} } }, save = { player = {} } }
|
|
local w = World.new(game)
|
|
w.maps, w.tilesets = maps, tilesets
|
|
w.map = Map.new(maps[mapId], tilesets[maps[mapId].tileset])
|
|
w.player = { cellX = 0, cellY = 0, facing = "up", moving = false }
|
|
w.loaded = nil
|
|
w.setMap = function(self, id, cx, cy, facing)
|
|
self.loaded = { id = id, x = cx, y = cy, facing = facing }
|
|
-- The stub stands in for the load, so the map the world believes it is
|
|
-- standing on has to move with it or the next take reads the old warps.
|
|
self.map = Map.new(maps[id], tilesets[maps[id].tileset])
|
|
return true
|
|
end
|
|
return w
|
|
end
|
|
|
|
-- MAPSETUP_DOOR fades out before the load, so the take is parked in
|
|
-- world.mapSetup; this drains it the way World:step does.
|
|
local function pump(w)
|
|
for _ = 1, 64 do
|
|
if not w.mapSetup then return end
|
|
w:updateMapSetup()
|
|
end
|
|
end
|
|
|
|
local function walk(w, mapId, warpIndex)
|
|
local taken = w:takeWarp(maps[mapId].warps[warpIndex])
|
|
pump(w)
|
|
return taken
|
|
end
|
|
|
|
-- ---- the door actually used ----------------------------------------------
|
|
do
|
|
local w = world("ROUTE_31")
|
|
check(walk(w, "ROUTE_31", 3), "into DARK CAVE off Route 31")
|
|
eq(w.loaded and w.loaded.id, "DARK_CAVE_VIOLET_ENTRANCE", "landing in the cave")
|
|
check(w.backupWarp ~= nil, "an outdoor-to-cave door banks the dig triple")
|
|
eq(w.backupWarp.map, "ROUTE_31", "naming the route outside")
|
|
eq(w.backupWarp.warp, 3, "and the mouth stepped on")
|
|
|
|
-- EscapeRopeOrDig's .CheckCanDig, then the warp its script runs.
|
|
local destMapId, destWarp = w:escapeRopeTarget()
|
|
eq(destMapId, "ROUTE_31", "the rope resolves back to Route 31")
|
|
check(w:runEscapeWarp(destMapId, destWarp), "and the rope warp runs")
|
|
pump(w)
|
|
eq(w.loaded.id, "ROUTE_31", "landing on Route 31")
|
|
eq(w.loaded.x, maps.ROUTE_31.warps[3].x, "on the cave mouth's own x")
|
|
eq(w.loaded.y, maps.ROUTE_31.warps[3].y, "and y")
|
|
end
|
|
|
|
-- The same cave, entered from the other side: the triple is re-banked on every
|
|
-- qualifying door, so the rope follows the player rather than the map.
|
|
do
|
|
local w = world("ROUTE_46")
|
|
check(walk(w, "ROUTE_46", 3), "into DARK CAVE off Route 46 instead")
|
|
eq(w.backupWarp.map, "ROUTE_46", "the banked map is Route 46 now")
|
|
eq(w.backupWarp.warp, 3, "with Route 46's own mouth")
|
|
local destMapId, destWarp = w:escapeRopeTarget()
|
|
eq(destMapId, "ROUTE_46", "so the rope comes out on Route 46")
|
|
eq(destWarp.x, maps.ROUTE_46.warps[3].x, "at that mouth's x")
|
|
eq(destWarp.y, maps.ROUTE_46.warps[3].y, "and y")
|
|
end
|
|
|
|
-- ---- what CheckOutdoorMap / CheckIndoorMap refuse -------------------------
|
|
do
|
|
-- Walking OUT of the cave is indoor-to-outdoor: `.SaveDigWarp` returns at
|
|
-- its first test and the banked triple is left standing.
|
|
local w = world("ROUTE_31")
|
|
check(walk(w, "ROUTE_31", 3), "in through the Route 31 mouth")
|
|
local banked = w.backupWarp
|
|
check(walk(w, "DARK_CAVE_VIOLET_ENTRANCE", 1), "and back out again")
|
|
eq(w.loaded.id, "ROUTE_31", "out on Route 31")
|
|
eq(w.backupWarp, banked, "leaving the dig triple exactly as it was")
|
|
|
|
-- A GATE counts as indoor, so a route gate banks like any other door.
|
|
check(walk(w, "ROUTE_31", 1), "into the Violet gate")
|
|
eq(w.backupWarp.map, "ROUTE_31", "a GATE is CheckIndoorMap's fourth arm")
|
|
eq(w.backupWarp.warp, 1, "banking the gate door")
|
|
|
|
-- Gate to town is outdoor-bound: nothing banks.
|
|
local townBanked = w.backupWarp
|
|
check(walk(w, "ROUTE_31_VIOLET_GATE", 1), "out of the gate into Violet")
|
|
eq(w.loaded.id, "VIOLET_CITY", "into Violet City")
|
|
eq(w.backupWarp, townBanked, "with the triple untouched")
|
|
|
|
-- Town to building is the ordinary case, and it banks.
|
|
check(walk(w, "VIOLET_CITY", 5), "into the Violet Pokemon Center")
|
|
eq(w.backupWarp.map, "VIOLET_CITY", "banking the town outside")
|
|
eq(w.backupWarp.warp, 5, "and the centre's door")
|
|
end
|
|
|
|
-- ---- the two maps the routine excludes ------------------------------------
|
|
do
|
|
local w = world("ROUTE_31")
|
|
check(walk(w, "ROUTE_31", 3), "bank a real triple first")
|
|
local banked = w.backupWarp
|
|
-- MOUNT_MOON_SQUARE is a ROUTE map inside MOUNT_MOON, so the door out of it
|
|
-- passes both environment tests and is refused by name anyway.
|
|
eq(maps.MOUNT_MOON_SQUARE.environment, "ROUTE",
|
|
"MOUNT MOON SQUARE really is an outdoor map")
|
|
eq(maps.MOUNT_MOON.environment, "CAVE", "inside a cave")
|
|
w.map = Map.new(maps.MOUNT_MOON_SQUARE,
|
|
tilesets[maps.MOUNT_MOON_SQUARE.tileset])
|
|
check(walk(w, "MOUNT_MOON_SQUARE", 1), "step off the square into the cave")
|
|
eq(w.loaded.id, "MOUNT_MOON", "into MOUNT MOON")
|
|
eq(w.backupWarp, banked,
|
|
"the square is excluded by name: no dig warp is banked there")
|
|
|
|
-- TIN_TOWER_ROOF is the other one, and it is a ROUTE map inside a DUNGEON.
|
|
eq(maps.TIN_TOWER_ROOF.environment, "ROUTE", "so is the TIN TOWER roof")
|
|
eq(maps.TIN_TOWER_9F.environment, "DUNGEON", "over a dungeon floor")
|
|
w.map = Map.new(maps.TIN_TOWER_ROOF, tilesets[maps.TIN_TOWER_ROOF.tileset])
|
|
check(walk(w, "TIN_TOWER_ROOF", 1), "down off the roof")
|
|
eq(w.loaded.id, "TIN_TOWER_9F", "onto 9F")
|
|
eq(w.backupWarp, banked, "and the roof banks nothing either")
|
|
end
|
|
|
|
-- ---- the -1 contract is untouched -----------------------------------------
|
|
do
|
|
-- The staircase writer still wins on its own arm: an INDOOR-to-INDOOR warp
|
|
-- banks nothing under the dig rule, and everything about POKECENTER_2F has
|
|
-- to keep working (tests/gen2_pokecenter_stairs_test.lua pins the rest).
|
|
local w = world("CHERRYGROVE_POKECENTER_1F")
|
|
check(walk(w, "CHERRYGROVE_POKECENTER_1F", 3), "up the centre's stairs")
|
|
eq(w.loaded.id, "POKECENTER_2F", "onto the shared 2F")
|
|
eq(w.backupWarp.map, "CHERRYGROVE_POKECENTER_1F",
|
|
"the -1 arrival banked the centre")
|
|
eq(w.backupWarp.warp, 3, "and its staircase")
|
|
|
|
-- And a dig triple banked outdoors does not make the rope work in a room
|
|
-- that is not a cave: .CheckCanDig gates on the CURRENT map's environment.
|
|
local town = world("CHERRYGROVE_CITY")
|
|
check(walk(town, "CHERRYGROVE_CITY", 2), "into the Cherrygrove centre")
|
|
eq(town.backupWarp.map, "CHERRYGROVE_CITY", "banking the town door")
|
|
eq(town:escapeRopeTarget(), nil,
|
|
"but a rope indoors still refuses: the map is not a cave or a dungeon")
|
|
end
|
|
|
|
S.finish()
|