Files
gen1recomp/tests/drivers/em_first_battle.lua
T
bryanthaboi 690f0cd9a1 TOUCHDOWN
2026-09-27 16:07:31 -04:00

234 lines
8.7 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/em_first_battle"
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
end
local function finish()
print(string.format("[driver] em_first_battle: %d failure(s)", fails))
love.event.quit(fails == 0 and 0 or 1)
U.wait(10)
end
for _ = 1, 900 do
if game.phase == "boot" and game.boot then break end
U.wait(1)
end
game:_handleBootAction({ action = "new_game", name = "NICK", gender = 0 })
U.wait(240)
local Runtime = require("src.core.game3.runtime")
local Party = require("src.core.game3.party")
local BattleBridge = require("src.core.game3.battle_bridge")
local Battle = require("src.core.game3.battle")
local Ui = require("src.core.game3.battle.ui")
local ExpSeq = require("src.core.game3.battle.exp_seq")
local BattleTransition = require("src.core.game3.battle_transition")
local Audio = require("src.core.game3.audio")
local Map = require("src.core.game3.map")
local Field = require("src.core.game3.field")
local C = require("src.core.game3.constants").of("emerald")
local session = Runtime.getSession()
result(session ~= nil, "field session exists")
if not session then return finish() end
local ok, err = pcall(function() Map.load(nil, game, "EM_ROUTE101", { x = 7, y = 13, facing = "down" }) end)
result(ok, "Route 101 loads " .. tostring(err or ""))
U.wait(40)
session.party = {}
-- pokeemerald/src/battle_setup.c:923
Party.giveMon(session, C.species.byName.SPECIES_TREECKO, 5, "TREECKO")
local mon = session.party[1]
result(mon ~= nil and mon.level == 5, "starter Treecko lv5 in the party")
if not mon then return finish() end
local exp0 = tonumber(mon.exp) or 0
local moveNames = {}
for i, m in ipairs(mon.moves or {}) do moveNames[i] = C:name("moves", m, "MOVE_") or tostring(m) end
print("[driver] starter moves " .. table.concat(moveNames, ","))
local outcome
local started, serr = BattleBridge.startFirstBattle(Runtime._mod, game, {
done = function(r) outcome = r end,
})
result(started == true, "first battle started " .. tostring(serr or ""))
if not started then return finish() end
local tid = BattleTransition._transitionId
result(tid == C.battle.byName.B_TRANSITION_BLUR, "transition is B_TRANSITION_BLUR (" .. tostring(tid) .. ")")
local song = Audio._currentSong and Audio._currentSong.id
result(song == C.songs.byName.MUS_VS_WILD, "battle music MUS_VS_WILD (" .. tostring(song) .. ")")
for _ = 1, 3000 do
if Battle.isActive() then break end
U.wait(1)
end
result(Battle.isActive(), "battle active after the transition")
local st = Battle.getState()
if not st then return finish() end
local foe = st.enemy and st.enemy.mon
result(foe and foe.species == C.species.byName.SPECIES_ZIGZAGOON and foe.level == 2, "foe is Zigzagoon lv2")
result(st.wild and st.kinds and st.kinds.firstBattle == "birch", "battle kind firstBattle=birch")
result(st.aiFlags == 0x80000000, "AI flags AI_SCRIPT_FIRST_BATTLE (" .. string.format("0x%X", st.aiFlags or 0) .. ")")
result(not st.firstBattle, "Oak first-battle path stays off")
local lastTap, f = 0, 0
local function pump_text()
f = f + 1
if Ui.dialogPending and Ui.dialogPending() and f - lastTap >= 14 then
lastTap = f
U.tap(game, "a")
return true
end
return false
end
local function at_command()
return Battle.isActive() and Battle._phase == "command" and Ui._mode == "menu"
end
local function wait_command(limit)
for _ = 1, limit or 6000 do
if at_command() or not Battle.isActive() then break end
if not pump_text() then U.wait(1) end
end
return at_command()
end
local function logged(pattern)
for _, t in ipairs(Ui.log()) do
if type(t) == "string" and t:find(pattern) then return true end
end
return false
end
local introShot = false
for _ = 1, 600 do
if Ui.dialogPending and Ui.dialogPending() then
U.wait(20)
introShot = U.still(game, DIR .. "/01_intro_wild_zigzagoon.png")
break
end
U.wait(1)
end
result(introShot, "intro shot")
result(logged("ZIGZAGOON"), "intro text names Wild ZIGZAGOON")
result(wait_command(), "reached the action menu")
U.wait(20)
result(U.still(game, DIR .. "/02_action_menu.png"), "action menu shot")
U.tap(game, "right")
U.wait(4)
U.tap(game, "down")
U.wait(4)
U.tap(game, "a")
U.wait(30)
result(logged("Don't leave me"), "RUN is refused with STRINGID_DONTLEAVEBIRCH")
result(U.still(game, DIR .. "/03_dont_leave_birch.png"), "run refused shot")
result(wait_command(), "back at the action menu")
U.tap(game, "up")
U.wait(4)
U.tap(game, "left")
U.wait(4)
local moveShot, faintShot, expShot = false, false, false
local turns = 0
local expSeen = false
for _ = 1, 20 do
if not Battle.isActive() then break end
if not wait_command() then break end
turns = turns + 1
U.tap(game, "a")
U.wait(20)
if not moveShot and Ui._mode == "moves" then
moveShot = U.still(game, DIR .. "/04_move_select.png")
end
U.tap(game, "a")
for _ = 1, 4000 do
if at_command() or not Battle.isActive() then break end
local e = Battle.getState() and Battle.getState().enemy
if not faintShot and e and e.mon and (tonumber(e.mon.hp) or 1) <= 0 then
U.wait(24)
faintShot = U.still(game, DIR .. "/05_zigzagoon_faints.png")
end
if not expShot and ExpSeq.busy() then
expSeen = true
U.wait(30)
expShot = U.still(game, DIR .. "/06_exp_gain.png")
end
if Battle._phase == "awarding" then expSeen = true end
if not pump_text() then U.wait(1) end
end
end
print("[driver] turns " .. turns .. " outcome " .. tostring(outcome) .. " endReason " .. tostring(st.endReason))
result(moveShot, "move select shot")
result(faintShot, "faint shot")
result(expSeen, "exp award sequence ran")
result(expShot, "exp gain shot")
result(logged("gained"), "STRINGID_PKMNGAINEDEXP printed")
for _ = 1, 3000 do
if outcome ~= nil then break end
if not pump_text() then U.wait(1) end
end
result(outcome == "win", "battle outcome win (" .. tostring(outcome) .. ")")
local exp1 = tonumber(session.party[1] and session.party[1].exp) or 0
result(exp1 > exp0, string.format("starter exp %d -> %d", exp0, exp1))
for _ = 1, 300 do
if not Field.locked then break end
U.wait(1)
end
U.wait(60)
result(Map.current == "EM_ROUTE101", "back on the field at Route 101 (" .. tostring(Map.current) .. ")")
result(not Battle.isActive(), "battle closed")
result(U.still(game, DIR .. "/07_back_on_field.png"), "field shot")
local Trainers = require("src.core.game3.scripting.trainers")
local Prize = require("src.core.game3.battle.prize")
local calvin = C.trainers.byName.TRAINER_CALVIN_1
local foeRow = Trainers.foeFromId(calvin)
result(foeRow ~= nil, "Calvin trainer row")
if not foeRow then return finish() end
session.party = {}
Party.giveMon(session, C.species.byName.SPECIES_GROVYLE, 30, "GROVYLE")
session.money = 1000
local want = Prize.calcRse(calvin, {})
outcome = nil
Ui._log = {}
local ok2, err2 = BattleBridge.start(Runtime._mod, game, foeRow, {
wild = false, trainerId = calvin, done = function(r) outcome = r end,
})
result(ok2 == true, "Calvin battle started " .. tostring(err2 or ""))
for _ = 1, 3000 do
if Battle.isActive() then break end
U.wait(1)
end
local tsong = Audio._currentSong and Audio._currentSong.id
result(tsong == C.songs.byName.MUS_VS_TRAINER, "trainer battle music MUS_VS_TRAINER (" .. tostring(tsong) .. ")")
local victoryHeard = false
for _ = 1, 20 do
if not Battle.isActive() then break end
if not wait_command() then break end
U.tap(game, "a")
U.wait(20)
U.tap(game, "a")
for _ = 1, 4000 do
if at_command() or not Battle.isActive() then break end
local s = Audio._currentSong and Audio._currentSong.id
if s == C.songs.byName.MUS_VICTORY_TRAINER then victoryHeard = true end
if not pump_text() then U.wait(1) end
end
end
for _ = 1, 3000 do
if outcome ~= nil then break end
if not pump_text() then U.wait(1) end
end
result(outcome == "win", "Calvin battle won (" .. tostring(outcome) .. ")")
result(victoryHeard, "MUS_VICTORY_TRAINER played on the win")
result(session.money == 1000 + want, string.format("prize money %d (+%d from gTrainerMoneyTable)", session.money, want))
result(logged("got %$" .. want) or logged(tostring(want)), "STRINGID_PLAYERGOTMONEY shows " .. want)
U.wait(60)
result(U.still(game, DIR .. "/08_after_calvin.png"), "after trainer battle shot")
return finish()
end