Files
gen1recomp/tests/drivers/game3_teachy_lesson.lua
2026-09-23 16:34:15 -04:00

276 lines
11 KiB
Lua

local U = require("tests.drivers.util")
local DIR = os.getenv("POKEPORT_SHOT_DIR") or "/tmp/game3_teachy_lesson"
-- pokefirered/data/maps/ViridianCity/scripts.inc:235 giveitem ITEM_TEACHY_TV
local ITEM_TEACHY_TV = 366
local failures = 0
local function result(ok, label)
print((ok and "PASS " or "FAIL ") .. label)
if not ok then failures = failures + 1 end
return ok
end
local function finish()
if failures == 0 then
print("PASS teachy_lesson")
love.event.quit(0)
else
print("FAIL teachy_lesson failures=" .. failures)
love.event.quit(1)
end
end
return function(game)
print("PASS driver_started")
for _ = 1, 900 do
if game.phase == "boot" and game.boot then break end
U.wait(1)
end
game:_handleBootAction({ action = "new_game", name = "RED" })
U.wait(240)
local Runtime = require("src.core.game3.runtime")
local Bag = require("src.core.game3.bag")
local StartMenu = require("src.ui.game3.start_menu")
local BagMenu = require("src.ui.game3.bag_menu")
local TeachyTv = require("src.core.game3.teachy_tv")
local TvUi = require("src.ui.game3.teachy_tv")
local session = Runtime.getSession()
if not result(session ~= nil, "new game reached the game3 field") then return finish() end
local function waitFor(fn, budget)
for _ = 1, (budget or 900) do
if fn() then return true end
U.wait(1)
end
return fn() and true or false
end
session.bag = session.bag or Bag.new()
Bag.add(session.bag, ITEM_TEACHY_TV, 1)
U.tap(game, "start")
U.wait(30)
if not result(StartMenu.isOpen(), "START opened the field menu") then return finish() end
for _ = 1, 12 do
local e = StartMenu.ENTRIES and StartMenu.ENTRIES[StartMenu.cursor]
if e and e.id == "bag" then break end
U.tap(game, "down")
U.wait(8)
end
U.tap(game, "a")
U.wait(60)
if not result(BagMenu.isOpen(), "BAG opened") then return finish() end
for _ = 1, 4 do
if BagMenu.currentPocket() == "KEY_ITEMS" then break end
U.tap(game, "right")
U.wait(15)
end
local function selectedName()
local rows = BagMenu.list()
local row = rows and rows[BagMenu.cursor]
return row and tostring(row.name) or nil
end
for _ = 1, 20 do
if selectedName() == "TEACHY TV" then break end
U.tap(game, "down")
U.wait(8)
end
if not result(selectedName() == "TEACHY TV", "the bag cursor is on TEACHY TV") then return finish() end
local function pocketsDump()
local parts = {}
for _, key in ipairs({ "ITEMS", "KEY_ITEMS", "POKE_BALLS" }) do
local ids = {}
for _, slot in ipairs((session.bag.pockets or {})[key] or {}) do
ids[#ids + 1] = tostring(slot.id) .. "x" .. tostring(slot.qty)
end
parts[#parts + 1] = key .. "=" .. table.concat(ids, ",")
end
return table.concat(parts, ";")
end
local bagBefore = { cursor = BagMenu.cursor, scroll = BagMenu.scroll, items = pocketsDump() }
print("[driver] bag before USE: " .. bagBefore.items)
local Audio = require("src.core.game3.audio")
local function songId()
local c = Audio.currentSong and Audio.currentSong()
return c and c.id
end
local fieldSong = Audio._mapSong
print("[driver] field song before USE: " .. tostring(fieldSong) .. " playing " .. tostring(songId()))
U.tap(game, "a")
U.wait(25)
U.tap(game, "a")
U.wait(60)
if not result(TvUi.isOpen(), "USE opened the TEACHY TV") then return finish() end
-- pokefirered/src/teachy_tv.c:490 PlayNewMapMusic(MUS_TEACHY_TV_MENU)
result(songId() == 346, "MUS_TEACHY_TV_MENU plays on the list, playing " .. tostring(songId()))
result(Audio._mapSong == fieldSong, "the location song is untouched, " .. tostring(Audio._mapSong))
U.shot(game, DIR .. "/teachy_lesson_00_list.png")
-- pokefirered/src/teachy_tv.c:201 sListMenuItems_NoTMCase
for _ = 1, 3 do
U.tap(game, "down")
U.wait(14)
end
result(TvUi.cursor == 4, "the cursor walked to the catching lesson, at " .. tostring(TvUi.cursor))
U.tap(game, "a")
U.wait(10)
result(TvUi.state == "lesson", "A started the lesson, state=" .. tostring(TvUi.state))
result(TeachyTv.whichScript(session) == TeachyTv.SCRIPT.CATCHING,
"whichScript is TTVSCR_CATCHING")
-- pokefirered/src/teachy_tv.c:755 TTVcmd_TransitionRenderBg2TeachyTvGraphicInitNpcPos
result(waitFor(function() return TvUi.title end, 200), "the title card came up")
U.wait(10)
U.shot(game, DIR .. "/teachy_lesson_01_title.png")
-- pokefirered/src/teachy_tv.c:782 TTVcmd_NpcMoveAndSetupTextPrinter
result(waitFor(function() return TvUi.phase == "hello" end, 600),
"the POKé DUDE walked in and said hello, phase=" .. tostring(TvUi.phase))
result(TvUi.hostVisible, "the host sprite is on screen at x=" .. tostring(TvUi.hostX))
print("[driver] hello page 1: " .. tostring(TvUi.pages()[1]))
U.wait(20)
U.shot(game, DIR .. "/teachy_lesson_02_hello.png")
for _ = 1, #TvUi.pages() - 1 do
U.tap(game, "a")
U.wait(10)
end
-- pokefirered/src/teachy_tv.c:838 TTVcmd_TextPrinterSwitchStringByOptionChosen
result(waitFor(function() return TvUi.phase == "intro" end, 200),
"CatchingScript1 took over, phase=" .. tostring(TvUi.phase))
result(#TvUi.pages() == #TeachyTv.introPages(TeachyTv.SCRIPT.CATCHING),
"the lesson is showing CatchingScript1, pages=" .. tostring(#TvUi.pages()))
print("[driver] intro page 1: " .. tostring(TvUi.pages()[TvUi.page]))
U.wait(20)
U.shot(game, DIR .. "/teachy_lesson_03_page1.png")
U.tap(game, "a")
U.wait(20)
result(TvUi.page == 2, "A advanced to page 2, at " .. tostring(TvUi.page))
print("[driver] intro page 2: " .. tostring(TvUi.pages()[TvUi.page]))
U.wait(10)
U.shot(game, DIR .. "/teachy_lesson_04_page2.png")
for _ = 1, #TvUi.pages() - 2 do
U.tap(game, "a")
U.wait(10)
end
-- pokefirered/src/teachy_tv.c:936 TTVcmd_EraseTextWindowIfKeyPressed
result(waitFor(function() return TvUi.stepName() == "erase_text_window_if_key_pressed" end, 200),
"the cluster waits for a key press, step=" .. tostring(TvUi.stepName()))
result(TvUi.waitingForKey(), "the prompt arrow is up")
U.tap(game, "a")
U.wait(10)
-- pokefirered/src/teachy_tv.c:947 TTVcmd_StartAnimNpcWalkIntoGrass
result(waitFor(function() return TvUi.stepName() == "dude_move_up" end, 200),
"the dude walks into the grass, step=" .. tostring(TvUi.stepName()))
U.wait(24)
-- pokefirered/src/teachy_tv.c:761
result(TvUi.static == nil, "no static over the Route 1 field during the walk")
result(#TvUi.grass > 0, "tall grass tufts are out, count " .. tostring(#TvUi.grass))
result(not require("src.core.game3.battle").isActive(), "the walk is shot before the encounter")
U.still(game, DIR .. "/teachy_lesson_05_grass_walk.png")
-- pokefirered/src/teachy_tv.c:1069 TTVcmd_TaskBattleOrFadeByOptionChosen
result(waitFor(function() return TvUi.stepName() ~= "dude_move_up"
and TvUi.stepName() ~= "dude_move_right" end, 300),
"the cluster reached the demonstration hand off, step=" .. tostring(TvUi.stepName()))
-- pokefirered/src/teachy_tv.c:1172 TeachyTvPrepBattle
local Battle = require("src.core.game3.battle")
local partyBefore = #(session.party or {})
if not result(waitFor(function() return Battle.isActive() end, 200), "the POKé DUDE battle started") then
return finish()
end
local st = Battle.getState()
result(st and st.pokedude == true, "it is a BATTLE_TYPE_POKEDUDE battle")
result(st and st.enemy and st.enemy.mon and st.enemy.mon.species == 39, "against JIGGLYPUFF")
local shotVo, shotMenu = false, false
local BattleUi = require("src.core.game3.battle.ui")
for _ = 1, 6000 do
if not Battle.isActive() then break end
local pd = st and st.pd
if not shotMenu and pd and pd.step == "action" and pd.battlers[0].timer > 40 then
shotMenu = true
U.still(game, DIR .. "/teachy_lesson_056_battle_action_menu.png")
end
local Message = require("src.ui.game3.message")
if Message.isOpen() and Message.frameKind and Message.frameKind() == "voiceover" then
if not shotVo and Message.isWaiting and Message.isWaiting() then
shotVo = true
U.still(game, DIR .. "/teachy_lesson_055_battle_voiceover.png")
end
U.tap(game, "a")
end
U.wait(1)
end
result(not Battle.isActive(), "the demonstration battle ended")
result(st and st.result == "catch", "the POKé DUDE caught the JIGGLYPUFF, result=" .. tostring(st and st.result))
local log = st and st.pd and st.pd.log or {}
print("[driver] voiceovers: " .. table.concat(log, ","))
result(#log == 5, "all five catching voiceovers played, got " .. #log)
result(#(session.party or {}) == partyBefore, "the player's party is untouched")
result(waitFor(function() return TvUi.phase == "outro" end, 400),
"the lesson resumed at CatchingScript2, phase=" .. tostring(TvUi.phase))
-- pokefirered/src/teachy_tv.c:1214 PlayNewMapMusic(MUS_FOLLOW_ME)
result(songId() == 272, "MUS_FOLLOW_ME plays after the battle, playing " .. tostring(songId()))
result(TeachyTv.whichScript(session) == TeachyTv.SCRIPT.CATCHING,
"and it is still the catching lesson")
print("[driver] outro page 1: " .. tostring(TvUi.pages()[TvUi.page]))
U.wait(20)
U.shot(game, DIR .. "/teachy_lesson_06_demo_handoff.png")
for _ = 1, #TvUi.pages() - 1 do
U.tap(game, "a")
U.wait(10)
end
result(waitFor(function() return TvUi.stepName() == "erase_text_window_if_key_pressed" end, 200),
"the outro waits for a key press")
U.tap(game, "a")
U.wait(10)
-- pokefirered/src/teachy_tv.c:1021 TTVcmd_RenderAndRemoveBg1EndGraphic
result(waitFor(function() return TvUi.stepName() == "render_and_remove_bg1_end_graphic" end, 400),
"the dude walked off, step=" .. tostring(TvUi.stepName()))
-- pokefirered/src/teachy_tv.c:1043 TTVcmd_End
result(waitFor(function() return TvUi.state == "list" end, 400),
"the lesson ended back on the list, state=" .. tostring(TvUi.state))
result(TeachyTv.hasWatched(session, TeachyTv.SCRIPT.CATCHING),
"the catching lesson is marked watched")
U.wait(20)
U.shot(game, DIR .. "/teachy_lesson_07_back_on_list.png")
U.tap(game, "b")
U.wait(45)
result(not TvUi.isOpen(), "B on the list closed the TV")
result(BagMenu.isOpen(), "the BAG is underneath again")
-- pokefirered/src/teachy_tv.c:705 Overworld_PlaySpecialMapMusic
result(songId() == fieldSong, "the field song is back in the BAG, playing " .. tostring(songId()))
result(Audio._mapSong == fieldSong, "the location song is still " .. tostring(fieldSong))
-- pokefirered/src/item_menu.c:2082 RestorePlayerBag
result(BagMenu.currentPocket() == "KEY_ITEMS",
"the player's bag is back on KEY ITEMS, pocket=" .. tostring(BagMenu.currentPocket()))
result(selectedName() == "TEACHY TV", "the cursor is back on TEACHY TV, on " .. tostring(selectedName()))
result(BagMenu.cursor == bagBefore.cursor and BagMenu.scroll == bagBefore.scroll,
"the KEY ITEMS cursor/scroll came back, " .. tostring(BagMenu.cursor) .. "/" .. tostring(BagMenu.scroll))
result(pocketsDump() == bagBefore.items, "the player's items came back: " .. pocketsDump())
U.wait(20)
U.shot(game, DIR .. "/teachy_lesson_08_bag_after_close.png")
U.tap(game, "b")
U.wait(40)
result(waitFor(function() return not BagMenu.isOpen() end, 120), "B closed the BAG")
if StartMenu.isOpen() then
U.tap(game, "b")
U.wait(30)
end
result(songId() == fieldSong, "the field song still plays on the field, playing " .. tostring(songId()))
finish()
end