extends Control ## Einstieg: hält den Spielstand und wechselt zwischen den Bildschirmen. var profile: Profile var screen: Control var save_path: String = Profile.SAVE_PATH var sfx: Sfx func _ready() -> void: _map_gamepad() theme = Style.make_theme() var bg := Style.Backdrop.new() bg.set_anchors_preset(Control.PRESET_FULL_RECT) bg.mouse_filter = Control.MOUSE_FILTER_IGNORE add_child(bg) sfx = Sfx.new() add_child(sfx) profile = Profile.load_or_new(save_path) apply_settings() show_screen(MenuScreen.new() if profile.started() else StartDeckScreen.new()) func apply_settings() -> void: sfx.set_volume(profile.settings.volume) sfx.set_music_volume(profile.settings.music) set_language(profile.settings.language) Style.font_scale = 1.2 if profile.settings.get("big_font", false) else 1.0 Style.animations = bool(profile.settings.get("animations", true)) theme = Style.make_theme() ## Neues Profil: Sammlung und Fortschritt werden verworfen, das Startdeck wird neu gewählt. func reset_profile() -> void: profile = Profile.starter() save() apply_settings() show_screen(StartDeckScreen.new()) func set_language(code: String) -> void: TranslationServer.set_locale(code) var kept: Array = [] # vorige Bildschirme, zu denen back() zurückführt (Einstellungen aus dem Kampf) ## keep: der aktuelle Bildschirm bleibt erhalten und kommt mit back() zurück. func show_screen(s: Control, keep: bool = false) -> void: if screen != null: if keep: remove_child(screen) kept.append(screen) else: screen.queue_free() for k in kept: k.queue_free() kept.clear() screen = s s.app = self s.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(s) if Style.animations: s.modulate.a = 0.0 create_tween().tween_property(s, "modulate:a", 1.0, 0.15) if pad_mode: focus_first_button.call_deferred() var pad_mode := false # zuletzt Gamepad benutzt: Fokusrahmen sichtbar, Steuerkreuz wechselt Knöpfe ## Gamepad in Menüs: erster Tastendruck setzt den Fokus, Maus nimmt ihn wieder weg. func _input(event: InputEvent) -> void: if event is InputEventJoypadButton or (event is InputEventJoypadMotion and absf(event.axis_value) > 0.5): if not pad_mode: pad_mode = true if get_viewport().gui_get_focus_owner() == null: focus_first_button() elif event is InputEventMouseMotion and pad_mode: pad_mode = false get_viewport().gui_release_focus() ## Gamepad-Tasten für die Menünavigation: A bestätigt, B bricht ab (falls nicht schon zugeordnet). func _map_gamepad() -> void: for pair in [["ui_accept", JOY_BUTTON_A], ["ui_cancel", JOY_BUTTON_B]]: var action: String = pair[0] if not InputMap.has_action(action): InputMap.add_action(action) if not InputMap.action_get_events(action).any(func(e): return e is InputEventJoypadButton): var ev := InputEventJoypadButton.new() ev.button_index = pair[1] ev.device = -1 # jedes Gamepad InputMap.action_add_event(action, ev) func focus_first_button() -> void: if screen == null or screen is BattleScreen: return var b := _first_button(screen) if b != null: b.grab_focus() func _first_button(node: Node) -> Button: for c in node.get_children(): if c is Button and not c.disabled and c.is_visible_in_tree(): return c var found := _first_button(c) if found != null: return found return null ## Zurück: zum gemerkten Bildschirm, sonst ins Hauptmenü. func back() -> void: if kept.is_empty(): show_screen(MenuScreen.new()) return var prev: Control = kept.pop_back() screen.queue_free() screen = prev add_child(prev) func save() -> void: profile.save(save_path)