Top windet sich über das Hochland, Mid quert die Kluft über die Mittelplattform, Bottom führt durch das Tiefland über die Deltabrücke; Top und Bottom sind exakt gleich lang, alles bleibt spiegelsymmetrisch. LuneTerrain liefert ein exakt gespiegeltes Höhenfeld, auf dem Figuren stehen. Bossgrotte als Terrasse auf der Achse zwischen Top und Mid, Aufmarschbereiche je Lane, perspektivische Kamera mit Sprungtasten (F2–F4, B, G, H, O, R, Q/E). Bestandsassets wiederverwendet, neue Formen als Blockout für G2/G4. Geprüft: verify_g1 443/443, Regeln 91/91, M2 73/73, verify_m1 38/38, verify_m2 14/14, Netz 43/43, Loopback 12/12, Balance 40 Partien (Seitentausch 20/20), Legacy 209/463. Vorher/Nachher-Aufnahmen und Messungen in G1-KARTE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
136 lines
5.3 KiB
GDScript
136 lines
5.3 KiB
GDScript
extends Node
|
||
## Comparison captures for the graphics phases G1–G6, always from the real game camera
|
||
## and the real HUD at the running window size (use 1920x1080).
|
||
## Run: godot --path . --resolution 1920x1080 res://tools/luneraria/g_views.tscn -- --out=res://docs/luneraria/screenshots/g1/nachher
|
||
## Views: 01 map, 02–04 lanes in combat, 05/06 bases, 07 grotto, 08 many units, 09 HUD,
|
||
## 10 hero selected, 11 close zoom, 12 camera in motion. Match and fixture are fixed
|
||
## (seed 4, Wurzelbund on Mid) so every phase is photographed the same way. Fixture gold
|
||
## only exists in this capture run; the rules are the ones of the running build.
|
||
const Game = preload("res://scripts/luneraria/lune_game.gd")
|
||
|
||
var out: String = "res://docs/luneraria/screenshots/g1/nachher/"
|
||
var main: Node
|
||
var shots: Array[String] = []
|
||
|
||
func _ready() -> void:
|
||
for arg: String in OS.get_cmdline_user_args():
|
||
if arg.begins_with("--out="):
|
||
out = arg.substr(6)
|
||
if not out.ends_with("/"):
|
||
out += "/"
|
||
call_deferred("run")
|
||
|
||
func shot(label: String, frames: int = 14) -> void:
|
||
for i: int in frames:
|
||
await get_tree().process_frame
|
||
await RenderingServer.frame_post_draw
|
||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(out))
|
||
get_viewport().get_texture().get_image().save_png(out + label + ".png")
|
||
shots.append(label)
|
||
print("G_VIEW ", label)
|
||
|
||
## Camera helpers that only use public map data, so they frame old and new layouts alike.
|
||
func grotto_point(game: Node3D) -> Vector2:
|
||
var map: LuneMap = game.match_state.map
|
||
return map.grotto_center() if map.has_method("grotto_center") else LuneMap.GROTTO
|
||
|
||
func look(game: Node3D, at: Vector2, zoom: float) -> void:
|
||
game.camera.look_at_point(Vector3(at.x, 0, at.y), zoom, true)
|
||
|
||
## Runs the combat clock quickly (more fixed steps per frame, rules unchanged) and holds it.
|
||
func advance_combat(game: Node3D, seconds: float) -> void:
|
||
var state: LuneMatch = game.match_state
|
||
game.paused = false
|
||
while state.phase == LuneMatch.Phase.COMBAT and state.combat.elapsed < seconds:
|
||
for i: int in range(20):
|
||
if state.phase != LuneMatch.Phase.COMBAT or state.combat.elapsed >= seconds:
|
||
break
|
||
state.step_combat()
|
||
await get_tree().process_frame
|
||
game.paused = true
|
||
|
||
## Documentation only (not a game view): orthographic top-down plan without the HUD.
|
||
func plan_view(game: Node3D) -> void:
|
||
var plan := Camera3D.new()
|
||
plan.projection = Camera3D.PROJECTION_ORTHOGONAL
|
||
plan.size = 86.0
|
||
plan.far = 400.0
|
||
game.add_child(plan)
|
||
plan.position = Vector3(0, 150, 0)
|
||
plan.rotation = Vector3(-PI * .5, 0, 0)
|
||
plan.current = true
|
||
game.hud.visible = false
|
||
await shot("00-kartenplan-draufsicht", 10)
|
||
game.hud.visible = true
|
||
game.camera.current = true
|
||
plan.queue_free()
|
||
|
||
func run() -> void:
|
||
Soundscape.enabled = false
|
||
main = load("res://scenes/luneraria.tscn").instantiate()
|
||
add_child(main)
|
||
var menu: MainMenu = main.menu
|
||
while not (menu.stage.is_ready("glutpakt") and menu.stage.is_ready("wurzelbund")):
|
||
await get_tree().process_frame
|
||
menu.bund = "wurzelbund"
|
||
menu.lane = "mid"
|
||
main.start_match({"seed": 4})
|
||
await get_tree().create_timer(.8).timeout
|
||
var game: Node3D = main.game
|
||
var state: LuneMatch = game.match_state
|
||
var slot: int = game.human_slot
|
||
# Fixture: enough gold for a hero with one item next to the starting army.
|
||
state.players[slot].draft.gold = 900
|
||
game._on_command({"type": "hero_buy", "hero_id": "held_ringborke"})
|
||
game._on_command({"type": "item_buy", "item_id": "basaltschild"})
|
||
game.hud._starter.pressed.emit()
|
||
game.hud.show_page(0)
|
||
game.focus_lane("mid", true)
|
||
await shot("09-hud-planung", 24)
|
||
game.hud.show_page(1)
|
||
await shot("10-held-ausgewaehlt")
|
||
game.hud.show_page(0)
|
||
game.camera.overview(true)
|
||
await shot("01-karte", 20)
|
||
await plan_view(game)
|
||
look(game, state.map.core_position(0), 26.0)
|
||
await shot("05-eigene-basis")
|
||
look(game, state.map.core_position(1), 26.0)
|
||
await shot("06-gegnerbasis")
|
||
look(game, grotto_point(game), 22.0)
|
||
await shot("07-bossgrotte")
|
||
game._on_ready()
|
||
await get_tree().process_frame
|
||
await advance_combat(game, 16.0)
|
||
var names := {"top": "02-top-lane", "mid": "03-mid-lane", "bot": "04-bottom-lane"}
|
||
for lane: String in LuneMap.LANES:
|
||
game.focus_lane(lane, true)
|
||
await shot(names[lane])
|
||
# Camera in motion: a real, non-instant pan from Mid towards the own base.
|
||
game.focus_lane("mid", true)
|
||
await get_tree().process_frame
|
||
var base: Vector2 = state.map.core_position(0)
|
||
game.camera.look_at_point(Vector3(base.x, 0, base.y), 30.0, false)
|
||
await shot("12-kamera-bewegt", 5)
|
||
# Many units: all six armies at the supply cap in a round-13 wave (capture fixture).
|
||
main.queue_free()
|
||
await get_tree().process_frame
|
||
var crowd: Node3D = Game.new()
|
||
add_child(crowd)
|
||
crowd.start({"seed": 5, "human_slot": 1})
|
||
var crowd_state: LuneMatch = crowd.match_state
|
||
crowd_state.round_number = 13
|
||
for other: int in range(6):
|
||
crowd_state.players[other].draft.gold = 100000
|
||
crowd_state.players[other].draft.roster.clear()
|
||
LuneBot.plan(crowd_state, other, "ausgewogen")
|
||
crowd._on_ready()
|
||
await get_tree().process_frame
|
||
await advance_combat(crowd, 13.0)
|
||
crowd.focus_lane("mid", true)
|
||
await shot("08-kampf-viele-einheiten", 20)
|
||
var fight: Vector2 = crowd_state.map.lane_point(0, "mid", crowd_state.map.lanes["mid"].length * .5)
|
||
look(crowd, fight, 13.0)
|
||
await shot("11-zoom-nah")
|
||
print("G_VIEWS_DONE ", shots.size())
|
||
get_tree().quit()
|