feat: Implement core game systems including settings management, player input, and initial gameplay mechanics with associated UI.

This commit is contained in:
Yogi Wiguna
2026-03-12 10:35:26 +08:00
parent 4f6783b468
commit 93eda69ad6
10 changed files with 218 additions and 155 deletions
+5 -1
View File
@@ -21,7 +21,6 @@ config/icon="res://icon.svg"
[autoload] [autoload]
SettingsManager="*res://scripts/managers/settings_manager.gd"
Nakama="*uid://bueyqhhvxe0tx" Nakama="*uid://bueyqhhvxe0tx"
NakamaManager="*res://scripts/nakama_manager.gd" NakamaManager="*res://scripts/nakama_manager.gd"
AuthManager="*res://scripts/managers/auth_manager.gd" AuthManager="*res://scripts/managers/auth_manager.gd"
@@ -33,6 +32,7 @@ GoalManager="*res://scripts/managers/goal_manager.gd"
PlayerManager="*res://scripts/managers/player_manager.gd" PlayerManager="*res://scripts/managers/player_manager.gd"
GoalsCycleManager="*res://scripts/managers/goals_cycle_manager.gd" GoalsCycleManager="*res://scripts/managers/goals_cycle_manager.gd"
Satori="*uid://b8vev00s34b7" Satori="*uid://b8vev00s34b7"
SettingsManager="*uid://c1ouaaqnn0lrc"
[display] [display]
@@ -69,24 +69,28 @@ move_north={
"deadzone": 0.5, "deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":87,"physical_keycode":0,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
] ]
} }
move_south={ move_south={
"deadzone": 0.5, "deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":83,"physical_keycode":0,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
] ]
} }
move_west={ move_west={
"deadzone": 0.5, "deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":0,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":0,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
] ]
} }
move_east={ move_east={
"deadzone": 0.5, "deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":68,"physical_keycode":0,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":68,"physical_keycode":0,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
] ]
} }
move_northeast={ move_northeast={
-4
View File
@@ -1161,24 +1161,20 @@ grow_horizontal = 0
grow_vertical = 0 grow_vertical = 0
[node name="ActionButtonContainer" type="VBoxContainer" parent="ActionMenu" unique_id=1026460846] [node name="ActionButtonContainer" type="VBoxContainer" parent="ActionMenu" unique_id=1026460846]
visible = false
layout_mode = 0 layout_mode = 0
offset_right = 40.0 offset_right = 40.0
offset_bottom = 40.0 offset_bottom = 40.0
[node name="MoveButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=1233901451] [node name="MoveButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=1233901451]
visible = false
layout_mode = 2 layout_mode = 2
text = "Move" text = "Move"
[node name="GrabButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=1584219139] [node name="GrabButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=1584219139]
visible = false
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
layout_mode = 2 layout_mode = 2
text = "Grab" text = "Grab"
[node name="PutButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=508990607] [node name="PutButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=508990607]
visible = false
custom_minimum_size = Vector2(100, 100) custom_minimum_size = Vector2(100, 100)
layout_mode = 2 layout_mode = 2
text = "Put" text = "Put"
+14 -8
View File
@@ -1012,6 +1012,20 @@ func activate_powerup(effect_id: int):
if st_manager: if st_manager:
st_manager.activate_effect(effect_id) st_manager.activate_effect(effect_id)
func activate_held_powerup():
"""Finds whichever powerup is currently held and activates it."""
var active_effect = -1
if special_tiles_manager:
for effect_key in special_tiles_manager.inventory:
if special_tiles_manager.inventory[effect_key]:
active_effect = effect_key
break
if active_effect != -1:
activate_powerup(active_effect)
else:
print("[Player] No powerup currently held to activate.")
func _process(delta): func _process(delta):
# Failsafe: Ensure player is visible if spawn point is selected and random spawn is active # Failsafe: Ensure player is visible if spawn point is selected and random spawn is active
@@ -1118,14 +1132,6 @@ func _physics_process(delta):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
func _unhandled_input(event): func _unhandled_input(event):
# Handle power-up usage
if event.is_action_pressed("use_powerup") and is_multiplayer_authority():
if is_frozen or is_stop_frozen:
return
if powerup_manager and powerup_manager.can_use_special():
powerup_manager.use_special_effect()
return
if input_manager: if input_manager:
input_manager.handle_unhandled_input(event) input_manager.handle_unhandled_input(event)
+79 -40
View File
@@ -300,7 +300,22 @@ label_settings = SubResource("LabelSettings_section")
layout_mode = 2 layout_mode = 2
theme_override_constants/h_separation = 20 theme_override_constants/h_separation = 20
theme_override_constants/v_separation = 10 theme_override_constants/v_separation = 10
columns = 2 columns = 3
[node name="ColH1" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid"]
layout_mode = 2
text = "Action"
label_settings = SubResource("LabelSettings_section")
[node name="ColH2" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid"]
layout_mode = 2
text = "Primary"
label_settings = SubResource("LabelSettings_section")
[node name="ColH3" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid"]
layout_mode = 2
text = "Secondary"
label_settings = SubResource("LabelSettings_section")
[node name="UpLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000007] [node name="UpLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000007]
layout_mode = 2 layout_mode = 2
@@ -314,6 +329,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "W" text = "W"
[node name="MoveUpAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000108]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "Up"
[node name="DownLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000009] [node name="DownLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000009]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@@ -326,6 +347,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "S" text = "S"
[node name="MoveDownAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000110]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "Down"
[node name="LeftLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000011] [node name="LeftLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000011]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@@ -338,6 +365,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "A" text = "A"
[node name="MoveLeftAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000112]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "Left"
[node name="RightLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000013] [node name="RightLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000013]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@@ -350,6 +383,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "D" text = "D"
[node name="MoveRightAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/MoveGrid" unique_id=100000114]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "Right"
[node name="PowerUpSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000015] [node name="PowerUpSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000015]
layout_mode = 2 layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") theme_override_styles/panel = SubResource("StyleBoxFlat_section_header")
@@ -363,55 +402,25 @@ label_settings = SubResource("LabelSettings_section")
layout_mode = 2 layout_mode = 2
theme_override_constants/h_separation = 20 theme_override_constants/h_separation = 20
theme_override_constants/v_separation = 10 theme_override_constants/v_separation = 10
columns = 2 columns = 3
[node name="P1Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000018] [node name="UsePowerupLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000118]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "PowerUp 1 (Speed)" text = "Activate PowerUp (Universal)"
label_settings = SubResource("LabelSettings_heading") label_settings = SubResource("LabelSettings_heading")
[node name="Powerup1Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000019] [node name="UsePowerupBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000119]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40) custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "1" text = "F"
[node name="P2Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000020] [node name="UsePowerupAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000120]
layout_mode = 2
size_flags_horizontal = 3
text = "PowerUp 2 (Freeze/Ghost)"
label_settings = SubResource("LabelSettings_heading")
[node name="Powerup2Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000021]
unique_name_in_owner = true unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40) custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "2" text = "N/A"
[node name="P3Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000022]
layout_mode = 2
size_flags_horizontal = 3
text = "PowerUp 3 (Wall)"
label_settings = SubResource("LabelSettings_heading")
[node name="Powerup3Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000023]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "3"
[node name="P4Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000024]
layout_mode = 2
size_flags_horizontal = 3
text = "PowerUp 4 (Ghost)"
label_settings = SubResource("LabelSettings_heading")
[node name="Powerup4Btn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000025]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "4"
[node name="PowerBarSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000026] [node name="PowerBarSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000026]
layout_mode = 2 layout_mode = 2
@@ -426,7 +435,7 @@ label_settings = SubResource("LabelSettings_section")
layout_mode = 2 layout_mode = 2
theme_override_constants/h_separation = 20 theme_override_constants/h_separation = 20
theme_override_constants/v_separation = 10 theme_override_constants/v_separation = 10
columns = 2 columns = 3
[node name="AttackLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000029] [node name="AttackLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000029]
layout_mode = 2 layout_mode = 2
@@ -440,6 +449,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "Q" text = "Q"
[node name="AttackModeAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000130]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "N/A"
[node name="SpawnBoostLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000031] [node name="SpawnBoostLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000031]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@@ -452,6 +467,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "E" text = "E"
[node name="SpawnBoostAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerBarGrid" unique_id=100000132]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "N/A"
[node name="OtherSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000033] [node name="OtherSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000033]
layout_mode = 2 layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") theme_override_styles/panel = SubResource("StyleBoxFlat_section_header")
@@ -465,7 +486,7 @@ label_settings = SubResource("LabelSettings_section")
layout_mode = 2 layout_mode = 2
theme_override_constants/h_separation = 20 theme_override_constants/h_separation = 20
theme_override_constants/v_separation = 10 theme_override_constants/v_separation = 10
columns = 2 columns = 3
[node name="GrabLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000036] [node name="GrabLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000036]
layout_mode = 2 layout_mode = 2
@@ -479,6 +500,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "Space" text = "Space"
[node name="GrabAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000137]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "N/A"
[node name="PutLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000038] [node name="PutLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000038]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@@ -491,6 +518,12 @@ custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "R" text = "R"
[node name="PutAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000139]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "N/A"
[node name="TektonGrabLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000040] [node name="TektonGrabLabel" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000040]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
@@ -502,3 +535,9 @@ unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40) custom_minimum_size = Vector2(150, 40)
layout_mode = 2 layout_mode = 2
text = "G" text = "G"
[node name="TektonGrabAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/OtherGrid" unique_id=100000141]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
text = "N/A"
+17 -46
View File
@@ -82,7 +82,7 @@ func _process(delta):
player.highlight_cells_if_authorized(area, highlight_id) player.highlight_cells_if_authorized(area, highlight_id)
func handle_unhandled_input(event): func handle_unhandled_input(event):
# Early return if not authorized human playersa # Early return if not authorized human player
if not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots"): if not player.is_multiplayer_authority() or player.is_bot or player.is_in_group("Bots"):
player.set_process_unhandled_input(false) player.set_process_unhandled_input(false)
return return
@@ -97,66 +97,37 @@ func handle_unhandled_input(event):
# --- Keyboard Shortcuts (Event-based) --- # --- Keyboard Shortcuts (Event-based) ---
if event is InputEventKey and event.pressed and not event.echo: if event is InputEventKey and event.pressed and not event.echo:
var mode = LobbyManager.get_game_mode()
var is_sng = mode == GameMode.Mode.STOP_N_GO
# Safety check for SettingsManager # Safety check for SettingsManager
if not SettingsManager: if not SettingsManager:
return return
# Get dynamic keybinds # 1. Unified check for POWER-UP Activation
var key_p1 = SettingsManager.get_control_keycode("powerup_1") if event.is_action_pressed("use_powerup"):
var key_p2 = SettingsManager.get_control_keycode("powerup_2") player.activate_held_powerup()
var key_p3 = SettingsManager.get_control_keycode("powerup_3") get_viewport().set_input_as_handled()
var key_p4 = SettingsManager.get_control_keycode("powerup_4") return
var ek = event.keycode
# 3. Action Buttons (Remappable via InputMap)
# Unified check for PowerUp keys if event.is_action_pressed("action_knock_tekton"):
if ek == key_p1:
# Single Slot Logic: Find whatever powerup is currently set to 'true' and activate it
var active_effect = -1
if player.special_tiles_manager:
for effect_key in player.special_tiles_manager.inventory:
if player.special_tiles_manager.inventory[effect_key]:
active_effect = effect_key
break
if active_effect != -1:
player.activate_powerup(active_effect)
else:
print("No powerup in slot 1 to activate.")
# KP Fallback
elif ek == KEY_KP_1:
var active_effect = -1
if player.special_tiles_manager:
for effect_key in player.special_tiles_manager.inventory:
if player.special_tiles_manager.inventory[effect_key]:
active_effect = effect_key
break
if active_effect != -1:
player.activate_powerup(active_effect)
# Action Buttons (Remappable)
elif ek == SettingsManager.get_control_keycode("attack_mode"):
if player.powerup_manager: if player.powerup_manager:
player.powerup_manager.use_special_effect() player.powerup_manager.use_special_effect()
if player.is_attack_mode and player.has_method("enter_attack_mode"): if player.is_attack_mode and player.has_method("enter_attack_mode"):
player.enter_attack_mode() player.enter_attack_mode()
get_viewport().set_input_as_handled()
elif ek == SettingsManager.get_control_keycode("spawn_boost"): elif event.is_action_pressed("spawn_boost"):
if player.is_carrying_tekton and player.powerup_manager: if player.is_carrying_tekton and player.powerup_manager:
if player.powerup_manager.has_method("spawn_boost_reward"): if player.powerup_manager.has_method("spawn_boost_reward"):
player.powerup_manager.spawn_boost_reward() player.powerup_manager.spawn_boost_reward()
get_viewport().set_input_as_handled()
elif ek == SettingsManager.get_control_keycode("tekton_grab"): elif event.is_action_pressed("action_grab_tekton"):
if not player.is_carrying_tekton and player.powerup_manager: if not player.is_carrying_tekton and player.powerup_manager:
if player.powerup_manager.can_use_special(): if player.powerup_manager.has_method("can_use_special"): # Corrected method name
player.grab_tekton() player.grab_tekton()
get_viewport().set_input_as_handled()
# Handle spawn point selection if not yet selected
# Handle spawn point selection if not yet selected # Handle spawn point selection if not yet selected
if not player.spawn_point_selected and player.highlighted_spawn_points.size() > 0: if not player.spawn_point_selected and player.highlighted_spawn_points.size() > 0:
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT: if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
+70 -6
View File
@@ -31,23 +31,33 @@ var settings = {
}, },
"controls": { "controls": {
"use_controller": false, "use_controller": false,
# Movement (Keybinds are typically fixed to WASD/Arrows in Input Map, but we show them) # Movement
"move_up": KEY_W, "move_up": KEY_W,
"move_up_alt": KEY_UP,
"move_down": KEY_S, "move_down": KEY_S,
"move_down_alt": KEY_DOWN,
"move_left": KEY_A, "move_left": KEY_A,
"move_left_alt": KEY_LEFT,
"move_right": KEY_D, "move_right": KEY_D,
"move_right_alt": KEY_RIGHT,
# Actions # Actions
"grab": KEY_SPACE, "grab": KEY_SPACE,
"grab_alt": KEY_J,
"put": KEY_R, "put": KEY_R,
"put_alt": KEY_K,
"tekton_grab": KEY_G, "tekton_grab": KEY_G,
"tekton_grab_alt": KEY_L,
# Power-Up Controls # Power-Up Controls
"powerup_1": KEY_1, "use_powerup": KEY_F,
"powerup_2": KEY_2, "use_powerup_alt": KEY_SHIFT,
"powerup_3": KEY_3,
"powerup_4": KEY_4,
# Power Bar Controls / Special # Power Bar Controls / Special
"attack_mode": KEY_Q, "attack_mode": KEY_Q,
"spawn_boost": KEY_E "attack_mode_alt": KEY_U,
"spawn_boost": KEY_E,
"spawn_boost_alt": KEY_I
} }
} }
@@ -80,6 +90,7 @@ func save_settings():
func apply_all_settings(): func apply_all_settings():
apply_video_settings() apply_video_settings()
apply_audio_settings() apply_audio_settings()
apply_control_settings()
emit_signal("settings_applied") emit_signal("settings_applied")
func apply_video_settings(): func apply_video_settings():
@@ -149,9 +160,62 @@ func set_bus_volume(bus_name: String, volume_linear: float):
AudioServer.set_bus_volume_db(bus_idx, linear_to_db(volume_linear)) AudioServer.set_bus_volume_db(bus_idx, linear_to_db(volume_linear))
AudioServer.set_bus_mute(bus_idx, volume_linear <= 0.001) AudioServer.set_bus_mute(bus_idx, volume_linear <= 0.001)
func apply_control_settings():
# Sync custom settings with InputMap
var mapping = {
"move_up": "move_north",
"move_down": "move_south",
"move_left": "move_west",
"move_right": "move_east",
"grab": "action_grab",
"put": "action_put",
"use_powerup": "use_powerup",
"tekton_grab": "action_grab_tekton",
"attack_mode": "action_knock_tekton",
"spawn_boost": "spawn_boost"
}
for setting_key in mapping.keys():
var action_name = mapping[setting_key]
if not InputMap.has_action(action_name):
InputMap.add_action(action_name)
InputMap.action_erase_events(action_name)
# Add Primary
var primary_key = settings.controls.get(setting_key)
if primary_key:
var event = InputEventKey.new()
event.keycode = primary_key
InputMap.action_add_event(action_name, event)
# Add Secondary
var secondary_key = settings.controls.get(setting_key + "_alt")
if secondary_key:
var event = InputEventKey.new()
event.keycode = secondary_key
InputMap.action_add_event(action_name, event)
# Add Joypad defaults for movement
if action_name.begins_with("move_"):
var joy_axis = -1
var axis_val = 0.0
match action_name:
"move_north": joy_axis = JOY_AXIS_LEFT_Y; axis_val = -1.0
"move_south": joy_axis = JOY_AXIS_LEFT_Y; axis_val = 1.0
"move_west": joy_axis = JOY_AXIS_LEFT_X; axis_val = -1.0
"move_east": joy_axis = JOY_AXIS_LEFT_X; axis_val = 1.0
if joy_axis != -1:
var joy_event = InputEventJoypadMotion.new()
joy_event.axis = joy_axis
joy_event.axis_value = axis_val
InputMap.action_add_event(action_name, joy_event)
func set_control(action_name: String, keycode: int): func set_control(action_name: String, keycode: int):
if settings.controls.has(action_name): if settings.controls.has(action_name):
settings.controls[action_name] = keycode settings.controls[action_name] = keycode
apply_control_settings() # Apply immediately
emit_signal("control_remapped", action_name, keycode) emit_signal("control_remapped", action_name, keycode)
save_settings() save_settings()
+1 -27
View File
@@ -206,11 +206,6 @@ func activate_effect(effect: int, target_player: Node3D = null):
print("PowerUp %s not found in inventory or false. Inventory: %s" % [effect, inventory]) print("PowerUp %s not found in inventory or false. Inventory: %s" % [effect, inventory])
return return
# Check Cooldown
if powerup_cooldowns.get(effect, 0.0) > 0:
print("PowerUp %s on cooldown." % SpecialEffect.keys()[effect])
return
# Check Attack Mode Restriction # Check Attack Mode Restriction
if player.get("is_attack_mode") and effect == SpecialEffect.INVISIBLE_MODE: if player.get("is_attack_mode") and effect == SpecialEffect.INVISIBLE_MODE:
NotificationManager.send_message(player, "Cannot enter Ghost mode while in Attack Mode!", NotificationManager.MessageType.WARNING) NotificationManager.send_message(player, "Cannot enter Ghost mode while in Attack Mode!", NotificationManager.MessageType.WARNING)
@@ -221,16 +216,8 @@ func activate_effect(effect: int, target_player: Node3D = null):
NotificationManager.send_message(player, "Cannot use this power while carrying a Tekton!", NotificationManager.MessageType.WARNING) NotificationManager.send_message(player, "Cannot use this power while carrying a Tekton!", NotificationManager.MessageType.WARNING)
return return
# Calculate Cooldown based on Level
var level = powerup_levels.get(effect, 1) var level = powerup_levels.get(effect, 1)
# Linear Interp: Lvl 1 = 15s, Lvl 8 = 5s print("[SpecialTiles] Player %s activated %s (Lvl %d). No cooldown applied." % [player.name, SpecialEffect.keys()[effect], level])
# Slope = (5 - 15) / (8 - 1) = -10 / 7 = -1.428...
var cooldown_time = COOLDOWN_L1 + ((level - 1) * (COOLDOWN_L8 - COOLDOWN_L1) / 7.0)
powerup_cooldowns[effect] = cooldown_time
emit_signal("cooldown_updated", effect, cooldown_time, cooldown_time)
print("[SpecialTiles] Player %s activated %s (Lvl %d). Cooldown: %.1fs" % [player.name, SpecialEffect.keys()[effect], level, cooldown_time])
match effect: match effect:
SpecialEffect.FASTER_SPEED: SpecialEffect.FASTER_SPEED:
@@ -555,19 +542,6 @@ func _check_for_icy_floor():
pass pass
func _process(delta): func _process(delta):
# Update Cooldowns
for effect in powerup_cooldowns.keys():
if powerup_cooldowns[effect] > 0:
powerup_cooldowns[effect] -= delta
# Emit signal occasionally or only on change? Every frame might be too much for UI?
# Optimization: Emit every 0.1s or if diff is significant?
# For snappy UI text, frame sync is okay for local player.
emit_signal("cooldown_updated", effect, powerup_cooldowns[effect], 0.0) # max unused for tick
if powerup_cooldowns[effect] <= 0:
powerup_cooldowns[effect] = 0
emit_signal("cooldown_updated", effect, 0, 0)
# Update Active Buffs (Speed) # Update Active Buffs (Speed)
if active_buffs.has(SpecialEffect.FASTER_SPEED): if active_buffs.has(SpecialEffect.FASTER_SPEED):
active_buffs[SpecialEffect.FASTER_SPEED] -= delta active_buffs[SpecialEffect.FASTER_SPEED] -= delta
+15 -1
View File
@@ -15,6 +15,7 @@ var attack_mode_button: Button # Renamed from special_button
var spawn_boost_button: Button var spawn_boost_button: Button
var settings_button: Button var settings_button: Button
var tekton_grab_button: Button var tekton_grab_button: Button
@onready var SettingsManager = get_node_or_null("/root/SettingsManager") @onready var SettingsManager = get_node_or_null("/root/SettingsManager")
# Settings - persisted to config file # Settings - persisted to config file
@@ -30,6 +31,7 @@ var button_positions: Dictionary = {
"attack_mode": Vector2(-200, -80), # Renamed "attack_mode": Vector2(-200, -80), # Renamed
"spawn_boost": Vector2(-120, -80) "spawn_boost": Vector2(-120, -80)
} }
var button_scale: float = 1.0 var button_scale: float = 1.0
# Reference to main scene and player # Reference to main scene and player
@@ -163,6 +165,7 @@ func _create_touch_ui():
put_button = _find_or_create_action_button(actions_container, "Put", "📦", button_positions.put) put_button = _find_or_create_action_button(actions_container, "Put", "📦", button_positions.put)
tekton_grab_button = _find_or_create_action_button(actions_container, "TektonGrab", "👋", Vector2(-280, -80)) tekton_grab_button = _find_or_create_action_button(actions_container, "TektonGrab", "👋", Vector2(-280, -80))
# Order: AttackMode, SpawnBoost, Grab, TektonGrab # Order: AttackMode, SpawnBoost, Grab, TektonGrab
if attack_mode_button: if attack_mode_button:
@@ -184,6 +187,7 @@ func _create_touch_ui():
actions_container.move_child(tekton_grab_button, 3) actions_container.move_child(tekton_grab_button, 3)
tekton_grab_button.icon = load("res://assets/graphics/touch_control/grab_tekton.png") tekton_grab_button.icon = load("res://assets/graphics/touch_control/grab_tekton.png")
tekton_grab_button.expand_icon = true tekton_grab_button.expand_icon = true
# Hide Put Button # Hide Put Button
if put_button: if put_button:
@@ -306,6 +310,7 @@ func _ensure_shortcut_label(btn: Button, button_name: String):
"AttackMode": existing_lbl.text = SettingsManager.get_control_text("attack_mode") "AttackMode": existing_lbl.text = SettingsManager.get_control_text("attack_mode")
"SpawnBoost": existing_lbl.text = SettingsManager.get_control_text("spawn_boost") "SpawnBoost": existing_lbl.text = SettingsManager.get_control_text("spawn_boost")
"TektonGrab": existing_lbl.text = SettingsManager.get_control_text("tekton_grab") "TektonGrab": existing_lbl.text = SettingsManager.get_control_text("tekton_grab")
print("[TouchControls] Updated %s shortcut label to: %s" % [button_name, existing_lbl.text]) print("[TouchControls] Updated %s shortcut label to: %s" % [button_name, existing_lbl.text])
@@ -338,6 +343,7 @@ func _ensure_shortcut_label(btn: Button, button_name: String):
"AttackMode": shortcut_lbl.text = SettingsManager.get_control_text("attack_mode") if SettingsManager else "Q" "AttackMode": shortcut_lbl.text = SettingsManager.get_control_text("attack_mode") if SettingsManager else "Q"
"SpawnBoost": shortcut_lbl.text = SettingsManager.get_control_text("spawn_boost") if SettingsManager else "E" "SpawnBoost": shortcut_lbl.text = SettingsManager.get_control_text("spawn_boost") if SettingsManager else "E"
"TektonGrab": shortcut_lbl.text = SettingsManager.get_control_text("tekton_grab") if SettingsManager else "G" "TektonGrab": shortcut_lbl.text = SettingsManager.get_control_text("tekton_grab") if SettingsManager else "G"
btn.add_child(shortcut_lbl) btn.add_child(shortcut_lbl)
@@ -358,6 +364,7 @@ func _on_button_pressed(button_name: String):
"AttackMode": btn = attack_mode_button "AttackMode": btn = attack_mode_button
"SpawnBoost": btn = spawn_boost_button "SpawnBoost": btn = spawn_boost_button
"TektonGrab": btn = tekton_grab_button "TektonGrab": btn = tekton_grab_button
if btn: if btn:
var tween = create_tween() var tween = create_tween()
@@ -396,6 +403,7 @@ func _on_button_pressed(button_name: String):
if local_player.has_method("grab_tekton"): if local_player.has_method("grab_tekton"):
local_player.grab_tekton() local_player.grab_tekton()
func _on_button_released(button_name: String): func _on_button_released(button_name: String):
var btn: Button var btn: Button
match button_name: match button_name:
@@ -404,6 +412,7 @@ func _on_button_released(button_name: String):
"AttackMode": btn = attack_mode_button "AttackMode": btn = attack_mode_button
"SpawnBoost": btn = spawn_boost_button "SpawnBoost": btn = spawn_boost_button
"TektonGrab": btn = tekton_grab_button "TektonGrab": btn = tekton_grab_button
if btn: if btn:
var tween = create_tween() var tween = create_tween()
@@ -445,7 +454,12 @@ func _load_settings():
attack_mode_pos = config.get_value("touch_controls", "special_position", Vector2(-200, -80)) attack_mode_pos = config.get_value("touch_controls", "special_position", Vector2(-200, -80))
var spawn_boost_pos = config.get_value("touch_controls", "spawn_boost_position", Vector2(-120, -80)) var spawn_boost_pos = config.get_value("touch_controls", "spawn_boost_position", Vector2(-120, -80))
button_positions = {"grab": grab_pos, "put": put_pos, "attack_mode": attack_mode_pos, "spawn_boost": spawn_boost_pos} button_positions = {
"grab": grab_pos,
"put": put_pos,
"attack_mode": attack_mode_pos,
"spawn_boost": spawn_boost_pos
}
# Apply loaded settings # Apply loaded settings
_apply_settings() _apply_settings()
+1 -16
View File
@@ -146,7 +146,7 @@ func _update_btn_shortcut(_effect_id: int, btn: Button):
return return
# Show only Shortcut 1 as per single-slot request # Show only Shortcut 1 as per single-slot request
sc_lbl.text = "[%s]" % SettingsManager.get_control_text("powerup_1") sc_lbl.text = "[%s]" % SettingsManager.get_control_text("use_powerup")
func _on_btn_pressed(effect_id: int): func _on_btn_pressed(effect_id: int):
print("[PowerUpUI] Clicked Button %d" % effect_id) print("[PowerUpUI] Clicked Button %d" % effect_id)
@@ -228,21 +228,6 @@ func _on_powerup_unlocked(effect: int, level: int):
else: else:
print("[PowerUpUI] ERROR: Unlocked Effect %d but no UI button found! Keys: %s" % [effect, icon_containers.keys()]) print("[PowerUpUI] ERROR: Unlocked Effect %d but no UI button found! Keys: %s" % [effect, icon_containers.keys()])
func _on_cooldown_updated(effect: int, time_left: float, max_time: float):
if icon_containers.has(effect):
var btn = icon_containers[effect]
var cd_lbl = btn.get_node_or_null("CooldownLabel")
if cd_lbl:
if time_left > 0:
cd_lbl.text = "%d" % int(time_left)
btn.disabled = true
btn.modulate = Color(0.7, 0.7, 0.7, 0.8)
else:
cd_lbl.text = ""
# Re-enable if we own it
if special_manager_ref and special_manager_ref.inventory.get(effect, false):
btn.disabled = false
btn.modulate = Color.WHITE
func _on_inventory_updated(inventory: Dictionary): func _on_inventory_updated(inventory: Dictionary):
# Update UI icons (Only show ONE active slot as per user request) # Update UI icons (Only show ONE active slot as per user request)
+16 -6
View File
@@ -105,16 +105,26 @@ func _connect_signals():
# Close # Close
close_button.pressed.connect(func(): visible = false) close_button.pressed.connect(func(): visible = false)
# Connect remapping buttons (exclude non-keybinds like use_controller) # Connect remapping buttons
for action_name in SettingsManager.settings.controls.keys(): for action_name in SettingsManager.settings.controls.keys():
if action_name == "use_controller": if action_name == "use_controller":
continue continue
var btn = get_node_or_null("%" + action_name.to_pascal_case() + "Btn") # Check Primary Button
if btn: var primary_btn = get_node_or_null("%" + action_name.to_pascal_case() + "Btn")
if btn.pressed.is_connected(_on_remap_button_pressed): if primary_btn:
btn.pressed.disconnect(_on_remap_button_pressed) if primary_btn.pressed.is_connected(_on_remap_button_pressed):
btn.pressed.connect(_on_remap_button_pressed.bind(action_name)) primary_btn.pressed.disconnect(_on_remap_button_pressed)
primary_btn.pressed.connect(_on_remap_button_pressed.bind(action_name))
# Check Alt Button
if not action_name.ends_with("_alt"):
var alt_action = action_name + "_alt"
var alt_btn = get_node_or_null("%" + action_name.to_pascal_case() + "AltBtn")
if alt_btn:
if alt_btn.pressed.is_connected(_on_remap_button_pressed):
alt_btn.pressed.disconnect(_on_remap_button_pressed)
alt_btn.pressed.connect(_on_remap_button_pressed.bind(alt_action))
func _on_video_setting_changed(_unused = false): func _on_video_setting_changed(_unused = false):
SettingsManager.settings.video.fullscreen = fullscreen_toggle.button_pressed SettingsManager.settings.video.fullscreen = fullscreen_toggle.button_pressed