CLOSES #1562, CLOSES #1804, CLOSES #1805, CLOSES #1810, CLOSES #1811, CLOSES #1814, CLOSES #1817, CLOSES #1818, CLOSES #1819, CLOSES #1821, CLOSES #1826, CLOSES #1827, CLOSES #1829, CLOSES #1833, CLOSES #1840, CLOSES #1842, CLOSES #1845, CLOSES #1846, CLOSES #1847, CLOSES #1848, CLOSES #1849, CLOSES #1853, CLOSES #1858, CLOSES #1862

This commit is contained in:
bryanthaboi
2026-08-27 05:09:10 -04:00
parent 5051cb902d
commit 48d8a4e922
68 changed files with 3979 additions and 328 deletions
@@ -0,0 +1,105 @@
-- A link switch runs SwitchPlayerMon on the switcher and SwitchEnemyMon on
-- the peer (core.asm:2418-2422, trainer_ai.asm:596-599) (#1562).
-- luajit tests/run_engine.lua
package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.modkit")
local Data = T.fixtures.fresh()
local Link = require("tests.modkit.link")
local Net = require("src.link.Net")
local Protocol = require("src.link.Protocol")
local LinkBattle = require("src.link.LinkBattle")
math.randomseed(4242)
local Input = Link.prepare(Data)
local gameA = Link.fakeGame(Data, { "FIXMON_A", "FIXMON_B" }, { name = "RED" })
local gameB = Link.fakeGame(Data, { "FIXMON_A", "FIXMON_B" }, { name = "BLUE" })
local netA, netB = Net.loopbackPair()
local packedA = Protocol.packParty(gameA.save.party)
local packedB = Protocol.packParty(gameB.save.party)
local battleA = LinkBattle.newHost(gameA, netA, {
myParty = packedA, theirParty = packedB,
theirName = "BLUE", seed = 987654321,
})
local battleB = LinkBattle.newGuest(gameB, netB, {
myParty = packedB, theirParty = packedA,
theirName = "RED", seed = 987654321,
})
local function watch(battle)
local seen = {}
local sayNext, sayNextAuto = battle.sayNext, battle.sayNextAuto
battle.sayNext = function(s, text) seen[#seen + 1] = text; return sayNext(s, text) end
battle.sayNextAuto = function(s, text, d)
seen[#seen + 1] = text
return sayNextAuto(s, text, d)
end
return seen
end
local seenA, seenB = watch(battleA), watch(battleB)
local function count(list, needle)
local n = 0
for _, text in ipairs(list) do
if text and text:find(needle, 1, true) then n = n + 1 end
end
return n
end
local function firstIndex(list, needle)
for i, text in ipairs(list) do
if text and text:find(needle, 1, true) then return i end
end
end
local resA, resB
battleA.onFinish = function(r) resA = r end
battleB.onFinish = function(r) resB = r end
gameA.stack:push(battleA)
gameB.stack:push(battleB)
local switched, retreatSeen = false, false
for _ = 1, 60000 do
if resA and resB then break end
Input.pressed = { a = true }
if not switched and battleA.phase == "menu" and battleA.playerParty[2] then
battleA:resolveSwitch(battleA.playerParty[2])
switched = true
end
for _, g in ipairs({ gameA, gameB }) do
local top = g.stack:top()
if top and top.forceSwitch and top.party then
for i, mon in ipairs(top.party) do
if mon.hp > 0 then top.index = i break end
end
end
g.stack:update(1 / 60)
end
if battleA.shrinkOut then retreatSeen = true end
end
T.check(switched, "the host got a menu phase to switch from")
T.eq(count(seenA, "Come back!"), 1,
"RetreatMon prints once, for the voluntary switch only")
T.check(retreatSeen, "AnimateRetreatingPlayerMon runs on the switcher")
T.eq(count(seenB, "drew"), 1, "the peer prints AIBattleWithdrawText once")
local withdrawA = firstIndex(seenA, "Come back!")
local sendA = firstIndex(seenA, "Go! ") or firstIndex(seenA, "Do it! ")
or firstIndex(seenA, "Get'm! ")
T.check(sendA ~= nil and withdrawA < sendA, "the recall line comes before the send-out")
local withdrawB = firstIndex(seenB, "drew")
local sendB = firstIndex(seenB, "sent\nout")
T.check(sendB ~= nil and withdrawB < sendB, "and so does the peer's withdraw line")
T.check(battleA.localHashes ~= nil and battleB.localHashes ~= nil,
"both sides still record per-turn hashes")
local mismatch
for turn, hash in pairs(battleA.localHashes) do
local other = battleB.localHashes[turn]
if other and other ~= hash then mismatch = mismatch or turn end
end
T.check(mismatch == nil, "the added lines leave the lockstep state hash alone")
T.finish("link switch prints the recall lines (#1562)")