mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
138 lines
4.7 KiB
Lua
138 lines
4.7 KiB
Lua
-- The starter choice at Elm's lab, which is the first `pokepic` a player meets.
|
|
--
|
|
-- maps/ElmsLab.asm, ElmsLabPokeBallScript (one per ball, Cyndaquil's at (6,3)):
|
|
--
|
|
-- turnobject ELMSLAB_ELM, DOWN
|
|
-- reanchormap
|
|
-- pokepic CYNDAQUIL
|
|
-- cry CYNDAQUIL
|
|
-- waitbutton
|
|
-- closepokepic
|
|
-- opentext
|
|
-- writetext ElmsLabText_ChooseCyndaquil
|
|
-- yesorno
|
|
--
|
|
-- The pic goes up with NO text window under it, so nothing else in that run of
|
|
-- commands consumes a button press: `waitbutton` (Script_waitbutton ->
|
|
-- WaitButton, home/text.asm) is the ONLY thing holding the frame, and it is
|
|
-- what gives the player time to look at the mon before the yes/no. The port
|
|
-- used to treat every `waitbutton` as already-paid-for by the text box that
|
|
-- usually precedes it, so pokepic / closepokepic ran inside one VM resume and
|
|
-- the pic was created and destroyed without a single frame drawing it (#911).
|
|
--
|
|
-- This driver stands in front of the Cyndaquil ball, presses A, and counts the
|
|
-- frames where World.pokePic is actually up. It shoots the popup, so a human
|
|
-- can see the pic and not just a number.
|
|
--
|
|
-- POKEPORT_GAME=gold POKEPORT_DRIVER=tests/drivers/gold_starter_pic.lua \
|
|
-- POKEPORT_SHOT_DIR=/tmp/gold-starter \
|
|
-- perl -e 'alarm 280; exec @ARGV' \
|
|
-- python3 -c "import pty; pty.spawn(['love','.'])"
|
|
local SHOT_DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/gold-starter"
|
|
|
|
-- main.lua's love.visible / love.focus handlers call Game:visible / Game:focus,
|
|
-- and src/core/Game2.lua defines neither -- so on Gold any window event (another
|
|
-- app taking the screen, which is constant when drivers share a machine) kills
|
|
-- the run before a single assertion prints. Fixing that belongs in Game2, not
|
|
-- in a driver; surviving it belongs here, so this run swallows the two
|
|
-- callbacks. Loaded from love.load, i.e. after main.lua has installed its own.
|
|
function love.visible() end
|
|
function love.focus() end
|
|
|
|
return function(game)
|
|
local w = game.world
|
|
local fails = 0
|
|
|
|
local function wait(n) for _ = 1, n do coroutine.yield() end end
|
|
|
|
local function ok(cond, msg)
|
|
if cond then
|
|
print("[starter] ok " .. msg)
|
|
else
|
|
fails = fails + 1
|
|
print("[starter] FAIL " .. msg)
|
|
end
|
|
return cond
|
|
end
|
|
|
|
local function shot(name)
|
|
local path = SHOT_DIR .. "/" .. name .. ".png"
|
|
game.capturePath = path
|
|
for _ = 1, 120 do
|
|
if not game.capturePath then break end
|
|
coroutine.yield()
|
|
end
|
|
wait(1)
|
|
local f = io.open(path, "rb")
|
|
if f then f:close() return true end
|
|
print("[starter] FAIL screenshot did not reach disk: " .. path)
|
|
fails = fails + 1
|
|
return false
|
|
end
|
|
|
|
local function tap(btn)
|
|
table.insert(game.input.pressQueue, btn)
|
|
coroutine.yield()
|
|
game.input.state[btn] = false
|
|
end
|
|
|
|
os.execute('mkdir -p "' .. SHOT_DIR .. '" 2>/dev/null')
|
|
wait(45)
|
|
|
|
-- SCENE_ELMSLAB_NOTHING: the meet-Elm walk-in has already played, which is
|
|
-- the state a player is in when they walk over to the balls.
|
|
w.mapScenes.ELMS_LAB = 1
|
|
w:setMap("ELMS_LAB", 6, 4, "up")
|
|
wait(20)
|
|
|
|
local shown, hidden = 0, 0
|
|
local realShow, realHide = w.showPokePic, w.hidePokePic
|
|
w.showPokePic = function(self, species)
|
|
shown = shown + 1
|
|
return realShow(self, species)
|
|
end
|
|
|
|
tap("a")
|
|
|
|
-- Count the frames the pic is actually up. The pic is a field on the world
|
|
-- rather than a pushed state, so this is the same thing love.draw reads.
|
|
local picFrames, sawPic = 0, false
|
|
for i = 1, 260 do
|
|
if w.pokePic then
|
|
picFrames = picFrames + 1
|
|
if not sawPic then
|
|
sawPic = true
|
|
shot("01_starter_popup")
|
|
end
|
|
end
|
|
if sawPic and not w.pokePic then break end
|
|
-- Press A again only once the pic has been on screen a while, so the
|
|
-- driver measures the hold instead of ending it on frame one.
|
|
if picFrames == 90 then tap("a") end
|
|
if i % 4 == 0 and not sawPic then tap("a") end
|
|
coroutine.yield()
|
|
end
|
|
|
|
ok(shown > 0, "the ball script ran `pokepic` (" .. shown .. " call(s))")
|
|
ok(picFrames > 0,
|
|
"and the pic was on screen for " .. picFrames .. " drawn frame(s)")
|
|
ok(picFrames >= 30,
|
|
"long enough to read: `waitbutton` holds it until the player presses A")
|
|
|
|
-- The yes/no follows the pic, so a run that got this far is at the prompt.
|
|
for _ = 1, 120 do
|
|
if w.choicebox or game.stack:top() ~= game.overworld then break end
|
|
coroutine.yield()
|
|
end
|
|
-- The box opens empty and types itself in over the next few frames, so a
|
|
-- capture on the frame it appeared would photograph a blank window and
|
|
-- prove nothing about the question.
|
|
wait(60)
|
|
shot("02_confirm_prompt")
|
|
|
|
if fails > 0 then
|
|
error(("gold starter pic: %d assertion(s) failed"):format(fails))
|
|
end
|
|
print("[driver] PASS gold starter pic: pokepic holds until A, then asks")
|
|
end
|