Files
gen1recomp/tests/drivers/pp_up_move_box_2320.lua

237 lines
8.7 KiB
Lua

-- home/pokemon.asm:246
-- engine/items/item_effects.asm:1967-2006
-- engine/pokemon/learn_move.asm:119-181
return function(game)
local U = dofile("tests/drivers/util.lua")
local Pokemon = require("src.pokemon.Pokemon")
local Screens = require("src.ui.Screens")
local Bag = require("src.inventory.Bag")
local PartyMenu = require("src.ui.PartyMenu")
local MoveSelectMenu = require("src.ui.MoveSelectMenu")
local MoveLearnMenu = require("src.ui.MoveLearnMenu")
local ChoiceBox = require("src.ui.ChoiceBox")
local TextBox = require("src.render.TextBox")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or os.getenv("SHOT_DIR") or "/tmp/shots2320"
local fail = 0
local function check(label, ok)
if not ok then fail = fail + 1 end
U.log(ok and "PASS" or "FAIL", label)
return ok
end
local function top() return game.stack:top() end
local function isBox(s) return getmetatable(s) == TextBox end
local function isParty(s) return getmetatable(s) == PartyMenu end
local function isMoveMenu(s) return getmetatable(s) == MoveSelectMenu end
local function isLearn(s) return getmetatable(s) == MoveLearnMenu end
local function find(pred)
for _, s in ipairs(game.stack.states or {}) do
if pred(s) then return s end
end
end
local function boxText(b)
local out = {}
for _, page in ipairs((b and b.pages) or {}) do
for _, l in ipairs(page) do out[#out + 1] = tostring(l) end
end
return table.concat(out, " ")
end
local function waitFor(pred, n)
for _ = 1, n or 240 do
if pred() then return true end
U.wait(1)
end
return pred()
end
local function cursorTo(menu, want)
for _ = 1, 40 do
if menu.index == want then return true end
U.tap(game, menu.index < want and "down" or "up")
U.wait(3)
end
return menu.index == want
end
local gengar = Pokemon.new(game.data, "GENGAR", 30)
gengar.moves = {
{ id = "LICK", pp = 30 }, { id = "CONFUSE_RAY", pp = 10 },
{ id = "NIGHT_SHADE", pp = 15 }, { id = "HYPNOSIS", pp = 20 },
}
local nido = Pokemon.new(game.data, "NIDOKING", 40)
nido.moves = {
{ id = "SURF", pp = 15 }, { id = "HORN_ATTACK", pp = 25 },
{ id = "POISON_STING", pp = 35 }, { id = "LEER", pp = 30 },
}
game.save.party = { gengar, nido }
game.save.player.name = "RED"
game.save.inventory = {}
Bag.add(game.save, "PP_UP", 5, game.data)
Bag.add(game.save, "TM_MEGA_PUNCH", 1, game.data)
U.teleport(game, "PALLET_TOWN", 10, 8, "down")
U.wait(10)
local function openPicker(id)
while #game.stack.states > 1 do game.stack:pop() end
U.wait(2)
local bag = Screens.push(game, "BagMenu", {})
U.wait(12)
local row
for i, r in ipairs(bag.items or {}) do
if r.value == id then row = i break end
end
if not row or not cursorTo(bag, row) then return nil end
U.tap(game, "a")
U.wait(12)
local ut = top()
if ut and ut.items and ut.items[1] and ut.items[1].label == "USE" then
cursorTo(ut, 1)
U.tap(game, "a")
U.wait(4)
end
if not waitFor(function()
if isParty(top()) then return true end
local t = top()
if isBox(t) and (t.done or t.waiting) then U.tap(game, "a") end
if getmetatable(t) == ChoiceBox then U.tap(game, "a") end
return false
end, 600) then return nil end
return top()
end
local function pickMon(picker, slot)
cursorTo(picker, slot)
U.tap(game, "a")
end
U.log("======== pass 1: timing, no shots ========")
local picker = openPicker("PP_UP")
if check("PP UP party picker opened", picker ~= nil) then
pickMon(picker, 1)
local promptBox = top()
check("A on GENGAR: a text box is on top, not the move box", isBox(promptBox))
local mm = find(isMoveMenu)
check("the move menu waits underneath, not ready", mm ~= nil and not mm.ready)
check("the chosen arrow is hollow", picker.chosenHollow == true)
check("the prompt is still typing", isBox(promptBox) and not promptBox.done)
local frames = 0
while not (isMoveMenu(top()) and top().ready) and frames < 400 do
U.wait(1)
frames = frames + 1
end
U.log("prompt frames before the move box:", frames)
check("the move box waited for the typed prompt (" .. frames .. " frames)",
frames >= 10 and frames < 400)
U.tap(game, "b")
U.wait(4)
check("B returns to the party menu", isParty(top()))
U.wait(2)
check("the party arrow is filled again", not picker.chosenHollow)
end
U.log("======== pass 2: PP UP with shots ========")
picker = openPicker("PP_UP")
if check("PP UP party picker opened again", picker ~= nil) then
pickMon(picker, 1)
U.wait(3)
U.shot(game, DIR .. "/2320_01_prompt_typing_hollow_arrow.png")
check("move box ready after the prompt",
waitFor(function() return isMoveMenu(top()) and top().ready end, 400))
local mm = top()
U.wait(2)
U.shot(game, DIR .. "/2320_02_move_box_over_textbox.png")
cursorTo(mm, 1)
U.tap(game, "a")
check("the result box opened",
waitFor(function() return isBox(top()) end, 30))
local res = top()
check("result reads PP increased", boxText(res):find("increased") ~= nil)
check("the move box is held under the result", mm.held == true and find(isMoveMenu) == mm)
check("the party arrow is still hollow", picker.chosenHollow == true)
waitFor(function() return res.done end, 240)
U.shot(game, DIR .. "/2320_03_result_keeps_move_box.png")
waitFor(function()
if isBox(top()) then U.tap(game, "a") end
return not find(isParty)
end, 120)
check("dismissing closes both the move box and the picker",
not find(isParty) and not find(isMoveMenu))
check("LICK got one PP Up", (gengar.moves[1].ppUps or 0) == 1)
end
U.log("======== PP UP on a maxed move reprompts ========")
gengar.moves[1].ppUps = 3
local before = game.save.inventory.PP_UP
picker = openPicker("PP_UP")
if check("PP UP party picker opened for the maxed move", picker ~= nil) then
pickMon(picker, 1)
waitFor(function() return isMoveMenu(top()) and top().ready end, 400)
local mm = top()
cursorTo(mm, 1)
U.tap(game, "a")
waitFor(function() return isBox(top()) end, 30)
local res = top()
check("maxed out text prints", boxText(res):find("maxed out") ~= nil)
waitFor(function() return res.done end, 240)
U.shot(game, DIR .. "/2320_04_pp_maxed_out.png")
U.tap(game, "a")
U.wait(2)
check("the prompt types again", isBox(top()) and find(isMoveMenu) == mm and not mm.ready)
check("the move box comes back",
waitFor(function() return top() == mm and mm.ready end, 400))
U.wait(2)
U.shot(game, DIR .. "/2320_05_maxed_reprompt.png")
check("no PP UP was spent", game.save.inventory.PP_UP == before)
U.tap(game, "b")
U.wait(4)
U.tap(game, "b")
U.wait(8)
end
U.log("======== TM on a full moveset ========")
picker = openPicker("TM_MEGA_PUNCH")
if check("TM party picker opened", picker ~= nil) then
pickMon(picker, 2)
local learn
local ok = waitFor(function()
learn = find(isLearn)
local t = top()
if learn and isBox(t) and boxText(t):find("forgotten") then return true end
if getmetatable(t) == ChoiceBox then U.tap(game, "a")
elseif isBox(t) and (t.done or t.waiting) then U.tap(game, "a") end
return false
end, 900)
check("Which move should be forgotten? types first", ok and learn and not learn.selecting)
U.wait(3)
U.shot(game, DIR .. "/2320_06_forget_prompt_typing.png")
check("the forget box follows the text",
waitFor(function() return learn and top() == learn and learn.selecting end, 400))
U.wait(2)
U.shot(game, DIR .. "/2320_07_forget_box_over_textbox.png")
cursorTo(learn, 1)
U.tap(game, "a")
U.wait(2)
check("SURF is refused and the forget box is gone",
isBox(top()) and boxText(top()):find("HM") ~= nil and not learn.selecting)
waitFor(function() return top().done end, 240)
U.shot(game, DIR .. "/2320_08_hm_refused_no_box.png")
U.tap(game, "a")
check("the forget prompt retypes, then the box returns",
waitFor(function() return top() == learn and learn.selecting end, 400))
cursorTo(learn, 2)
U.tap(game, "a")
U.wait(2)
check("the forget box is gone for 1, 2 and... Poof!", not find(isLearn))
waitFor(function()
local t = top()
if isBox(t) and (t.done or t.waiting) then U.tap(game, "a") end
return not find(isParty)
end, 900)
local knows = false
for _, mv in ipairs(nido.moves) do if mv.id == "MEGA_PUNCH" then knows = true end end
check("NIDOKING learned MEGA PUNCH", knows)
end
U.log(fail == 0 and "PASS pp_up_move_box_2320" or ("FAIL pp_up_move_box_2320 (" .. fail .. ")"))
love.event.quit(fail == 0 and 0 or 1)
end