local U = require("tests.drivers.util") local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_pp_items_2420" -- pokefirered/include/constants/items.h:38 local ITEM_ETHER = 34 local ITEM_PP_UP = 69 local ITEM_LEPPA_BERRY = 138 local ITEM_BERRY_POUCH = 365 local PALLET = "FR_PALLET_TOWN" local failures = 0 local function result(ok, label) print((ok and "PASS " or "FAIL ") .. label) if not ok then failures = failures + 1 end return ok end local function finish() if failures == 0 then print("PASS pp_items_2420") love.event.quit(0) else print("FAIL pp_items_2420 failures=" .. failures) love.event.quit(1) end end return function(game) for _ = 1, 900 do if game.phase == "boot" and game.boot then break end U.wait(1) end game:_handleBootAction({ action = "new_game", name = "RED" }) U.wait(240) local Runtime = require("src.core.game3.runtime") local Map = require("src.core.game3.map") local Player = require("src.core.game3.player") local Bag = require("src.core.game3.bag") local Party = require("src.core.game3.party") local Pokemon = require("src.core.game3.pokemon") local StartMenu = require("src.ui.game3.start_menu") local BagMenu = require("src.ui.game3.bag_menu") local PartyMenu = require("src.ui.game3.party_menu") local BerryPouch = require("src.ui.game3.berry_pouch") local session = Runtime.getSession() if not result(session ~= nil, "new game reached the game3 field") then return finish() end session.party = {} Party.giveMon(session, 7, 15) local mon = session.party[1] mon.moves = { 33, 39, 145, 110 } mon.pp = { 2, 30, 30, 40 } mon.maxPp = { 35, 30, 30, 40 } mon.ppBonusesPacked = nil session.bag = session.bag or {} Bag.add(session.bag, ITEM_ETHER, 3) Bag.add(session.bag, ITEM_PP_UP, 1) Bag.add(session.bag, ITEM_LEPPA_BERRY, 2) Bag.add(session.bag, ITEM_BERRY_POUCH, 1) Map.load(nil, game, PALLET, { x = 7, y = 10, facing = "down" }) Player.moving = false Player.cellX, Player.cellY = 7, 10 Player.px, Player.py = 7 * 16, 10 * 16 Player.targetX, Player.targetY = 7, 10 U.wait(90) local function pickInBag(pocket, itemId) for _ = 1, 6 do if BagMenu.currentPocket() == pocket then break end U.tap(game, "right") U.wait(15) end for _ = 1, 30 do local want for i, r in ipairs(BagMenu.list() or {}) do if tonumber(r.id) == itemId then want = i end end if not want or BagMenu.cursor == want then break end U.tap(game, (BagMenu.cursor > want) and "up" or "down") U.wait(8) end local row = BagMenu.isOpen() and BagMenu.list()[BagMenu.cursor] return row and tonumber(row.id) == itemId end local function openFieldBag(pocket, itemId) U.tap(game, "start") U.wait(30) for _ = 1, 12 do local e = StartMenu.ENTRIES and StartMenu.ENTRIES[StartMenu.cursor] if e and e.id == "bag" then break end U.tap(game, "down") U.wait(8) end U.tap(game, "a") U.wait(60) return pickInBag(pocket, itemId) end local function waitMode(m, n) for _ = 1, n or 120 do if PartyMenu.isOpen() and PartyMenu.mode == m then return true end U.wait(1) end return false end local function closeAllField() for _ = 1, 20 do if not (PartyMenu.isOpen() or BagMenu.isOpen() or (StartMenu.isOpen and StartMenu.isOpen())) then break end U.tap(game, "b") U.wait(20) end end -- pokefirered/src/party_menu.c:4591 ItemUseCB_TryRestorePP if not result(openFieldBag("ITEMS", ITEM_ETHER), "field bag cursor on ETHER") then return finish() end U.tap(game, "a") U.wait(20) U.tap(game, "a") if not result(waitMode("use", 120), "USE opened the party menu") then return finish() end U.wait(20) PartyMenu.cursor = 1 U.tap(game, "a") U.wait(10) result(waitMode("forget", 30), "a move-select window opened") result(PartyMenu._forgetPrompt == "Restore which move?", "prompt is gText_RestoreWhichMove (" .. tostring(PartyMenu._forgetPrompt) .. ")") U.wait(10) U.shot(game, DIR .. "/2420_field_ether_restore_which_move.png") local hp0 = mon.hp U.tap(game, "a") waitMode("message", 60) U.wait(20) result((PartyMenu._messageText or ""):find("PP was restored.", 1, true) ~= nil, "gText_PPWasRestored shown (" .. tostring(PartyMenu._messageText) .. ")") U.shot(game, DIR .. "/2420_field_ether_pp_restored.png") result(mon.pp[1] == 12, "field ETHER restored TACKLE 2 -> " .. tostring(mon.pp[1])) result(mon.hp == hp0, "and HP unchanged") result(Bag.has(session.bag, ITEM_ETHER, 2) and not Bag.has(session.bag, ITEM_ETHER, 3), "one ETHER consumed") U.tap(game, "a") U.wait(20) closeAllField() -- pokefirered/src/party_menu.c:4709 ItemUseCB_PPUp if not result(openFieldBag("ITEMS", ITEM_PP_UP), "field bag cursor on PP UP") then return finish() end U.tap(game, "a") U.wait(20) U.tap(game, "a") if not result(waitMode("use", 120), "USE opened the party menu for PP UP") then return finish() end U.wait(20) PartyMenu.cursor = 1 U.tap(game, "a") U.wait(10) result(waitMode("forget", 30) and PartyMenu._forgetPrompt == "Boost PP of which?", "prompt is gText_BoostPp (" .. tostring(PartyMenu._forgetPrompt) .. ")") U.wait(10) U.shot(game, DIR .. "/2420_field_ppup_boost_which.png") local base = Pokemon.movePp(33) U.tap(game, "a") waitMode("message", 60) U.wait(20) result((PartyMenu._messageText or ""):find("TACKLE's PP increased.", 1, true) ~= nil, "gText_MovesPPIncreased shown (" .. tostring(PartyMenu._messageText) .. ")") U.shot(game, DIR .. "/2420_field_ppup_pp_increased.png") local want = base + math.floor(base * 20 / 100) result(mon.maxPp[1] == want, string.format("PP UP max PP %d -> %s (+20%% of base)", base, tostring(mon.maxPp[1]))) result(mon.pp[1] == 12 + want - base, "and current PP rose by the same step (" .. tostring(mon.pp[1]) .. ")") U.tap(game, "a") U.wait(20) closeAllField() local BattleBridge = require("src.core.game3.battle_bridge") local Battle = require("src.core.game3.battle") local Ui = require("src.core.game3.battle.ui") local ok, err = BattleBridge.startWild(Runtime._mod, game, { species = 16, level = 5 }, { fade = false }) if not result(ok == true, "wild battle started " .. tostring(err or "")) then return finish() end local function at_command() return Battle.isActive() and Battle._phase == "command" and Ui._mode == "menu" end local lastTap, f = 0, 0 local function pumpToCommand(n) for _ = 1, n or 3000 do f = f + 1 if at_command() then return true end if Ui.dialogPending and Ui.dialogPending() and f - lastTap >= 14 then lastTap = f U.tap(game, "a") else U.wait(1) end end return at_command() end if not result(pumpToCommand(), "reached the battle command menu") then return finish() end local st = Battle.getState() st.enemy.mon.moves = { 150, 0, 0, 0 } st.enemy.mon.pp = { 40, 0, 0, 0 } local State = require("src.core.game3.battle.state") local bmon = State.ensureBattleMoves(st.player) bmon.pp[1] = 1 bmon.pp[2] = 0 local party = st.playerParty local pmon = party[st.player.partyIndex or 1] pmon.hp = math.max(1, (tonumber(pmon.maxHp) or 20) - 5) st.player.mon.hp = pmon.hp local function openBattleBag() Ui._menuIndex = 2 U.tap(game, "a") for _ = 1, 120 do if BagMenu.isOpen() and BagMenu.mode == "list" then break end U.wait(1) end U.wait(30) return BagMenu.isOpen() end local function pickMonAndMove(moveCursor, shotName, msgShot) if not waitMode("use", 120) then return false end U.wait(20) PartyMenu.cursor = 1 U.tap(game, "a") U.wait(10) if not waitMode("forget", 30) then return false end for _ = 2, moveCursor do U.tap(game, "down") U.wait(6) end U.wait(10) U.shot(game, DIR .. "/" .. shotName) U.tap(game, "a") waitMode("message", 60) U.wait(20) U.shot(game, DIR .. "/" .. msgShot) local txt = PartyMenu._messageText U.tap(game, "a") return true, txt end -- pokefirered/src/party_menu.c:4675 TryUsePPItemInBattle local hpBefore = pmon.hp if not result(openBattleBag(), "battle BAG opened") then return finish() end if not result(pickInBag("ITEMS", ITEM_ETHER), "battle bag cursor on ETHER") then return finish() end U.tap(game, "a") U.wait(20) U.tap(game, "a") local okE, txtE = pickMonAndMove(1, "2420_battle_ether_restore_which_move.png", "2420_battle_ether_pp_restored.png") result(okE and (txtE or ""):find("PP was restored.", 1, true) ~= nil, "battle ETHER picked a move and showed PP was restored (" .. tostring(txtE) .. ")") pumpToCommand() result(st.player.mon.pp[1] == 11, "battle ETHER restored the active battler's PP 1 -> " .. tostring(st.player.mon.pp[1])) result(pmon.pp[1] == 11, "and the party mon's PP matches (" .. tostring(pmon.pp[1]) .. ")") result(pmon.hp == hpBefore and st.player.mon.hp == hpBefore, "HP unchanged " .. tostring(hpBefore) .. " -> " .. tostring(st.player.mon.hp)) local sawUsed = false for _, t in ipairs(Ui.log()) do if t:find("ETHER", 1, true) then sawUsed = true end end result(sawUsed, "battle log has RED used the ETHER") if not result(openBattleBag(), "battle BAG opened again") then return finish() end if not result(pickInBag("KEY_ITEMS", ITEM_BERRY_POUCH), "battle bag cursor on BERRY POUCH") then return finish() end BerryPouch.show(session, session.bag, { session = session, bag = session.bag }) U.wait(30) for i, r in ipairs(BerryPouch.list() or {}) do if tonumber(r.id) == ITEM_LEPPA_BERRY then BerryPouch.cursor = i end end U.tap(game, "a") U.wait(15) U.tap(game, "a") local okL, txtL = pickMonAndMove(2, "2420_battle_leppa_restore_which_move.png", "2420_battle_leppa_pp_restored.png") result(okL and (txtL or ""):find("PP was restored.", 1, true) ~= nil, "battle LEPPA picked a move and showed PP was restored (" .. tostring(txtL) .. ")") pumpToCommand() result(st.player.mon.pp[2] == 10, "battle LEPPA restored move 2 PP 0 -> " .. tostring(st.player.mon.pp[2])) result(pmon.pp[2] == 10, "and the party mon's PP matches (" .. tostring(pmon.pp[2]) .. ")") result(pmon.hp == hpBefore, "HP still unchanged (" .. tostring(pmon.hp) .. ")") finish() end