mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
165 lines
5.7 KiB
Lua
165 lines
5.7 KiB
Lua
-- Prof. Oak's PC session (#576): engine/menus/oaks_pc.asm OpenOaksPC --
|
|
-- the access text, "Want to get your #DEX rated?" with a YES/NO, the dex
|
|
-- rating (completion line + tier text), the rating jingle only once the
|
|
-- rating text has printed (DisplayDexRating -> PlayPokedexRatingSfx), and
|
|
-- the "Closed link to PROF.OAK's PC." tail before control returns. The
|
|
-- old flow played the jingle the moment the entry was picked and skipped
|
|
-- both the intro and the closing link.
|
|
-- ROM-free: uses the fixture dataset so CI (no data/generated/) stays green.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.modkit")
|
|
local Data = T.fixtures.load()
|
|
|
|
-- the ROM-extracted strings the fixture text table does not carry; labels
|
|
-- and wording match pokered text/pokedex_ratings.asm + oaks_pc.asm
|
|
Data.text._AccessedOaksPCText =
|
|
"Accessed PROF.\nOAK's PC.\fAccessed #DEX\nRating System."
|
|
Data.text._GetDexRatedText = "Want to get your\n#DEX rated?"
|
|
Data.text._ClosedOaksPCText = "Closed link to\nPROF.OAK's PC."
|
|
Data.text._DexCompletionText =
|
|
"#DEX comp-\nletion is:\f{NUM:hDexRatingNumMonsSeen} #MON seen\n" ..
|
|
"{NUM:hDexRatingNumMonsOwned} #MON owned\fPROF.OAK's\nRating:"
|
|
Data.text._DexRatingText_Own50To59 =
|
|
"You finally got at\nleast 50 species!"
|
|
|
|
local SaveData = require("src.core.SaveData")
|
|
local OW = require("src.world.OverworldController")
|
|
|
|
local function setUpvalue(fn, name, val)
|
|
local i = 1
|
|
while true do
|
|
local n = debug.getupvalue(fn, i)
|
|
if not n then return false end
|
|
if n == name then debug.setupvalue(fn, i, val); return true end
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
local pushed = {}
|
|
local plays = {}
|
|
local stackStub = {
|
|
push = function(_, item)
|
|
pushed[#pushed + 1] = item
|
|
end,
|
|
}
|
|
local textBoxStub = {
|
|
new = function(_, text, onDone, opts)
|
|
return { kind = "text", text = text, onDone = onDone, opts = opts }
|
|
end,
|
|
}
|
|
local menuStub = {
|
|
new = function(_, items, opts)
|
|
return { kind = "menu", items = items, opts = opts or {} }
|
|
end,
|
|
}
|
|
-- Sound / Menu are required lazily at the call sites; stub via package.loaded
|
|
local realSound = package.loaded["src.core.Sound"]
|
|
package.loaded["src.core.Sound"] = {
|
|
play = function(_, name)
|
|
plays[#plays + 1] = name
|
|
end,
|
|
playCry = function() end,
|
|
}
|
|
local realMenu = package.loaded["src.ui.Menu"]
|
|
package.loaded["src.ui.Menu"] = menuStub
|
|
|
|
local fakeGame = {
|
|
data = Data,
|
|
save = SaveData.newGame(),
|
|
stack = stackStub,
|
|
}
|
|
for _, name in ipairs({ "openOaksPC", "dexRating" }) do
|
|
T.check(setUpvalue(OW[name], "TextBox", textBoxStub),
|
|
("TextBox upvalue on %s"):format(name))
|
|
T.check(setUpvalue(OW[name], "Game", fakeGame),
|
|
("Game upvalue on %s"):format(name))
|
|
end
|
|
T.check(setUpvalue(OW.openPC, "Game", fakeGame), "Game upvalue on openPC")
|
|
|
|
local fakeSelf = setmetatable({}, { __index = OW })
|
|
|
|
local function lastPush()
|
|
return pushed[#pushed]
|
|
end
|
|
local function reset()
|
|
fakeGame.save = SaveData.newGame()
|
|
fakeGame.save.flags.EVENT_GOT_POKEDEX = true
|
|
local seen, owned = {}, {}
|
|
for i = 1, 55 do seen[i] = true; owned[i] = true end
|
|
fakeGame.save.pokedex = { seen = seen, owned = owned }
|
|
pushed = {}
|
|
plays = {}
|
|
end
|
|
local function runChain()
|
|
-- A through every box that is up; the choice box answers YES
|
|
local guard = 0
|
|
while lastPush() and lastPush().kind == "text" and guard < 10 do
|
|
guard = guard + 1
|
|
local box = lastPush()
|
|
if box.opts and box.opts.choice then
|
|
box.opts.choice(true)
|
|
elseif box.onDone then
|
|
box.onDone()
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
-- === full session from the launcher menu: intro, YES, rating, jingle, close
|
|
reset()
|
|
local done = false
|
|
fakeSelf:openPC(function() done = true end)
|
|
local menu = lastPush()
|
|
T.eq(menu.kind, "menu", "openPC pushes the PC menu")
|
|
local oak
|
|
for _, item in ipairs(menu.items) do
|
|
if item.label == "PROF.OAK's PC" then oak = item end
|
|
end
|
|
T.check(oak ~= nil, "PROF.OAK's PC is offered once the Pokédex is had")
|
|
oak.onSelect()
|
|
-- drop the menu's Turn_On_PC and the row's Enter_PC
|
|
plays = {}
|
|
T.eq(pushed[2].kind, "text", "selection opens the access text")
|
|
T.check(tostring(pushed[2].text):find("Accessed", 1, true) ~= nil,
|
|
"first session box is the access text")
|
|
runChain()
|
|
T.check(done, "session completes")
|
|
T.check(pushed[3].opts ~= nil and pushed[3].opts.choice ~= nil,
|
|
"the rated question carries the YES/NO choice")
|
|
T.check(tostring(pushed[3].text):find("rated", 1, true) ~= nil,
|
|
"second session box asks for the rating")
|
|
local ratingBox = pushed[4]
|
|
T.check(ratingBox.opts and ratingBox.opts.auto ~= nil
|
|
and ratingBox.opts.auto.wait ~= nil,
|
|
"rating box sounds the jingle then waits for a button")
|
|
T.check(tostring(ratingBox.text):find("55", 1, true) ~= nil,
|
|
"completion line carries the seen/owned counts")
|
|
T.check(tostring(ratingBox.text):find("least 50 species", 1, true) ~= nil,
|
|
"rating box carries the Own50To59 tier text")
|
|
T.eq(#plays, 0, "no jingle while the evaluation is printing")
|
|
ratingBox.opts.auto.sound()
|
|
T.eq(#plays, 1, "jingle fires once the rating text is printed")
|
|
T.eq(plays[1], "Pokedex_Rating", "jingle is the Pokedex_Rating fanfare")
|
|
T.check(tostring(pushed[5].text):find("Closed link", 1, true) ~= nil,
|
|
"the closing link prints at the end of the session")
|
|
|
|
-- === declining the rating skips the evaluation but still closes the link
|
|
reset()
|
|
done = false
|
|
fakeSelf:openOaksPC(function() done = true end)
|
|
T.eq(pushed[1].kind, "text", "openOaksPC opens with the access text")
|
|
pushed[1].onDone()
|
|
T.check(pushed[2].opts and pushed[2].opts.choice ~= nil,
|
|
"rated question is a YES/NO")
|
|
pushed[2].opts.choice(false)
|
|
T.check(tostring(lastPush().text):find("Closed link", 1, true) ~= nil,
|
|
"NO skips the rating and closes the PC")
|
|
T.eq(#plays, 0, "declining plays no jingle")
|
|
|
|
package.loaded["src.ui.Menu"] = realMenu
|
|
if realSound ~= nil then package.loaded["src.core.Sound"] = realSound end
|
|
|
|
T.finish("oaks_pc_flow")
|