Files
bryanthaboi ae6cac89e1 G2 support
2026-08-11 11:53:30 -04:00

155 lines
5.6 KiB
Lua

-- Assertion driver: the phone in the RUNNING game. It PASSes or it fails
-- loudly; there is nothing to eyeball.
--
-- POKEPORT_IDENTITY=gold-dev POKEPORT_GAME=gold \
-- POKEPORT_DRIVER=tests/drivers/gold_phone_call.lua \
-- perl -e 'alarm 300; exec @ARGV' \
-- python3 -c "import pty; pty.spawn(['love','.'])"
--
-- Three things the ROM-free suites cannot see from outside a booted world:
-- * StartMap's `farcall InitCallReceiveDelay`: a genuine World:setMap has
-- to arm the receive countdown off the game clock.
-- * CheckTimeEvents' CheckPhoneCall arm: with a contact in the book and
-- the countdown run down, a random call has to RING in the overworld --
-- the caller-ID page, the extracted bank $41 chat, the Click! -- and a
-- caller script's .WantsBattle has to arm its _READY_FOR_REMATCH event.
-- * The Pokegear's CALL entry: the callee's SCRIPT1 runs through the same
-- VM while the card keeps the screen.
local U = require("tests.drivers.util")
return function(game)
local fails = 0
local function ok(cond, msg)
if cond then print("[phone] ok " .. msg)
else fails = fails + 1 print("[phone] FAIL " .. msg) end
return cond
end
local function tap(button, frames)
game.input.pressQueue[#game.input.pressQueue + 1] = button
game.input.state[button] = true
U.wait(2)
game.input.state[button] = false
U.wait(frames or 4)
end
-- TextBox.paginate emits a page as a LIST of wrapped lines; flatten the
-- whole open box to one searchable string.
local function boxText(top)
if not (top and top.pages) then return nil end
local out = {}
for _, page in ipairs(top.pages) do
if type(page) == "table" then
out[#out + 1] = table.concat(page, "\n")
else
out[#out + 1] = tostring(page)
end
end
return table.concat(out, "|")
end
U.wait(45)
local w = game.world
assert(w and w.map, "gold world did not boot")
local save = game.save
local Phone = require("src.core.gen2.Phone")
-- The phone reads its clock through World:stepContext's game.clock seam, so
-- the driver owns the minutes the countdown walks.
game.clock = { day = 0, hour = 9, minute = 0 }
-- ------------------------------------------- StartMap arms the countdown
save.phone = nil
assert(w:setMap("ROUTE_31", 8, 6, "down"), "setMap failed for ROUTE_31")
U.wait(3)
ok(save.phone and save.phone.delayMins == 20,
"a map load arms the receive countdown at twenty minutes")
ok(save.phone and save.phone.timeCycles == 0, "with the cycle counter zeroed")
ok(save.phone and save.phone.delayStart
and save.phone.delayStart.minute == 0, "stamped off the game clock")
-- CheckStandingOnEntrance must not refuse, so stand on a plain floor cell.
local cx, cy = w.player.cellX, w.player.cellY
for y = 2, 16 do
for x = 2, 16 do
if w.map:cellCollision(x, y) == 0x00 then cx, cy = x, y end
end
end
assert(w:setMap("ROUTE_31", cx, cy, "down"), "no floor cell on ROUTE_31")
U.wait(3)
-- ------------------------------------------- a random call rings
-- Joey (contact 15) lives on ROUTE_30, so he is available from ROUTE_31,
-- and his caller script's rematch gate is ENGINE_FLYPOINT_GOLDENROD
-- (checkflag 69 in the extracted body).
Phone.addContact(save, 15)
w:setEngineFlag(69, true)
local calls, sawRing, sawClick, sawReset = 0, false, false, false
for _ = 1, 40 do
if w.events:get(628) then break end
game.clock.minute = game.clock.minute + 20
for _ = 1, 20 do
U.wait(1)
if w:busy() then break end
end
if w:busy() then
calls = calls + 1
for _ = 1, 300 do
local textAll = boxText(game.stack and game.stack:top())
if textAll then
if textAll:find("RING!", 1, true) then sawRing = true end
if textAll:find("Click!", 1, true) then sawClick = true end
end
if not w:busy() then break end
tap("a", 2)
end
if save.phone.timeCycles == 0 and save.phone.delayMins == 20 then
sawReset = true
end
end
end
ok(calls > 0, ("a random incoming call rang in the overworld (%d calls)")
:format(calls))
ok(sawRing, "opening on the RING! caller-ID page")
ok(sawClick, "and hanging up on the Click!")
ok(w.events:get(628),
"a caller script armed EVENT_JOEY_READY_FOR_REMATCH (628)")
ok(sawReset, "and the hang-up restarted the receive countdown")
-- ------------------------------------------- the Pokegear calls out
w:setEngineFlag(2, true) -- ENGINE_PHONE_CARD
w:setEngineFlag(4, true) -- ENGINE_POKEGEAR
game:openStartMenuItem("pokegear")
U.wait(3)
local gear = game.stack:top()
assert(gear and gear.cards, "the Pokegear did not open")
gear.mode = "card"
for index, card in ipairs(gear.cards) do
if card.id == "phone" then gear.cardIndex = index end
end
U.wait(2)
tap("a", 3) -- CALL/DELETE/CANCEL submenu on Joey's slot
tap("a", 3) -- CALL
local spoke = false
for _ = 1, 200 do
local top = game.stack and game.stack:top()
local textAll = boxText(top)
if textAll and textAll:find("JOEY", 1, true) then spoke = true end
if not (w.vm and w.vm:running()) and not (top and top.pages) then break end
tap("a", 2)
end
ok(gear.call ~= nil, "the card holds the placed call")
ok(gear.call and gear.call.script == "JoeyPhoneCalleeScript",
"to Joey's own SCRIPT1")
ok(gear.call and gear.call.ranScript == true,
"which ran through the overworld VM")
ok(spoke, "and he actually talked")
tap("a", 3) -- hang up
ok(gear.call == nil, "A hangs the call up")
print(fails == 0 and "PASS gold_phone_call"
or ("FAIL gold_phone_call (%d)"):format(fails))
love.event.quit(fails == 0 and 0 or 1)
end