mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 16:21:05 +02:00
158 lines
6.0 KiB
Lua
158 lines
6.0 KiB
Lua
-- Driver: one STADIUM screenshot per species, every one of the 151 standing
|
|
-- on the ENEMY mark in its standby loop.
|
|
--
|
|
-- stadium_shots.lua photographs a handful of deliberately awkward cases; this
|
|
-- is the exhaustive sweep behind it. What it exists to catch is the class of
|
|
-- fault that is per-MODEL and invisible to the headless QA pass -- a texture
|
|
-- that comes out magenta, a mon standing in the floor or floating over it, a
|
|
-- silhouette that is subtly the wrong shape -- none of which is a number
|
|
-- stadium_anim_qa.lua can measure.
|
|
--
|
|
-- SHOT_DIR=mods/DramaticShapeVoxelMod/.claude/stadium_verify \
|
|
-- POKEPORT_SPEED=4 \
|
|
-- POKEPORT_DRIVER=mods/DramaticShapeVoxelMod/tests/stadium_all_shots.lua \
|
|
-- lovec.exe .
|
|
--
|
|
-- Files land as NNN_species.png in dex order. Run from the PROJECT ROOT.
|
|
--
|
|
-- ------- everything but the foe is nailed down
|
|
--
|
|
-- The whole value of 151 shots is that they are comparable, so the staging is
|
|
-- identical in every one: same map, same cells, same hour (the day/night
|
|
-- cycle would otherwise relight every shot), same rung, and the same small
|
|
-- Pokemon on the player's mark -- DIGLETT, chosen because it is the shortest
|
|
-- model in the set and so hides the least of the arena behind it. Whatever
|
|
-- differs between two of these shots is the foe.
|
|
--
|
|
-- ------- the model/sprite verdict is the other half
|
|
--
|
|
-- A species whose pack will not load, or whose animation data the packer
|
|
-- declined, does not error: StadiumMon.setSpecies answers false and the mode
|
|
-- quietly stands the Game Boy's flat pic on the tile instead. That is the
|
|
-- correct behaviour and it is nearly invisible in a screenshot at a glance --
|
|
-- which is exactly why it needs counting rather than looking. Stadium.showing
|
|
-- is asked for every species and the ones that decline are listed at the end.
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local DIR = os.getenv("SHOT_DIR") or ".claude/stadium_verify"
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
local BattleState = require("src.battle.BattleState")
|
|
|
|
local exports = game.mods and game.mods.exports
|
|
local lib = exports and exports.DRAMATIC_SHAPE and exports.DRAMATIC_SHAPE.lib
|
|
if not lib then
|
|
U.log("DRAMATIC_SHAPE is not loaded -- enable it and run again")
|
|
return
|
|
end
|
|
local Battles = lib.require("OverworldBattle")
|
|
local Stadium = lib.require("Stadium")
|
|
local Pack = lib.require("StadiumPack")
|
|
local Install = lib.require("StadiumInstall")
|
|
|
|
-- every real species the merged data carries, in dex order
|
|
local species = {}
|
|
for id, def in pairs(game.data.pokemon) do
|
|
if type(id) == "string" and type(def) == "table"
|
|
and def.dex and def.dex >= 1 and def.dex <= 151 then
|
|
species[#species + 1] = { id = id, dex = def.dex }
|
|
end
|
|
end
|
|
table.sort(species, function(a, b) return a.dex < b.dex end)
|
|
|
|
game.save.player.name = "RED"
|
|
|
|
-- ONTO THE MAP FIRST: the model build (if one is owed) is pushed from the
|
|
-- mod's update hook on the first frame the overworld is the top state, so
|
|
-- waiting for it before teleporting waits forever.
|
|
U.teleport(game, "ROUTE_1", 5, 8, "down")
|
|
|
|
local waited = 0
|
|
while (Install.pending() or Install.status.state == "building")
|
|
and waited < 5400 do
|
|
U.wait(10)
|
|
waited = waited + 10
|
|
end
|
|
if waited > 0 then
|
|
U.log(("waited %.1fs for the model build -- %s")
|
|
:format(waited / 60, tostring(Install.status.state)))
|
|
end
|
|
|
|
Battles.setting:setValue("stadium", game)
|
|
Battles.backSetting:setValue(false, game)
|
|
lib.require("DayNight").setting:setValue(os.getenv("DS_TOD") or "day", game)
|
|
|
|
local have = 0
|
|
for dex = 1, 151 do
|
|
if Pack.available(dex) then have = have + 1 end
|
|
end
|
|
U.log(("%d species, %d/151 packs on disk, rung = %s")
|
|
:format(#species, have, tostring(Battles.setting:get())))
|
|
|
|
-- let the neighbourhood's meshes land, so the first fight opens on the
|
|
-- real arena rather than the flat fallback
|
|
U.wait(90)
|
|
|
|
local asPic, stuck, missed = {}, {}, {}
|
|
|
|
for _, s in ipairs(species) do
|
|
-- the player's side is a constant (see the header), so the only thing
|
|
-- that changes between two shots is the Pokemon being verified
|
|
game.save.party = { Pokemon.new(game.data, "DIGLETT", 40) }
|
|
|
|
local battle = BattleState.newWild(game, s.id, 30)
|
|
battle.onFinish = function() end
|
|
game.overworld:pushBattle(battle)
|
|
|
|
-- the wipe and the intro chatter, then far enough past it that the
|
|
-- player's own Pokemon has been sent out -- before that the player's
|
|
-- side is legitimately the trainer's back sprite and the foe is still
|
|
-- sliding in
|
|
U.wait(70)
|
|
for _ = 1, 40 do
|
|
if battle.phase == "menu" then break end
|
|
U.tap(game, "a")
|
|
U.wait(10)
|
|
end
|
|
if battle.phase ~= "menu" then
|
|
stuck[#stuck + 1] = s.id
|
|
U.log(("STUCK before menu: %s (phase %s)")
|
|
:format(s.id, tostring(battle.phase)))
|
|
end
|
|
-- and let the send-out beat finish so the mon is standing still in its
|
|
-- standby loop rather than mid-arrival
|
|
U.wait(45)
|
|
|
|
-- model or flat pic? asked here, with the fight actually on screen
|
|
if not Stadium.showing("enemy") then
|
|
asPic[#asPic + 1] = ("%03d %s"):format(s.dex, s.id)
|
|
end
|
|
|
|
local path = ("%s/%03d_%s.png"):format(DIR, s.dex, s.id:lower())
|
|
if not U.shot(game, path) then
|
|
missed[#missed + 1] = s.id
|
|
end
|
|
|
|
while game.stack:top() and game.stack:top() ~= game.overworld do
|
|
game.stack:pop()
|
|
end
|
|
U.wait(10)
|
|
end
|
|
|
|
U.log(("---- %d shots -> %s"):format(#species - #missed, DIR))
|
|
if #asPic > 0 then
|
|
U.log(("%d species declined to a model and were shot as FLAT PICS: %s")
|
|
:format(#asPic, table.concat(asPic, ", ")))
|
|
else
|
|
U.log("all species stood as MODELS -- none fell back to a flat pic")
|
|
end
|
|
if #stuck > 0 then
|
|
U.log(("%d never reached the battle menu: %s")
|
|
:format(#stuck, table.concat(stuck, ", ")))
|
|
end
|
|
if #missed > 0 then
|
|
U.log(("%d screenshots did not reach disk: %s")
|
|
:format(#missed, table.concat(missed, ", ")))
|
|
end
|
|
U.log("done -- " .. DIR)
|
|
end
|