Files
gen1recomp/tests/drivers/g3trade_relay_trade.lua
2026-09-24 05:17:32 -04:00

229 lines
8.5 KiB
Lua

local U = require("tests.drivers.util")
local SEAT = tonumber(os.getenv("G3TRADE_SEAT") or "0") or 0
local ROOMFILE = os.getenv("G3TRADE_ROOMFILE")
or ((os.getenv("TMPDIR") or "/tmp"):gsub("/+$", "") .. "/g3trade_room.txt")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or ".bazinga/BSA/09-23-26-03-gen3online/shots/gen3trade"
local TAG = "g3trade_seat" .. SEAT
local TRADE_CENTER = "FR_TRADE_CENTER"
-- pokefirered/include/constants/flags.h:1375
local FLAG_SYS_POKEDEX_GET = 0x829
local MACHOKE, MACHAMP, BULBASAUR, SQUIRTLE, PIKACHU = 67, 68, 1, 7, 25
local failures = 0
local function result(ok, label)
print((ok and "PASS " or "FAIL ") .. TAG .. " " .. label)
if not ok then failures = failures + 1 end
return ok
end
local function now()
return love.timer.getTime()
end
return function(game)
print("PASS " .. TAG .. " driver_started")
local Link, Client
local function finish()
if Link then pcall(Link.closeLink, "driver_done") end
if Client then pcall(Client.disconnect) end
if failures == 0 then
print("PASS " .. TAG .. " relay_trade")
love.event.quit(0)
else
print("FAIL " .. TAG .. " relay_trade failures=" .. failures)
love.event.quit(1)
end
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 = SEAT == 0 and "RED" or "LEAF" })
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 LT = require("src.core.game3.link.trade")
local TradeScene = require("src.core.game3.trade_scene")
local Menu = require("src.ui.game3.link_trade_menu")
local Game3Link = require("src.link.Game3Link")
local RelayTransport = require("src.core.game3.link.relay_transport")
local ArenaData = require("src.online.ArenaData")
Link = require("src.core.game3.link")
Client = require("src.online.Client")
local session = Runtime.getSession()
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
local g3 = Runtime._game or game
Flags.setFlag(Space.store, Space.vm and Space.vm.ctx, FLAG_SYS_POKEDEX_GET, true)
session.name = SEAT == 0 and "RED" or "LEAF"
session.trainerId = SEAT == 0 and 0x1234 or 0x2222
session.party = {}
if SEAT == 0 then
Party.giveMon(session, MACHOKE, 30)
Party.giveMon(session, BULBASAUR, 10)
else
Party.giveMon(session, SQUIRTLE, 11)
Party.giveMon(session, PIKACHU, 14)
end
local expectFirst = SEAT == 0 and SQUIRTLE or MACHAMP
local saves, savedLead = 0, nil
local realSave = g3.saveGame
g3.saveGame = function(self, ...)
saves = saves + 1
savedLead = session.party[1] and session.party[1].species
if realSave then return realSave(self, ...) end
end
local function waitUntil(pred, seconds)
local deadline = now() + (seconds or 10)
while not pred() do
if now() > deadline then return false end
U.wait(1)
end
return true
end
local profile, why = ArenaData.liveProfile3(g3, "g3_link")
if not result(profile ~= nil, "the running game has a live Gen 3 profile (" .. tostring(why) .. ")") then
return finish()
end
local okC, errC = Client.connect({ name = session.name, profiles = { profile },
presence = { where = "game", status = "busy" } })
result(okC, "Client.connect to " .. tostring(os.getenv("POKEPORT_RELAY_ADDR")) .. " " .. tostring(errC))
if not result(waitUntil(function() return Client.state() == "online" end, 10), "online on the relay") then
return finish()
end
if SEAT == 0 then
os.remove(ROOMFILE)
Client.createRoom({ intent = "trade", profile = profile, seats = 2 })
if not result(waitUntil(function() return Client.room() ~= nil end, 10), "seat 0 opened a trade room") then
return finish()
end
local fh = io.open(ROOMFILE, "w")
if fh then
fh:write(tostring(Client.room().room))
fh:close()
end
else
local roomId
waitUntil(function()
local fh = io.open(ROOMFILE, "r")
if fh then
roomId = fh:read("*l")
fh:close()
end
return roomId ~= nil and roomId ~= ""
end, 15)
if not result(roomId ~= nil, "seat 1 found the room id") then return finish() end
Client.joinRoom(roomId, "player", profile)
end
local paired = waitUntil(function()
local room = Client.room()
return room and Client.seat() ~= nil and #(room.players or {}) == 2 and room.match ~= nil
end, 15)
if not result(paired, "both seats are in the room and the match started") then return finish() end
result(Client.seat() == SEAT, "this process holds seat " .. SEAT)
local transport = RelayTransport.new(Client.roomSession())
local live = Game3Link.attach(transport, {
seat = Client.seat(), seats = 2, game = g3, linkType = Game3Link.LINKTYPE.TRADE,
})
Link.attach(live)
if not result(waitUntil(function() return live:isReady() end, 10), "the Game3Link handshake is full") then
return finish()
end
-- pokefirered/data/maps/TradeCenter/map.json:1 TradeCenter_EventScript_Chair0 / Chair1
Map.load(nil, g3, TRADE_CENTER, { x = SEAT == 0 and 4 or 7, y = 5, facing = SEAT == 0 and "right" or "left" })
Player.cellX, Player.cellY = SEAT == 0 and 4 or 7, 5
Player.px, Player.py = Player.cellX * 16, Player.cellY * 16
Player.targetX, Player.targetY = Player.cellX, Player.cellY
U.wait(60)
-- pokefirered/src/cable_club.c:958
LT.startMenu()
if not result(waitUntil(function() return Menu.isOpen() and Menu.cb == "main" and Menu.fade == 0 end, 15),
"the trade menu is up with the other party on it") then
return finish()
end
result(#LT.peerParty == 2, "the other seat's two mons arrived unpacked")
U.wait(10)
U.still(game, DIR .. "/" .. TAG .. "_trade_menu.png")
U.tap(game, "a")
U.wait(4)
U.tap(game, "down")
U.wait(4)
U.tap(game, "a")
if not result(waitUntil(function() return Menu.cb == "confirm_prompt" and Menu.confirming end, 20),
"both offered their lead and IS THIS TRADE OKAY? came up") then
return finish()
end
U.wait(4)
U.still(game, DIR .. "/" .. TAG .. "_confirm.png")
if SEAT == 1 then
local realConfirm, holdUntil = LT.tryConfirm, nil
LT.tryConfirm = function(...)
holdUntil = holdUntil or (now() + 3)
if now() < holdUntil then return false end
LT.tryConfirm = realConfirm
return realConfirm(...)
end
end
U.tap(game, "a")
result(waitUntil(function() return LT.state == "commit_wait" or LT._committed end, 10),
"the confirm went to the relay")
result(saves == 0, "nothing was written before trade_commit")
print("INFO " .. TAG .. " digest=" .. tostring(LT._digest))
if SEAT == 0 then
U.wait(10)
if result(LT.state == "commit_wait", "seat 0 waits on Communication standby for the other confirm") then
U.still(game, DIR .. "/" .. TAG .. "_commit_wait.png")
end
end
if not result(waitUntil(function() return TradeScene.isOpen() end, 15),
"trade_commit arrived and the trade scene started") then
return finish()
end
if result(waitUntil(function() return TradeScene.phase() == "bye_bye" end, 15),
"the scene put the outgoing mon on screen") then
U.wait(10)
U.still(game, DIR .. "/" .. TAG .. "_scene.png")
end
local done = waitUntil(function()
if not TradeScene.isOpen() and LT.completed >= 1 then return true end
local Evo = package.loaded["src.ui.game3.evolution_scene"]
local Message = package.loaded["src.ui.game3.message"]
if (Evo and Evo.isOpen and Evo.isOpen()) or (Message and Message.isOpen and Message.isOpen()) then
table.insert(game.input.pressQueue, "a")
end
return false
end, 25)
if not result(done, "the scene, evolution and save ran to the end") then return finish() end
result(saves == 1, "the save was written exactly once (" .. saves .. ")")
result(savedLead == expectFirst, "the save holds the received mon (" .. tostring(savedLead) .. ")")
result(session.party[1] and session.party[1].species == expectFirst,
"the party lead is now species " .. tostring(expectFirst))
result(LT._saveFailed == false, "the post-trade save reported success")
if result(waitUntil(function() return Menu.isOpen() and Menu.cb == "main" and Menu.fade == 0 end, 15),
"the Trade Center returned to the trade menu with the new party") then
U.wait(10)
U.still(game, DIR .. "/" .. TAG .. "_after_save_party.png")
end
return finish()
end