Files
gen1recomp/tests/engine/move_box_overlap_2320.lua

279 lines
9.8 KiB
Lua

-- home/pokemon.asm:246
-- engine/items/item_effects.asm:1979-2006
-- engine/pokemon/learn_move.asm:119-181
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local S = require("tests.harness").suite("PP UP / TM move box #2320")
local check, eq = S.check, S.eq
local ItemEffects = require("src.inventory.ItemEffects")
do
local Data = {
items = { PP_UP = { name = "PP UP" } },
moves = { LICK = { name = "LICK", pp = 30 } },
pokemon = { GENGAR = { name = "GENGAR" } },
text = {},
}
local t = { species = "GENGAR", hp = 20, stats = { hp = 20 },
moves = { { id = "LICK", pp = 48, ppUps = 3 } } }
local result, payload = ItemEffects.use(Data, {}, "PP_UP", t, nil, 1)
eq(result, "ppmaxed", "PP UP on a move with 3 PP Ups reports maxed out")
eq(payload and payload[1], "LICK's PP\nis maxed out.", "and prints PPMaxedOutText")
eq(t.moves[1].ppUps, 3, "the move is untouched")
end
local draws
local FontStub = {
drawBox = function(tx, ty, tw, th) draws[#draws + 1] = { "box", tx, ty, tw, th } end,
draw = function(text, x, y) draws[#draws + 1] = { "text", text, x, y } end,
drawCode = function(code, x, y) draws[#draws + 1] = { "code", code, x, y } end,
}
package.loaded["src.render.Font"] = FontStub
local boxes = {}
local TextBoxStub = {}
TextBoxStub.strip = function(text)
if type(text) ~= "string" then return text end
return (text:gsub("{DONE}", ""):gsub("{PROMPT}", ""))
end
TextBoxStub.new = function(game, text, onDone, opts)
local b = { fake = true, text = text, onDone = onDone, opts = opts }
boxes[#boxes + 1] = b
return b
end
package.loaded["src.render.TextBox"] = TextBoxStub
package.loaded["src.render.HudTiles"] = {
tile = function() end, drawHPBar = function() end, statusTile = function() end,
}
package.loaded["src.render.PaletteFX"] = {
shader = function() return nil end, pal = function() return nil end,
}
local MoveSelectMenu = require("src.ui.MoveSelectMenu")
local MoveLearnMenu = require("src.ui.MoveLearnMenu")
local PartyMenu = require("src.ui.PartyMenu")
PartyMenu.drawIcon = function() end
local pressed = {}
local function newGame()
local game = {
input = { wasPressed = function(_, b) return pressed[b] == true end,
isDown = function() return false end },
data = {
moves = { LICK = { name = "LICK" }, HYPNOSIS = { name = "HYPNOSIS" },
SURF = { name = "SURF" }, MEGA_PUNCH = { name = "MEGA PUNCH", pp = 20 } },
pokemon = { GENGAR = { name = "GENGAR" } },
statuses = {},
text = {},
},
}
game.stack = {
states = {},
push = function(self, s, ...)
self.states[#self.states + 1] = s
if type(s.enter) == "function" then s:enter(...) end
end,
pop = function(self) return table.remove(self.states) end,
top = function(self) return self.states[#self.states] end,
}
return game
end
local function press(state, btn)
pressed = { [btn] = true }
state:update(1 / 60)
pressed = {}
end
local function finishBox(game)
local b = game.stack:top()
if b and b.fake and b.opts and b.opts.stay and b.opts.stay.onShown then
b.opts.stay.onShown()
return true
end
return false
end
local function cursorGlyphAt(y)
for _, d in ipairs(draws) do
if d[1] == "code" and d[3] == 0 and d[4] == y then return d[2] end
end
end
do
local game = newGame()
local mon = { species = "GENGAR", level = 30, hp = 60, stats = { hp = 60 },
moves = { { id = "LICK", pp = 30 }, { id = "HYPNOSIS", pp = 20 } } }
game.save = { party = { mon, { species = "GENGAR", level = 5, hp = 10,
stats = { hp = 10 }, moves = {} } } }
local menuRef, chosen
local picker = PartyMenu.new(game, {
pickOnly = true, itemUse = true, keepOpen = true,
onSwitch = function(m, p)
menuRef = MoveSelectMenu.new(game, m, "Raise PP of which\ntechnique?{DONE}",
function(i, menu) chosen = { i, menu } end, nil, p)
game.stack:push(menuRef)
end,
})
game.stack:push(picker)
draws = {}
picker:draw()
eq(cursorGlyphAt(8), 0xED, "the party cursor is the filled arrow before the pick")
press(picker, "a")
check(picker.chosenHollow == true, "A on a kept-open picker marks the row chosen")
draws = {}
picker:draw()
eq(cursorGlyphAt(8), 0xEC, "the chosen mon's arrow turns hollow")
check(menuRef ~= nil, "the move menu was pushed")
local top = game.stack:top()
check(top and top.fake, "a text box types the prompt before the move box")
eq(top and top.text, "Raise PP of which\ntechnique?{DONE}", "with the item's prompt")
check(top and top.opts and top.opts.stay ~= nil, "a done-text stay box")
eq(menuRef.ready, false, "the move menu takes no input while the prompt types")
draws = {}
menuRef:draw()
eq(#draws, 0, "and draws nothing yet")
pressed = { a = true }
menuRef:update(1 / 60)
pressed = {}
eq(chosen, nil, "an A press during the prompt picks nothing")
check(finishBox(game), "the prompt finished typing")
eq(game.stack:top(), menuRef, "the prompt box hands the screen to the move menu")
eq(menuRef.ready, true, "the move menu is live")
draws = {}
menuRef:draw()
eq(draws[1][1], "box", "prompt text box drawn first")
eq(draws[1][2], 0, "at column 0")
eq(draws[1][3], 12, "row 12")
local last
for _, d in ipairs(draws) do if d[1] == "box" then last = d end end
eq(last and last[2], 4, "the move box is the last box drawn")
eq(last and last[3], 7, "at 4,7, over the text box's top edge")
press(menuRef, "down")
press(menuRef, "a")
eq(chosen and chosen[1], 2, "A hands back the picked slot")
eq(chosen and chosen[2], menuRef, "and the menu")
eq(game.stack:top(), picker, "nothing was pushed over it, so it released itself")
eq(#game.stack.states, 1, "back to the party menu")
menuRef = nil
press(picker, "a")
finishBox(game)
local held = game.stack:top()
eq(getmetatable(held), MoveSelectMenu, "the move menu is up again")
local result = { fake = true, text = "LICK's PP\nincreased." }
held.onChoose = function() game.stack:push(result) end
press(held, "a")
eq(game.stack:top(), result, "the result text is on top")
check(held.held == true, "the move menu is held under it")
eq(game.stack.states[#game.stack.states - 1], held, "still on the stack under the result")
draws = {}
held:draw()
local moveBox
for _, d in ipairs(draws) do
if d[1] == "box" and d[2] == 4 and d[3] == 7 then moveBox = d end
if d[1] == "box" and d[2] == 0 and d[3] == 12 then moveBox = "prompt" end
end
check(type(moveBox) == "table", "the held menu keeps drawing the move box, not its prompt")
draws = {}
picker:draw()
eq(cursorGlyphAt(8), 0xEC, "the party arrow stays hollow under the result")
game.stack:pop()
picker:close()
eq(#game.stack.states, 0, "closing the picker drops the held move box too")
end
do
local game = newGame()
local mon = { species = "GENGAR", moves = { { id = "LICK" } } }
local p = { fake = "picker" }
local other = MoveSelectMenu.new(game, mon, "x", nil, nil, nil)
game.stack.states = { p, other }
PartyMenu.close(setmetatable({ game = game }, { __index = p }))
eq(#game.stack.states, 2, "close leaves a menu it does not own alone")
end
do
local game = newGame()
local mon = { species = "GENGAR", moves = { { id = "LICK" }, { id = "HYPNOSIS" } } }
local m = MoveSelectMenu.new(game, mon, "Raise PP of which\ntechnique?")
game.stack:push(m)
finishBox(game)
press(m, "down")
local maxed = { fake = true }
m.onChoose = function() game.stack:push(maxed) end
press(m, "a")
game.stack:pop()
m:ask()
local reprompt = game.stack:top()
check(reprompt.fake and reprompt.text == "Raise PP of which\ntechnique?",
"ask() types the prompt again")
eq(m.ready, false, "the menu waits for it")
draws = {}
m:draw()
local promptBox, moveBox = false, false
for _, d in ipairs(draws) do
if d[1] == "box" and d[3] == 12 then promptBox = true end
if d[1] == "box" and d[3] == 7 then moveBox = true end
end
check(moveBox and not promptBox, "the move box stays up while the prompt retypes")
finishBox(game)
eq(m.index, 1, "the cursor starts over on the first move")
eq(m.ready, true, "and the menu is live again")
end
do
local game = newGame()
local mon = { species = "GENGAR", level = 30,
moves = { { id = "SURF" }, { id = "LICK" }, { id = "HYPNOSIS" }, { id = "LICK" } } }
local m = MoveLearnMenu.new(game, mon, "MEGA_PUNCH", function() end)
game.stack:push(m)
local ask = game.stack:top()
check(ask.fake and ask.opts and ask.opts.choice, "TryingToLearn YES/NO first")
game.stack:pop()
ask.opts.choice(true)
local forget = game.stack:top()
check(forget.fake and forget.text:find("Which move should", 1, true) ~= nil,
"YES types WhichMoveToForgetText")
check(forget.opts and forget.opts.stay ~= nil, "as a done-text stay box")
eq(m.selecting, false, "the forget list waits for the text")
draws = {}
m:draw()
eq(#draws, 0, "and is not drawn yet")
finishBox(game)
eq(game.stack:top(), m, "the text hands off to the forget list")
eq(m.selecting, true, "which is live")
draws = {}
m:draw()
eq(draws[1][1], "box", "text box first")
eq(draws[1][3], 12, "at row 12")
local last
for _, d in ipairs(draws) do if d[1] == "box" then last = d end end
eq(last and last[2], 4, "forget box last")
eq(last and last[3], 7, "at 4,7")
press(m, "a")
local hm = game.stack:top()
check(hm.fake and hm.text:find("HM techniques", 1, true) ~= nil, "SURF is refused")
eq(m.selecting, false, "the forget box is gone under the refusal")
game.stack:pop()
hm.onDone()
local again = game.stack:top()
check(again.fake and again.text:find("Which move should", 1, true) ~= nil,
"then the prompt types again")
finishBox(game)
eq(m.selecting, true, "and the forget list comes back")
eq(m.index, 1, "on the first move")
end
S.finish()