feat: update

This commit is contained in:
2026-06-11 18:28:25 +08:00
parent 8520f9db3c
commit 8a2fb36a98
65 changed files with 4407 additions and 572 deletions
+81 -32
View File
@@ -99,6 +99,10 @@ const SMACK_CHARGE_WINDOW: float = 3.0
var player_mission_completions: Dictionary = {} # player_id → int
var player_cleansers: Dictionary = {} # player_id → int (0 or 1)
var cleanser_active: Dictionary = {} # player_id → true when immunity active
var cleanser_cells_left: Dictionary = {} # player_id → int (cells remaining)
const CLEANSER_MAX_CELLS: int = 5
const CLEANSER_ACTIVATION_DELAY: float = 0.3
# =============================================================================
# Trapped Players
@@ -131,6 +135,7 @@ var phase_label: Label
var cleanser_label: Label
var cleanser_icon: TextureRect
var cleanser_count: int = 0
var slowmo_label: Label
var _gauntlet_hud_scene: PackedScene = preload("res://scenes/gauntlet_hud.tscn")
# =============================================================================
@@ -763,13 +768,13 @@ func clear_sticky_cell(pos: Vector2i) -> void:
main_scene.rpc("sync_grid_item", pos.x, 2, pos.y, -1)
func _try_use_cleanser() -> void:
"""Local player attempts to use Cleanser on adjacent sticky cells."""
"""Local player attempts to activate Cleanser for 5-cell sticky immunity."""
var local_pid = multiplayer.get_unique_id()
var count = player_cleansers.get(local_pid, 0)
if count <= 0:
return
# Find local player
# Block activation during stun
var all_players = get_tree().get_nodes_in_group("Players")
var local_player = null
for p in all_players:
@@ -777,41 +782,75 @@ func _try_use_cleanser() -> void:
if pid == local_pid:
local_player = p
break
if not local_player or not gridmap:
if not local_player:
return
if local_player.get("is_frozen") or local_player.get("is_stop_frozen"):
return
# Already active
if cleanser_active.has(local_pid):
return
# Get player grid position
var player_pos = local_player.global_position
var grid_pos = Vector2i(int(player_pos.x), int(player_pos.z))
# 0.3s activation delay
await get_tree().create_timer(CLEANSER_ACTIVATION_DELAY).timeout
# Clear sticky cells in 3x3 area around player
var cleared_any = false
for dx in range(-1, 2):
for dz in range(-1, 2):
var check_pos = grid_pos + Vector2i(dx, dz)
if sticky_cells.has(check_pos):
if multiplayer.is_server():
clear_sticky_cell(check_pos)
else:
rpc("rpc_use_cleanser", check_pos)
cleared_any = true
# Re-validate after delay
if not is_instance_valid(local_player):
return
if local_player.get("is_frozen") or local_player.get("is_stop_frozen"):
return
if cleared_any:
# Consume cleanser
player_cleansers[local_pid] = 0
update_cleanser_ui(0)
# Trigger slow-mo for dramatic effect
if multiplayer.is_server():
trigger_slowmo()
else:
rpc("rpc_trigger_slowmo")
# Notify server if we're a client
if not multiplayer.is_server() and _can_rpc():
rpc("rpc_consume_cleanser", local_pid)
elif multiplayer.is_server():
# Sync to all clients
# Activate cleanser immunity
cleanser_active[local_pid] = true
cleanser_cells_left[local_pid] = CLEANSER_MAX_CELLS
# Consume cleanser from inventory
player_cleansers[local_pid] = 0
update_cleanser_ui(0)
# Sync to server/clients
if not multiplayer.is_server() and _can_rpc():
rpc("rpc_activate_cleanser", local_pid)
elif multiplayer.is_server():
if _can_rpc():
rpc("sync_cleanser_count", local_pid, 0)
# Trigger slow-mo for dramatic effect
if multiplayer.is_server():
trigger_slowmo()
else:
rpc("rpc_trigger_slowmo")
NotificationManager.send_message(local_player, "Cleanser Active! (5 cells)", NotificationManager.MessageType.POWERUP)
func deactivate_cleanser(player_id: int) -> void:
"""Deactivate cleanser immunity for a player."""
cleanser_active.erase(player_id)
cleanser_cells_left.erase(player_id)
func is_cleanser_active(player_id: int) -> bool:
"""Check if a player has active cleanser immunity."""
return cleanser_active.has(player_id)
func use_cleanser_cell(player_id: int) -> bool:
"""Use one cleanser cell. Returns true if still active, false if exhausted."""
if not cleanser_active.has(player_id):
return false
cleanser_cells_left[player_id] -= 1
if cleanser_cells_left[player_id] <= 0:
deactivate_cleanser(player_id)
return false
return true
@rpc("any_peer", "call_local", "reliable")
func rpc_activate_cleanser(pid: int) -> void:
"""RPC for clients to activate cleanser on server."""
if multiplayer.is_server():
if not cleanser_active.has(pid):
cleanser_active[pid] = true
cleanser_cells_left[pid] = CLEANSER_MAX_CELLS
player_cleansers[pid] = 0
if _can_rpc():
rpc("sync_cleanser_count", local_pid, 0)
rpc("sync_cleanser_count", pid, 0)
@rpc("any_peer", "call_local", "reliable")
func rpc_use_cleanser(pos: Vector2i) -> void:
@@ -848,6 +887,9 @@ func trigger_slowmo(duration: float = 4.0) -> void:
# Show visual overlay
if main_scene and main_scene.has_node("Camera3D200"):
_show_slowmo_overlay()
# Show slow-mo HUD label
if slowmo_label:
slowmo_label.visible = true
if _can_rpc():
rpc("sync_slowmo_start", duration)
@@ -855,6 +897,9 @@ func _end_slowmo() -> void:
slowmo_active = false
Engine.time_scale = 1.0
_hide_slowmo_overlay()
# Hide slow-mo HUD label
if slowmo_label:
slowmo_label.visible = false
if _can_rpc():
rpc("sync_slowmo_end")
@@ -890,6 +935,8 @@ func sync_slowmo_start(duration: float) -> void:
slowmo_timer = duration
Engine.time_scale = SLOWMO_SCALE
_show_slowmo_overlay()
if slowmo_label:
slowmo_label.visible = true
@rpc("authority", "call_local", "reliable")
func sync_slowmo_end() -> void:
@@ -907,6 +954,7 @@ func _setup_hud() -> void:
phase_label = hud_layer.get_node("TopContainer/PhaseLabel")
cleanser_icon = hud_layer.get_node("BottomContainer/CleanserHBox/CleanserIcon")
cleanser_label = hud_layer.get_node("BottomContainer/CleanserHBox/CleanserLabel")
slowmo_label = hud_layer.get_node_or_null("TopContainer/SlowMoLabel")
_generate_cleanser_icon()
func _generate_cleanser_icon() -> void:
@@ -995,6 +1043,7 @@ func _on_goal_count_updated(peer_id: int, count: int) -> void:
player_cleansers[peer_id] = 0
if player_cleansers[peer_id] < 1:
player_cleansers[peer_id] = 1
emit_signal("cleanser_granted", peer_id)
print("[Gauntlet] Player %d granted Cleanser (mission %d)" % [peer_id, completions])
# Respawn mission tiles in non-sticky locations