mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
227 lines
7.7 KiB
Lua
227 lines
7.7 KiB
Lua
-- engine/events/pokemart.asm:159-169
|
|
-- engine/events/pokemart.asm:84-91
|
|
-- home/list_menu.asm:89-91
|
|
-- luajit tests/engine/mart_price_text_bug2291.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")
|
|
|
|
local function glyphs(text)
|
|
local n = 0
|
|
for _ in tostring(text):gmatch("[%z\1-\127\194-\244][\128-\191]*") do
|
|
n = n + 1
|
|
end
|
|
return n
|
|
end
|
|
|
|
local realFont = package.loaded["src.render.Font"]
|
|
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 glyphs(text) * 8 end,
|
|
split = function(text)
|
|
local out = {}
|
|
for s in tostring(text):gmatch("[%z\1-\127\194-\244][\128-\191]*") do
|
|
out[#out + 1] = s
|
|
end
|
|
return out
|
|
end,
|
|
spansFitting = function(spans, pixels)
|
|
return math.min(#spans, math.floor(pixels / 8))
|
|
end,
|
|
encode = function(text)
|
|
local out = {}
|
|
for s in tostring(text):gmatch("[%z\1-\127\194-\244][\128-\191]*") do
|
|
out[#out + 1] = s
|
|
end
|
|
return out
|
|
end,
|
|
advanceOf = function() return 8 end,
|
|
}
|
|
|
|
local RELOAD = {
|
|
"src.ui.QuantityBox", "src.ui.ShopMenu", "src.ui.ListMenu",
|
|
"src.ui.ChoiceBox", "src.ui.Menu", "src.ui.Theme", "src.render.TextBox",
|
|
}
|
|
for _, m in ipairs(RELOAD) do package.loaded[m] = nil end
|
|
|
|
local ShopMenu = require("src.ui.ShopMenu")
|
|
local TextBox = require("src.render.TextBox")
|
|
local QuantityBox = require("src.ui.QuantityBox")
|
|
local ChoiceBox = require("src.ui.ChoiceBox")
|
|
|
|
local GREET = "Take your time."
|
|
local SELL_GREET = "What would you\nlike to sell?"
|
|
|
|
local function newGame(money)
|
|
local stack, pressed = {}, {}
|
|
local game = {
|
|
data = {
|
|
items = { POKE_BALL = { name = "POKe BALL", price = 200 } },
|
|
text = {
|
|
_PokemartBuyingGreetingText = GREET,
|
|
_PokemonSellingGreetingText = SELL_GREET,
|
|
_PokemartTellBuyPriceText = "{RAM:wStringBuffer}?\nThat will be\011¥{NUM:hMoney, 3 | LEADING_ZEROES | LEFT_ALIGN}. OK?{DONE}",
|
|
_PokemartTellSellPriceText = "I can pay you\n¥{NUM:hMoney, 3 | LEADING_ZEROES | LEFT_ALIGN} for that.{DONE}",
|
|
_PokemartBoughtItemText = "Here you are!\nThank you!{PROMPT}",
|
|
},
|
|
constants = {},
|
|
},
|
|
save = { money = money, inventory = {}, bagOrder = {}, options = { textSpeed = 3 } },
|
|
input = {
|
|
wasPressed = function(_, b) return pressed[b] == true end,
|
|
isDown = function() return false end,
|
|
},
|
|
}
|
|
game.stack = {
|
|
push = function(_, s) stack[#stack + 1] = s end,
|
|
pop = function() return table.remove(stack) end,
|
|
top = function() return stack[#stack] end,
|
|
}
|
|
local function frame(btn)
|
|
for k in pairs(pressed) do pressed[k] = nil end
|
|
if btn then pressed[btn] = true end
|
|
local top = stack[#stack]
|
|
top:update(1 / 60)
|
|
for k in pairs(pressed) do pressed[k] = nil end
|
|
end
|
|
return game, stack, frame
|
|
end
|
|
|
|
local function drain(game)
|
|
for _ = 1, 600 do
|
|
local top = game.stack:top()
|
|
if not (top and top.stay and not top.stayShown) then return end
|
|
top:update(1 / 60)
|
|
end
|
|
end
|
|
|
|
local function flat(box)
|
|
local out = {}
|
|
for _, page in ipairs(box.pages or {}) do
|
|
for _, line in ipairs(page) do out[#out + 1] = line end
|
|
end
|
|
return out
|
|
end
|
|
|
|
do
|
|
local game, stack, frame = newGame(3000)
|
|
local menu = ShopMenu.new(game, { "POKE_BALL" }, function() end)
|
|
menu.items[1].onSelect()
|
|
drain(game)
|
|
local list = stack[#stack]
|
|
list.index = 1
|
|
list.onChoose({ value = "POKE_BALL" })
|
|
eq(list.hollowIndex, list.index, "buy: the chosen row shows the hollow cursor")
|
|
local qty = stack[#stack]
|
|
check(getmetatable(qty) == QuantityBox, "buy: the quantity box opens")
|
|
qty.onDone(1)
|
|
local box = stack[#stack]
|
|
check(getmetatable(box) == TextBox, "buy: the price line is a typed text box, not a bare YES/NO")
|
|
check(box.choice ~= nil, "buy: YES/NO waits on the text box")
|
|
eq(stack[#stack - 1], qty, "buy: the quantity box stays up under the price text")
|
|
eq(stack[#stack - 2], list, "buy: the list is under the quantity box")
|
|
eq(list.footer, GREET, "buy: the price line is not dumped into the footer")
|
|
local lines = flat(box)
|
|
eq(lines[1], "POKe BALL?", "buy: the clerk names the item")
|
|
eq(lines[2], "That will be", "buy: line 2")
|
|
eq(lines[3], "¥200. OK?", "buy: line 3 carries the price")
|
|
|
|
frame()
|
|
eq(box.done, false, "buy: the price line types, it is not instant")
|
|
eq(stack[#stack], box, "buy: no YES/NO while the line is typing")
|
|
|
|
local sawCont = false
|
|
for _ = 1, 300 do
|
|
if box.waiting then sawCont = true break end
|
|
frame()
|
|
end
|
|
check(sawCont, "buy: the cont line waits on the arrow")
|
|
local vis = box:visibleText() or {}
|
|
eq(vis[1], "POKe BALL?", "buy: arrow wait shows the item name")
|
|
eq(vis[2], "That will be", "buy: arrow wait shows That will be")
|
|
eq(stack[#stack], box, "buy: no YES/NO at the arrow wait")
|
|
|
|
for _ = 1, 10 do frame() end
|
|
frame("a")
|
|
local pushed = false
|
|
for _ = 1, 300 do
|
|
if getmetatable(stack[#stack]) == ChoiceBox then pushed = true break end
|
|
frame()
|
|
end
|
|
check(pushed, "buy: YES/NO opens once the text finishes")
|
|
check(box.done, "buy: the text box is done when YES/NO opens")
|
|
eq(stack[#stack - 1], box, "buy: YES/NO sits over the price text")
|
|
eq(stack[#stack - 2], qty, "buy: the quantity box is still drawn under YES/NO")
|
|
|
|
game.stack:pop()
|
|
game.stack:pop()
|
|
box.choice(false)
|
|
eq(stack[#stack], list, "buy NO: the quantity box closes back to the list")
|
|
eq(list.footer, GREET, "buy NO: the greeting is back")
|
|
end
|
|
|
|
do
|
|
local game, stack = newGame(3000)
|
|
local menu = ShopMenu.new(game, { "POKE_BALL" }, function() end)
|
|
menu.items[1].onSelect()
|
|
drain(game)
|
|
local list = stack[#stack]
|
|
list.onChoose({ value = "POKE_BALL" })
|
|
local qty = stack[#stack]
|
|
qty.onDone(2)
|
|
local box = stack[#stack]
|
|
game.stack:pop()
|
|
box.choice(true)
|
|
eq(game.save.money, 2600, "buy YES: money is paid")
|
|
eq(game.save.inventory.POKE_BALL, 2, "buy YES: the items go in the bag")
|
|
local bought = stack[#stack]
|
|
check(getmetatable(bought) == TextBox and bought.choice == nil,
|
|
"buy YES: the receipt text is up")
|
|
eq(stack[#stack - 1], qty, "buy YES: the quantity box stays under the receipt")
|
|
game.stack:pop()
|
|
bought.onDone()
|
|
eq(stack[#stack], list, "buy YES: the receipt closes back to the list")
|
|
end
|
|
|
|
do
|
|
local game, stack = newGame(0)
|
|
game.save.inventory.POKE_BALL = 5
|
|
game.save.bagOrder = { "POKE_BALL" }
|
|
local menu = ShopMenu.new(game, { "POKE_BALL" }, function() end)
|
|
menu.items[2].onSelect()
|
|
drain(game)
|
|
local list = stack[#stack]
|
|
list.index = 1
|
|
list.onChoose(list.items[1])
|
|
eq(list.hollowIndex, list.index, "sell: the chosen row shows the hollow cursor")
|
|
local qty = stack[#stack]
|
|
check(getmetatable(qty) == QuantityBox, "sell: the quantity box opens")
|
|
qty.onDone(2)
|
|
local box = stack[#stack]
|
|
check(getmetatable(box) == TextBox and box.choice ~= nil,
|
|
"sell: the price line is a typed text box with YES/NO")
|
|
eq(stack[#stack - 1], qty, "sell: the quantity box stays up under the price text")
|
|
eq(list.footer, SELL_GREET, "sell: the price line is not dumped into the footer")
|
|
local lines = flat(box)
|
|
eq(lines[1], "I can pay you", "sell: line 1")
|
|
eq(lines[2], "¥200 for that.", "sell: line 2 carries the price")
|
|
eq(box.done, false, "sell: the price line is not instant")
|
|
game.stack:pop()
|
|
box.choice(true)
|
|
eq(stack[#stack], list, "sell YES: back to the sell list")
|
|
eq(game.save.money, 200, "sell YES: money is paid")
|
|
eq(game.save.inventory.POKE_BALL, 3, "sell YES: items leave the bag")
|
|
end
|
|
|
|
package.loaded["src.render.Font"] = realFont
|
|
for _, m in ipairs(RELOAD) do package.loaded[m] = nil end
|
|
require("src.ui.Screens").invalidate()
|
|
|
|
T.finish()
|