Files
gen1recomp/tests/engine/oaks_aide_requirement_bug1006.lua

218 lines
8.7 KiB
Lua

-- Oak's aide quotes the REQUIREMENT, not your current count (#1006).
-- pokered engine/events/oaks_aide.asm .notEnoughOwnedMons.
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 data/text/text_1.asm
Data.text._OaksAideHiText =
"Hi! Remember me?\nI'm PROF.OAK's\vAIDE!\fIf you caught " ..
"{NUM:hOaksAideRequirement, 1, 3}\nkinds of POKéMON,\vI'm supposed to\v" ..
"give you an\v{RAM:wOaksAideRewardItemName}!\fSo, {PLAYER}! Have\n" ..
"you caught at\vleast {NUM:hOaksAideRequirement, 1, 3} kinds of\vPOKéMON?"
Data.text._OaksAideUhOhText =
"Let's see...\nUh-oh! You have\vcaught only " ..
"{NUM:hOaksAideNumMonsOwned, 1, 3}\vkinds of POKéMON!\fYou need " ..
"{NUM:hOaksAideRequirement, 1, 3} kinds\nif you want the\v" ..
"{RAM:wOaksAideRewardItemName}."
Data.text._OaksAideComeBackText =
"Oh. I see.\fWhen you get {NUM:hOaksAideRequirement, 1, 3}\nkinds, come " ..
"back\vfor {RAM:wOaksAideRewardItemName}."
Data.text._OaksAideHereYouGoText =
"Great! You have\ncaught {NUM:hOaksAideNumMonsOwned, 1, 3} kinds \v" ..
"of POKéMON!\vCongratulations!\fHere you go!"
Data.text._OaksAideGotItemText =
"{PLAYER} got the\n{RAM:wOaksAideRewardItemName}!"
Data.text._OaksAideNoRoomText =
"Oh! I see you\ndon't have any\vroom for the\v{RAM:wOaksAideRewardItemName}."
-- ../pokered/scripts/Route2Gate.asm:34-36, Route11Gate2F.asm:45-47
Data.text._Route2GateOaksAideFlashExplanationText =
"The HM FLASH\nlights even the\vdarkest dungeons."
Data.text._Route11Gate2FOaksAideItemfinderDescriptionText =
"There are items on\nthe ground that\vcan't be seen.\fITEMFINDER will\n" ..
"detect an item\vclose to you."
Data.items.HM_FLASH = { id = "HM_FLASH", index = 196, name = "HM FLASH" }
Data.items.ITEMFINDER = { id = "ITEMFINDER", index = 6, name = "ITEMFINDER" }
local SaveData = require("src.core.SaveData")
local pushed = {}
local realTextBox = package.loaded["src.render.TextBox"]
package.loaded["src.render.TextBox"] = {
new = function(_, text, onDone, opts)
return { text = text, onDone = onDone, opts = opts }
end,
soundOpts = function(_, sound, opts)
opts = opts or {}
opts.auto = { wait = true, delay = 0, sound = function() return sound end }
return opts
end,
}
local story4 = dofile("data/scripts/story4.lua")
local ROUTE_11 = story4.ROUTE_11_GATE_2F.talk.TEXT_ROUTE11GATE2F_OAKS_AIDE
local ROUTE_2 = story4.ROUTE_2_GATE.talk.TEXT_ROUTE2GATE_OAKS_AIDE
T.check(type(ROUTE_11) == "function" and type(ROUTE_2) == "function",
"both aides are wired to the shared oaksAide handler")
local game = {
data = Data,
save = SaveData.newGame(),
stack = { push = function(_, box) pushed[#pushed + 1] = box end },
}
local function reset(ownedCount)
game.save = SaveData.newGame()
game.save.player.name = "RED"
local owned = {}
for i = 1, ownedCount do owned["SPECIES_" .. i] = true end
game.save.pokedex = { seen = {}, owned = owned }
pushed = {}
end
local function lastText()
return tostring(pushed[#pushed] and pushed[#pushed].text)
end
local function has(fragment)
return lastText():find(fragment, 1, true) ~= nil
end
local function held(id)
return game.save.inventory[id] or 0
end
-- A press on the box that is up
local function dismiss()
local box = pushed[#pushed]
if box and box.onDone then box.onDone() end
end
-- === the aide asks for his own threshold, whatever the player owns
reset(12)
local done = false
ROUTE_11(game, {}, {}, function() done = true end)
local offer = pushed[1]
T.check(offer.opts and offer.opts.choice ~= nil,
"the aide's opener is the YesNoChoice question")
T.check(has("least 30 kinds"), "opener asks for the aide's 30 kinds")
T.check(has("give you an\vITEMFINDER"), "opener names the reward item")
T.check(not has("{NUM"), "no placeholder survives into the opener")
-- === YES with too few kinds: both decimals are filled, and differently
offer.opts.choice(true)
T.check(has("caught only 12"), "Uh-oh line reports the kinds actually owned")
T.check(has("You need 30 kinds"), "Uh-oh line then states the requirement")
T.check(not has("You need 12 kinds"),
"the requirement is not overwritten by the owned count (#1006)")
T.check(has("want the\vITEMFINDER"), "Uh-oh line still names the reward")
dismiss()
T.check(done, "the Uh-oh branch completes the talk")
T.eq(held("ITEMFINDER"), 0, "no reward below the threshold")
T.check(not game.save.flags.EVENT_GOT_ITEMFINDER,
"the aide can still be asked again")
-- === the threshold tracks the aide, not a constant: Route 2 wants 10
reset(3)
ROUTE_2(game, {}, {}, function() end)
pushed[1].opts.choice(true)
T.check(has("caught only 3"), "Route 2 Uh-oh reports 3 kinds owned")
T.check(has("You need 10 kinds"), "Route 2 states its own 10-kind threshold")
T.check(has("want the\vHM FLASH"), "Route 2 names the HM FLASH reward")
-- === NO: ComeBackText quotes the requirement, nothing is given
reset(12)
done = false
ROUTE_11(game, {}, {}, function() done = true end)
pushed[1].opts.choice(false)
T.check(has("When you get 30"), "come-back line quotes the requirement")
T.check(has("back\vfor ITEMFINDER"), "come-back line names the reward")
dismiss()
T.check(done, "declining completes the talk")
T.eq(held("ITEMFINDER"), 0, "declining gives nothing")
-- === YES at the threshold: HereYouGo carries the OWNED count, then the
reset(30)
done = false
ROUTE_11(game, {}, {}, function() done = true end)
pushed[1].opts.choice(true)
T.check(has("caught 30 kinds"), "congratulation line carries the owned count")
T.eq(held("ITEMFINDER"), 0,
"the congratulation comes before GiveItem (oaks_aide.asm:18-25)")
dismiss()
T.check(has("RED got the\nITEMFINDER!"), "the item line names player and item")
local gotBox = pushed[#pushed]
T.check(gotBox.opts and gotBox.opts.auto
and type(gotBox.opts.auto.sound) == "function",
"the got-item box carries sound_get_item_1 (oaks_aide.asm:64-67)")
T.check(gotBox.opts.auto.wait == true,
"the fanfare box still waits for the button press")
T.check(not done, "the talk does not end on the got-item box")
dismiss()
T.check(has("ITEMFINDER will"),
"the aide explains the reward right after giving it (Route11Gate2F.asm:39-41)")
dismiss()
T.check(done, "the explanation box is what completes the talk")
T.eq(held("ITEMFINDER"), 1, "ITEMFINDER lands in the bag")
T.check(game.save.flags.EVENT_GOT_ITEMFINDER, "the aide's event flag is set")
-- === repeat visit: the explanation text, no second ITEMFINDER
pushed = {}
done = false
ROUTE_11(game, {}, {}, function() done = true end)
T.eq(#pushed, 1, "a served player gets exactly one box")
T.check(pushed[1].opts == nil or pushed[1].opts.choice == nil,
"the repeat line is not a question")
T.check(has("ITEMFINDER will"), "the repeat line is the same explanation")
T.eq(held("ITEMFINDER"), 1, "no second ITEMFINDER")
-- === ../pokered/scripts/Route2Gate.asm:11 EVENT_GOT_HM05
reset(10)
done = false
ROUTE_2(game, {}, {}, function() done = true end)
pushed[1].opts.choice(true)
dismiss()
dismiss()
T.check(has("The HM FLASH"), "Route 2 falls through to the FLASH explanation")
dismiss()
T.check(done, "Route 2 reward branch completes on the explanation")
T.eq(held("HM_FLASH"), 1, "HM FLASH lands in the bag")
T.check(game.save.flags.EVENT_GOT_HM05,
"Route 2 sets EVENT_GOT_HM05, the name the save crosswalk knows")
T.check(not game.save.flags.EVENT_GOT_HM_FLASH,
"the port-local EVENT_GOT_HM_FLASH name is gone")
-- === ../pokered/engine/events/oaks_aide.asm:18-32 .bagFull
local Bag = require("src.inventory.Bag")
reset(30)
done = false
for i = 1, Bag.capacity(Data, "ITEM") do
game.save.inventory["FILLER_" .. i] = 1
end
ROUTE_11(game, {}, {}, function() done = true end)
pushed[1].opts.choice(true)
T.check(has("caught 30 kinds"), "a full bag still gets the congratulation")
dismiss()
T.check(has("room for the\vITEMFINDER"), "then the no-room line")
dismiss()
T.check(done, "the no-room branch ends the talk with no explanation")
T.eq(held("ITEMFINDER"), 0, "nothing is given when the bag is full")
T.check(not game.save.flags.EVENT_GOT_ITEMFINDER,
"a failed give leaves the aide's flag clear (OAKS_AIDE_BAG_FULL)")
reset(10)
done = false
game.save.flags.EVENT_GOT_HM_FLASH = true
ROUTE_2(game, {}, {}, function() done = true end)
T.eq(#pushed, 1, "the old EVENT_GOT_HM_FLASH name still serves one box")
T.check(pushed[1].opts == nil or pushed[1].opts.choice == nil,
"an old save is not asked the question again")
T.check(has("The HM FLASH"), "an old save gets the explanation line")
T.eq(held("HM_FLASH"), 0, "an old save gets no second HM FLASH")
if realTextBox ~= nil then
package.loaded["src.render.TextBox"] = realTextBox
else
package.loaded["src.render.TextBox"] = nil
end
T.finish("oaks_aide_requirement_bug1006")