mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-25 15:01:11 +02:00
1905261c5b
CLOSES #1483, CLOSES #1610, CLOSES #1615, CLOSES #1646, CLOSES #1649, CLOSES #1651, CLOSES #1653, CLOSES #1656, CLOSES #1683, CLOSES #1685, CLOSES #1686, CLOSES #1687, CLOSES #1688, CLOSES #1689, CLOSES #1690, CLOSES #1693, CLOSES #1694, CLOSES #1695, CLOSES #1696, CLOSES #1702, CLOSES #1704, CLOSES #1705, CLOSES #1706, CLOSES #1707, CLOSES #1708, CLOSES #1710, CLOSES #1711, CLOSES #1712, CLOSES #1713, CLOSES #1716, CLOSES #1717, CLOSES #1718, CLOSES #1719, CLOSES #1720, CLOSES #1721, CLOSES #1725, CLOSES #1732, CLOSES #1745, CLOSES #1748, CLOSES #1749, CLOSES #1751, CLOSES #1754
254 lines
9.2 KiB
Lua
254 lines
9.2 KiB
Lua
-- The bag list ends on the terminator's CANCEL row (#1685).
|
|
--
|
|
-- pokered's item lists are $ff-terminated. PrintListMenuEntries walks four
|
|
-- entries and, on the terminator, `jp z, .printCancelMenuItem` -- which is
|
|
-- `ld de, ListMenuCancelText / jp PlaceString`, a TAIL jump that RETURNS
|
|
-- from PrintListMenuEntries (home/list_menu.asm:371-372, 523-528). The '▼'
|
|
-- at :518-522 is only reached by the fall-through, so any page showing
|
|
-- CANCEL shows no down arrow. DisplayListMenuIDLoop compares the selection
|
|
-- against wListCount and takes ExitListMenu when it is the row past the last
|
|
-- item (:105-110), which is the same exit B takes.
|
|
--
|
|
-- The port emitted one row per bag entry and stopped, so the list had no
|
|
-- CANCEL to walk onto and printed an invented "Nothing here." when the bag
|
|
-- was empty.
|
|
-- luajit tests/engine/bag_cancel_row_bug1685.lua
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
love = love or require("tests.love_stub")
|
|
|
|
-- Font wants a real atlas and this suite is about what lands on which row,
|
|
-- so it records the calls instead (the shape tests/engine/
|
|
-- bag_item_box_bug1521.lua uses). ListMenu and Theme bind Font at require
|
|
-- time, and BagMenu binds ListMenu and TextBox at require time.
|
|
local calls = {}
|
|
package.loaded["src.render.Font"] = {
|
|
BORDER = { tl = 1, tr = 2, bl = 3, br = 4, h = 5, v = 6 },
|
|
draw = function(text, x, y) calls[#calls + 1] = { "draw", text, x, y } end,
|
|
drawCode = function(code, x, y) calls[#calls + 1] = { "code", code, x, y } end,
|
|
drawBox = function(tx, ty, tw, th) calls[#calls + 1] = { "box", tx, ty, tw, th } end,
|
|
width = function(text) return #tostring(text) * 8 end,
|
|
-- Menu.new sizes its box off split(); reaching it at all is the failure
|
|
-- this suite reports, so the stub answers instead of erroring
|
|
split = function(text)
|
|
local spans = {}
|
|
for i = 1, #tostring(text) do spans[i] = { from = i, to = i, code = 0 } end
|
|
return spans
|
|
end,
|
|
}
|
|
package.loaded["src.core.Sound"] = { play = function() end, playCry = function() end }
|
|
package.loaded["src.render.TextBox"] = {
|
|
new = function(_, text, done) return { textBox = true, text = text, done = done } end,
|
|
soundOpts = function() return nil end,
|
|
}
|
|
package.loaded["src.ui.ListMenu"] = nil
|
|
package.loaded["src.ui.Theme"] = nil
|
|
package.loaded["src.ui.BagMenu"] = nil
|
|
local ListMenu = require("src.ui.ListMenu")
|
|
local Theme = require("src.ui.Theme")
|
|
local BagMenu = require("src.ui.BagMenu")
|
|
require("src.ui.Screens").invalidate()
|
|
|
|
local Fixtures = require("tests.modkit.fixtures")
|
|
local Bag = require("src.inventory.Bag")
|
|
local Strings = require("src.core.Strings")
|
|
|
|
local CANCEL = Strings("CANCEL")
|
|
|
|
local Data = Fixtures.fresh()
|
|
for i = 1, 6 do
|
|
local id = "FIXITEM_" .. i
|
|
Data.items[id] = { id = id, index = 100 + i, name = "FIX ITEM " .. i,
|
|
price = 100, tossable = true }
|
|
end
|
|
|
|
local function freshGame(count)
|
|
local game = {
|
|
data = Data,
|
|
save = {
|
|
party = {},
|
|
player = { name = "RED", id = 1 },
|
|
inventory = {},
|
|
options = {},
|
|
flags = {},
|
|
money = 0,
|
|
},
|
|
}
|
|
game.stack = {
|
|
states = {},
|
|
push = function(self, s) table.insert(self.states, s) end,
|
|
pop = function(self) return table.remove(self.states) end,
|
|
top = function(self) return self.states[#self.states] end,
|
|
}
|
|
-- one button edge per update, the way Input reports a fixed step
|
|
game.input = { pressed = nil }
|
|
function game.input:wasPressed(b) return self.pressed == b end
|
|
function game.input:isDown() return false end
|
|
for i = 1, count do Bag.add(game.save, "FIXITEM_" .. i, i) end
|
|
return game
|
|
end
|
|
|
|
local function openBag(game, opts)
|
|
local list = BagMenu.new(game, opts)
|
|
game.stack:push(list)
|
|
return list
|
|
end
|
|
|
|
local function found(kind, pred)
|
|
for _, c in ipairs(calls) do
|
|
if c[1] == kind and pred(c) then return c end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function drawnAt(text, x, y)
|
|
return found("draw", function(c)
|
|
return c[2] == text and c[3] == x and (y == nil or c[4] == y)
|
|
end)
|
|
end
|
|
|
|
local function press(list, btn)
|
|
list.game.input.pressed = btn
|
|
list:update(1 / 60)
|
|
list.game.input.pressed = nil
|
|
end
|
|
|
|
-- the row itself: one CANCEL after the last bag entry, carrying no id and no
|
|
-- quantity (home/list_menu.asm:523-528)
|
|
do
|
|
local game = freshGame(6)
|
|
local list = openBag(game)
|
|
eq(#list.items, 7, "six bag entries plus the terminator's CANCEL row")
|
|
local last = list.items[#list.items]
|
|
eq(last.label, CANCEL, "the last row is CANCEL")
|
|
eq(last.cancel, true, "flagged as the terminator row, not an item")
|
|
eq(last.value, nil, "with no item id behind it")
|
|
eq(last.right, nil, "and no 'xN' count (PrintListMenuEntries never gets "
|
|
.. "that far for the terminator)")
|
|
eq(CANCEL, "CANCEL", "ListMenuCancelText reads CANCEL")
|
|
for i = 1, 6 do
|
|
eq(list.items[i].value, "FIXITEM_" .. i, "row " .. i .. " is still its item")
|
|
end
|
|
end
|
|
|
|
-- page one of a long list: four real names, the '▼', no CANCEL yet
|
|
do
|
|
local game = freshGame(6)
|
|
local list = openBag(game)
|
|
calls = {}
|
|
list:draw()
|
|
for row = 1, 4 do
|
|
local y = 32 + (row - 1) * 16
|
|
check(drawnAt("FIX ITEM " .. row, 48, y) ~= nil,
|
|
"name " .. row .. " sits at (48, " .. y .. ")")
|
|
end
|
|
check(found("draw", function(c) return c[2] == CANCEL end) == nil,
|
|
"CANCEL is below the fold on page one, not printed on it")
|
|
check(found("code", function(c)
|
|
return c[2] == Theme.moreArrow and c[3] == 144 and c[4] == 88
|
|
end) ~= nil, "four real rows fill the page, so the '▼' prints (:518-522)")
|
|
end
|
|
|
|
-- walking down: the cursor reaches CANCEL and stops there, and the page it
|
|
-- lands on drops the '▼'
|
|
do
|
|
local game = freshGame(6)
|
|
local list = openBag(game)
|
|
for _ = 1, 6 do press(list, "down") end
|
|
eq(list.index, 7, "six downs put the cursor on the CANCEL row")
|
|
eq(list.scroll, 4, "with the scroll capped at wListCount - 2")
|
|
press(list, "down")
|
|
eq(list.index, 7, "and a seventh down goes nowhere: CANCEL is the last row")
|
|
eq(list.scroll, 4, "the list does not scroll past it either")
|
|
|
|
calls = {}
|
|
list:draw()
|
|
-- rows 5, 6, CANCEL, then the terminator's return
|
|
check(drawnAt("FIX ITEM 5", 48, 32) ~= nil, "FIX ITEM 5 leads the last page")
|
|
check(drawnAt(CANCEL, 48, 64) ~= nil,
|
|
"CANCEL sits one row below the last item, at the item names' x")
|
|
check(found("code", function(c)
|
|
return c[2] == Theme.cursor and c[3] == 40 and c[4] == 64
|
|
end) ~= nil, "the cursor is on it, in wTopMenuItemX's column")
|
|
check(found("code", function(c) return c[2] == Theme.moreArrow end) == nil,
|
|
"and the '▼' is gone: .printCancelMenuItem returns before it")
|
|
end
|
|
|
|
-- the subtle one: three items plus CANCEL fills all four printed rows, so
|
|
-- `shown == rows` alone would still paint the arrow next to CANCEL
|
|
do
|
|
local game = freshGame(3)
|
|
local list = openBag(game)
|
|
eq(#list.items, 4, "three items and CANCEL exactly fill the four rows")
|
|
calls = {}
|
|
list:draw()
|
|
check(drawnAt(CANCEL, 48, 80) ~= nil, "CANCEL is the fourth printed row")
|
|
check(found("code", function(c) return c[2] == Theme.moreArrow end) == nil,
|
|
"a full page whose last row is CANCEL still prints no '▼' (:371-372)")
|
|
end
|
|
|
|
-- an empty bag is a box with CANCEL alone, which is what the cart shows
|
|
do
|
|
local game = freshGame(0)
|
|
local list = openBag(game)
|
|
eq(#list.items, 1, "no items: the terminator is the whole list")
|
|
eq(list.items[1] and list.items[1].cancel, true, "and that row is CANCEL")
|
|
calls = {}
|
|
list:draw()
|
|
check(drawnAt(CANCEL, 48, 32) ~= nil, "printed on the first row")
|
|
check(found("draw", function(c)
|
|
return tostring(c[2]):find("Nothing here", 1, true) ~= nil
|
|
end) == nil, "the port's invented \"Nothing here.\" line is gone")
|
|
check(found("code", function(c) return c[2] == Theme.moreArrow end) == nil,
|
|
"one row, no '▼'")
|
|
end
|
|
|
|
-- A on CANCEL is ExitListMenu: the same exit B takes (:105-110)
|
|
do
|
|
local game = freshGame(6)
|
|
local cancels = 0
|
|
local list = openBag(game, { onCancel = function() cancels = cancels + 1 end })
|
|
for _ = 1, 6 do press(list, "down") end
|
|
eq(list.index, 7, "cursor on CANCEL")
|
|
press(list, "a")
|
|
check(game.stack:top() ~= list, "A on CANCEL leaves the item list")
|
|
eq(#game.stack.states, 0, "with nothing pushed over it: no USE/TOSS box, "
|
|
.. "no message")
|
|
eq(cancels, 1, "and the caller's onCancel ran, exactly as for B")
|
|
end
|
|
|
|
do
|
|
local game = freshGame(6)
|
|
local cancels = 0
|
|
local list = openBag(game, { onCancel = function() cancels = cancels + 1 end })
|
|
press(list, "b")
|
|
check(game.stack:top() ~= list, "B still exits the list")
|
|
eq(cancels, 1, "through the same callback")
|
|
end
|
|
|
|
-- SELECT swaps two bag entries; the terminator is not one
|
|
-- (engine/menus/swap_items.asm:19-22)
|
|
do
|
|
local game = freshGame(6)
|
|
local list = openBag(game)
|
|
for _ = 1, 6 do press(list, "down") end
|
|
press(list, "select")
|
|
eq(list.swapIndex, nil, "SELECT on the CANCEL row starts no swap")
|
|
press(list, "up")
|
|
press(list, "select")
|
|
eq(list.swapIndex, 6, "while SELECT on a real row still does")
|
|
end
|
|
|
|
package.loaded["src.render.Font"] = nil
|
|
package.loaded["src.core.Sound"] = nil
|
|
package.loaded["src.render.TextBox"] = nil
|
|
package.loaded["src.ui.ListMenu"] = nil
|
|
package.loaded["src.ui.Theme"] = nil
|
|
package.loaded["src.ui.BagMenu"] = nil
|
|
require("src.ui.Screens").invalidate()
|
|
|
|
T.finish()
|