feat: Implement the main game scene with new player functionality, Stop n Go and Portal Mode managers, a dynamic message bar, and pre-game countdown logic.

This commit is contained in:
2026-03-05 02:07:14 +08:00
parent cd7881bc3f
commit ebfa8f99a7
3 changed files with 318 additions and 46 deletions
+19 -19
View File
@@ -737,11 +737,11 @@ func apply_stagger(duration: float = 1.5):
# If still immune, show immunity tint (Green?), otherwise White
# UNLESS we are still stop-frozen (Cyan)
if is_stop_frozen:
_apply_tint_recursive(self, Color.CYAN)
_apply_tint_recursive(self , Color.CYAN)
elif immunity_timer > 0:
_apply_tint_recursive(self, Color(0.5, 1.0, 0.5)) # Light Green for immunity
_apply_tint_recursive(self , Color(0.5, 1.0, 0.5)) # Light Green for immunity
else:
_apply_tint_recursive(self, Color.WHITE) # Remove tint
_apply_tint_recursive(self , Color.WHITE) # Remove tint
@rpc("any_peer", "call_local", "reliable")
func sync_stop_freeze(enabled: bool):
@@ -753,16 +753,16 @@ func sync_stop_freeze(enabled: bool):
is_stop_frozen = enabled
if enabled:
_apply_tint_recursive(self, Color.CYAN)
_apply_tint_recursive(self , Color.CYAN)
print("[STOP n GO] Player %s FROZEN until GO phase" % name)
else:
# Restore appropriate tint
if is_frozen:
_apply_tint_recursive(self, Color.BLUE)
_apply_tint_recursive(self , Color.BLUE)
elif immunity_timer > 0:
_apply_tint_recursive(self, Color(0.5, 1.0, 0.5))
_apply_tint_recursive(self , Color(0.5, 1.0, 0.5))
else:
_apply_tint_recursive(self, Color.WHITE)
_apply_tint_recursive(self , Color.WHITE)
print("[STOP n GO] Player %s UNFROZEN" % name)
@rpc("any_peer", "call_local")
@@ -905,7 +905,7 @@ func on_stop_phase_violation():
var cell = Vector3i(pos.x, 1, pos.y)
rpc("sync_grid_item", cell.x, cell.y, cell.z, item_id)
NotificationManager.send_message(self, "STOP VIOLATION! Tiles scattered!", NotificationManager.MessageType.WARNING)
NotificationManager.send_message(self , "STOP VIOLATION! Tiles scattered!", NotificationManager.MessageType.WARNING)
func _find_multiple_drop_positions(count: int) -> Array:
var positions = []
@@ -1051,7 +1051,7 @@ func _process_remote_interpolation(_delta):
# Fallback to simple lerp if not enough snapshots
# Keep this very soft to smooth out transitions between tween and interpolation
if global_position.distance_squared_to(target_visual_position) > 0.001:
global_position = global_position.lerp(target_visual_position, _delta * 10.0)
global_position = global_position.lerp(target_visual_position, _delta * 10.0)
return
var render_time = Time.get_ticks_msec() - INTERPOLATION_OFFSET
@@ -1063,7 +1063,7 @@ func _process_remote_interpolation(_delta):
for i in range(1, snapshot_buffer.size()):
if snapshot_buffer[i].time > render_time:
newer = snapshot_buffer[i]
older = snapshot_buffer[i-1]
older = snapshot_buffer[i - 1]
break
if newer:
@@ -1257,7 +1257,7 @@ func _find_random_spawn_position() -> Vector2i:
# We should check if it is NOT TILE_OBSTACLE.
var item = enhanced_gridmap.get_cell_item(Vector3i(x, 0, z))
# Assuming 4 is obstacle, and -1 is void. 0 is walkable, 2 is safe zone.
if item != -1 and item != 4:
if item != -1 and item != 4:
if not is_position_occupied(pos):
available_positions.append(pos)
@@ -2164,13 +2164,13 @@ func sync_throw_tekton(target_pos: Vector2i):
# 1. Stun nearby players (Radius 2?)
# "if there's a player around that floor they will got stunned" -> "around that floor" implies radius
var impact_center = target_pos
var stun_radius = 1.5
var stun_radius = 1.5
var players = get_tree().get_nodes_in_group("Players")
print("[Throw] Checking stun impact at %s. Found %d players." % [impact_center, players.size()])
for p in players:
if p == self: continue
if p == self: continue
# Check distance
var dist = Vector2(p.current_position.x, p.current_position.y).distance_to(Vector2(impact_center.x, impact_center.y))
@@ -2184,7 +2184,7 @@ func sync_throw_tekton(target_pos: Vector2i):
# 2. Tekton drops tiles (Spawn tiles around) AND shrinks
if tekton.has_method("on_thrown_landing"):
tekton.on_thrown_landing(self, 2.0)
tekton.on_thrown_landing(self , 2.0)
else:
# Fallback
tekton.on_hit(self , 1.0)
@@ -2218,7 +2218,7 @@ func sync_drop_tekton():
# Trigger landing effects (minimal scale)
if tekton.has_method("on_thrown_landing"):
tekton.on_thrown_landing(self, 1.0) # Minimal scale impact
tekton.on_thrown_landing(self , 1.0) # Minimal scale impact
print("[Player %s] Dropped Tekton at %s" % [name, current_position])
@@ -2231,7 +2231,7 @@ func enter_attack_mode():
is_attack_mode = true
is_knock_mode = false # Mutually exclusive
NotificationManager.send_message(self, "Attack Mode ACTIVATED (Red)", NotificationManager.MessageType.POWERUP)
NotificationManager.send_message(self , "Attack Mode ACTIVATED (Red)", NotificationManager.MessageType.POWERUP)
update_active_player_indicator()
func enter_knock_mode():
@@ -2239,7 +2239,7 @@ func enter_knock_mode():
is_knock_mode = true
is_attack_mode = false # Mutually exclusive
NotificationManager.send_message(self, "Knock Mode ACTIVATED (Yellow)", NotificationManager.MessageType.POWERUP)
NotificationManager.send_message(self , "Knock Mode ACTIVATED (Yellow)", NotificationManager.MessageType.POWERUP)
update_active_player_indicator()
func update_active_player_indicator():
@@ -2276,7 +2276,7 @@ func knock_tekton():
# Reset Knock Mode after successful hit
is_knock_mode = false
NotificationManager.send_message(self, "Knock Successful!", NotificationManager.MessageType.POWERUP)
NotificationManager.send_message(self , "Knock Successful!", NotificationManager.MessageType.POWERUP)
update_active_player_indicator()
else:
# If we called knock_tekton but nothing was nearby, maybe we just enter the mode?
@@ -2289,7 +2289,7 @@ func sync_knock_tekton(tekton_path: NodePath):
if tekton:
# Intensity 2.0 for knock (drops 200% tiles) + Shrink/Recover
# Use on_thrown_landing to trigger shrink animation and floor freeze
tekton.on_thrown_landing(self, 2.0)
tekton.on_thrown_landing(self , 2.0)
print("[Player %s] Knocked Tekton %s" % [name, tekton.name])
# Visual feedback (Juice)