extends Node # PowerUpManager - Handles power-up points, holo tile tracking, and special effect usage const MAX_POINTS: int = 12 const POINTS_PER_BAR: int = 4 const MAX_BARS: int = 4 const HOLO_PICKUPS_PER_BAR: int = 4 const SPECIAL_COOLDOWN: float = 4.0 # 4 second cooldown var player: Node3D var enhanced_gridmap: Node # Power-up state var current_points: int = 0 var holo_pickup_count: int = 0 var special_cooldown_timer: float = 0.0 # Current cooldown remaining signal points_changed(current: int, max_points: int) signal bar_filled() signal effect_used() func initialize(p_player: Node3D, p_gridmap: Node): player = p_player enhanced_gridmap = p_gridmap set_process(true) func _process(delta): # Update cooldown timer if special_cooldown_timer > 0: special_cooldown_timer -= delta # ============================================================================= # Holo Tile Pickup # ============================================================================= func add_holo_pickup(): """Called when player picks up a holo tile (11-14).""" holo_pickup_count += 1 if holo_pickup_count >= HOLO_PICKUPS_PER_BAR: holo_pickup_count = 0 _add_bar() print("[PowerUp] Player %s picked up holo tile. Count: %d/4" % [player.name, holo_pickup_count]) if player.is_multiplayer_authority(): rpc("sync_holo_count", holo_pickup_count, current_points) func _add_bar(): """Add one full bar (4 points) of power-up.""" var points_to_add = POINTS_PER_BAR current_points = min(current_points + points_to_add, MAX_POINTS) emit_signal("bar_filled") emit_signal("points_changed", current_points, MAX_POINTS) # Type 1 = POWERUP message for special styling player.rpc("display_message", "Power-up bar filled!", 1) print("[PowerUp] Player %s gained 1 bar! Total: %d/%d points" % [player.name, current_points, MAX_POINTS]) if player.is_multiplayer_authority(): player.get_node("PowerUpManager").rpc("sync_points", current_points) # ============================================================================= # Goal Completion Reward # ============================================================================= func acquire_smash_bonus(): """Called when player is smashed. Grants 1 bar up to a max of 2 bars.""" if get_bars() < 2: _add_bar() print("[PowerUp] Player %s gained smash bonus bar! Total: %d/%d" % [player.name, current_points, MAX_POINTS]) else: print("[PowerUp] Player %s smash bonus capped (already has >= 2 bars)" % player.name) func add_goal_completion_reward(): """Called when player completes a goal pattern. Awards 1 bar.""" _add_bar() print("[PowerUp] Player %s completed goal - awarded 1 bar" % [player.name]) # ============================================================================= # Using Special Effects # ============================================================================= func can_use_special() -> bool: """Returns true if player has at least 1 bar (4 points) AND IS NOT ON COOLDOWN.""" return current_points >= POINTS_PER_BAR and special_cooldown_timer <= 0 func get_bars() -> int: """Returns current number of full bars.""" return current_points / POINTS_PER_BAR func use_special_effect(): """Consume 1 bar and trigger a random special effect.""" if not can_use_special(): # Type 3 = WARNING message player.rpc("display_message", "Not enough power-up!", 3) return false # Check cooldown if special_cooldown_timer > 0: player.rpc("display_message", "Special on cooldown! (%.1fs)" % special_cooldown_timer, 3) return false # Consume 1 bar current_points -= POINTS_PER_BAR emit_signal("effect_used") emit_signal("points_changed", current_points, MAX_POINTS) # Start cooldown special_cooldown_timer = SPECIAL_COOLDOWN # Play special animation (backflip) - synced across network if player.is_multiplayer_authority() and player.has_method("sync_special_animation"): player.rpc("sync_special_animation") # Trigger random special effect via SpecialTilesManager var special_tiles_manager = player.get_node_or_null("SpecialTilesManager") if special_tiles_manager: special_tiles_manager.trigger_random_effect() print("[PowerUp] Player %s used special effect! Remaining: %d/%d points, Cooldown: %.1fs" % [player.name, current_points, MAX_POINTS, SPECIAL_COOLDOWN]) if player.is_multiplayer_authority(): rpc("sync_points", current_points) return true # ============================================================================= # Sync # ============================================================================= @rpc("any_peer", "call_local", "reliable") func sync_holo_count(count: int, points: int): holo_pickup_count = count current_points = points emit_signal("points_changed", current_points, MAX_POINTS) @rpc("any_peer", "call_local", "reliable") func sync_points(points: int): current_points = points emit_signal("points_changed", current_points, MAX_POINTS) # ============================================================================= # Getters # ============================================================================= func get_points() -> int: return current_points func get_max_points() -> int: return MAX_POINTS func get_fill_percentage() -> float: return float(current_points) / float(MAX_POINTS) func reset(): current_points = 0 holo_pickup_count = 0 emit_signal("points_changed", current_points, MAX_POINTS)