From 5275c4acd8bb2a0dc4fa2412bce0332874effee1 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Thu, 12 Feb 2026 12:11:38 +0800 Subject: [PATCH] feat: Implement player input and movement managers for grid-based interaction and movement. --- scenes/player.gd | 43 ++++++++++++++++++++- scripts/managers/player_input_manager.gd | 13 ++++++- scripts/managers/player_movement_manager.gd | 12 ++++++ scripts/tekton.gd | 10 +++-- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/scenes/player.gd b/scenes/player.gd index 646f8c1..0f7da6c 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -1951,7 +1951,40 @@ func sync_throw_tekton(target_pos: Vector2i): print("[Player %s] Threw Tekton to %s (Dist: %s)" % [name, target_pos, target_pos.distance_to(tekton.current_position)]) +# is_attack_mode is already declared at top of file (or inherited?) +# Keeping is_knock_mode here for now or moving it up would be better, but let's just fix the error first. +var is_knock_mode: bool = false # Yellow mode for knocking Tekton + +func enter_attack_mode(): + if not is_multiplayer_authority(): return + + is_attack_mode = true + is_knock_mode = false # Mutually exclusive + NotificationManager.send_message(self, "Attack Mode ACTIVATED (Red)", NotificationManager.MessageType.POWERUP) + update_active_player_indicator() + +func enter_knock_mode(): + if not is_multiplayer_authority(): return + + is_knock_mode = true + is_attack_mode = false # Mutually exclusive + NotificationManager.send_message(self, "Knock Mode ACTIVATED (Yellow)", NotificationManager.MessageType.POWERUP) + update_active_player_indicator() + +func update_active_player_indicator(): + var color = Color.WHITE + + if is_attack_mode: + color = Color.RED + elif is_knock_mode: + color = Color.YELLOW + + # Apply visual tint to character model across network + rpc("sync_modulate", color) + func knock_tekton(): + # ... legacy or helper function ... + pass if not is_multiplayer_authority() or is_frozen: return @@ -1967,13 +2000,19 @@ func knock_tekton(): if is_multiplayer_authority(): rpc("sync_knock_tekton", tekton.get_path()) + + # Reset Knock Mode after successful hit + is_knock_mode = false + NotificationManager.send_message(self, "Knock Successful!", NotificationManager.MessageType.POWERUP) + update_active_player_indicator() @rpc("any_peer", "call_local", "reliable") func sync_knock_tekton(tekton_path: NodePath): var tekton = get_node_or_null(tekton_path) if tekton: - # Intensity 2.0 for knock (drops 200% tiles) - tekton.on_hit(self , 2.0) + # Intensity 2.0 for knock (drops 200% tiles) + Shrink/Recover + # Use on_thrown_landing to trigger shrink animation and floor freeze + tekton.on_thrown_landing(self, 2.0) print("[Player %s] Knocked Tekton %s" % [name, tekton.name]) # Visual feedback (Juice) diff --git a/scripts/managers/player_input_manager.gd b/scripts/managers/player_input_manager.gd index d691f70..93eef98 100644 --- a/scripts/managers/player_input_manager.gd +++ b/scripts/managers/player_input_manager.gd @@ -102,7 +102,15 @@ func handle_unhandled_input(event): KEY_Q: if player.powerup_manager: # Attack Mode (formerly Special) + # Now we want "Straight to Attack Mode" style + player.powerup_manager.use_special_effect() + + # Force visual update / mutual exclusivity manually if powerup manager doesn't do it yet + if player.is_attack_mode and player.has_method("enter_attack_mode"): + # Re-triggering enter_attack_mode might be redundant but safely ensures visuals/Knock=False + player.enter_attack_mode() + KEY_E: if player.powerup_manager: # Spawn Boost @@ -117,7 +125,10 @@ func handle_unhandled_input(event): else: player.grab_tekton() KEY_B: - player.knock_tekton() + if player.has_method("enter_knock_mode"): + player.enter_knock_mode() + else: + player.knock_tekton() # Handle spawn point selection if not yet selected diff --git a/scripts/managers/player_movement_manager.gd b/scripts/managers/player_movement_manager.gd index df6770e..4629990 100644 --- a/scripts/managers/player_movement_manager.gd +++ b/scripts/managers/player_movement_manager.gd @@ -81,6 +81,18 @@ func simple_move_to(grid_position: Vector2i) -> bool: var push_dir = grid_position - player.current_position if not try_push(grid_position, push_dir): return false + + # Check for Tekton interaction (Knock Mode) + # If moving into a Tekton's space while in Knock Mode, trigger knock + if player.get("is_knock_mode"): + # Find Tekton at grid_position + var tektons = player.get_tree().get_nodes_in_group("Tektons") + for t in tektons: + if t.current_position == grid_position and not t.is_carried: + # Trigger Knock + player.knock_tekton() + return false # Don't move into the tile, just knock + rotate_towards_target(grid_position) diff --git a/scripts/tekton.gd b/scripts/tekton.gd index 4d6873d..38cd209 100644 --- a/scripts/tekton.gd +++ b/scripts/tekton.gd @@ -148,9 +148,11 @@ func _flash_damage(): var is_recovering: bool = false # True when shrunk/waiting @rpc("any_peer", "call_local", "reliable") -func on_thrown_landing(attacker: Node = null): - """Called when Tekton lands after being thrown.""" - print("[Tekton] Landed! Shrinking and waiting...") +func on_thrown_landing(attacker: Node = null, intensity: float = 1.0): + """Called when Tekton lands after being thrown or knocked.""" + print("[Tekton] Landed/Knocked! Shrinking and waiting... (Intensity: %.1f)" % intensity) + + _flash_damage() # Add visual flash too? Why not. is_recovering = true @@ -194,7 +196,7 @@ func on_thrown_landing(attacker: Node = null): # Spawn tiles (as requested "tekton will spawn a tiles around that floor also") if is_multiplayer_authority(): - spawn_tiles_around(8) # Standard amount + spawn_tiles_around(int(8 * intensity)) # Floor Freeze (Visual/Instant - Run on all clients locally) temporarily_change_floor(current_position, 1, 6, 3.0)