Refactor skill components and update resource paths for consistency; enhance skill management in scenes

This commit is contained in:
2025-08-26 20:10:18 +02:00
parent 4c15f50f6e
commit 6e71c321f7
60 changed files with 89 additions and 1847 deletions

View File

@@ -1,11 +0,0 @@
extends Node
var settings_config := ConfigFile.new()
const SETTINGS_PATH := "user://settings.ini"
func _ready() -> void:
if !FileAccess.file_exists(SETTINGS_PATH):
settings_config.save(SETTINGS_PATH)
else:
settings_config.load(SETTINGS_PATH)

View File

@@ -1 +0,0 @@
uid://dueoywjgtwv7m

View File

@@ -1,42 +0,0 @@
extends Node
@export var save_path: String = "user://savegame.save"
@export var version: int = 1
@onready var gm: GM = $"/root/GameManager"
func save_game():
var save_data := {
"player_state": gm.player_state,
"version": version,
}
var file := FileAccess.open(save_path, FileAccess.WRITE)
file.store_var(save_data)
file.close()
print("Game saved to: ", save_path)
func load_game() -> bool:
if not FileAccess.file_exists(save_path):
return false
var file := FileAccess.open(save_path, FileAccess.READ)
var save_data: Dictionary = file.get_var()
file.close()
if save_data.has("version") and save_data["version"] != version:
print("Save file version mismatch. Expected: ", version, ", Found: ", save_data["version"])
return false
print("Game state loaded from: ", save_path)
print("Player state: ", save_data["player_state"])
gm.player_state = save_data["player_state"]
var skills: Array[SkillData] = []
for skill in gm.player_state["unlocked_skills"]:
skills.append(skill)
gm.unlock_skills(skills)
return true
func check_save_exists() -> bool:
return FileAccess.file_exists(save_path)

View File

@@ -1 +0,0 @@
uid://d3tgf7fyr6xek

View File

@@ -1,169 +0,0 @@
extends Node
## A globally accessible manager for device-specific actions using SteamInput for any controller
## and standard Godot Input for the keyboard.
##
## All methods in this class that have a "device" parameter can accept -1
## which means the keyboard device.
# The actions defined in the Steam .vdf file are listed here
# with true or false indicating if input is analog or digital.
# False is digital (buttons), true is analog (joysticks, triggers, etc).
var action_names := {
"move": true,
"jump": false,
"left": false,
"right": false,
"down": false,
"up": false,
"interact": false,
"pause": false,
}
var got_handles := false
var game_action_set
var current_action_set
var actions := {}
# Store the state of each action and the frame it entered that state.
var action_states := {}
func init() -> void:
Steam.input_device_connected.connect(_on_steam_input_device_connected)
Steam.input_device_disconnected.connect(_on_steam_input_device_disconnected)
func _on_steam_input_device_connected(input_handle: int) -> void:
if not got_handles:
get_handles()
Steam.activateActionSet(input_handle, current_action_set)
print("Device connected %s" % str(input_handle))
func _on_steam_input_device_disconnected(input_handle: int) -> void:
print("Device disconnected %s" % str(input_handle))
func get_handles() -> void:
got_handles = true
game_action_set = Steam.getActionSetHandle("GameControls")
current_action_set = game_action_set
get_action_handles(action_names)
func get_action_handles(action_names: Dictionary) -> void:
for action in action_names.keys():
if action_names[action]:
actions[action] = Steam.getAnalogActionHandle(action)
else:
actions[action] = Steam.getDigitalActionHandle(action)
func get_controllers() -> Array[int]:
var controllers: Array[int] = [-1]
var steam_controllers = Steam.getConnectedControllers()
if steam_controllers:
controllers.append_array(steam_controllers)
return controllers
func get_action_strength(device: int, action: StringName, exact_match: bool = false) -> float:
if device >= 0:
if not got_handles: return 0
var action_data = Steam.getAnalogActionData(device, actions[action])
return action_data.x
return Input.get_action_strength(action, exact_match)
func get_axis(device: int, negative_action: StringName, positive_action: StringName) -> float:
if device >= 0:
if not got_handles: return 0
var negative = Steam.getAnalogActionData(device, actions[negative_action])
var positive = Steam.getAnalogActionData(device, actions[positive_action])
return positive.x - negative.x
return Input.get_axis(negative_action, positive_action)
func get_vector(device: int, negative_x: StringName, positive_x: StringName, negative_y: StringName, positive_y: StringName, deadzone: float = -1.0) -> Vector2:
if device >= 0:
if not got_handles: return Vector2.ZERO
var negative_x_val = Steam.getAnalogActionData(device, actions[negative_x])
var positive_x_val = Steam.getAnalogActionData(device, actions[positive_x])
var negative_y_val = Steam.getAnalogActionData(device, actions[negative_y])
var positive_y_val = Steam.getAnalogActionData(device, actions[positive_y])
# Steam's y axis is inverted compared to Godot
return Vector2(positive_x_val - negative_x_val, -(positive_y_val - negative_y_val)).normalized()
return Input.get_vector(negative_x, positive_x, negative_y, positive_y, deadzone)
func get_move_input(device: int) -> Vector2:
if device >= 0:
if not got_handles: return Vector2.ZERO
# Get the analog stick movement
var action_data = Steam.getAnalogActionData(device, actions["Move"])
return Vector2(action_data.x, -action_data.y).normalized()
return Vector2(Input.get_axis("left", "right"), Input.get_axis("up", "down")).normalized()
func get_action_state(device: int, action: String) -> Dictionary:
# Get the current action, but create the defaults along the way if they don't exist.
if not action_states.get(device):
action_states[device] = {}
if not action_states[device].get(action):
action_states[device][action] = { "held": false, "press_frame": -1, "release_frame": -1 }
return action_states[device][action]
func set_action_state(device: int, action: StringName, currently_held: bool, current_frame: int) -> Dictionary:
# Get the state of the action last frame
var previous_action_state := get_action_state(device, action)
# If we're pressing the action now and we weren't pressing it last frame,
# track that we pressed the action this frame.
if currently_held and not previous_action_state.held:
action_states[device][action].held = true
action_states[device][action].press_frame = current_frame
# If we're not pressing it this frame but we were pressing it last frame,
# track that we released the action this frame.
elif not currently_held and previous_action_state.held:
action_states[device][action].held = false
action_states[device][action].release_frame = current_frame
# Return the current state of the action
return action_states[device][action]
func is_action_pressed(device: int, action: StringName, exact_match: bool = false) -> bool:
if device >= 0:
if not got_handles: return false
var current_frame := Engine.get_process_frames()
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
set_action_state(device, action, currently_held, current_frame)
return currently_held
# If keyboard, use normal Godot input system.
return Input.is_action_pressed(action, exact_match)
func is_action_just_pressed(device: int, action: StringName, exact_match: bool = false) -> bool:
if device >= 0:
if not got_handles: return false
var current_frame := Engine.get_process_frames()
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
var action_state := set_action_state(device, action, currently_held, current_frame)
return currently_held and action_state.press_frame == current_frame
# If keyboard, use normal Godot input system.
return Input.is_action_just_pressed(action, exact_match)
func is_action_just_released(device: int, action: StringName, exact_match: bool = false) -> bool:
if device >= 0:
if not got_handles: return false
var current_frame := Engine.get_process_frames()
var currently_held = Steam.getDigitalActionData(device, actions[action]).state
var action_state := set_action_state(device, action, currently_held, current_frame)
return not currently_held and action_state.release_frame == current_frame
# If keyboard, use normal Godot input system.
return Input.is_action_just_released(action, exact_match)

View File

@@ -1 +0,0 @@
uid://ctb7ehok6dme3

View File

