diff --git a/project.godot b/project.godot index 8de997e..b6032df 100644 --- a/project.godot +++ b/project.godot @@ -21,7 +21,6 @@ config/icon="res://icon.svg" [autoload] -SettingsManager="*res://scripts/managers/settings_manager.gd" Nakama="*uid://bueyqhhvxe0tx" NakamaManager="*res://scripts/nakama_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" GoalsCycleManager="*res://scripts/managers/goals_cycle_manager.gd" Satori="*uid://b8vev00s34b7" +SettingsManager="*uid://c1ouaaqnn0lrc" [display] @@ -69,24 +69,28 @@ move_north={ "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) , 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={ "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) , 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={ "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) , 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={ "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) , 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={ diff --git a/scenes/main.tscn b/scenes/main.tscn index ae6b54a..928927e 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -1161,24 +1161,20 @@ grow_horizontal = 0 grow_vertical = 0 [node name="ActionButtonContainer" type="VBoxContainer" parent="ActionMenu" unique_id=1026460846] -visible = false layout_mode = 0 offset_right = 40.0 offset_bottom = 40.0 [node name="MoveButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=1233901451] -visible = false layout_mode = 2 text = "Move" [node name="GrabButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=1584219139] -visible = false custom_minimum_size = Vector2(100, 100) layout_mode = 2 text = "Grab" [node name="PutButton" type="Button" parent="ActionMenu/ActionButtonContainer" unique_id=508990607] -visible = false custom_minimum_size = Vector2(100, 100) layout_mode = 2 text = "Put" diff --git a/scenes/player.gd b/scenes/player.gd index 031f813..b5c047a 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -1012,6 +1012,20 @@ func activate_powerup(effect_id: int): if st_manager: 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): # 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): - # 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: input_manager.handle_unhandled_input(event) diff --git a/scenes/ui/settings_menu.tscn b/scenes/ui/settings_menu.tscn index b7cac60..7addbdf 100644 --- a/scenes/ui/settings_menu.tscn +++ b/scenes/ui/settings_menu.tscn @@ -300,7 +300,22 @@ label_settings = SubResource("LabelSettings_section") layout_mode = 2 theme_override_constants/h_separation = 20 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] layout_mode = 2 @@ -314,6 +329,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 size_flags_horizontal = 3 @@ -326,6 +347,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 size_flags_horizontal = 3 @@ -338,6 +365,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 size_flags_horizontal = 3 @@ -350,6 +383,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") @@ -363,55 +402,25 @@ label_settings = SubResource("LabelSettings_section") layout_mode = 2 theme_override_constants/h_separation = 20 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 size_flags_horizontal = 3 -text = "PowerUp 1 (Speed)" +text = "Activate PowerUp (Universal)" 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 custom_minimum_size = Vector2(150, 40) layout_mode = 2 -text = "1" +text = "F" -[node name="P2Label" type="Label" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000020] -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] +[node name="UsePowerupAltBtn" type="Button" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox/PowerUpGrid" unique_id=100000120] unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 -text = "2" - -[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" +text = "N/A" [node name="PowerBarSection" type="PanelContainer" parent="PanelContainer/VBoxContainer/ContentSection/TabContainer/Controls/VBox" unique_id=100000026] layout_mode = 2 @@ -426,7 +435,7 @@ label_settings = SubResource("LabelSettings_section") layout_mode = 2 theme_override_constants/h_separation = 20 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] layout_mode = 2 @@ -440,6 +449,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 size_flags_horizontal = 3 @@ -452,6 +467,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_section_header") @@ -465,7 +486,7 @@ label_settings = SubResource("LabelSettings_section") layout_mode = 2 theme_override_constants/h_separation = 20 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] layout_mode = 2 @@ -479,6 +500,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 size_flags_horizontal = 3 @@ -491,6 +518,12 @@ custom_minimum_size = Vector2(150, 40) layout_mode = 2 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] layout_mode = 2 size_flags_horizontal = 3 @@ -502,3 +535,9 @@ unique_name_in_owner = true custom_minimum_size = Vector2(150, 40) layout_mode = 2 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" diff --git a/scripts/managers/player_input_manager.gd b/scripts/managers/player_input_manager.gd index 760146f..9ae99d4 100644 --- a/scripts/managers/player_input_manager.gd +++ b/scripts/managers/player_input_manager.gd @@ -82,7 +82,7 @@ func _process(delta): player.highlight_cells_if_authorized(area, highlight_id) 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"): player.set_process_unhandled_input(false) return @@ -97,66 +97,37 @@ func handle_unhandled_input(event): # --- Keyboard Shortcuts (Event-based) --- 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 if not SettingsManager: return - # Get dynamic keybinds - var key_p1 = SettingsManager.get_control_keycode("powerup_1") - var key_p2 = SettingsManager.get_control_keycode("powerup_2") - var key_p3 = SettingsManager.get_control_keycode("powerup_3") - var key_p4 = SettingsManager.get_control_keycode("powerup_4") - - var ek = event.keycode - - # Unified check for PowerUp keys - 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"): + # 1. Unified check for POWER-UP Activation + if event.is_action_pressed("use_powerup"): + player.activate_held_powerup() + get_viewport().set_input_as_handled() + return + + + # 3. Action Buttons (Remappable via InputMap) + if event.is_action_pressed("action_knock_tekton"): if player.powerup_manager: player.powerup_manager.use_special_effect() if player.is_attack_mode and player.has_method("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.powerup_manager.has_method("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 player.powerup_manager.can_use_special(): + if player.powerup_manager.has_method("can_use_special"): # Corrected method name player.grab_tekton() - - # Handle spawn point selection if not yet selected - + get_viewport().set_input_as_handled() + # Handle spawn point selection if not yet selected 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: diff --git a/scripts/managers/settings_manager.gd b/scripts/managers/settings_manager.gd index 2a3dd74..ea38c7a 100644 --- a/scripts/managers/settings_manager.gd +++ b/scripts/managers/settings_manager.gd @@ -31,23 +31,33 @@ var settings = { }, "controls": { "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_alt": KEY_UP, "move_down": KEY_S, + "move_down_alt": KEY_DOWN, "move_left": KEY_A, + "move_left_alt": KEY_LEFT, "move_right": KEY_D, + "move_right_alt": KEY_RIGHT, + # Actions "grab": KEY_SPACE, + "grab_alt": KEY_J, "put": KEY_R, + "put_alt": KEY_K, "tekton_grab": KEY_G, + "tekton_grab_alt": KEY_L, + # Power-Up Controls - "powerup_1": KEY_1, - "powerup_2": KEY_2, - "powerup_3": KEY_3, - "powerup_4": KEY_4, + "use_powerup": KEY_F, + "use_powerup_alt": KEY_SHIFT, + # Power Bar Controls / Special "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(): apply_video_settings() apply_audio_settings() + apply_control_settings() emit_signal("settings_applied") 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_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): if settings.controls.has(action_name): settings.controls[action_name] = keycode + apply_control_settings() # Apply immediately emit_signal("control_remapped", action_name, keycode) save_settings() diff --git a/scripts/managers/special_tiles_manager.gd b/scripts/managers/special_tiles_manager.gd index 420a28f..05fe162 100644 --- a/scripts/managers/special_tiles_manager.gd +++ b/scripts/managers/special_tiles_manager.gd @@ -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]) return - # Check Cooldown - if powerup_cooldowns.get(effect, 0.0) > 0: - print("PowerUp %s on cooldown." % SpecialEffect.keys()[effect]) - return - # Check Attack Mode Restriction 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) @@ -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) return - # Calculate Cooldown based on Level var level = powerup_levels.get(effect, 1) - # Linear Interp: Lvl 1 = 15s, Lvl 8 = 5s - # 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]) + print("[SpecialTiles] Player %s activated %s (Lvl %d). No cooldown applied." % [player.name, SpecialEffect.keys()[effect], level]) match effect: SpecialEffect.FASTER_SPEED: @@ -555,19 +542,6 @@ func _check_for_icy_floor(): pass 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) if active_buffs.has(SpecialEffect.FASTER_SPEED): active_buffs[SpecialEffect.FASTER_SPEED] -= delta diff --git a/scripts/managers/touch_controls.gd b/scripts/managers/touch_controls.gd index f2a623a..9951a63 100644 --- a/scripts/managers/touch_controls.gd +++ b/scripts/managers/touch_controls.gd @@ -15,6 +15,7 @@ var attack_mode_button: Button # Renamed from special_button var spawn_boost_button: Button var settings_button: Button var tekton_grab_button: Button + @onready var SettingsManager = get_node_or_null("/root/SettingsManager") # Settings - persisted to config file @@ -30,6 +31,7 @@ var button_positions: Dictionary = { "attack_mode": Vector2(-200, -80), # Renamed "spawn_boost": Vector2(-120, -80) } + var button_scale: float = 1.0 # 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) tekton_grab_button = _find_or_create_action_button(actions_container, "TektonGrab", "👋", Vector2(-280, -80)) + # Order: AttackMode, SpawnBoost, Grab, TektonGrab if attack_mode_button: @@ -184,6 +187,7 @@ func _create_touch_ui(): actions_container.move_child(tekton_grab_button, 3) tekton_grab_button.icon = load("res://assets/graphics/touch_control/grab_tekton.png") tekton_grab_button.expand_icon = true + # Hide 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") "SpawnBoost": existing_lbl.text = SettingsManager.get_control_text("spawn_boost") "TektonGrab": existing_lbl.text = SettingsManager.get_control_text("tekton_grab") + 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" "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" + btn.add_child(shortcut_lbl) @@ -358,6 +364,7 @@ func _on_button_pressed(button_name: String): "AttackMode": btn = attack_mode_button "SpawnBoost": btn = spawn_boost_button "TektonGrab": btn = tekton_grab_button + if btn: var tween = create_tween() @@ -396,6 +403,7 @@ func _on_button_pressed(button_name: String): if local_player.has_method("grab_tekton"): local_player.grab_tekton() + func _on_button_released(button_name: String): var btn: Button match button_name: @@ -404,6 +412,7 @@ func _on_button_released(button_name: String): "AttackMode": btn = attack_mode_button "SpawnBoost": btn = spawn_boost_button "TektonGrab": btn = tekton_grab_button + if btn: var tween = create_tween() @@ -445,7 +454,12 @@ func _load_settings(): 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)) - 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_settings() diff --git a/scripts/ui/powerup_inventory_ui.gd b/scripts/ui/powerup_inventory_ui.gd index 7d74d20..54b2913 100644 --- a/scripts/ui/powerup_inventory_ui.gd +++ b/scripts/ui/powerup_inventory_ui.gd @@ -146,7 +146,7 @@ func _update_btn_shortcut(_effect_id: int, btn: Button): return # 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): print("[PowerUpUI] Clicked Button %d" % effect_id) @@ -228,21 +228,6 @@ func _on_powerup_unlocked(effect: int, level: int): else: 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): # Update UI icons (Only show ONE active slot as per user request) diff --git a/scripts/ui/settings_menu.gd b/scripts/ui/settings_menu.gd index 1562e0e..37bfb87 100644 --- a/scripts/ui/settings_menu.gd +++ b/scripts/ui/settings_menu.gd @@ -105,16 +105,26 @@ func _connect_signals(): # Close 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(): if action_name == "use_controller": continue - var btn = get_node_or_null("%" + action_name.to_pascal_case() + "Btn") - if btn: - if btn.pressed.is_connected(_on_remap_button_pressed): - btn.pressed.disconnect(_on_remap_button_pressed) - btn.pressed.connect(_on_remap_button_pressed.bind(action_name)) + # Check Primary Button + var primary_btn = get_node_or_null("%" + action_name.to_pascal_case() + "Btn") + if primary_btn: + if primary_btn.pressed.is_connected(_on_remap_button_pressed): + 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): SettingsManager.settings.video.fullscreen = fullscreen_toggle.button_pressed