saumwacht-godot/scripts/luneraria/ui/lune_settings.gd
Martin Stickelbroeck 1b540f2a55 G3 (Zwischenstand): neues Ingame-HUD; Projekt wechselt nach Unity
Nicht abgenommen: Nach dem ersten Spieltest wurde entschieden, Champions of
Luneraria nach Unity 6 zu portieren. Dieser Stand ist die Referenz für das
HUD im Unity-Projekt (../luneraria-unity).

- HUD neu aus Komponenten mit eigenem Theme, Porträts aus den echten Modellen
  (einmal gerendert, zwischengespeichert), Lane-Übersicht mit deterministischer
  Bedrohung aus öffentlichem Zustand, Bossgrotte, nächste Welle, Ereignisse,
  Minimap mit zusammengefassten Armeen, Held/Items/Talente, Einheitendetails,
  Angriffschampions, Bereit-Sperre, UI-Größe, Team-Formen statt nur Farben
- Privatsphäre über LuneHudModel: fremdes Gold und fremde Entwürfe erscheinen nie
- Keine Regeländerung: Regeln 91/91, M2 73/73, Netz 43/43; verify_g3 715/715;
  verify_m1 38/38 und verify_m2 14/14 mit angepassten UI-Treibern
- Spieltest bis Welle 8 über die echte Oberfläche, Befunde in G3-HUD.md
- HELDEN-KONZEPT.md: vom Projektinhaber vorgegebene Helden (nicht umgesetzt)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 19:59:55 +02:00

121 lines
5.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class_name LuneSettings
extends ColorRect
## Options and controls for Champions of Luneraria; the same Preferences as before plus the
## HUD size. The key list is the one place where every shortcut is shown.
signal closed
const SCALES: Array[float] = [.9, 1.0, 1.15, 1.3]
const KEYS: Array = [
["Planung", [["1–5", "Truppe kaufen"], ["Leertaste", "Bereit"], ["Klick auf Einheit", "Details, Aufwerten, Einsatz"], ["Esc", "Auswahl oder Fenster schließen"]]],
["Kampf", [["Leertaste / P", "Pause (offline)"], ["Tempo-Knopf", "1× · 2× · 4×"]]],
["Kamera", [["F2 · F3 · F4", "Top · Mid · Bottom"], ["G", "Bossgrotte"], ["B", "eigener Ancient"], ["H", "eigener Held"],
["Tab", "nächste Lane"], ["O", "Übersicht"], ["R", "zurücksetzen"], ["Q / E", "drehen"], ["WASD · Pfeile · mittlere Maustaste", "verschieben"],
["Mausrad", "Zoom"], ["Minimap", "klicken oder ziehen"]]],
["Allgemein", [["F1", "Optionen"], ["M", "Ton an/aus"], ["F11", "Vollbild"]]],
]
var _volume: HSlider
var _checks: Dictionary = {}
var _scale: ChoiceGroup
func _ready() -> void:
theme = LuneUiTheme.shared()
color = Color(.02, .03, .04, .9)
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
mouse_filter = Control.MOUSE_FILTER_STOP
var center := CenterContainer.new()
center.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(center)
var panel := PanelContainer.new()
panel.theme_type_variation = "MenuPanel"
panel.custom_minimum_size.x = 900
center.add_child(panel)
var column := VBoxContainer.new()
column.add_theme_constant_override("separation", 10)
panel.add_child(column)
var heading := _label("Optionen & Steuerung", "HeadingLabel", column)
heading.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_label("Ein laufender Kampf pausiert offline, solange dieses Fenster geöffnet ist.", "MutedLabel", column).horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
var top := HBoxContainer.new()
top.add_theme_constant_override("separation", 30)
column.add_child(top)
var left := VBoxContainer.new()
left.add_theme_constant_override("separation", 8)
left.size_flags_horizontal = Control.SIZE_EXPAND_FILL
top.add_child(left)
_label("LAUTSTÄRKE", "SectionLabel", left)
_volume = HSlider.new()
_volume.max_value = 100
_volume.custom_minimum_size.y = 28
left.add_child(_volume)
_volume.value_changed.connect(func(value: float) -> void:
Preferences.volume = value / 100.0
Preferences.commit())
for entry: Array in [["muted", "Ton stumm [M]"], ["fullscreen", "Vollbild [F11]"], ["reduced_motion", "Bewegung reduzieren"]]:
var check := CheckButton.new()
check.text = entry[1]
left.add_child(check)
var key: String = entry[0]
check.toggled.connect(func(value: bool) -> void:
Preferences.set(key, value)
Preferences.commit())
_checks[key] = check
var right := VBoxContainer.new()
right.add_theme_constant_override("separation", 8)
right.size_flags_horizontal = Control.SIZE_EXPAND_FILL
top.add_child(right)
_label("UI-GRÖSSE IM SPIEL", "SectionLabel", right)
_scale = ChoiceGroup.new(true)
for value: float in SCALES:
_scale.add_option("%d %%" % int(round(value * 100.0)))
right.add_child(_scale)
_scale.item_selected.connect(func(index: int) -> void:
Preferences.ui_scale = SCALES[index]
Preferences.commit())
var note := _label("Größer für hochauflösende oder weit entfernte Bildschirme. Das HUD begrenzt die Größe selbst, sodass nichts aus dem Fenster ragt.", "MutedLabel", right)
note.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
column.add_child(HSeparator.new())
_label("STEUERUNG", "SectionLabel", column)
var keys := HBoxContainer.new()
keys.add_theme_constant_override("separation", 26)
column.add_child(keys)
for index: int in range(2):
var list := GridContainer.new()
list.columns = 2
list.add_theme_constant_override("h_separation", 14)
list.add_theme_constant_override("v_separation", 2)
list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
keys.add_child(list)
for group: Array in (KEYS.slice(0, 2) + [KEYS[3]] if index == 0 else [KEYS[2]]):
var caption := _label(str(group[0]).to_upper(), "EyebrowLabel", list)
caption.add_theme_font_size_override("font_size", 14)
list.add_child(Control.new())
for pair: Array in group[1]:
var key_label := _label(str(pair[0]), "CardFactLabel", list)
key_label.add_theme_font_size_override("font_size", 15)
key_label.add_theme_color_override("font_color", LuneUiTheme.BRONZE_LIGHT)
var action := _label(str(pair[1]), "MutedLabel", list)
action.add_theme_font_size_override("font_size", 15)
var back := Button.new()
back.text = "ZURÜCK [Esc]"
back.theme_type_variation = "PrimaryButton"
back.pressed.connect(func() -> void: closed.emit())
column.add_child(back)
func _label(text_value: String, variation: String, parent: Node) -> Label:
var label := Label.new()
label.text = text_value
label.theme_type_variation = variation
parent.add_child(label)
return label
func sync() -> void:
_volume.set_value_no_signal(Preferences.volume * 100.0)
for key: String in _checks:
(_checks[key] as CheckButton).set_pressed_no_signal(bool(Preferences.get(key)))
var best: int = 1
for index: int in range(SCALES.size()):
if absf(SCALES[index] - Preferences.ui_scale) < absf(SCALES[best] - Preferences.ui_scale):
best = index
_scale.select(best)