@@ -1,54 +0,0 @@
extends Node
@export var ui_stack: Array[Control] = []
signal screen_pushed(screen: Control)
signal screen_popped(screen: Control)
func push_screen(screen: Control) -> void:
if not screen:
push_error("Cannot push a null screen.")
return
ui_stack.append(screen)
screen.show()
screen.set_process_input(true)
screen.set_focus_mode(Control.FOCUS_ALL)
screen.grab_focus()
screen_pushed.emit(screen)
func pop_screen() -> void:
if ui_stack.is_empty():
return
var top: Control = ui_stack.pop_back()
top.hide()
top.set_process_input(false)
screen_popped.emit(top)
top.accept_event()
if not ui_stack.is_empty():
ui_stack.back().grab_focus()
func top_screen() -> Control:
return ui_stack.back() if not ui_stack.is_empty() else null
func is_screen_on_top(screen: Control) -> bool:
return not ui_stack.is_empty() and ui_stack.back() == screen
func is_visible_on_stack(screen: Control) -> bool:
return ui_stack.has(screen) and screen.visible
func close_all() -> void:
while not ui_stack.is_empty():
pop_screen()
func hide_and_disable(screen: Control) -> void:
screen.hide()
screen.set_process_input(false)

View File

@@ -1 +0,0 @@
uid://vmhlsc3fu3bn

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=42 format=3 uid="uid://bqi5s710xb1ju"]
[gd_scene load_steps=48 format=3 uid="uid://bqi5s710xb1ju"]
[ext_resource type="Script" uid="uid://csel4s0e4g5uf" path="res://scripts/components/PlayerController.cs" id="1_yysbb"]
[ext_resource type="Shader" uid="uid://bs4xvm4qkurpr" path="res://shaders/hit_flash.tres" id="2_lgb3u"]
@@ -21,7 +21,13 @@
[ext_resource type="AudioStream" uid="uid://duj2q0rqytaxg" path="res://sfx/jump.wav" id="18_pysae"]
[ext_resource type="AudioStream" uid="uid://bmfn6p88gy575" path="res://sfx/player_hurt.wav" id="19_7anly"]
[ext_resource type="Script" uid="uid://dlh5xcv2sy82s" path="res://scripts/components/SkillUnlockedComponent.cs" id="19_gwc8i"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="19_yysbb"]
[ext_resource type="AudioStream" uid="uid://ycgtf6wj7mto" path="res://sfx/heal.wav" id="20_bptj5"]
[ext_resource type="Resource" uid="uid://dw5ee2lpeypnb" path="res://resources/skills/brick_throw.tres" id="20_o1ihh"]
[ext_resource type="Resource" uid="uid://cdp8sex36vdq2" path="res://resources/skills/explosive_brick.tres" id="21_ur2y5"]
[ext_resource type="Resource" uid="uid://cr5lo4h8wm0jc" path="res://resources/skills/fire_brick.tres" id="22_7til7"]
[ext_resource type="Resource" uid="uid://ceakv6oqob6m7" path="res://resources/skills/ice_brick.tres" id="23_e5pae"]
[ext_resource type="Resource" uid="uid://d3bjre2etov1n" path="res://resources/skills/magnetic.tres" id="24_xuhvf"]
[ext_resource type="Script" uid="uid://bo506l4x0808e" path="res://scripts/components/HitComponent.cs" id="26_6n1ss"]
[ext_resource type="Script" uid="uid://cjcc7fia15wu3" path="res://scripts/components/CanBeLaunchedComponent.cs" id="27_oefns"]
[ext_resource type="PackedScene" uid="uid://bg76mtpcmfm2j" path="res://objects/ui/charging_bar_layer.tscn" id="28_3f5nm"]
@@ -201,9 +207,11 @@ Root = NodePath("..")
[node name="SkillManager" type="Node" parent="."]
script = ExtResource("18_6lsog")
AvailableSkills = Array[ExtResource("19_yysbb")]([ExtResource("20_o1ihh"), ExtResource("21_ur2y5"), ExtResource("22_7til7"), ExtResource("23_e5pae"), ExtResource("24_xuhvf")])
[node name="SkillUnlockerComponent" type="Node" parent="."]
[node name="SkillUnlockerComponent" type="Node" parent="." node_paths=PackedStringArray("SkillManager")]
script = ExtResource("19_gwc8i")
SkillManager = NodePath("../SkillManager")
[node name="HitComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Health", "HitFx")]
script = ExtResource("26_6n1ss")

View File

@@ -1,11 +1,11 @@
[gd_scene load_steps=4 format=3 uid="uid://coayig4dxelo2"]
[ext_resource type="Script" uid="uid://cm06xg1l3xtw5" path="res://scripts/components/brick_throw.gd" id="1_hniwk"]
[ext_resource type="Script" uid="uid://b0bv8kw5w5037" path="res://scripts/components/BrickThrowComponent.cs" id="1_ogpnm"]
[ext_resource type="PackedScene" uid="uid://bymro4t7angv5" path="res://objects/entities/brick.tscn" id="2_4txoq"]
[ext_resource type="Resource" uid="uid://br84dsfa3ti04" path="res://resources/throw_behaviors/tap_throw_input.tres" id="3_gxahf"]
[node name="BrickThrowComponent" type="Node"]
script = ExtResource("1_hniwk")
brick_scene = ExtResource("2_4txoq")
fire_rate = 0.3
throw_input_behavior = ExtResource("3_gxahf")
script = ExtResource("1_ogpnm")
BrickScene = ExtResource("2_4txoq")
FireRate = 0.3
ThrowInputBehavior = ExtResource("3_gxahf")

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cunyndudjh2he"]
[ext_resource type="Script" uid="uid://ce8w71vgv37pt" path="res://scripts/components/magnetic_skill.gd" id="1_lwbas"]
[ext_resource type="Script" uid="uid://bi5nx8s1gisbd" path="res://scripts/components/MagneticSkillComponent.cs" id="1_xua8f"]
[node name="MagneticSkill" type="Node"]
script = ExtResource("1_lwbas")
script = ExtResource("1_xua8f")

View File

@@ -1,7 +1,13 @@
[gd_scene load_steps=6 format=3 uid="uid://dlm2ri562fynd"]
[gd_scene load_steps=12 format=3 uid="uid://dlm2ri562fynd"]
[ext_resource type="Script" uid="uid://bnc16gndpl87i" path="res://scripts/UI/Marketplace.cs" id="1_li4x3"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="2_c7w2b"]
[ext_resource type="FontFile" uid="uid://xm0vbusjr7b7" path="res://fonts/PressStart2P-Regular.ttf" id="2_ho1tm"]
[ext_resource type="Resource" uid="uid://dw5ee2lpeypnb" path="res://resources/skills/brick_throw.tres" id="3_1dl8j"]
[ext_resource type="Resource" uid="uid://cdp8sex36vdq2" path="res://resources/skills/explosive_brick.tres" id="4_qdv1c"]
[ext_resource type="Resource" uid="uid://cr5lo4h8wm0jc" path="res://resources/skills/fire_brick.tres" id="5_4m43l"]
[ext_resource type="Resource" uid="uid://ceakv6oqob6m7" path="res://resources/skills/ice_brick.tres" id="6_ialmx"]
[ext_resource type="Resource" uid="uid://d3bjre2etov1n" path="res://resources/skills/magnetic.tres" id="7_cycc1"]
[ext_resource type="PackedScene" uid="uid://dtl03rod7l2t0" path="res://objects/ui/marketplace_button.tscn" id="9_ode10"]
[ext_resource type="PackedScene" uid="uid://ceqjwmihj70lt" path="res://objects/ui/skill_button.tscn" id="10_c7w2b"]
@@ -16,6 +22,7 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_li4x3")
Skills = Array[ExtResource("2_c7w2b")]([ExtResource("3_1dl8j"), ExtResource("4_qdv1c"), ExtResource("5_4m43l"), ExtResource("6_ialmx"), ExtResource("7_cycc1")])
ToUnlockGrid = NodePath("PanelContainer/MarginContainer/VBoxContainer/ToUnlockGridContainer")
UnlockedGrid = NodePath("PanelContainer/MarginContainer/VBoxContainer/UnlockedGridContainer")
Font = ExtResource("2_ho1tm")

View File

@@ -32,13 +32,9 @@ config/icon="uid://jix7wdn0isr3"
GameManager="*res://objects/game_manager.tscn"
PhantomCameraManager="*res://addons/phantom_camera/scripts/managers/phantom_camera_manager.gd"
AudioController="*res://objects/audio_controller.tscn"
SteamIntegrationNode="*res://objects/steam_integration.tscn"
SteamControllerInput="*res://autoloads/steam_controller_input.gd"
AchievementsManager="*res://objects/achievements.tscn"
UIManager="*res://Autoloads/UIManager.cs"
ConfigFileHandler="*res://Autoloads/ConfigFileHandler.cs"
SaveSystem="*res://Autoloads/SaveSystem.cs"
Console="*res://addons/console/console.gd"
[debug]

