From 9201c99d42b1f9694f74eaae20a1f7184c1d14af Mon Sep 17 00:00:00 2001 From: adtpdn Date: Mon, 2 Feb 2026 08:34:04 +0800 Subject: [PATCH] update --- scenes/player.gd | 6 +- scripts/managers/player_movement_manager.gd | 9 +- scripts/managers/special_tiles_manager.gd | 115 +++++++++++++++++--- 3 files changed, 113 insertions(+), 17 deletions(-) diff --git a/scenes/player.gd b/scenes/player.gd index 3b8d16d..3f8f345 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -1046,8 +1046,12 @@ func start_movement_along_path(path: Array, clear_visual: bool = true): tween.set_trans(Tween.TRANS_LINEAR) tween.set_ease(Tween.EASE_IN_OUT) + var step_duration = 0.25 + if movement_manager: + step_duration = step_duration / movement_manager.speed_multiplier + for point in path: - tween.tween_property(self, "position", grid_to_world(Vector2i(point.x, point.y)), 0.25) + tween.tween_property(self, "position", grid_to_world(Vector2i(point.x, point.y)), step_duration) tween.tween_callback(func(): current_position = Vector2i(path[-1].x, path[-1].y) diff --git a/scripts/managers/player_movement_manager.gd b/scripts/managers/player_movement_manager.gd index 39fed10..bc7472f 100644 --- a/scripts/managers/player_movement_manager.gd +++ b/scripts/managers/player_movement_manager.gd @@ -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 diff --git a/scripts/managers/special_tiles_manager.gd b/scripts/managers/special_tiles_manager.gd index fcdbafa..aeba3ae 100644 --- a/scripts/managers/special_tiles_manager.gd +++ b/scripts/managers/special_tiles_manager.gd @@ -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: