Files
tekton/scripts/managers/powerup_manager.gd
T
2026-01-23 22:26:44 +08:00

162 lines
5.3 KiB
GDScript

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)