View File

@@ -1,6 +1,7 @@
[gd_resource type="Resource" load_steps=4 format=3 uid="uid://dw5ee2lpeypnb"]
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://dw5ee2lpeypnb"]
[ext_resource type="PackedScene" uid="uid://coayig4dxelo2" path="res://objects/player_skills/brick_throw_skill.tscn" id="1_5gnea"]
[ext_resource type="Resource" uid="uid://br84dsfa3ti04" path="res://resources/throw_behaviors/tap_throw_input.tres" id="1_yimbq"]
[ext_resource type="Texture2D" uid="uid://dxtdwgg3po0eg" path="res://sprites/brick_power_Skill_icon.png" id="2_yimbq"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="3_yimbq"]
@@ -11,7 +12,7 @@ Description = "BRICK_POWER_DESCRIPTION"
Config = Dictionary[String, Variant]({
"fire_rate": 0.6,
"player_controller": NodePath("."),
"throw_input_behavior": null,
"throw_input_behavior": ExtResource("1_yimbq"),
"timer": NodePath("ThrowTimer")
})
Cost = 50

View File

@@ -1,25 +1,25 @@
[gd_resource type="Resource" script_class="SkillData" load_steps=6 format=3 uid="uid://cdp8sex36vdq2"]
[gd_resource type="Resource" load_steps=6 format=3 uid="uid://cdp8sex36vdq2"]
[ext_resource type="PackedScene" uid="uid://5surx230gfw3" path="res://objects/entities/exploding_brick.tscn" id="1_6pfoa"]
[ext_resource type="Resource" uid="uid://diuv6pr6a0dup" path="res://resources/throw_behaviors/charge_throw_input.tres" id="2_87gkt"]
[ext_resource type="PackedScene" uid="uid://coayig4dxelo2" path="res://objects/player_skills/brick_throw_skill.tscn" id="2_e0o8w"]
[ext_resource type="Script" uid="uid://bya240e627ti6" path="res://scripts/resources/skill_data.gd" id="3_cgsq1"]
[ext_resource type="Texture2D" uid="uid://c0xtjfpmkfolk" path="res://sprites/explosive_brick_skill_icon.png" id="3_wkqmb"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="5_wkqmb"]
[resource]
script = ExtResource("3_cgsq1")
name = "EXPLOSIVE_BRICK"
description = "EXPLOSIVE_BRICK_DESCRIPTION"
node = ExtResource("2_e0o8w")
config = {
script = ExtResource("5_wkqmb")
Name = "EXPLOSIVE_BRICK"
Description = "EXPLOSIVE_BRICK_DESCRIPTION"
Config = Dictionary[String, Variant]({
"brick_scene": ExtResource("1_6pfoa"),
"player_controller": NodePath("."),
"throw_input_behavior": ExtResource("2_87gkt"),
"timer": NodePath("ThrowTimer")
}
cost = 180
icon = ExtResource("3_wkqmb")
type = 1
is_active = false
level = 0
max_level = 1
})
Cost = 180
Icon = ExtResource("3_wkqmb")
IsActive = false
Level = 0
MaxLevel = 1
Type = 1
Node = ExtResource("2_e0o8w")

View File

@@ -1,25 +1,25 @@
[gd_resource type="Resource" script_class="SkillData" load_steps=6 format=3 uid="uid://2glvryih82t1"]
[gd_resource type="Resource" load_steps=6 format=3 uid="uid://cr5lo4h8wm0jc"]
[ext_resource type="PackedScene" uid="uid://daau4j5hbklk0" path="res://objects/entities/fire_brick.tscn" id="1_2g43l"]
[ext_resource type="Script" uid="uid://bya240e627ti6" path="res://scripts/resources/skill_data.gd" id="1_2j5ko"]
[ext_resource type="PackedScene" uid="uid://coayig4dxelo2" path="res://objects/player_skills/brick_throw_skill.tscn" id="1_g53fp"]
[ext_resource type="Resource" uid="uid://br84dsfa3ti04" path="res://resources/throw_behaviors/tap_throw_input.tres" id="2_dm5pj"]
[ext_resource type="Texture2D" uid="uid://cocbnr38qsikt" path="res://sprites/fire_brick_skill_icon.png" id="3_w87qb"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="5_us7vb"]
[resource]
script = ExtResource("1_2j5ko")
name = "FIRE_BRICK"
description = "FIRE_BIRCK_DESCRIPTION"
node = ExtResource("1_g53fp")
config = {
script = ExtResource("5_us7vb")
Name = "FIRE_BRICK"
Description = "FIRE_BIRCK_DESCRIPTION"
Config = Dictionary[String, Variant]({
"brick_scene": ExtResource("1_2g43l"),
"player_controller": NodePath("."),
"throw_input_behavior": ExtResource("2_dm5pj"),
"timer": NodePath("ThrowTimer")
}
cost = 150
icon = ExtResource("3_w87qb")
type = 1
is_active = false
level = 0
max_level = 3
})
Cost = 150
Icon = ExtResource("3_w87qb")
IsActive = false
Level = 0
MaxLevel = 3
Type = 1
Node = ExtResource("1_g53fp")

View File

@@ -1,25 +1,25 @@
[gd_resource type="Resource" script_class="SkillData" load_steps=6 format=3 uid="uid://cx5fsbexblp60"]
[gd_resource type="Resource" load_steps=6 format=3 uid="uid://ceakv6oqob6m7"]
[ext_resource type="PackedScene" uid="uid://bcmx07k12gcsc" path="res://objects/entities/ice_brick.tscn" id="1_ci3d1"]
[ext_resource type="PackedScene" uid="uid://coayig4dxelo2" path="res://objects/player_skills/brick_throw_skill.tscn" id="1_rflri"]
[ext_resource type="Resource" uid="uid://br84dsfa3ti04" path="res://resources/throw_behaviors/tap_throw_input.tres" id="2_hsgyv"]
[ext_resource type="Script" uid="uid://bya240e627ti6" path="res://scripts/resources/skill_data.gd" id="2_pspkt"]
[ext_resource type="Texture2D" uid="uid://c1qaxspv8aemf" path="res://sprites/ice_brick_skill_icon.png" id="3_6btth"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="5_57pl3"]
[resource]
script = ExtResource("2_pspkt")
name = "ICE_BRICK"
description = "ICE_BRICK_DESCRIPTION"
node = ExtResource("1_rflri")
config = {
script = ExtResource("5_57pl3")
Name = "ICE_BRICK"
Description = "ICE_BRICK_DESCRIPTION"
Config = Dictionary[String, Variant]({
"brick_scene": ExtResource("1_ci3d1"),
"player_controller": NodePath("."),
"throw_input_behavior": ExtResource("2_hsgyv"),
"timer": NodePath("ThrowTimer")
}
cost = 150
icon = ExtResource("3_6btth")
type = 1
is_active = false
level = 0
max_level = 3
})
Cost = 180
Icon = ExtResource("3_6btth")
IsActive = false
Level = 0
MaxLevel = 3
Type = 1
Node = ExtResource("1_rflri")

View File

@@ -1,22 +1,22 @@
[gd_resource type="Resource" script_class="SkillData" load_steps=4 format=3 uid="uid://d3bjre2etov1n"]
[gd_resource type="Resource" load_steps=4 format=3 uid="uid://d3bjre2etov1n"]
[ext_resource type="Texture2D" uid="uid://cvhoq7aubxlmq" path="res://sprites/ui/magnetic_skill_icon.png" id="1_16qcg"]
[ext_resource type="PackedScene" uid="uid://cunyndudjh2he" path="res://objects/player_skills/magnetic_skill.tscn" id="1_er41s"]
[ext_resource type="Script" uid="uid://bya240e627ti6" path="res://scripts/resources/skill_data.gd" id="1_r01oq"]
[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="3_htb6q"]
[resource]
script = ExtResource("1_r01oq")
name = "MAGNETIC"
description = "MAGNETIC_DESCRIPTION"
node = ExtResource("1_er41s")
config = {
script = ExtResource("3_htb6q")
Name = "MAGNETIC"
Description = "MAGNETIC_DESCRIPTION"
Config = Dictionary[String, Variant]({
"magnetic_area": NodePath("MagneticArea"),
"magnetic_move_duration": 1.25,
"root": NodePath(".")
}
cost = 70
icon = ExtResource("1_16qcg")
type = 2
is_active = false
level = 1
max_level = 1
})
Cost = 70
Icon = ExtResource("1_16qcg")
IsActive = false
Level = 1
MaxLevel = 1
Type = 2
Node = ExtResource("1_er41s")

