mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
245 lines
11 KiB
Lua
245 lines
11 KiB
Lua
-- Parity test, Workstream E.
|
|
-- Self-contained: run via `luajit tests/parity_E.lua`; also dofile'd by
|
|
-- tests/run_tests.lua's aggregator.
|
|
--
|
|
-- Covers: Cinnabar Lab fossil revival delay -- scripts/
|
|
-- CinnabarLabFossilRoom.asm (CinnabarLabFossilRoomScientist1Text),
|
|
-- engine/events/cinnabar_lab.asm (GiveFossilToCinnabarLab), and
|
|
-- scripts/CinnabarIsland.asm line 6 (ResetEvent
|
|
-- EVENT_LAB_STILL_REVIVING_FOSSIL on every map load). Deposit a fossil
|
|
-- through the fossil-select menu (every carried fossil in FossilsList
|
|
-- order, Yes/No confirm, ComeAgainText on either cancel) -> pending for
|
|
-- the rest of the visit -> ready once CINNABAR_ISLAND's onEnter has run
|
|
-- again -> grant the mon and reset the quest, ported in
|
|
-- data/scripts/story2.lua (the talk handler) and data/scripts/story5.lua
|
|
-- (M.CINNABAR_ISLAND.onEnter).
|
|
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.PALLET_TOWN) then Data:load() end
|
|
local S = require("tests.harness").suite("parity E")
|
|
local check, eq = S.check, S.eq
|
|
|
|
-- The real TextBox needs a loaded font plus frame-stepped input to type
|
|
-- and dismiss pages -- unrelated to what this workstream verifies (flag /
|
|
-- inventory / party state transitions). Stub it to fire its onDone
|
|
-- callback immediately, exactly like the real box does once the player
|
|
-- has mashed through it, and record the shown strings for the
|
|
-- text-content assertions below. opts.choice boxes (SeesFossilText's
|
|
-- YesNoChoice) resolve with the scripted `choiceAnswer`. Restored at
|
|
-- the end of this file so suites that dofile after this one (the
|
|
-- run_tests.lua aggregator) still get the real TextBox.
|
|
local realTextBox = package.loaded["src.render.TextBox"]
|
|
local shownTexts = {}
|
|
local choiceAnswer = true -- scripted YES/NO for opts.choice boxes
|
|
local realSoundOpts = require("src.render.TextBox").soundOpts
|
|
package.loaded["src.render.TextBox"] = {
|
|
new = function(game, text, onDone, opts)
|
|
table.insert(shownTexts, text)
|
|
if opts and opts.choice then
|
|
opts.choice(choiceAnswer)
|
|
elseif onDone then
|
|
onDone()
|
|
end
|
|
return { text = text }
|
|
end,
|
|
soundOpts = realSoundOpts,
|
|
}
|
|
|
|
-- ../pokered/scripts/CinnabarLabFossilRoom.asm:74-83
|
|
local realCommands = package.loaded["src.script.Commands"]
|
|
package.loaded["src.script.Commands"] = nil
|
|
local ScriptCommands = require("src.script.Commands")
|
|
local function fakeRunner(game, ow)
|
|
local runner = {}
|
|
runner.resume = function() end
|
|
runner.yield = function() end
|
|
runner.isRunning = function() return false end
|
|
function runner:run(script, extra)
|
|
local ctx = { game = game, save = game.save, overworld = ow, runner = runner }
|
|
for k, v in pairs(extra or {}) do ctx[k] = v end
|
|
local labels = {}
|
|
for i, row in ipairs(script) do
|
|
if row[1] == "label" then labels[row[2]] = i end
|
|
end
|
|
local pc = 1
|
|
while pc <= #script do
|
|
local row = script[pc]
|
|
local fn = ScriptCommands[row[1]]
|
|
local target = fn and fn(ctx, row[2], row[3], row[4], row[5])
|
|
pc = target and (labels[target] or (#script + 1)) or (pc + 1)
|
|
end
|
|
if ctx.onDone then ctx.onDone() end
|
|
end
|
|
return runner
|
|
end
|
|
|
|
-- The fossil-select menu (GiveFossilToCinnabarLab's bordered list,
|
|
-- src/ui/Menu.lua) selects from frame-stepped input; stub it to pick
|
|
-- the scripted entry immediately (or back out with B when menuPick is
|
|
-- "cancel"), recording the labels for the order assertions.
|
|
local realMenu = package.loaded["src.ui.Menu"]
|
|
local menuPick = 1
|
|
local menuLabels = nil
|
|
package.loaded["src.ui.Menu"] = {
|
|
new = function(game, items, opts)
|
|
menuLabels = {}
|
|
for i, it in ipairs(items) do menuLabels[i] = it.label end
|
|
if menuPick == "cancel" then
|
|
if opts and opts.onCancel then opts.onCancel() end
|
|
else
|
|
items[menuPick].onSelect()
|
|
end
|
|
return {}
|
|
end,
|
|
}
|
|
|
|
local SaveData = require("src.core.SaveData")
|
|
local story2 = require("data.scripts.story2")
|
|
local story5 = require("data.scripts.story5")
|
|
|
|
check(story2.CINNABAR_LAB_FOSSIL_ROOM ~= nil, "CINNABAR_LAB_FOSSIL_ROOM registered")
|
|
check(story2.CINNABAR_LAB_FOSSIL_ROOM
|
|
and story2.CINNABAR_LAB_FOSSIL_ROOM.talk.TEXT_CINNABARLABFOSSILROOM_SCIENTIST1 ~= nil,
|
|
"scientist1 talk handler registered")
|
|
check(story5.CINNABAR_ISLAND ~= nil and story5.CINNABAR_ISLAND.onEnter ~= nil,
|
|
"CINNABAR_ISLAND.onEnter registered")
|
|
|
|
local talkScientist1 = story2.CINNABAR_LAB_FOSSIL_ROOM.talk.TEXT_CINNABARLABFOSSILROOM_SCIENTIST1
|
|
|
|
local function newGame()
|
|
local save = SaveData.newGame()
|
|
local game = { data = Data, save = save, stack = { push = function() end } }
|
|
return game
|
|
end
|
|
|
|
local function talk(game)
|
|
shownTexts = {}
|
|
local doneCalled = false
|
|
local ow = {}
|
|
ow.runner = fakeRunner(game, ow)
|
|
talkScientist1(game, ow, nil, function() doneCalled = true end)
|
|
return doneCalled
|
|
end
|
|
|
|
-- === 1) no fossil in inventory: no-fossils text, no flags set ===
|
|
do
|
|
local game = newGame()
|
|
check(talk(game), "no-fossil talk completes")
|
|
check(not game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB, "no fossil: GAVE_FOSSIL_TO_LAB not set")
|
|
check(not game.save.flags.EVENT_LAB_STILL_REVIVING_FOSSIL, "no fossil: STILL_REVIVING not set")
|
|
eq(#game.save.party, 0, "no fossil: party unchanged")
|
|
eq(shownTexts[#shownTexts], "No! Is too bad!{DONE}", "no fossil shows NoFossilsText")
|
|
end
|
|
|
|
-- === 2)-5) full deposit -> pending -> re-entry -> grant cycle ===
|
|
do
|
|
local game = newGame()
|
|
game.save.inventory.OLD_AMBER = 1
|
|
|
|
-- 2) depositing OLD_AMBER through the menu + YES confirm: cleared
|
|
-- from the bag, quest flags set, AERODACTYL not granted yet (same
|
|
-- conversation as the deposit).
|
|
menuPick, choiceAnswer = 1, true
|
|
check(talk(game), "deposit talk completes")
|
|
eq(menuLabels and #menuLabels, 1, "fossil menu lists the one carried fossil")
|
|
eq(menuLabels and menuLabels[1], "OLD AMBER", "fossil menu shows the item name")
|
|
local sees
|
|
for _, s in ipairs(shownTexts) do
|
|
if s:find("Resurrection") then sees = s end
|
|
end
|
|
check(sees and sees:find("OLD AMBER", 1, true) and sees:find("AERODACTYL", 1, true),
|
|
"SeesFossilText names both the fossil (wNameBuffer) and the mon (wStringBuffer)")
|
|
eq(game.save.inventory.OLD_AMBER, nil, "OLD_AMBER cleared from inventory on deposit")
|
|
check(game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB == true, "GAVE_FOSSIL_TO_LAB set on deposit")
|
|
check(game.save.flags.EVENT_LAB_STILL_REVIVING_FOSSIL == true, "STILL_REVIVING set on deposit")
|
|
eq(#game.save.party, 0, "AERODACTYL not granted in the deposit conversation")
|
|
eq(game.save.labFossilMon, "AERODACTYL", "pending species (AERODACTYL) remembered")
|
|
|
|
-- 3) re-talking within the same visit: still pending, no grant
|
|
check(talk(game), "same-visit re-talk completes")
|
|
check(game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB == true,
|
|
"same-visit re-talk: GAVE_FOSSIL_TO_LAB still set")
|
|
check(game.save.flags.EVENT_LAB_STILL_REVIVING_FOSSIL == true,
|
|
"same-visit re-talk: STILL_REVIVING still set")
|
|
eq(#game.save.party, 0, "same-visit re-talk: still no mon granted")
|
|
eq(shownTexts[#shownTexts], "I take a little\ntime!\fYou go for walk a\nlittle while!{DONE}",
|
|
"same-visit re-talk shows GoForAWalkText")
|
|
|
|
-- 4) leaving and re-entering CINNABAR_ISLAND (its onEnter) clears
|
|
-- STILL_REVIVING but leaves GAVE_FOSSIL_TO_LAB set
|
|
story5.CINNABAR_ISLAND.onEnter(game, {})
|
|
check(game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB == true,
|
|
"CINNABAR_ISLAND onEnter: GAVE_FOSSIL_TO_LAB survives the reload")
|
|
check(not game.save.flags.EVENT_LAB_STILL_REVIVING_FOSSIL,
|
|
"CINNABAR_ISLAND onEnter clears STILL_REVIVING")
|
|
|
|
-- 5) talking again grants AERODACTYL at level 30 and resets the whole
|
|
-- quest (all three EVENT_ flags, and the transient species field) so
|
|
-- a second fossil can be deposited later
|
|
check(talk(game), "ready talk completes")
|
|
eq(#game.save.party, 1, "AERODACTYL granted into the party after re-entry")
|
|
eq(game.save.party[1] and game.save.party[1].species, "AERODACTYL",
|
|
"granted species is AERODACTYL")
|
|
eq(game.save.party[1] and game.save.party[1].level, 30, "AERODACTYL granted at level 30")
|
|
check(not game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB, "grant resets GAVE_FOSSIL_TO_LAB")
|
|
check(not game.save.flags.EVENT_LAB_STILL_REVIVING_FOSSIL, "grant resets STILL_REVIVING")
|
|
check(not game.save.flags.EVENT_LAB_HANDING_OVER_FOSSIL_MON, "grant resets HANDING_OVER_FOSSIL_MON")
|
|
eq(game.save.labFossilMon, nil, "pending species cleared after grant")
|
|
-- GivePokemon prints for itself (engine/events/give_pokemon.asm:52-71)
|
|
local sawGot, sawNick = false, false
|
|
for _, s in ipairs(shownTexts) do
|
|
if s:find("got", 1, true) and s:find("AERODACTYL", 1, true) then sawGot = true end
|
|
if s:find("nickname", 1, true) then sawNick = true end
|
|
end
|
|
check(sawGot, "the grant prints _GotMonText")
|
|
check(sawNick, "and asks for a nickname (AddPartyMon -> AskName)")
|
|
end
|
|
|
|
-- === the menu lists every carried fossil in FossilsList scan order
|
|
-- (DOME_FOSSIL, HELIX_FOSSIL, OLD_AMBER) and deposits the chosen one ===
|
|
do
|
|
local game = newGame()
|
|
game.save.inventory.OLD_AMBER = 1
|
|
game.save.inventory.HELIX_FOSSIL = 1
|
|
menuPick, choiceAnswer = 1, true
|
|
check(talk(game), "multi-fossil deposit talk completes")
|
|
eq(menuLabels and #menuLabels, 2, "menu lists both carried fossils")
|
|
eq(menuLabels and menuLabels[1], "HELIX FOSSIL", "HELIX FOSSIL listed first (FossilsList order)")
|
|
eq(menuLabels and menuLabels[2], "OLD AMBER", "OLD AMBER listed second")
|
|
eq(game.save.labFossilMon, "OMANYTE", "choosing HELIX FOSSIL deposits it")
|
|
eq(game.save.inventory.HELIX_FOSSIL, nil, "HELIX_FOSSIL cleared from inventory")
|
|
eq(game.save.inventory.OLD_AMBER, 1, "OLD_AMBER left untouched for a later visit")
|
|
end
|
|
|
|
-- === backing out of the menu with B: ComeAgainText, nothing taken
|
|
-- (GiveFossilToCinnabarLab .cancelledGivingFossil) ===
|
|
do
|
|
local game = newGame()
|
|
game.save.inventory.DOME_FOSSIL = 1
|
|
menuPick = "cancel"
|
|
check(talk(game), "menu-cancel talk completes")
|
|
eq(shownTexts[#shownTexts], "Aiyah! You come\nagain!{DONE}", "menu B-out shows ComeAgainText")
|
|
eq(game.save.inventory.DOME_FOSSIL, 1, "fossil kept after menu cancel")
|
|
check(not game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB, "menu cancel sets no quest flags")
|
|
eq(game.save.labFossilMon, nil, "menu cancel leaves no pending species")
|
|
end
|
|
|
|
-- === answering NO on the SeesFossilText confirm: same cancel path ===
|
|
do
|
|
local game = newGame()
|
|
game.save.inventory.DOME_FOSSIL = 1
|
|
menuPick, choiceAnswer = 1, false
|
|
check(talk(game), "confirm-NO talk completes")
|
|
eq(shownTexts[#shownTexts], "Aiyah! You come\nagain!{DONE}", "NO on the confirm shows ComeAgainText")
|
|
eq(game.save.inventory.DOME_FOSSIL, 1, "fossil kept after NO")
|
|
check(not game.save.flags.EVENT_GAVE_FOSSIL_TO_LAB, "NO sets no quest flags")
|
|
eq(game.save.labFossilMon, nil, "NO leaves no pending species")
|
|
end
|
|
|
|
package.loaded["src.render.TextBox"] = realTextBox
|
|
package.loaded["src.ui.Menu"] = realMenu
|
|
package.loaded["src.script.Commands"] = realCommands
|
|
|
|
S.finish()
|