mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 00:10:56 +02:00
155 lines
5.6 KiB
Lua
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
|