Files
2026-08-06 01:07:38 -04:00

138 lines
4.3 KiB
Lua

-- Driver: screenshot the forest's atmosphere.
--
-- Viridian Forest through the pins: gold shafts and drifting pollen by
-- day, silver moon rays and fireflies at night, the haze under both, one
-- first-person frame standing inside a beam, and the control shots -- the
-- row OFF (which must be pixel-identical to a run before the feature
-- existed) and LOW (haze, half the shafts, no particles).
--
-- Deterministic on purpose: encounters killed, tile animation frozen, the
-- atmosphere's own clock pinned, so an AB_TAG=before/after pair diffs
-- clean (see tools/voxel-survey.md for the workflow).
--
-- SHOT_DIR=.scratchpad/forestfog AB_TAG=after \
-- POKEPORT_DRIVER=mods/DramaticShapeVoxelMod/tests/forest_fog_shots.lua lovec.exe .
return function(game)
local U = dofile("tests/drivers/util.lua")
local Pipelines = require("src.render.Pipelines")
local ROOT = (os.getenv("SHOT_DIR") or ".scratchpad/forestfog")
.. "/" .. (os.getenv("AB_TAG") or "after")
local exports = game.mods and game.mods.exports
local handle = exports and exports.DRAMATIC_SHAPE
if not (handle and handle.lib) then
U.log("DRAMATIC_SHAPE is not loaded -- enable it and run again")
return
end
local lib = handle.lib
local DayNight = lib.require("DayNight")
local ChunkMesher = lib.require("ChunkMesher")
local Voxel = lib.require("VoxelState")
local ForestAtmos = lib.require("ForestAtmos")
if not (game.data.maps and game.data.maps.VIRIDIAN_FOREST) then
U.log("no VIRIDIAN_FOREST in this dataset")
return
end
-- ------- the determinism recipe (see round_regress_shots)
require("src.world.OverworldController").rollEncounter =
function() return nil end
local TileRenderer = require("src.render.TileRenderer")
TileRenderer.tick = function() end
TileRenderer.animFrame = function() return 0 end
local Zoom = require("src.render.Zoom")
pcall(function()
game.save.options.zoom = 1
Zoom.applyOptions(game.save.options)
end)
-- pin the atmosphere's own clock: every shimmer and every mote is a
-- pure function of this number
ForestAtmos.frozen = true
ForestAtmos.time = 5
local function setTime(value)
DayNight.setting:sync(value)
DayNight.update(0)
end
local function settle()
for _ = 1, 900 do
if ChunkMesher.pending() == 0 then break end
U.wait(1)
end
for _ = 1, 300 do
if Voxel.t >= 1 and Voxel.ready and ChunkMesher.pending() == 0 then
break
end
U.wait(1)
end
U.wait(40)
end
local function go(x, y, face, rung)
U.teleport(game, "VIRIDIAN_FOREST", x, y, face or "up")
Pipelines.setLevel("voxel", rung or 5)
Pipelines.setLevel("tiltshift", 0) -- judge the atmosphere, not the blur
settle()
end
ForestAtmos.setting:sync("full")
-- ------- day: gold spears and pollen, three vantages
setTime("day")
go(17, 20)
U.shot(game, ROOT .. "/10_day_17_20.png")
go(16, 20)
U.shot(game, ROOT .. "/11_day_16_20.png")
go(16, 24)
U.shot(game, ROOT .. "/12_day_16_24.png")
-- ------- night: moon rays and fireflies, same vantages
setTime("night")
go(17, 20)
U.shot(game, ROOT .. "/20_night_17_20.png")
go(16, 20)
U.shot(game, ROOT .. "/21_night_16_20.png")
go(16, 24)
U.shot(game, ROOT .. "/22_night_16_24.png")
-- ------- first person, standing in a beam
--
-- The shafts are dealt by seed, so ask the layout where one landed and
-- walk into it rather than guessing a cell.
local shaft
pcall(function()
local map = game.overworld and game.overworld.map
local L = map and ForestAtmos.layoutFor(map)
shaft = L and L.shafts and L.shafts[1]
end)
if shaft then
local cx = math.floor(shaft.x / 16)
local cy = math.floor(shaft.z / 16)
setTime("day")
go(cx, cy + 1, "up", 6) -- the 1ST rung, facing the beam
U.shot(game, ROOT .. "/30_fp_in_beam_day.png")
setTime("night")
U.wait(30)
U.shot(game, ROOT .. "/31_fp_in_beam_night.png")
else
U.log("no shaft landed -- check the layout seed")
end
-- ------- the controls
setTime("day")
ForestAtmos.setting:sync("low")
go(17, 20)
U.shot(game, ROOT .. "/40_low_day.png")
ForestAtmos.setting:sync("off")
go(17, 20)
U.shot(game, ROOT .. "/41_off_day.png") -- must match a pre-feature run
ForestAtmos.setting:sync("full")
ForestAtmos.frozen = false
setTime("day")
U.log("done -- " .. ROOT)
end