mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
bfba1f7bb7
* main menu scrollable when over 8 items * buggies * more buggies * Lorelei, Bruno, and Agatha now push their AfterBattle text right after a win
142 lines
5.1 KiB
Lua
142 lines
5.1 KiB
Lua
-- Parity test: Lance room walk-in stays on the floor, and defeat dialogue
|
|
-- includes the rival-became-champion after-battle text.
|
|
--
|
|
-- Sources: scripts/LancesRoom.asm (WalkToLance / LancesRoomLanceEndBattleScript),
|
|
-- text/LancesRoom.asm (_LancesRoomLanceAfterBattleText).
|
|
-- Self-contained: run via `luajit tests/parity_lance.lua`; also dofile'd
|
|
-- by tests/run_tests.lua's aggregator.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
if not _G.love then _G.love = require("tests.love_stub") end
|
|
local Data = require("src.core.Data")
|
|
if not (Data.maps and Data.maps.LANCES_ROOM) then Data:load() end
|
|
local Font = require("src.render.Font")
|
|
if not pcall(Font.encode, "A") then Font.load(Data) end
|
|
local S = require("tests.harness").suite("parity lance")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local mapScripts = require("data.scripts.init")
|
|
local hooks = mapScripts.get("LANCES_ROOM")
|
|
check(hooks and hooks.walkInRoute, "LANCES_ROOM exposes walkInRoute")
|
|
|
|
local D = { up = { 0, -1 }, down = { 0, 1 }, left = { -1, 0 }, right = { 1, 0 } }
|
|
|
|
-- === (1) walk-in RLE lands on the door-lock trigger (6,11) ===
|
|
do
|
|
local x, y = 24, 16
|
|
local steps = 0
|
|
for _, seg in ipairs(hooks.walkInRoute) do
|
|
local d = D[seg[1]]
|
|
check(d ~= nil, "walk segment direction " .. tostring(seg[1]))
|
|
for _ = 1, seg[2] do
|
|
x, y = x + d[1], y + d[2]
|
|
steps = steps + 1
|
|
end
|
|
end
|
|
eq(x, 6, "walk-in ends at x=6")
|
|
eq(y, 11, "walk-in ends at y=11 (door-lock / arena entry)")
|
|
check(steps > 0, "walk-in has steps")
|
|
end
|
|
|
|
-- === (2) every cell of the route is walkable with the entrance open ===
|
|
do
|
|
local Map = require("src.world.Map")
|
|
local def = Data.maps.LANCES_ROOM
|
|
local tileset = Data.tilesets[def.tileset]
|
|
-- mutate a copy of the block list so we don't poison the registry
|
|
local blocks = {}
|
|
for i, b in ipairs(def.blocks) do blocks[i] = b end
|
|
local copy = {}
|
|
for k, v in pairs(def) do copy[k] = v end
|
|
copy.blocks = blocks
|
|
-- LanceShowOrHideEntranceBlocks with the door unlocked
|
|
blocks[6 * def.width + 2 + 1] = 0x31
|
|
blocks[6 * def.width + 3 + 1] = 0x32
|
|
local map = Map.new(copy, tileset)
|
|
local x, y = 24, 16
|
|
check(map:isWalkableCell(x, y), "start (24,16) walkable")
|
|
for _, seg in ipairs(hooks.walkInRoute) do
|
|
local d = D[seg[1]]
|
|
for _ = 1, seg[2] do
|
|
x, y = x + d[1], y + d[2]
|
|
check(map:isWalkableCell(x, y),
|
|
("walk-in cell (%d,%d) is floor, not void/wall"):format(x, y))
|
|
end
|
|
end
|
|
end
|
|
|
|
-- === (3) after-battle text names the rival as the real champion ===
|
|
do
|
|
local after = Data.text._LancesRoomLanceAfterBattleText
|
|
check(after ~= nil, "_LancesRoomLanceAfterBattleText extracted")
|
|
check(after:find("ELITE", 1, true) or after:find("{RIVAL}", 1, true),
|
|
"after text mentions rival / Elite Four")
|
|
check(after:find("champion", 1, true) or after:find("CHAMPION", 1, true),
|
|
"after text has the champion reveal")
|
|
check(after:find("before you", 1, true) or after:find("before you!", 1, true)
|
|
or after:find("FOUR before", 1, true),
|
|
"after text says rival beat the Elite Four first")
|
|
local header = Data:trainerHeader("LancesRoom", 1)
|
|
check(header and header.after == "_LancesRoomLanceAfterBattleText",
|
|
"trainer header wires the after-battle label")
|
|
check(header and header.won == "_LancesRoomLanceEndBattleText",
|
|
"trainer header wires the won label")
|
|
end
|
|
|
|
-- === (4) onStep win callback pushes the after text (not only won text) ===
|
|
do
|
|
local pushed = {}
|
|
local game = {
|
|
data = Data,
|
|
save = {
|
|
flags = {},
|
|
defeatedTrainers = {},
|
|
player = { name = "RED", rival = "BLUE" },
|
|
},
|
|
stack = {
|
|
push = function(_, state)
|
|
pushed[#pushed + 1] = state
|
|
end,
|
|
},
|
|
}
|
|
local lance = {
|
|
def = { name = "LANCESROOM_LANCE", index = 1,
|
|
trainerClass = "OPP_LANCE", trainerParty = 1, text = 1 },
|
|
id = "LANCES_ROOM:1",
|
|
facePlayer = function() end,
|
|
}
|
|
local engaged = false
|
|
local ow = {
|
|
npcs = { lance },
|
|
player = { cellX = 6, cellY = 2 },
|
|
trainerDefeated = function(_, npc)
|
|
return game.save.defeatedTrainers[npc.id] == true
|
|
end,
|
|
engageTrainer = function(_, npc, onDone)
|
|
engaged = npc == lance
|
|
-- simulate engageTrainer's win path: flag the trainer, then onDone
|
|
game.save.defeatedTrainers[npc.id] = true
|
|
game.save.flags.EVENT_BEAT_LANCES_ROOM_TRAINER_0 = true
|
|
if onDone then onDone() end
|
|
end,
|
|
}
|
|
local handled = hooks.onStep(game, ow, 6, 2)
|
|
check(handled == true, "Lance coord trigger engages")
|
|
check(engaged, "engageTrainer called for Lance")
|
|
check(#pushed == 1 and pushed[1].pages ~= nil, "after-battle TextBox pushed")
|
|
-- TextBox.substitute already expanded {RIVAL}/{PLAYER}; page glyphs
|
|
-- are opaque, so re-check the source label via the header + that a
|
|
-- box was queued on win only.
|
|
check(#pushed[1].pages > 0, "after-battle TextBox has pages")
|
|
-- loss path must not show after text
|
|
pushed = {}
|
|
game.save.defeatedTrainers = {}
|
|
ow.engageTrainer = function(_, npc, onDone)
|
|
-- lose: do not mark defeated
|
|
if onDone then onDone() end
|
|
end
|
|
hooks.onStep(game, ow, 6, 2)
|
|
eq(#pushed, 0, "loss does not push after-battle text")
|
|
end
|
|
|
|
print("parity_lance: ok")
|