Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore unversioniert; letztere sind unter ../backups gesichert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
140 lines
5.6 KiB
GDScript
140 lines
5.6 KiB
GDScript
extends Node
|
|
const AI = preload("res://scripts/ai/simple_ai.gd")
|
|
var main: Node3D
|
|
var checks: int = 0
|
|
var failures: Array[String] = []
|
|
var expedition: bool = "--expedition" in OS.get_cmdline_user_args()
|
|
|
|
func check(value: bool, message: String) -> void:
|
|
checks += 1
|
|
if not value:
|
|
failures.append(message)
|
|
printerr("RUNTIME_FAIL: ", message)
|
|
|
|
func key(code: Key) -> void:
|
|
var event := InputEventKey.new()
|
|
event.keycode = code
|
|
event.pressed = true
|
|
get_viewport().push_input(event,true)
|
|
event = event.duplicate()
|
|
event.pressed = false
|
|
get_viewport().push_input(event,true)
|
|
|
|
func _ready() -> void:
|
|
call_deferred("run")
|
|
|
|
func run() -> void:
|
|
GameState.reset_match()
|
|
GameState.factions = ["glutpakt", "glutpakt"]
|
|
GameState.timed_build = true
|
|
GameState.select_mode(GameState.MODE_SHORT)
|
|
main = load("res://scenes/main.tscn").instantiate()
|
|
add_child(main)
|
|
WaveManager.set_physics_process(false)
|
|
await get_tree().process_frame
|
|
main.hud._overlay_action.pressed.emit()
|
|
main.hud._starter_button.pressed.emit()
|
|
await get_tree().process_frame
|
|
var cursor := Vector2(530,360)
|
|
var press := InputEventMouseButton.new()
|
|
press.position = cursor
|
|
press.button_index = MOUSE_BUTTON_MIDDLE
|
|
press.pressed = true
|
|
get_viewport().push_input(press,true)
|
|
var motion := InputEventMouseMotion.new()
|
|
motion.position = cursor + Vector2(90,40)
|
|
motion.relative = Vector2(90,40)
|
|
motion.button_mask = MOUSE_BUTTON_MASK_MIDDLE
|
|
var initial_focus: Vector3 = main._focus
|
|
get_viewport().push_input(motion,true)
|
|
press = press.duplicate()
|
|
press.pressed = false
|
|
get_viewport().push_input(press,true)
|
|
check(main._manual_camera and main._focus != initial_focus, "Middle drag pans and disables auto-follow")
|
|
key(KEY_R)
|
|
check(not main._manual_camera and main._focus.is_equal_approx(initial_focus), "Reset resumes following")
|
|
main.hud._ready_button.grab_focus()
|
|
key(KEY_F1)
|
|
key(KEY_SPACE)
|
|
check(GameState.phase == GameState.Phase.BUILD and main.hud.settings_panel.visible, "Ready button cannot activate behind options")
|
|
key(KEY_ESCAPE)
|
|
check(main.hud._ready_button.has_focus(), "Closing options restores keyboard focus")
|
|
# Exercise volume, mute and lane filtering without altering saved preferences.
|
|
var old_mute: bool = Preferences.muted
|
|
var old_volume: float = Preferences.volume
|
|
Preferences.muted = false
|
|
Preferences.volume = .65
|
|
Preferences.apply()
|
|
Soundscape.enabled = true
|
|
Soundscape.viewed_team = 0
|
|
await get_tree().create_timer(.15).timeout
|
|
check(Soundscape.play("ability"), "An audible effect starts")
|
|
check(not Soundscape.play("ability"), "Immediate duplicate effect is rate-limited")
|
|
check(not Soundscape.play("stone",1,true), "Hidden lane is silent")
|
|
Preferences.muted = true
|
|
Preferences.apply()
|
|
check(not Soundscape.play("error"), "Mute prevents effects")
|
|
Preferences.muted = false
|
|
Preferences.apply()
|
|
# Advance seven regular waves, then render a timed 2x boss fight.
|
|
GameState.ai_level = GameState.AI_LEARNING
|
|
if expedition:
|
|
GameState.reset_match()
|
|
if "--wurzelbund" in OS.get_cmdline_user_args():
|
|
GameState.factions = ["wurzelbund", "wurzelbund"]
|
|
GameState.select_mode(GameState.MODE_EXPEDITION)
|
|
GameState.ai_level = GameState.AI_STANDARD
|
|
WaveManager.start_match()
|
|
var ai := AI.new()
|
|
Soundscape.enabled = false
|
|
var last_wave: int = DataCatalog.wave_count()
|
|
main.battle.render_enabled = false
|
|
for number: int in range(1,last_wave+1):
|
|
ai.plan(0,number,WaveManager.rival_snapshot(),GameState.last_reports[0],GameState.AI_STANDARD)
|
|
if number == last_wave:
|
|
main.battle.render_enabled = true
|
|
WaveManager.ready_for_battle()
|
|
if number == last_wave:
|
|
break
|
|
for step: int in range(5401):
|
|
if GameState.phase != GameState.Phase.COMBAT:
|
|
break
|
|
WaveManager.advance(1.0/60.0)
|
|
WaveManager.ready_for_battle()
|
|
GameState.speed = 2
|
|
Soundscape.enabled = true
|
|
WaveManager.set_physics_process(true)
|
|
await get_tree().create_timer(2.0).timeout
|
|
var frames: Array[float] = []
|
|
var calls: Array[int] = []
|
|
var start: int = Time.get_ticks_usec()
|
|
var previous: int = start
|
|
var sound_start: int = Soundscape.played
|
|
var units_start: int = main.battle.units.size()
|
|
while Time.get_ticks_usec() - start < 12000000:
|
|
await get_tree().process_frame
|
|
var now: int = Time.get_ticks_usec()
|
|
frames.append((now - previous)/1000.0)
|
|
calls.append(int(Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME)))
|
|
previous = now
|
|
frames.sort()
|
|
calls.sort()
|
|
var mean: float = 0
|
|
for value: float in frames:
|
|
mean += value
|
|
mean /= frames.size()
|
|
var sounds: int = Soundscape.played - sound_start
|
|
check(sounds > 0 and sounds <= 190, "2x audio stays bounded and produces effects")
|
|
var result: Dictionary = {"engine": Engine.get_version_info().string, "device": RenderingServer.get_video_adapter_name(),
|
|
"viewport": str(get_viewport().get_visible_rect().size), "wave": last_wave, "speed": 2, "sample_seconds": 12,
|
|
"units_at_start": units_start, "frames":frames.size(),"mean_frame_ms":mean,"p95_frame_ms":frames[floori(frames.size()*.95)],
|
|
"mean_fps":1000.0/mean,"max_draw_calls":calls.back(),"audio_events":sounds,"checks":checks,"failures":failures}
|
|
var phase: String = "phase10" if "--phase10" in OS.get_cmdline_user_args() else "phase9" if "--wurzelbund" in OS.get_cmdline_user_args() else "phase8" if expedition else ("phase7" if "--phase7" in OS.get_cmdline_user_args() else "phase6")
|
|
result["renderer"] = RenderingServer.get_current_rendering_method()
|
|
var file := FileAccess.open("res://docs/" + phase + "-runtime.json", FileAccess.WRITE)
|
|
file.store_string(JSON.stringify(result,"\t")); file.close()
|
|
print("PHASE6_RUNTIME: ",JSON.stringify(result))
|
|
Preferences.volume = old_volume
|
|
Preferences.muted = old_mute
|
|
Preferences.apply()
|
|
await Soundscape.quit_game(0 if failures.is_empty() else 1)
|