2025-12-13 19:11:51 +00:00
|
|
|
extends Node
|
2025-12-12 23:22:21 +00:00
|
|
|
class_name GlobalState
|
2024-10-01 23:32:59 +00:00
|
|
|
|
|
|
|
|
#region configuration
|
2025-03-23 13:20:50 +00:00
|
|
|
signal settings_changed
|
2025-12-12 23:22:21 +00:00
|
|
|
var _settings_initialized
|
|
|
|
|
|
2026-01-22 10:02:58 +00:00
|
|
|
var room: Room
|
2025-12-12 23:22:21 +00:00
|
|
|
var save_game: SaveGame
|
|
|
|
|
signal environment_settings_changed
|
|
|
|
|
|
|
|
|
|
# FIXME find a better way to switch fonts and maybe emit the theme_changed signal!
|
|
|
|
|
signal theme_changed
|
|
|
|
|
var current_main_theme:Theme = preload("res://logic-scenes/themes/handwriting.theme")
|
2025-03-23 13:20:50 +00:00
|
|
|
|
2026-01-15 12:04:52 +00:00
|
|
|
var player : PlayerController
|
|
|
|
|
var player_view : Camera3D
|
|
|
|
|
|
2025-12-13 11:52:25 +00:00
|
|
|
func set_theme(new_theme:Theme):
|
|
|
|
|
current_main_theme = new_theme
|
|
|
|
|
theme_changed.emit(new_theme)
|
|
|
|
|
|
2026-01-16 12:59:09 +00:00
|
|
|
const user_settings_path:String = "user://user_settings.json"
|
|
|
|
|
const user_saves_path:String = "user://savegames"
|
2024-10-01 23:32:59 +00:00
|
|
|
|
|
|
|
|
@export_group("Acessability")
|
2025-03-23 13:20:50 +00:00
|
|
|
@export var reduce_motion: bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
reduce_motion = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export var screen_reader_enabled:bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
screen_reader_enabled = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-03-23 13:20:50 +00:00
|
|
|
@export var rendering_disabled: bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
rendering_disabled = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export var use_simplified_navigation:bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
use_simplified_navigation = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
2024-10-21 09:39:16 +00:00
|
|
|
@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)
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export var show_navigation_buttons: bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
show_navigation_buttons = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export_enum("handwriting", "serif", "legible", "system") var font_style: int = 0:
|
|
|
|
|
set(value):
|
|
|
|
|
font_style = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export_enum("disabled", "text", "cc") var subtitles: int = false:
|
|
|
|
|
set(value):
|
|
|
|
|
subtitles = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
2024-10-18 13:42:53 +00:00
|
|
|
@export var ui_scaling: float = 1:
|
|
|
|
|
set(value):
|
|
|
|
|
ui_scaling = value
|
2025-10-07 22:33:15 +00:00
|
|
|
ProjectSettings.set_setting("display/window/stretch/scale", value)
|
|
|
|
|
get_tree().root.content_scale_factor = value
|
2025-03-23 13:20:50 +00:00
|
|
|
@export var show_content_notes: bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
show_content_notes = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export var provide_summaries: bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
provide_summaries = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
|
|
|
|
@export var allow_skipping: bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
allow_skipping = value
|
2025-12-12 23:22:21 +00:00
|
|
|
if _settings_initialized:
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
2024-10-01 23:32:59 +00:00
|
|
|
|
|
|
|
|
@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))
|
2025-05-09 15:34:45 +00:00
|
|
|
@export var force_stereo: bool = false:
|
|
|
|
|
set(stereo):
|
|
|
|
|
if stereo != force_stereo:
|
|
|
|
|
force_stereo = stereo
|
|
|
|
|
settings_changed.emit()
|
2025-06-04 13:25:23 +00:00
|
|
|
@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
|
2025-05-09 15:34:45 +00:00
|
|
|
@export var obscure_logs:bool = true
|
|
|
|
|
|
|
|
|
|
|
2025-08-16 14:20:24 +00:00
|
|
|
@export_enum("system_locale", "english", "german") var text_language: int = 0:
|
2024-10-18 13:42:53 +00:00
|
|
|
set(value):
|
|
|
|
|
text_language = value
|
2025-08-13 18:24:28 +00:00
|
|
|
match text_language:
|
2025-03-28 12:41:18 +00:00
|
|
|
1: TranslationServer.set_locale("en")
|
|
|
|
|
2: TranslationServer.set_locale("de")
|
2024-10-18 13:42:53 +00:00
|
|
|
_: TranslationServer.set_locale(OS.get_locale())
|
2025-05-21 09:13:44 +00:00
|
|
|
settings_changed.emit()
|
2025-08-16 14:20:24 +00:00
|
|
|
@export_enum("system_locale", "english", "german") var speech_language: int = 0:
|
2024-10-18 13:42:53 +00:00
|
|
|
set(value):
|
2024-10-18 16:15:46 +00:00
|
|
|
speech_language = value
|
2024-10-01 23:32:59 +00:00
|
|
|
|
|
|
|
|
@export_group("Gameplay Settings")
|
2025-10-07 22:33:15 +00:00
|
|
|
@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
|
2024-10-01 23:32:59 +00:00
|
|
|
@export_enum("off", "top_left", "top_right", "bottom_left", "bottom_right") var stream_overlay_position: int
|
2023-04-15 14:01:22 +00:00
|
|
|
|
2024-10-18 13:42:53 +00:00
|
|
|
# for passing VFX settings not contained by project settings to scene environemnt
|
2024-09-27 20:02:28 +00:00
|
|
|
var ssil_enable:bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
ssil_enable = value
|
|
|
|
|
environment_settings_changed.emit()
|
2025-12-13 19:11:51 +00:00
|
|
|
|
2024-09-27 20:02:28 +00:00
|
|
|
var sdfgi_enable:bool = false:
|
|
|
|
|
set(value):
|
|
|
|
|
sdfgi_enable = value
|
|
|
|
|
environment_settings_changed.emit()
|
|
|
|
|
|
2024-02-03 21:00:44 +00:00
|
|
|
|
2024-10-01 23:32:59 +00:00
|
|
|
func load_user_settings():
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2024-10-01 23:32:59 +00:00
|
|
|
if FileAccess.file_exists(user_settings_path):
|
2025-12-12 23:22:21 +00:00
|
|
|
var file := FileAccess.open(user_settings_path, FileAccess.READ)
|
|
|
|
|
var raw_json := FileAccess.get_file_as_string(user_settings_path)
|
2024-10-01 23:32:59 +00:00
|
|
|
file.close()
|
|
|
|
|
var parsed: Dictionary = JSON.parse_string(raw_json)
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-03-28 12:41:18 +00:00
|
|
|
for kategory in parsed.values():
|
|
|
|
|
for key in kategory.keys():
|
2025-10-29 21:20:04 +00:00
|
|
|
if key in self:
|
|
|
|
|
set(key, parsed[key])
|
2024-10-01 23:32:59 +00:00
|
|
|
|
|
|
|
|
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
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-12-12 23:22:21 +00:00
|
|
|
_settings_initialized = true
|
2025-05-16 23:52:47 +00:00
|
|
|
settings_changed.emit()
|
2024-10-01 23:32:59 +00:00
|
|
|
|
|
|
|
|
func save_settings():
|
2025-12-12 23:22:21 +00:00
|
|
|
var out_dict := {
|
2024-10-01 23:32:59 +00:00
|
|
|
"accessability": {
|
2024-10-18 13:42:53 +00:00
|
|
|
"reduce_motion:": reduce_motion,
|
2024-10-01 23:32:59 +00:00
|
|
|
"screen_reader_enabled": screen_reader_enabled,
|
|
|
|
|
"rendering_disabled": rendering_disabled,
|
|
|
|
|
"use_simplified_navigation": use_simplified_navigation,
|
|
|
|
|
"show_navigation_buttons": show_navigation_buttons,
|
|
|
|
|
"subtitles": subtitles,
|
2024-10-18 13:42:53 +00:00
|
|
|
"font_style": font_style,
|
|
|
|
|
"ui_scaling": ui_scaling,
|
2024-10-01 23:32:59 +00:00
|
|
|
"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,
|
2025-03-28 12:41:18 +00:00
|
|
|
"speech_volume": speech_volume,
|
|
|
|
|
"speech_language": speech_language,
|
2025-05-16 12:30:52 +00:00
|
|
|
"text_language": text_language,
|
2025-05-09 15:34:45 +00:00
|
|
|
"force_stereo": force_stereo
|
2024-10-01 23:32:59 +00:00
|
|
|
},
|
|
|
|
|
"gameplay": {
|
|
|
|
|
"input_sensitivity": input_sensitivity,
|
|
|
|
|
"inverty_y_axis": inverty_y_axis,
|
2025-10-07 22:33:15 +00:00
|
|
|
"inverty_y_mouse": inverty_y_mouse,
|
|
|
|
|
"fov": fov,
|
2024-10-01 23:32:59 +00:00
|
|
|
"stream_overlay_position": stream_overlay_position
|
2025-05-09 15:37:33 +00:00
|
|
|
},
|
|
|
|
|
"privacy": {
|
|
|
|
|
"disconnect_steam": disconnect_steam,
|
|
|
|
|
"obscure_logs": obscure_logs
|
2024-10-01 23:32:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-12-12 23:22:21 +00:00
|
|
|
var file := FileAccess.open(user_settings_path, FileAccess.WRITE)
|
2024-10-01 23:32:59 +00:00
|
|
|
file.store_string(JSON.stringify(out_dict))
|
|
|
|
|
file.close()
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-12-12 23:22:21 +00:00
|
|
|
_settings_initialized = true
|
2025-03-23 13:20:50 +00:00
|
|
|
settings_changed.emit()
|
2024-10-01 23:32:59 +00:00
|
|
|
|
2025-02-06 17:55:05 +00:00
|
|
|
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"):
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-02-06 17:55:05 +00:00
|
|
|
# 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)
|
|
|
|
|
|
2024-10-01 23:32:59 +00:00
|
|
|
#endregion
|
|
|
|
|
|
2023-06-30 23:14:25 +00:00
|
|
|
func _ready():
|
2025-09-04 23:54:21 +00:00
|
|
|
await get_tree().process_frame
|
2024-10-01 23:32:59 +00:00
|
|
|
music_volume = music_volume
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2023-06-30 23:14:25 +00:00
|
|
|
|
2024-10-01 23:32:59 +00:00
|
|
|
#region focus handling (called staging to avoid name colisions)
|
2023-07-11 13:27:44 +00:00
|
|
|
|
2025-02-06 17:55:05 +00:00
|
|
|
# CAUTION: scene_reference directly accesses stage list to play sequences.
|
|
|
|
|
|
2024-10-18 13:42:53 +00:00
|
|
|
var stage_list:Array = []
|
|
|
|
|
var focus_locked: bool = false
|
|
|
|
|
|
2023-07-11 13:27:44 +00:00
|
|
|
# Intented for use when an actor wants focus for itself, can reclaim focus, thus dropping the stack that focused.
|
2026-01-09 10:10:56 +00:00
|
|
|
func take_stage(actor: Object, _reclaim: bool = false) -> void:
|
2026-01-21 21:35:35 +00:00
|
|
|
print(">>> take_stage(", actor,")");
|
2026-01-09 10:10:56 +00:00
|
|
|
assert(not focus_locked, "Focus is locked, %s cannot take focus." % actor)
|
|
|
|
|
stage_list.push_front(actor)
|
|
|
|
|
|
2023-06-25 20:40:31 +00:00
|
|
|
|
|
|
|
|
# Element no longer wants focus, if Element itself is also dropped, this option can be chosen aswell.
|
2026-01-09 10:10:56 +00:00
|
|
|
func leave_stage(actor:Object) -> void:
|
2026-01-21 21:35:35 +00:00
|
|
|
print("<<< leave_stage(", actor,")");
|
2026-01-09 10:10:56 +00:00
|
|
|
assert(actor in stage_list, "Actor %s not in stage list." % actor)
|
|
|
|
|
stage_list.erase(actor)
|
2025-12-08 09:43:02 +00:00
|
|
|
|
2025-02-06 17:55:05 +00:00
|
|
|
|
2023-06-25 20:40:31 +00:00
|
|
|
# Currently focused element loses focus, but remains in stack.
|
|
|
|
|
func free_focus():
|
2024-09-15 09:30:31 +00:00
|
|
|
if focus_locked: return false
|
2026-01-12 17:39:34 +00:00
|
|
|
if stage_list.size() > 0: stage_list.front().focused = false
|
2023-07-13 14:14:40 +00:00
|
|
|
|
2025-10-29 21:20:04 +00:00
|
|
|
func reset_focus():
|
|
|
|
|
stage_list = [stage_list[-1]]
|
|
|
|
|
|
2023-06-25 20:40:31 +00:00
|
|
|
|
2023-07-13 14:14:40 +00:00
|
|
|
func queue_for_stage(target: Object, index: int = 1):
|
2024-09-15 09:30:31 +00:00
|
|
|
stage_list.insert(index, target)
|
2023-07-18 18:59:00 +00:00
|
|
|
|
2024-10-01 23:32:59 +00:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region play state
|
|
|
|
|
|
|
|
|
|
enum rooms {
|
2025-03-25 21:34:13 +00:00
|
|
|
NULL,
|
2024-10-01 23:32:59 +00:00
|
|
|
YOUTH,
|
2024-10-16 10:29:20 +00:00
|
|
|
TRANSITION,
|
|
|
|
|
ADULTHOOD,
|
2024-10-01 23:32:59 +00:00
|
|
|
ENDING
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-06 17:55:05 +00:00
|
|
|
enum sequences {
|
2026-01-11 21:09:19 +00:00
|
|
|
DRAVEN,
|
2025-02-06 17:55:05 +00:00
|
|
|
CHILDHOOD,
|
|
|
|
|
VOICE,
|
|
|
|
|
JUI_JUTSU,
|
|
|
|
|
TRANS,
|
|
|
|
|
AUTISM,
|
|
|
|
|
UNI_START,
|
|
|
|
|
VOLUNTARY,
|
|
|
|
|
UNI_CONTINUE,
|
|
|
|
|
UNI_ALT,
|
|
|
|
|
THERAPY,
|
|
|
|
|
BURNOUT
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-02 20:35:19 +00:00
|
|
|
var current_room: rooms = rooms.NULL
|
|
|
|
|
var onready_room: rooms = rooms.NULL
|