Files
gen1recomp/tests/drivers/game3_stitchmap_items.lua

329 lines
12 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_stitchmap_items"
-- pokefirered/include/constants/items.h:89
local ITEM_ESCAPE_ROPE = 85
-- pokefirered/include/constants/items.h:271
local ITEM_COIN_CASE = 260
-- pokefirered/include/constants/items.h:444
local ITEM_POWDER_JAR = 372
-- pokefirered/include/constants/items.h:327
local ITEM_TM28 = 316
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 stitchmap_items")
love.event.quit(0)
else
print("FAIL stitchmap_items 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 ItemUse = require("src.core.game3.item_use")
local ItemsData = require("src.core.game3.items_data")
local Party = require("src.core.game3.party")
local Pokemon = require("src.core.game3.pokemon")
local FieldMoves = require("src.core.game3.field_moves")
local Message = require("src.ui.game3.message")
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 MapCatalog = require("src.import.gba.map_catalog")
local session = Runtime.getSession()
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
local MT_MOON = MapCatalog.pretToEngine("MtMoon_1F")
if not result(type(MT_MOON) == "string", "Mt Moon 1F resolves to a cache map id") then
return finish()
end
local function place(x, y, facing)
Player.moving = false
Player.progress = 0
Player.cellX, Player.cellY = x, y
Player.px, Player.py = x * 16, y * 16
Player.targetX, Player.targetY = x, y
Player.facing = facing
if game.session then
game.session.x, game.session.y, game.session.facing = x, y, facing
end
end
session.bag = session.bag or {}
Bag.add(session.bag, ITEM_COIN_CASE, 1)
Bag.add(session.bag, ITEM_POWDER_JAR, 1)
Bag.add(session.bag, ITEM_ESCAPE_ROPE, 3)
Bag.add(session.bag, ITEM_TM28, 1)
-- pokefirered/src/coins.c:16 SetCoins
Bag.Coins.set(session, 2750)
result(Bag.Coins.get(session) == 2750, "the player has 2750 coins")
require("src.core.game3.scripting.flags").setFlag(require("src.core.game3.scripting.space").store, nil, 0x828, true) -- data/maps/PalletTown_ProfessorOaksLab/scripts.inc:1120
if #(session.party or {}) == 0 then
Party.giveMon(session, 4, 8)
end
local mon = session.party and session.party[1]
if not result(type(mon) == "table", "the player has a party mon") then return finish() end
result(mon.nickname == "", "the mon came out of Party.giveMon with no nickname")
local monName = Pokemon.displayMonName(mon)
result(monName ~= "" and monName ~= nil, "its display name is " .. tostring(monName))
local tmOk = ItemUse.useTm(session, session.bag, ITEM_TM28, 1)
result(tmOk == true, "TM28 taught it DIG")
result(Pokemon.knowsMove(mon, FieldMoves.MOVES.DIG) == true, "the mon knows DIG")
local function openStart()
for _ = 1, 20 do
if StartMenu.isOpen() then return true end
U.tap(game, "start")
U.wait(12)
end
return StartMenu.isOpen()
end
local function startEntry(id)
if not openStart() then return false end
for _ = 1, 20 do
local e = StartMenu.ENTRIES[StartMenu.cursor]
if e and e.id == id then return true end
U.tap(game, "down")
U.wait(8)
end
local e = StartMenu.ENTRIES[StartMenu.cursor]
return e and e.id == id
end
local function openBag()
if not startEntry("bag") then return false end
U.tap(game, "a")
for _ = 1, 60 do
if BagMenu.isOpen() and not BagMenu._open then break end
U.wait(4)
end
return BagMenu.isOpen()
end
local function toPocket(pocket)
local want
for i, p in ipairs(ItemsData.BAG_POCKET_ORDER or {}) do
if p == pocket then want = i end
end
if not want then return false end
for _ = 1, 12 do
if BagMenu.pocketIdx == want then return true end
U.tap(game, BagMenu.pocketIdx < want and "right" or "left")
U.wait(20)
end
return BagMenu.currentPocket() == pocket
end
local function toRow(itemId)
local target
for i, r in ipairs(BagMenu.list()) do
if ItemsData.toNumericId(r.id) == itemId then target = i end
end
if not target then return false end
for _ = 1, 30 do
if BagMenu.cursor == target then return true end
U.tap(game, BagMenu.cursor < target and "down" or "up")
U.wait(8)
end
return BagMenu.cursor == target
end
local function pressUse()
U.tap(game, "a")
U.wait(10)
if BagMenu.mode ~= "action" then return false end
for _ = 1, 8 do
if BagMenu.ACTIONS[BagMenu.actionCursor] == "USE" then break end
U.tap(game, "down")
U.wait(8)
end
U.tap(game, "a")
U.wait(40)
return true
end
Map.load(nil, game, PALLET, { x = 12, y = 11, facing = "down" })
place(12, 11, "down")
U.wait(90)
result(Map.current == PALLET, "standing in Pallet Town, map=" .. tostring(Map.current))
-- pokefirered/src/item_use.c:337 FieldUseFunc_CoinCase
result(openBag(), "the START menu opened the bag")
result(toPocket("KEY_ITEMS"), "on the KEY ITEMS pocket, got " .. tostring(BagMenu.currentPocket()))
result(toRow(ITEM_COIN_CASE), "cursor on the COIN CASE")
result(pressUse(), "USE picked for the COIN CASE")
result(BagMenu.isOpen() == true, "the bag stayed open for the COIN CASE message")
result(BagMenu.mode == "message", "the bag is in message mode, got " .. tostring(BagMenu.mode))
local coinText = tostring(BagMenu.messageText)
result(coinText:find("Your COINS:", 1, true) == 1, "the line is gText_CoinCase: " .. coinText)
result(coinText:find("2750", 1, true) ~= nil, "it shows the live coin count")
result(U.shot(game, DIR .. "/stitchmap_items_01_coin_case.png"), "coin case screenshot")
U.tap(game, "b")
U.wait(20)
result(BagMenu.mode == "list" and BagMenu.isOpen(), "B returned to the item list")
-- pokefirered/src/item_use.c:348 FieldUseFunc_PowderJar
result(toRow(ITEM_POWDER_JAR), "cursor on the POWDER JAR")
result(pressUse(), "USE picked for the POWDER JAR")
local powderText = tostring(BagMenu.messageText)
result(BagMenu.mode == "message", "the bag is in message mode for the POWDER JAR")
result(powderText:find("POWDER QTY:", 1, true) == 1, "the line is gText_PowderQty: " .. powderText)
result(U.shot(game, DIR .. "/stitchmap_items_02_powder_jar.png"), "powder jar screenshot")
U.tap(game, "b")
U.wait(20)
-- pokefirered/src/item_use.c:614 CanUseEscapeRopeOnCurrMap
local ropesBefore = Bag.get(session.bag, ITEM_ESCAPE_ROPE)
result(toPocket("ITEMS"), "on the ITEMS pocket, got " .. tostring(BagMenu.currentPocket()))
result(toRow(ITEM_ESCAPE_ROPE), "cursor on the ESCAPE ROPE")
result(pressUse(), "USE picked for the ESCAPE ROPE in Pallet Town")
local ropeText = tostring(BagMenu.messageText)
result(BagMenu.mode == "message", "Pallet Town answered with a message")
result(ropeText:find("OAK:", 1, true) == 1, "Pallet Town refuses the ESCAPE ROPE: " .. ropeText)
result(Bag.get(session.bag, ITEM_ESCAPE_ROPE) == ropesBefore, "the refused rope was not spent")
result(U.shot(game, DIR .. "/stitchmap_items_03_rope_refused_pallet.png"),
"refused escape rope screenshot")
U.tap(game, "b")
U.wait(20)
for _ = 1, 40 do
if not BagMenu.isOpen() then break end
U.tap(game, "b")
U.wait(10)
end
if StartMenu.isOpen() then
U.tap(game, "b")
U.wait(20)
end
result(BagMenu.isOpen() == false, "the bag closed")
Map.load(nil, game, MT_MOON, { x = 5, y = 35, facing = "down" })
place(5, 35, "down")
U.wait(120)
result(Map.current == MT_MOON, "standing in Mt Moon 1F, map=" .. tostring(Map.current))
local moonDef = Map.currentDef()
result(moonDef ~= nil and (tonumber(moonDef.allowEscaping) or 0) ~= 0,
"the live Mt Moon def carries allowEscaping")
-- pokefirered/src/fldeff_dig.c:12 SetUpFieldMove_Dig
result(startEntry("pokemon"), "the START menu is on POKEMON")
U.tap(game, "a")
for _ = 1, 60 do
if PartyMenu.isOpen and PartyMenu.isOpen() then break end
U.wait(4)
end
result(PartyMenu.isOpen == nil or PartyMenu.isOpen() == true, "the party menu opened")
U.tap(game, "a")
U.wait(20)
local digIdx
for i, act in ipairs(PartyMenu.ACTIONS or {}) do
if act == "DIG" then digIdx = i end
end
if not result(digIdx ~= nil, "DIG is offered in the party action menu") then return finish() end
for _ = 1, 10 do
if PartyMenu.actionCursor == digIdx then break end
U.tap(game, PartyMenu.actionCursor < digIdx and "down" or "up")
U.wait(8)
end
result(PartyMenu.actionCursor == digIdx, "cursor on DIG")
U.tap(game, "a")
U.wait(30)
for _ = 1, 120 do
if Message.isOpen() and not Message.isTyping() then break end
U.wait(2)
end
local digLine = tostring(Message.currentPage() or "")
result(Message.isOpen() == true, "DIG printed a field message")
result(digLine:find("^ used") == nil, "the DIG line is not blank-named: " .. digLine)
result(digLine:find(monName, 1, true) == 1, "the DIG line names the mon: " .. digLine)
result(U.shot(game, DIR .. "/stitchmap_items_04_dig_named.png"), "dig message screenshot")
for _ = 1, 400 do
if Map.current ~= MT_MOON then break end
U.wait(4)
end
result(Map.current ~= MT_MOON, "DIG warped out of Mt Moon to " .. tostring(Map.current))
U.wait(60)
for _ = 1, 40 do
if not Message.isOpen() then break end
U.tap(game, "a")
U.wait(8)
end
Map.load(nil, game, MT_MOON, { x = 5, y = 35, facing = "down" })
place(5, 35, "down")
U.wait(120)
result(Map.current == MT_MOON, "back in Mt Moon 1F for the escape rope")
result(U.shot(game, DIR .. "/stitchmap_items_05_mt_moon.png"), "Mt Moon screenshot")
result(openBag(), "the bag opened inside Mt Moon")
result(toPocket("ITEMS"), "on the ITEMS pocket, got " .. tostring(BagMenu.currentPocket()))
local ropes = Bag.get(session.bag, ITEM_ESCAPE_ROPE)
result(toRow(ITEM_ESCAPE_ROPE), "cursor on the ESCAPE ROPE in Mt Moon")
result(pressUse(), "USE picked for the ESCAPE ROPE in Mt Moon")
for _ = 1, 300 do
if not BagMenu.isOpen() and Message.isOpen() and not Message.isTyping() then break end
U.wait(1)
end
-- pokefirered/src/item_use.c:159 SetUpItemUseOnFieldCallback
result(BagMenu.isOpen() == false,
"the bag faded out before the rope's line printed (mode=" .. tostring(BagMenu.mode) .. ")")
-- pokefirered/src/item_use.c:634 ItemUseOnFieldCB_EscapeRope
result(Message.isOpen() == true
and tostring(Message.currentPage() or ""):find("ESCAPE ROPE", 1, true) ~= nil,
"and it is gText_PlayerUsedVar2 on the field box ("
.. tostring(Message.currentPage()) .. ")")
result(Map.current == MT_MOON, "nothing warped while it was up")
-- pokefirered/src/item_use.c:642 Task_UseDigEscapeRopeOnField
for _ = 1, 40 do
if not Message.isOpen() then break end
U.tap(game, "a")
U.wait(8)
end
for _ = 1, 400 do
if Map.current ~= MT_MOON then break end
U.wait(4)
end
result(Map.current ~= MT_MOON, "the rope warped out of Mt Moon to " .. tostring(Map.current))
result(Bag.get(session.bag, ITEM_ESCAPE_ROPE) == ropes - 1, "the used rope was spent")
U.wait(90)
for _ = 1, 40 do
if not Message.isOpen() then break end
U.tap(game, "a")
U.wait(8)
end
U.wait(60)
result(U.shot(game, DIR .. "/stitchmap_items_06_rope_arrival.png"), "escape rope arrival screenshot")
finish()
end