mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 16:31:05 +02:00
269 lines
9.5 KiB
Lua
269 lines
9.5 KiB
Lua
-- Headless tests for tools/save-editor/panels/MapBrowser.lua.
|
|
-- Run from repo root: lua5.4 tests/save_editor_task8_tests.lua
|
|
-- (love_stub lacks push/pop/scale/scissor; MapBrowser skips real
|
|
-- rendering under those but still runs all click/button logic, which is
|
|
-- what these tests exercise via Kit.beginFrame like the other panels.)
|
|
|
|
package.path = package.path .. ";./?.lua;./?/init.lua;./tools/save-editor/?.lua"
|
|
.. ";./tools/save-editor/panels/?.lua"
|
|
|
|
local love_stub = require("tests.love_stub")
|
|
love = love_stub
|
|
|
|
local passed, failed = 0, 0
|
|
|
|
local function check(cond, msg)
|
|
if cond then
|
|
passed = passed + 1
|
|
else
|
|
failed = failed + 1
|
|
print("FAIL: " .. msg)
|
|
end
|
|
end
|
|
|
|
local function eq(a, b, msg)
|
|
check(a == b, msg .. string.format(" (got %s, want %s)", tostring(a), tostring(b)))
|
|
end
|
|
|
|
print("== save editor task 8 (map browser) tests ==")
|
|
|
|
local Data = require("src.core.Data")
|
|
Data:load()
|
|
|
|
local SaveData = require("src.core.SaveData")
|
|
local State = require("State")
|
|
local Kit = require("Kit")
|
|
local MapBrowser = require("MapBrowser")
|
|
|
|
local LIST_W, LIST_H, ROW_H = 200, 300, 20
|
|
local MAX_ROWS = math.floor(LIST_H / ROW_H)
|
|
local VIEW_W, VIEW_H = 480, 432
|
|
|
|
local function newState()
|
|
local S = State.new()
|
|
S.data = Data
|
|
S.save = SaveData.newGame()
|
|
S.mapId = S.save.player.map -- PALLET_TOWN
|
|
return S
|
|
end
|
|
|
|
local px, py = 12, 80
|
|
local vx, vy = px + LIST_W + 20, py + 24
|
|
|
|
-- ---------------------------------------------------------------- list
|
|
do
|
|
local S = newState()
|
|
local ids = {}
|
|
for id in pairs(Data.maps) do table.insert(ids, id) end
|
|
table.sort(ids)
|
|
check(#ids > 200, "generated data has lots of maps")
|
|
|
|
-- click the 3rd row of the map id list -> selects that map, no crash
|
|
-- despite love_stub missing push/pop/scale/scissor
|
|
Kit.beginFrame(px + 10, py + 24 + 2 * ROW_H + 5, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
eq(S.mapId, ids[3], "clicking list row 3 selects the 3rd sorted map id")
|
|
check(S.mapClickCell == nil, "switching maps clears any selected cell")
|
|
end
|
|
|
|
do
|
|
local S = newState()
|
|
-- Next then Prev should return to the first page
|
|
Kit.beginFrame(px + 64 + 5, py + 24 + MAX_ROWS * ROW_H + 8 + 5, true) -- Next
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
eq(S.mapListScroll, MAX_ROWS, "Next advances one page")
|
|
|
|
Kit.beginFrame(px + 5, py + 24 + MAX_ROWS * ROW_H + 8 + 5, true) -- Prev
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
eq(S.mapListScroll, 0, "Prev returns to page 0")
|
|
end
|
|
|
|
-- ------------------------------------------------------------- click-to-cell
|
|
do
|
|
local S = newState() -- PALLET_TOWN
|
|
-- (5,6) is a known-walkable, non-warp cell (tests/run_tests.lua uses
|
|
-- the same ground truth); zoom 2 means 32 screen px per cell.
|
|
local mx = vx + 5 * 16 * S.mapZoom + 4
|
|
local my = vy + 6 * 16 * S.mapZoom + 4
|
|
Kit.beginFrame(mx, my, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.mapClickCell ~= nil, "clicking inside the viewport selects a cell")
|
|
if S.mapClickCell then
|
|
eq(S.mapClickCell.cx, 5, "selected cell cx")
|
|
eq(S.mapClickCell.cy, 6, "selected cell cy")
|
|
end
|
|
|
|
-- clicking outside the viewport (e.g. over the list) must not select a cell
|
|
S.mapClickCell = nil
|
|
Kit.beginFrame(px + 5, py + 5, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.mapClickCell == nil, "clicking outside the viewport doesn't select a cell")
|
|
end
|
|
|
|
-- ---------------------------------------------------------------- set player
|
|
do
|
|
local S = newState()
|
|
S.mapClickCell = { cx = 3, cy = 4 }
|
|
local by = vy + VIEW_H + 8
|
|
Kit.beginFrame(vx + 10, by + 22 + 10, true) -- Set player here
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
eq(S.save.player.map, S.mapId, "Set player here updates player.map")
|
|
eq(S.save.player.x, 3, "Set player here updates player.x")
|
|
eq(S.save.player.y, 4, "Set player here updates player.y")
|
|
check(S.dirty == true, "Set player here marks dirty")
|
|
end
|
|
|
|
do
|
|
local S = newState()
|
|
local by = vy + VIEW_H + 8
|
|
Kit.beginFrame(vx + 10, by + 22 + 10, true) -- Set player here, no cell selected
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.status:match("Click a cell first"), "Set player here without a selection warns")
|
|
end
|
|
|
|
-- ------------------------------------------------------------- lastOutdoor
|
|
do
|
|
local S = newState() -- PALLET_TOWN has connections -> outdoor
|
|
S.mapClickCell = { cx = 5, cy = 6 }
|
|
local by = vy + VIEW_H + 8
|
|
Kit.beginFrame(vx + 150 + 10, by + 22 + 10, true) -- Set lastOutdoor here
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.save.lastOutdoor ~= nil, "Set lastOutdoor here sets lastOutdoor")
|
|
if S.save.lastOutdoor then
|
|
eq(S.save.lastOutdoor.id, "PALLET_TOWN", "lastOutdoor.id")
|
|
eq(S.save.lastOutdoor.x, 5, "lastOutdoor.x")
|
|
eq(S.save.lastOutdoor.y, 6, "lastOutdoor.y")
|
|
end
|
|
end
|
|
|
|
do
|
|
-- an interior with no connections and not in save.visited -> rejected
|
|
local S = newState()
|
|
S.mapId = "REDS_HOUSE_1F"
|
|
S.mapClickCell = { cx = 1, cy = 1 }
|
|
local by = vy + VIEW_H + 8
|
|
Kit.beginFrame(vx + 150 + 10, by + 22 + 10, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.save.lastOutdoor == nil, "Set lastOutdoor here refuses a non-outdoor map")
|
|
check(S.status:match("outdoor"), "status explains the refusal")
|
|
end
|
|
|
|
-- ---------------------------------------------------------------- lastHeal
|
|
do
|
|
local S = newState()
|
|
S.mapClickCell = { cx = 2, cy = 8 }
|
|
local by = vy + VIEW_H + 8
|
|
Kit.beginFrame(vx + 320 + 10, by + 22 + 10, true) -- Set lastHeal here
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.save.lastHeal ~= nil, "Set lastHeal here sets lastHeal")
|
|
eq(S.save.lastHeal.map, S.mapId, "lastHeal.map")
|
|
eq(S.save.lastHeal.x, 2, "lastHeal.x")
|
|
eq(S.save.lastHeal.y, 8, "lastHeal.y")
|
|
end
|
|
|
|
-- --------------------------------------------------------------- warp jump
|
|
do
|
|
local S = newState()
|
|
S.mapId = "PALLET_TOWN"
|
|
local map = require("src.world.MapLoader").load(Data, "PALLET_TOWN")
|
|
check(#map.def.warps > 0, "Pallet Town has warps to test with")
|
|
local w = map.def.warps[1]
|
|
|
|
local mx = vx + w.x * 16 * S.mapZoom + 4
|
|
local my = vy + w.y * 16 * S.mapZoom + 4
|
|
Kit.beginFrame(mx, my, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
check(S.mapId ~= "PALLET_TOWN" or w.destMap == "PALLET_TOWN",
|
|
"clicking a warp cell jumps S.mapId to its destination")
|
|
check(S.status:match("Followed warp"), "warp click sets a status message")
|
|
end
|
|
|
|
do
|
|
-- LAST_MAP warp with no remembered outdoor map must not crash, and
|
|
-- must not silently move the view.
|
|
local S = newState()
|
|
S.mapId = "REDS_HOUSE_1F"
|
|
local MapLoader = require("src.world.MapLoader")
|
|
local map = MapLoader.load(Data, "REDS_HOUSE_1F")
|
|
local lastMapWarp
|
|
for _, w in ipairs(map.def.warps) do
|
|
if w.destMap == "LAST_MAP" then lastMapWarp = w end
|
|
end
|
|
if lastMapWarp then
|
|
S.save.lastOutdoor = nil
|
|
local mx = vx + lastMapWarp.x * 16 * S.mapZoom + 4
|
|
local my = vy + lastMapWarp.y * 16 * S.mapZoom + 4
|
|
Kit.beginFrame(mx, my, true)
|
|
local ok = pcall(MapBrowser.draw, S, Kit, px, py)
|
|
check(ok, "LAST_MAP warp with no lastOutdoor doesn't crash")
|
|
eq(S.mapId, "REDS_HOUSE_1F", "LAST_MAP warp with no lastOutdoor doesn't move the view")
|
|
check(S.status:match("lastOutdoor"), "status explains the skipped warp")
|
|
else
|
|
check(true, "REDS_HOUSE_1F has no LAST_MAP warp to test (skipped)")
|
|
end
|
|
end
|
|
|
|
do
|
|
-- Indigo Plateau uses tileset PLATEAU -> plateau.png (not indigo.png).
|
|
-- Following its lobby door must remember lastOutdoor so the lobby's
|
|
-- LAST_MAP mats return here (same as the game's outsideTilesets).
|
|
local S = newState()
|
|
S.mapId = "INDIGO_PLATEAU"
|
|
S.save.lastOutdoor = { id = "ROUTE_22", x = 8, y = 5 }
|
|
local MapLoader = require("src.world.MapLoader")
|
|
local indigo = MapLoader.load(Data, "INDIGO_PLATEAU")
|
|
eq(indigo.tileset.image, "assets/generated/tilesets/plateau.png",
|
|
"Indigo Plateau tileset image is plateau.png")
|
|
local door = indigo.def.warps[1]
|
|
local mx = vx + door.x * 16 * S.mapZoom + 4
|
|
local my = vy + door.y * 16 * S.mapZoom + 4
|
|
Kit.beginFrame(mx, my, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
eq(S.mapId, "INDIGO_PLATEAU_LOBBY", "Indigo door warp jumps to the lobby")
|
|
check(S.save.lastOutdoor and S.save.lastOutdoor.id == "INDIGO_PLATEAU",
|
|
"following Indigo door remembers lastOutdoor as INDIGO_PLATEAU")
|
|
|
|
local lobby = MapLoader.load(Data, "INDIGO_PLATEAU_LOBBY")
|
|
local exitWarp
|
|
for _, w in ipairs(lobby.def.warps) do
|
|
if w.destMap == "LAST_MAP" then exitWarp = w break end
|
|
end
|
|
check(exitWarp ~= nil, "Indigo lobby has a LAST_MAP exit")
|
|
-- re-zero the camera so the exit-cell click math matches cellAtScreen
|
|
S.mapCamX, S.mapCamY = 0, 0
|
|
mx = vx + exitWarp.x * 16 * S.mapZoom + 4
|
|
my = vy + exitWarp.y * 16 * S.mapZoom + 4
|
|
Kit.beginFrame(mx, my, true)
|
|
MapBrowser.draw(S, Kit, px, py)
|
|
eq(S.mapId, "INDIGO_PLATEAU", "Indigo lobby LAST_MAP exit returns to the plateau")
|
|
end
|
|
|
|
-- --------------------------------------------------------- zoom / pan input
|
|
do
|
|
local S = newState()
|
|
local z0 = S.mapZoom
|
|
MapBrowser.wheelmoved(S, 1)
|
|
check(S.mapZoom > z0, "wheelmoved(+) zooms in")
|
|
MapBrowser.wheelmoved(S, -1)
|
|
MapBrowser.wheelmoved(S, -1)
|
|
check(S.mapZoom < z0, "wheelmoved(-) zooms out")
|
|
|
|
S.mapZoom = 1
|
|
for _ = 1, 20 do MapBrowser.wheelmoved(S, -1) end
|
|
check(S.mapZoom >= 1, "zoom clamps at a minimum")
|
|
end
|
|
|
|
do
|
|
local S = newState()
|
|
S.mapCamX, S.mapCamY = 0, 0
|
|
MapBrowser.keypressed(S, "d")
|
|
eq(S.mapCamX, 16, "keypressed d pans camera right by one cell")
|
|
MapBrowser.keypressed(S, "down")
|
|
eq(S.mapCamY, 16, "keypressed down pans camera down by one cell")
|
|
MapBrowser.keypressed(S, "unrelatedkey")
|
|
eq(S.mapCamX, 16, "unrelated keys don't pan the camera")
|
|
end
|
|
|
|
print(string.format("save editor task 8 tests: %d passed, %d failed", passed, failed))
|
|
if failed > 0 then os.exit(1) end
|