diff --git a/scenes/main.tscn b/scenes/main.tscn index 0977cc2..2456870 100644 --- a/scenes/main.tscn +++ b/scenes/main.tscn @@ -1065,6 +1065,32 @@ theme_override_fonts/font = ExtResource("13_j8jky") theme_override_font_sizes/font_size = 32 text = "X0" +[node name="StopTimer" type="PanelContainer" parent="." unique_id=991540081] +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -58.0 +offset_top = 80.0 +offset_right = 58.0 +offset_bottom = 113.00012 +grow_horizontal = 2 + +[node name="HBox" type="HBoxContainer" parent="StopTimer" unique_id=1541315617] +layout_mode = 2 +theme_override_constants/separation = 4 + +[node name="Segment0" type="Panel" parent="StopTimer/HBox" unique_id=307582302] +custom_minimum_size = Vector2(36, 20) +layout_mode = 2 + +[node name="Segment1" type="Panel" parent="StopTimer/HBox" unique_id=615805583] +custom_minimum_size = Vector2(36, 20) +layout_mode = 2 + +[node name="Segment2" type="Panel" parent="StopTimer/HBox" unique_id=1041800993] +custom_minimum_size = Vector2(36, 20) +layout_mode = 2 + [node name="PowerUpBar" type="PanelContainer" parent="." unique_id=1775378146] anchors_preset = 4 anchor_top = 0.5 diff --git a/scripts/managers/stop_n_go_manager.gd b/scripts/managers/stop_n_go_manager.gd index 934a204..8d1c476 100644 --- a/scripts/managers/stop_n_go_manager.gd +++ b/scripts/managers/stop_n_go_manager.gd @@ -11,6 +11,7 @@ enum Phase {GO, STOP} const GO_DURATION: float = 12.0 const STOP_DURATION: float = 6.0 +const REQUIRED_GOALS: int = 2 var current_phase: Phase = Phase.GO var phase_timer: float = GO_DURATION @@ -30,6 +31,13 @@ var phase_label: Label var mission_label: Label var red_tint_overlay: ColorRect +# Traffic Light / StopTimer Visuals +var stop_timer_node: PanelContainer +var stop_segments: Array[Panel] = [] +var lit_style: StyleBoxFlat +var dim_style: StyleBoxFlat +var red_style: StyleBoxFlat + func _ready(): set_process(false) _setup_hud() @@ -83,8 +91,10 @@ func _process(delta): if not is_active: return + # Decrement timer locally for all peers (smoother HUD than waiting for RPC) + phase_timer -= delta + if multiplayer.is_server(): - phase_timer -= delta if phase_timer <= 0: if current_phase == Phase.GO: _start_phase(Phase.STOP) @@ -112,13 +122,68 @@ func _update_hud_visuals(): # 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 + mission_label.text = "GOALS (%d/%d)" % [completed_count, REQUIRED_GOALS] - if completed_count >= 3: + if completed_count >= REQUIRED_GOALS: 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) + + # Update StopTimer (Traffic Light) + _update_stop_timer_visuals() + +func _update_stop_timer_visuals(): + if not stop_timer_node: + # Try to find it once + var main = get_node_or_null("/root/Main") + if main: + stop_timer_node = main.get_node_or_null("StopTimer") + if stop_timer_node: + var hbox = stop_timer_node.get_node_or_null("HBox") + if hbox: + stop_segments.clear() + for i in range(4): + var seg = hbox.get_node_or_null("Segment%d" % i) + if seg: stop_segments.append(seg) + + # Prepare styles + lit_style = StyleBoxFlat.new() + lit_style.bg_color = Color.YELLOW + lit_style.border_width_left = 2 + lit_style.border_width_top = 2 + lit_style.border_width_right = 2 + lit_style.border_width_bottom = 2 + lit_style.border_color = Color(1.0, 1.0, 1.0, 0.5) + + dim_style = StyleBoxFlat.new() + dim_style.bg_color = Color(0.1, 0.1, 0.1, 0.8) # Dark dim + + red_style = StyleBoxFlat.new() + red_style.bg_color = Color.RED + red_style.border_width_left = 2 + red_style.border_width_top = 2 + red_style.border_width_right = 2 + red_style.border_width_bottom = 2 + red_style.border_color = Color(1.0, 0.5, 0.5, 0.5) + + if not stop_timer_node: return + + # ALWAYS VISIBLE in Stop n Go mode + stop_timer_node.visible = true + + if current_phase == Phase.GO: + # GO Phase: All dim unless in last 4 seconds + for i in range(stop_segments.size()): + var threshold = 4.0 - i + if phase_timer <= threshold: + stop_segments[i].add_theme_stylebox_override("panel", lit_style) + else: + stop_segments[i].add_theme_stylebox_override("panel", dim_style) + else: + # STOP Phase: All Red + for seg in stop_segments: + seg.add_theme_stylebox_override("panel", red_style) func activate_client_side(): is_active = true @@ -355,7 +420,7 @@ func check_win_condition(player_id: int, position: Vector2i) -> bool: if position.x < finish_line_x: return false - # 2. Must have 3 Goal Completions (tracked by GoalsCycleManager) + # 2. Must have enough Goal Completions (tracked by GoalsCycleManager) var main = get_node_or_null("/root/Main") if not main: return false @@ -364,14 +429,14 @@ func check_win_condition(player_id: int, position: Vector2i) -> bool: var completed_count = goals_cycle_manager.player_goal_counts.get(player_id, 0) - if completed_count >= 3: + if completed_count >= REQUIRED_GOALS: 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) + NotificationManager.send_message(player_node, "Incomplete! Achieve %d goals (x%d) to win!" % [REQUIRED_GOALS, REQUIRED_GOALS], NotificationManager.MessageType.WARNING) - print("[StopNGo] Player %d reached finish but goal count too low: %d/3" % [player_id, completed_count]) + print("[StopNGo] Player %d reached finish but goal count too low: %d/%d" % [player_id, completed_count, REQUIRED_GOALS]) return false