diff --git a/addons/enhanced_gridmap/enhanced_gridmap.gd b/addons/enhanced_gridmap/enhanced_gridmap.gd index 91d8e23..eb265d6 100644 --- a/addons/enhanced_gridmap/enhanced_gridmap.gd +++ b/addons/enhanced_gridmap/enhanced_gridmap.gd @@ -282,7 +282,7 @@ func randomize_floor(floor_index: int, custom_rng_callable: Callable = Callable( # IMPORTANT: Only place items if Floor 0 has a valid ground tile (Walkable, Safe Zone, etc) var floor_0_item = get_cell_item(Vector3i(x, 0, z)) - var is_ground = (floor_0_item != -1) # All tiles on Layer 0 are valid ground + var is_ground = (floor_0_item != -1 and not floor_0_item in non_walkable_items) if not is_ground: set_cell_item(Vector3i(x, floor_index, z), -1) # Clear item if no ground diff --git a/scenes/main.gd b/scenes/main.gd index 58cef46..d67deb3 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -1594,13 +1594,14 @@ func _on_global_timer_updated(time_remaining: float): @rpc("any_peer", "call_local", "reliable") func sync_game_end_stop_n_go(winner_id: int): print("[STOP n GO] Game ended! Winner: ", winner_id) + var winner_name = "Player " + str(winner_id) var player_node = get_node_or_null(str(winner_id)) if player_node: winner_name = player_node.display_name - # Broadcast win - add_message_to_bar("WINNER", winner_name + " Reached the Finish Line!", MessageType.GOAL) + # Broadcast win (Validation already done in check_win_condition) + add_message_to_bar("MATCH COMPLETE", winner_name + " Wins with 3 Missions!", MessageType.GOAL) # Stop logic if stop_n_go_manager: diff --git a/scenes/player.gd b/scenes/player.gd index 7e30f84..09d997f 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -1311,10 +1311,11 @@ func start_movement_along_path(path: Array, clear_visual: bool = true): # This ensures that when interpolation resumes (in _process), it pulls to the correct spot target_visual_position = grid_to_world(current_position) - # Check if we've reached the finish line (uses lap-aware finish locations) - var current_finish_locs = race_manager.get_current_finish_locations() if race_manager else finish_locations - if current_position in current_finish_locs and can_finish: - finish_race() + # Racing Win Check (Skipped in Stop n Go which uses its own block above) + if LobbyManager.game_mode != "Stop n Go": + var current_finish_locs = race_manager.get_current_finish_locations() if race_manager else finish_locations + if current_position in current_finish_locs and can_finish: + finish_race() var main = get_tree().get_root().get_node_or_null("Main") diff --git a/scripts/managers/stop_n_go_manager.gd b/scripts/managers/stop_n_go_manager.gd index b258353..b78ad98 100644 --- a/scripts/managers/stop_n_go_manager.gd +++ b/scripts/managers/stop_n_go_manager.gd @@ -105,21 +105,20 @@ func _update_hud_visuals(): red_tint_overlay.visible = (current_phase == Phase.STOP) var my_id = multiplayer.get_unique_id() - if mission_label and player_missions.has(my_id): - var mission = player_missions[my_id] - # Get Icon name or ID for display - var tile_name = "Items" - match mission["target_tile"]: - 7: tile_name = "Hearts" - 8: tile_name = "Diamonds" - 9: tile_name = "Stars" - 10: tile_name = "Coins" - - mission_label.text = "Collect %d %s: %d / %d" % [mission["required"], tile_name, mission["current"], mission["required"]] + if mission_label: + var main = get_node_or_null("/root/Main") + var goals_cycle_manager = main.get_node_or_null("GoalsCycleManager") if main else null - if mission["current"] >= mission["required"]: - mission_label.text = "MISSION COMPLETE! REACH FINISH!" + # Get count from GoalsCycleManager (Source of truth for PlayerBoardLabel) + var completed_count = goals_cycle_manager.player_goal_counts.get(my_id, 0) if goals_cycle_manager else 0 + + mission_label.text = "GOALS (%d/3)" % completed_count + + if completed_count >= 3: + mission_label.text = "ALL GOALS COMPLETE!\nREACH THE FINISH!" mission_label.add_theme_color_override("font_color", Color.GOLD) + else: + mission_label.add_theme_color_override("font_color", Color.WHITE) func activate_client_side(): is_active = true @@ -284,22 +283,9 @@ func _spawn_mission_tiles(): count += 1 func _assign_missions(): - # Assign UNIQUE target tile types to players cyclicly - var players = GameStateManager.players - var tile_types = [ScarcityModel.TILE_HEART, ScarcityModel.TILE_DIAMOND, ScarcityModel.TILE_STAR, ScarcityModel.TILE_COIN] - - var idx = 0 - for p_id in players: - var target = tile_types[idx % tile_types.size()] - player_missions[p_id] = { - "target_tile": target, - "required": 3, - "current": 0 - } - idx += 1 - - if can_rpc(): - rpc("sync_missions", player_missions) + # NO-OP: Missions are now achievement-based (Complete 3 Goals) + # which is tracked natively by GoalsCycleManager. + pass @rpc("authority", "call_local", "reliable") func sync_missions(missions: Dictionary): @@ -338,38 +324,38 @@ func _penalize_player(player_id: int): # Notification is also handled inside on_stop_phase_violation on the player node emit_signal("player_penalized", player_id) -func update_mission_progress(player_id: int, tile_id: int): - if not player_missions.has(player_id): return - - var mission = player_missions[player_id] - if tile_id == mission["target_tile"]: - mission["current"] = min(mission["current"] + 1, mission["required"]) - - if mission["current"] >= mission["required"]: - emit_signal("mission_status_updated", player_id, true) - - # FIX: NotificationManager.send_message_to_player() does NOT exist. - # We need to find the player node and use send_message(target, msg, type) - var main = get_node("/root/Main") - if main: - var player_node = main.get_node_or_null(str(player_id)) - if player_node: - NotificationManager.send_message(player_node, "Mission Complete! Reach the Finish!", NotificationManager.MessageType.GOAL) - - if multiplayer.is_server() and can_rpc(): - rpc("sync_mission_progress", player_id, mission["current"]) +func update_mission_progress(_player_id: int, _tile_id: int): + # Redundant in Board-based mode, but kept for compatibility. + # The board is synced separately via sync_playerboard in playerboard_manager.gd. + pass @rpc("any_peer", "call_local", "reliable") -func sync_mission_progress(player_id: int, current: int): - if player_missions.has(player_id): - player_missions[player_id]["current"] = current +func sync_mission_progress(_player_id: int, _mission_index: int, _current: int): + # Deprecated + pass func check_win_condition(player_id: int, position: Vector2i) -> bool: - if not player_missions.has(player_id): return false + # 1. Must reach the finish line (Column 21) + if position.x < finish_line_x: + return false + + # 2. Must have 3 Goal Completions (tracked by GoalsCycleManager) + var main = get_node_or_null("/root/Main") + if not main: return false - var mission = player_missions[player_id] - if mission["current"] >= mission["required"]: - # Win when reaching X >= 21 - if position.x >= finish_line_x: - return true - return false + var goals_cycle_manager = main.get_node_or_null("GoalsCycleManager") + if not goals_cycle_manager: return false + + var completed_count = goals_cycle_manager.player_goal_counts.get(player_id, 0) + + if completed_count >= 3: + print("[StopNGo] Player %d REACHED FINISH with %d goals complete!" % [player_id, completed_count]) + return true + else: + # Inform the player locally if they reach the end without goals + var player_node = main.get_node_or_null(str(player_id)) + if player_node: + NotificationManager.send_message(player_node, "Incomplete! Achieve 3 goals (x3) to win!", NotificationManager.MessageType.WARNING) + + print("[StopNGo] Player %d reached finish but goal count too low: %d/3" % [player_id, completed_count]) + return false