-- 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