View File

@@ -173,6 +173,9 @@ position = Vector2(7146.51, 21.1388)
[node name="Brick Player" parent="." instance=ExtResource("1_k3uyd")]
[node name="SkillUnlockerComponent" parent="Brick Player" index="17" node_paths=PackedStringArray("SkillManager")]
SkillManager = NodePath("../SkillManager")
[node name="HitParticles" parent="Brick Player" index="27"]
process_material = SubResource("ParticleProcessMaterial_lgb3u")

View File

@@ -99,8 +99,8 @@ public partial class Marketplace : Control
button.Pressed += () => OnUpgradeButtonPressed(skill);
_unlockButtons.Add(button);
UnlockedGrid.AddChild(button);
UnlockedGrid.QueueSort();
ToUnlockGrid.AddChild(button);
ToUnlockGrid.QueueSort();
}
private void OnUpgradeButtonPressed(SkillData skill)

View File

@@ -1,17 +0,0 @@
class_name Achievements
extends Node
func unlock_achievement(achievement_name: String) -> bool:
if not Steam.setAchievement(achievement_name):
print("Failed to unlock achievement: ", achievement_name)
return false
return true
func reset_achievement(achievement_name: String) -> bool:
if not Steam.clearAchievement(achievement_name):
print("Failed to reset achievement: ", achievement_name)
return false
return true

View File

@@ -1 +0,0 @@
uid://deguukal87gcb

View File

@@ -1,138 +0,0 @@
class_name ConsoleManagement
extends Node
@export var player_health: HealthComponent
@export var skill_unlocker: SkillUnlockerComponent
@export var skill_manager: SkillManager
@onready var game_manager: GM = $"/root/GameManager"
@onready var achievements: Achievements = $"/root/AchievementsManager"
func _ready() -> void:
Console.pause_enabled = true
Console.add_command("add_coins", console_add_coins, ["amount"], 1, "Add coins to the player.")
Console.add_command("set_coins", console_set_coins, ["amount"], 1, "Set the player's coins.")
Console.add_command("set_lives", console_set_lives, ["amount"], 1, "Set the player's lives.")
Console.add_command("set_health", console_set_health, ["amount"], 1, "Set the player's health.")
Console.add_command("unlock_skill", console_unlock_skill, ["skill_name"], 1, "Unlock a skill for the player.")
Console.add_command("remove_skill", console_remove_skill, ["skill_name"], 1, "Remove a skill from the player.")
Console.add_command("remove_all_skills", console_remove_all_skills, [], 0, "Remove all skills from the player.")
Console.add_command("unlock_all_skills", console_unlock_all_skills, [], 0, "Unlock all skills for the player.")
Console.add_command("unlock_achievement", console_unlock_achievement, ["achievement_name"], 1, "Unlock an achievement for the player.")
Console.add_command("reset_achievement", console_reset_achievement, ["achievement_name"], 1, "Reset an achievement for the player.")
func console_add_coins(amount: Variant) -> void:
if not game_manager:
return
if not amount.is_valid_int():
Console.print_error("Invalid amount: " + str(amount))
return
game_manager.add_coins(int(amount))
Console.print_info("Added " + str(amount) + " coins.")
func console_set_coins(amount: Variant) -> void:
if not game_manager:
return
if not amount.is_valid_int():
Console.print_error("Invalid amount: " + str(amount))
return
game_manager.set_coins(int(amount))
Console.print_info("Set coins to " + str(amount))
func console_set_lives(amount: Variant) -> void:
if not game_manager:
return
if not amount.is_valid_int():
Console.print_error("Invalid amount: " + str(amount))
return
game_manager.set_lives(int(amount))
Console.print_info("Set lives to " + str(amount))
func console_set_health(amount: Variant) -> void:
if not player_health:
return
if not amount.is_valid_float():
Console.print_error("Invalid amount: " + str(amount))
return
player_health.set_health(float(amount))
Console.print_info("Set health to " + str(amount))
func console_unlock_skill(skill_name: Variant) -> void:
if not skill_manager or not skill_unlocker or not game_manager:
return
if not skill_name:
Console.print_error("Invalid skill name: " + str(skill_name))
return
var skill_data: SkillData = skill_manager.get_skill_by_name(skill_name)
skill_data.level = 1
if not skill_data:
Console.print_error("Skill not found: " + str(skill_name))
return
game_manager.unlock_skill(skill_data)
skill_manager.activate_skill(skill_data)
skill_unlocker.skill_unlocked.emit(skill_data)
Console.print_info("Unlocked skill: " + str(skill_name))
func console_unlock_all_skills() -> void:
if not skill_manager or not skill_unlocker or not game_manager:
return
skill_unlocker.unlock_all_skills()
Console.print_info("Unlocked all skills.")
func console_remove_skill(skill_name: Variant) -> void:
if not skill_manager or not skill_unlocker or not game_manager:
return
if not skill_name:
Console.print_error("Invalid skill name: " + str(skill_name))
return
game_manager.remove_skill(skill_name)
skill_manager.remove_skill(skill_name)
Console.print_info("Removed skill: " + str(skill_name))
func console_remove_all_skills() -> void:
if not skill_manager or not skill_unlocker or not game_manager:
return
for skill_name in skill_manager.active_components.keys():
game_manager.remove_skill(skill_name)
skill_manager.remove_skill(skill_name)
func console_unlock_achievement(achievement_name: Variant) -> void:
if not achievement_name:
Console.print_error("Invalid achievement name: " + str(achievement_name))
return
if not achievements:
Console.print_error("Achievements manager not found.")
return
if not achievements.unlock_achievement(achievement_name):
Console.print_error("Failed to unlock achievement: " + str(achievement_name))
Console.print_info("Unlocked achievement: " + str(achievement_name))
func console_reset_achievement(achievement_name: Variant) -> void:
if not achievement_name:
Console.print_error("Invalid achievement name: " + str(achievement_name))
return
if not achievements:
Console.print_error("Achievements manager not found.")
return
if not achievements.reset_achievement(achievement_name):
Console.print_error("Failed to reset achievement: " + str(achievement_name))
Console.print_info("Reset achievement: " + str(achievement_name))

View File

@@ -1 +0,0 @@
uid://8r1y8elyw7kt

View File

