120f9716b6
A POKEPORT_DRIVER run is deliberately unpaced -- main.lua's pacingEnabled() returns false whenever the variable is set, so love.run spins as fast as the machine allows and takes one Game:update(1/60) per turn of the loop. Right for a screenshot script, wrong for a recording: "wait 180 frames" is three seconds only by coincidence of hardware. No engine change needed. The loop is blocked while the driver coroutine is running, so sleeping inside it before each yield paces the whole thing -- one logic step per one sixtieth of real time, 1x by construction. Measured with DS_AUTOCLOSE: asked for 6.0s, took 6.31s, and it errs slow rather than fast. shiny_one.lua does ONE encounter and then never finishes, which is how the window stays up: main.lua quits the moment a driver coroutine goes dead. So closing the window by hand is what ends the take. shiny_run.sh launches the five in turn and blocks on each, so the next never opens over the top of one still being recorded, and a bad take can just be closed and re-run. It also puts options.lua back afterwards. The game persists the whole options table mid-run, so every capture leaves its display settings on disk.
111 lines
4.1 KiB
Lua
111 lines
4.1 KiB
Lua
-- Driver: five shiny encounters, five outdoor places, paced for a capture.
|
|
--
|
|
-- POKEPORT_DRIVER=mods/DramaticShapeVoxelMod/tests/shiny_obs.lua \
|
|
-- "/c/Program Files/LOVE/lovec.exe" .
|
|
--
|
|
-- Run from the PROJECT ROOT. Nothing here is a screenshot test -- it is a
|
|
-- performance, timed for somebody recording the window.
|
|
--
|
|
-- Each beat: teleport, let the ground mesh, open a wild battle, let the
|
|
-- Pokemon ARRIVE (the wipe, the send-out, the shiny sparkle), then hold
|
|
-- three full seconds on it before closing the battle and moving on. The hold
|
|
-- is deliberately silent -- no button taps during it -- so the recording is
|
|
-- of the Pokemon standing there and not of a text box being clicked through.
|
|
--
|
|
-- Every encounter is shiny, because the odds are pinned to 1 for the run and
|
|
-- the roll still happens where it always does, inside Pokemon.new.
|
|
return function(game)
|
|
local U = dofile("tests/drivers/util.lua")
|
|
local BattleState = require("src.battle.BattleState")
|
|
local Pokemon = require("src.pokemon.Pokemon")
|
|
|
|
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 -- nothing to show")
|
|
return
|
|
end
|
|
local Shiny = lib.require("Shiny")
|
|
local OverworldBattle = lib.require("OverworldBattle")
|
|
local StadiumInstall = lib.require("StadiumInstall")
|
|
|
|
-- ------- timing, in frames at 60fps
|
|
local SETTLE = 110 -- after a teleport, for the neighbourhood to mesh
|
|
local ARRIVE = 70 -- the wipe, then the Pokemon landing on its tile
|
|
local HOLD = 180 -- THE THREE SECONDS
|
|
local BETWEEN = 45 -- back on the map before the next one opens
|
|
|
|
-- ------- the models
|
|
if not StadiumInstall.ready() then
|
|
U.log("building stadium models first...")
|
|
StadiumInstall.begin()
|
|
local guard = 0
|
|
while not StadiumInstall.ready() and guard < 2000 do
|
|
for _ = 1, 6 do StadiumInstall.step() end
|
|
U.wait(1)
|
|
guard = guard + 1
|
|
end
|
|
end
|
|
U.log("stadium ready: " .. tostring(StadiumInstall.ready()))
|
|
|
|
OverworldBattle.setting:setValue("stadium", game)
|
|
Shiny.setOdds(1) -- every encounter, shiny
|
|
|
|
game.save.player.name = "RED"
|
|
game.save.party = { Pokemon.new(game.data, "PIKACHU", 50) }
|
|
|
|
-- Five outdoor places, deliberately unalike -- a coast, an open route, a
|
|
-- water city, a rocky pass and a wooded shore -- so the recording is five
|
|
-- different-looking fights and not the same meadow five times. Each mon is
|
|
-- put somewhere its colour has something to sit against.
|
|
local RUNS = {
|
|
{ "BLASTOISE", 45, "PALLET_TOWN", 5, 6 },
|
|
{ "PIDGEOTTO", 32, "ROUTE_1", 5, 8 },
|
|
{ "GYARADOS", 45, "CERULEAN_CITY", 10, 12 },
|
|
{ "CHARIZARD", 50, "ROUTE_4", 10, 5 },
|
|
{ "NINETALES", 42, "ROUTE_25", 12, 5 },
|
|
}
|
|
|
|
-- a beat before the first one, so a recorder that started with the window
|
|
-- is not already mid-encounter by the time it is rolling
|
|
U.log("starting in 3...")
|
|
U.wait(60)
|
|
U.log("2...")
|
|
U.wait(60)
|
|
U.log("1...")
|
|
U.wait(60)
|
|
|
|
for i, r in ipairs(RUNS) do
|
|
local species, level, map, cx, cy = r[1], r[2], r[3], r[4], r[5]
|
|
if not game.data.pokemon[species] then
|
|
U.log(("skip %s -- not in this dataset"):format(species))
|
|
elseif not game.data.maps[map] then
|
|
U.log(("skip %s -- no map %s"):format(species, map))
|
|
else
|
|
U.teleport(game, map, cx, cy, "down")
|
|
U.wait(SETTLE)
|
|
|
|
local battle = BattleState.newWild(game, species, level)
|
|
battle.onFinish = function() end
|
|
game.overworld:pushBattle(battle)
|
|
|
|
local mon = battle.enemy and battle.enemy.mon
|
|
U.log(("%d/5 %-10s %-14s shiny=%s")
|
|
:format(i, species, map, tostring(Shiny.isShiny(mon))))
|
|
|
|
-- the arrival, then three seconds of nothing but the Pokemon
|
|
U.wait(ARRIVE)
|
|
U.wait(HOLD)
|
|
|
|
-- close the battle and go back to the map
|
|
while game.stack:top() and game.stack:top() ~= game.overworld do
|
|
game.stack:pop()
|
|
end
|
|
U.wait(BETWEEN)
|
|
end
|
|
end
|
|
|
|
Shiny.setOdds(8192)
|
|
U.log("done -- five encounters")
|
|
end
|