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 0000000..624a9c3 Binary files /dev/null and b/source/localization/de.mo differ 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 0000000..5a61dda Binary files /dev/null and b/source/localization/en.mo differ 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