@@ -1,231 +0,0 @@
class_name GM
extends Node
@export var level_scenes: Array[PackedScene]
@export var player_state := {
"coins": 0,
"lives": 3,
"unlocked_skills": [],
"current_level": 0,
"unlocked_levels": [0],
"completed_levels": [],
}
var nodes_in_scene := []
var current_session_state := {
"coins_collected": 0,
"skills_unlocked": [],
}
func _enter_tree() -> void:
get_tree().node_added.connect(on_node_added)
get_tree().node_removed.connect(on_node_removed)
func on_node_added(node: Node) -> void:
nodes_in_scene.append(node)
func on_node_removed(node: Node) -> void:
if node in nodes_in_scene:
nodes_in_scene.erase(node)
func get_colllectable_nodes() -> Array[CollectableComponent]:
var collectable_nodes: Array[CollectableComponent] = []
for node in nodes_in_scene:
var collectable_component: CollectableComponent = node.get_node_or_null("Collectable")
if not collectable_component:
collectable_component = node.get_node_or_null("CollectableComponent")
if not collectable_component:
continue
collectable_nodes.append(collectable_component)
return collectable_nodes
func get_coin_nodes() -> Array[CollectableComponent]:
var coin_nodes := []
for node in nodes_in_scene:
var collectable_component: CollectableComponent = node.get_node_or_null("Collectable")
if not collectable_component:
continue
if collectable_component.collectable_data.type == CollectableResource.CollectableType.COIN:
coin_nodes.append(collectable_component)
return coin_nodes
func get_kid_nodes() -> Array[CollectableComponent]:
var kid_nodes := []
for node in nodes_in_scene:
var collectable_component: CollectableComponent = node.get_node_or_null("Collectable")
if not collectable_component:
continue
if collectable_component.collectable_data.type == CollectableResource.CollectableType.KID:
kid_nodes.append(collectable_component)
return kid_nodes
func get_player_node() -> Node:
for node in nodes_in_scene:
if node is PlayerController:
return node
return null
func add_coins(amount: int) -> void:
player_state["coins"] += amount
player_state["coins"] = max(0, player_state["coins"])
func set_coins(amount: int) -> void:
player_state["coins"] = amount
func get_coins() -> int:
return player_state["coins"] + current_session_state["coins_collected"]
func remove_coins(amount: int) -> void:
var session_coins = current_session_state["coins_collected"]
if amount <= session_coins:
current_session_state["coins_collected"] -= amount
else:
var remaining_amount = amount - session_coins
current_session_state["coins_collected"] = 0
player_state["coins"] = max(0, player_state["coins"] - remaining_amount)
player_state["coins"] = max(0, player_state["coins"])
func add_lives(amount: int) -> void:
player_state["lives"] += amount
func remove_lives(amount: int) -> void:
player_state["lives"] -= amount
func set_lives(amount: int) -> void:
player_state["lives"] = amount
func get_lives() -> int:
return player_state["lives"]
func is_skill_unlocked(skill: SkillData) -> bool:
return skill in player_state["unlocked_skills"] or skill in current_session_state["skills_unlocked"]
func unlock_skill(skill: SkillData) -> void:
if not is_skill_unlocked(skill):
player_state["unlocked_skills"].append(skill)
func remove_skill(skill: SkillData) -> void:
if is_skill_unlocked(skill):
player_state["unlocked_skills"].erase(skill)
func unlock_skills(skills: Array[SkillData]) -> void:
for skill in skills:
unlock_skill(skill)
func reset_player_state() -> void:
player_state = {
"coins": 0,
"lives": 3,
"unlocked_skills": [],
"current_level": 0,
"unlocked_levels": [0],
"completed_levels": [],
}
func unlock_level(level_index: int) -> void:
if level_index not in player_state["unlocked_levels"]: player_state["unlocked_levels"].append(level_index)
func try_to_go_to_next_level() -> void:
var next_level = player_state["current_level"] + 1
if next_level < level_scenes.size() and next_level in player_state["unlocked_levels"]:
player_state["current_level"] += 1
get_tree().change_scene_to_packed(level_scenes[next_level])
func mark_level_complete(level_index: int) -> void:
unlock_level(level_index + 1)
if level_index not in player_state["completed_levels"]: player_state["completed_levels"].append(level_index)
func reset_current_session_state() -> void:
current_session_state = {
"coins_collected": 0,
"skills_unlocked": [],
}
func restart_game() -> void:
reset_player_state()
reset_current_session_state()
get_tree().change_scene_to_packed(level_scenes[0])
SaveSystem.save_game()
func quit_game() -> void:
get_tree().quit()
func pause_game() -> void:
Engine.time_scale = 0
func resume_game() -> void:
Engine.time_scale = 1
func start_new_game() -> void:
reset_player_state()
reset_current_session_state()
get_tree().change_scene_to_packed(level_scenes[0])
SaveSystem.save_game()
func continue_game() -> void:
if not SaveSystem.load_game():
printerr("Failed to load game. Starting a new game instead.")
start_new_game()
return
if player_state["current_level"] < level_scenes.size():
get_tree().change_scene_to_packed(level_scenes[player_state["current_level"]])
else:
printerr("No levels unlocked to continue.")
func on_level_complete() -> void:
var level_index = player_state["current_level"]
mark_level_complete(level_index)
add_coins(current_session_state["coins_collected"])
for skill in current_session_state["skills_unlocked"]:
unlock_skill(skill)
reset_current_session_state()
try_to_go_to_next_level()
SaveSystem.save_game()
func get_unlocked_skills() -> Array:
var skills_unlocked = player_state.get("unlocked_skills", [])
var skills_current_session = current_session_state.get("skills_unlocked", [])
if not skills_current_session:
return skills_unlocked
if not skills_unlocked:
return skills_current_session
return skills_unlocked + skills_current_session

View File

@@ -1 +0,0 @@
uid://dd30bgqiagi25

View File

@@ -1,64 +0,0 @@
class_name PlayerController
extends CharacterBody2D
@export var default_movement_type: String = "platform"
@export var movement_types: Dictionary = {}
@export var ship_sprite: Sprite2D
var current_movement: PlayerMovement = null
signal movement_switched(movement_type: String)
func _ready() -> void:
for movement_type in movement_types:
var movement_node: Node = get_node_or_null(movement_types[movement_type])
if movement_node and movement_node is PlayerMovement:
movement_node.enabled = false
switch_movement(default_movement_type)
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventKey:
if event.is_action_pressed("switch_movement"):
var next_movement_type: String = get_next_movement_type()
switch_movement(next_movement_type)
func switch_movement(movement_type: String) -> void:
if current_movement:
current_movement.enabled = false
if movement_type in movement_types:
current_movement = get_node_or_null(movement_types[movement_type])
if not current_movement:
push_error("Movement type '%s' not found in movement_types." % movement_type)
return
current_movement.enabled = true
movement_switched.emit(current_movement.type)
else:
push_error("Movement type '%s' not found in movement_types." % movement_type)
if not current_movement:
push_error("No current movement set after switching.")
func get_next_movement_type() -> String:
var keys: Array = movement_types.keys()
var current_index: int = keys.find(current_movement.type)
if current_index == -1:
return default_movement_type
current_index = (current_index + 1) % keys.size()
return keys[current_index]
func on_spaceship_entered() -> void:
switch_movement("ship")
ship_sprite.visible = true
func on_spaceship_exited() -> void:
switch_movement(default_movement_type)
ship_sprite.visible = false

View File

@@ -1 +0,0 @@
uid://ccuddyoakg04u

View File

@@ -1,8 +0,0 @@
extends Node
func _process(_delta: float) -> void:
if OS.is_debug_build() and Input.is_action_just_pressed("screenshot"):
var img := get_viewport().get_texture().get_image()
var id := OS.get_unique_id() + "_" + Time.get_datetime_string_from_system()
var path := "user://screenshot_" + str(id) + ".png"
img.save_png(path)

View File

@@ -1 +0,0 @@
uid://bydv4g1n5s3nf

View File

@@ -1,103 +0,0 @@
class_name SkillManager
extends Node
@export var available_skills: Array[SkillData] = []
@onready var gm: GM = $"/root/GameManager"
var active_components: Dictionary = {}
func _ready() -> void:
apply_unlocked_skills()
func add_skill(skill_data: SkillData) -> void:
if active_components.has(skill_data.name):
return
if skill_data.type == SkillData.SkillType.THROW:
var unlocked_skills: Array = gm.get_unlocked_skills()
for skill in unlocked_skills:
var data = null
for s in available_skills:
if s == skill:
data = s
break
if data and data.type == SkillData.SkillType.THROW:
remove_skill(data.name)
var skill_instance := skill_data.node.instantiate()
for key in skill_data.config.keys():
if key in skill_instance:
var value = skill_data.config[key]
var parent := get_parent()
if value is NodePath:
if parent.has_node(value):
value = parent.get_node(value)
elif skill_instance.has_node(value):
value = skill_instance.get_node(value)
else:
continue
skill_instance[key] = value
owner.add_child(skill_instance)
active_components[skill_data.name] = skill_instance
func remove_skill(skill_name: String) -> void:
if not active_components.has(skill_name):
return
var skill_instance = active_components[skill_name]
if is_instance_valid(skill_instance):
skill_instance.queue_free()
var skills: Array = gm.get_unlocked_skills()
for s in skills:
if s.name == skill_name:
s.is_active = false
break
active_components.erase(skill_name)
func apply_unlocked_skills() -> void:
for skill_data in available_skills:
if gm.is_skill_unlocked(skill_data):
print("Applying skill: ", skill_data.name)
call_deferred("add_skill", skill_data)
else:
remove_skill(skill_data.name)
func get_skill_by_name(skill_name: String) -> SkillData:
for skill_data in available_skills:
if skill_data.name == skill_name:
return skill_data
return null
func activate_skill(skill: SkillData) -> void:
if not active_components.has(skill.name):
if skill:
add_skill(skill)
skill.is_active = true
func deactivate_skill(skill: SkillData) -> void:
if active_components.has(skill.name):
remove_skill(skill.name)
if skill:
skill.is_active = false
func toggle_skill_activation(skill: SkillData) -> void:
if not skill:
return
if active_components.has(skill.name):
deactivate_skill(skill)
else:
activate_skill(skill)

