From a7a4ca68aaba690cf2905f5382e6dc092cd39bb7 Mon Sep 17 00:00:00 2001 From: god Date: Mon, 6 Jul 2026 02:41:37 +0800 Subject: [PATCH] implement delivery ready indicator logic + off-color detection --- scenes/candy_survival_hud.tscn | 10 +++++ scripts/managers/candy_survival_manager.gd | 41 +++++++++++++---- scripts/managers/goal_manager.gd | 11 ++++- scripts/managers/playerboard_manager.gd | 51 ++++++++++++++++++++-- 4 files changed, 99 insertions(+), 14 deletions(-) diff --git a/scenes/candy_survival_hud.tscn b/scenes/candy_survival_hud.tscn index 1cd3cc3..97add6f 100644 --- a/scenes/candy_survival_hud.tscn +++ b/scenes/candy_survival_hud.tscn @@ -102,4 +102,14 @@ theme_override_colors/font_outline_color = Color(0, 0, 0, 1) theme_override_constants/outline_size = 5 theme_override_fonts/font = ExtResource("1_font") text = "Score: 0" +horizontal_alignment = 1 + +[node name="DeliveryIndicator" type="Label" parent="BottomContainer/HBoxContainer/ScorePanel"] +layout_mode = 2 +theme_override_font_sizes/font_size = 20 +theme_override_colors/font_color = Color(1.0, 1.0, 0.2, 1) +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 5 +theme_override_fonts/font = ExtResource("1_font") +text = "" horizontal_alignment = 1 \ No newline at end of file diff --git a/scripts/managers/candy_survival_manager.gd b/scripts/managers/candy_survival_manager.gd index 49006d2..5da8886 100644 --- a/scripts/managers/candy_survival_manager.gd +++ b/scripts/managers/candy_survival_manager.gd @@ -52,6 +52,7 @@ var hud_rush_bar: ProgressBar var hud_rush_label: Label var hud_stack_badge: Label var hud_points_label: Label +var hud_delivery_indicator: Label var _candy_survival_hud_scene: PackedScene = preload("res://scenes/candy_survival_hud.tscn") func _ready(): @@ -70,6 +71,7 @@ func _setup_hud() -> void: hud_ghost_label = bot_box.get_node_or_null("SabotagePanel/GhostChargesLabel") hud_stack_badge = bot_box.get_node_or_null("ScorePanel/CandyStackBadge") hud_points_label = bot_box.get_node_or_null("ScorePanel/PointsLabel") + hud_delivery_indicator = bot_box.get_node_or_null("ScorePanel/DeliveryIndicator") var top_box = hud_layer.get_node_or_null("TopContainer") if top_box: @@ -175,6 +177,10 @@ func _process(delta: float) -> void: # Sync color to the Mekton NPC if mekton_node and mekton_node.has_method("set_face_color_rpc"): mekton_node.rpc("set_face_color_rpc", current_face) + + # Update delivery indicators for all players based on new face + for pid in player_candies: + _update_candy_badge(pid) # Sugar Rush timers @@ -222,24 +228,30 @@ func _process(delta: float) -> void: # ── Blueprint ── -func on_blueprint_completed(pid: int, primary_color: int, off_color: bool) -> void: +func on_blueprint_completed(pid: int, primary_tile_id: int, off_color: bool) -> void: var base_points = 1000 var points = base_points if not off_color else int(base_points * OFF_COLOR_PENALTY) _add_score(pid, points) player_blueprints[pid] = player_blueprints.get(pid, 0) + 1 - _give_candy(pid, primary_color) + + var candy_color = CandyColor.HEART + for key in TILE_IDS: + if TILE_IDS[key] == primary_tile_id: + candy_color = key + break + + _give_candy(pid, candy_color) -func can_finish_with_off_color(pid: int, primary_color: int) -> bool: - return not _grid_has_color_tiles(primary_color) +func can_finish_with_off_color(pid: int, primary_tile_id: int) -> bool: + return not _grid_has_color_tiles(primary_tile_id) -func _grid_has_color_tiles(color: int) -> bool: +func _grid_has_color_tiles(target_tile_id: int) -> bool: if not gridmap: return true - var target = TILE_IDS.get(color, 7) for x in range(1, ARENA_COLS - 1): for y in range(1, ARENA_ROWS - 1): var v = Vector3i(x, 1, y) - if gridmap.get_cell_item(v) == target: + if gridmap.get_cell_item(v) == target_tile_id: return true return false @@ -254,7 +266,8 @@ func _update_candy_badge(pid: int) -> void: var count = player_candies.get(pid, 0) var mult = 1.0 + count * MULTI_STEP var color = player_candy_color.get(pid, -1) - rpc("sync_candy_badge", pid, count, mult) + var face_match = (color != -1 and color == current_face) + rpc("sync_candy_badge", pid, count, mult, face_match) # Update the 3D meshes on the player's head across all clients var all_players = get_tree().get_nodes_in_group("Players") @@ -476,10 +489,20 @@ func get_score(pid: int) -> int: # ── RPCs (stubs — HUD client handles visuals) ── @rpc("authority", "call_remote", "unreliable") -func sync_candy_badge(pid: int, count: int, mult: float) -> void: +func sync_candy_badge(pid: int, count: int, mult: float, face_match: bool) -> void: if pid == multiplayer.get_unique_id(): if hud_stack_badge: hud_stack_badge.text = "Stack: %d (x%.1f)" % [count, mult] + if hud_delivery_indicator: + if count > 0: + if face_match: + hud_delivery_indicator.text = "READY TO DELIVER!" + hud_delivery_indicator.add_theme_color_override("font_color", Color(0.4, 1.0, 0.4)) + else: + hud_delivery_indicator.text = "Waiting for match..." + hud_delivery_indicator.add_theme_color_override("font_color", Color(1.0, 0.4, 0.4)) + else: + hud_delivery_indicator.text = "" @rpc("authority", "call_remote", "unreliable") func sync_knock_result(attacker: int, target: int, candies: int) -> void: diff --git a/scripts/managers/goal_manager.gd b/scripts/managers/goal_manager.gd index 0d97029..ab16623 100644 --- a/scripts/managers/goal_manager.gd +++ b/scripts/managers/goal_manager.gd @@ -13,11 +13,18 @@ func initialize_random_goals(size: int, min_value: int, max_value: int, null_cou var rng = RandomNumberGenerator.new() rng.randomize() + const SPECIAL_VALUES = {1: 7, 2: 8, 3: 9, 4: 10} + + if LobbyManager.game_mode == "Candy Survival": + var val = rng.randi_range(min_value, max_value) + var chosen_tile = val if not val in SPECIAL_VALUES else SPECIAL_VALUES[val] + for i in range(size): + goals.append(chosen_tile) + return goals + var null_val = 0 var max_nulls = 3 - const SPECIAL_VALUES = {1: 7, 2: 8, 3: 9, 4: 10} - for i in range(size): if null_val < max_nulls and rng.randf() < null_count: goals.append(-1) diff --git a/scripts/managers/playerboard_manager.gd b/scripts/managers/playerboard_manager.gd index 27fa228..bde7d53 100644 --- a/scripts/managers/playerboard_manager.gd +++ b/scripts/managers/playerboard_manager.gd @@ -733,11 +733,56 @@ func _check_goal_completion(): if not player.race_manager: return - # Check if the pattern matches - if player.race_manager.check_pattern_match(): + var is_match = false + var is_off_color = false + var primary_color = -1 + + if LobbyManager.game_mode == "Candy Survival": + # Custom Candy Survival blueprint check (can be off-color) + var main = player.get_tree().get_root().get_node_or_null("Main") + var gm = main.get_node_or_null("CandySurvivalManager") if main else null + + # Find any 3x3 block that is completely filled with tiles (no -1) + for start_row in range(3): + for start_col in range(3): + var filled = true + var dominant_colors = {} + + for i in range(3): + for j in range(3): + var val = player.playerboard[(start_row + i) * 5 + (start_col + j)] + if val == -1: + filled = false + else: + dominant_colors[val] = dominant_colors.get(val, 0) + 1 + + if filled: + is_match = true + # Find majority color + var max_count = 0 + for c in dominant_colors: + if dominant_colors[c] > max_count: + max_count = dominant_colors[c] + primary_color = c + + is_off_color = (max_count < 9) + if is_off_color and gm and gm.has_method("can_finish_with_off_color"): + if not gm.can_finish_with_off_color(player.name.to_int(), primary_color): + is_match = false # Reject if primary color is still available on grid + + if is_match: + break + if is_match: + break + + if is_match and gm and gm.has_method("on_blueprint_completed"): + gm.on_blueprint_completed(player.name.to_int(), primary_color, is_off_color) + else: + is_match = player.race_manager.check_pattern_match() + + if is_match: print("[PlayerboardManager] Goal completed for player %s!" % player.name) - # Level up boost difficulty on goal completion var powerup_manager = player.get_node_or_null("PowerUpManager") if powerup_manager: powerup_manager.add_goal_completion_reward()