From eba0d09d7055881bba45ca14d3653e4bb75421da Mon Sep 17 00:00:00 2001 From: VinPropane Date: Sun, 7 Jun 2026 13:37:25 -0400 Subject: [PATCH] NEO-122: Extract quest HUD controller to satisfy gdlint limits. Move quest progress/accept wiring out of main.gd so pre-push gdlint passes max line length and max file lines checks. --- client/scripts/main.gd | 289 +++------------------ client/scripts/quest_hud_controller.gd | 262 +++++++++++++++++++ client/scripts/quest_hud_controller.gd.uid | 1 + client/test/quest_progress_client_test.gd | 3 +- 4 files changed, 297 insertions(+), 258 deletions(-) create mode 100644 client/scripts/quest_hud_controller.gd create mode 100644 client/scripts/quest_hud_controller.gd.uid diff --git a/client/scripts/main.gd b/client/scripts/main.gd index ae2ffd3..993c50f 100644 --- a/client/scripts/main.gd +++ b/client/scripts/main.gd @@ -17,8 +17,8 @@ extends Node3D ## Steep ramp: **2 m / 1.5 m** rise/run (~53°) so slope exceeds `Player` `floor_max_angle` (~50°) ## and is not walkable; gentle ramp stays shallower than `NavigationMesh.agent_max_climb`. Steep is ## under `World` only (not nav source geometry). -## Prototype HUD: world `CharacterBody3D` position in `UICanvas/HudRootScroll/HudRoot/PlayerPositionLabel` -## (updated in `_physics_process` so it matches physics ticks). +## Prototype HUD: player position in PlayerPositionLabel (HudRootScroll/HudRoot); +## updated in `_physics_process` to match physics ticks. const MOVE_REJECT_MSG_SECONDS: float = 4.0 @@ -56,7 +56,7 @@ const REFINE_SKILL_ID := "refine" const BREACH_GIG_ID := "breach" const PROTOTYPE_ENCOUNTER_ID := "prototype_combat_pocket" const PROTOTYPE_ENCOUNTER_REQUIRED_TARGETS := 3 -const PROTOTYPE_QUEST_GATHER_ID := "prototype_quest_gather_intro" +const QuestHudController := preload("res://scripts/quest_hud_controller.gd") ## Bump on each rejection so older one-shot timers do not clear a newer message. var _move_reject_msg_token: int = 0 @@ -109,9 +109,7 @@ var _last_gig_snapshot: Dictionary = {} var _gig_error: String = "" var _last_encounter_progress_snapshot: Dictionary = {} var _encounter_progress_error: String = "" -var _last_quest_progress_snapshot: Dictionary = {} -var _quest_progress_error: String = "" -var _quest_defs_error: String = "" +var _quest_hud: Node = null var _gather_pre_scrap_qty: int = 0 var _gather_pending_interactable_id: String = "" var _gather_awaiting_inventory_finalize: bool = false @@ -129,22 +127,22 @@ var _dev_pulse_bootstrap_attempted: bool = false @onready var _radius_preview: Node3D = $World/InteractionMarkers @onready var _move_reject_label: Label = $UICanvas/MoveRejectLabel @onready var _hud_root: VBoxContainer = $UICanvas/HudRootScroll/HudRoot -@onready var _player_pos_label: Label = $UICanvas/HudRootScroll/HudRoot/PlayerPositionLabel -@onready var _target_lock_label: Label = $UICanvas/HudRootScroll/HudRoot/TargetLockLabel -@onready var _cast_feedback_label: Label = $UICanvas/HudRootScroll/HudRoot/CastFeedbackLabel -@onready var _combat_target_hp_label: Label = $UICanvas/HudRootScroll/HudRoot/CombatTargetHpLabel -@onready var _player_combat_hp_label: Label = $UICanvas/HudRootScroll/HudRoot/PlayerCombatHpLabel -@onready var _encounter_progress_label: Label = $UICanvas/HudRootScroll/HudRoot/EncounterProgressLabel -@onready var _encounter_complete_label: Label = $UICanvas/HudRootScroll/HudRoot/EncounterCompleteLabel -@onready var _quest_progress_label: Label = $UICanvas/HudRootScroll/HudRoot/QuestProgressLabel -@onready var _quest_accept_feedback_label: Label = $UICanvas/HudRootScroll/HudRoot/QuestAcceptFeedbackLabel -@onready var _npc_state_label: Label = $UICanvas/HudRootScroll/HudRoot/NpcStateLabel -@onready var _telegraph_label: Label = $UICanvas/HudRootScroll/HudRoot/TelegraphLabel -@onready var _cooldown_slots_label: Label = $UICanvas/HudRootScroll/HudRoot/CooldownSlotsLabel +@onready var _player_pos_label: Label = _hud_root.get_node("PlayerPositionLabel") +@onready var _target_lock_label: Label = _hud_root.get_node("TargetLockLabel") +@onready var _cast_feedback_label: Label = _hud_root.get_node("CastFeedbackLabel") +@onready var _combat_target_hp_label: Label = _hud_root.get_node("CombatTargetHpLabel") +@onready var _player_combat_hp_label: Label = _hud_root.get_node("PlayerCombatHpLabel") +@onready var _encounter_progress_label: Label = _hud_root.get_node("EncounterProgressLabel") +@onready var _encounter_complete_label: Label = _hud_root.get_node("EncounterCompleteLabel") +@onready var _quest_progress_label: Label = _hud_root.get_node("QuestProgressLabel") +@onready var _quest_accept_feedback_label: Label = _hud_root.get_node("QuestAcceptFeedbackLabel") +@onready var _npc_state_label: Label = _hud_root.get_node("NpcStateLabel") +@onready var _telegraph_label: Label = _hud_root.get_node("TelegraphLabel") +@onready var _cooldown_slots_label: Label = _hud_root.get_node("CooldownSlotsLabel") @onready var _economy_hud_section: VBoxContainer = $UICanvas/EconomyHudSection @onready var _inventory_label: Label = _economy_hud_section.get_node("BodyScroll/Body/InventoryLabel") -@onready var _gather_feedback_label: Label = $UICanvas/HudRootScroll/HudRoot/GatherFeedbackLabel -@onready var _craft_feedback_label: Label = $UICanvas/HudRootScroll/HudRoot/CraftFeedbackLabel +@onready var _gather_feedback_label: Label = _hud_root.get_node("GatherFeedbackLabel") +@onready var _craft_feedback_label: Label = _hud_root.get_node("CraftFeedbackLabel") @onready var _skill_progression_label: Label = _economy_hud_section.get_node("BodyScroll/Body/SkillProgressionLabel") @onready var _gig_xp_label: Label = _economy_hud_section.get_node("BodyScroll/Body/GigXpLabel") @@ -855,250 +853,27 @@ func _request_encounter_progress_refresh() -> void: func _setup_quest_progress_sync() -> void: # NEO-122: quest progress + accept HUD; boot hydrate + refresh after gather/craft/defeat. - _apply_authority_http_config_to_client(_quest_progress_client) - _apply_authority_http_config_to_client(_quest_defs_client) - if _quest_progress_client.has_signal("quest_progress_received"): - _quest_progress_client.connect( - "quest_progress_received", Callable(self, "_on_quest_progress_received") - ) - if _quest_progress_client.has_signal("quest_sync_failed"): - _quest_progress_client.connect( - "quest_sync_failed", Callable(self, "_on_quest_progress_sync_failed") - ) - if _quest_progress_client.has_signal("quest_accept_result_received"): - _quest_progress_client.connect( - "quest_accept_result_received", Callable(self, "_on_quest_accept_result_received") - ) - if _quest_progress_client.has_signal("quest_accept_failed"): - _quest_progress_client.connect( - "quest_accept_failed", Callable(self, "_on_quest_accept_failed") - ) - if _quest_defs_client.has_signal("definitions_ready"): - _quest_defs_client.connect("definitions_ready", Callable(self, "_on_quest_definitions_ready")) - if _quest_defs_client.has_signal("definitions_sync_failed"): - _quest_defs_client.connect( - "definitions_sync_failed", Callable(self, "_on_quest_definitions_sync_failed") - ) - _render_quest_progress_label() - _render_quest_accept_feedback_label() - if _quest_defs_client.has_method("request_sync_from_server"): - _quest_defs_client.call("request_sync_from_server") - if _quest_progress_client.has_method("request_sync_from_server"): - _quest_progress_client.call("request_sync_from_server") - - -func _on_quest_progress_received(snapshot: Dictionary) -> void: - _quest_progress_error = "" - _last_quest_progress_snapshot = snapshot.duplicate(true) - _render_quest_progress_label() - - -func _on_quest_progress_sync_failed(reason: String) -> void: - _quest_progress_error = reason - _last_quest_progress_snapshot = {} - _render_quest_progress_label() - - -func _on_quest_accept_result_received(quest_id: String, result: Dictionary) -> void: - if bool(result.get("accepted", false)): - _render_quest_accept_feedback_label( - "Quest accept: %s accepted" % _quest_display_name(quest_id) - ) - else: - var rc := str(result.get("reasonCode", "")).strip_edges() - if rc.is_empty(): - _render_quest_accept_feedback_label("Quest accept: denied (no reasonCode)") - else: - _render_quest_accept_feedback_label("Quest accept: denied — %s" % rc) - _request_quest_progress_refresh() - - -func _on_quest_accept_failed(_quest_id: String, reason: String) -> void: - _render_quest_accept_feedback_label("Quest accept: failed — %s" % reason) - - -func _on_quest_definitions_ready(_quests: Array) -> void: - _quest_defs_error = "" - if _quest_progress_error.is_empty() and not _last_quest_progress_snapshot.is_empty(): - _render_quest_progress_label() - - -func _on_quest_definitions_sync_failed(reason: String) -> void: - _quest_defs_error = reason - _render_quest_progress_label() - - -func _render_quest_progress_label() -> void: - if not is_instance_valid(_quest_progress_label): - return - var header := "Quests:" - if not _quest_progress_error.is_empty(): - _quest_progress_label.text = "%s\nerror — %s" % [header, _quest_progress_error] - return - if _last_quest_progress_snapshot.is_empty(): - if not _quest_defs_error.is_empty(): - _quest_progress_label.text = ( - "%s\ndefinitions error — %s\nLoading…" % [header, _quest_defs_error] - ) - else: - _quest_progress_label.text = "%s\nLoading…" % header - return - var lines: PackedStringArray = [header] - if not _quest_defs_error.is_empty(): - lines.append("definitions error — %s" % _quest_defs_error) - var defs: Array = _quest_defs_snapshot() - if defs.is_empty(): - var quests: Variant = _last_quest_progress_snapshot.get("quests", null) - if quests is Array: - for row_variant in quests as Array: - if not row_variant is Dictionary: - continue - var row: Dictionary = row_variant - var qid: String = str(row.get("questId", "")) - lines.append(" %s" % _format_quest_status_line(qid, qid, row)) - else: - for def_variant in defs: - if not def_variant is Dictionary: - continue - var def: Dictionary = def_variant - var qid: String = str(def.get("id", "")) - if qid.is_empty(): - continue - var row: Dictionary = _quest_row(qid) - var label: String = _quest_display_name(qid) - lines.append(" %s" % _format_quest_status_line(qid, label, row)) - _quest_progress_label.text = "\n".join(lines) - - -func _format_quest_status_line(_quest_id: String, display_name: String, row: Dictionary) -> String: - var status: String = str(row.get("status", "not_started")) - match status: - "not_started": - return "%s: not started" % display_name - "active": - var step_index: int = int(row.get("currentStepIndex", 0)) - var counter_text: String = _format_objective_counters_summary( - row.get("objectiveCounters", {}) - ) - if counter_text.is_empty(): - return "%s: active step %d" % [display_name, step_index + 1] - return "%s: active step %d %s" % [display_name, step_index + 1, counter_text] - "completed": - var completed_at: String = str(row.get("completedAt", "")).strip_edges() - if completed_at.is_empty(): - return "%s: completed" % display_name - return "%s: completed (%s)" % [display_name, completed_at] - _: - return "%s: unknown status (%s)" % [display_name, status] - - -func _format_objective_counters_summary(counters: Variant) -> String: - if counters == null or not counters is Dictionary: - return "" - var d: Dictionary = counters - if d.is_empty(): - return "" - var parts: PackedStringArray = PackedStringArray() - for key in d.keys(): - parts.append("%s=%s" % [str(key), str(d[key])]) - return "(%s)" % ", ".join(parts) - - -func _render_quest_accept_feedback_label(text: String = "Quest accept: — (Q gather / Shift+Q next)") -> void: - if is_instance_valid(_quest_accept_feedback_label): - _quest_accept_feedback_label.text = text - - -func _quest_row(quest_id: String) -> Dictionary: - if not is_instance_valid(_quest_progress_client): - return {} - if not _quest_progress_client.has_method("quest_row"): - return {} - var row: Variant = _quest_progress_client.call( - "quest_row", quest_id, _last_quest_progress_snapshot + _quest_hud = QuestHudController.new() + add_child(_quest_hud) + _quest_hud.call( + "setup", + _quest_progress_client, + _quest_defs_client, + _quest_progress_label, + _quest_accept_feedback_label, + Callable(self, "_apply_authority_http_config_to_client") ) - return row as Dictionary - - -func _quest_display_name(quest_id: String) -> String: - if not is_instance_valid(_quest_defs_client): - return quest_id - if not _quest_defs_client.has_method("display_name_for"): - return quest_id - return str(_quest_defs_client.call("display_name_for", quest_id)) - - -func _quest_defs_snapshot() -> Array: - if not is_instance_valid(_quest_defs_client): - return [] - if not _quest_defs_client.has_method("quests_snapshot"): - return [] - return _quest_defs_client.call("quests_snapshot") as Array func _request_quest_progress_refresh() -> void: - if not is_instance_valid(_quest_progress_client): - return - if _quest_progress_client.has_method("request_sync_from_server"): - _quest_progress_client.call("request_sync_from_server") - - -func _find_first_eligible_quest_id() -> String: - var defs: Array = _quest_defs_snapshot() - for def_variant in defs: - if not def_variant is Dictionary: - continue - var def: Dictionary = def_variant - var qid: String = str(def.get("id", "")) - if qid.is_empty(): - continue - var row: Dictionary = _quest_row(qid) - if str(row.get("status", "")) != "not_started": - continue - var prereqs: Variant = def.get("prerequisiteQuestIds", []) - if not prereqs is Array: - continue - var prereqs_met := true - for p_variant in prereqs as Array: - var pid: String = str(p_variant) - if str(_quest_row(pid).get("status", "")) != "completed": - prereqs_met = false - break - if prereqs_met: - return qid - return "" - - -func _request_quest_accept(quest_id: String) -> void: - if not is_instance_valid(_quest_progress_client): - return - if _quest_progress_client.has_method("is_accept_busy") and bool(_quest_progress_client.call("is_accept_busy")): - return - if _quest_progress_client.has_method("request_accept"): - _quest_progress_client.call("request_accept", quest_id) - - -func _request_eligible_quest_accept() -> void: - var eligible_id: String = _find_first_eligible_quest_id() - if eligible_id.is_empty(): - _render_quest_accept_feedback_label("Quest accept: no eligible quest") - return - _request_quest_accept(eligible_id) + if is_instance_valid(_quest_hud): + _quest_hud.call("request_progress_refresh") func _try_quest_accept_key_input(event: InputEvent) -> bool: - if not event is InputEventKey: - return false - var k := event as InputEventKey - if not k.pressed or k.echo: - return false - if k.physical_keycode != KEY_Q and k.keycode != KEY_Q: - return false - if k.shift_pressed: - _request_eligible_quest_accept() - else: - _request_quest_accept(PROTOTYPE_QUEST_GATHER_ID) - return true + if is_instance_valid(_quest_hud): + return bool(_quest_hud.call("try_accept_key_input", event)) + return false func _render_gather_feedback_label(text: String = "Gather: —") -> void: diff --git a/client/scripts/quest_hud_controller.gd b/client/scripts/quest_hud_controller.gd new file mode 100644 index 0000000..81f6826 --- /dev/null +++ b/client/scripts/quest_hud_controller.gd @@ -0,0 +1,262 @@ +extends Node + +## NEO-122: quest progress + accept HUD wiring (extracted from main.gd). + +const GATHER_QUEST_ID := "prototype_quest_gather_intro" +const ACCEPT_IDLE_HINT := "Quest accept: — (Q gather / Shift+Q next)" + +var _progress_client: Node = null +var _defs_client: Node = null +var _progress_label: Label = null +var _accept_label: Label = null +var _last_snapshot: Dictionary = {} +var _progress_error: String = "" +var _defs_error: String = "" + + +func setup( + progress_client: Node, + defs_client: Node, + progress_label: Label, + accept_label: Label, + apply_http_config: Callable +) -> void: + _progress_client = progress_client + _defs_client = defs_client + _progress_label = progress_label + _accept_label = accept_label + if apply_http_config.is_valid(): + apply_http_config.call(progress_client) + apply_http_config.call(defs_client) + if _progress_client.has_signal("quest_progress_received"): + _progress_client.connect("quest_progress_received", Callable(self, "_on_progress_received")) + if _progress_client.has_signal("quest_sync_failed"): + _progress_client.connect("quest_sync_failed", Callable(self, "_on_sync_failed")) + if _progress_client.has_signal("quest_accept_result_received"): + _progress_client.connect( + "quest_accept_result_received", Callable(self, "_on_accept_result_received") + ) + if _progress_client.has_signal("quest_accept_failed"): + _progress_client.connect("quest_accept_failed", Callable(self, "_on_accept_failed")) + if _defs_client.has_signal("definitions_ready"): + _defs_client.connect("definitions_ready", Callable(self, "_on_definitions_ready")) + if _defs_client.has_signal("definitions_sync_failed"): + _defs_client.connect("definitions_sync_failed", Callable(self, "_on_definitions_sync_failed")) + _render_progress_label() + _render_accept_feedback_label() + if _defs_client.has_method("request_sync_from_server"): + _defs_client.call("request_sync_from_server") + request_progress_refresh() + + +func request_progress_refresh() -> void: + if not is_instance_valid(_progress_client): + return + if _progress_client.has_method("request_sync_from_server"): + _progress_client.call("request_sync_from_server") + + +func try_accept_key_input(event: InputEvent) -> bool: + if not event is InputEventKey: + return false + var k := event as InputEventKey + if not k.pressed or k.echo: + return false + if k.physical_keycode != KEY_Q and k.keycode != KEY_Q: + return false + if k.shift_pressed: + _request_eligible_accept() + else: + _request_accept(GATHER_QUEST_ID) + return true + + +func _on_progress_received(snapshot: Dictionary) -> void: + _progress_error = "" + _last_snapshot = snapshot.duplicate(true) + _render_progress_label() + + +func _on_sync_failed(reason: String) -> void: + _progress_error = reason + _last_snapshot = {} + _render_progress_label() + + +func _on_accept_result_received(quest_id: String, result: Dictionary) -> void: + if bool(result.get("accepted", false)): + _render_accept_feedback_label("Quest accept: %s accepted" % _display_name(quest_id)) + else: + var rc := str(result.get("reasonCode", "")).strip_edges() + if rc.is_empty(): + _render_accept_feedback_label("Quest accept: denied (no reasonCode)") + else: + _render_accept_feedback_label("Quest accept: denied — %s" % rc) + request_progress_refresh() + + +func _on_accept_failed(_quest_id: String, reason: String) -> void: + _render_accept_feedback_label("Quest accept: failed — %s" % reason) + + +func _on_definitions_ready(_quests: Array) -> void: + _defs_error = "" + if _progress_error.is_empty() and not _last_snapshot.is_empty(): + _render_progress_label() + + +func _on_definitions_sync_failed(reason: String) -> void: + _defs_error = reason + _render_progress_label() + + +func _render_progress_label() -> void: + if not is_instance_valid(_progress_label): + return + var header := "Quests:" + if not _progress_error.is_empty(): + _progress_label.text = "%s\nerror — %s" % [header, _progress_error] + return + if _last_snapshot.is_empty(): + if not _defs_error.is_empty(): + _progress_label.text = ( + "%s\ndefinitions error — %s\nLoading…" % [header, _defs_error] + ) + else: + _progress_label.text = "%s\nLoading…" % header + return + var lines: PackedStringArray = [header] + if not _defs_error.is_empty(): + lines.append("definitions error — %s" % _defs_error) + var defs: Array = _defs_snapshot() + if defs.is_empty(): + var quests: Variant = _last_snapshot.get("quests", null) + if quests is Array: + for row_variant in quests as Array: + if not row_variant is Dictionary: + continue + var row: Dictionary = row_variant + var qid: String = str(row.get("questId", "")) + lines.append(" %s" % _format_status_line(qid, qid, row)) + else: + for def_variant in defs: + if not def_variant is Dictionary: + continue + var def: Dictionary = def_variant + var qid: String = str(def.get("id", "")) + if qid.is_empty(): + continue + var row: Dictionary = _quest_row(qid) + var label: String = _display_name(qid) + lines.append(" %s" % _format_status_line(qid, label, row)) + _progress_label.text = "\n".join(lines) + + +func _format_status_line(_quest_id: String, display_name: String, row: Dictionary) -> String: + var status: String = str(row.get("status", "not_started")) + match status: + "not_started": + return "%s: not started" % display_name + "active": + var step_index: int = int(row.get("currentStepIndex", 0)) + var counter_text: String = _format_objective_counters_summary( + row.get("objectiveCounters", {}) + ) + if counter_text.is_empty(): + return "%s: active step %d" % [display_name, step_index + 1] + return "%s: active step %d %s" % [display_name, step_index + 1, counter_text] + "completed": + var completed_at: String = str(row.get("completedAt", "")).strip_edges() + if completed_at.is_empty(): + return "%s: completed" % display_name + return "%s: completed (%s)" % [display_name, completed_at] + _: + return "%s: unknown status (%s)" % [display_name, status] + + +func _format_objective_counters_summary(counters: Variant) -> String: + if counters == null or not counters is Dictionary: + return "" + var d: Dictionary = counters + if d.is_empty(): + return "" + var parts: PackedStringArray = PackedStringArray() + for key in d.keys(): + parts.append("%s=%s" % [str(key), str(d[key])]) + return "(%s)" % ", ".join(parts) + + +func _render_accept_feedback_label(text: String = ACCEPT_IDLE_HINT) -> void: + if is_instance_valid(_accept_label): + _accept_label.text = text + + +func _quest_row(quest_id: String) -> Dictionary: + if not is_instance_valid(_progress_client): + return {} + if not _progress_client.has_method("quest_row"): + return {} + var row: Variant = _progress_client.call("quest_row", quest_id, _last_snapshot) + return row as Dictionary + + +func _display_name(quest_id: String) -> String: + if not is_instance_valid(_defs_client): + return quest_id + if not _defs_client.has_method("display_name_for"): + return quest_id + return str(_defs_client.call("display_name_for", quest_id)) + + +func _defs_snapshot() -> Array: + if not is_instance_valid(_defs_client): + return [] + if not _defs_client.has_method("quests_snapshot"): + return [] + return _defs_client.call("quests_snapshot") as Array + + +func _find_first_eligible_quest_id() -> String: + var defs: Array = _defs_snapshot() + for def_variant in defs: + if not def_variant is Dictionary: + continue + var def: Dictionary = def_variant + var qid: String = str(def.get("id", "")) + if qid.is_empty(): + continue + var row: Dictionary = _quest_row(qid) + if str(row.get("status", "")) != "not_started": + continue + var prereqs: Variant = def.get("prerequisiteQuestIds", []) + if not prereqs is Array: + continue + var prereqs_met := true + for p_variant in prereqs as Array: + var pid: String = str(p_variant) + if str(_quest_row(pid).get("status", "")) != "completed": + prereqs_met = false + break + if prereqs_met: + return qid + return "" + + +func _request_accept(quest_id: String) -> void: + if not is_instance_valid(_progress_client): + return + var accept_busy := false + if _progress_client.has_method("is_accept_busy"): + accept_busy = bool(_progress_client.call("is_accept_busy")) + if accept_busy: + return + if _progress_client.has_method("request_accept"): + _progress_client.call("request_accept", quest_id) + + +func _request_eligible_accept() -> void: + var eligible_id: String = _find_first_eligible_quest_id() + if eligible_id.is_empty(): + _render_accept_feedback_label("Quest accept: no eligible quest") + return + _request_accept(eligible_id) diff --git a/client/scripts/quest_hud_controller.gd.uid b/client/scripts/quest_hud_controller.gd.uid new file mode 100644 index 0000000..008829b --- /dev/null +++ b/client/scripts/quest_hud_controller.gd.uid @@ -0,0 +1 @@ +uid://c8k3m2questhudctrl01 diff --git a/client/test/quest_progress_client_test.gd b/client/test/quest_progress_client_test.gd index b99caad..5438c66 100644 --- a/client/test/quest_progress_client_test.gd +++ b/client/test/quest_progress_client_test.gd @@ -239,7 +239,8 @@ func test_request_accept_emits_quest_accept_result_received() -> void: # Assert assert_that(started).is_true() assert_that(_accept_capture.get("questId", "")).is_equal(PROTOTYPE_QUEST_GATHER_ID) - assert_that(bool((_accept_capture.get("result", {}) as Dictionary).get("accepted", false))).is_true() + var accept_result: Dictionary = _accept_capture.get("result", {}) as Dictionary + assert_that(bool(accept_result.get("accepted", false))).is_true() assert_that(transport.last_url).contains("/accept") assert_that(transport.last_method).is_equal(HTTPClient.METHOD_POST)