View File

@@ -1 +0,0 @@
uid://cjqe428jwip6b

View File

@@ -1,33 +0,0 @@
class_name SteamIntegration
extends Node
var app_id: String = "3575090"
var is_on_steam_deck: bool = false
var is_online: bool = false
var has_bought_game: bool = false
func _init() -> void:
OS.set_environment("SteamAppId", app_id)
OS.set_environment("SteamGameId", app_id)
func _ready() -> void:
Steam.steamInit()
Steam.enableDeviceCallbacks()
SteamControllerInput.init()
var is_running := Steam.isSteamRunning()
if !is_running:
print("Steam is not running.")
return
print("Steam is running.")
is_on_steam_deck = Steam.isSteamRunningOnSteamDeck()
is_online = Steam.loggedOn()
has_bought_game = Steam.isSubscribed()
if not has_bought_game:
print("You have not bought the game.")

View File

@@ -1 +0,0 @@
uid://f4y8evisxgnc

View File

@@ -1,104 +0,0 @@
extends Node
@export var master_volume_slider: Slider
@export var music_volume_slider: Slider
@export var sfx_volume_slider: Slider
@export var audio_settings_control: Control
@export var mute_treshold: float = -20.0
func _ready() -> void:
initialize()
if master_volume_slider:
master_volume_slider.value_changed.connect(_on_master_volume_slider_value_changed)
if music_volume_slider:
music_volume_slider.value_changed.connect(_on_music_volume_slider_value_changed)
if sfx_volume_slider:
sfx_volume_slider.value_changed.connect(_on_sfx_volume_slider_value_changed)
load_settings()
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_cancel"):
if UiManager.is_screen_on_top(audio_settings_control):
save_settings()
UiManager.pop_screen()
func initialize() -> void:
if master_volume_slider:
var volume_db: float = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("Master"))
master_volume_slider.value = volume_db
master_volume_slider.min_value = mute_treshold
master_volume_slider.max_value = 0.0
if music_volume_slider:
var music_volume_db: float = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("music"))
music_volume_slider.value = music_volume_db
music_volume_slider.min_value = mute_treshold
music_volume_slider.max_value = 0.0
if sfx_volume_slider:
var sfx_volume_db: float = AudioServer.get_bus_volume_db(AudioServer.get_bus_index("sfx"))
sfx_volume_slider.value = sfx_volume_db
sfx_volume_slider.min_value = mute_treshold
sfx_volume_slider.max_value = 0.0
func _handle_mute(bus_index: int, value: float) -> void:
if AudioServer:
if value == mute_treshold:
AudioServer.set_bus_mute(bus_index, true)
else:
AudioServer.set_bus_mute(bus_index, false)
func _on_master_volume_slider_value_changed(value: float) -> void:
if AudioServer:
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), value)
_handle_mute(AudioServer.get_bus_index("Master"), value)
func _on_music_volume_slider_value_changed(value: float) -> void:
if AudioServer:
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("music"), value)
_handle_mute(AudioServer.get_bus_index("music"), value)
func _on_sfx_volume_slider_value_changed(value: float) -> void:
if AudioServer:
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("sfx"), value)
_handle_mute(AudioServer.get_bus_index("sfx"), value)
func save_settings() -> void:
if not AudioServer:
return
var settings_config := ConfigFileHandler.settings_config
settings_config.set_value("audio_settings", "master_volume", master_volume_slider.value)
settings_config.set_value("audio_settings", "music_volume", music_volume_slider.value)
settings_config.set_value("audio_settings", "sfx_volume", sfx_volume_slider.value)
settings_config.set_value("audio_settings", "mute_treshold", mute_treshold)
settings_config.save(ConfigFileHandler.SETTINGS_PATH)
func load_settings() -> void:
if not AudioServer:
return
var settings_config := ConfigFileHandler.settings_config
if not settings_config.has_section("audio_settings"):
print("Audio settings section not found in config file.")
return
var master_volume: float = settings_config.get_value("audio_settings", "master_volume", 0.0)
var music_volume: float = settings_config.get_value("audio_settings", "music_volume", 0.0)
var sfx_volume: float = settings_config.get_value("audio_settings", "sfx_volume", 0.0)
if master_volume_slider:
master_volume_slider.value = master_volume
if music_volume_slider:
music_volume_slider.value = music_volume
if sfx_volume_slider:
sfx_volume_slider.value = sfx_volume
mute_treshold = settings_config.get_value("audio_settings", "mute_treshold", -20.0)

View File

@@ -1 +0,0 @@
uid://dujk6pnftm7ra

View File

@@ -1,81 +0,0 @@
extends Node
@export var progress_bar: ProgressBar
@export var brick_throw_component: BrickThrowComponent
var throw_input: ChargeThrowInputResource
func _ready() -> void:
owner.child_entered_tree.connect(on_nodes_changed)
if progress_bar:
progress_bar.hide()
setup_dependencies()
func on_charge_updated(charge_ratio: float) -> void:
if not progress_bar:
return
progress_bar.value = charge_ratio
progress_bar.show()
func on_charge_stopped() -> void:
if not progress_bar:
return
progress_bar.hide()
func on_charge_started() -> void:
if not progress_bar:
return
progress_bar.show()
func setup_progress_bar() -> void:
if not progress_bar:
return
progress_bar.min_value = throw_input.min_power
progress_bar.max_value = throw_input.max_power
progress_bar.value = throw_input.min_power
progress_bar.step = 0.01
progress_bar.hide()
func setup_dependencies() -> void:
if not brick_throw_component:
return
if brick_throw_component.throw_input_behavior is ChargeThrowInputResource:
throw_input = brick_throw_component.throw_input_behavior as ChargeThrowInputResource
else:
throw_input = null
if not throw_input:
return
if not progress_bar:
return
if not throw_input.supports_charging():
progress_bar.hide()
return
setup_progress_bar()
throw_input.charge_started.connect(on_charge_started)
throw_input.charge_updated.connect(on_charge_updated)
throw_input.charge_stopped.connect(on_charge_stopped)
func on_nodes_changed(node: Node) -> void:
if node is BrickThrowComponent and brick_throw_component == null:
brick_throw_component = node as BrickThrowComponent
setup_dependencies()
return

View File

@@ -1 +0,0 @@
uid://q32rtephu1t1

View File

@@ -1,6 +0,0 @@
extends Control
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_cancel"):
if UiManager.is_screen_on_top(self):
UiManager.pop_screen()

View File

@@ -1 +0,0 @@
uid://dtjgndehihl6d

View File

@@ -1,62 +0,0 @@
class_name DeathScreen
extends Node
@export var death_screen_root: Control
@export var current_level: LevelResource
@export var current_level_label: Label
@export var lives_left_label: Label
@export var timeout_time: float = 2.0
@export var nodes_to_disable: Array[Node] = []
@onready var gm: GM = $"/root/GameManager"
var timer: Timer
func _ready() -> void:
set_lables()
func set_lables() -> void:
if not gm:
return
current_level_label.text = current_level.level_name
lives_left_label.text = " x " + str(gm.get_lives())
func setup_timer() -> void:
timer = Timer.new()
timer.wait_time = timeout_time
timer.one_shot = true
timer.timeout.connect(on_timeout)
add_child(timer)
timer.start()
func toggle_nodes() -> void:
for node in nodes_to_disable:
if node.process_mode == PROCESS_MODE_DISABLED:
node.process_mode = PROCESS_MODE_INHERIT
else:
node.process_mode = PROCESS_MODE_DISABLED
func on_player_death() -> void:
if not gm:
return
toggle_nodes()
set_lables()
death_screen_root.show()
setup_timer()
func on_timeout() -> void:
if not gm:
return
if gm.get_lives() == 0:
return
get_tree().reload_current_scene()

