Deepen ancient briefing and dialogue UI
This commit is contained in:
@@ -55,8 +55,8 @@ const UNIT_ARROW_ATTACK_DURATION := 0.36
|
||||
const UNIT_COMMAND_ATTACK_DURATION := 0.38
|
||||
const UNIT_HEAVY_ATTACK_DURATION := 0.34
|
||||
const UNIT_TACTIC_CAST_DURATION := 0.42
|
||||
const DIALOGUE_PANEL_POSITION := Vector2(72, 356)
|
||||
const DIALOGUE_PANEL_SIZE := Vector2(1100, 304)
|
||||
const DIALOGUE_PANEL_POSITION := Vector2(60, 356)
|
||||
const DIALOGUE_PANEL_SIZE := Vector2(1160, 304)
|
||||
const DIALOGUE_PORTRAIT_SIZE := Vector2(184, 262)
|
||||
const DIALOGUE_COLUMN_SIZE := Vector2(850, 266)
|
||||
const DIALOGUE_TEXT_SIZE := Vector2(830, 112)
|
||||
@@ -143,6 +143,7 @@ var briefing_location_label: Label
|
||||
var briefing_seal_ribbon: HBoxContainer
|
||||
var briefing_objective_panel: PanelContainer
|
||||
var briefing_objective_label: Label
|
||||
var briefing_camp_overview_panel: PanelContainer
|
||||
var briefing_camp_overview_row: HBoxContainer
|
||||
var briefing_camp_overview_texture: TextureRect
|
||||
var briefing_camp_overview_fallback_label: Label
|
||||
@@ -184,6 +185,8 @@ var manual_save_button: Button
|
||||
var manual_load_button: Button
|
||||
var dialogue_row: HBoxContainer
|
||||
var dialogue_panel: PanelContainer
|
||||
var dialogue_left_tassel: VBoxContainer
|
||||
var dialogue_right_tassel: VBoxContainer
|
||||
var dialogue_portrait_panel: PanelContainer
|
||||
var dialogue_portrait_texture: TextureRect
|
||||
var dialogue_portrait_label: Label
|
||||
@@ -341,7 +344,7 @@ func _age_panel_style(style: StyleBoxFlat, variant: String, border_width: int) -
|
||||
style.set_border_width(SIDE_RIGHT, border_width + 1)
|
||||
style.content_margin_top += 2
|
||||
style.content_margin_bottom += 2
|
||||
"edict", "notice_edict", "speech_scroll", "bamboo_slips":
|
||||
"edict", "notice_edict", "speech_scroll", "bamboo_slips", "silk_map":
|
||||
style.set_border_width(SIDE_TOP, border_width + 2)
|
||||
style.set_border_width(SIDE_BOTTOM, border_width + 2)
|
||||
"edict_compact":
|
||||
@@ -425,6 +428,12 @@ func _apply_panel_style(panel: PanelContainer, variant: String) -> void:
|
||||
border = UI_INK_WASH
|
||||
border_width = 5
|
||||
margin = 4
|
||||
"silk_map":
|
||||
fill = Color(0.54, 0.38, 0.18, 0.992)
|
||||
border = UI_SCROLL_EDGE
|
||||
border_width = 4
|
||||
margin = 10
|
||||
shadow_size = 5
|
||||
"compact":
|
||||
fill = Color(0.052, 0.078, 0.052, 0.982)
|
||||
border = UI_JADE_EDGE
|
||||
@@ -753,6 +762,64 @@ func _make_ornament_bar(width: float = 4.0, height: float = 0.0) -> ColorRect:
|
||||
return bar
|
||||
|
||||
|
||||
func _make_edict_marker_stack(labels: Array, height: float = 84.0) -> VBoxContainer:
|
||||
var stack := VBoxContainer.new()
|
||||
stack.custom_minimum_size = Vector2(30, height)
|
||||
stack.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
stack.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
stack.add_theme_constant_override("separation", 3)
|
||||
for index in range(labels.size()):
|
||||
var panel := PanelContainer.new()
|
||||
panel.custom_minimum_size = Vector2(30, 22)
|
||||
panel.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
_apply_panel_style(panel, "speaker_seal" if index == 0 else "caption")
|
||||
stack.add_child(panel)
|
||||
|
||||
var label := Label.new()
|
||||
label.text = str(labels[index])
|
||||
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
label.custom_minimum_size = Vector2(18, 16)
|
||||
_apply_label_style(label, UI_PARCHMENT_TEXT, 13)
|
||||
panel.add_child(label)
|
||||
return stack
|
||||
|
||||
|
||||
func _make_hanging_tassel(height: float = 262.0) -> VBoxContainer:
|
||||
var tassel := VBoxContainer.new()
|
||||
tassel.custom_minimum_size = Vector2(18, height)
|
||||
tassel.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
tassel.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
tassel.add_theme_constant_override("separation", 4)
|
||||
|
||||
var top_seal := ColorRect.new()
|
||||
top_seal.color = UI_SEAL_RED
|
||||
top_seal.custom_minimum_size = Vector2(18, 18)
|
||||
top_seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
tassel.add_child(top_seal)
|
||||
|
||||
var cords := HBoxContainer.new()
|
||||
cords.custom_minimum_size = Vector2(18, maxf(0.0, height - 44.0))
|
||||
cords.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
cords.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
cords.add_theme_constant_override("separation", 4)
|
||||
for index in range(2):
|
||||
var cord := ColorRect.new()
|
||||
cord.color = UI_TARNISHED_BRONZE if index == 0 else UI_CINNABAR_DARK
|
||||
cord.custom_minimum_size = Vector2(6, height - 44.0)
|
||||
cord.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
cord.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
cords.add_child(cord)
|
||||
tassel.add_child(cords)
|
||||
|
||||
var bottom_seal := ColorRect.new()
|
||||
bottom_seal.color = UI_SEAL_RED_DARK
|
||||
bottom_seal.custom_minimum_size = Vector2(18, 18)
|
||||
bottom_seal.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
tassel.add_child(bottom_seal)
|
||||
return tassel
|
||||
|
||||
|
||||
func _create_hud() -> void:
|
||||
var layer := CanvasLayer.new()
|
||||
add_child(layer)
|
||||
@@ -1200,22 +1267,35 @@ func _create_hud() -> void:
|
||||
briefing_objective_panel.add_child(briefing_objective_row)
|
||||
|
||||
briefing_objective_row.add_child(_make_bamboo_gutter(18, 84))
|
||||
briefing_objective_row.add_child(_make_edict_marker_stack(["令", "勝", "敗"], 84))
|
||||
|
||||
briefing_objective_label = Label.new()
|
||||
briefing_objective_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
briefing_objective_label.custom_minimum_size = Vector2(586, 84)
|
||||
briefing_objective_label.custom_minimum_size = Vector2(500, 84)
|
||||
briefing_objective_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_apply_label_style(briefing_objective_label, UI_AGED_INK, 15)
|
||||
briefing_objective_row.add_child(briefing_objective_label)
|
||||
briefing_objective_row.add_child(_make_edict_marker_stack(["軍", "功", "封"], 84))
|
||||
briefing_objective_row.add_child(_make_bamboo_gutter(18, 84))
|
||||
|
||||
briefing_column.add_child(_make_ink_wash_rule(680, 7))
|
||||
briefing_column.add_child(_make_section_caption("비단 전장도 · 군막 장부", 680))
|
||||
|
||||
briefing_camp_overview_panel = PanelContainer.new()
|
||||
briefing_camp_overview_panel.custom_minimum_size = Vector2(680, 102)
|
||||
_apply_panel_style(briefing_camp_overview_panel, "silk_map")
|
||||
briefing_column.add_child(briefing_camp_overview_panel)
|
||||
|
||||
var briefing_camp_overview_shell := HBoxContainer.new()
|
||||
briefing_camp_overview_shell.add_theme_constant_override("separation", 10)
|
||||
briefing_camp_overview_panel.add_child(briefing_camp_overview_shell)
|
||||
briefing_camp_overview_shell.add_child(_make_edict_marker_stack(["圖", "地"], 72))
|
||||
|
||||
briefing_camp_overview_row = HBoxContainer.new()
|
||||
briefing_camp_overview_row.custom_minimum_size = Vector2(680, 84)
|
||||
briefing_camp_overview_row.custom_minimum_size = Vector2(580, 84)
|
||||
briefing_camp_overview_row.add_theme_constant_override("separation", 10)
|
||||
briefing_column.add_child(briefing_camp_overview_row)
|
||||
briefing_camp_overview_row.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
briefing_camp_overview_shell.add_child(briefing_camp_overview_row)
|
||||
|
||||
var camp_thumbnail_panel := PanelContainer.new()
|
||||
camp_thumbnail_panel.custom_minimum_size = BRIEFING_CAMP_THUMBNAIL_SIZE
|
||||
@@ -1243,10 +1323,11 @@ func _create_hud() -> void:
|
||||
|
||||
briefing_camp_overview_label = Label.new()
|
||||
briefing_camp_overview_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
briefing_camp_overview_label.custom_minimum_size = Vector2(520, 72)
|
||||
briefing_camp_overview_label.custom_minimum_size = Vector2(420, 72)
|
||||
briefing_camp_overview_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_apply_label_style(briefing_camp_overview_label, UI_AGED_INK, 14)
|
||||
briefing_camp_overview_row.add_child(briefing_camp_overview_label)
|
||||
briefing_camp_overview_shell.add_child(_make_bamboo_gutter(14, 72))
|
||||
|
||||
briefing_column.add_child(_make_scroll_rod(680, 3))
|
||||
|
||||
@@ -1474,9 +1555,12 @@ func _create_hud() -> void:
|
||||
root.add_child(dialogue_panel)
|
||||
|
||||
dialogue_row = HBoxContainer.new()
|
||||
dialogue_row.add_theme_constant_override("separation", 14)
|
||||
dialogue_row.add_theme_constant_override("separation", 10)
|
||||
dialogue_panel.add_child(dialogue_row)
|
||||
|
||||
dialogue_left_tassel = _make_hanging_tassel(DIALOGUE_PORTRAIT_SIZE.y)
|
||||
dialogue_row.add_child(dialogue_left_tassel)
|
||||
|
||||
dialogue_portrait_panel = PanelContainer.new()
|
||||
dialogue_portrait_panel.custom_minimum_size = DIALOGUE_PORTRAIT_SIZE
|
||||
_apply_panel_style(dialogue_portrait_panel, "portrait")
|
||||
@@ -1506,6 +1590,9 @@ func _create_hud() -> void:
|
||||
dialogue_column.add_theme_constant_override("separation", 7)
|
||||
dialogue_row.add_child(dialogue_column)
|
||||
|
||||
dialogue_right_tassel = _make_hanging_tassel(DIALOGUE_PORTRAIT_SIZE.y)
|
||||
dialogue_row.add_child(dialogue_right_tassel)
|
||||
|
||||
dialogue_column.add_child(_make_tablet_binding(DIALOGUE_TEXT_SIZE.x, 13))
|
||||
|
||||
dialogue_seal_ribbon = _make_seal_ribbon(DIALOGUE_TEXT_SIZE.x, 18)
|
||||
@@ -4380,8 +4467,10 @@ func _normalized_dialogue_lines(lines: Array) -> Array:
|
||||
var text := str(line.get("text", ""))
|
||||
if text.is_empty():
|
||||
continue
|
||||
var speaker := str(line.get("speaker", ""))
|
||||
var display_speaker := str(line.get("display_speaker", speaker))
|
||||
result.append({
|
||||
"speaker": str(line.get("speaker", "")),
|
||||
"speaker": display_speaker,
|
||||
"text": text,
|
||||
"portrait": str(line.get("portrait", "")),
|
||||
"side": _normalized_dialogue_side(line.get("side", "left"))
|
||||
@@ -4437,12 +4526,13 @@ func _render_dialogue_line() -> void:
|
||||
return
|
||||
var line: Dictionary = active_dialogue_lines[active_dialogue_index]
|
||||
var speaker := str(line.get("speaker", ""))
|
||||
var display_speaker := str(line.get("display_speaker", speaker))
|
||||
var side := _normalized_dialogue_side(line.get("side", "left"))
|
||||
_apply_dialogue_side(side)
|
||||
dialogue_speaker_label.text = speaker
|
||||
dialogue_speaker_label.visible = not speaker.is_empty()
|
||||
dialogue_speaker_label.text = display_speaker
|
||||
dialogue_speaker_label.visible = not display_speaker.is_empty()
|
||||
dialogue_text_label.text = str(line.get("text", ""))
|
||||
_update_dialogue_portrait(speaker, str(line.get("portrait", "")))
|
||||
_update_dialogue_portrait(display_speaker, str(line.get("portrait", "")))
|
||||
_update_dialogue_controls()
|
||||
dialogue_panel.visible = true
|
||||
_update_hud()
|
||||
@@ -4460,7 +4550,7 @@ func _update_dialogue_controls() -> void:
|
||||
func _apply_dialogue_side(side: String) -> void:
|
||||
if dialogue_row == null or dialogue_portrait_panel == null or dialogue_column == null:
|
||||
return
|
||||
var portrait_index := 1 if side == "right" else 0
|
||||
var portrait_index: int = maxi(0, dialogue_row.get_child_count() - 2) if side == "right" else 1
|
||||
dialogue_row.move_child(dialogue_portrait_panel, portrait_index)
|
||||
dialogue_speaker_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT if side == "right" else HORIZONTAL_ALIGNMENT_LEFT
|
||||
dialogue_text_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT if side == "right" else HORIZONTAL_ALIGNMENT_LEFT
|
||||
@@ -4880,6 +4970,8 @@ func _update_briefing_camp_overview(briefing: Dictionary, prep_locked: bool) ->
|
||||
return
|
||||
var overview_text := _format_briefing_camp_overview_text(briefing, prep_locked)
|
||||
briefing_camp_overview_row.visible = not overview_text.is_empty()
|
||||
if briefing_camp_overview_panel != null:
|
||||
briefing_camp_overview_panel.visible = not overview_text.is_empty()
|
||||
if briefing_camp_overview_label != null:
|
||||
briefing_camp_overview_label.text = overview_text
|
||||
var texture := _current_battle_background_texture()
|
||||
|
||||
@@ -2650,6 +2650,8 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void:
|
||||
_check_panel_style_frame(failures, scene.briefing_panel, "briefing panel", Color(0.20, 0.11, 0.045, 1.0), 10)
|
||||
_check_panel_style_fill(failures, scene.briefing_objective_panel, "briefing objective edict panel", Color(0.66, 0.52, 0.31, 0.995))
|
||||
_check_panel_style_frame(failures, scene.briefing_objective_panel, "briefing objective edict panel", Color(0.20, 0.11, 0.045, 1.0), 6)
|
||||
_check_panel_style_fill(failures, scene.briefing_camp_overview_panel, "briefing silk map panel", Color(0.54, 0.38, 0.18, 0.992))
|
||||
_check_panel_style_frame(failures, scene.briefing_camp_overview_panel, "briefing silk map panel", Color(0.43, 0.25, 0.095, 0.996), 4)
|
||||
_check_panel_style_fill(failures, scene.dialogue_panel, "dialogue panel", Color(0.070, 0.018, 0.010, 0.997))
|
||||
_check_panel_style_frame(failures, scene.dialogue_panel, "dialogue panel", Color(0.78, 0.58, 0.27, 1.0), 9)
|
||||
_check_panel_style_fill(failures, scene.dialogue_portrait_panel, "dialogue portrait panel", Color(0.035, 0.014, 0.008, 1.0))
|
||||
@@ -2660,11 +2662,33 @@ func _check_ancient_ui_theme(failures: Array[String]) -> void:
|
||||
_check_seal_ribbon(failures, scene.result_seal_ribbon, "result seal ribbon")
|
||||
_check_bamboo_gutter_row(failures, scene.briefing_objective_panel, "briefing objective bamboo gutters")
|
||||
_check_bamboo_gutter_row(failures, scene.dialogue_text_panel, "dialogue scroll bamboo gutters")
|
||||
_check_edict_marker_stack(failures, scene.briefing_objective_panel, "briefing objective edict markers")
|
||||
_check_hanging_tassel(failures, scene.dialogue_left_tassel, "dialogue left tassel")
|
||||
_check_hanging_tassel(failures, scene.dialogue_right_tassel, "dialogue right tassel")
|
||||
_check_dialogue_column_budget(failures, scene)
|
||||
if scene.dialogue_continue_button == null or scene.dialogue_continue_button.text != "다음 죽간":
|
||||
failures.append("dialogue continue button should use ancient slip text")
|
||||
if scene.dialogue_previous_button == null or scene.dialogue_previous_button.text != "이전 죽간":
|
||||
failures.append("dialogue previous button should use ancient slip text")
|
||||
var localized_lines := scene._normalized_dialogue_lines([{"speaker": "Cao Cao", "display_speaker": "조조", "text": "군령을 전하라."}])
|
||||
if localized_lines.is_empty() or str((localized_lines[0] as Dictionary).get("speaker", "")) != "조조":
|
||||
failures.append("dialogue normalization should preserve display_speaker for localized names")
|
||||
else:
|
||||
scene.active_dialogue_lines = localized_lines
|
||||
scene.active_dialogue_index = 0
|
||||
scene._render_dialogue_line()
|
||||
if scene.dialogue_speaker_label == null or scene.dialogue_speaker_label.text != "조조":
|
||||
failures.append("dialogue speaker label should render localized display_speaker")
|
||||
scene._hide_dialogue_panel()
|
||||
var right_lines := scene._normalized_dialogue_lines([{"speaker": "Xiahou Dun", "display_speaker": "하후돈", "side": "right", "text": "우익에서 응하겠습니다."}])
|
||||
if right_lines.is_empty():
|
||||
failures.append("dialogue normalization should keep right-side lines")
|
||||
else:
|
||||
scene.active_dialogue_lines = right_lines
|
||||
scene.active_dialogue_index = 0
|
||||
scene._render_dialogue_line()
|
||||
_check_right_side_dialogue_layout(failures, scene)
|
||||
scene._hide_dialogue_panel()
|
||||
if scene._ui_font(false) == null:
|
||||
failures.append("ancient UI regular font should load from project assets")
|
||||
if scene._ui_font(true) == null:
|
||||
@@ -2748,6 +2772,57 @@ func _check_bamboo_gutter(failures: Array[String], node: Node, label: String) ->
|
||||
failures.append("%s should use three bamboo slips" % label)
|
||||
|
||||
|
||||
func _check_edict_marker_stack(failures: Array[String], panel: PanelContainer, label: String) -> void:
|
||||
if panel == null or panel.get_child_count() <= 0:
|
||||
failures.append("%s missing row" % label)
|
||||
return
|
||||
var row := panel.get_child(0) as HBoxContainer
|
||||
if row == null or row.get_child_count() < 5:
|
||||
failures.append("%s should include side marker stacks" % label)
|
||||
return
|
||||
_check_marker_stack(failures, row.get_child(1), "%s left stack" % label)
|
||||
_check_marker_stack(failures, row.get_child(row.get_child_count() - 2), "%s right stack" % label)
|
||||
|
||||
|
||||
func _check_marker_stack(failures: Array[String], node: Node, label: String) -> void:
|
||||
var stack := node as VBoxContainer
|
||||
if stack == null:
|
||||
failures.append("%s should be a vertical seal stack" % label)
|
||||
return
|
||||
if stack.get_child_count() < 2:
|
||||
failures.append("%s should include multiple seal plaques" % label)
|
||||
|
||||
|
||||
func _check_hanging_tassel(failures: Array[String], tassel: VBoxContainer, label: String) -> void:
|
||||
if tassel == null:
|
||||
failures.append("%s missing" % label)
|
||||
return
|
||||
if tassel.get_child_count() != 3:
|
||||
failures.append("%s should use top seal, hanging cords, and bottom seal" % label)
|
||||
return
|
||||
var cords := tassel.get_child(1) as HBoxContainer
|
||||
if cords == null or cords.get_child_count() != 2:
|
||||
failures.append("%s should include two hanging cord strips" % label)
|
||||
|
||||
|
||||
func _check_right_side_dialogue_layout(failures: Array[String], scene) -> void:
|
||||
if scene.dialogue_row == null or scene.dialogue_row.get_child_count() != 4:
|
||||
failures.append("right-side dialogue should keep four major columns")
|
||||
return
|
||||
if scene.dialogue_row.get_child(0) != scene.dialogue_left_tassel:
|
||||
failures.append("right-side dialogue should keep the left tassel at the outer edge")
|
||||
if scene.dialogue_row.get_child(1) != scene.dialogue_column:
|
||||
failures.append("right-side dialogue should place speech scroll before the portrait")
|
||||
if scene.dialogue_row.get_child(2) != scene.dialogue_portrait_panel:
|
||||
failures.append("right-side dialogue should place portrait near the right tassel")
|
||||
if scene.dialogue_row.get_child(3) != scene.dialogue_right_tassel:
|
||||
failures.append("right-side dialogue should keep the right tassel at the outer edge")
|
||||
if scene.dialogue_speaker_label == null or scene.dialogue_speaker_label.horizontal_alignment != HORIZONTAL_ALIGNMENT_RIGHT:
|
||||
failures.append("right-side dialogue speaker label should align right")
|
||||
if scene.dialogue_text_label == null or scene.dialogue_text_label.horizontal_alignment != HORIZONTAL_ALIGNMENT_RIGHT:
|
||||
failures.append("right-side dialogue text should align right")
|
||||
|
||||
|
||||
func _check_dialogue_column_budget(failures: Array[String], scene) -> void:
|
||||
if scene.dialogue_column == null:
|
||||
failures.append("dialogue column missing")
|
||||
|
||||
Reference in New Issue
Block a user