mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 16:31:05 +02:00
be90e5b42c
* intro api upgrade * api updates * fix tests * updated templates
244 lines
7.8 KiB
Lua
244 lines
7.8 KiB
Lua
-- Driver: NEW GAME through the silly Oak intro (example_silly_oak must be
|
|
-- installed under mods/). Mashes text, picks every menu option in a fixed
|
|
-- pattern, screenshots key beats, then asserts mod.save answers.
|
|
--
|
|
-- Setup:
|
|
-- cp -r mods/examples/example_silly_oak mods/
|
|
-- SHOT_DIR=/tmp/silly_oak POKEPORT_DRIVER=tests/drivers/silly_oak_intro_test.lua love .
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local DIR = os.getenv("SHOT_DIR") or "/tmp/shots"
|
|
|
|
local function top() return game.stack:top() end
|
|
local function speechState()
|
|
for _, s in ipairs(game.stack.states or {}) do
|
|
if s.oakPic ~= nil or (s.steps and s.answers) then return s end
|
|
end
|
|
end
|
|
local function topName()
|
|
local s = top()
|
|
if not s then return "?" end
|
|
return s.screenId or (s.__index and tostring(s.__index)) or tostring(s)
|
|
end
|
|
local function isMenu(s)
|
|
return s and s.items and s.index and s.tx ~= nil
|
|
end
|
|
local function isNaming(s)
|
|
return s and s.glyphs ~= nil and s.title ~= nil
|
|
end
|
|
local function isChoiceBox(s)
|
|
return s and s.onChoose and s.index ~= nil and not s.items
|
|
end
|
|
|
|
-- confirm the mod actually loaded
|
|
local loaded = false
|
|
if game.modStatus and game.modStatus.loaded then
|
|
for _, m in ipairs(game.modStatus.loaded) do
|
|
if m.id == "example_silly_oak" then loaded = true break end
|
|
end
|
|
end
|
|
if not loaded and game.mods and game.mods.mods then
|
|
local m = game.mods.mods.example_silly_oak
|
|
loaded = m and m.enabled and not m.failed
|
|
end
|
|
U.log("example_silly_oak loaded:", tostring(loaded))
|
|
if not loaded then
|
|
U.log("FAIL: copy the mod up first:")
|
|
U.log(" cp -r mods/examples/example_silly_oak mods/")
|
|
return
|
|
end
|
|
|
|
U.wait(5)
|
|
U.tap(game, "start") -- skip intro movie
|
|
U.wait(15)
|
|
U.tap(game, "a") -- title -> menu
|
|
U.wait(8)
|
|
-- with an existing save the menu is CONTINUE / NEW GAME / OPTION;
|
|
-- always land on NEW GAME (row 2 when a save exists, else row 1)
|
|
local ok, saved = pcall(function()
|
|
return require("src.core.SaveData").load() ~= nil
|
|
end)
|
|
if ok and saved then
|
|
U.tap(game, "down")
|
|
U.wait(5)
|
|
end
|
|
U.tap(game, "a") -- NEW GAME
|
|
U.wait(20)
|
|
|
|
-- confirm we actually entered OakSpeech, not CONTINUE into the world
|
|
local entered = false
|
|
for _ = 1, 60 do
|
|
if speechState() then entered = true break end
|
|
if game.overworld and top() == game.overworld then break end
|
|
U.wait(1)
|
|
end
|
|
if not entered then
|
|
U.log("FAIL: never entered OakSpeech (did we hit CONTINUE?)")
|
|
U.log("top:", topName())
|
|
return
|
|
end
|
|
|
|
U.shot(game, DIR .. "/silly_01_start.png")
|
|
|
|
-- walk the speech: A advances text; menus get a deliberate pick pattern
|
|
local picks = {
|
|
-- silly_toast YES/NO: pick YES (index 1)
|
|
toast = 1,
|
|
-- naming player: take preset 1 (RED) via NEW NAME menu -> first preset
|
|
-- snack: OLD ROD (index 3)
|
|
snack = 3,
|
|
-- trusts rival: NO (index 2)
|
|
trust = 2,
|
|
-- pineapple YES/NO: pick NO
|
|
pineapple = 2,
|
|
}
|
|
local saw = {
|
|
toast_kid = false, mew = false, snack = false, trust = false,
|
|
pineapple = false, shrink = false,
|
|
}
|
|
local snackPicked, trustPicked = false, false
|
|
local toastAnswered, pineappleAnswered = false, false
|
|
local shot = {}
|
|
|
|
for _ = 1, 900 do
|
|
local speech = speechState()
|
|
local s = top()
|
|
|
|
if speech and speech.shrink then
|
|
saw.shrink = true
|
|
if not shot.shrink then
|
|
shot.shrink = true
|
|
U.shot(game, DIR .. "/silly_05_shrink.png")
|
|
end
|
|
break
|
|
end
|
|
|
|
-- track which injected beats we hit + screenshot once each
|
|
if speech and speech.steps and speech.step then
|
|
local cur = speech.steps[speech.step]
|
|
if cur then
|
|
if cur.id == "silly_toast_kid" then
|
|
saw.toast_kid = true
|
|
if not shot.toast_kid then
|
|
shot.toast_kid = true
|
|
U.shot(game, DIR .. "/silly_04_toast_kid.png")
|
|
end
|
|
end
|
|
if cur.id == "silly_mew" then
|
|
saw.mew = true
|
|
if not shot.mew then
|
|
shot.mew = true
|
|
U.shot(game, DIR .. "/silly_04b_mew.png")
|
|
end
|
|
end
|
|
if cur.id == "silly_snack" then saw.snack = true end
|
|
if cur.id == "silly_trust" then saw.trust = true end
|
|
if cur.id == "silly_pineapple" then saw.pineapple = true end
|
|
end
|
|
end
|
|
|
|
if isChoiceBox(s) then
|
|
-- YES/NO: move to desired row then A
|
|
local want
|
|
local cur = speech and speech.steps and speech.steps[speech.step]
|
|
if cur and cur.id == "silly_toast" then
|
|
want = picks.toast
|
|
toastAnswered = true
|
|
elseif cur and cur.id == "silly_pineapple" then
|
|
want = picks.pineapple
|
|
pineappleAnswered = true
|
|
else
|
|
want = 1
|
|
end
|
|
if s.index ~= want then
|
|
U.tap(game, "down")
|
|
U.wait(2)
|
|
end
|
|
U.tap(game, "a")
|
|
U.wait(4)
|
|
elseif isMenu(s) and not isNaming(s) then
|
|
-- multi choice or naming presets
|
|
local cur = speech and speech.steps and speech.steps[speech.step]
|
|
local want = 1
|
|
if cur and cur.id == "silly_snack" then
|
|
want = picks.snack
|
|
snackPicked = true
|
|
if not shot.snack then
|
|
shot.snack = true
|
|
U.shot(game, DIR .. "/silly_02_snack.png")
|
|
end
|
|
elseif cur and cur.id == "silly_trust" then
|
|
want = picks.trust
|
|
trustPicked = true
|
|
if not shot.trust then
|
|
shot.trust = true
|
|
U.shot(game, DIR .. "/silly_03_trust.png")
|
|
end
|
|
elseif s.items and s.items[1] and s.items[1].label == "NEW NAME" then
|
|
-- naming preset menu: pick first preset (row 2)
|
|
want = 2
|
|
end
|
|
while s.index < want do
|
|
U.tap(game, "down")
|
|
U.wait(2)
|
|
s = top()
|
|
if not isMenu(s) then break end
|
|
end
|
|
U.tap(game, "a")
|
|
U.wait(4)
|
|
else
|
|
U.tap(game, "a")
|
|
U.wait(2)
|
|
end
|
|
|
|
if game.overworld and top() == game.overworld then break end
|
|
end
|
|
|
|
-- finish shrink + land in overworld
|
|
for _ = 1, 150 do
|
|
if game.overworld and top() == game.overworld then break end
|
|
U.wait(1)
|
|
end
|
|
U.wait(10)
|
|
U.shot(game, DIR .. "/silly_06_overworld.png")
|
|
|
|
local bucket = (game.save and game.save.modData
|
|
and game.save.modData.example_silly_oak)
|
|
or (game.mods and game.mods.modSave
|
|
and game.mods.modSave.example_silly_oak)
|
|
or {}
|
|
|
|
U.log("saw toast_kid:", tostring(saw.toast_kid),
|
|
"mew:", tostring(saw.mew),
|
|
"snack:", tostring(saw.snack),
|
|
"trust:", tostring(saw.trust),
|
|
"pineapple:", tostring(saw.pineapple),
|
|
"shrink:", tostring(saw.shrink))
|
|
U.log("answers:",
|
|
"likes_toast=", tostring(bucket.likes_toast),
|
|
"snack=", tostring(bucket.snack),
|
|
"trusts_rival=", tostring(bucket.trusts_rival),
|
|
"pineapple=", tostring(bucket.pineapple_on_pizza),
|
|
"quiz_done=", tostring(bucket.quiz_done))
|
|
U.log("player=", game.save and game.save.player and game.save.player.name,
|
|
"rival=", game.save and game.save.player and game.save.player.rival)
|
|
U.log("top:", topName(),
|
|
"map:", game.overworld and game.overworld.map
|
|
and game.overworld.map.id or "?")
|
|
|
|
local function need(cond, msg)
|
|
if not cond then U.log("FAIL:", msg) else U.log("ok:", msg) end
|
|
end
|
|
need(saw.toast_kid, "custom Toast Kid sprite beat ran")
|
|
need(saw.mew, "MEW sprite beat ran")
|
|
need(saw.snack or snackPicked, "snack choice ran")
|
|
need(saw.trust or trustPicked, "rival trust choice ran")
|
|
need(saw.pineapple or pineappleAnswered, "pineapple yes/no ran")
|
|
need(bucket.likes_toast == true, "likes_toast saved true")
|
|
need(bucket.snack == "OLD ROD", "snack saved OLD ROD")
|
|
need(bucket.trusts_rival == false, "trusts_rival saved false")
|
|
need(bucket.pineapple_on_pizza == false, "pineapple saved false")
|
|
need(bucket.quiz_done == true, "quiz_done set")
|
|
need(game.overworld and top() == game.overworld, "landed in overworld")
|
|
end
|