mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-09-26 13:33:27 -04:00
242 lines
8.5 KiB
Lua
242 lines
8.5 KiB
Lua
local U = require("tests.drivers.util")
|
|
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_fame_unlock"
|
|
|
|
local GYM = "FR_PEWTER_CITY_GYM"
|
|
-- pokefirered/data/maps/PewterCity_Gym/map.json:20 BROCK is the first object event
|
|
local BROCK_LOCAL_ID = 1
|
|
-- pokefirered/include/constants/flags.h:1364
|
|
local FLAG_BADGE01_GET = 0x820
|
|
-- pokefirered/include/constants/opponents.h:420
|
|
local TRAINER_LEADER_BROCK = 414
|
|
-- pokefirered/include/constants/moves.h:61
|
|
local MOVE_SURF = 57
|
|
-- pokefirered/include/constants/items.h:435
|
|
local ITEM_FAME_CHECKER = 363
|
|
|
|
return function(game)
|
|
local fails = 0
|
|
local function result(ok, label)
|
|
print((ok and "PASS " or "FAIL ") .. label)
|
|
if not ok then fails = fails + 1 end
|
|
return ok
|
|
end
|
|
local function finish()
|
|
if fails == 0 then
|
|
print("PASS fame_unlock")
|
|
love.event.quit(0)
|
|
else
|
|
print("FAIL fame_unlock failures=" .. fails)
|
|
love.event.quit(1)
|
|
end
|
|
end
|
|
|
|
print("PASS driver_started")
|
|
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 Space = require("src.core.game3.scripting.space")
|
|
local Flags = require("src.core.game3.scripting.flags")
|
|
local Player = require("src.core.game3.player")
|
|
local Party = require("src.core.game3.party")
|
|
local Objects = require("src.core.game3.objects")
|
|
local Battle = require("src.core.game3.battle")
|
|
local Anim = require("src.core.game3.battle.anim")
|
|
local Ui = require("src.core.game3.battle.ui")
|
|
local Message = require("src.ui.game3.message")
|
|
local FameChecker = require("src.core.game3.fame_checker")
|
|
|
|
local PERSON, PICK = FameChecker.PERSON, FameChecker.PICKSTATE
|
|
|
|
local session = Runtime.getSession()
|
|
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
|
|
|
|
local function ctx() return Space.vm and Space.vm.ctx end
|
|
local function getFlag(id)
|
|
return Flags.getFlag(Space.store, ctx(), id) and true or false
|
|
end
|
|
|
|
session.party = {}
|
|
Party.giveMon(session, 9, 60)
|
|
Party.giveMon(session, 3, 60)
|
|
for _, mon in ipairs(session.party) do
|
|
mon.moves = { MOVE_SURF, 0, 0, 0 }
|
|
mon.pp = { 30, 0, 0, 0 }
|
|
end
|
|
|
|
local function placeAt(mapId, x, y, facing)
|
|
Map.load(nil, game, mapId, { x = x, y = y, facing = facing or "up" })
|
|
if game.session then
|
|
game.session.x, game.session.y, game.session.facing = x, y, facing or "up"
|
|
end
|
|
Player.cellX, Player.cellY = x, y
|
|
Player.px, Player.py = x * 16, y * 16
|
|
Player.targetX, Player.targetY = x, y
|
|
Player.facing = facing or "up"
|
|
U.wait(90)
|
|
end
|
|
|
|
result(FameChecker.pickState(session, PERSON.BROCK) == PICK.NO_DRAW,
|
|
"BROCK is not drawn in the Fame Checker on a new game")
|
|
result(FameChecker.pickState(session, PERSON.OAK) == PICK.COLORED,
|
|
"OAK starts coloured, as ResetFameChecker leaves him")
|
|
result(FameChecker.flavorTextFlags(session, PERSON.BROCK) == 0,
|
|
"BROCK has no flavour text on a new game")
|
|
|
|
placeAt(GYM, 5, 12, "up")
|
|
local brock = Objects.find(BROCK_LOCAL_ID)
|
|
if not result(brock ~= nil, "BROCK is on the Pewter Gym map") then return finish() end
|
|
print(string.format("[driver] BROCK at (%d,%d)", brock.cellX, brock.cellY))
|
|
|
|
placeAt(GYM, brock.cellX, brock.cellY + 1, "up")
|
|
U.shot(game, DIR .. "/fame_unlock_01_facing_brock.png")
|
|
|
|
local lastTap = 0
|
|
local f = 0
|
|
local function pumpText()
|
|
f = f + 1
|
|
if Ui and Ui.dialogPending and Ui.dialogPending() and not (Anim and Anim.busy and Anim.busy())
|
|
and f - lastTap >= 14 then
|
|
lastTap = f
|
|
U.tap(game, "a")
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
for _ = 1, 1200 do
|
|
if Battle.isActive() then break end
|
|
if Message and Message.isOpen and Message.isOpen() then
|
|
U.tap(game, "a")
|
|
U.wait(6)
|
|
else
|
|
U.wait(2)
|
|
end
|
|
end
|
|
|
|
-- pokefirered/data/maps/PewterCity_Gym/scripts.inc:5
|
|
result(FameChecker.pickState(session, PERSON.BROCK) == PICK.COLORED,
|
|
"talking to BROCK ran famechecker FCPICKSTATE_COLORED, pickState="
|
|
.. tostring(FameChecker.pickState(session, PERSON.BROCK)))
|
|
result(FameChecker.flavorTextFlags(session, PERSON.BROCK) == 0,
|
|
"no flavour text yet, only the picture is unlocked")
|
|
|
|
if not result(Battle.isActive(), "Brock's trainerbattle_single started") then
|
|
U.shot(game, DIR .. "/fame_unlock_02_no_battle.png")
|
|
return finish()
|
|
end
|
|
local st = Battle.getState()
|
|
result(st ~= nil and st.trainerId == TRAINER_LEADER_BROCK,
|
|
"fighting TRAINER_LEADER_BROCK (" .. tostring(st and st.trainerId) .. ")")
|
|
|
|
local function atCommand()
|
|
return Battle.isActive() and Battle._phase == "command" and Ui._mode == "menu"
|
|
end
|
|
|
|
local turns, spun = 0, 0
|
|
for _ = 1, 30000 do
|
|
if not Battle.isActive() then break end
|
|
spun = spun + 1
|
|
if spun % 900 == 0 then
|
|
print(string.format("[driver] battle wait phase=%s mode=%s turns=%d",
|
|
tostring(Battle._phase), tostring(Ui._mode), turns))
|
|
end
|
|
if atCommand() then
|
|
turns = turns + 1
|
|
U.tap(game, "a")
|
|
U.wait(14)
|
|
U.tap(game, "a")
|
|
U.wait(14)
|
|
elseif Ui.choiceActive and Ui.choiceActive() then
|
|
-- pokefirered/src/battle_message.c:371 sText_EnemyAboutToSwitchPkmn
|
|
U.tap(game, "b")
|
|
U.wait(14)
|
|
elseif Message and Message.isOpen and Message.isOpen() and not Anim.busy() then
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
elseif not pumpText() then
|
|
U.wait(1)
|
|
end
|
|
end
|
|
print("[driver] battle turns issued: " .. tostring(turns))
|
|
result(not Battle.isActive(), "the gym battle ended")
|
|
|
|
local textShot = false
|
|
for _ = 1, 3000 do
|
|
local running = Space.vm and Space.vm:isRunning()
|
|
local open = Message and Message.isOpen and Message.isOpen()
|
|
if not running and not open then break end
|
|
if open and not textShot and getFlag(FLAG_BADGE01_GET)
|
|
and FameChecker.hasFlavorText(session, PERSON.BROCK, 1) then
|
|
textShot = true
|
|
U.wait(30)
|
|
U.shot(game, DIR .. "/fame_unlock_02_brock_unlocked.png")
|
|
end
|
|
if open then U.tap(game, "a") end
|
|
U.wait(6)
|
|
end
|
|
U.wait(60)
|
|
result(textShot, "shot the post-battle page that carries famechecker FAMECHECKER_BROCK, 1")
|
|
|
|
if not result(getFlag(FLAG_BADGE01_GET), "the BOULDERBADGE branch ran, so BROCK was beaten") then
|
|
U.shot(game, DIR .. "/fame_unlock_03_lost.png")
|
|
return finish()
|
|
end
|
|
|
|
-- pokefirered/data/maps/PewterCity_Gym/scripts.inc:13
|
|
result(FameChecker.hasFlavorText(session, PERSON.BROCK, 1),
|
|
"famechecker FAMECHECKER_BROCK, 1 unlocked flavour text slot 1")
|
|
result(FameChecker.flavorTextFlags(session, PERSON.BROCK) == 2,
|
|
"only slot 1 is unlocked, flags="
|
|
.. tostring(FameChecker.flavorTextFlags(session, PERSON.BROCK)))
|
|
-- pokefirered/src/fame_checker.c:1238
|
|
result(FameChecker.pickState(session, PERSON.BROCK) == PICK.COLORED,
|
|
"the SILHOUETTE write inside the special did not demote a coloured BROCK")
|
|
result(FameChecker.hasUnlockedAllFlavorTexts(session, PERSON.BROCK) == false,
|
|
"BROCK is not fully unlocked from one gym win")
|
|
|
|
local list = FameChecker.unlockedPersons(session)
|
|
local names = {}
|
|
for i, p in ipairs(list) do names[i] = tostring(p) end
|
|
print("[driver] unlocked persons: " .. table.concat(names, ","))
|
|
result(#list == 2 and list[1] == PERSON.OAK and list[2] == PERSON.BROCK,
|
|
"the Fame Checker list is OAK then BROCK")
|
|
|
|
-- pokefirered/src/item_use.c:680 FieldUseFunc_FameChecker
|
|
local Bag = require("src.core.game3.bag")
|
|
local ItemUse = require("src.core.game3.item_use")
|
|
local Ui = require("src.ui.game3.fame_checker")
|
|
session.bag = session.bag or Bag.new()
|
|
Bag.add(session.bag, ITEM_FAME_CHECKER, 1)
|
|
local usedOk, usedKind = ItemUse.useField(session, session.bag, ITEM_FAME_CHECKER)
|
|
U.wait(30)
|
|
if not result(usedOk == true and usedKind == "fame_checker" and Ui.isOpen(),
|
|
"the FAME CHECKER opened the screen, kind=" .. tostring(usedKind)) then
|
|
return finish()
|
|
end
|
|
U.tap(game, "down")
|
|
U.wait(20)
|
|
result(Ui.selectedPerson() == PERSON.BROCK, "the cursor is on BROCK's entry")
|
|
local icons = Ui.icons(PERSON.BROCK)
|
|
result(icons[1].unlocked and not icons[0].unlocked,
|
|
"BROCK's entry shows panel 1 unlocked and the rest locked")
|
|
U.tap(game, "start")
|
|
U.wait(30)
|
|
result(Ui.pickMode, "START shows BROCK's coloured picture")
|
|
U.shot(game, DIR .. "/fame_unlock_03_brock_entry.png")
|
|
U.tap(game, "b")
|
|
U.wait(20)
|
|
U.tap(game, "select")
|
|
U.wait(30)
|
|
result(not Ui.isOpen(), "SELECT closed the Fame Checker")
|
|
|
|
finish()
|
|
end
|