Files
gen1recomp/tests/gen2_billspc_deposit_test.lua

270 lines
9.4 KiB
Lua

-- luajit tests/gen2_billspc_deposit_test.lua
-- engine/pokemon/bills_pc.asm:117, home/pokemon.asm:124-127, pokegold home/pokemon.asm:101-107
package.path = "./?.lua;./?/init.lua;" .. package.path
local S = require("tests.harness").suite("gen2 bills pc deposit")
local check, eq = S.check, S.eq
love = require("tests.love_stub")
local BoxMenu = require("src.ui.gen2.BoxMenu")
local Boxes = require("src.core.gen2.Boxes")
local Chrome = require("src.ui.gen2.Chrome")
local Font = require("src.render.Font")
local GameVersion = require("src.core.GameVersion")
local Sound = require("src.core.Sound")
local function mon(species)
return { species = species, nickname = species, name = species,
level = 5, hp = 20, maxHp = 20 }
end
local function newInput()
local input = { pressed = {} }
function input:press(...)
for _, button in ipairs({ ... }) do self.pressed[button] = true end
end
function input:wasPressed(button)
if self.pressed[button] then
self.pressed[button] = nil
return true
end
return false
end
function input:isDown() return false end
return input
end
local function newGame(save)
local input = newInput()
return {
input = input,
save = save,
data = { audio = { cries = { TYRANITAR = {}, CYNDAQUIL = {}, GEODUDE = {} } },
pokemon = {} },
stack = { _items = {},
push = function(self, s) self._items[#self._items + 1] = s end,
pop = function(self) return table.remove(self._items) end,
top = function(self) return self._items[#self._items] end,
},
}, input
end
local function newSave()
local save = { party = { mon("TYRANITAR"), mon("CYNDAQUIL"), mon("TOTODILE") },
boxes = {}, boxNames = {}, currentBox = 1 }
Boxes.box(save, 1)[1] = mon("GEODUDE")
return save
end
local function press(screen, input, ...)
for _, button in ipairs({ ... }) do
input:press(button)
screen:update(0)
end
end
local function open(mode)
local save = newSave()
local game, input = newGame(save)
local menu = BoxMenu.new(game, { save = save, mode = mode,
onClose = function() end })
return menu, input, save
end
local rec
local realDrawCode, realBox, realPrint = Font.drawCode, Chrome.box, Chrome.print
local realRect, realFill = love.graphics.rectangle, nil
Font.drawCode = function(code, x, y)
rec.codes[#rec.codes + 1] = { code = code, x = x, y = y }
end
Chrome.box = function(tx, ty, tw, th)
rec.boxes[#rec.boxes + 1] = { tx, ty, tw, th }
realBox(tx, ty, tw, th)
end
Chrome.print = function(text, tx, ty)
rec.prints[#rec.prints + 1] = { text = text, tx = tx, ty = ty }
end
love.graphics.rectangle = function(mode, x, y, w, h)
rec.rects[#rec.rects + 1] = { mode = mode, x = x, y = y, w = w, h = h }
end
local function draw(menu)
rec = { codes = {}, boxes = {}, prints = {}, rects = {} }
menu:draw()
return rec
end
local cryPlaying = false
local realPlayCry = Sound.playCry
Sound.playCry = function() return { isPlaying = function() return cryPlaying end } end
do
GameVersion.set("gold")
local menu = open("deposit")
local r = draw(menu)
local atCorner = {}
for _, g in ipairs(r.codes) do
if g.x == 8 * 8 and g.y == 2 * 8 then atCorner[#atCorner + 1] = g.code end
end
eq(#atCorner, 2, "row 2's left corner is painted exactly twice (list tl, header bl)")
eq(atCorner[#atCorner], Font.BORDER.bl, "and the header's '└' lands last")
local order = {}
for _, b in ipairs(r.boxes) do
if b[1] == 8 and (b[2] == 0 or b[2] == 2) then order[#order + 1] = b[2] end
end
eq(order[1], 2, "the list box is drawn first")
eq(order[2], 0, "and the header box over it")
end
do
GameVersion.set("gold")
local menu = open("deposit")
local f = menu:selectionFrameRect(1)
eq(f.x .. "," .. f.y .. "," .. f.w .. "," .. f.h, "71,25,80,16", "Gold's frame is 80x16 at (71,25)")
check(not f.rounded, "with square corners")
f = menu:selectionFrameRect(2)
eq(f.y, 41, "row 2 sits 16px lower")
local r = draw(menu)
local line
for _, q in ipairs(r.rects) do if q.mode == "line" then line = q end end
check(line and line.x == 71.5 and line.y == 25.5 and line.w == 79 and line.h == 15,
"Gold draws one outline rectangle at those pixels")
GameVersion.set("crystal")
menu = open("deposit")
f = menu:selectionFrameRect(1)
eq(f.x .. "," .. f.y .. "," .. f.w .. "," .. f.h, "70,29,83,13", "Crystal's frame is 83x13 at (70,29)")
check(f.rounded, "with rounded corners")
r = draw(menu)
local fills = {}
for _, q in ipairs(r.rects) do
if q.mode == "fill" and q.h == 1 and q.w == 79 then fills[#fills + 1] = q end
end
eq(#fills, 2, "two 79px horizontal runs")
eq(fills[1].x .. "," .. fills[1].y, "72,29", "top line y=29 x=72..150")
eq(fills[2].x .. "," .. fills[2].y, "72,41", "bottom line y=41")
local sides, corners = {}, {}
for _, q in ipairs(r.rects) do
if q.mode == "fill" and q.w == 1 and q.h == 9 then sides[#sides + 1] = q.x end
if q.mode == "fill" and q.w == 1 and q.h == 1 then corners[#corners + 1] = q.x .. "," .. q.y end
end
table.sort(sides)
eq(sides[1] .. "," .. sides[2], "70,152", "sides at x=70 and x=152")
table.sort(corners)
eq(table.concat(corners, " "), "151,30 151,40 71,30 71,40", "corner pixels inset by one")
local anyLine = false
for _, q in ipairs(r.rects) do if q.mode == "line" then anyLine = true end end
check(not anyLine, "and no square outline on Crystal")
end
do
GameVersion.set("gold")
local menu, input = open("deposit")
check(menu:selectionFrameVisible(), "the frame is up while browsing the list")
press(menu, input, "a")
eq(menu.phase, "submenu", "A opens DEPOSIT/STATS/RELEASE/CANCEL")
check(not menu:selectionFrameVisible(), "ClearSprites: no frame under the submenu")
local r = draw(menu)
local frameRects = 0
for _, q in ipairs(r.rects) do
if q.mode == "line" or (q.mode == "fill" and q.w <= 83 and q.h <= 16
and q.y >= 24 and q.y <= 41 and q.x >= 70) then
frameRects = frameRects + 1
end
end
eq(frameRects, 0, "and drawPanel paints none of it")
press(menu, input, "b")
check(menu:selectionFrameVisible(), "B brings the list and its frame back")
end
do
GameVersion.set("crystal")
local menu, input, save = open("deposit")
cryPlaying = true
press(menu, input, "a", "a")
eq(#save.party, 2, "DEPOSIT moved the mon")
eq(Boxes.box(save, 1)[2].nickname, "TYRANITAR", "into the current box")
check(menu.cryWait ~= nil, "Crystal enters the cry wait")
eq(menu.message, nil, "with no message yet")
eq(menu.panelCleared, nil, "and the left panel intact")
eq(menu:panelMon().nickname, "TYRANITAR", "still showing the deposited mon")
eq(menu.phase, "submenu", "under the submenu")
check(not menu:selectionFrameVisible(), "and no frame")
local r = draw(menu)
local storedPrinted = false
for _, p in ipairs(r.prints) do
if type(p.text) == "string" and p.text:find("Stored") then storedPrinted = true end
end
check(not storedPrinted, "nothing says Stored yet")
press(menu, input, "a")
press(menu, input, "a")
check(menu.cryWait ~= nil and menu.message == nil, "two frames in, still waiting")
cryPlaying = false
menu:update(0)
eq(menu.cryWait, nil, "the wait ends when the cry does")
eq(menu.message, "Stored TYRANITAR!", "and Stored prints")
eq(menu.messageFrames, 50, "for the 50-frame hold")
eq(menu.panelCleared, true, "with the panel cleared")
eq(menu:panelMon().nickname, "CYNDAQUIL", "panelMon falls back to the selection")
menu, input = open("deposit")
cryPlaying = true
press(menu, input, "a", "a")
for _ = 1, 180 do menu:update(0) end
check(menu.cryWait ~= nil, "180 frames of a stuck cry are tolerated")
menu:update(0)
eq(menu.cryWait, nil, "frame 181 lets go")
eq(menu.message, "Stored TYRANITAR!", "and holds the message")
menu, input = open("withdraw")
cryPlaying = true
press(menu, input, "a", "a")
check(menu.cryWait ~= nil, "WITHDRAW waits on the cry too")
eq(menu:panelMon().nickname, "GEODUDE", "showing the withdrawn mon")
cryPlaying = false
for _ = 1, 3 do menu:update(0) end
eq(menu.message, "Got GEODUDE!", "then Got prints")
end
do
GameVersion.set("gold")
local menu, input = open("deposit")
cryPlaying = true
press(menu, input, "a", "a")
eq(menu.cryWait, nil, "Gold has no cry wait")
eq(menu.message, "Stored TYRANITAR!", "Stored prints at once")
eq(menu.messageFrames, 50, "with the 50-frame hold")
eq(menu.panelCleared, true, "and the panel cleared")
end
do
GameVersion.set("crystal")
local menu, input = open("deposit")
eq(table.concat(menu:messageBox({ "Stored X!" }), ","), "0,15,20,3", "one line: Textbox (0,15) 1x18")
eq(table.concat(menu:messageBox({ "a", "b" }), ","), "0,12,20,6", "two lines keep the tall box")
cryPlaying = false
press(menu, input, "a", "a")
for _ = 1, 3 do menu:update(0) end
eq(menu.message, "Stored TYRANITAR!", "Stored is up")
local r = draw(menu)
local box = r.boxes[#r.boxes]
for _, b in ipairs(r.boxes) do if b[1] == 0 then box = b end end
eq(table.concat(box, ","), "0,15,20,3", "drawPanel draws the one-row box")
local at
for _, p in ipairs(r.prints) do if p.text == "Stored TYRANITAR!" then at = p end end
check(at and at.tx == 1 and at.ty == 16, "with the string at (1,16)")
local tall = false
for _, b in ipairs(r.boxes) do if b[1] == 0 and b[2] == 12 then tall = true end end
check(not tall, "and no 6-row box")
end
Font.drawCode, Chrome.box, Chrome.print = realDrawCode, realBox, realPrint
love.graphics.rectangle = realRect
Sound.playCry = realPlayCry
GameVersion.set("red")
S.finish()