Files
security-game/src/test/capture_screenshots.gd
T
zwitschi 513f8a0f60 Visual polish pass (v0.2.0): phase lighting, street lamps, marquee, dressing, night screenshots
- Phase-based lighting: sun direction/energy/color, ProceduralSkyMaterial
  gradient, and ambient per shift phase (GameManager.PHASE_LIGHTING),
  applied on phase transitions and shift start
- WorldBuilder: street lamp poles with emissive bulbs + OmniLights,
  set_night_mode(), glowing STEP LINE marquee (Label3D + emissive bars),
  crosswalk stripes, planters, low-poly street trees
- NPC avatars: per-seed height/brightness variation (deterministic LCG)
- Denser routine traffic probabilities
- capture_screenshots.gd: fast-forward to LATE phase and capture night set;
  README gallery is now 2x3 day+night; docs/screenshots regenerated
- Version bumped to 0.2.0; build/ artifacts rebuilt; Linux binary smoke-tested
- New headless tests for phased lighting config and street dressing (56 total)
2026-10-31 13:24:40 +01:00

103 lines
2.8 KiB
GDScript

extends SceneTree
## Dev helper: run the game windowed and capture staged screenshots for the
## README (day set + LATE-night set with street lamps and flashlight).
## Saves 1280x720 PNGs to user://screenshots/.
## Usage: godot --path . --script res://src/test/capture_screenshots.gd
const OUT_DIR := "user://screenshots"
const MAX_FRAMES := 3600 # hard cap (~60s)
var frames := 0
var gm: Node = null
var state := 0
var state_frames := 0
var targeted := false
func _initialize() -> void:
root.size = Vector2i(1600, 900)
var packed: PackedScene = load("res://scenes/main.tscn")
var inst: Node = packed.instantiate()
root.add_child(inst)
func _process(_delta: float) -> bool:
frames += 1
# The main scene's _ready may not have run when _initialize added it;
# look for GameManager lazily each frame until it exists.
if gm == null:
gm = root.find_child("GameManager", true, false)
if gm == null and frames > 120:
push_error("GameManager not found")
quit(1)
return true
if frames > MAX_FRAMES:
print("timeout reached")
quit(0)
return true
_advance()
return false
func _advance() -> void:
state_frames += 1
match state:
0:
# 2s overview from the guard post (early morning light).
if state_frames >= 120:
_shoot("01-venue-overview.png")
state = 1
state_frames = 0
1:
# Wait for a nearby NPC so the interaction HUD has a target.
if gm != null and gm.npcs.size() > 0:
gm.call("_cycle_nearby_target")
targeted = true
state = 2
state_frames = 0
2:
if state_frames >= 30:
_shoot("02-targeting-npc.png")
if targeted and gm != null:
gm.call("_toggle_inspection")
state = 3
state_frames = 0
3:
if state_frames >= 30:
_shoot("03-access-inspection.png")
if gm != null:
gm.hud.hide_inspection()
if gm.npcs.size() > 0:
gm.call("_cycle_nearby_target")
gm.call("_open_radio", false)
state = 4
state_frames = 0
4:
if state_frames >= 30:
_shoot("04-radio-report.png")
# Close the radio form, then jump the shift to the LATE phase.
if gm != null:
gm.radio_panel.hide()
gm.coordinator.elapsed_s = 750.0
state = 5
state_frames = 0
5:
# Let the phase transition (and street lamps / marquee) settle, then
# take the night avenue shot.
if state_frames >= 90:
_shoot("05-late-night-avenue.png")
if gm != null:
gm.call("_toggle_flashlight")
state = 6
state_frames = 0
6:
if state_frames >= 40:
_shoot("06-night-flashlight.png")
state = 7
quit(0)
func _shoot(file_name: String) -> void:
var dir := DirAccess.open("user://")
if dir == null or not dir.dir_exists("screenshots"):
dir.make_dir_recursive("screenshots")
var img: Image = root.get_texture().get_image()
var err := img.save_png(OUT_DIR.path_join(file_name))
print("%s -> err=%d (%dx%d)" % [file_name, err, img.get_width(), img.get_height()])