From 905b863f53920065d5f9228230b879a7d68d7f98 Mon Sep 17 00:00:00 2001 From: Michele Rossi Date: Sun, 3 May 2026 16:09:21 +0200 Subject: [PATCH] Add current goal panel, cleanup prestige panel --- core/goals/current_goal_panel.gd | 153 ++++++++++++++++++ core/goals/current_goal_panel.gd.uid | 1 + core/goals/current_goal_panel.tscn | 26 +++ core/prestige/prestige_panel.gd | 38 ++--- .../tiny_sword/buildings/castle/castle.tscn | 36 ++++- docs/gyms/tiny_sword/tiny_sword.tscn | 3 - 6 files changed, 224 insertions(+), 33 deletions(-) create mode 100644 core/goals/current_goal_panel.gd create mode 100644 core/goals/current_goal_panel.gd.uid create mode 100644 core/goals/current_goal_panel.tscn diff --git a/core/goals/current_goal_panel.gd b/core/goals/current_goal_panel.gd new file mode 100644 index 0000000..4d6080f --- /dev/null +++ b/core/goals/current_goal_panel.gd @@ -0,0 +1,153 @@ +## Single-goal tile showing the current (first uncompleted) goal from GoalCatalogue. +## Mirrors a single row from goals_debug_ui: goal name, requirements text, and a resolve button. +extends PanelContainer + +@onready var _game_state: LevelGameState = find_parent("LevelGameState") +@onready var _goal_label: Label = $VBoxContainer/GoalLabel +@onready var _requirements_label: Label = $VBoxContainer/RequirementsLabel +@onready var _resolve_button: Button = $VBoxContainer/ResolveButton + +var _current_goal: GoalData + + +func _ready() -> void: + _resolve_button.pressed.connect(_on_resolve_pressed) + if _game_state: + _game_state.currency_changed.connect(_on_currency_changed) + _game_state.generator_state_changed.connect(_on_generator_state_changed) + _game_state.goal_completed.connect(_on_goal_completed) + if not _game_state.goal_catalogue or _game_state.goal_catalogue.goals.is_empty(): + _game_state.ready.connect(_on_level_state_ready) + + _refresh_current_goal() + _refresh_ui() + _refresh_ui.call_deferred() + + +func _get_current_goal() -> GoalData: + if _game_state == null: + return null + var catalogue: GoalCatalogue = _game_state.goal_catalogue + if catalogue == null: + return null + + for goal in catalogue.goals: + if goal == null: + continue + if not goal.has_id(): + continue + if _game_state.is_goal_completed(goal.id): + continue + return goal + + return null + + +func _refresh_current_goal() -> void: + _current_goal = _get_current_goal() + + +func _refresh_ui() -> void: + if _current_goal == null: + _goal_label.text = "All goals complete!" + _requirements_label.text = "" + _resolve_button.disabled = true + _resolve_button.text = "Done" + return + + _goal_label.text = String(_current_goal.id) + + if _game_state == null: + return + + var already_completed: bool = _game_state.is_goal_completed(_current_goal.id) + + _requirements_label.text = _get_requirements_text(_current_goal) + + var met: bool = _game_state.is_goal_met(_current_goal) + var can_click: bool = met and not already_completed + + _resolve_button.disabled = not can_click + _resolve_button.text = "Done" if already_completed else "Resolve" + + +func _get_requirements_text(goal: GoalData) -> String: + if goal == null or _game_state == null: + return "" + + var parts: Array[String] = [] + for req in goal.get_requirements(): + if req == null: + continue + + var currency: Currency = req.get_currency() + if currency == null: + continue + + var currency_id: StringName = _game_state.get_currency_id(currency) + var total_amount: BigNumber = _game_state.get_total_currency_acquired_by_id(currency_id) + var required_amount: BigNumber = req.get_amount() + var currency_name: String = _game_state.get_currency_name(currency_id) + + parts.append( + "%s %s / %s" % [ + currency_name, + total_amount.to_string_suffix(2), + required_amount.to_string_suffix(2), + ] + ) + + if parts.is_empty(): + return "No requirements" + return " | ".join(parts) + + +func _on_resolve_pressed() -> void: + if _current_goal == null: + return + if _game_state == null: + return + if _game_state.is_goal_completed(_current_goal.id): + return + if not _game_state.is_goal_met(_current_goal): + return + + if _current_goal.unlock_behavior == GoalData.UnlockBehavior.MANUAL: + _game_state._complete_goal_manually(_current_goal.id) + + _refresh_current_goal() + _refresh_ui() + + +func _on_currency_changed(_currency_id: StringName, _new_amount: BigNumber) -> void: + _refresh_current_goal() + _refresh_ui() + + +func _on_generator_state_changed(_generator_id: StringName, _state: Dictionary) -> void: + _refresh_current_goal() + _refresh_ui() + + +func _on_goal_completed(_goal_id: StringName) -> void: + _refresh_current_goal() + _refresh_ui() + + +func _on_level_state_ready() -> void: + if _game_state: + _game_state.ready.disconnect(_on_level_state_ready) + _refresh_current_goal() + _refresh_ui() + + +func _exit_tree() -> void: + if _game_state: + if _game_state.currency_changed.is_connected(_on_currency_changed): + _game_state.currency_changed.disconnect(_on_currency_changed) + if _game_state.generator_state_changed.is_connected(_on_generator_state_changed): + _game_state.generator_state_changed.disconnect(_on_generator_state_changed) + if _game_state.goal_completed.is_connected(_on_goal_completed): + _game_state.goal_completed.disconnect(_on_goal_completed) + if _game_state.ready.is_connected(_on_level_state_ready): + _game_state.ready.disconnect(_on_level_state_ready) diff --git a/core/goals/current_goal_panel.gd.uid b/core/goals/current_goal_panel.gd.uid new file mode 100644 index 0000000..5bbbdc8 --- /dev/null +++ b/core/goals/current_goal_panel.gd.uid @@ -0,0 +1 @@ +uid://dfn06haxb2yhr diff --git a/core/goals/current_goal_panel.tscn b/core/goals/current_goal_panel.tscn new file mode 100644 index 0000000..b51ea35 --- /dev/null +++ b/core/goals/current_goal_panel.tscn @@ -0,0 +1,26 @@ +[gd_scene format=3 uid="uid://dudfvxilbydas"] + +[ext_resource type="Script" uid="uid://dfn06haxb2yhr" path="res://core/goals/current_goal_panel.gd" id="1_70l2h"] + +[node name="CurrentGoalPanel" type="PanelContainer" unique_id=1791509101] +offset_left = 155.0 +offset_top = 210.0 +offset_right = 500.0 +offset_bottom = 320.0 +script = ExtResource("1_70l2h") + +[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=933762288] +layout_mode = 2 +theme_override_constants/separation = 4 + +[node name="GoalLabel" type="Label" parent="VBoxContainer" unique_id=1859068341] +layout_mode = 2 +text = "Goal" + +[node name="RequirementsLabel" type="Label" parent="VBoxContainer" unique_id=2092922827] +layout_mode = 2 +text = "Requirements" + +[node name="ResolveButton" type="Button" parent="VBoxContainer" unique_id=760904344] +layout_mode = 2 +text = "Resolve" diff --git a/core/prestige/prestige_panel.gd b/core/prestige/prestige_panel.gd index 12d2b9f..b098ea6 100644 --- a/core/prestige/prestige_panel.gd +++ b/core/prestige/prestige_panel.gd @@ -15,26 +15,20 @@ var _is_waiting_for_confirm: bool = false func _ready() -> void: var manager: Node = _get_prestige_manager() - if manager != null and manager.has_signal("prestige_state_changed"): - manager.prestige_state_changed.connect(_on_prestige_state_changed) - if manager != null and manager.has_signal("prestige_performed"): - manager.prestige_performed.connect(_on_prestige_performed) - if game_state and not game_state.currency_changed.is_connected(_on_currency_changed): - game_state.currency_changed.connect(_on_currency_changed) - + manager.prestige_state_changed.connect(_on_prestige_state_changed) + manager.prestige_performed.connect(_on_prestige_performed) + game_state.currency_changed.connect(_on_currency_changed) _refresh_ui() func _on_reset_button_pressed() -> void: - var manager: Node = _get_prestige_manager() - if manager == null or not manager.has_method("can_prestige"): + var manager: PrestigeManager = _get_prestige_manager() + + if not bool(manager.can_prestige()): return - if not bool(manager.call("can_prestige")): - return - - var pending: BigNumber = manager.call("calculate_pending_gain") - var basis_label: String = String(manager.call("get_basis_label")) - var basis_value: BigNumber = manager.call("get_basis_value_for_display") + var pending: BigNumber = manager.calculate_pending_gain() + var basis_label: String = String(manager.get_basis_label()) + var basis_value: BigNumber = manager.get_basis_value_for_display() var confirm_message: String = "Reset this run for +%s prestige?\n\nThis resets currencies, owned generators, and buff levels. Lifetime totals and prestige are kept." % pending.to_string_suffix(2) confirm_message = "%s\n\nBased on %s: %s" % [confirm_message, basis_label, basis_value.to_string_suffix(2)] @@ -70,23 +64,23 @@ func _on_confirm_dialog_canceled() -> void: _is_waiting_for_confirm = false func _refresh_ui() -> void: - var manager: Node = _get_prestige_manager() + var manager: PrestigeManager = _get_prestige_manager() if manager == null: visible = false return visible = true - var total: BigNumber = manager.call("get_total_prestige") - var pending: BigNumber = manager.call("calculate_pending_gain") - var multiplier: float = float(manager.call("get_total_multiplier")) - var basis_text: String = String(manager.call("get_basis_label")) - var basis_value: BigNumber = manager.call("get_basis_value_for_display") + var total: BigNumber = manager.get_total_prestige() + var pending: BigNumber = manager.calculate_pending_gain() + var multiplier: float = float(manager.get_total_multiplier()) + var basis_text: String = String(manager.get_basis_label()) + var basis_value: BigNumber = manager.get_basis_value_for_display() _total_value.text = total.to_string_suffix(2) _pending_value.text = pending.to_string_suffix(2) _multiplier_value.text = "x%.2f" % multiplier _basis_label.text = "%s (%s)" % [basis_text, basis_value.to_string_suffix(2)] - _reset_button.disabled = not bool(manager.call("can_prestige")) + _reset_button.disabled = not bool(manager.can_prestige()) func _get_prestige_manager() -> PrestigeManager: return game_state.prestige_manager diff --git a/docs/gyms/tiny_sword/buildings/castle/castle.tscn b/docs/gyms/tiny_sword/buildings/castle/castle.tscn index 06bfb7a..be9a85c 100644 --- a/docs/gyms/tiny_sword/buildings/castle/castle.tscn +++ b/docs/gyms/tiny_sword/buildings/castle/castle.tscn @@ -4,6 +4,7 @@ [ext_resource type="Texture2D" uid="uid://cry4arn00kgrt" path="res://docs/gyms/tiny_sword/buildings/castle/Castle.png" id="1_tgvch"] [ext_resource type="PackedScene" uid="uid://dlidx2x0otpjg" path="res://core/prestige/prestige_panel.tscn" id="3_l7gct"] [ext_resource type="Script" uid="uid://cpfmctd4xsfho" path="res://docs/gyms/tiny_sword/buildings/castle/test_buff.gd" id="4_l7gct"] +[ext_resource type="PackedScene" uid="uid://dudfvxilbydas" path="res://core/goals/current_goal_panel.tscn" id="4_r36om"] [ext_resource type="Resource" uid="uid://bjc6qmvr7pe12" path="res://docs/gyms/tiny_sword/buffs/spawn_worker_buff.tres" id="5_s3a5k"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_tgvch"] @@ -27,24 +28,43 @@ offset_top = -80.0 offset_right = 575.0 offset_bottom = 126.0 -[node name="TestBuff" type="PanelContainer" parent="." unique_id=2112401476] -offset_left = 155.0 -offset_top = 157.0 -offset_right = 263.0 -offset_bottom = 197.0 +[node name="PanelContainer" type="PanelContainer" parent="." unique_id=549346899] +offset_right = 415.0 +offset_bottom = 196.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="MarginContainer" type="MarginContainer" parent="PanelContainer" unique_id=321038386] +layout_mode = 2 +theme_override_constants/margin_left = 20 +theme_override_constants/margin_top = 20 +theme_override_constants/margin_right = 20 +theme_override_constants/margin_bottom = 20 + +[node name="VBoxContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer" unique_id=450633732] +layout_mode = 2 +size_flags_vertical = 0 +theme_override_constants/separation = 4 +alignment = 1 + +[node name="TestBuff" type="PanelContainer" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=1906280979] +layout_mode = 2 script = ExtResource("4_l7gct") buff_data = ExtResource("5_s3a5k") -[node name="HBoxContainer" type="HBoxContainer" parent="TestBuff" unique_id=1293262110] +[node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/VBoxContainer/TestBuff" unique_id=1293262110] layout_mode = 2 -[node name="Label" type="Label" parent="TestBuff/HBoxContainer" unique_id=1519392687] +[node name="Label" type="Label" parent="PanelContainer/MarginContainer/VBoxContainer/TestBuff/HBoxContainer" unique_id=1519392687] layout_mode = 2 text = "Label" -[node name="Button" type="Button" parent="TestBuff/HBoxContainer" unique_id=1254643833] +[node name="Button" type="Button" parent="PanelContainer/MarginContainer/VBoxContainer/TestBuff/HBoxContainer" unique_id=1254643833] layout_mode = 2 text = "Button" +[node name="CurrentGoalPanel" parent="PanelContainer/MarginContainer/VBoxContainer" unique_id=1627561697 instance=ExtResource("4_r36om")] +layout_mode = 2 + [connection signal="mouse_entered" from="Area2D" to="." method="_on_area_2d_mouse_entered"] [connection signal="mouse_exited" from="Area2D" to="." method="_on_area_2d_mouse_exited"] diff --git a/docs/gyms/tiny_sword/tiny_sword.tscn b/docs/gyms/tiny_sword/tiny_sword.tscn index 2106f61..ce36306 100644 --- a/docs/gyms/tiny_sword/tiny_sword.tscn +++ b/docs/gyms/tiny_sword/tiny_sword.tscn @@ -96,6 +96,3 @@ script = ExtResource("17_x77df") clamp_enabled = true clamp_min = Vector2(-1920, -1080) clamp_max = Vector2(1920, 1080) -zoom_sensitivity = null -zoom_min = null -zoom_max = null