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

@@ -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