extends Node var master_volume: float = 1.0 var sfx_muted: bool = false var music_volume: float = 0.8 var fullscreen: bool = false var nebula_enabled: bool = true var star_density: int = 1 # 0=low 1=mid 2=high var language: String = "de" # "de" or "en" var touch_mode: int = 0 # 0=auto, 1=always on, 2=always off # Runtime-only — not saved. Set by input detection in main.gd / touch_controls.gd. var last_input_device: String = "keyboard" # "keyboard" | "pad" | "touch" # Rebindable gameplay actions (P1 only). const REBIND_ACTIONS: Array[String] = ["p1_thrust", "p1_left", "p1_right", "p1_shoot", "p1_wipe"] # Stores physical keycodes (int) for rebound keys. Empty = use project defaults. var key_bindings: Dictionary = {} const PATH := "user://settings.cfg" func _ready() -> void: load_settings() apply_all() func apply_all() -> void: apply_volume() apply_key_bindings() # Mobile always runs fullscreen — ignore the saved setting. if OS.has_feature("android") or OS.has_feature("ios"): DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) elif fullscreen: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) func apply_volume() -> void: var db := linear_to_db(master_volume) if not sfx_muted else -80.0 AudioServer.set_bus_volume_db(0, db) func apply_music_volume() -> void: var bus_idx := AudioServer.get_bus_index("Music") if bus_idx != -1: AudioServer.set_bus_volume_db(bus_idx, linear_to_db(music_volume) if music_volume > 0.0 else -80.0) func apply_key_bindings() -> void: for action: String in key_bindings: var keycode: int = key_bindings[action] if keycode > 0 and InputMap.has_action(action): # Remove existing keyboard events for this action var events := InputMap.action_get_events(action) for ev in events: if ev is InputEventKey: InputMap.action_erase_event(action, ev) # Add the custom key var new_ev := InputEventKey.new() new_ev.physical_keycode = keycode as Key InputMap.action_add_event(action, new_ev) func reset_key_bindings() -> void: InputMap.load_from_project_settings() key_bindings.clear() save_settings() func save_settings() -> void: var cfg := ConfigFile.new() cfg.set_value("sound", "volume", master_volume) cfg.set_value("sound", "muted", sfx_muted) cfg.set_value("sound", "music", music_volume) cfg.set_value("graphics", "fullscreen", fullscreen) cfg.set_value("graphics", "nebula", nebula_enabled) cfg.set_value("graphics", "stars", star_density) cfg.set_value("game", "language", language) cfg.set_value("game", "touch_mode", touch_mode) for action: String in REBIND_ACTIONS: if key_bindings.has(action): cfg.set_value("bindings", action, key_bindings[action]) cfg.save(PATH) func load_settings() -> void: var cfg := ConfigFile.new() if cfg.load(PATH) != OK: return master_volume = cfg.get_value("sound", "volume", 1.0) sfx_muted = cfg.get_value("sound", "muted", false) music_volume = cfg.get_value("sound", "music", 0.8) fullscreen = cfg.get_value("graphics", "fullscreen", false) nebula_enabled = cfg.get_value("graphics", "nebula", true) star_density = cfg.get_value("graphics", "stars", 1) language = cfg.get_value("game", "language", "de") touch_mode = cfg.get_value("game", "touch_mode", 0) key_bindings.clear() for action: String in REBIND_ACTIONS: if cfg.has_section_key("bindings", action): key_bindings[action] = cfg.get_value("bindings", action)