mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 05:32:07 -04:00
197 lines
6.5 KiB
Lua
197 lines
6.5 KiB
Lua
-- engine/menus/start_sub_menus.asm:330-362, 424-439;
|
|
-- engine/items/item_effects.asm:2547-2595
|
|
-- Self-contained; run via `luajit tests/parity_bag_toss_bug2247.lua`.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
if not _G.love then _G.love = require("tests.love_stub") end
|
|
local S = require("tests.harness").suite("parity bag toss #2247")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local Data = require("src.core.Data")
|
|
Data:load()
|
|
|
|
local Bag = require("src.inventory.Bag")
|
|
local Timing = require("src.core.Timing")
|
|
|
|
local realTextBox = package.loaded["src.render.TextBox"]
|
|
local realBag = package.loaded["src.ui.BagMenu"]
|
|
local soundOpts = require("src.render.TextBox").soundOpts
|
|
local strip = require("src.render.TextBox").strip
|
|
package.loaded["src.render.TextBox"] = {
|
|
new = function(_, text, done, opts)
|
|
return { textBox = true, text = text, done = done, opts = opts }
|
|
end,
|
|
soundOpts = soundOpts,
|
|
strip = strip,
|
|
}
|
|
package.loaded["src.ui.BagMenu"] = nil
|
|
local BagMenu = require("src.ui.BagMenu")
|
|
local Menu = require("src.ui.Menu")
|
|
local QuantityBox = require("src.ui.QuantityBox")
|
|
local ChoiceBox = require("src.ui.ChoiceBox")
|
|
require("src.ui.Screens").invalidate()
|
|
|
|
local function newStack()
|
|
local stack = { states = {} }
|
|
function stack:push(s) self.states[#self.states + 1] = s end
|
|
function stack:pop() return table.remove(self.states) end
|
|
function stack:top() return self.states[#self.states] end
|
|
return stack
|
|
end
|
|
|
|
local function newInput()
|
|
local input = { pressed = nil }
|
|
function input:wasPressed(b) return self.pressed == b end
|
|
return input
|
|
end
|
|
|
|
local function freshGame(id, n)
|
|
local game = {
|
|
data = Data,
|
|
stack = newStack(),
|
|
input = newInput(),
|
|
save = {
|
|
party = {},
|
|
player = { name = "RED" },
|
|
inventory = {},
|
|
options = {},
|
|
pokedex = { seen = {}, owned = {} },
|
|
flags = {},
|
|
money = 0,
|
|
},
|
|
}
|
|
Bag.add(game.save, id, n)
|
|
return game
|
|
end
|
|
|
|
local function isBox(s) return type(s) == "table" and s.textBox == true end
|
|
local function is(s, class) return getmetatable(s) == class end
|
|
|
|
local function press(game, state, btn)
|
|
game.input.pressed = btn
|
|
state:update(1 / 60)
|
|
game.input.pressed = nil
|
|
end
|
|
|
|
local function dismiss(stack, box)
|
|
if stack:top() == box then stack:pop() end
|
|
if box.done then box.done() end
|
|
end
|
|
|
|
local function rowFor(list, id)
|
|
for i, r in ipairs(list.items) do
|
|
if r.value == id then return i end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function names(stack)
|
|
local out = {}
|
|
for _, s in ipairs(stack.states) do
|
|
out[#out + 1] = is(s, Menu) and "Menu" or is(s, QuantityBox) and "QuantityBox"
|
|
or is(s, ChoiceBox) and "ChoiceBox" or isBox(s) and "TextBox"
|
|
or (s.items and "ListMenu") or "?"
|
|
end
|
|
return table.concat(out, ",")
|
|
end
|
|
|
|
local function chooseToss(game, id)
|
|
local list = BagMenu.new(game, {})
|
|
game.stack:push(list)
|
|
local row = rowFor(list, id)
|
|
list.index = row
|
|
list.onChoose(list.items[row], list)
|
|
local sub = game.stack:top()
|
|
check(is(sub, Menu), "USE/TOSS menu opened")
|
|
sub.noSound = true
|
|
sub.index = 2
|
|
eq(sub.items[2].label, "TOSS", "row 2 is TOSS")
|
|
press(game, sub, "a")
|
|
return list, row, sub
|
|
end
|
|
|
|
local function answer(game, choice, btn)
|
|
press(game, choice, btn)
|
|
for _ = 1, Timing.YES_NO_ANSWER + 1 do
|
|
if game.stack:top() ~= choice then break end
|
|
choice:update(1 / 60)
|
|
end
|
|
check(game.stack:top() ~= choice, "the YES/NO box came down after the hold")
|
|
end
|
|
|
|
do
|
|
local game = freshGame("GREAT_BALL", 14)
|
|
local list, row, sub = chooseToss(game, "GREAT_BALL")
|
|
-- start_sub_menus.asm:362
|
|
eq(names(game.stack), "ListMenu,Menu,QuantityBox",
|
|
"TOSS keeps the USE/TOSS menu up under the quantity box")
|
|
eq(sub.hollowIndex, 2, "TOSS row keeps the hollow cursor")
|
|
|
|
local qbox = game.stack:top()
|
|
press(game, qbox, "a")
|
|
eq(names(game.stack), "ListMenu,Menu,QuantityBox,TextBox",
|
|
"A on the quantity box prints over the kept boxes")
|
|
local ask = game.stack:top()
|
|
check(ask.text:find("^Is it OK to toss") ~= nil, "it is the IsItOKToTossItemText")
|
|
check(ask.text:find("GREAT BALL", 1, true) ~= nil, "naming the item")
|
|
check(ask.text:find("{RAM:", 1, true) == nil, "wStringBuffer is filled in")
|
|
check(ask.opts and ask.opts.stay and ask.opts.stay.prompt == true,
|
|
"it is a prompt the box stays up under")
|
|
eq(game.save.inventory.GREAT_BALL, 14, "nothing removed yet")
|
|
|
|
ask.opts.stay.onShown()
|
|
eq(names(game.stack), "ListMenu,Menu,QuantityBox,TextBox,ChoiceBox",
|
|
"YES/NO only after A on the prompt")
|
|
eq(game.save.inventory.GREAT_BALL, 14, "still nothing removed")
|
|
|
|
answer(game, game.stack:top(), "a")
|
|
eq(game.save.inventory.GREAT_BALL, 13, "YES removes the item")
|
|
eq(list.items[row].count, 14, "but the list row still shows the old count")
|
|
eq(names(game.stack), "ListMenu,Menu,QuantityBox,TextBox",
|
|
"Threw away prints over the kept quantity box and menu")
|
|
local threw = game.stack:top()
|
|
check(threw.text:find("^Threw away") ~= nil, "it is ThrewAwayItemText")
|
|
|
|
dismiss(game.stack, threw)
|
|
eq(names(game.stack), "ListMenu", "ItemMenuLoop: every box is gone")
|
|
eq(list.items[row].count, 13, "and the list is redrawn with the new count")
|
|
eq(list.index, row, "cursor still on the row")
|
|
end
|
|
|
|
do
|
|
local game = freshGame("GREAT_BALL", 14)
|
|
local list, row = chooseToss(game, "GREAT_BALL")
|
|
press(game, game.stack:top(), "b")
|
|
eq(names(game.stack), "ListMenu", "B drops the quantity box and the menu")
|
|
eq(game.save.inventory.GREAT_BALL, 14, "inventory intact")
|
|
eq(list.items[row].count, 14, "list intact")
|
|
end
|
|
|
|
do
|
|
local game = freshGame("GREAT_BALL", 14)
|
|
local list, row = chooseToss(game, "GREAT_BALL")
|
|
press(game, game.stack:top(), "a")
|
|
game.stack:top().opts.stay.onShown()
|
|
answer(game, game.stack:top(), "b")
|
|
eq(names(game.stack), "ListMenu", "NO drops the prompt, quantity box and menu")
|
|
eq(game.save.inventory.GREAT_BALL, 14, "inventory intact")
|
|
eq(list.items[row].count, 14, "list intact")
|
|
end
|
|
|
|
do
|
|
local game = freshGame("TOWN_MAP", 1)
|
|
local list, row = chooseToss(game, "TOWN_MAP")
|
|
eq(names(game.stack), "ListMenu,Menu,TextBox",
|
|
"the refusal prints over the kept USE/TOSS menu")
|
|
local msg = game.stack:top()
|
|
check(msg.text:find("too impor", 1, true) ~= nil, "it is TooImportantToTossText")
|
|
dismiss(game.stack, msg)
|
|
eq(names(game.stack), "ListMenu", "and dismissing it drops the menu too")
|
|
eq(game.save.inventory.TOWN_MAP, 1, "inventory intact")
|
|
eq(list.items[row].value, "TOWN_MAP", "list intact")
|
|
end
|
|
|
|
package.loaded["src.render.TextBox"] = realTextBox
|
|
package.loaded["src.ui.BagMenu"] = realBag
|
|
require("src.ui.Screens").invalidate()
|
|
S.finish()
|