added nice smoke puffs to interactible objects
This commit is contained in:
@@ -24,6 +24,9 @@ var level_coins_collected: int = 0
|
||||
# Client ready tracking (server only)
|
||||
var clients_ready: Dictionary = {} # peer_id -> bool
|
||||
|
||||
# Level complete tracking
|
||||
var level_complete_triggered: bool = false # Prevent multiple level complete triggers
|
||||
|
||||
func _ready():
|
||||
# Add to group for easy access
|
||||
add_to_group("game_world")
|
||||
@@ -376,6 +379,31 @@ func _request_loot_pickup(loot_id: int, loot_position: Vector2, player_peer_id:
|
||||
else:
|
||||
print("GameWorld: Could not find loot for pickup request: id=", loot_id, " pos=", loot_position)
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func _sync_player_exit_stairs(player_peer_id: int):
|
||||
# Client receives notification that a player reached exit stairs
|
||||
if multiplayer.is_server():
|
||||
return # Server ignores this (it's the sender)
|
||||
|
||||
# Find the player by peer ID
|
||||
var players = get_tree().get_nodes_in_group("player")
|
||||
var target_player = null
|
||||
for p in players:
|
||||
if p.has_method("get_multiplayer_authority") and p.get_multiplayer_authority() == player_peer_id:
|
||||
target_player = p
|
||||
break
|
||||
|
||||
# Only disable controls/collision if this is our local player
|
||||
if target_player:
|
||||
var my_peer_id = multiplayer.get_unique_id()
|
||||
if player_peer_id == my_peer_id:
|
||||
# This is our local player - disable controls and collision
|
||||
target_player.controls_disabled = true
|
||||
target_player.set_collision_layer_value(1, false)
|
||||
print("GameWorld: Client disabled controls and collision for local player ", target_player.name)
|
||||
# Show black fade overlay for this player
|
||||
_show_black_fade_overlay()
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func _sync_show_level_complete(level_time: float):
|
||||
# Clients receive level complete UI sync from server
|
||||
@@ -400,6 +428,30 @@ func _sync_hide_level_complete():
|
||||
if level_complete_ui:
|
||||
level_complete_ui.visible = false
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func _sync_restore_player_controls():
|
||||
# Clients receive restore controls/collision sync from server
|
||||
if multiplayer.is_server():
|
||||
return # Server ignores this (it's the sender)
|
||||
|
||||
# Restore controls and collision for local player
|
||||
var my_peer_id = multiplayer.get_unique_id()
|
||||
var players = get_tree().get_nodes_in_group("player")
|
||||
for player in players:
|
||||
if player.has_method("get_multiplayer_authority") and player.get_multiplayer_authority() == my_peer_id:
|
||||
player.controls_disabled = false
|
||||
player.set_collision_layer_value(1, true)
|
||||
print("GameWorld: Client restored controls and collision for local player ", player.name)
|
||||
break
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func _sync_remove_black_fade():
|
||||
# Clients receive remove black fade sync from server
|
||||
if multiplayer.is_server():
|
||||
return # Server ignores this (it's the sender)
|
||||
|
||||
_remove_black_fade_overlay()
|
||||
|
||||
@rpc("authority", "reliable")
|
||||
func _sync_show_level_number(level: int):
|
||||
# Clients receive level number UI sync from server
|
||||
@@ -478,6 +530,9 @@ func _generate_dungeon():
|
||||
print("GameWorld: Not server, skipping dungeon generation")
|
||||
return
|
||||
|
||||
# Reset level complete flag for new level
|
||||
level_complete_triggered = false
|
||||
|
||||
print("GameWorld: Generating dungeon level ", current_level)
|
||||
|
||||
# Generate seed (deterministic for level 1, can be random for future levels)
|
||||
@@ -1555,8 +1610,32 @@ func _on_player_reached_stairs(player: Node):
|
||||
if not multiplayer.is_server() and multiplayer.has_multiplayer_peer():
|
||||
return # Only server handles this
|
||||
|
||||
# Prevent multiple triggers - if already triggered, ignore
|
||||
if level_complete_triggered:
|
||||
print("GameWorld: Level complete already triggered, ignoring duplicate trigger")
|
||||
return
|
||||
|
||||
print("GameWorld: Player ", player.name, " reached stairs!")
|
||||
|
||||
# Mark as triggered to prevent re-triggering
|
||||
level_complete_triggered = true
|
||||
|
||||
# Disable controls and collision for the player who reached stairs
|
||||
var player_peer_id = player.get_multiplayer_authority() if player.has_method("get_multiplayer_authority") else 0
|
||||
player.controls_disabled = true
|
||||
# Remove collision layer (layer 1 = players)
|
||||
player.set_collision_layer_value(1, false)
|
||||
print("GameWorld: Disabled controls and collision for player ", player.name)
|
||||
|
||||
# Show black fade overlay for server's local player if this is the server's player
|
||||
var my_peer_id = multiplayer.get_unique_id() if multiplayer.has_multiplayer_peer() else 1
|
||||
if player_peer_id == my_peer_id:
|
||||
_show_black_fade_overlay()
|
||||
|
||||
# Sync controls disabled and collision removal to clients
|
||||
if multiplayer.has_multiplayer_peer() and player_peer_id > 0:
|
||||
_sync_player_exit_stairs.rpc(player_peer_id)
|
||||
|
||||
# Drop any held objects for all players before level completion
|
||||
var entities_node = get_node_or_null("Entities")
|
||||
if entities_node:
|
||||
@@ -1629,6 +1708,18 @@ func _on_player_reached_stairs(player: Node):
|
||||
if hud and hud.has_method("start_timer"):
|
||||
hud.start_timer()
|
||||
|
||||
# Restore controls and collision for all players (server side)
|
||||
_restore_player_controls_and_collision()
|
||||
|
||||
# Sync restore to all clients
|
||||
if multiplayer.has_multiplayer_peer():
|
||||
_sync_restore_player_controls.rpc()
|
||||
|
||||
# Remove black fade overlay (server and clients)
|
||||
_remove_black_fade_overlay()
|
||||
if multiplayer.has_multiplayer_peer():
|
||||
_sync_remove_black_fade.rpc()
|
||||
|
||||
# Move all players to start room (server side)
|
||||
_move_all_players_to_start_room()
|
||||
|
||||
@@ -1665,9 +1756,10 @@ func _get_local_player_stats() -> Dictionary:
|
||||
var local_player = null
|
||||
|
||||
if multiplayer.has_multiplayer_peer():
|
||||
# Multiplayer: find player with matching authority
|
||||
# Multiplayer: find player with matching authority (client's own player)
|
||||
var my_peer_id = multiplayer.get_unique_id()
|
||||
for player in players:
|
||||
if player.has_method("is_multiplayer_authority") and player.is_multiplayer_authority():
|
||||
if player.has_method("get_multiplayer_authority") and player.get_multiplayer_authority() == my_peer_id:
|
||||
local_player = player
|
||||
break
|
||||
else:
|
||||
@@ -1759,6 +1851,54 @@ func _fade_in_player(player: Node):
|
||||
sprite_layer.modulate.a = 0.0 # Start invisible
|
||||
fade_tween.tween_property(sprite_layer, "modulate:a", 1.0, 1.0)
|
||||
|
||||
func _show_black_fade_overlay():
|
||||
# Create black fade overlay for player who reached exit
|
||||
# Remove existing fade if any
|
||||
var existing_fade = get_node_or_null("BlackFadeOverlay")
|
||||
if existing_fade:
|
||||
existing_fade.queue_free()
|
||||
|
||||
# Create CanvasLayer with z_index 999 (below level complete UI which is 1000)
|
||||
var fade_layer = CanvasLayer.new()
|
||||
fade_layer.name = "BlackFadeOverlay"
|
||||
fade_layer.layer = 999 # Below level complete UI (1000) but above gameplay
|
||||
add_child(fade_layer)
|
||||
|
||||
# Create ColorRect that fills the screen
|
||||
var fade_rect = ColorRect.new()
|
||||
fade_rect.name = "FadeRect"
|
||||
fade_rect.color = Color(0, 0, 0, 1) # Black, fully opaque
|
||||
fade_rect.set_anchors_preset(Control.PRESET_FULL_RECT) # Fill entire screen
|
||||
fade_layer.add_child(fade_rect)
|
||||
|
||||
# Fade in from transparent to black
|
||||
fade_rect.modulate.a = 0.0 # Start transparent
|
||||
var fade_tween = create_tween()
|
||||
fade_tween.tween_property(fade_rect, "modulate:a", 1.0, 0.5) # Fade in over 0.5 seconds
|
||||
print("GameWorld: Created black fade overlay for player who reached exit")
|
||||
|
||||
func _remove_black_fade_overlay():
|
||||
# Remove black fade overlay when new level starts
|
||||
var existing_fade = get_node_or_null("BlackFadeOverlay")
|
||||
if existing_fade:
|
||||
# Fade out quickly before removing
|
||||
var fade_rect = existing_fade.get_node_or_null("FadeRect")
|
||||
if fade_rect:
|
||||
var fade_tween = create_tween()
|
||||
fade_tween.tween_property(fade_rect, "modulate:a", 0.0, 0.2) # Fade out over 0.2 seconds
|
||||
await fade_tween.finished
|
||||
existing_fade.queue_free()
|
||||
print("GameWorld: Removed black fade overlay")
|
||||
|
||||
func _restore_player_controls_and_collision():
|
||||
# Restore controls and collision for all players when new level starts
|
||||
var players = get_tree().get_nodes_in_group("player")
|
||||
for player in players:
|
||||
player.controls_disabled = false
|
||||
# Restore collision layer (layer 1 = players)
|
||||
player.set_collision_layer_value(1, true)
|
||||
print("GameWorld: Restored controls and collision for player ", player.name)
|
||||
|
||||
func _show_level_complete_ui(level_time: float = 0.0):
|
||||
# Create or show level complete UI
|
||||
var level_complete_ui = get_node_or_null("LevelCompleteUI")
|
||||
@@ -1894,6 +2034,7 @@ func _create_level_complete_ui_programmatically() -> Node:
|
||||
# Create level complete UI programmatically
|
||||
var canvas_layer = CanvasLayer.new()
|
||||
canvas_layer.name = "LevelCompleteUI"
|
||||
canvas_layer.layer = 1000 # Very high z_index so it appears above black fade
|
||||
add_child(canvas_layer)
|
||||
|
||||
# Load standard font (as FontFile)
|
||||
|
||||
Reference in New Issue
Block a user