|
|
|
@@ -12,12 +12,14 @@ signal player_joined(player_data: Dictionary)
|
|
|
|
|
signal player_left(player_id: int)
|
|
|
|
|
signal ready_state_changed(player_id: int, is_ready: bool)
|
|
|
|
|
signal all_players_ready()
|
|
|
|
|
signal host_disconnected()
|
|
|
|
|
signal game_starting()
|
|
|
|
|
signal match_duration_changed(duration_seconds: int)
|
|
|
|
|
signal randomize_spawn_changed(enabled: bool)
|
|
|
|
|
signal character_changed(player_id: int, character_name: String)
|
|
|
|
|
signal area_changed(area_name: String)
|
|
|
|
|
signal player_list_changed()
|
|
|
|
|
signal rematch_votes_updated(count: int, required: int)
|
|
|
|
|
|
|
|
|
|
# Stop N Go settings signals
|
|
|
|
|
signal sng_go_duration_changed(duration: int)
|
|
|
|
@@ -50,6 +52,9 @@ signal enable_cycle_timer_changed(enabled: bool)
|
|
|
|
|
var scarcity_mode: String = "Normal" # Normal, Aggressive, Chaos
|
|
|
|
|
signal scarcity_mode_changed(mode: String)
|
|
|
|
|
|
|
|
|
|
# Disconnection reason for UI feedback
|
|
|
|
|
var disconnect_reason: String = ""
|
|
|
|
|
|
|
|
|
|
# Stop N Go settings
|
|
|
|
|
var sng_go_duration: int = 15
|
|
|
|
|
var sng_stop_duration: int = 4
|
|
|
|
@@ -60,6 +65,9 @@ var doors_swap_time: int = 15
|
|
|
|
|
var doors_refresh_time: int = 25
|
|
|
|
|
var doors_required_goals: int = 8
|
|
|
|
|
|
|
|
|
|
# Rematch tracking
|
|
|
|
|
var rematch_votes: Array = [] # [player_id, ...]
|
|
|
|
|
|
|
|
|
|
# Character and area selection
|
|
|
|
|
var available_characters: Array[String] = ["Copper", "Dabro", "Gatot", "Pip", "Random"]
|
|
|
|
|
var available_areas: Array[String] = []
|
|
|
|
@@ -87,6 +95,7 @@ func _ready():
|
|
|
|
|
NakamaManager.match_joined.connect(_on_match_joined)
|
|
|
|
|
multiplayer.peer_connected.connect(_on_peer_connected)
|
|
|
|
|
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
|
|
|
|
|
multiplayer.server_disconnected.connect(_on_server_disconnected)
|
|
|
|
|
|
|
|
|
|
func _update_available_areas(mode: String) -> void:
|
|
|
|
|
match mode:
|
|
|
|
@@ -133,14 +142,13 @@ func join_room(match_id: String) -> void:
|
|
|
|
|
|
|
|
|
|
func leave_room() -> void:
|
|
|
|
|
"""Leave the current room."""
|
|
|
|
|
current_room = {}
|
|
|
|
|
players_in_room.clear()
|
|
|
|
|
is_host = false
|
|
|
|
|
_all_ready = false
|
|
|
|
|
print("[LobbyManager] Leaving room. Clearing all local state.")
|
|
|
|
|
|
|
|
|
|
# Disconnect from Nakama match
|
|
|
|
|
if NakamaManager.socket:
|
|
|
|
|
NakamaManager.socket.close()
|
|
|
|
|
# Important: Reset all lobby settings and player lists first
|
|
|
|
|
reset()
|
|
|
|
|
|
|
|
|
|
# Disconnect from Nakama and reset multiplayer peer
|
|
|
|
|
NakamaManager.cleanup()
|
|
|
|
|
|
|
|
|
|
# Important: Clean up game state as well to prevent ghost players
|
|
|
|
|
GameStateManager.reset()
|
|
|
|
@@ -496,13 +504,13 @@ func sync_game_mode(mode: String) -> void:
|
|
|
|
|
_update_available_areas(mode)
|
|
|
|
|
emit_signal("game_mode_changed", mode)
|
|
|
|
|
|
|
|
|
|
func start_game() -> void:
|
|
|
|
|
func start_game(force: bool = false) -> void:
|
|
|
|
|
"""Host triggers game start (transitions all players to main.tscn)."""
|
|
|
|
|
if not is_host:
|
|
|
|
|
push_error("Only host can start the game")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if not _all_ready:
|
|
|
|
|
if not force and not _all_ready:
|
|
|
|
|
push_error("Not all players are ready")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
@@ -639,6 +647,54 @@ func _on_peer_disconnected(peer_id: int) -> void:
|
|
|
|
|
emit_signal("player_left", peer_id)
|
|
|
|
|
_check_all_ready()
|
|
|
|
|
|
|
|
|
|
func _on_server_disconnected() -> void:
|
|
|
|
|
"""Called on all clients when the host (server) disconnects."""
|
|
|
|
|
print("[LobbyManager] Server (Host) disconnected. Terminating room...")
|
|
|
|
|
disconnect_reason = "Host disconnected. Match terminated."
|
|
|
|
|
rematch_votes.clear()
|
|
|
|
|
emit_signal("host_disconnected")
|
|
|
|
|
leave_room()
|
|
|
|
|
|
|
|
|
|
# =============================================================================
|
|
|
|
|
# Rematch Logic
|
|
|
|
|
# =============================================================================
|
|
|
|
|
|
|
|
|
|
func reset_rematch_votes() -> void:
|
|
|
|
|
rematch_votes.clear()
|
|
|
|
|
emit_signal("rematch_votes_updated", 0, 2)
|
|
|
|
|
|
|
|
|
|
@rpc("any_peer", "call_local", "reliable")
|
|
|
|
|
func request_rematch(player_id: int) -> void:
|
|
|
|
|
"""Client requests a rematch. Only 2 votes needed to trigger."""
|
|
|
|
|
if not multiplayer.is_server():
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if player_id not in rematch_votes:
|
|
|
|
|
rematch_votes.append(player_id)
|
|
|
|
|
print("[LobbyManager] Rematch vote from %d. Total: %d/2" % [player_id, rematch_votes.size()])
|
|
|
|
|
|
|
|
|
|
# Sync vote count to all clients
|
|
|
|
|
rpc("sync_rematch_votes", rematch_votes.size(), 2)
|
|
|
|
|
|
|
|
|
|
# Check if we have enough votes
|
|
|
|
|
if rematch_votes.size() >= 2:
|
|
|
|
|
print("[LobbyManager] Rematch threshold met! Starting game...")
|
|
|
|
|
start_rematch()
|
|
|
|
|
|
|
|
|
|
@rpc("authority", "call_local", "reliable")
|
|
|
|
|
func sync_rematch_votes(count: int, required: int) -> void:
|
|
|
|
|
emit_signal("rematch_votes_updated", count, required)
|
|
|
|
|
|
|
|
|
|
func start_rematch() -> void:
|
|
|
|
|
"""Host starts the rematch."""
|
|
|
|
|
if not is_host:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
reset_rematch_votes()
|
|
|
|
|
|
|
|
|
|
# Start game using existing start_game logic, bypassing ready check
|
|
|
|
|
start_game(true)
|
|
|
|
|
|
|
|
|
|
@rpc("reliable")
|
|
|
|
|
func sync_player_list(player_list: Array) -> void:
|
|
|
|
|
"""Sync player list from host to all clients."""
|
|
|
|
|