implement delivery ready indicator logic + off-color detection
This commit is contained in:
@@ -103,3 +103,13 @@ theme_override_constants/outline_size = 5
|
|||||||
theme_override_fonts/font = ExtResource("1_font")
|
theme_override_fonts/font = ExtResource("1_font")
|
||||||
text = "Score: 0"
|
text = "Score: 0"
|
||||||
horizontal_alignment = 1
|
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
|
||||||
@@ -52,6 +52,7 @@ var hud_rush_bar: ProgressBar
|
|||||||
var hud_rush_label: Label
|
var hud_rush_label: Label
|
||||||
var hud_stack_badge: Label
|
var hud_stack_badge: Label
|
||||||
var hud_points_label: Label
|
var hud_points_label: Label
|
||||||
|
var hud_delivery_indicator: Label
|
||||||
var _candy_survival_hud_scene: PackedScene = preload("res://scenes/candy_survival_hud.tscn")
|
var _candy_survival_hud_scene: PackedScene = preload("res://scenes/candy_survival_hud.tscn")
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
@@ -70,6 +71,7 @@ func _setup_hud() -> void:
|
|||||||
hud_ghost_label = bot_box.get_node_or_null("SabotagePanel/GhostChargesLabel")
|
hud_ghost_label = bot_box.get_node_or_null("SabotagePanel/GhostChargesLabel")
|
||||||
hud_stack_badge = bot_box.get_node_or_null("ScorePanel/CandyStackBadge")
|
hud_stack_badge = bot_box.get_node_or_null("ScorePanel/CandyStackBadge")
|
||||||
hud_points_label = bot_box.get_node_or_null("ScorePanel/PointsLabel")
|
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")
|
var top_box = hud_layer.get_node_or_null("TopContainer")
|
||||||
if top_box:
|
if top_box:
|
||||||
@@ -176,6 +178,10 @@ func _process(delta: float) -> void:
|
|||||||
if mekton_node and mekton_node.has_method("set_face_color_rpc"):
|
if mekton_node and mekton_node.has_method("set_face_color_rpc"):
|
||||||
mekton_node.rpc("set_face_color_rpc", current_face)
|
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
|
# Sugar Rush timers
|
||||||
var any_rush = false
|
var any_rush = false
|
||||||
@@ -222,24 +228,30 @@ func _process(delta: float) -> void:
|
|||||||
|
|
||||||
# ── Blueprint ──
|
# ── 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 base_points = 1000
|
||||||
var points = base_points if not off_color else int(base_points * OFF_COLOR_PENALTY)
|
var points = base_points if not off_color else int(base_points * OFF_COLOR_PENALTY)
|
||||||
_add_score(pid, points)
|
_add_score(pid, points)
|
||||||
player_blueprints[pid] = player_blueprints.get(pid, 0) + 1
|
player_blueprints[pid] = player_blueprints.get(pid, 0) + 1
|
||||||
_give_candy(pid, primary_color)
|
|
||||||
|
|
||||||
func can_finish_with_off_color(pid: int, primary_color: int) -> bool:
|
var candy_color = CandyColor.HEART
|
||||||
return not _grid_has_color_tiles(primary_color)
|
for key in TILE_IDS:
|
||||||
|
if TILE_IDS[key] == primary_tile_id:
|
||||||
|
candy_color = key
|
||||||
|
break
|
||||||
|
|
||||||
func _grid_has_color_tiles(color: int) -> bool:
|
_give_candy(pid, candy_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(target_tile_id: int) -> bool:
|
||||||
if not gridmap:
|
if not gridmap:
|
||||||
return true
|
return true
|
||||||
var target = TILE_IDS.get(color, 7)
|
|
||||||
for x in range(1, ARENA_COLS - 1):
|
for x in range(1, ARENA_COLS - 1):
|
||||||
for y in range(1, ARENA_ROWS - 1):
|
for y in range(1, ARENA_ROWS - 1):
|
||||||
var v = Vector3i(x, 1, y)
|
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 true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -254,7 +266,8 @@ func _update_candy_badge(pid: int) -> void:
|
|||||||
var count = player_candies.get(pid, 0)
|
var count = player_candies.get(pid, 0)
|
||||||
var mult = 1.0 + count * MULTI_STEP
|
var mult = 1.0 + count * MULTI_STEP
|
||||||
var color = player_candy_color.get(pid, -1)
|
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
|
# Update the 3D meshes on the player's head across all clients
|
||||||
var all_players = get_tree().get_nodes_in_group("Players")
|
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) ──
|
# ── RPCs (stubs — HUD client handles visuals) ──
|
||||||
|
|
||||||
@rpc("authority", "call_remote", "unreliable")
|
@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 pid == multiplayer.get_unique_id():
|
||||||
if hud_stack_badge:
|
if hud_stack_badge:
|
||||||
hud_stack_badge.text = "Stack: %d (x%.1f)" % [count, mult]
|
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")
|
@rpc("authority", "call_remote", "unreliable")
|
||||||
func sync_knock_result(attacker: int, target: int, candies: int) -> void:
|
func sync_knock_result(attacker: int, target: int, candies: int) -> void:
|
||||||
|
|||||||
@@ -13,11 +13,18 @@ func initialize_random_goals(size: int, min_value: int, max_value: int, null_cou
|
|||||||
var rng = RandomNumberGenerator.new()
|
var rng = RandomNumberGenerator.new()
|
||||||
rng.randomize()
|
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 null_val = 0
|
||||||
var max_nulls = 3
|
var max_nulls = 3
|
||||||
|
|
||||||
const SPECIAL_VALUES = {1: 7, 2: 8, 3: 9, 4: 10}
|
|
||||||
|
|
||||||
for i in range(size):
|
for i in range(size):
|
||||||
if null_val < max_nulls and rng.randf() < null_count:
|
if null_val < max_nulls and rng.randf() < null_count:
|
||||||
goals.append(-1)
|
goals.append(-1)
|
||||||
|
|||||||
@@ -733,11 +733,56 @@ func _check_goal_completion():
|
|||||||
if not player.race_manager:
|
if not player.race_manager:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if the pattern matches
|
var is_match = false
|
||||||
if player.race_manager.check_pattern_match():
|
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)
|
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")
|
var powerup_manager = player.get_node_or_null("PowerUpManager")
|
||||||
if powerup_manager:
|
if powerup_manager:
|
||||||
powerup_manager.add_goal_completion_reward()
|
powerup_manager.add_goal_completion_reward()
|
||||||
|
|||||||
Reference in New Issue
Block a user