From 8e0aa322dee69bcdf0a181fff6e5754981d288db Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Thu, 26 Feb 2026 16:55:36 +0800 Subject: [PATCH] feat: Implement core player entity with multiplayer state synchronization, character selection, movement, and manager-based input. --- scenes/player.gd | 17 +++++++---- scripts/managers/player_input_manager.gd | 8 ++--- scripts/managers/touch_controls.gd | 38 +++++++++++++++++------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/scenes/player.gd b/scenes/player.gd index e24bced..e2c8986 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -13,6 +13,7 @@ var powerup_manager var score: int = 0 signal position_changed +signal tekton_carried_changed(is_carrying) # Display name (synced across network) var _display_name: String = "" @@ -46,6 +47,7 @@ var is_carrying_tekton: bool: get: return is_carried_tekton set(value): is_carried_tekton = value + emit_signal("tekton_carried_changed", value) # Visual/Logic side effects if any var is_carried_tekton: bool = false @@ -2126,20 +2128,19 @@ func update_active_player_indicator(): sync_modulate(color) # Apply locally if offline/not ready func knock_tekton(): - # ... legacy or helper function ... - pass if not is_multiplayer_authority() or is_frozen or is_stop_frozen: return - # Requirement: Full Powerup Bar - if not powerup_manager or not powerup_manager.can_use_special(): + # Requirement: Full Powerup Bar (or we are already in knock mode) + if not is_knock_mode and (not powerup_manager or not powerup_manager.can_use_special()): NotificationManager.send_message(self , "Need Full Boost to Knock!", NotificationManager.MessageType.WARNING) return var tekton = _find_nearby_tekton() if tekton: - # Consume Boost - powerup_manager.consume_boost(100.0) + # Consume Boost if we haven't already (or just consume it now if we are in mode) + if powerup_manager: + powerup_manager.consume_boost(100.0) if is_multiplayer_authority(): rpc("sync_knock_tekton", tekton.get_path()) @@ -2148,6 +2149,10 @@ func knock_tekton(): is_knock_mode = false NotificationManager.send_message(self, "Knock Successful!", NotificationManager.MessageType.POWERUP) update_active_player_indicator() + else: + # If we called knock_tekton but nothing was nearby, maybe we just enter the mode? + # But usually this is called by movement_manager which knows something is there. + pass @rpc("any_peer", "call_local", "reliable") func sync_knock_tekton(tekton_path: NodePath): diff --git a/scripts/managers/player_input_manager.gd b/scripts/managers/player_input_manager.gd index 00fc3d6..c34011c 100644 --- a/scripts/managers/player_input_manager.gd +++ b/scripts/managers/player_input_manager.gd @@ -138,12 +138,10 @@ func handle_unhandled_input(event): player.grab_tekton() KEY_B: if player.powerup_manager and player.powerup_manager.can_use_special(): - if player.has_method("enter_knock_mode"): - player.enter_knock_mode() - player.powerup_manager.reset_boost() - else: + if player.has_method("_find_nearby_tekton") and player._find_nearby_tekton(): player.knock_tekton() - player.powerup_manager.reset_boost() + elif player.has_method("enter_knock_mode"): + player.enter_knock_mode() # Handle spawn point selection if not yet selected diff --git a/scripts/managers/touch_controls.gd b/scripts/managers/touch_controls.gd index 01399f4..ee1b944 100644 --- a/scripts/managers/touch_controls.gd +++ b/scripts/managers/touch_controls.gd @@ -44,6 +44,10 @@ func initialize(p_main: Node3D): func set_player(p_player: Node3D): local_player = p_player + # Connect to Tekton status updates + if not local_player.tekton_carried_changed.is_connected(_on_tekton_carried_changed): + local_player.tekton_carried_changed.connect(_on_tekton_carried_changed) + # Connect to PowerUpManager if it exists (for boost updates) var powerup_mgr = local_player.get_node_or_null("PowerUpManager") if powerup_mgr: @@ -351,18 +355,21 @@ func _on_button_pressed(button_name: String): "TektonKnock": var powerup_mgr = local_player.get_node_or_null("PowerUpManager") if powerup_mgr and powerup_mgr.can_use_special(): - if local_player.has_method("enter_knock_mode"): - local_player.enter_knock_mode() - powerup_mgr.reset_boost() - elif local_player.has_method("knock_tekton"): + # Proactive: If nearby, knock immediately. Else enter mode. + if local_player.has_method("_find_nearby_tekton") and local_player._find_nearby_tekton(): local_player.knock_tekton() - powerup_mgr.reset_boost() + elif local_player.has_method("enter_knock_mode"): + local_player.enter_knock_mode() "TektonThrow": - var powerup_mgr = local_player.get_node_or_null("PowerUpManager") - if powerup_mgr and powerup_mgr.can_use_special(): - if local_player.has_method("throw_tekton"): - local_player.throw_tekton() - powerup_mgr.reset_boost() + if local_player.is_carrying_tekton: + var powerup_mgr = local_player.get_node_or_null("PowerUpManager") + if powerup_mgr and powerup_mgr.can_use_special(): + if local_player.has_method("throw_tekton"): + local_player.throw_tekton() + powerup_mgr.reset_boost() + else: + if local_player.has_method("grab_tekton"): + local_player.grab_tekton() func _on_button_released(button_name: String): var btn: Button @@ -543,7 +550,16 @@ func _on_boost_points_changed(current_points: int, max_points: int): _update_boost_button_state(attack_mode_button, is_full) _update_boost_button_state(spawn_boost_button, is_full) _update_boost_button_state(tekton_knock_button, is_full) - _update_boost_button_state(tekton_throw_button, is_full) + + # TektonThrow can be used for "Grab" even without full boost + var can_throw_or_grab = is_full or (local_player and not local_player.is_carrying_tekton) + _update_boost_button_state(tekton_throw_button, can_throw_or_grab) + +func _on_tekton_carried_changed(_is_carrying: bool): + # Refresh button states when player grabs/throws a tekton + var powerup_mgr = local_player.get_node_or_null("PowerUpManager") + if powerup_mgr: + _on_boost_points_changed(powerup_mgr.current_boost, powerup_mgr.MAX_BOOST) func _update_boost_button_state(btn: Button, is_enabled: bool): if not btn: return