Refine graphical CCS interview flow
This commit is contained in:
@@ -10,7 +10,8 @@ const CHOICE_HOVER := preload("res://assets/ccs_cases_2/images/doctor/dialogue-c
|
||||
const CHOICE_PRESSED := preload("res://assets/ccs_cases_2/images/doctor/dialogue-choice-pressed.png")
|
||||
const CHOICE_CROP := Rect2(80.0, 200.0, 1610.0, 485.0)
|
||||
const CHOICES_PER_PAGE := 4
|
||||
const RESPONSE_HOLD_SECONDS := 1.25
|
||||
const DIALOGUE_PAGE_MIN_CHARS := 32
|
||||
const DIALOGUE_PAGE_MAX_CHARS := 82
|
||||
|
||||
@onready var hour_hand: Node2D = $ClockMount/HourHand
|
||||
@onready var minute_hand: Node2D = $ClockMount/MinuteHand
|
||||
@@ -18,6 +19,7 @@ const RESPONSE_HOLD_SECONDS := 1.25
|
||||
@onready var patient: TextureRect = $Patient
|
||||
@onready var dialogue_bubble: Control = $DialogueBubble
|
||||
@onready var dialogue_text: Label = $DialogueBubble/Text
|
||||
@onready var dialogue_continue_hint: Label = $DialogueBubble/ContinueHint
|
||||
@onready var choice_area: Control = $DialogueChoiceArea
|
||||
@onready var choice_container: HBoxContainer = $DialogueChoiceArea/DialogueChoices
|
||||
@onready var choice_pager: HBoxContainer = $DialogueChoiceArea/ChoicePager
|
||||
@@ -27,16 +29,20 @@ const RESPONSE_HOLD_SECONDS := 1.25
|
||||
|
||||
var blink_tween: Tween
|
||||
var dialogue_tween: Tween
|
||||
var response_hold_tween: Tween
|
||||
var clock_seconds := 9.0 * 60.0 * 60.0
|
||||
var debrief_panel: PanelContainer
|
||||
var experience_mode := "management"
|
||||
var pending_choices: Array = []
|
||||
var available_choices: Array = []
|
||||
var choice_page := 0
|
||||
var dialogue_pages: Array[String] = []
|
||||
var dialogue_page_index := 0
|
||||
var dialogue_characters_per_second := 35.0
|
||||
var dialogue_reveal_complete := false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
dialogue_bubble.gui_input.connect(_on_dialogue_bubble_input)
|
||||
previous_page_button.pressed.connect(_change_choice_page.bind(-1))
|
||||
next_page_button.pressed.connect(_change_choice_page.bind(1))
|
||||
_update_clock()
|
||||
@@ -95,13 +101,25 @@ func _set_patient_blink(amount: float) -> void:
|
||||
func show_patient_dialogue(text: String, characters_per_second: float = 35.0) -> void:
|
||||
if dialogue_tween and dialogue_tween.is_valid():
|
||||
dialogue_tween.kill()
|
||||
if response_hold_tween and response_hold_tween.is_valid():
|
||||
response_hold_tween.kill()
|
||||
dialogue_text.text = text
|
||||
dialogue_pages = _split_dialogue_pages(text)
|
||||
dialogue_page_index = 0
|
||||
dialogue_characters_per_second = characters_per_second
|
||||
_show_dialogue_page()
|
||||
|
||||
|
||||
func _show_dialogue_page() -> void:
|
||||
if dialogue_tween and dialogue_tween.is_valid():
|
||||
dialogue_tween.kill()
|
||||
if dialogue_pages.is_empty():
|
||||
complete_response_transition()
|
||||
return
|
||||
dialogue_text.text = dialogue_pages[dialogue_page_index]
|
||||
dialogue_text.visible_ratio = 0.0
|
||||
dialogue_reveal_complete = false
|
||||
dialogue_continue_hint.visible = false
|
||||
dialogue_bubble.visible = true
|
||||
call_deferred("_resize_dialogue_bubble")
|
||||
var reveal_duration := float(text.length()) / maxf(characters_per_second, 1.0)
|
||||
dialogue_bubble.grab_focus()
|
||||
var reveal_duration := float(dialogue_text.text.length()) / maxf(dialogue_characters_per_second, 1.0)
|
||||
dialogue_tween = create_tween()
|
||||
dialogue_tween.tween_property(dialogue_text, "visible_ratio", 1.0, reveal_duration)
|
||||
dialogue_tween.finished.connect(_on_dialogue_reveal_finished)
|
||||
@@ -110,9 +128,11 @@ func show_patient_dialogue(text: String, characters_per_second: float = 35.0) ->
|
||||
func hide_patient_dialogue() -> void:
|
||||
if dialogue_tween and dialogue_tween.is_valid():
|
||||
dialogue_tween.kill()
|
||||
if response_hold_tween and response_hold_tween.is_valid():
|
||||
response_hold_tween.kill()
|
||||
dialogue_bubble.visible = false
|
||||
dialogue_continue_hint.visible = false
|
||||
dialogue_pages = []
|
||||
dialogue_page_index = 0
|
||||
dialogue_reveal_complete = false
|
||||
pending_choices = []
|
||||
|
||||
|
||||
@@ -120,12 +140,6 @@ func is_patient_dialogue_visible() -> bool:
|
||||
return dialogue_bubble.visible
|
||||
|
||||
|
||||
func _resize_dialogue_bubble() -> void:
|
||||
var line_count := maxi(dialogue_text.get_line_count(), 1)
|
||||
var target_height := clampf(82.0 + line_count * 29.0, 150.0, 310.0)
|
||||
dialogue_bubble.size.y = target_height
|
||||
|
||||
|
||||
func configure_interview(node: Dictionary) -> void:
|
||||
if debrief_panel != null and is_instance_valid(debrief_panel):
|
||||
debrief_panel.queue_free()
|
||||
@@ -148,6 +162,8 @@ func configure_interview(node: Dictionary) -> void:
|
||||
|
||||
|
||||
func complete_dialogue_reveal() -> void:
|
||||
if dialogue_reveal_complete:
|
||||
return
|
||||
if dialogue_tween and dialogue_tween.is_valid():
|
||||
dialogue_tween.kill()
|
||||
dialogue_text.visible_ratio = 1.0
|
||||
@@ -156,23 +172,77 @@ func complete_dialogue_reveal() -> void:
|
||||
|
||||
func _on_dialogue_reveal_finished() -> void:
|
||||
dialogue_tween = null
|
||||
if response_hold_tween and response_hold_tween.is_valid():
|
||||
response_hold_tween.kill()
|
||||
response_hold_tween = create_tween()
|
||||
response_hold_tween.tween_interval(RESPONSE_HOLD_SECONDS)
|
||||
response_hold_tween.tween_callback(complete_response_transition)
|
||||
dialogue_reveal_complete = true
|
||||
dialogue_continue_hint.text = (
|
||||
"Click to see questions ▼"
|
||||
if dialogue_page_index >= dialogue_pages.size() - 1
|
||||
else "Click to continue ▼"
|
||||
)
|
||||
dialogue_continue_hint.visible = true
|
||||
|
||||
|
||||
func advance_dialogue() -> void:
|
||||
if not dialogue_bubble.visible:
|
||||
return
|
||||
if not dialogue_reveal_complete:
|
||||
complete_dialogue_reveal()
|
||||
return
|
||||
if dialogue_page_index < dialogue_pages.size() - 1:
|
||||
dialogue_page_index += 1
|
||||
_show_dialogue_page()
|
||||
return
|
||||
complete_response_transition()
|
||||
|
||||
|
||||
func complete_response_transition() -> void:
|
||||
if response_hold_tween and response_hold_tween.is_valid():
|
||||
response_hold_tween.kill()
|
||||
response_hold_tween = null
|
||||
var choices := pending_choices
|
||||
pending_choices = []
|
||||
dialogue_bubble.visible = false
|
||||
dialogue_continue_hint.visible = false
|
||||
dialogue_pages = []
|
||||
dialogue_page_index = 0
|
||||
dialogue_reveal_complete = false
|
||||
show_dialogue_choices(choices)
|
||||
|
||||
|
||||
func _on_dialogue_bubble_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
advance_dialogue()
|
||||
accept_event()
|
||||
elif event is InputEventKey and event.pressed and not event.echo \
|
||||
and event.keycode in [KEY_ENTER, KEY_KP_ENTER, KEY_SPACE]:
|
||||
advance_dialogue()
|
||||
accept_event()
|
||||
|
||||
|
||||
func _split_dialogue_pages(text: String) -> Array[String]:
|
||||
var normalized := text.strip_edges()
|
||||
if normalized.is_empty():
|
||||
return []
|
||||
var pages: Array[String] = []
|
||||
var current := ""
|
||||
for word in normalized.split(" ", false):
|
||||
var candidate := word if current.is_empty() else "%s %s" % [current, word]
|
||||
var has_natural_break := current.length() >= DIALOGUE_PAGE_MIN_CHARS \
|
||||
and _ends_dialogue_phrase(word)
|
||||
if candidate.length() > DIALOGUE_PAGE_MAX_CHARS and not current.is_empty():
|
||||
pages.append(current)
|
||||
current = word
|
||||
elif has_natural_break:
|
||||
pages.append(candidate)
|
||||
current = ""
|
||||
else:
|
||||
current = candidate
|
||||
if not current.is_empty():
|
||||
pages.append(current)
|
||||
return pages
|
||||
|
||||
|
||||
func _ends_dialogue_phrase(word: String) -> bool:
|
||||
return word.ends_with(",") or word.ends_with(";") or word.ends_with(":") \
|
||||
or word.ends_with(".") or word.ends_with("?") or word.ends_with("!")
|
||||
|
||||
|
||||
func set_choices_pending(pending: bool) -> void:
|
||||
for child in choice_container.get_children():
|
||||
if child is BaseButton:
|
||||
|
||||
Reference in New Issue
Block a user