Add dialogue portrait slots
This commit is contained in:
@@ -84,6 +84,9 @@ var formation_list: VBoxContainer
|
||||
var formation_status_label: Label
|
||||
var formation_unit_id := ""
|
||||
var dialogue_panel: PanelContainer
|
||||
var dialogue_portrait_panel: PanelContainer
|
||||
var dialogue_portrait_texture: TextureRect
|
||||
var dialogue_portrait_label: Label
|
||||
var dialogue_speaker_label: Label
|
||||
var dialogue_text_label: Label
|
||||
var dialogue_continue_button: Button
|
||||
@@ -447,17 +450,42 @@ func _create_hud() -> void:
|
||||
dialogue_panel.size = Vector2(760, 140)
|
||||
root.add_child(dialogue_panel)
|
||||
|
||||
var dialogue_row := HBoxContainer.new()
|
||||
dialogue_row.add_theme_constant_override("separation", 14)
|
||||
dialogue_panel.add_child(dialogue_row)
|
||||
|
||||
dialogue_portrait_panel = PanelContainer.new()
|
||||
dialogue_portrait_panel.custom_minimum_size = Vector2(96, 112)
|
||||
dialogue_row.add_child(dialogue_portrait_panel)
|
||||
|
||||
var dialogue_portrait_stack := Control.new()
|
||||
dialogue_portrait_stack.custom_minimum_size = Vector2(96, 112)
|
||||
dialogue_portrait_panel.add_child(dialogue_portrait_stack)
|
||||
|
||||
dialogue_portrait_texture = TextureRect.new()
|
||||
dialogue_portrait_texture.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
dialogue_portrait_texture.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
dialogue_portrait_stack.add_child(dialogue_portrait_texture)
|
||||
|
||||
dialogue_portrait_label = Label.new()
|
||||
dialogue_portrait_label.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
dialogue_portrait_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
dialogue_portrait_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
dialogue_portrait_label.add_theme_font_size_override("font_size", 22)
|
||||
dialogue_portrait_stack.add_child(dialogue_portrait_label)
|
||||
|
||||
var dialogue_column := VBoxContainer.new()
|
||||
dialogue_column.custom_minimum_size = Vector2(620, 112)
|
||||
dialogue_column.add_theme_constant_override("separation", 8)
|
||||
dialogue_panel.add_child(dialogue_column)
|
||||
dialogue_row.add_child(dialogue_column)
|
||||
|
||||
dialogue_speaker_label = Label.new()
|
||||
dialogue_speaker_label.custom_minimum_size = Vector2(720, 22)
|
||||
dialogue_speaker_label.custom_minimum_size = Vector2(600, 22)
|
||||
dialogue_column.add_child(dialogue_speaker_label)
|
||||
|
||||
dialogue_text_label = Label.new()
|
||||
dialogue_text_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
dialogue_text_label.custom_minimum_size = Vector2(720, 56)
|
||||
dialogue_text_label.custom_minimum_size = Vector2(600, 56)
|
||||
dialogue_column.add_child(dialogue_text_label)
|
||||
|
||||
dialogue_continue_button = Button.new()
|
||||
@@ -1486,13 +1514,14 @@ func _normalized_dialogue_lines(lines: Array) -> Array:
|
||||
continue
|
||||
result.append({
|
||||
"speaker": str(line.get("speaker", "")),
|
||||
"text": text
|
||||
"text": text,
|
||||
"portrait": str(line.get("portrait", ""))
|
||||
})
|
||||
elif typeof(line) == TYPE_STRING:
|
||||
var text := str(line)
|
||||
if text.is_empty():
|
||||
continue
|
||||
result.append({"speaker": "", "text": text})
|
||||
result.append({"speaker": "", "text": text, "portrait": ""})
|
||||
return result
|
||||
|
||||
|
||||
@@ -1533,12 +1562,54 @@ func _render_dialogue_line() -> void:
|
||||
dialogue_speaker_label.text = speaker
|
||||
dialogue_speaker_label.visible = not speaker.is_empty()
|
||||
dialogue_text_label.text = str(line.get("text", ""))
|
||||
_update_dialogue_portrait(speaker, str(line.get("portrait", "")))
|
||||
dialogue_continue_button.text = "Close" if active_dialogue_index >= active_dialogue_lines.size() - 1 else "Next"
|
||||
dialogue_panel.visible = true
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _update_dialogue_portrait(speaker: String, portrait_path: String) -> void:
|
||||
if dialogue_portrait_panel == null:
|
||||
return
|
||||
var texture := _load_dialogue_portrait(portrait_path)
|
||||
var has_portrait := texture != null
|
||||
var has_placeholder := not speaker.is_empty()
|
||||
dialogue_portrait_panel.visible = has_portrait or has_placeholder
|
||||
dialogue_portrait_texture.texture = texture
|
||||
dialogue_portrait_texture.visible = has_portrait
|
||||
dialogue_portrait_label.text = _dialogue_portrait_initials(speaker)
|
||||
dialogue_portrait_label.visible = not has_portrait and has_placeholder
|
||||
|
||||
|
||||
func _load_dialogue_portrait(portrait_path: String) -> Texture2D:
|
||||
var normalized_path := portrait_path.strip_edges()
|
||||
if normalized_path.is_empty():
|
||||
return null
|
||||
if not normalized_path.begins_with("res://") and not normalized_path.begins_with("user://"):
|
||||
normalized_path = "res://%s" % normalized_path
|
||||
if not ResourceLoader.exists(normalized_path, "Texture2D"):
|
||||
return null
|
||||
return load(normalized_path) as Texture2D
|
||||
|
||||
|
||||
func _dialogue_portrait_initials(speaker: String) -> String:
|
||||
var normalized_speaker := speaker.strip_edges()
|
||||
if normalized_speaker.is_empty():
|
||||
return ""
|
||||
var parts := normalized_speaker.split(" ", false)
|
||||
var initials := ""
|
||||
for part in parts:
|
||||
if str(part).is_empty():
|
||||
continue
|
||||
initials += str(part).substr(0, 1).to_upper()
|
||||
if initials.length() >= 2:
|
||||
break
|
||||
if initials.is_empty():
|
||||
return normalized_speaker.substr(0, 1).to_upper()
|
||||
return initials
|
||||
|
||||
|
||||
func _advance_dialogue() -> void:
|
||||
if not _is_dialogue_visible():
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user