View File

@@ -1 +0,0 @@
uid://b3d1p21sviww4

View File

@@ -1,40 +0,0 @@
class_name GameOverScreen
extends Node
@export var game_over_screen: Control
@export var restart_button: Button
@export var main_menu_button: Button
@export var main_menu_scene: PackedScene
@onready var gm: GM = $"/root/GameManager"
func _ready() -> void:
if not gm:
return
game_over_screen.hide()
restart_button.pressed.connect(on_restart_button_pressed)
main_menu_button.pressed.connect(on_main_menu_button_pressed)
func on_restart_button_pressed() -> void:
if not gm:
return
gm.restart_game()
func on_main_menu_button_pressed() -> void:
if not gm or not main_menu_scene:
return
gm.reset_player_state()
get_tree().change_scene_to(main_menu_scene)
func on_player_death() -> void:
if not gm or not gm.get_lives() == 0:
return
game_over_screen.show()

View File

@@ -1 +0,0 @@
uid://bkd7o2u4psu4p

View File

@@ -1,51 +0,0 @@
class_name Hud
extends Node
@export var player_health: HealthComponent
@export var coins_label: Label
@export var health_progressbar: ProgressBar
@export var lives_label: Label
@onready var game_manager: GM = $"/root/GameManager"
func _ready() -> void:
if not player_health:
var nodes := get_tree().get_nodes_in_group("player")
for node in nodes:
player_health = node.get_node_or_null("HealthComponent")
if player_health:
break
return
func _process(_delta: float) -> void:
if not game_manager:
return
set_health_progressbar()
set_lives_label()
set_coins_label()
func set_coins_label() -> void:
if not game_manager:
return
#todo: set internationalized text
coins_label.text = tr("COINS_LABEL") + ":" + str(game_manager.get_coins())
func set_lives_label() -> void:
if not game_manager:
return
lives_label.text = tr("LIVES_LABEL") + ":" + str(game_manager.get_lives())
func set_health_progressbar() -> void:
if not player_health:
return
health_progressbar.value = player_health.health
health_progressbar.max_value = player_health.max_health

View File

@@ -1 +0,0 @@
uid://c3pde84b3kdco

View File

@@ -1,115 +0,0 @@
class_name InputSettings
extends Control
@export var input_button_scene: PackedScene = preload("res://objects/ui/input_button.tscn")
@export var action_list: Container
@export var reset_to_default_button: Button
@export var input_actions: Dictionary = {
'left': 'Move left',
'right': 'Move right',
'up': 'Move up',
'down': 'Move down',
'jump': 'Jump',
'attack': 'Attack',
'show_marketplace': "Toggle marketplace",
}
var is_remapping: bool = false
var action_to_remap = null
var remapping_button = null
var buttons: Array[Button] = []
@onready var config_file_handler = $'/root/ConfigFileHandler'
func _ready() -> void:
create_action_list()
if buttons.size() > 0:
buttons[0].grab_focus()
if reset_to_default_button:
reset_to_default_button.pressed.connect(on_reset_button_pressed)
func _input(event: InputEvent) -> void:
if is_remapping:
if event is InputEventKey or (event is InputEventMouseButton and event.pressed) or event is InputEventJoypadButton:
if event is InputEventMouseButton and event.double_click:
event.double_click = false
InputMap.action_erase_events(action_to_remap)
InputMap.action_add_event(action_to_remap, event)
update_action_list(remapping_button, event)
is_remapping = false
action_to_remap = null
remapping_button = null
accept_event()
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_cancel"):
if UiManager.is_screen_on_top(self):
UiManager.pop_screen()
save_settings()
load_settings()
func create_action_list() -> void:
InputMap.load_from_project_settings()
for item in action_list.get_children():
item.queue_free()
for action in input_actions:
var button := input_button_scene.instantiate() as Button
var action_label := button.find_child("LabelAction") as Label
var input_label := button.find_child("LabelInput") as Label
action_label.text = input_actions[action]
var events := InputMap.action_get_events(action)
if events.size() > 0:
input_label.text = events[0].as_text().trim_suffix(" (Physical)")
else:
input_label.text = "None"
action_list.add_child(button)
button.pressed.connect(on_input_button_pressed.bind(button, action))
buttons.append(button)
func on_input_button_pressed(button: Button, action) -> void:
if is_remapping:
return
is_remapping = true
action_to_remap = action
remapping_button = button
button.find_child("LabelInput").text = "Press any key..."
func update_action_list(button: Button, event: InputEvent) -> void:
button.find_child("LabelInput").text = event.as_text().trim_suffix(" (Physical)")
func on_reset_button_pressed() -> void:
create_action_list()
func save_settings() -> void:
config_file_handler.settings_config.set_value("input_settings", "input_actions", input_actions)
config_file_handler.settings_config.save(config_file_handler.SETTINGS_PATH)
func load_settings() -> void:
if not config_file_handler.settings_config.has_section("input_settings"):
return
var actions = config_file_handler.settings_config.get_value("input_settings", "input_actions", {})
if not actions:
return
input_actions = actions
create_action_list()

View File

@@ -1 +0,0 @@
uid://dppwl7xie2mh

View File

@@ -1,64 +0,0 @@
extends Node
@export var main_menu_control: Control
@export var new_game_button: Button
@export var continue_button: Button
@export var settings_button: Button
@export var credits_button: Button
@export var exit_button: Button
@export var version_label: Label
@export var settings_control: Control
@export var credits_control: Control
@onready var gm: GM = $"/root/GameManager"
func _ready() -> void:
if new_game_button:
new_game_button.pressed.connect(_on_new_game_button_pressed)
if continue_button:
continue_button.pressed.connect(_on_continue_button_pressed)
if settings_button:
settings_button.pressed.connect(_on_settings_button_pressed)
if credits_button:
credits_button.pressed.connect(_on_credits_button_pressed)
if exit_button:
exit_button.pressed.connect(quit_game)
if version_label:
version_label.text = "v. " + ProjectSettings.get_setting("application/config/version")
if not SaveSystem.check_save_exists() and continue_button:
continue_button.disabled = true
else:
continue_button.disabled = false
continue_button.grab_focus()
func _on_new_game_button_pressed() -> void:
if gm:
gm.start_new_game()
else:
printerr("GameManager not found. Cannot start new game.")
func _on_continue_button_pressed() -> void:
if gm:
gm.continue_game()
else:
printerr("GameManager not found. Cannot continue game.")
func quit_game() -> void:
if gm:
gm.quit_game()
func _on_settings_button_pressed() -> void:
if settings_control:
UiManager.push_screen(settings_control)
func _on_credits_button_pressed() -> void:
if credits_control:
UiManager.push_screen(credits_control)

View File

@@ -1 +0,0 @@
uid://hyfvthdbgjbc

View File

