mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
23617f43b4
CLOSES #2290, CLOSES #2338, CLOSES #2186, CLOSES #2305, CLOSES #2332, CLOSES #2320, CLOSES #2344, CLOSES #2291, CLOSES #2335, CLOSES #2340, CLOSES #2385, CLOSES #2352, CLOSES #2378, CLOSES #2403, CLOSES #2404, CLOSES #2405, CLOSES #2367, CLOSES #2037, CLOSES #2177, CLOSES #2368, CLOSES #2382, CLOSES #1951
258 lines
8.9 KiB
Lua
258 lines
8.9 KiB
Lua
-- engine/items/item_effects.asm:1954
|
|
-- engine/battle/core.asm:2520
|
|
-- Not under POKEPORT_SPEED: SFX_HEAL_AILMENT rides the real-time audio clock.
|
|
-- POKEPORT_DRIVER=tests/drivers/pp_restore_menu_2155_2158.lua \
|
|
-- POKEPORT_IDENTITY=pp2155 POKEPORT_TOUCH=0 POKEPORT_VERSION=red \
|
|
-- SHOT_DIR=/tmp/shots2155 love .
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local Bag = require("src.inventory.Bag")
|
|
local ItemEffects = require("src.inventory.ItemEffects")
|
|
local PartyMenu = require("src.ui.PartyMenu")
|
|
local MoveSelectMenu = require("src.ui.MoveSelectMenu")
|
|
local TextBox = require("src.render.TextBox")
|
|
|
|
local pass, fail = 0, 0
|
|
local function check(label, ok)
|
|
if ok then pass = pass + 1 else 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 isPicker(s)
|
|
return s ~= nil and (s.screenId == "PartyMenu" or getmetatable(s) == PartyMenu)
|
|
end
|
|
local function isMoveMenu(s) return getmetatable(s) == MoveSelectMenu end
|
|
local function isBox(s) return getmetatable(s) == TextBox end
|
|
local function inStack(pred)
|
|
for _, s in ipairs(game.stack.states or {}) do
|
|
if pred(s) then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
U.log("======== #2155/#2158 PP restore: machine checks ========")
|
|
for _, id in ipairs({ "ELIXER", "MAX_ELIXER", "ETHER", "MAX_ETHER", "PP_UP" }) do
|
|
check(id .. " keeps the party menu drawn",
|
|
ItemEffects.keepsPartyMenuOpen(id) == true)
|
|
check(id .. " resolves in the item table", game.data.items[id] ~= nil)
|
|
end
|
|
check("MoveSelectMenu draws", type(MoveSelectMenu.draw) == "function")
|
|
|
|
local lead = Pokemon.new(game.data, "CHARIZARD", 50)
|
|
local topped = Pokemon.new(game.data, "SNORLAX", 40)
|
|
for _, mv in ipairs(lead.moves) do mv.pp = 1 end
|
|
game.save.party = { lead, topped }
|
|
game.save.player.name = "RED"
|
|
for _, id in ipairs({ "ELIXER", "MAX_ELIXER", "ETHER", "MAX_ETHER" }) do
|
|
Bag.add(game.save, id, 5)
|
|
end
|
|
U.teleport(game, "PALLET_TOWN", 10, 8, "down")
|
|
U.wait(10)
|
|
|
|
local function cursorTo(menu, want)
|
|
for _ = 1, 40 do
|
|
if not menu or menu.index == want then return menu and menu.index == want end
|
|
U.tap(game, menu.index < want and "down" or "up")
|
|
U.wait(3)
|
|
end
|
|
return menu.index == want
|
|
end
|
|
|
|
local function openPickerFor(id)
|
|
U.tap(game, "start")
|
|
U.wait(10)
|
|
local menu = top()
|
|
if not (menu and menu.screenId == "StartMenu") then
|
|
return nil, "start menu never opened"
|
|
end
|
|
local itemRow
|
|
for i, it in ipairs(menu.items or {}) do
|
|
if it.label == "ITEM" then itemRow = i break end
|
|
end
|
|
if not itemRow or not cursorTo(menu, itemRow) then return nil, "no ITEM row" end
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
local bag = top()
|
|
if not (bag and bag.screenId == "BagMenu") then return nil, "bag never opened" end
|
|
local bagRow
|
|
for i, r in ipairs(bag.items or {}) do
|
|
if r.value == id then bagRow = i break end
|
|
end
|
|
if not bagRow or not cursorTo(bag, bagRow) then return nil, id .. " not in bag" end
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
local ut = top()
|
|
if ut and ut.items and ut.items[1] and ut.items[1].label == "USE" then
|
|
if not cursorTo(ut, 1) then return nil, "USE row unreachable" end
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
end
|
|
local picker = top()
|
|
if not isPicker(picker) then return nil, "party picker never opened" end
|
|
return picker
|
|
end
|
|
|
|
local function backToOverworld()
|
|
for _ = 1, 30 do
|
|
if top() == game.overworld then return true end
|
|
U.tap(game, "b")
|
|
U.wait(6)
|
|
end
|
|
return top() == game.overworld
|
|
end
|
|
|
|
local function dismiss()
|
|
for _ = 1, 30 do
|
|
if not inStack(isPicker) then break end
|
|
U.tap(game, "a")
|
|
U.wait(8)
|
|
end
|
|
end
|
|
|
|
local function waitMoveMenu()
|
|
for _ = 1, 240 do
|
|
local t = top()
|
|
if isMoveMenu(t) and t.ready then return true end
|
|
U.wait(1)
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function waitForBag()
|
|
for _ = 1, 60 do
|
|
local t = top()
|
|
if t ~= nil and t.screenId == "BagMenu" then break end
|
|
U.wait(1)
|
|
end
|
|
end
|
|
|
|
U.log("======== #2155 ELIXER: SFX_HEAL_AILMENT over a live party menu ========")
|
|
local picker, why = openPickerFor("ELIXER")
|
|
check("party picker opened for ELIXER" .. (why and (" (" .. why .. ")") or ""),
|
|
picker ~= nil)
|
|
if picker then
|
|
check("keepOpen is set for the ELIXERs", picker.keepOpen == true)
|
|
cursorTo(picker, 1)
|
|
U.tap(game, "a")
|
|
U.wait(6)
|
|
check("the party menu is still on the stack after the pick", inStack(isPicker))
|
|
-- engine/items/item_effects.asm:2022
|
|
check("the cursor is still drawn", picker.cursorsErased ~= true)
|
|
for _ = 1, 60 do
|
|
if isBox(top()) then break end
|
|
U.wait(1)
|
|
end
|
|
check("the PP restored box opened", isBox(top()))
|
|
check("...over the STILL-drawn party menu", inStack(isPicker))
|
|
check("every slot came back up", lead.moves[1].pp > 1)
|
|
U.log("LISTEN", "SFX_HEAL_AILMENT should have played as the box opened")
|
|
U.wait(60)
|
|
U.shot(game, DIR .. "/pp2155_elixir_message_over_party.png")
|
|
dismiss()
|
|
check("the picker is gone once the message is dismissed", not inStack(isPicker))
|
|
-- pokered engine/items/item_effects.asm:1244
|
|
waitForBag()
|
|
check("and we are back on the ITEM list",
|
|
top() ~= nil and top().screenId == "BagMenu")
|
|
end
|
|
backToOverworld()
|
|
|
|
U.log("======== #2155 MAX ELIXER refusal prints over the party menu ========")
|
|
local refuse = openPickerFor("MAX_ELIXER")
|
|
if check("party picker opened for MAX ELIXER", refuse ~= nil) then
|
|
cursorTo(refuse, 2) -- the untouched SNORLAX
|
|
U.tap(game, "a")
|
|
U.wait(6)
|
|
for _ = 1, 60 do
|
|
if isBox(top()) then break end
|
|
U.wait(1)
|
|
end
|
|
check("the no-effect box opened", isBox(top()))
|
|
check("...over the STILL-drawn party menu", inStack(isPicker))
|
|
U.wait(60)
|
|
U.shot(game, DIR .. "/pp2155_max_elixir_no_effect.png")
|
|
dismiss()
|
|
end
|
|
backToOverworld()
|
|
|
|
U.log("======== #2158 ETHER: wMoveMenuType 2 window over the party menu ========")
|
|
for _, mv in ipairs(lead.moves) do mv.pp = 1 end
|
|
local ether = openPickerFor("ETHER")
|
|
if check("party picker opened for ETHER", ether ~= nil) then
|
|
check("keepOpen is set for the ETHERs", ether.keepOpen == true)
|
|
cursorTo(ether, 1)
|
|
U.tap(game, "a")
|
|
check("the move window is the top state", waitMoveMenu())
|
|
check("...with the party menu still drawn underneath", inStack(isPicker))
|
|
U.wait(20)
|
|
U.shot(game, DIR .. "/pp2158_ether_move_window.png")
|
|
|
|
-- engine/items/item_effects.asm:1985
|
|
U.tap(game, "b")
|
|
U.wait(8)
|
|
check("B goes back to the party menu", isPicker(top()))
|
|
U.tap(game, "a")
|
|
check("and the move window opens again", waitMoveMenu())
|
|
|
|
local before = lead.moves[1].pp
|
|
U.tap(game, "a")
|
|
U.wait(6)
|
|
for _ = 1, 60 do
|
|
if isBox(top()) then break end
|
|
U.wait(1)
|
|
end
|
|
check("the PP restored box opened", isBox(top()))
|
|
check("...over the STILL-drawn party menu", inStack(isPicker))
|
|
check("the picked move gained PP", lead.moves[1].pp > before)
|
|
U.log("LISTEN", "SFX_HEAL_AILMENT should have played for the ETHER too")
|
|
U.wait(60)
|
|
U.shot(game, DIR .. "/pp2158_ether_message_over_party.png")
|
|
dismiss()
|
|
-- pokered engine/items/item_effects.asm:1244
|
|
waitForBag()
|
|
check("back on the ITEM list", top() ~= nil and top().screenId == "BagMenu")
|
|
end
|
|
backToOverworld()
|
|
|
|
U.log("======== #2158 MAX ETHER refusal keeps both windows up ========")
|
|
local maxEther = openPickerFor("MAX_ETHER")
|
|
if check("party picker opened for MAX ETHER", maxEther ~= nil) then
|
|
cursorTo(maxEther, 2) -- the untouched SNORLAX
|
|
U.tap(game, "a")
|
|
check("the move window opened", waitMoveMenu())
|
|
U.tap(game, "a")
|
|
U.wait(6)
|
|
for _ = 1, 60 do
|
|
if isBox(top()) then break end
|
|
U.wait(1)
|
|
end
|
|
check("the no-effect box opened", isBox(top()))
|
|
check("...over the STILL-drawn party menu", inStack(isPicker))
|
|
U.wait(60)
|
|
U.shot(game, DIR .. "/pp2158_max_ether_no_effect.png")
|
|
dismiss()
|
|
end
|
|
backToOverworld()
|
|
|
|
U.log(("======== PP restore driver: %d passed, %d failed ========")
|
|
:format(pass, fail))
|
|
U.log(fail == 0 and "DRIVER PASS" or "DRIVER FAIL")
|
|
|
|
for _, mv in ipairs(lead.moves) do mv.pp = 1 end
|
|
local handoff = openPickerFor("ETHER")
|
|
if handoff then
|
|
cursorTo(handoff, 1)
|
|
U.tap(game, "a")
|
|
U.wait(8)
|
|
end
|
|
U.log("The ETHER move window is open over the party menu. Compare it with")
|
|
U.log("shots/issue_2158_1.png: a 16x6 box at tile 4,7, four names single")
|
|
U.log("spaced with '-' for empty slots, no PP column, cursor at column 5,")
|
|
U.log("and 'Restore PP of / which technique?' in the bottom box. B returns")
|
|
U.log("to the party menu; A restores PP with the Heal_Ailment jingle.")
|
|
love.event.quit(fail == 0 and 0 or 1)
|
|
end
|