This commit is contained in:
2026-02-02 08:34:04 +08:00
parent d6c84dd30d
commit 9201c99d42
3 changed files with 113 additions and 17 deletions
+8 -1
View File
@@ -9,6 +9,7 @@ var use_diagonal_movement: bool = false
var is_moving: bool = false
var rotation_speed: float = 10.0
var target_rotation: float = 0.0
var speed_multiplier: float = 1.0 # For slow-mo effects
func initialize(p_player: Node3D, p_gridmap: Node):
player = p_player
@@ -123,7 +124,6 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
if enhanced_gridmap.is_position_valid(pushed_to_pos) and \
enhanced_gridmap.get_cell_item(Vector3i(pushed_to_pos.x, 0, pushed_to_pos.y)) != -1 and \
not player.is_position_occupied(pushed_to_pos):
# Valid push
var push_path = [Vector2(pushed_to_pos.x, pushed_to_pos.y)]
other_player.rpc("start_movement_along_path", push_path, false)
@@ -142,6 +142,13 @@ func try_push(target_pos: Vector2i, direction: Vector2i) -> bool:
return true
func set_speed_multiplier(multiplier: float):
speed_multiplier = multiplier
# If we are currently moving, we might need to adjust the speed of the active tween?
# However, the movement is handled via RPC 'start_movement_along_path' which
# likely uses a fixed speed or duration on all clients.
# Let's check how 'start_movement_along_path' is implemented in player.gd.
func buffer_move_input(direction: Vector2i):
buffered_direction = direction
+100 -15
View File
@@ -30,13 +30,15 @@ var enhanced_gridmap: Node
var rng: RandomNumberGenerator
# Effect durations
const FREEZE_DURATION = 3.0
const FREEZE_ZONE_DURATION = 15.0
const FREEZE_SLOW_MULTIPLIER = 0.2 # Super slow down
const BLOCK_DURATION = 9.0
const INVISIBLE_DURATION = 6.0
# Active effect tracking
var blocked_tiles: Array[Dictionary] = [] # {position: Vector3i, original_item: int, timer: float}
var freeze_zones: Array[Dictionary] = [] # {position: Vector2i, timer: float}
var invisible_timer: float = 0.0
# INVENTORY SYSTEM
@@ -127,8 +129,7 @@ func activate_effect(effect: int, target_player: Node3D = null):
_execute_block_floor(target_player)
SpecialEffect.FREEZE_PLAYER:
if target_player:
_execute_freeze_player(target_player)
_execute_freeze_zones() # No target needed anymore
SpecialEffect.INVISIBLE_MODE:
# Always self
@@ -161,7 +162,7 @@ func trigger_random_effect():
SpecialEffect.SPAWN_TILES:
_execute_spawn_tiles(player)
SpecialEffect.FREEZE_PLAYER:
_execute_freeze_player(_get_random_opponent())
_execute_freeze_zones()
SpecialEffect.BLOCK_FLOOR:
_execute_block_floor(player)
SpecialEffect.INVISIBLE_MODE:
@@ -222,18 +223,32 @@ func _execute_spawn_tiles(target: Node3D):
NotificationManager.send_message(target, NotificationManager.MESSAGES.TILES_SPAWNED, NotificationManager.MessageType.POWERUP)
func _execute_freeze_player(target: Node3D):
if not target:
print("[SpecialTiles] No opponent found for FREEZE_PLAYER")
return
func _execute_freeze_zones():
# Area-based freeze: spawn pattern around activating player
var center = player.current_position
var pattern_keys = PATTERNS.keys()
var pattern_name = pattern_keys[rng.randi() % pattern_keys.size()]
var pattern = PATTERNS[pattern_name]
if target.has_method("apply_stagger"): # Stagger = Freeze roughly
target.rpc("apply_stagger", FREEZE_DURATION)
else:
target.set("is_frozen", true)
_create_unfreeze_timer(target, FREEZE_DURATION)
NotificationManager.send_message(target, NotificationManager.MESSAGES.FROZEN_BY % player.display_name, NotificationManager.MessageType.WARNING)
print("[SpecialTiles] Player %s spawning FREEZE zones in pattern %s" % [player.name, pattern_name])
for offset in pattern:
var pos = center + offset
if enhanced_gridmap.is_position_valid(pos):
# Add to active zones
freeze_zones.append({
"position": pos,
"timer": FREEZE_ZONE_DURATION
})
# Sync visual (use item ID 15 for "Icy" floor marker or similar)
if player.is_multiplayer_authority():
var main = player.get_tree().get_root().get_node_or_null("Main")
if main:
# Layer 2 for effect overlays
main.rpc("sync_grid_item", pos.x, 2, pos.y, 15)
NotificationManager.send_message(player, NotificationManager.MESSAGES.FREEZE_ZONE_READY if NotificationManager.MESSAGES.has("FREEZE_ZONE_READY") else "Freeze zones deployed!", NotificationManager.MessageType.POWERUP)
func _execute_block_floor(target: Node3D):
# Make nearby tile non-walkable for 9 seconds
@@ -296,9 +311,79 @@ func spawn_powerups_around(center: Vector2i, force_powerups: bool = true):
main.rpc("sync_grid_item", cell.x, cell.y, cell.z, item_id)
func _update_freeze_zones(delta: float):
# Only the authority of this manager (the caster) handles the timers and cleanup
if not player.is_multiplayer_authority():
return
var zones_to_remove = []
for i in range(freeze_zones.size()):
freeze_zones[i].timer -= delta
if freeze_zones[i].timer <= 0:
zones_to_remove.append(i)
# Cleanup expired zones
zones_to_remove.reverse()
for idx in zones_to_remove:
var zone = freeze_zones[idx]
var main = player.get_tree().get_root().get_node_or_null("Main")
if main:
main.rpc("sync_grid_item", zone.position.x, 2, zone.position.y, -1)
freeze_zones.remove_at(idx)
func _check_for_icy_floor():
# Every player checks if they are standing on an icy floor (item 15 on layer 2)
# This ensures slow-mo works even if zones were cast by another player.
if not player.is_multiplayer_authority():
return
if not enhanced_gridmap:
return
var current_item = enhanced_gridmap.get_cell_item(Vector3i(player.current_position.x, 2, player.current_position.y))
if current_item == 15:
_apply_slow_mo(player)
elif player.movement_manager and player.movement_manager.speed_multiplier < 1.0:
# Check if we should restore speed
# In this case, we'll let _apply_slow_mo's timer handle it,
# OR we can explicitly reset here if NOT on item 15.
pass
func _process(delta):
_update_blocked_tiles(delta)
_update_invisible_timer(delta)
_update_freeze_zones(delta)
_check_for_icy_floor()
func _apply_slow_mo(target_player: Node3D):
if target_player.has_method("apply_stagger") and target_player.is_frozen:
return # Already fully frozen/staggered
if target_player.movement_manager:
target_player.movement_manager.set_speed_multiplier(FREEZE_SLOW_MULTIPLIER)
# Visual tint
if target_player.has_method("sync_modulate"):
target_player.rpc("sync_modulate", Color(0.6, 0.8, 1.0)) # Icy blue
# Reset speed after a short delay if they leave
_create_restore_speed_timer(target_player, 0.2)
func _create_restore_speed_timer(target_player: Node3D, duration: float):
# We use a short timer to reset speed. If they are still in the zone,
# _process will re-apply it next frame.
await player.get_tree().create_timer(duration).timeout
if is_instance_valid(target_player) and target_player.movement_manager:
# Check if they are still on an icy floor
var still_in_zone = false
if enhanced_gridmap:
var item = enhanced_gridmap.get_cell_item(Vector3i(target_player.current_position.x, 2, target_player.current_position.y))
if item == 15:
still_in_zone = true
if not still_in_zone:
target_player.movement_manager.set_speed_multiplier(1.0)
if target_player.has_method("sync_modulate"):
target_player.rpc("sync_modulate", Color.WHITE)
func _update_invisible_timer(delta: float):
if invisible_timer > 0: