Constrain CCS patient dialogue
This commit is contained in:
@@ -103,6 +103,7 @@ antialiased = true
|
||||
|
||||
[node name="DialogueBubble" type="Control" parent="."]
|
||||
z_index = 30
|
||||
clip_contents = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 0
|
||||
anchor_left = 0.53
|
||||
@@ -127,7 +128,7 @@ texture = ExtResource("6_chat_bubble")
|
||||
expand_mode = 1
|
||||
stretch_mode = 0
|
||||
|
||||
[node name="Text" type="Label" parent="DialogueBubble"]
|
||||
[node name="Text" type="RichTextLabel" parent="DialogueBubble"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
@@ -141,6 +142,8 @@ grow_vertical = 2
|
||||
theme_override_colors/font_color = Color(0.055, 0.105, 0.145, 1)
|
||||
theme_override_font_sizes/font_size = 20
|
||||
text = "Hello, doctor."
|
||||
fit_content = false
|
||||
scroll_active = false
|
||||
autowrap_mode = 2
|
||||
vertical_alignment = 1
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ const DIALOGUE_PAGE_MAX_CHARS := 82
|
||||
@onready var second_hand: Node2D = $ClockMount/SecondHand
|
||||
@onready var patient: TextureRect = $Patient
|
||||
@onready var dialogue_bubble: Control = $DialogueBubble
|
||||
@onready var dialogue_text: Label = $DialogueBubble/Text
|
||||
@onready var dialogue_text: RichTextLabel = $DialogueBubble/Text
|
||||
@onready var dialogue_continue_hint: Label = $DialogueBubble/ContinueHint
|
||||
@onready var choice_area: Control = $DialogueChoiceArea
|
||||
@onready var choice_container: HBoxContainer = $DialogueChoiceArea/DialogueChoices
|
||||
|
||||
@@ -4,6 +4,11 @@ const Brand := preload("res://scripts/ui/medmind_style.gd")
|
||||
const Style := preload("res://scripts/ui/ui_style.gd")
|
||||
const DOCTOR_SCENE := preload("res://scenes/ccs_cases_2/doctor_office.tscn")
|
||||
const DESIGN_SIZE := Vector2(1500.0, 800.0)
|
||||
const FOCUSED_INTERVIEW_CASE_ID := "ccs-gastro-duodenal-ulcer-office-001"
|
||||
const RETIRED_INTERVIEW_TOPIC_IDS := [
|
||||
"abdominal_symptoms", "bleeding_alarm_features", "medications",
|
||||
"medical_history", "social_history", "additional_review"
|
||||
]
|
||||
|
||||
var main
|
||||
var stage_root: Control
|
||||
@@ -16,6 +21,7 @@ var current_view := ""
|
||||
var cases_loaded := false
|
||||
var active_loaded := false
|
||||
var pending_action := ""
|
||||
var restart_case_external_id := ""
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -39,10 +45,13 @@ func _connect_service() -> void:
|
||||
CCSService.attempt_changed.connect(_on_attempt_changed)
|
||||
if not CCSService.request_failed.is_connected(_on_request_failed):
|
||||
CCSService.request_failed.connect(_on_request_failed)
|
||||
if not CCSService.attempt_abandoned.is_connected(_on_attempt_abandoned):
|
||||
CCSService.attempt_abandoned.connect(_on_attempt_abandoned)
|
||||
|
||||
|
||||
func on_show(_payload: Variant = null) -> void:
|
||||
CCSService.launch_origin = "ccs_cases_2"
|
||||
restart_case_external_id = ""
|
||||
cases_loaded = false
|
||||
active_loaded = false
|
||||
pending_action = "loading"
|
||||
@@ -52,6 +61,7 @@ func on_show(_payload: Variant = null) -> void:
|
||||
|
||||
|
||||
func on_hide() -> void:
|
||||
restart_case_external_id = ""
|
||||
_clear_active_scene()
|
||||
|
||||
|
||||
@@ -102,6 +112,9 @@ func _render_attempt(attempt: Dictionary) -> void:
|
||||
if node.is_empty():
|
||||
_show_unsupported_attempt("The graphical interview could not load its current dialogue.")
|
||||
return
|
||||
if _is_retired_interview_revision(attempt, node):
|
||||
_restart_with_current_interview(attempt)
|
||||
return
|
||||
if str(attempt.get("experienceMode", "management")) != "graphical_interview" \
|
||||
and bool(attempt.get("openingCompleted", false)) and not bool(node.get("isTerminal", false)):
|
||||
_show_unsupported_attempt("This case has progressed beyond the graphical interview.")
|
||||
@@ -263,6 +276,37 @@ func _repeat_interview() -> void:
|
||||
CCSService.create_attempt(case_external_id, "timed")
|
||||
|
||||
|
||||
func _is_retired_interview_revision(attempt: Dictionary, node: Dictionary) -> bool:
|
||||
if str(attempt.get("caseExternalId", "")) != FOCUSED_INTERVIEW_CASE_ID:
|
||||
return false
|
||||
if str(node.get("id", "")) in RETIRED_INTERVIEW_TOPIC_IDS:
|
||||
return true
|
||||
for raw_choice in node.get("choices", []):
|
||||
if str(raw_choice.get("id", "")) in RETIRED_INTERVIEW_TOPIC_IDS:
|
||||
return true
|
||||
var patient_text := str(node.get("patientText", "")).to_lower()
|
||||
return patient_text.contains("stomach bothers me") or patient_text.contains("gnawing ache")
|
||||
|
||||
|
||||
func _restart_with_current_interview(attempt: Dictionary) -> void:
|
||||
if pending_action == "refreshing_interview":
|
||||
return
|
||||
restart_case_external_id = str(attempt.get("caseExternalId", ""))
|
||||
pending_action = "refreshing_interview"
|
||||
_show_selection("Updating this interview to its latest dizziness and fatigue dialogue...")
|
||||
CCSService.abandon()
|
||||
|
||||
|
||||
func _on_attempt_abandoned() -> void:
|
||||
if restart_case_external_id.is_empty():
|
||||
return
|
||||
var case_external_id := restart_case_external_id
|
||||
restart_case_external_id = ""
|
||||
pending_action = "creating"
|
||||
status_label.text = "Starting the updated interview..."
|
||||
CCSService.create_attempt(case_external_id, "timed")
|
||||
|
||||
|
||||
func _on_request_failed(message: String) -> void:
|
||||
if not visible:
|
||||
return
|
||||
@@ -272,6 +316,11 @@ func _on_request_failed(message: String) -> void:
|
||||
status_label.text = "An active case was found. Loading it now..."
|
||||
CCSService.load_active()
|
||||
return
|
||||
if failed_action == "refreshing_interview":
|
||||
restart_case_external_id = ""
|
||||
status_label.text = "The updated interview could not be started. %s" % message
|
||||
retry_button.visible = true
|
||||
return
|
||||
if active_scene != null:
|
||||
active_scene.set_choices_pending(false)
|
||||
else:
|
||||
|
||||
@@ -54,6 +54,20 @@ func _run() -> void:
|
||||
await process_frame
|
||||
_assert(screen.current_view == "case_selection", "CCS Cases 2 should begin with compatible case selection")
|
||||
_assert(screen.case_list.get_child_count() == 1, "legacy cases should be excluded from graphical selection")
|
||||
var retired_attempt := {
|
||||
"caseExternalId": "ccs-gastro-duodenal-ulcer-office-001"
|
||||
}
|
||||
_assert(screen._is_retired_interview_revision(retired_attempt, {
|
||||
"id": "fatigue_course", "patientText": "My stomach bothers me.", "choices": []
|
||||
}), "the retired stomach response should trigger a current-revision restart")
|
||||
_assert(screen._is_retired_interview_revision(retired_attempt, {
|
||||
"id": "chief_concern", "patientText": "Dizzy.",
|
||||
"choices": [{"id": "abdominal_symptoms", "text": "Ask about stomach pain"}]
|
||||
}), "retired stomach-topic choices should trigger a current-revision restart")
|
||||
_assert(not screen._is_retired_interview_revision(retired_attempt, {
|
||||
"id": "chief_concern", "patientText": "Dizzy and tired.",
|
||||
"choices": [{"id": "dizziness_character", "text": "Ask about dizziness"}]
|
||||
}), "the focused dizziness and fatigue revision should remain active")
|
||||
|
||||
service.attempt = _sample_attempt(false)
|
||||
screen._render_state()
|
||||
@@ -219,11 +233,16 @@ func _choice_labels_fit(scene: Control) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
func _label_content_fits(label: Label) -> bool:
|
||||
var font := label.get_theme_font("font")
|
||||
var font_size := label.get_theme_font_size("font_size")
|
||||
var content_height := float(label.get_line_count()) * font.get_height(font_size)
|
||||
return content_height <= label.size.y + 0.5
|
||||
func _label_content_fits(label: Control) -> bool:
|
||||
if label is RichTextLabel:
|
||||
return label.get_content_height() <= label.size.y + 0.5
|
||||
var plain_label := label as Label
|
||||
if plain_label == null:
|
||||
return false
|
||||
var font := plain_label.get_theme_font("font")
|
||||
var font_size := plain_label.get_theme_font_size("font_size")
|
||||
var content_height := float(plain_label.get_line_count()) * font.get_height(font_size)
|
||||
return content_height <= plain_label.size.y + 0.5
|
||||
|
||||
|
||||
func _assert(condition: bool, message: String) -> void:
|
||||
|
||||
Reference in New Issue
Block a user