Files
gen1recomp/tests/engine/menu_hold_scroll_bug1898.lua
T

236 lines
8.4 KiB
Lua

-- home/joypad2.asm:16-53 (#1898)
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")
package.loaded["src.render.Font"] = {
BORDER = { tl = 1, tr = 2, bl = 3, br = 4, h = 5, v = 6 },
draw = function() end,
drawCode = function() end,
drawBox = function() end,
width = function(text) return #tostring(text) * 8 end,
split = function(text)
local spans = {}
for i = 1, #tostring(text) do spans[i] = { from = i, to = i } end
return spans
end,
spansFitting = function(spans) return #spans end,
}
local MenuRepeat = require("src.ui.MenuRepeat")
local ListMenu = require("src.ui.ListMenu")
local function newInput()
local input = { edges = {}, held = {} }
function input:press(button)
self.edges[button] = true
self.held[button] = true
end
function input:release(button)
self.edges[button] = nil
self.held[button] = nil
end
function input:wasPressed(button)
if self.edges[button] then
self.edges[button] = nil
return true
end
return false
end
function input:isDown(button) return self.held[button] == true end
return input
end
do
eq(MenuRepeat.GEN1_DELAY, 30, "half a second before the first repeat")
eq(MenuRepeat.GEN1_RATE, 5, "then 1/12 of a second between repeats")
eq(MenuRepeat.GEN2_DELAY, 15, "JoyTextDelay seeds wTextDelayFrames with 15")
eq(MenuRepeat.GEN2_RATE, 5, "and reseeds it with 5")
local input = newInput()
local state = MenuRepeat.new(MenuRepeat.GEN1_DELAY, MenuRepeat.GEN1_RATE)
input:press("down")
local dir, edge = MenuRepeat.direction(state, input, { "up", "down" })
eq(dir, "down", "the press itself reports immediately")
eq(edge, true, "and is flagged as the edge")
local fired = {}
for frame = 1, 60 do
local d = MenuRepeat.direction(state, input, { "up", "down" })
if d then fired[#fired + 1] = frame end
end
eq(fired[1], 30, "the hold is ignored for half a second")
eq(fired[2], 35, "then repeats every five frames")
eq(fired[3], 40, "and keeps repeating")
eq(#fired, 7, "seven repeats in the second after the press")
input:release("down")
eq(MenuRepeat.direction(state, input, { "up", "down" }), nil,
"letting go stops it")
eq(state.frames, 0, "and clears the counter, so the next hold waits again")
local off = MenuRepeat.new(MenuRepeat.GEN1_DELAY, MenuRepeat.GEN1_RATE, false)
input:press("down")
MenuRepeat.direction(off, input, { "up", "down" })
local repeated = false
for _ = 1, 120 do
if MenuRepeat.direction(off, input, { "up", "down" }) then repeated = true end
end
check(not repeated, "a disabled state stays edge-only")
input:release("down")
end
do
local items = {}
for i = 1, 10 do items[i] = { value = i, label = "ITEM " .. i } end
local input = newInput()
local game = { input = input,
stack = { push = function() end, pop = function() end,
top = function() end } }
local list = ListMenu.new(game, "ITEMS", items, { kind = "bag", itemBox = true })
eq(list.keyRepeat, true,
"DisplayListMenuID runs with hJoy7 = 1, with no mod hook in sight")
eq(list.repeatDelay, 30, "at the cart's half-second delay")
eq(list.repeatRate, 5, "and the cart's repeat rate")
input:press("down")
list:update(1 / 60)
eq(list.index, 2, "the press moves the cursor one row")
for _ = 1, 29 do list:update(1 / 60) end
eq(list.index, 2, "a short hold moves nothing more")
list:update(1 / 60)
eq(list.index, 3, "the 30th held frame is the first repeat")
for _ = 1, 5 do list:update(1 / 60) end
eq(list.index, 4, "and every fifth frame after that")
for _ = 1, 60 do list:update(1 / 60) end
eq(list.index, 10, "holding Down walks to the end of the list")
eq(list.scroll, 7, "with the window scrolled to the bottom")
input:release("down")
input:press("up")
list:update(1 / 60)
for _ = 1, 200 do list:update(1 / 60) end
eq(list.index, 1, "holding Up walks back to the top")
eq(list.scroll, 0, "and the window comes with it")
end
do
local data = { pokemon = {}, constants = { dexSize = 151, dexDigits = 3 } }
for n = 1, 151 do
local id = ("DEXMON_%03d"):format(n)
data.pokemon[id] = { id = id, name = ("MON%03d"):format(n), dex = n }
end
local save = { pokedex = { seen = {}, owned = {} } }
for n = 1, 20 do save.pokedex.seen[("DEXMON_%03d"):format(n)] = true end
local input = newInput()
local game = { data = data, save = save, input = input,
stack = { push = function() end, pop = function() end,
top = function() end } }
local PokedexMenu = require("src.ui.PokedexMenu")
local dex = PokedexMenu.new(game, {})
eq(#dex.items, 20, "twenty seen species in the list")
input:press("down")
dex:update(1 / 60)
eq(dex.index, 2, "ShowPokedexMenu's own list moves on the press")
for _ = 1, 29 do dex:update(1 / 60) end
eq(dex.index, 2, "and waits out the same half second")
dex:update(1 / 60)
eq(dex.index, 3, "before the first repeat")
for _ = 1, 200 do dex:update(1 / 60) end
eq(dex.index, 20, "a long hold reaches the last seen species")
input:release("down")
input:press("right")
dex:update(1 / 60)
eq(dex.scroll, 13, "Right pages the scroll offset and clamps at the end")
for _ = 1, 60 do dex:update(1 / 60) end
eq(dex.scroll, 13, "holding Right at the bottom cannot page past it")
input:release("right")
input:press("left")
dex:update(1 / 60)
eq(dex.scroll, 6, "Left pages back seven rows")
for _ = 1, 40 do dex:update(1 / 60) end
eq(dex.scroll, 0, "and a held Left runs the list back to the top")
input:release("left")
end
do
local PackMenu = require("src.ui.gen2.PackMenu")
local Save = require("src.core.gen2.Save")
local items = {}
local order = {}
for i = 1, 8 do
local id = "FAKEITEM_" .. i
items[id] = { id = id, name = "ITEM " .. i, pocket = "ITEM", index = i,
canToss = true, canSelect = false,
fieldMenu = "ITEMMENU_CLOSE" }
order[i] = id
end
local save = Save.newGame()
save.inventory = {}
for _, id in ipairs(order) do save.inventory[id] = 1 end
save.bagOrder = order
local input = newInput()
local game = { input = input, save = save, options = save.options,
data = { items = items, moves = {}, pokemon = {},
audio = { sfx = {} } },
stack = { push = function() end, pop = function() end } }
local pack = PackMenu.new(game, { save = save, pocket = "ITEM",
onClose = function() end, world = { useFieldItem = function() end } })
pack.gfx = { available = function() return false end, draw = function() end,
colorsAt = function() return nil end }
eq(pack.hold.delay, 15, "the pocket list runs at JoyTextDelay's cadence")
eq(pack.hold.rate, 5, "with the cart's five-frame repeat")
local total = pack:total()
check(total >= 9, "eight items plus the CANCEL row")
input:press("down")
pack:update(1 / 60)
eq(pack.index, 2, "the press moves one row")
for _ = 1, 14 do pack:update(1 / 60) end
eq(pack.index, 2, "fifteen frames of delay first")
pack:update(1 / 60)
eq(pack.index, 3, "then the first repeat")
for _ = 1, 200 do pack:update(1 / 60) end
eq(pack.index, total,
"a held Down stops on the last row rather than wrapping round")
input:release("down")
end
do
local Gen2Dex = require("src.ui.gen2.PokedexMenu")
local entries, seen = {}, {}
for n = 1, 30 do
local id = ("G2MON_%03d"):format(n)
entries[id] = { dex = n, species = id, name = ("MON%03d"):format(n) }
seen[id] = true
end
local input = newInput()
local save = { pokedex = { seen = seen, caught = {} } }
local game = { data = {}, save = save, input = input }
local dex = Gen2Dex.new(game, { save = save,
pokedex = { entries = entries },
pokemon = {} })
eq(dex.hold.delay, 15, "the listing runs at JoyTextDelay's cadence")
check(#dex.rows >= 30, "thirty seen species in the listing")
input:press("down")
dex:update(1 / 60)
eq(dex.index, 2, "the press moves one row")
for _ = 1, 14 do dex:update(1 / 60) end
eq(dex.index, 2, "after the same fifteen-frame delay")
dex:update(1 / 60)
eq(dex.index, 3, "the hold starts repeating")
for _ = 1, 400 do dex:update(1 / 60) end
eq(dex.index, #dex.rows,
"Pokedex_ListingMoveCursorDown stops at the end of the listing")
input:release("down")
end
T.finish("menu hold-to-scroll bug 1898")