@@ -1,126 +0,0 @@
class_name Marketplace
extends Node
@export var root: Control
@export var skill_data: Array[SkillData] = []
@export var to_unlock_grid: GridContainer
@export var unlocked_grid: GridContainer
@export var font: Font
@export var skill_unlocker: SkillUnlockerComponent
@export var components_to_disable: Array[Node] = []
@export var marketplace_button: PackedScene
@export var skill_button: PackedScene
@onready var game_manager: GM = $"/root/GameManager"
var unlock_buttons: Array[Button] = []
var skill_buttons: Array[SkillButton] = []
func _ready() -> void:
if not skill_unlocker:
return
var skills_to_unlock: Array[SkillData] = []
for skill in skill_data:
skills_to_unlock.append(skill)
for skill in skills_to_unlock:
create_upgrade_button(skill)
var unlocked_skills := game_manager.get_unlocked_skills()
for skill in unlocked_skills:
create_skill_button(skill)
skill_unlocker.skill_unlocked.connect(on_skill_unlocked)
func _process(_delta: float) -> void:
for btn in skill_buttons:
if not btn.skill_data:
continue
if btn.skill_data.is_active:
btn.activate()
else:
btn.deactivate()
func _input(event: InputEvent) -> void:
if event.is_action_pressed("show_marketplace"):
if root.is_visible():
root.hide()
for component in components_to_disable:
component.process_mode = PROCESS_MODE_INHERIT
else:
root.show()
for component in components_to_disable:
component.process_mode = PROCESS_MODE_DISABLED
func get_button_text(skill: SkillData) -> String:
return tr(skill.name) + " " + str(skill.cost)
func create_upgrade_button(skill: SkillData) -> void:
var button := marketplace_button.instantiate() as MarketplaceButton
button.text = get_button_text(skill)
button.icon = skill.icon
button.skill_data = skill
button.pressed.connect(func () -> void: _on_button_pressed(skill))
unlock_buttons.append(button)
to_unlock_grid.add_child(button)
to_unlock_grid.queue_sort()
func create_skill_button(skill: SkillData) -> void:
var button := skill_button.instantiate() as SkillButton
button.skill_data = skill
button.setup()
button.pressed.connect(func() -> void: on_skill_button_pressed(button))
button.activate()
skill_buttons.append(button)
unlocked_grid.add_child(button)
unlocked_grid.queue_sort()
func remove_button(skill: SkillData):
for child in to_unlock_grid.get_children():
if child.text == get_button_text(skill):
child.queue_free()
break
func _on_button_pressed(skill: SkillData) -> void:
if not skill_unlocker:
return
if game_manager.is_skill_unlocked(skill):
if skill.level < skill.max_level:
skill_unlocker.try_upgrade_skill(skill)
if not skill.is_active:
skill_unlocker.skill_manager.toggle_skill_activation(skill)
else:
skill_unlocker.skill_manager.toggle_skill_activation(skill)
else:
skill_unlocker.try_unlock_skill(skill)
func on_skill_unlocked(skill: SkillData) -> void:
if not skill:
return
for btn in skill_buttons:
if btn.skill_data and btn.skill_data.name == skill.name:
return
create_skill_button(skill)
func on_skill_button_pressed(button: SkillButton) -> void:
if not skill_unlocker or not button.skill_data:
return
skill_unlocker.skill_manager.toggle_skill_activation(button.skill_data)

View File

@@ -1 +0,0 @@
uid://duifmqjarjpuv

View File

@@ -1,48 +0,0 @@
class_name MarketplaceButton
extends Button
@export var skill_data: SkillData
@export var unlocked_skill_icon: Texture2D
@export var locked_skill_icon: Texture2D
@export var skill_level_container: Container
@onready var gm: GM = $"/root/GameManager"
func _ready() -> void:
if not skill_data:
printerr("MarketplaceButton: skill_data is not set.")
if not unlocked_skill_icon or not locked_skill_icon:
printerr("MarketplaceButton: unlocked_skill_icon or locked_skill_icon is not set.")
return
if not skill_level_container:
printerr("MarketplaceButton: skill_level_container is not set.")
return
setup()
var player := gm.get_player_node()
var skill_unlocker_component := player.get_node_or_null("SkillUnlockerComponent") as SkillUnlockerComponent
if skill_unlocker_component:
skill_unlocker_component.skill_unlocked.connect(_on_skill_unlock)
func setup() -> void:
if not skill_data:
return
for i in range(skill_data.max_level):
var _icon := TextureRect.new()
_icon.texture = unlocked_skill_icon if i < skill_data.level else locked_skill_icon
skill_level_container.add_child(_icon)
func _on_skill_unlock(skill: SkillData) -> void:
if skill.name == skill_data.name:
for i in range(skill_data.max_level):
var icon := skill_level_container.get_child(i) as TextureRect
if i < skill.level:
icon.texture = unlocked_skill_icon
else:
icon.texture = locked_skill_icon
disabled = skill.level >= skill_data.max_level

View File

@@ -1 +0,0 @@
uid://dx8lex40lotr5

View File

@@ -1,90 +0,0 @@
class_name PauseMenu
extends Node
@export var pause_menu_control: Control
@export var resume_button: Button
@export var quit_button: Button
@export var settings_button: Button
@export var exit_to_menu_button: Button
@export var settings_menu: Control
@export var exit_to_menu_scene: PackedScene
@onready var gm: GM = $"/root/GameManager"
var is_console_open: bool = false
func _ready() -> void:
if not pause_menu_control:
printerr("PauseMenu: Pause menu control not set.")
return
if not resume_button:
printerr("PauseMenu: Resume button not set.")
return
if not quit_button:
printerr("PauseMenu: Quit button not set.")
return
if not settings_button:
printerr("PauseMenu: Settings button not set.")
return
if not exit_to_menu_button:
printerr("PauseMenu: Exit to menu button not set.")
return
pause_menu_control.hide()
resume_button.pressed.connect(_on_resume_button_pressed)
quit_button.pressed.connect(_on_quit_button_pressed)
settings_button.pressed.connect(_on_settings_button_pressed)
exit_to_menu_button.pressed.connect(_on_exit_to_menu_button_pressed)
Console.console_opened.connect(_on_console_open)
Console.console_closed.connect(_on_console_close)
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("pause") and not is_console_open:
if UiManager.is_visible_on_stack(pause_menu_control):
_on_resume_button_pressed()
else:
UiManager.push_screen(pause_menu_control)
gm.pause_game()
func _on_resume_button_pressed() -> void:
UiManager.pop_screen()
gm.resume_game()
func _on_quit_button_pressed() -> void:
gm.quit_game()
func _on_settings_button_pressed() -> void:
if not settings_menu:
printerr("PauseMenu: Settings menu scene not set.")
return
UiManager.push_screen(settings_menu)
gm.pause_game()
func _on_exit_to_menu_button_pressed() -> void:
if not exit_to_menu_scene:
printerr("PauseMenu: Exit to menu scene not set.")
return
gm.resume_game()
gm.reset_current_session_state()
get_tree().change_scene_to_packed(exit_to_menu_scene)
func _on_console_open():
is_console_open = true
func _on_console_close():
is_console_open = false

View File

@@ -1 +0,0 @@
uid://cugifchx6jhuk

View File

@@ -1,70 +0,0 @@
class_name SettingsMenu
extends Node
@export var input_settings: Control
@export var audio_settings: Control
@export var display_settings: Control
@export var gameplay_settings: Control
@export var settings_menu_control: Control
@export var input_settings_button: Button
@export var audio_settings_button: Button
@export var display_settings_button: Button
@export var gameplay_settings_button: Button
func _ready() -> void:
if not settings_menu_control or not input_settings_button or not audio_settings_button or not display_settings_button or not gameplay_settings_button:
printerr("No settings menu control or buttons found.")
return
if input_settings:
input_settings_button.pressed.connect(_on_input_settings_button_pressed)
input_settings.hide()
if audio_settings:
audio_settings_button.pressed.connect(_on_audio_settings_button_pressed)
audio_settings.hide()
if display_settings:
display_settings_button.pressed.connect(_on_display_settings_button_pressed)
display_settings.hide()
if gameplay_settings:
gameplay_settings_button.pressed.connect(_on_gameplay_settings_button_pressed)
gameplay_settings.hide()
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("ui_cancel"):
if UiManager.is_screen_on_top(settings_menu_control):
UiManager.pop_screen()
func _on_input_settings_button_pressed() -> void:
if not input_settings:
return
UiManager.push_screen(input_settings)
func _on_audio_settings_button_pressed() -> void:
if not audio_settings:
return
UiManager.push_screen(audio_settings)
func _on_display_settings_button_pressed() -> void:
if not display_settings:
return
UiManager.push_screen(display_settings)
func _on_gameplay_settings_button_pressed() -> void:
if not gameplay_settings:
return
UiManager.push_screen(gameplay_settings)

View File

@@ -1 +0,0 @@
uid://c506rigcjlm6x

View File

@@ -1,22 +0,0 @@
class_name SkillButton
extends Button
@export var skill_data: SkillData
func setup() -> void:
if not skill_data:
return
icon = skill_data.icon
text = tr(skill_data.name)
func activate() -> void:
set("theme_override_colors/font_color", Color("#49aa10"))
func deactivate() -> void:
set("theme_override_colors/font_color", Color("#ffffff"))

View File

@@ -1 +0,0 @@
uid://0obbehfd8fki