From c7f96c78c4700ddb8014d62d2c26068c0d426fee Mon Sep 17 00:00:00 2001 From: SchimmelSpreu83 Date: Sat, 1 Mar 2025 13:28:21 +0100 Subject: [PATCH] Huge changes Implemented spawn points correctly. Added saving & loading (currently only implemented with the spawn_index). You can now set spawn indicies in the DynamicAreaLoader to automatically load when the game is set to that value (on ready). Added configuration warnings to DynamicAreaLoader & PlayerSpawnPoint Added some generic translation (pot) files. Added AudioManager autoload to play, stop, fade audio streams (and set the bus directly). Added SceneFader autoload. Added SaveManager autoload. Added OptionsMenu with currently only volume sliders and a fullscreen toggle button. Added PauseMenu --- .../characters/common/footstep_component.gd | 5 +- .../characters/player/player_character.gd | 9 + .../collision/areas/dynamic_area_loader.gd | 59 ++++-- .../components/general/interactive_loader.gd | 4 +- .../components/general/player_spawn_point.gd | 77 ++++++- source/components/hazards/saw/saw.gd | 4 + source/components/ui/menus/boot/boot.gd | 12 +- .../shader_precompiler.gd | 9 +- .../ui/menus/loading_screen/loading_screen.gd | 19 ++ .../loading_screen/loading_screen.gd.uid | 1 + .../menus/loading_screen/loading_screen.tscn | 30 +++ .../ui/menus/main_menu/main_menu.gd | 57 +++++- .../ui/menus/main_menu/main_menu.tscn | 84 ++++++-- source/components/ui/menus/menu_base.gd | 1 + .../components/ui/menus/menu_button_opener.gd | 10 + .../ui/menus/menu_button_opener.gd.uid | 1 + .../elements/fullscreen_button.gd | 10 + .../elements/fullscreen_button.gd.uid | 1 + .../options_menu/elements/slider_label.gd | 40 ++++ .../options_menu/elements/slider_label.gd.uid | 1 + .../options_menu/elements/volume_slider.gd | 51 +++++ .../elements/volume_slider.gd.uid | 1 + .../ui/menus/options_menu/options_menu.gd | 2 + .../ui/menus/options_menu/options_menu.gd.uid | 1 + .../ui/menus/options_menu/options_menu.tscn | 177 ++++++++++++++++ .../ui/menus/pause_menu/pause_menu.gd | 49 +++++ .../ui/menus/pause_menu/pause_menu.gd.uid | 1 + .../ui/menus/pause_menu/pause_menu.tscn | 63 ++++++ source/game.gd | 8 + source/game.gd.uid | 1 + source/game.tscn | 83 ++++++++ .../globals/autoloads/audio/audio_manager.gd | 67 ++++++ .../autoloads/audio/audio_manager.gd.uid | 1 + .../autoloads/audio/audio_manager.tscn | 6 + source/globals/autoloads/game_globals.gd | 11 + source/globals/autoloads/input_manager.gd | 6 +- source/globals/autoloads/save_manager.gd | 32 +++ source/globals/autoloads/save_manager.gd.uid | 1 + .../autoloads/scene_fader/scene_fader.gd | 67 ++++++ .../autoloads/scene_fader/scene_fader.gd.uid | 1 + .../autoloads/scene_fader/scene_fader.tscn | 125 ++++++++++++ .../autoloads/settings/settings_manager.gd | 71 +++++++ .../settings/settings_manager.gd.uid | 1 + source/localization/de.mo | Bin 0 -> 432 bytes source/localization/de.po | 38 ++++ source/localization/en.mo | Bin 0 -> 416 bytes source/localization/en.po | 38 ++++ source/localization/translation.pot | 32 +++ source/main.tscn | 3 - .../_dynamic_load_test_map.tscn | 190 ++++++++++-------- source/project.godot | 20 +- source/resources/game_environment.tres | 8 + 52 files changed, 1448 insertions(+), 141 deletions(-) create mode 100644 source/components/ui/menus/loading_screen/loading_screen.gd create mode 100644 source/components/ui/menus/loading_screen/loading_screen.gd.uid create mode 100644 source/components/ui/menus/loading_screen/loading_screen.tscn create mode 100644 source/components/ui/menus/menu_button_opener.gd create mode 100644 source/components/ui/menus/menu_button_opener.gd.uid create mode 100644 source/components/ui/menus/options_menu/elements/fullscreen_button.gd create mode 100644 source/components/ui/menus/options_menu/elements/fullscreen_button.gd.uid create mode 100644 source/components/ui/menus/options_menu/elements/slider_label.gd create mode 100644 source/components/ui/menus/options_menu/elements/slider_label.gd.uid create mode 100644 source/components/ui/menus/options_menu/elements/volume_slider.gd create mode 100644 source/components/ui/menus/options_menu/elements/volume_slider.gd.uid create mode 100644 source/components/ui/menus/options_menu/options_menu.gd create mode 100644 source/components/ui/menus/options_menu/options_menu.gd.uid create mode 100644 source/components/ui/menus/options_menu/options_menu.tscn create mode 100644 source/components/ui/menus/pause_menu/pause_menu.gd create mode 100644 source/components/ui/menus/pause_menu/pause_menu.gd.uid create mode 100644 source/components/ui/menus/pause_menu/pause_menu.tscn create mode 100644 source/game.gd create mode 100644 source/game.gd.uid create mode 100644 source/game.tscn create mode 100644 source/globals/autoloads/audio/audio_manager.gd create mode 100644 source/globals/autoloads/audio/audio_manager.gd.uid create mode 100644 source/globals/autoloads/audio/audio_manager.tscn create mode 100644 source/globals/autoloads/save_manager.gd create mode 100644 source/globals/autoloads/save_manager.gd.uid create mode 100644 source/globals/autoloads/scene_fader/scene_fader.gd create mode 100644 source/globals/autoloads/scene_fader/scene_fader.gd.uid create mode 100644 source/globals/autoloads/scene_fader/scene_fader.tscn create mode 100644 source/globals/autoloads/settings/settings_manager.gd create mode 100644 source/globals/autoloads/settings/settings_manager.gd.uid create mode 100644 source/localization/de.mo create mode 100644 source/localization/de.po create mode 100644 source/localization/en.mo create mode 100644 source/localization/en.po create mode 100644 source/localization/translation.pot delete mode 100644 source/main.tscn create mode 100644 source/resources/game_environment.tres diff --git a/source/components/characters/common/footstep_component.gd b/source/components/characters/common/footstep_component.gd index 6e99444..84e7e80 100644 --- a/source/components/characters/common/footstep_component.gd +++ b/source/components/characters/common/footstep_component.gd @@ -18,20 +18,21 @@ func _ready() -> void: func _physics_process(delta: float) -> void: + # Don't process if it isn't necessary. if not is_instance_valid(character): return if audio_player.is_empty(): - # Don't process if it isn't necessary. return var on_floor: bool = character.is_on_floor() if on_floor: if _was_in_air: + # We landed. Play a footstep. play_footstep() _distance_traveled = 0.0 - var velocity: Vector3 = abs(character.velocity) #+ (abs(character.get_platform_velocity()) if not character.velocity.is_zero_approx() else Vector3.ZERO) + var velocity: Vector3 = abs(character.velocity) velocity.y = 0.0 if velocity.is_zero_approx(): diff --git a/source/components/characters/player/player_character.gd b/source/components/characters/player/player_character.gd index 2bc6eca..59f125f 100644 --- a/source/components/characters/player/player_character.gd +++ b/source/components/characters/player/player_character.gd @@ -16,6 +16,15 @@ var has_control: bool = true func _ready() -> void: GameGlobals.player = self + + if not get_tree().root.is_node_ready(): + await get_tree().root.ready + + var spawn_point := PlayerSpawnPoint.get_spawn_point_by_index(GameGlobals.spawn_index) + + if is_instance_valid(spawn_point): + global_position = spawn_point.global_position + head.global_rotation = spawn_point.global_rotation func _physics_process(delta: float) -> void: diff --git a/source/components/collision/areas/dynamic_area_loader.gd b/source/components/collision/areas/dynamic_area_loader.gd index 6ec207c..8229bfa 100644 --- a/source/components/collision/areas/dynamic_area_loader.gd +++ b/source/components/collision/areas/dynamic_area_loader.gd @@ -1,3 +1,4 @@ +@tool @icon("dynamic_area_loader.svg") class_name DynamicAreaLoader3D extends Area3D @@ -16,7 +17,10 @@ signal load_finished(loaded_node: Node) ## The node to load and add.[br][br] ## [b]IMPORTANT:[/b] The node needs to be marked as [b]Load as Placeholder[/b], otherwise nothing ## happens when loading (see [InstancePlaceholder]). -@export var placeholder_node: Node +@export var placeholder_node: Node: + set(value): + placeholder_node = value + update_configuration_warnings() ## If [code]true[/code], the actual loading will be done separately in a thread.[br] ## This prevents the game from freezing for a moment when loading a large scene.[br] ## However, loading can be slower on lower-end hardware. @@ -25,37 +29,47 @@ signal load_finished(loaded_node: Node) ## when the [PlayerCharacter] exits this area.[br]This is to prevent the [PlayerCharacter] ## from keep re-loading the area by just walking back and fourth through the load zones. @export_range(0.0, 10.0, 0.01, "or_greater", "suffix:s") var keep_loaded_duration: float = 3.0 +## Automatically load the area when entering the scene tree, if the [member GameGlobals.spawn_point] +## is set to any of these values. +@export var loaded_if_spawnpoint: Array[int] = [] ## The reference to the currently loaded node that was loaded. var loaded_node: Node func _ready() -> void: + if Engine.is_editor_hint(): + return + + if loaded_if_spawnpoint.has(GameGlobals.spawn_index): + load_area(null, true) + body_entered.connect(_on_body_entered) body_exited.connect(_on_body_exited) ## Instances the area defined by [member placeholder_node].[br] ## See [method load_area_threaded] if you want to load the area in a thread instead -## of having a freeze during load. -func load_area(custom_scene: PackedScene = null) -> void: - if is_instance_valid(placeholder_node) and placeholder_node is InstancePlaceholder: - if is_instance_valid(loaded_node) or not overlaps_body(GameGlobals.get_player()): - return +## of having a freeze during load.[br][br] +## If [param forced] is [code]true[/code], don't check if the player is colliding when calling this function. +func load_area(custom_scene: PackedScene = null, forced: bool = false) -> void: + assert(is_instance_valid(placeholder_node), "[placeholder_node] needs to be set.") + assert(placeholder_node is InstancePlaceholder, "[placeholder_node] needs to be marked as 'Load As Placeholder'.") - loaded_node = placeholder_node.create_instance(false, custom_scene) - load_finished.emit(loaded_node) + if is_instance_valid(loaded_node) or (not forced and not overlaps_body(GameGlobals.get_player())): + return + + loaded_node = placeholder_node.create_instance(false, custom_scene) + load_finished.emit(loaded_node) ## Loads the scene defined in ## [member placeholder_node] ([member InstancePlaceholder.get_instance_path]) threaded.[br] -## Calls [method load_area] with the [param custom_scene] set to the loaded scene. -func load_area_threaded() -> void: - if is_instance_valid(loaded_node): - return - - if not is_instance_valid(placeholder_node) or placeholder_node is not InstancePlaceholder: - return +## Calls [method load_area] with the [param custom_scene] set to the loaded scene.[br][br] +## [param forced] does the same thing as in [method load_area]. +func load_area_threaded(forced: bool = false) -> void: + assert(is_instance_valid(placeholder_node), "[placeholder_node] needs to be set.") + assert(placeholder_node is InstancePlaceholder, "[placeholder_node] needs to be marked as 'Load As Placeholder'.") placeholder_node = placeholder_node as InstancePlaceholder @@ -70,7 +84,7 @@ func load_area_threaded() -> void: var scene: PackedScene = ResourceLoader.load_threaded_get(path) - load_area(scene) + load_area(scene, forced) ## Unloads ([method Node.queue_free]) the [member loaded_node].[br] @@ -79,7 +93,7 @@ func load_area_threaded() -> void: func unload_area(instantly_unload: bool = false) -> void: if not is_instance_valid(loaded_node): return - + if not instantly_unload and keep_loaded_duration > 0.0: var duration: float = keep_loaded_duration @@ -104,3 +118,14 @@ func _on_body_entered(body: Node3D) -> void: func _on_body_exited(body: Node3D) -> void: if body == GameGlobals.get_player(): unload_area() + + +func _get_configuration_warnings() -> PackedStringArray: + if not is_instance_valid(placeholder_node): + return ["'placeholder_node' is not set."] + + # TODO: Find a way to detect that in the editor. + if placeholder_node is not InstancePlaceholder and false: + return ["'placeholder_node' needs to be marked as 'Load As Placeholder'"] + + return [] diff --git a/source/components/general/interactive_loader.gd b/source/components/general/interactive_loader.gd index 588ccd3..5ce4559 100644 --- a/source/components/general/interactive_loader.gd +++ b/source/components/general/interactive_loader.gd @@ -1,6 +1,8 @@ class_name InteractiveLoader extends Node +var load_progress: Array = [] + func load_threaded(path: String) -> Resource: if not is_inside_tree(): @@ -14,7 +16,7 @@ func load_threaded(path: String) -> Resource: ResourceLoader.load_threaded_request(path, "", false, ResourceLoader.CACHE_MODE_REUSE) while ResourceLoader.load_threaded_get_status(path) != ResourceLoader.THREAD_LOAD_LOADED: - match ResourceLoader.load_threaded_get_status(path): + match ResourceLoader.load_threaded_get_status(path, load_progress): ResourceLoader.THREAD_LOAD_FAILED || ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: Logger.print_msg("[Interactive Loader] load failed.", -1.0, Logger.ErrTypes.WARNING) return null diff --git a/source/components/general/player_spawn_point.gd b/source/components/general/player_spawn_point.gd index 85c6d2a..fe7ec42 100644 --- a/source/components/general/player_spawn_point.gd +++ b/source/components/general/player_spawn_point.gd @@ -3,8 +3,22 @@ class_name PlayerSpawnPoint extends Marker3D @export var spawn_index: int = 0: set = set_spawn_index +@export_tool_button("Set unique index") var set_unique_index: Callable = func() -> void: + for spawn_point: PlayerSpawnPoint in spawn_points: + if spawn_point == self: + continue + + if spawn_point.spawn_index == spawn_index: + set_spawn_index(spawn_index + 1) + set_unique_index.call() + return + + update_configuration_warnings() +@export var editor_auto_assign_unique_id: bool = true +static var spawn_points: Array[PlayerSpawnPoint] = [] var idx_label: Label3D +var config_warnings_hint: Label3D func _init() -> void: @@ -12,17 +26,78 @@ func _init() -> void: var player_scene: PackedScene = load("res://components/characters/player/player_character.tscn") add_child(player_scene.instantiate(), false, Node.INTERNAL_MODE_FRONT) - # Setup label. + # Setup labels. idx_label = Label3D.new() idx_label.billboard = BaseMaterial3D.BILLBOARD_ENABLED idx_label.shaded = false + idx_label.font_size = 64 add_child(idx_label, false, Node.INTERNAL_MODE_FRONT) idx_label.position.y = 1.8 set_spawn_index(spawn_index) + + config_warnings_hint = Label3D.new() + config_warnings_hint.billboard = BaseMaterial3D.BILLBOARD_ENABLED + config_warnings_hint.shaded = false + config_warnings_hint.no_depth_test = true + config_warnings_hint.fixed_size = true + config_warnings_hint.text = "!" + config_warnings_hint.modulate = Color.RED + add_child(config_warnings_hint, false, Node.INTERNAL_MODE_FRONT) + config_warnings_hint.position.y = 1.0 + + var tween: Tween = create_tween().set_loops() + tween.tween_property(config_warnings_hint, ^"scale", Vector3.ONE * 1.5, 0.075) + tween.tween_property(config_warnings_hint, ^"scale", Vector3.ONE * 1.0, 0.075) + + update_configuration_warnings() + + +func _enter_tree() -> void: + if not spawn_points.has(self): + spawn_points.append(self) + + if editor_auto_assign_unique_id and Engine.is_editor_hint(): + set_unique_index.call_deferred() + + +func _exit_tree() -> void: + spawn_points.erase(self) func set_spawn_index(index: int) -> void: spawn_index = index + update_configuration_warnings() if is_instance_valid(idx_label): idx_label.text = str(spawn_index) + + +func make_current(do_autosave: bool = true) -> void: + GameGlobals.spawn_index = spawn_index + + if do_autosave: + SaveManager.save_game() + + +static func get_spawn_point_by_index(index: int) -> PlayerSpawnPoint: + for spawn_point: PlayerSpawnPoint in PlayerSpawnPoint.spawn_points: + if spawn_point.spawn_index == index: + return spawn_point + + return null + + +func _get_configuration_warnings() -> PackedStringArray: + var warnings: PackedStringArray = [] + + for spawn_point: PlayerSpawnPoint in spawn_points: + if spawn_point.spawn_index == spawn_index and spawn_point != self: + warnings.append(str(spawn_point, " has the same spawn index as us.")) + spawn_point.config_warnings_hint.show() + + spawn_point.update_configuration_warnings() + + if warnings.is_empty(): + config_warnings_hint.hide() + + return warnings diff --git a/source/components/hazards/saw/saw.gd b/source/components/hazards/saw/saw.gd index d7efef5..5c55721 100644 --- a/source/components/hazards/saw/saw.gd +++ b/source/components/hazards/saw/saw.gd @@ -5,6 +5,10 @@ extends Node3D @onready var saw_skin: Node3D = $SawSkin +func _ready() -> void: + saw_skin.rotation.z = randf() * TAU + + # Called every frame. 'delta' is the elapsed time since the previous frame. func _physics_process(delta: float) -> void: saw_skin.rotate_z(spin_speed * delta) diff --git a/source/components/ui/menus/boot/boot.gd b/source/components/ui/menus/boot/boot.gd index 44e456d..f84129b 100644 --- a/source/components/ui/menus/boot/boot.gd +++ b/source/components/ui/menus/boot/boot.gd @@ -3,5 +3,15 @@ extends Control @onready var shader_precompiler: Node = $ShaderPrecompiler +func _ready() -> void: + if SettingsManager.get_setting(&"game", &"has_compiled_shaders"): + shader_precompiler.canvas_layer.hide() + _on_shader_precompiler_finished_compilation() + else: + await get_tree().create_timer(1.0).timeout + shader_precompiler.precompile_shaders() + + func _on_shader_precompiler_finished_compilation() -> void: - get_tree().quit() + SettingsManager.set_setting(&"game", &"has_compiled_shaders", true) + SceneFader.load_to_path(GameGlobals.MAIN_MENU_PATH) diff --git a/source/components/ui/menus/boot/shader_precompilation/shader_precompiler.gd b/source/components/ui/menus/boot/shader_precompilation/shader_precompiler.gd index bfbfb80..99cd2ac 100644 --- a/source/components/ui/menus/boot/shader_precompilation/shader_precompiler.gd +++ b/source/components/ui/menus/boot/shader_precompilation/shader_precompiler.gd @@ -4,18 +4,13 @@ signal finished_compilation const EXCLUDED_DIRECTORIES: Array[String] = [ "res://addons", - "res://.godot" + "res://.godot", ] #const SIMUTANEOUS_SCENES: int = 5 @onready var progress_bar: ProgressBar = %ProgressBar - - -# Called when the node enters the scene tree for the first time. -func _ready() -> void: - await get_tree().create_timer(1.0).timeout - precompile_shaders() +@onready var canvas_layer: CanvasLayer = $CanvasLayer func precompile_shaders() -> void: diff --git a/source/components/ui/menus/loading_screen/loading_screen.gd b/source/components/ui/menus/loading_screen/loading_screen.gd new file mode 100644 index 0000000..639a54d --- /dev/null +++ b/source/components/ui/menus/loading_screen/loading_screen.gd @@ -0,0 +1,19 @@ +class_name LoadingScreen +extends MenuBase + +var _interactive_loader: InteractiveLoader + +@onready var progress_bar: ProgressBar = %ProgressBar + + +func _process(_delta: float) -> void: + if is_instance_valid(_interactive_loader) and not _interactive_loader.load_progress.is_empty(): + progress_bar.value = _interactive_loader.load_progress.front() + + +func load_scene(path: String) -> PackedScene: + _interactive_loader = InteractiveLoader.new() + add_child(_interactive_loader) + var resource: Object = await _interactive_loader.load_threaded(path) + _interactive_loader.queue_free() + return resource diff --git a/source/components/ui/menus/loading_screen/loading_screen.gd.uid b/source/components/ui/menus/loading_screen/loading_screen.gd.uid new file mode 100644 index 0000000..a417bce --- /dev/null +++ b/source/components/ui/menus/loading_screen/loading_screen.gd.uid @@ -0,0 +1 @@ +uid://tmo4wscguj62 diff --git a/source/components/ui/menus/loading_screen/loading_screen.tscn b/source/components/ui/menus/loading_screen/loading_screen.tscn new file mode 100644 index 0000000..82e9da4 --- /dev/null +++ b/source/components/ui/menus/loading_screen/loading_screen.tscn @@ -0,0 +1,30 @@ +[gd_scene load_steps=2 format=3 uid="uid://buvus4ym83wa8"] + +[ext_resource type="Script" uid="uid://tmo4wscguj62" path="res://components/ui/menus/loading_screen/loading_screen.gd" id="1_1gk3q"] + +[node name="LoadingScreen" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_1gk3q") +metadata/_custom_type_script = "uid://crdgxvb8i0cif" + +[node name="ProgressBar" type="ProgressBar" parent="."] +unique_name_in_owner = true +custom_minimum_size = Vector2(512, 0) +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -2.0 +offset_top = -13.5 +offset_right = 2.0 +offset_bottom = 13.5 +grow_horizontal = 2 +grow_vertical = 2 +max_value = 1.0 diff --git a/source/components/ui/menus/main_menu/main_menu.gd b/source/components/ui/menus/main_menu/main_menu.gd index 173b569..687daad 100644 --- a/source/components/ui/menus/main_menu/main_menu.gd +++ b/source/components/ui/menus/main_menu/main_menu.gd @@ -1,10 +1,61 @@ -extends MenuBase +class_name MainMenu +extends Node + +const AMBIENCE_STREAM: AudioStream = preload("res://Dark House.wav") + +@onready var continue_button: Button = %ContinueButton +@onready var new_game_button: Button = %NewGameButton +@onready var quit_button: Button = %QuitButton +@onready var options_menu: Control = $OptionsMenu +@onready var main_menu_ui: Control = $MainMenuUI +func _ready() -> void: + continue_button.disabled = not SaveManager.save_exists() -func _on_play_button_pressed() -> void: - pass # Replace with function body. + AudioManager.play_audio(AMBIENCE_STREAM, AudioManager.MUSIC) + + +func _unhandled_input(event: InputEvent) -> void: + if options_menu.is_visible_in_tree() and event.is_action_pressed(&"pause"): + main_menu_ui.show() + options_menu.hide() + + +func load_game() -> void: + AudioManager.fade_audio(AMBIENCE_STREAM, -80.0, SceneFader.fade_in_duration, AudioManager.MUSIC, true) + SceneFader.load_to_path(GameGlobals.GAME_PATH) + + +func _on_new_game_button_pressed() -> void: + if SceneFader.is_fading: + return + + GameGlobals.reset_game() + SaveManager.delete_save() + SaveManager.save_game() + load_game() + + +func _on_continue_button_pressed() -> void: + if SceneFader.is_fading: + return + + GameGlobals.reset_game() + SaveManager.load_game() + load_game() func _on_quit_button_pressed() -> void: + if SceneFader.is_fading: + return + get_tree().quit() + + +func _on_settings_button_pressed() -> void: + if SceneFader.is_fading: + return + + main_menu_ui.hide() + options_menu.show() diff --git a/source/components/ui/menus/main_menu/main_menu.tscn b/source/components/ui/menus/main_menu/main_menu.tscn index f3a94f3..8cc550e 100644 --- a/source/components/ui/menus/main_menu/main_menu.tscn +++ b/source/components/ui/menus/main_menu/main_menu.tscn @@ -1,27 +1,34 @@ -[gd_scene load_steps=2 format=3 uid="uid://dwd8wf02j2epn"] +[gd_scene load_steps=4 format=3 uid="uid://dwd8wf02j2epn"] [ext_resource type="Script" uid="uid://bmsx3h2kunhb0" path="res://components/ui/menus/main_menu/main_menu.gd" id="1_6xfbl"] +[ext_resource type="PackedScene" uid="uid://4s2nskkco0a2" path="res://components/ui/menus/options_menu/options_menu.tscn" id="2_i2wwg"] -[node name="MainMenu" type="Control"] +[sub_resource type="Environment" id="Environment_6xfbl"] +ambient_light_source = 2 +ambient_light_color = Color(0.177136, 0.177136, 0.177136, 1) + +[node name="MainMenu" type="Node"] +script = ExtResource("1_6xfbl") + +[node name="MainMenuUI" type="Control" parent="."] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -script = ExtResource("1_6xfbl") -[node name="Label" type="Label" parent="."] +[node name="TitleLabel" type="Label" parent="MainMenuUI"] layout_mode = 1 anchors_preset = 10 anchor_right = 1.0 -offset_bottom = 23.0 +offset_bottom = 88.0 grow_horizontal = 2 theme_override_font_sizes/font_size = 64 -text = "Untitled Maskot Horror Game" +text = "Magic N' Stuff" horizontal_alignment = 1 -[node name="ButtonContainer" type="VBoxContainer" parent="."] +[node name="ButtonContainer" type="VBoxContainer" parent="MainMenuUI"] custom_minimum_size = Vector2(128, 0) layout_mode = 1 anchors_preset = 8 @@ -29,21 +36,64 @@ anchor_left = 0.5 anchor_top = 0.5 anchor_right = 0.5 anchor_bottom = 0.5 -offset_left = -21.0 -offset_top = -33.0 -offset_right = 21.0 -offset_bottom = 33.0 +offset_left = -64.0 +offset_top = -68.0 +offset_right = 64.0 +offset_bottom = 68.0 grow_horizontal = 2 grow_vertical = 2 alignment = 1 -[node name="PlayButton" type="Button" parent="ButtonContainer"] +[node name="ContinueButton" type="Button" parent="MainMenuUI/ButtonContainer"] +unique_name_in_owner = true layout_mode = 2 -text = "Play" +text = "CONTINUE" -[node name="QuitButton" type="Button" parent="ButtonContainer"] +[node name="NewGameButton" type="Button" parent="MainMenuUI/ButtonContainer"] +unique_name_in_owner = true layout_mode = 2 -text = "Quit" +text = "NEW_GAME" -[connection signal="pressed" from="ButtonContainer/PlayButton" to="." method="_on_play_button_pressed"] -[connection signal="pressed" from="ButtonContainer/QuitButton" to="." method="_on_quit_button_pressed"] +[node name="SettingsButton" type="Button" parent="MainMenuUI/ButtonContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "SETTINGS" + +[node name="QuitButton" type="Button" parent="MainMenuUI/ButtonContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "QUIT" + +[node name="OptionsMenu" parent="." instance=ExtResource("2_i2wwg")] +visible = false + +[node name="Background" type="Node3D" parent="."] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="Background"] +environment = SubResource("Environment_6xfbl") + +[node name="TVLight" type="OmniLight3D" parent="Background"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, -1) +light_energy = 0.135 +omni_range = 3.0 +omni_attenuation = 2.15 + +[node name="CSGGeometry" type="CSGCombiner3D" parent="Background"] + +[node name="CSGBox3D" type="CSGBox3D" parent="Background/CSGGeometry"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0) +size = Vector3(10, 4, 7) + +[node name="CSGBox3D2" type="CSGBox3D" parent="Background/CSGGeometry/CSGBox3D"] +operation = 2 +size = Vector3(9, 3, 6) + +[node name="Camera3D" type="Camera3D" parent="Background"] +transform = Transform3D(1, 0, 0, 0, 0.996195, -0.0871557, 0, 0.0871557, 0.996195, 0, 0.4, 1) +current = true +fov = 55.0 + +[connection signal="pressed" from="MainMenuUI/ButtonContainer/ContinueButton" to="." method="_on_continue_button_pressed"] +[connection signal="pressed" from="MainMenuUI/ButtonContainer/NewGameButton" to="." method="_on_new_game_button_pressed"] +[connection signal="pressed" from="MainMenuUI/ButtonContainer/SettingsButton" to="." method="_on_settings_button_pressed"] +[connection signal="pressed" from="MainMenuUI/ButtonContainer/QuitButton" to="." method="_on_quit_button_pressed"] diff --git a/source/components/ui/menus/menu_base.gd b/source/components/ui/menus/menu_base.gd index ab33ed5..4431c0b 100644 --- a/source/components/ui/menus/menu_base.gd +++ b/source/components/ui/menus/menu_base.gd @@ -12,6 +12,7 @@ func open_menu(last_menu: MenuBase = previous_menu) -> void: if is_instance_valid(last_menu): previous_menu = last_menu + last_menu.hide() menu_opened.emit() diff --git a/source/components/ui/menus/menu_button_opener.gd b/source/components/ui/menus/menu_button_opener.gd new file mode 100644 index 0000000..ca8c772 --- /dev/null +++ b/source/components/ui/menus/menu_button_opener.gd @@ -0,0 +1,10 @@ +class_name MenuButtonOpener +extends Button + +@export var open_menu: MenuBase +@export var previous_menu: MenuBase + + +func _pressed() -> void: + if is_instance_valid(open_menu): + open_menu.open_menu(previous_menu) diff --git a/source/components/ui/menus/menu_button_opener.gd.uid b/source/components/ui/menus/menu_button_opener.gd.uid new file mode 100644 index 0000000..bc57b6c --- /dev/null +++ b/source/components/ui/menus/menu_button_opener.gd.uid @@ -0,0 +1 @@ +uid://dtgap28ru5dt0 diff --git a/source/components/ui/menus/options_menu/elements/fullscreen_button.gd b/source/components/ui/menus/options_menu/elements/fullscreen_button.gd new file mode 100644 index 0000000..1ca434a --- /dev/null +++ b/source/components/ui/menus/options_menu/elements/fullscreen_button.gd @@ -0,0 +1,10 @@ +extends CheckBox + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + button_pressed = SettingsManager.get_setting(&"video", &"fullscreen") + + +func _toggled(toggled_on: bool) -> void: + SettingsManager.set_fullscreen(toggled_on) diff --git a/source/components/ui/menus/options_menu/elements/fullscreen_button.gd.uid b/source/components/ui/menus/options_menu/elements/fullscreen_button.gd.uid new file mode 100644 index 0000000..f661ff9 --- /dev/null +++ b/source/components/ui/menus/options_menu/elements/fullscreen_button.gd.uid @@ -0,0 +1 @@ +uid://dlkewd0xr6ytq diff --git a/source/components/ui/menus/options_menu/elements/slider_label.gd b/source/components/ui/menus/options_menu/elements/slider_label.gd new file mode 100644 index 0000000..2b61cb7 --- /dev/null +++ b/source/components/ui/menus/options_menu/elements/slider_label.gd @@ -0,0 +1,40 @@ +class_name SliderLabel +extends Label + + +@export var slider: Slider: set = set_slider +@export var pad_zeros: int = 1 +@export var pad_decimals: int = 2 +@export var prefix: String = "" +@export var suffix: String = "" +@export_group("Remap Value") +@export var do_remap: bool = false +@export var remap_initial_min: float = 0.0 +@export var remap_initial_max: float = 1.0 +@export var remap_output_min: float = 0.0 +@export var remap_output_max: float = 1.0 + + +func set_slider(new_slider: Slider) -> void: + if new_slider == slider: + return + + if is_instance_valid(slider): + slider.value_changed.disconnect(_on_value_changed) + + if is_instance_valid(new_slider): + new_slider.value_changed.connect(_on_value_changed) + if not new_slider.is_node_ready(): + await new_slider.ready + _on_value_changed(new_slider.get_value()) # Apply the value of the new slider. + + slider = new_slider + + +func _on_value_changed(new_value: float) -> void: + var value: float = new_value + if do_remap: + value = remap(value, remap_initial_min, remap_initial_max, remap_output_min, remap_output_max) + + var new_text: String = str(value).pad_zeros(pad_zeros).pad_decimals(pad_decimals) + set_text(str(prefix, new_text, suffix)) diff --git a/source/components/ui/menus/options_menu/elements/slider_label.gd.uid b/source/components/ui/menus/options_menu/elements/slider_label.gd.uid new file mode 100644 index 0000000..9c2c9f7 --- /dev/null +++ b/source/components/ui/menus/options_menu/elements/slider_label.gd.uid @@ -0,0 +1 @@ +uid://dg2s0gww8q6jh diff --git a/source/components/ui/menus/options_menu/elements/volume_slider.gd b/source/components/ui/menus/options_menu/elements/volume_slider.gd new file mode 100644 index 0000000..dcff3d6 --- /dev/null +++ b/source/components/ui/menus/options_menu/elements/volume_slider.gd @@ -0,0 +1,51 @@ +class_name VolumeSlider +extends HSlider + + +## A normal slider that automatically changes the volume of the given [param bus] in +## the given [param bus_layout]. +## This slider will automatically load and save it's value when it enters the tree +## or changes it's value.[br] +## INFO: You don't need to change [param min_value] and [param max_value], the calculations +## towards [param volume_db] are automatically being done. + +## The bus that get's it's volume changed. +@export var bus: StringName = &"Master" +@export var auto_set_muted: bool = false +@export var min_volume: float = 0.0 +@export var max_volume: float = 1.0 +@export var default_volume: float = 1.0 +## The audio bus layout that get's affected. +#@export var bus_layout: AudioBusLayout = preload("res://resources/default_bus_layout.tres") + + +func _ready() -> void: + value_changed.connect(func(_value_changed: bool) -> void: + SettingsManager.set_setting(&"audio", bus, remap(value, min_value, max_value, 0.0, 1.0), true) + ) + + if not value_changed.is_connected(set_volume): + value_changed.connect(set_volume) + + var err: float = SettingsManager.get_setting(&"audio", bus) + + var new_value: float = remap(err, 0.0, 1.0, min_value, max_value) + set_value_no_signal(new_value) + set_volume(new_value) + value_changed.emit(value) + + +## Set's the volume on the audio bus given by [param bus] to the volume_range (Range from 0 to 100).[br] +## Note that this won't change [param value]. +func set_volume(volume_range: float) -> void: + volume_range = remap(volume_range, min_value, max_value, min_volume, max_volume) + var new_volume: float = linear_to_db(volume_range) + var bus_idx: int = AudioServer.get_bus_index(bus) + + AudioServer.set_bus_volume_db(bus_idx, new_volume) + if auto_set_muted: + AudioServer.set_bus_mute(bus_idx, is_zero_approx(volume_range)) + + +#func save_volume(volume_range: float) -> void: + #OptionSaver.save_option("audio", bus, (volume_range / max_value)) diff --git a/source/components/ui/menus/options_menu/elements/volume_slider.gd.uid b/source/components/ui/menus/options_menu/elements/volume_slider.gd.uid new file mode 100644 index 0000000..8760e6e --- /dev/null +++ b/source/components/ui/menus/options_menu/elements/volume_slider.gd.uid @@ -0,0 +1 @@ +uid://d2j5jmj08o7f5 diff --git a/source/components/ui/menus/options_menu/options_menu.gd b/source/components/ui/menus/options_menu/options_menu.gd new file mode 100644 index 0000000..dcae6ac --- /dev/null +++ b/source/components/ui/menus/options_menu/options_menu.gd @@ -0,0 +1,2 @@ +class_name OptionsMenu +extends Control diff --git a/source/components/ui/menus/options_menu/options_menu.gd.uid b/source/components/ui/menus/options_menu/options_menu.gd.uid new file mode 100644 index 0000000..2d75c26 --- /dev/null +++ b/source/components/ui/menus/options_menu/options_menu.gd.uid @@ -0,0 +1 @@ +uid://dl8uyh4kcvgl4 diff --git a/source/components/ui/menus/options_menu/options_menu.tscn b/source/components/ui/menus/options_menu/options_menu.tscn new file mode 100644 index 0000000..bbd7d90 --- /dev/null +++ b/source/components/ui/menus/options_menu/options_menu.tscn @@ -0,0 +1,177 @@ +[gd_scene load_steps=4 format=3 uid="uid://4s2nskkco0a2"] + +[ext_resource type="Script" uid="uid://dg2s0gww8q6jh" path="res://components/ui/menus/options_menu/elements/slider_label.gd" id="2_gjkvu"] +[ext_resource type="Script" uid="uid://d2j5jmj08o7f5" path="res://components/ui/menus/options_menu/elements/volume_slider.gd" id="2_hj0r6"] +[ext_resource type="Script" uid="uid://dlkewd0xr6ytq" path="res://components/ui/menus/options_menu/elements/fullscreen_button.gd" id="3_hj0r6"] + +[node name="OptionsMenu" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="TabContainer" type="TabContainer" parent="."] +custom_minimum_size = Vector2(256, 256) +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -20.0 +offset_right = 20.0 +offset_bottom = 20.0 +grow_horizontal = 2 +grow_vertical = 2 +tab_alignment = 1 +current_tab = 0 + +[node name="Audio" type="Control" parent="TabContainer"] +layout_mode = 2 +metadata/_tab_index = 0 + +[node name="MarginContainer" type="MarginContainer" parent="TabContainer/Audio"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Audio/MarginContainer"] +layout_mode = 2 + +[node name="MasterLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Master" + +[node name="MasterContainer" type="HBoxContainer" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VolumeSlider" type="HSlider" parent="TabContainer/Audio/MarginContainer/VBoxContainer/MasterContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +value = 100.0 +tick_count = 10 +ticks_on_borders = true +script = ExtResource("2_hj0r6") +metadata/_custom_type_script = "uid://d2j5jmj08o7f5" + +[node name="SliderLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer/MasterContainer" node_paths=PackedStringArray("slider")] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "1.0" +script = ExtResource("2_gjkvu") +slider = NodePath("../VolumeSlider") +pad_decimals = 0 +metadata/_custom_type_script = "uid://dg2s0gww8q6jh" + +[node name="SFXLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "SFX" + +[node name="SFXContainer" type="HBoxContainer" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VolumeSlider" type="HSlider" parent="TabContainer/Audio/MarginContainer/VBoxContainer/SFXContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +value = 100.0 +tick_count = 10 +ticks_on_borders = true +script = ExtResource("2_hj0r6") +bus = &"SFX" +metadata/_custom_type_script = "uid://d2j5jmj08o7f5" + +[node name="SliderLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer/SFXContainer" node_paths=PackedStringArray("slider")] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "1.0" +script = ExtResource("2_gjkvu") +slider = NodePath("../VolumeSlider") +pad_decimals = 0 +metadata/_custom_type_script = "uid://dg2s0gww8q6jh" + +[node name="MusicLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Music" + +[node name="MusicContainer" type="HBoxContainer" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VolumeSlider" type="HSlider" parent="TabContainer/Audio/MarginContainer/VBoxContainer/MusicContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +value = 100.0 +tick_count = 10 +ticks_on_borders = true +script = ExtResource("2_hj0r6") +bus = &"Music" +metadata/_custom_type_script = "uid://d2j5jmj08o7f5" + +[node name="SliderLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer/MusicContainer" node_paths=PackedStringArray("slider")] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "1.0" +script = ExtResource("2_gjkvu") +slider = NodePath("../VolumeSlider") +pad_decimals = 0 +metadata/_custom_type_script = "uid://dg2s0gww8q6jh" + +[node name="AmbientLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Ambient" + +[node name="AmbientContainer" type="HBoxContainer" parent="TabContainer/Audio/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VolumeSlider" type="HSlider" parent="TabContainer/Audio/MarginContainer/VBoxContainer/AmbientContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +value = 100.0 +tick_count = 10 +ticks_on_borders = true +script = ExtResource("2_hj0r6") +bus = &"Ambient" +metadata/_custom_type_script = "uid://d2j5jmj08o7f5" + +[node name="SliderLabel" type="Label" parent="TabContainer/Audio/MarginContainer/VBoxContainer/AmbientContainer" node_paths=PackedStringArray("slider")] +custom_minimum_size = Vector2(30, 0) +layout_mode = 2 +text = "1.0" +script = ExtResource("2_gjkvu") +slider = NodePath("../VolumeSlider") +pad_decimals = 0 +metadata/_custom_type_script = "uid://dg2s0gww8q6jh" + +[node name="Graphics" type="Control" parent="TabContainer"] +visible = false +layout_mode = 2 +metadata/_tab_index = 1 + +[node name="MarginContainer" type="MarginContainer" parent="TabContainer/Graphics"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 4 +theme_override_constants/margin_top = 4 +theme_override_constants/margin_right = 4 +theme_override_constants/margin_bottom = 4 + +[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Graphics/MarginContainer"] +layout_mode = 2 + +[node name="FullscreenButton" type="CheckBox" parent="TabContainer/Graphics/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Fullscreen" +script = ExtResource("3_hj0r6") diff --git a/source/components/ui/menus/pause_menu/pause_menu.gd b/source/components/ui/menus/pause_menu/pause_menu.gd new file mode 100644 index 0000000..9c6921c --- /dev/null +++ b/source/components/ui/menus/pause_menu/pause_menu.gd @@ -0,0 +1,49 @@ +class_name PauseMenu +extends Node + +const ACTION_PAUSE: StringName = &"pause" + +var can_pause: bool = true + +@onready var pause_menu: MenuBase = $PauseMenu +@onready var options_menu: Control = $OptionsMenu + + +func _input(event: InputEvent) -> void: + if event.is_action_pressed(ACTION_PAUSE): + if options_menu.is_visible_in_tree(): + options_menu.hide() + pause_menu.show() + else: + toggle_pause() + + +func set_paused(value: bool) -> void: + if SceneFader.is_fading: + return + + get_tree().paused = value + pause_menu.visible = value + + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE if value else Input.MOUSE_MODE_CAPTURED + + +func toggle_pause() -> void: + if not can_pause or options_menu.is_visible(): + return + + set_paused(not get_tree().paused) + + +func _on_continue_button_pressed() -> void: + set_paused(false) + + +func _on_main_menu_button_pressed() -> void: + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + await SceneFader.load_to_path(GameGlobals.MAIN_MENU_PATH, true) + + +func _on_settings_button_pressed() -> void: + pause_menu.hide() + options_menu.show() diff --git a/source/components/ui/menus/pause_menu/pause_menu.gd.uid b/source/components/ui/menus/pause_menu/pause_menu.gd.uid new file mode 100644 index 0000000..7881a0f --- /dev/null +++ b/source/components/ui/menus/pause_menu/pause_menu.gd.uid @@ -0,0 +1 @@ +uid://cx3lpgmhrra8v diff --git a/source/components/ui/menus/pause_menu/pause_menu.tscn b/source/components/ui/menus/pause_menu/pause_menu.tscn new file mode 100644 index 0000000..e49e74e --- /dev/null +++ b/source/components/ui/menus/pause_menu/pause_menu.tscn @@ -0,0 +1,63 @@ +[gd_scene load_steps=4 format=3 uid="uid://dawmen0hlfaaq"] + +[ext_resource type="Script" uid="uid://cx3lpgmhrra8v" path="res://components/ui/menus/pause_menu/pause_menu.gd" id="1_43sid"] +[ext_resource type="Script" uid="uid://crdgxvb8i0cif" path="res://components/ui/menus/menu_base.gd" id="1_hcnxh"] +[ext_resource type="PackedScene" uid="uid://4s2nskkco0a2" path="res://components/ui/menus/options_menu/options_menu.tscn" id="3_hcnxh"] + +[node name="PauseMenu" type="Node"] +process_mode = 3 +script = ExtResource("1_43sid") + +[node name="PauseMenu" type="Control" parent="."] +visible = false +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_hcnxh") +metadata/_custom_type_script = "uid://crdgxvb8i0cif" + +[node name="Label" type="Label" parent="PauseMenu"] +layout_mode = 1 +anchors_preset = 10 +anchor_right = 1.0 +offset_bottom = 23.0 +grow_horizontal = 2 +theme_override_font_sizes/font_size = 128 +text = "Paused" +horizontal_alignment = 1 + +[node name="VBoxContainer" type="VBoxContainer" parent="PauseMenu"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -20.0 +offset_top = -20.0 +offset_right = 20.0 +offset_bottom = 20.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ContinueButton" type="Button" parent="PauseMenu/VBoxContainer"] +layout_mode = 2 +text = "Continue" + +[node name="SettingsButton" type="Button" parent="PauseMenu/VBoxContainer"] +layout_mode = 2 +text = "Settings" + +[node name="MainMenuButton" type="Button" parent="PauseMenu/VBoxContainer"] +layout_mode = 2 +text = "Main Menu" + +[node name="OptionsMenu" parent="." instance=ExtResource("3_hcnxh")] +visible = false + +[connection signal="pressed" from="PauseMenu/VBoxContainer/ContinueButton" to="." method="_on_continue_button_pressed"] +[connection signal="pressed" from="PauseMenu/VBoxContainer/SettingsButton" to="." method="_on_settings_button_pressed"] +[connection signal="pressed" from="PauseMenu/VBoxContainer/MainMenuButton" to="." method="_on_main_menu_button_pressed"] diff --git a/source/game.gd b/source/game.gd new file mode 100644 index 0000000..8509bb8 --- /dev/null +++ b/source/game.gd @@ -0,0 +1,8 @@ +extends Node + + +# Called when the node enters the scene tree for the first time. +func _ready() -> void: + Input.mouse_mode = Input.MOUSE_MODE_CAPTURED + + AudioManager.play_audio(preload("res://Dark House.wav"), AudioManager.AMBIENCE) diff --git a/source/game.gd.uid b/source/game.gd.uid new file mode 100644 index 0000000..be713f6 --- /dev/null +++ b/source/game.gd.uid @@ -0,0 +1 @@ +uid://dbsjg3o61vuji diff --git a/source/game.tscn b/source/game.tscn new file mode 100644 index 0000000..6b7d9f2 --- /dev/null +++ b/source/game.tscn @@ -0,0 +1,83 @@ +[gd_scene load_steps=7 format=3 uid="uid://s7cw6ulb7kh7"] + +[ext_resource type="PackedScene" uid="uid://clhy3kiceqf2o" path="res://components/characters/player/player_character.tscn" id="1_80nbo"] +[ext_resource type="Script" uid="uid://dbsjg3o61vuji" path="res://game.gd" id="1_fc0e3"] +[ext_resource type="Environment" uid="uid://xe70va0pjc6c" path="res://resources/game_environment.tres" id="2_7jktm"] +[ext_resource type="Script" uid="uid://3hlvt5k34xva" path="res://components/general/player_spawn_point.gd" id="2_e2o6t"] +[ext_resource type="PackedScene" uid="uid://dawmen0hlfaaq" path="res://components/ui/menus/pause_menu/pause_menu.tscn" id="3_feb5d"] +[ext_resource type="PackedScene" uid="uid://c0jearfhlqcvr" path="res://components/hazards/saw/saw.tscn" id="5_ryrav"] + +[node name="Game" type="Node"] +script = ExtResource("1_fc0e3") + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = ExtResource("2_7jktm") + +[node name="PlayerCharacter" parent="." instance=ExtResource("1_80nbo")] + +[node name="Menus" type="CanvasLayer" parent="."] + +[node name="PauseMenu" parent="Menus" instance=ExtResource("3_feb5d")] + +[node name="Areas" type="Node" parent="."] + +[node name="IntroArea" type="Node3D" parent="Areas"] + +[node name="Blockout" type="CSGCombiner3D" parent="Areas/IntroArea"] +use_collision = true + +[node name="CSGBox3D" type="CSGBox3D" parent="Areas/IntroArea/Blockout"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -4.5) +size = Vector3(5, 4, 12) + +[node name="CSGBox3D3" type="CSGBox3D" parent="Areas/IntroArea/Blockout/CSGBox3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5) +operation = 2 +size = Vector3(4, 3, 12) + +[node name="CSGBox3D2" type="CSGBox3D" parent="Areas/IntroArea/Blockout"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 7, -22) +size = Vector3(32, 15, 27) + +[node name="CSGBox3D3" type="CSGBox3D" parent="Areas/IntroArea/Blockout/CSGBox3D2"] +operation = 2 +size = Vector3(31, 14, 25) + +[node name="CSGBox3D4" type="CSGBox3D" parent="Areas/IntroArea/Blockout/CSGBox3D2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -5.5, 12.25) +operation = 2 +size = Vector3(4, 3, 2.5) + +[node name="OmniLight3D" type="OmniLight3D" parent="Areas/IntroArea"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6, -24) +omni_range = 20.0 + +[node name="Saw" parent="Areas/IntroArea" instance=ExtResource("5_ryrav")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0, 0.5, -25) + +[node name="Saw2" parent="Areas/IntroArea" instance=ExtResource("5_ryrav")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.2, 0.5, -25) + +[node name="Saw3" parent="Areas/IntroArea" instance=ExtResource("5_ryrav")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.4, 0.5, -25) + +[node name="Saw4" parent="Areas/IntroArea" instance=ExtResource("5_ryrav")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.6, 0.5, -25) + +[node name="Saw5" parent="Areas/IntroArea" instance=ExtResource("5_ryrav")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 0.8, 0.5, -25) + +[node name="Saw6" parent="Areas/IntroArea" instance=ExtResource("5_ryrav")] +transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1, 0.5, -25) + +[node name="SpawnPoints" type="Node" parent="."] + +[node name="PlayerSpawnPoint" type="Marker3D" parent="SpawnPoints"] +script = ExtResource("2_e2o6t") +metadata/_custom_type_script = "uid://3hlvt5k34xva" + +[node name="PlayerSpawnPoint2" type="Marker3D" parent="SpawnPoints"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -15) +script = ExtResource("2_e2o6t") +spawn_index = 1 +metadata/_custom_type_script = "uid://3hlvt5k34xva" diff --git a/source/globals/autoloads/audio/audio_manager.gd b/source/globals/autoloads/audio/audio_manager.gd new file mode 100644 index 0000000..95f7963 --- /dev/null +++ b/source/globals/autoloads/audio/audio_manager.gd @@ -0,0 +1,67 @@ +extends Node + +const MASTER: StringName = &"Master" +const MUSIC: StringName = &"Music" +const SFX: StringName = &"SFX" +const AMBIENCE: StringName = &"Ambient" + + +func play_audio(stream: AudioStream, bus: StringName, force_restart: bool = false) -> void: + if is_playing_audio(stream, bus): + if force_restart: + var existing_player: AudioStreamPlayer = get_audio_player_for_stream(stream, bus) + existing_player.stop() + existing_player.play() + + return + + var player: AudioStreamPlayer = _create_audio_player(stream, bus) + player.finished.connect(stop_audio.bind(stream, bus)) + + add_child(player) + player.play() + + +func stop_audio(stream: AudioStream, bus: StringName) -> void: + var player: AudioStreamPlayer = get_audio_player_for_stream(stream, bus) + + if is_instance_valid(player): + player.queue_free() + + +func fade_audio(stream: AudioStream, volume_db: float, duration: float, bus: StringName, stop_on_finish: bool = false) -> void: + var player: AudioStreamPlayer = get_audio_player_for_stream(stream, bus) + + if not is_instance_valid(player): + return + + var tween: Tween = create_tween() + tween.tween_property(player, ^"volume_db", volume_db, duration) + + await tween.finished + + if stop_on_finish and is_instance_valid(player): + stop_audio(stream, bus) + + +func fade_audio_linear(stream: AudioStream, volume_linear: float, bus: StringName, duration: float, stop_on_finish: bool = false) -> void: + await fade_audio(stream, linear_to_db(volume_linear), duration, bus, stop_on_finish) + + +func get_audio_player_for_stream(stream: AudioStream, bus: StringName) -> AudioStreamPlayer: + for player: AudioStreamPlayer in get_children(): + if player.stream == stream and player.bus == bus: + return player + + return null + + +func is_playing_audio(stream: AudioStream, bus: StringName) -> bool: + return is_instance_valid(get_audio_player_for_stream(stream, bus)) + + +func _create_audio_player(stream: AudioStream, bus: StringName) -> AudioStreamPlayer: + var player := AudioStreamPlayer.new() + player.bus = bus + player.stream = stream + return player diff --git a/source/globals/autoloads/audio/audio_manager.gd.uid b/source/globals/autoloads/audio/audio_manager.gd.uid new file mode 100644 index 0000000..cc0c872 --- /dev/null +++ b/source/globals/autoloads/audio/audio_manager.gd.uid @@ -0,0 +1 @@ +uid://chwfg6slvsay8 diff --git a/source/globals/autoloads/audio/audio_manager.tscn b/source/globals/autoloads/audio/audio_manager.tscn new file mode 100644 index 0000000..78152ce --- /dev/null +++ b/source/globals/autoloads/audio/audio_manager.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://diduaxhewgjwa"] + +[ext_resource type="Script" uid="uid://chwfg6slvsay8" path="res://globals/autoloads/audio/audio_manager.gd" id="1_pjc45"] + +[node name="AudioManager" type="Node"] +script = ExtResource("1_pjc45") diff --git a/source/globals/autoloads/game_globals.gd b/source/globals/autoloads/game_globals.gd index 723048c..ff50577 100644 --- a/source/globals/autoloads/game_globals.gd +++ b/source/globals/autoloads/game_globals.gd @@ -1,8 +1,19 @@ extends Node +const MAIN_MENU_PATH: String = "res://components/ui/menus/main_menu/main_menu.tscn" +const GAME_PATH: String = "res://game.tscn" var player: PlayerCharacter +var spawn_index: int = 0 func get_player() -> PlayerCharacter: return player + + +func reset_game() -> void: + spawn_index = 0 + + +func set_spawn_index(index: int) -> void: + spawn_index = index diff --git a/source/globals/autoloads/input_manager.gd b/source/globals/autoloads/input_manager.gd index 2ad9e05..671690e 100644 --- a/source/globals/autoloads/input_manager.gd +++ b/source/globals/autoloads/input_manager.gd @@ -18,8 +18,12 @@ func _input(event: InputEvent) -> void: using_controller = true if event.is_action_pressed(TOGGLE_MOUSE_BUTTON): - Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if Input.mouse_mode == Input.MOUSE_MODE_VISIBLE else Input.MOUSE_MODE_VISIBLE) + toggle_mouse() func window_focused() -> bool: return DisplayServer.window_is_focused() + + +func toggle_mouse() -> void: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if Input.mouse_mode == Input.MOUSE_MODE_VISIBLE else Input.MOUSE_MODE_VISIBLE) diff --git a/source/globals/autoloads/save_manager.gd b/source/globals/autoloads/save_manager.gd new file mode 100644 index 0000000..904a972 --- /dev/null +++ b/source/globals/autoloads/save_manager.gd @@ -0,0 +1,32 @@ +extends Node + +const SAVE_PATH: String = "user://saves/" +const SAVE_FILENAME: String = "saved_game.dat" + +func save_game() -> void: + DirAccess.make_dir_recursive_absolute(SAVE_PATH) + + var file := FileAccess.open(str(SAVE_PATH, SAVE_FILENAME), FileAccess.WRITE) + + # Store the variables. + file.store_var(GameGlobals.spawn_index) + + +func load_game() -> bool: + if not save_exists(): + return false + + var file := FileAccess.open(str(SAVE_PATH, SAVE_FILENAME), FileAccess.READ) + + # Load the variables. + GameGlobals.spawn_index = file.get_var() + + return true + + +func delete_save() -> void: + DirAccess.remove_absolute(str(SAVE_PATH, SAVE_FILENAME)) + + +func save_exists() -> bool: + return FileAccess.file_exists(str(SAVE_PATH, SAVE_FILENAME)) diff --git a/source/globals/autoloads/save_manager.gd.uid b/source/globals/autoloads/save_manager.gd.uid new file mode 100644 index 0000000..4b0f5ee --- /dev/null +++ b/source/globals/autoloads/save_manager.gd.uid @@ -0,0 +1 @@ +uid://iadl2o6wkphx diff --git a/source/globals/autoloads/scene_fader/scene_fader.gd b/source/globals/autoloads/scene_fader/scene_fader.gd new file mode 100644 index 0000000..70869dc --- /dev/null +++ b/source/globals/autoloads/scene_fader/scene_fader.gd @@ -0,0 +1,67 @@ +extends CanvasLayer + + + +var fade_in_duration: float = 2.0 +var fade_out_duration: float = 2.0 +var is_fading: bool = false +var is_loading: bool = false + + +@onready var interactive_loader: InteractiveLoader = $InteractiveLoader +@onready var color_rect: ColorRect = $ColorRect +@onready var loading_hint_animations: AnimationPlayer = $HintMargin/Control/LoadingHint/LoadingHintAnimations +@onready var loading_hint: TextureRect = $HintMargin/Control/LoadingHint + + +func _ready() -> void: + color_rect.hide() + + +func load_to_path(path: String, unpause_game: bool = false) -> void: + if is_loading: + return + + is_loading = true + + await fade_in() + + var scene: PackedScene = await interactive_loader.load_threaded(path) + + assert(is_instance_valid(scene)) + + get_tree().change_scene_to_packed(scene) + + if unpause_game: + get_tree().paused = false + + fade_out() + is_loading = false + + +func fade_in() -> void: + color_rect.show() + is_fading = true + + var tween: Tween = create_tween() + tween.tween_property(color_rect, ^"color:a", 1.0, fade_in_duration) + await tween.finished + + is_fading = false + + loading_hint_animations.play(&"hover") + loading_hint.show() + + +func fade_out() -> void: + loading_hint_animations.stop() + loading_hint.hide() + + is_fading = true + + var tween: Tween = create_tween() + tween.tween_property(color_rect, ^"color:a", 0.0, fade_out_duration) + await tween.finished + + color_rect.hide() + is_fading = false diff --git a/source/globals/autoloads/scene_fader/scene_fader.gd.uid b/source/globals/autoloads/scene_fader/scene_fader.gd.uid new file mode 100644 index 0000000..af4403d --- /dev/null +++ b/source/globals/autoloads/scene_fader/scene_fader.gd.uid @@ -0,0 +1 @@ +uid://cynllcoh2smgv diff --git a/source/globals/autoloads/scene_fader/scene_fader.tscn b/source/globals/autoloads/scene_fader/scene_fader.tscn new file mode 100644 index 0000000..5727e28 --- /dev/null +++ b/source/globals/autoloads/scene_fader/scene_fader.tscn @@ -0,0 +1,125 @@ +[gd_scene load_steps=7 format=3 uid="uid://dis4efdm5s2fc"] + +[ext_resource type="Script" uid="uid://cynllcoh2smgv" path="res://globals/autoloads/scene_fader/scene_fader.gd" id="1_7tt87"] +[ext_resource type="Script" uid="uid://d0k03wk1s7cw0" path="res://components/general/interactive_loader.gd" id="2_dwqb8"] +[ext_resource type="Texture2D" uid="uid://dhw8y2oqxvgwu" path="res://godot_icon.svg" id="3_dwqb8"] + +[sub_resource type="Animation" id="Animation_t3447"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [-0.261799] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(1112, 608)] +} + +[sub_resource type="Animation" id="Animation_dwqb8"] +resource_name = "hover" +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:rotation") +tracks/0/interp = 2 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.5), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [0.174533, -0.174533] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".:position") +tracks/1/interp = 2 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0.25, 0.75), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector2(0, 0), Vector2(0, 5)] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_e571n"] +_data = { +&"RESET": SubResource("Animation_t3447"), +&"hover": SubResource("Animation_dwqb8") +} + +[node name="SceneFader" type="CanvasLayer"] +process_mode = 3 +layer = 10 +script = ExtResource("1_7tt87") + +[node name="InteractiveLoader" type="Node" parent="."] +script = ExtResource("2_dwqb8") +metadata/_custom_type_script = "uid://d0k03wk1s7cw0" + +[node name="ColorRect" type="ColorRect" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0, 0, 0, 1) + +[node name="HintMargin" type="MarginContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +theme_override_constants/margin_left = 16 +theme_override_constants/margin_top = 16 +theme_override_constants/margin_right = 16 +theme_override_constants/margin_bottom = 16 + +[node name="Control" type="Control" parent="HintMargin"] +custom_minimum_size = Vector2(64, 64) +layout_mode = 2 +size_flags_horizontal = 8 +size_flags_vertical = 8 +mouse_filter = 2 + +[node name="LoadingHint" type="TextureRect" parent="HintMargin/Control"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 1112.0 +offset_top = 608.0 +offset_right = 1112.0 +offset_bottom = 608.0 +grow_horizontal = 2 +grow_vertical = 2 +rotation = -0.261799 +pivot_offset = Vector2(20, 32) +mouse_filter = 2 +texture = ExtResource("3_dwqb8") +expand_mode = 5 + +[node name="LoadingHintAnimations" type="AnimationPlayer" parent="HintMargin/Control/LoadingHint"] +libraries = { +&"": SubResource("AnimationLibrary_e571n") +} diff --git a/source/globals/autoloads/settings/settings_manager.gd b/source/globals/autoloads/settings/settings_manager.gd new file mode 100644 index 0000000..206e7fa --- /dev/null +++ b/source/globals/autoloads/settings/settings_manager.gd @@ -0,0 +1,71 @@ +extends Node + +const SETTINGS_PATH: String = "user://settings.cfg" + +var settings: Dictionary[String, Dictionary] = { + &"game": { + &"has_compiled_shaders": false, + }, + &"audio": { + &"Master": 1.0, + &"SFX": 1.0, + &"Music": 1.0, + &"Ambient": 1.0, + }, + &"video": { + &"fullscreen": true + } +} + + +func _ready() -> void: + load_settings() + + +func load_settings() -> void: + if not FileAccess.file_exists(SETTINGS_PATH): + save_settings() + return + + var config := ConfigFile.new() + config.load(SETTINGS_PATH) + + for section: String in settings.keys(): + for key: String in settings[section].keys(): + var default: Variant = get_setting(section, key) + set_setting(section, key, config.get_value(section, key, default), false) + + +func save_settings() -> void: + var config := ConfigFile.new() + + for section: String in settings.keys(): + for key: String in settings[section].keys(): + config.set_value(section, key, settings[section][key]) + + config.save(SETTINGS_PATH) + + +func set_setting(section: String, key: String, value: Variant, do_save: bool = true) -> void: + settings[section][key] = value + + if do_save: + save_settings() + + +func get_setting(section: String, key: String) -> Variant: + return settings[section][key] + + +func adjust_volume(bus: StringName, volume: float) -> void: + set_setting(&"audio", bus, volume, false) + return + + var fmod_bus: FmodBus = FmodServer.get_bus(str("res://components/fmod/Build/Desktop/", bus, ".bank")) + if is_instance_valid(fmod_bus): + fmod_bus.volume = volume + + +func set_fullscreen(fullscreened: bool) -> void: + DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN if fullscreened else DisplayServer.WINDOW_MODE_WINDOWED) + set_setting(&"video", &"fullscreen", fullscreened) diff --git a/source/globals/autoloads/settings/settings_manager.gd.uid b/source/globals/autoloads/settings/settings_manager.gd.uid new file mode 100644 index 0000000..028683e --- /dev/null +++ b/source/globals/autoloads/settings/settings_manager.gd.uid @@ -0,0 +1 @@ +uid://py4o5sbsljq4 diff --git a/source/localization/de.mo b/source/localization/de.mo new file mode 100644 index 0000000000000000000000000000000000000000..624a9c34b63febb0f9444ca2004b15ae01ab3eb7 GIT binary patch literal 432 zcmYk1y-ve06om~Gfr40=8S(-yze5$o0IjJak+hJMvLTb)2BY9qiGyHcgoOc#1s24{ z3o-I69G6Pv%AbzUwS8>=tTkR4Y7wl14p;&?u=NO*!P8Vm19<@VJz^%B3mFNk?b3%!tP%Z~l4D zP00!TK+LkYnww6$(1tWJ?#IY8bZ0ikxm0@3O|E2Fk=Y-_N4z!LXYU$O$%RgeRO!rf zTbIf>=e$dr%D+eS3rdx7cbdD+ZHEm>8GL7~C@0NAs;P1#>)0WYPSF!eSBCPu)*0L{ DT+VB7 literal 0 HcmV?d00001 diff --git a/source/localization/de.po b/source/localization/de.po new file mode 100644 index 0000000..a5a3096 --- /dev/null +++ b/source/localization/de.po @@ -0,0 +1,38 @@ +# LANGUAGE translation for MagicNStuff for the following files: +# res://components/ui/menus/main_menu/main_menu.tscn +# +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MagicNStuff\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.4.2\n" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "Magic N' Stuff" +msgstr "" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "CONTINUE" +msgstr "Weiterspielen" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "NEW_GAME" +msgstr "Neues Spiel" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "SETTINGS" +msgstr "Einstellungen" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "QUIT" +msgstr "Beenden" diff --git a/source/localization/en.mo b/source/localization/en.mo new file mode 100644 index 0000000000000000000000000000000000000000..5a61dda23bd893279e711271379673932157056c GIT binary patch literal 416 zcmYk0Jx{|h5QYsDfif~P_z$>z4pk5XYC{x>q$x>(4VmN;j9RC1E_`f^uvS70EUf$? zMt%$D5~-a0==J;hbmyO~&KsjzC$@FC?i@eKg|0ML-XdI+0@luNYgvF-1gA7HGiwiKd zsc+KkJD4pTlU#q1sLJ!tjd)xUEaG<=v)aO nG?>3n#1-TU`9b%vyYDc&Lg@xr1P|PoQ(&V;Axi)$E^GD+l@(;f literal 0 HcmV?d00001 diff --git a/source/localization/en.po b/source/localization/en.po new file mode 100644 index 0000000..85c9fd7 --- /dev/null +++ b/source/localization/en.po @@ -0,0 +1,38 @@ +# LANGUAGE translation for MagicNStuff for the following files: +# res://components/ui/menus/main_menu/main_menu.tscn +# +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MagicNStuff\n" +"POT-Creation-Date: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.4.2\n" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "Magic N' Stuff" +msgstr "" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "CONTINUE" +msgstr "Continue" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "NEW_GAME" +msgstr "New Game" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "SETTINGS" +msgstr "Settings" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "QUIT" +msgstr "Quit" diff --git a/source/localization/translation.pot b/source/localization/translation.pot new file mode 100644 index 0000000..c283265 --- /dev/null +++ b/source/localization/translation.pot @@ -0,0 +1,32 @@ +# LANGUAGE translation for MagicNStuff for the following files: +# res://components/ui/menus/main_menu/main_menu.tscn +# +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: MagicNStuff\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8-bit\n" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "Magic N' Stuff" +msgstr "" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "CONTINUE" +msgstr "" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "NEW_GAME" +msgstr "" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "SETTINGS" +msgstr "" + +#: components/ui/menus/main_menu/main_menu.tscn +msgid "QUIT" +msgstr "" diff --git a/source/main.tscn b/source/main.tscn deleted file mode 100644 index 8b94191..0000000 --- a/source/main.tscn +++ /dev/null @@ -1,3 +0,0 @@ -[gd_scene format=3 uid="uid://cvj5b6ygk8u02"] - -[node name="Main" type="Node"] diff --git a/source/maps/_dynamic_load_test/_dynamic_load_test_map.tscn b/source/maps/_dynamic_load_test/_dynamic_load_test_map.tscn index 59636be..d4e454a 100644 --- a/source/maps/_dynamic_load_test/_dynamic_load_test_map.tscn +++ b/source/maps/_dynamic_load_test/_dynamic_load_test_map.tscn @@ -18,7 +18,8 @@ sky = SubResource("Sky_yaqeo") tonemap_mode = 2 glow_enabled = true -[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_g60qb"] +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_g60qb"] +albedo_color = Color(1, 0.426083, 0.0827108, 1) [sub_resource type="BoxShape3D" id="BoxShape3D_g60qb"] size = Vector3(9, 4, 9) @@ -44,8 +45,7 @@ size = Vector3(22, 4, 7) [sub_resource type="BoxShape3D" id="BoxShape3D_0qpgw"] size = Vector3(9, 4, 25) -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_g60qb"] -albedo_color = Color(1, 0.426083, 0.0827108, 1) +[sub_resource type="WorldBoundaryShape3D" id="WorldBoundaryShape3D_g60qb"] [sub_resource type="CylinderMesh" id="CylinderMesh_g60qb"] @@ -61,6 +61,94 @@ shadow_enabled = true [node name="WorldEnvironment" type="WorldEnvironment" parent="."] environment = SubResource("Environment_4rgsp") +[node name="Areas" type="Node" parent="."] + +[node name="AlwaysLoaded" type="CSGCombiner3D" parent="Areas"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 9) +use_collision = true + +[node name="CSGBox3D" type="CSGBox3D" parent="Areas/AlwaysLoaded"] +size = Vector3(8, 1, 7) +material = SubResource("StandardMaterial3D_g60qb") + +[node name="PerformanceTestPlatform1" type="Area3D" parent="Areas" node_paths=PackedStringArray("placeholder_node")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 0) +script = ExtResource("1_q4yy4") +placeholder_node = NodePath("Area1") +loaded_if_spawnpoint = Array[int]([0]) +metadata/_custom_type_script = "uid://bj2bhtdul8xct" + +[node name="Area1" parent="Areas/PerformanceTestPlatform1" instance_placeholder="res://maps/_dynamic_load_test/area_1.tscn"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -2, 2) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Areas/PerformanceTestPlatform1"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 2) +shape = SubResource("BoxShape3D_g60qb") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="PerformanceTestPlatform2" type="Area3D" parent="Areas" node_paths=PackedStringArray("placeholder_node")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, -7) +script = ExtResource("1_q4yy4") +placeholder_node = NodePath("Area2") +loaded_if_spawnpoint = Array[int]([1]) +metadata/_custom_type_script = "uid://bj2bhtdul8xct" + +[node name="Area2" parent="Areas/PerformanceTestPlatform2" instance_placeholder="res://maps/_dynamic_load_test/area_2.tscn"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -2, 2) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Areas/PerformanceTestPlatform2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 2) +shape = SubResource("BoxShape3D_yaqeo") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="CollisionShape3D2" type="CollisionShape3D" parent="Areas/PerformanceTestPlatform2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 3.67773) +shape = SubResource("BoxShape3D_4rgsp") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="CollisionShape3D3" type="CollisionShape3D" parent="Areas/PerformanceTestPlatform2"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.5, 0.5, 5.67773) +shape = SubResource("BoxShape3D_m4fap") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="Hallway1Loader" type="Area3D" parent="Areas" node_paths=PackedStringArray("placeholder_node")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, -7) +script = ExtResource("1_q4yy4") +placeholder_node = NodePath("Hallway1") +metadata/_custom_type_script = "uid://bj2bhtdul8xct" + +[node name="Hallway1" parent="Areas/Hallway1Loader" instance_placeholder="res://maps/_dynamic_load_test/hallway_1.tscn"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, -2, 16) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Areas/Hallway1Loader"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 17.85) +shape = SubResource("BoxShape3D_k1ge7") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="Hallway2Loader" type="Area3D" parent="Areas" node_paths=PackedStringArray("placeholder_node")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, -7) +script = ExtResource("1_q4yy4") +placeholder_node = NodePath("Hallway2") +metadata/_custom_type_script = "uid://bj2bhtdul8xct" + +[node name="Hallway2" parent="Areas/Hallway2Loader" instance_placeholder="res://maps/_dynamic_load_test/hallway_2.tscn"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, -2, 16) + +[node name="CollisionShape3D" type="CollisionShape3D" parent="Areas/Hallway2Loader"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 25.5) +shape = SubResource("BoxShape3D_ka7nb") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="CollisionShape3D2" type="CollisionShape3D" parent="Areas/Hallway2Loader"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.5, 0.5, 3.67773) +shape = SubResource("BoxShape3D_kaxur") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + +[node name="CollisionShape3D3" type="CollisionShape3D" parent="Areas/Hallway2Loader"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14, 0.5, 12.6777) +shape = SubResource("BoxShape3D_0qpgw") +debug_color = Color(0.678973, 0.504376, 0, 0.42) + [node name="WorldFloor" type="StaticBody3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) metadata/_edit_lock_ = true @@ -69,90 +157,6 @@ metadata/_edit_group_ = true [node name="CollisionShape3D" type="CollisionShape3D" parent="WorldFloor"] shape = SubResource("WorldBoundaryShape3D_g60qb") -[node name="DynamicAreaLoader3D" type="Area3D" parent="." node_paths=PackedStringArray("placeholder_node")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 0) -script = ExtResource("1_q4yy4") -placeholder_node = NodePath("Area1") -metadata/_custom_type_script = "uid://bj2bhtdul8xct" - -[node name="Area1" parent="DynamicAreaLoader3D" instance_placeholder="res://maps/_dynamic_load_test/area_1.tscn"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -2, 2) - -[node name="CollisionShape3D" type="CollisionShape3D" parent="DynamicAreaLoader3D"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 2) -shape = SubResource("BoxShape3D_g60qb") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="DynamicAreaLoader3D2" type="Area3D" parent="." node_paths=PackedStringArray("placeholder_node")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, -7) -script = ExtResource("1_q4yy4") -placeholder_node = NodePath("Area2") -metadata/_custom_type_script = "uid://bj2bhtdul8xct" - -[node name="Area2" parent="DynamicAreaLoader3D2" instance_placeholder="res://maps/_dynamic_load_test/area_2.tscn"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, -2, 2) - -[node name="CollisionShape3D" type="CollisionShape3D" parent="DynamicAreaLoader3D2"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 2) -shape = SubResource("BoxShape3D_yaqeo") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="CollisionShape3D2" type="CollisionShape3D" parent="DynamicAreaLoader3D2"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12.5, 0.5, 3.67773) -shape = SubResource("BoxShape3D_4rgsp") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="CollisionShape3D3" type="CollisionShape3D" parent="DynamicAreaLoader3D2"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.5, 0.5, 5.67773) -shape = SubResource("BoxShape3D_m4fap") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="Hallway1Loader" type="Area3D" parent="." node_paths=PackedStringArray("placeholder_node")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, -7) -script = ExtResource("1_q4yy4") -placeholder_node = NodePath("Hallway1") -metadata/_custom_type_script = "uid://bj2bhtdul8xct" - -[node name="Hallway1" parent="Hallway1Loader" instance_placeholder="res://maps/_dynamic_load_test/hallway_1.tscn"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, -2, 16) - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Hallway1Loader"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 17.85) -shape = SubResource("BoxShape3D_k1ge7") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="Hallway2Loader" type="Area3D" parent="." node_paths=PackedStringArray("placeholder_node")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, -7) -script = ExtResource("1_q4yy4") -placeholder_node = NodePath("Hallway2") -metadata/_custom_type_script = "uid://bj2bhtdul8xct" - -[node name="Hallway2" parent="Hallway2Loader" instance_placeholder="res://maps/_dynamic_load_test/hallway_2.tscn"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2, -2, 16) - -[node name="CollisionShape3D" type="CollisionShape3D" parent="Hallway2Loader"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0.5, 25.5) -shape = SubResource("BoxShape3D_ka7nb") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="CollisionShape3D2" type="CollisionShape3D" parent="Hallway2Loader"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.5, 0.5, 3.67773) -shape = SubResource("BoxShape3D_kaxur") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="CollisionShape3D3" type="CollisionShape3D" parent="Hallway2Loader"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -14, 0.5, 12.6777) -shape = SubResource("BoxShape3D_0qpgw") -debug_color = Color(0.678973, 0.504376, 0, 0.42) - -[node name="AlwaysLoaded" type="CSGCombiner3D" parent="."] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 9) -use_collision = true - -[node name="CSGBox3D" type="CSGBox3D" parent="AlwaysLoaded"] -size = Vector3(8, 1, 7) -material = SubResource("StandardMaterial3D_g60qb") - [node name="MeshInstance3D" type="MeshInstance3D" parent="."] transform = Transform3D(5.58473, 6.33307, 0, -6.33307, 5.58473, 0, 0, 0, 8.44375, -13.6652, 0, -15.4998) mesh = SubResource("CylinderMesh_g60qb") @@ -162,5 +166,17 @@ transform = Transform3D(0.330597, 0, 0.943772, 0, 1, 0, -0.943772, 0, 0.330597, script = ExtResource("3_yaqeo") metadata/_custom_type_script = "uid://3hlvt5k34xva" +[node name="PlayerSpawnPoint2" type="Marker3D" parent="."] +transform = Transform3D(0.330597, 0, 0.943772, 0, 1, 0, -0.943772, 0, 0.330597, 2.60837, 0.5, -2.6832) +script = ExtResource("3_yaqeo") +spawn_index = 1 +metadata/_custom_type_script = "uid://3hlvt5k34xva" + +[node name="PlayerSpawnPoint3" type="Marker3D" parent="."] +transform = Transform3D(0.43358, 0, -0.901115, 0, 1, 0, 0.901115, 0, 0.43358, -14.3916, 0.5, -2.6832) +script = ExtResource("3_yaqeo") +spawn_index = 2 +metadata/_custom_type_script = "uid://3hlvt5k34xva" + [node name="Saw" parent="." instance=ExtResource("4_4rgsp")] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.31477, 1.59362, 6.44809) diff --git a/source/project.godot b/source/project.godot index 93d03f7..27d7dae 100644 --- a/source/project.godot +++ b/source/project.godot @@ -11,13 +11,18 @@ config_version=5 [application] config/name="MagicNStuff" +run/main_scene="uid://coga3ke4xw3a0" config/features=PackedStringArray("4.4", "Forward Plus") config/icon="uid://bovb32x4x3ps5" [autoload] +SettingsManager="*res://globals/autoloads/settings/settings_manager.gd" +SceneFader="*res://globals/autoloads/scene_fader/scene_fader.tscn" GameGlobals="*res://globals/autoloads/game_globals.gd" InputManager="*res://globals/autoloads/input_manager.gd" +SaveManager="*res://globals/autoloads/save_manager.gd" +AudioManager="*res://globals/autoloads/audio/audio_manager.tscn" Logger="*res://addons/logger/logger.tscn" RunConfigManager="*res://addons/run-configs/run-config-manager.gd" VersionDisplay="*res://addons/version_display/version_display.tscn" @@ -33,7 +38,9 @@ folder_colors={ "res://addons/": "gray", "res://components/": "green", "res://globals/": "orange", -"res://maps/": "yellow" +"res://localization/": "teal", +"res://maps/": "yellow", +"res://resources/": "purple" } [input] @@ -99,6 +106,12 @@ camera_right={ "events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":1.0,"script":null) ] } +pause={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"pressure":0.0,"pressed":false,"script":null) +] +} toggle_console={ "deadzone": 0.2, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194341,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) @@ -129,3 +142,8 @@ bbcode_edit/editor/open_current_file_documentation={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194332,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } + +[internationalization] + +locale/translations=PackedStringArray("res://localization/de.mo", "res://localization/de.po", "res://localization/en.mo", "res://localization/en.po") +locale/translations_pot_files=PackedStringArray("res://components/ui/menus/main_menu/main_menu.tscn") diff --git a/source/resources/game_environment.tres b/source/resources/game_environment.tres new file mode 100644 index 0000000..231a936 --- /dev/null +++ b/source/resources/game_environment.tres @@ -0,0 +1,8 @@ +[gd_resource type="Environment" format=3 uid="uid://xe70va0pjc6c"] + +[resource] +tonemap_mode = 3 +ssao_enabled = true +ssao_radius = 0.7 +ssao_intensity = 1.0 +glow_enabled = true