@tool extends Node #region configuration signal settings_changed var settings_initialised @export_file var user_settings_path:String = "user://user_settings.json" @export_file var user_saves_path:String = "user://savegames" @export_group("Acessability") @export var reduce_motion: bool = false: set(value): reduce_motion = value if settings_initialised: settings_changed.emit() @export var screen_reader_enabled:bool = false: set(value): screen_reader_enabled = value if settings_initialised: settings_changed.emit() @export var rendering_disabled: bool = false: set(value): rendering_disabled = value if settings_initialised: settings_changed.emit() @export var use_simplified_navigation:bool = false: set(value): use_simplified_navigation = value if settings_initialised: settings_changed.emit() @export var enable_hyperacoustic_filter: bool = false: set(value): enable_hyperacoustic_filter = value if enable_hyperacoustic_filter: AudioServer.set_bus_effect_enabled(0, 0, enable_hyperacoustic_filter) if settings_initialised: settings_changed.emit() @export var show_navigation_buttons: bool = false: set(value): show_navigation_buttons = value if settings_initialised: settings_changed.emit() @export_enum("handwriting", "serif", "legible", "system") var font_style: int = 0: set(value): font_style = value if settings_initialised: settings_changed.emit() @export_enum("disabled", "text", "cc") var subtitles: int = false: set(value): subtitles = value if settings_initialised: settings_changed.emit() @export var ui_scaling: float = 1: set(value): ui_scaling = value ProjectSettings.set_setting("display/window/stretch/scale", value) get_tree().root.content_scale_factor = value @export var show_content_notes: bool = false: set(value): show_content_notes = value if settings_initialised: settings_changed.emit() @export var provide_summaries: bool = false: set(value): provide_summaries = value if settings_initialised: settings_changed.emit() @export var allow_skipping: bool = false: set(value): allow_skipping = value if settings_initialised: settings_changed.emit() # FIXME find a better way to switch fonts and maybe emit the theme_changed signal! var current_main_theme:Theme = preload("res://logic-scenes/themes/handwriting.theme") @export_group("AudioSettings") @export var main_volume:float = 1: set(volume): main_volume = volume AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), linear_to_db(volume)) @export var sfx_muted:bool = false: set(mute): sfx_muted = mute AudioServer.set_bus_volume_db(AudioServer.get_bus_index("sfx"), linear_to_db(mute)) @export var sfx_volume:float = 1: set(volume): sfx_volume = volume AudioServer.set_bus_volume_db(AudioServer.get_bus_index("sfx"), linear_to_db(volume/2)) @export var music_muted:bool = false: set(mute): sfx_muted = mute AudioServer.set_bus_volume_db(AudioServer.get_bus_index("sfx"), linear_to_db(mute)) @export var music_volume:float = 1: set(volume): music_volume = volume AudioServer.set_bus_volume_db(AudioServer.get_bus_index("music"), linear_to_db(volume/2.5)) @export var speech_volume: float = 1: set(volume): speech_volume = volume AudioServer.set_bus_volume_db(AudioServer.get_bus_index("text"), linear_to_db(volume)) @export var force_stereo: bool = false: set(stereo): if stereo != force_stereo: force_stereo = stereo settings_changed.emit() @export var disconnect_steam:bool = false: set(disconnect): if disconnect and not disconnect_steam: Steam.steamShutdown() Steamworks.has_initialized = false elif not disconnect and disconnect_steam: Steamworks._ready() disconnect_steam = disconnect @export var obscure_logs:bool = true @export_enum("system_locale", "english", "german") var text_language: int = 0: set(value): text_language = value match text_language: 1: TranslationServer.set_locale("en") 2: TranslationServer.set_locale("de") _: TranslationServer.set_locale(OS.get_locale()) settings_changed.emit() @export_enum("system_locale", "english", "german") var speech_language: int = 0: set(value): speech_language = value @export_group("Gameplay Settings") @export var input_sensitivity: float = 1.0 @export var fov: float = 35.0 @export var inverty_y_axis: bool = false @export var inverty_y_mouse: bool = false @export_enum("off", "top_left", "top_right", "bottom_left", "bottom_right") var stream_overlay_position: int # for passing VFX settings not contained by project settings to scene environemnt var ssil_enable:bool = false: set(value): ssil_enable = value environment_settings_changed.emit() var sdfgi_enable:bool = false: set(value): sdfgi_enable = value environment_settings_changed.emit() var active_save_game: SaveGame signal environment_settings_changed signal theme_changed func load_user_settings(): if FileAccess.file_exists(user_settings_path): var file = FileAccess.open(user_settings_path, FileAccess.READ) var raw_json = FileAccess.get_file_as_string(user_settings_path) file.close() var parsed: Dictionary = JSON.parse_string(raw_json) for kategory in parsed.values(): for key in kategory.keys(): if key in self: set(key, parsed[key]) else: if OS.has_feature("macos"): var out: Array OS.execute("defaults", ["read", "/Users/$loggedInUser/Library/Preferences/com.apple.universalaccess.plist", "reduceMotion"], out) if out[0] == "reduce": reduce_motion = true settings_initialised = true settings_changed.emit() func save_settings(): var out_dict = { "accessability": { "reduce_motion:": reduce_motion, "screen_reader_enabled": screen_reader_enabled, "rendering_disabled": rendering_disabled, "use_simplified_navigation": use_simplified_navigation, "show_navigation_buttons": show_navigation_buttons, "subtitles": subtitles, "font_style": font_style, "ui_scaling": ui_scaling, "show_content_notes:": show_content_notes, "provide_summaries:": provide_summaries, "allow_skipping:": allow_skipping }, "audio": { "main_volume": main_volume, "sfx_muted": sfx_muted, "sfx_volume": sfx_volume, "music_muted": music_muted, "music_volume": music_volume, "speech_volume": speech_volume, "speech_language": speech_language, "text_language": text_language, "force_stereo": force_stereo }, "gameplay": { "input_sensitivity": input_sensitivity, "inverty_y_axis": inverty_y_axis, "inverty_y_mouse": inverty_y_mouse, "fov": fov, "stream_overlay_position": stream_overlay_position }, "privacy": { "disconnect_steam": disconnect_steam, "obscure_logs": obscure_logs } } var file = FileAccess.open(user_settings_path, FileAccess.WRITE) file.store_string(JSON.stringify(out_dict)) file.close() settings_initialised = true settings_changed.emit() var last_mode := DisplayServer.WINDOW_MODE_WINDOWED func _unhandled_input(event: InputEvent) -> void: #FIXME this can be removed when state no longer needs to be a tool if not Engine.is_editor_hint(): if event.is_action_pressed("toggle_fullscreen"): # I have no idea why I wrote thit as conviluted, # but it works(TM) so I am not gonna change it :D if DisplayServer.window_get_mode() == DisplayServer.WINDOW_MODE_FULLSCREEN: DisplayServer.window_set_mode(last_mode) else: last_mode = DisplayServer.window_get_mode() DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) #endregion func _ready(): await get_tree().process_frame for child in get_tree().root.get_children(): if child is RoomTemplate and active_save_game == null: push_warning("Room initialised without a SaveGame. Creating proxy save.") #TODO: make this a bit more clean maybe? active_save_game = ResourceLoader.load("res://dev-util/debug_save.tres") if "has_stage" in child: pass_stage_to(child) break music_volume = music_volume #region focus handling (called staging to avoid name colisions) # CAUTION: scene_reference directly accesses stage list to play sequences. var stage_list:Array = [] var focus_locked: bool = false # Intented for use when an actor wants focus for itself, can reclaim focus, thus dropping the stack that focused. func take_stage(actor: Object, reclaim: bool = false) -> bool: if focus_locked or Scenes.current_sequence != -1: return false if reclaim: stage_list.front().has_stage = false if stage_list.has(actor): while stage_list.pop_front() != actor: break actor.has_stage = true stage_list.push_front(actor) return actor.has_stage push_warning(actor, " wanted to reclaim focus, but was not on list.") return pass_stage_to(actor) # Element no longer wants focus, if Element itself is also dropped, this option can be chosen aswell. func leave_stage(actor:Object) -> bool: if stage_list[0] == actor: actor.has_stage = false focus_locked = false stage_list.erase(actor) if stage_list != []: stage_list.front().has_stage = true else: get_tree().quit() return false func get_current_actor(): return stage_list.front() # Used to put a new target on top of the Focus Stack. func pass_stage_to(target:Object, force = false, lock_focus = false) -> bool: if "pass_to_actor" in target: return pass_stage_to(target.pass_to_actor) if (focus_locked or get_tree().paused) and not force: push_error(target, " requested focus while it was locked or tree is paused.") elif !is_instance_valid(target): push_error("Focus instance not valid") elif !"has_stage" in target: push_error(target, " has no has focus method.") else: if stage_list.size() > 0: if stage_list.front() == target: push_warning(target, " is already target. Abort passing focus.") return false if not stage_list.size() == 0: stage_list.front().has_stage = false target.has_stage = true if target.has_stage: stage_list.push_front(target) assert(stage_list.size() < 100) focus_locked = lock_focus return true return false # Currently focused element loses focus, but remains in stack. func free_focus(): if focus_locked: return false if stage_list.size() > 0: stage_list.front().has_stage = false func reset_focus(): stage_list = [stage_list[-1]] func transition_stage_to(thief: Object, lock_focus = false): focus_locked = lock_focus if stage_list.size() > 0: if stage_list.front().has_stage: stage_list.pop_front().has_stage = false return pass_stage_to(thief, true) func queue_for_stage(target: Object, index: int = 1): stage_list.insert(index, target) #endregion #region play state enum rooms { NULL, YOUTH, TRANSITION, ADULTHOOD, ENDING } enum sequences { DRAEVEN, CHILDHOOD, VOICE, JUI_JUTSU, TRANS, AUTISM, UNI_START, VOLUNTARY, UNI_CONTINUE, UNI_ALT, THERAPY, BURNOUT } var current_room: rooms = rooms.NULL var onready_room: rooms = rooms.NULL