Files
gen1recomp/tests/engine/prize_full_party_bug2034.lua

220 lines
6.8 KiB
Lua

-- ../pokered/engine/events/prize_menu.asm:181 (#2034)
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 out = {}
for i = 1, #tostring(text) do out[i] = i end
return out
end,
}
package.loaded["src.render.TextBox"] = {
new = function(_, text, onDone, opts)
return { text = text, onDone = onDone, opts = opts, isTextBox = true }
end,
}
package.loaded["src.core.Sound"] = { play = function() end }
package.loaded["src.core.GameVersion"] = {
isBlue = function() return false end,
isYellow = function() return false end,
}
local bagFull = false
package.loaded["src.inventory.Bag"] = {
add = function() return not bagFull end,
}
local M = assert(loadfile("data/scripts/story3.lua"))()
local counters = M.GAME_CORNER_PRIZE_ROOM.talk
local pressed, done, ran
local function mkGame(coins)
done, ran = false, nil
local mons = {}
for _, n in ipairs({ "ABRA", "CLEFAIRY", "NIDORINA" }) do
mons[n] = { name = n }
end
return {
data = {
text = {},
pokemon = mons,
items = {
TM_DRAGON_RAGE = { name = "TM23" },
TM_HYPER_BEAM = { name = "TM15" },
TM_SUBSTITUTE = { name = "TM35" },
},
},
save = { coins = coins, inventory = { COIN_CASE = 1 } },
input = {
wasPressed = function(_, b) return pressed == b end,
isDown = function() return false end,
},
stack = {
states = {},
push = function(self, s) self.states[#self.states + 1] = s end,
pop = function(self) return table.remove(self.states) end,
top = function(self) return self.states[#self.states] end,
},
}
end
local function mkOw(game)
return {
runner = {
run = function(_, script, extra)
ran = { script = script, extra = extra, depth = #game.stack.states }
end,
},
}
end
local function open(n, coins)
local game = mkGame(coins or 5000)
local ow = mkOw(game)
counters["TEXT_GAMECORNERPRIZEROOM_PRIZE_VENDOR_" .. n](
game, ow, nil, function() done = true end)
local exchange = game.stack:pop()
exchange.onDone()
local which = game.stack:top()
which.opts.stay.onShown()
return game, which, game.stack:top(), ow
end
local function pick(game, window, index, yes)
window.index = index
pressed = "a"
window:update(1 / 60)
pressed = nil
local ask = game.stack:pop()
ask.opts.choice(yes)
end
do
local game, which, window, ow = open(1)
local cost = window.prizes[1].cost
pick(game, window, 1, true)
check(ran ~= nil, "the mon gift runs on the script runner")
-- engine/events/prize_menu.asm:24-28,42
check(ow.prizeWindow ~= nil,
"the prize list is still drawn while the gift script runs")
eq(ow.prizeWindow.index, 1, "with the cursor on the picked row")
eq(ran.depth, 0,
"WhichPrizeText and the menu come down first, so nothing is orphaned")
eq(#game.stack.states, 0, "and the callback pushed nothing of its own")
for _, state in ipairs(game.stack.states) do
check(state ~= which, "the stay box never survives the transaction")
end
eq(game.save.coins, 5000, "coins are the script's job, not the callback's")
check(type(ran.extra.onDone) == "function",
"the runner releases the sign when the script ends")
ran.extra.onDone()
eq(ow.prizeWindow, nil, "and the window's rows go back with it")
check(done, "the conversation ends there")
local rows = ran.script
eq(rows[1][1], "give_pokemon", "GivePokemon first (prize_menu.asm:224)")
eq(rows[1][2], window.prizes[1].prize.species, "for the picked prize")
eq(rows[1][5], true, "with GotMonText (give_pokemon.asm:46, :68)")
eq(rows[2][1], "jump_if_false", "carry decides (prize_menu.asm:233)")
eq(rows[3][1], "take_coins", "only then .subtractCoins")
eq(rows[3][2], cost, "for the prize's price")
local function exec(gave)
local labels, texts, coins = {}, {}, 0
for i, row in ipairs(rows) do
if row[1] == "label" then labels[row[2]] = i end
end
local pc, lastCheck = 1, nil
while pc <= #rows do
local row = rows[pc]
local verb = row[1]
if verb == "give_pokemon" then
lastCheck = gave
elseif verb == "take_coins" then
coins = coins + row[2]
elseif verb == "show_text" then
texts[#texts + 1] = row[2]
elseif verb == "jump" then
pc = labels[row[2]]
elseif verb == "jump_if_false" and not lastCheck then
pc = labels[row[2]]
end
pc = pc + 1
end
return coins, table.concat(texts, ",")
end
local spent, texts = exec(true)
eq(spent, cost, "a mon that landed costs its coins")
eq(texts, "", "and prints nothing beyond GivePokemon's own text")
spent, texts = exec(false)
eq(spent, 0, "party and box full: `ret nc`, no coins move")
eq(texts, "_BoxIsFullText",
"and the box-full line is GivePokemon's (give_pokemon.asm:40-42)")
end
do
bagFull = false
local game, _, window = open(3, 9999)
local cost = window.prizes[2].cost
pick(game, window, 2, true)
eq(ran, nil, "a TM needs no script (prize_menu.asm:209-216)")
eq(game.save.coins, 9999 - cost, ".subtractCoins runs inline")
eq(#game.stack.states, 0, "with the menu and its text box both down")
check(done, "and the sign released")
end
do
bagFull = true
local game, _, window = open(3)
pick(game, window, 1, true)
eq(game.save.coins, 5000, ".bagFull rets before .subtractCoins")
eq(#game.stack.states, 1, "one box left over the overworld")
check(type(game.stack:top().onDone) == "function",
"PrizeRoomBagIsFullText owns the release (prize_menu.asm:245-246)")
bagFull = false
end
do
local game, which, window = open(1)
pick(game, window, 1, false)
eq(#game.stack.states, 1, "OhFineThenText is all that is left")
check(game.stack:top() ~= which, "the stay box is gone")
eq(game.save.coins, 5000, "no coins move on NO")
end
do
local game, which, window = open(1, 10)
pick(game, window, 1, true)
eq(#game.stack.states, 1, "SorryNeedMoreCoinsText is all that is left")
check(game.stack:top() ~= which, "the stay box is gone")
eq(ran, nil, "HasEnoughCoins fails before GivePokemon")
end
do
local Commands = require("src.script.Commands")
local ctx = { save = { coins = 500 } }
Commands.take_coins(ctx, 180)
eq(ctx.save.coins, 320, "take_coins subtracts")
Commands.take_coins(ctx, 9999)
eq(ctx.save.coins, 0, "and clamps at zero")
end
package.loaded["src.render.Font"] = nil
package.loaded["src.render.TextBox"] = nil
package.loaded["src.core.Sound"] = nil
package.loaded["src.core.GameVersion"] = nil
package.loaded["src.inventory.Bag"] = nil
T.finish()