Compact camp conversation rows
This commit is contained in:
@@ -21,7 +21,7 @@ Godot 4 tactical RPG prototype inspired by classic turn-based Romance of the Thr
|
||||
- First named equipment rewards exist in the northern campaign arc and show a `[Named]` or `Named` tag in reward, inventory, shop, Armory, and equipment menus.
|
||||
- Scenario-specific pre-battle shop purchases, optional finite shop stock, and 50% sell-back save immediately and sync into the upcoming battle inventory.
|
||||
- Pre-battle shop rows emphasize item artwork, compact price/status badges, and hover details instead of dense inline text.
|
||||
- Pre-battle Talk can list scenario camp conversations by officer or topic, branch them from saved campaign choices, grant one-time pre-battle supplies, and shop stock can include merchant flavor lines before a battle.
|
||||
- Pre-battle Talk can list scenario camp conversations by officer or topic with portrait rows, compact topic/supply badges, hover dialogue previews, saved-branch filtering, one-time pre-battle supplies, and merchant flavor lines before a battle.
|
||||
- Pre-battle Armory equipment changes, including unequipping gear back into stock, save immediately and sync roster equipment plus inventory stock, with portrait and item-icon rows plus hover change details.
|
||||
- Pre-battle Roster can move optional officers between sortie and reserve within scenario limits, using portrait rows, compact status badges, and hover details.
|
||||
- Pre-battle Formation lets deployed officers swap starting positions inside scenario-defined cells, with portrait rows, coordinate badges, and hover placement instructions.
|
||||
|
||||
@@ -10008,48 +10008,60 @@ func _rebuild_talk_menu() -> void:
|
||||
|
||||
|
||||
func _add_camp_conversation_row(conversation: Dictionary) -> void:
|
||||
var tooltip_text := _format_camp_conversation_tooltip_text(conversation)
|
||||
var row := HBoxContainer.new()
|
||||
row.custom_minimum_size = Vector2(580, 64)
|
||||
row.custom_minimum_size = Vector2(580, 62)
|
||||
row.add_theme_constant_override("separation", 8)
|
||||
row.tooltip_text = tooltip_text
|
||||
talk_list.add_child(row)
|
||||
|
||||
row.add_child(_make_camp_conversation_portrait(conversation))
|
||||
row.add_child(_make_camp_conversation_portrait(conversation, tooltip_text))
|
||||
|
||||
var column := VBoxContainer.new()
|
||||
column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
column.add_theme_constant_override("separation", 3)
|
||||
column.add_theme_constant_override("separation", 4)
|
||||
column.tooltip_text = tooltip_text
|
||||
row.add_child(column)
|
||||
|
||||
var conversation_id := str(conversation.get("id", ""))
|
||||
var button := Button.new()
|
||||
button.text = _format_camp_conversation_row_title(conversation)
|
||||
button.custom_minimum_size = Vector2(500, 32)
|
||||
button.custom_minimum_size = Vector2(500, 30)
|
||||
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
button.tooltip_text = tooltip_text
|
||||
_apply_button_style(button)
|
||||
button.pressed.connect(_on_camp_conversation_pressed.bind(conversation_id))
|
||||
column.add_child(button)
|
||||
|
||||
var preview_label := Label.new()
|
||||
preview_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
preview_label.custom_minimum_size = Vector2(500, 24)
|
||||
preview_label.text = _format_camp_conversation_preview_text(conversation)
|
||||
_apply_label_style(preview_label, UI_AGED_INK)
|
||||
column.add_child(preview_label)
|
||||
var badge_row := HBoxContainer.new()
|
||||
badge_row.custom_minimum_size = Vector2(500, 22)
|
||||
badge_row.add_theme_constant_override("separation", 5)
|
||||
badge_row.tooltip_text = tooltip_text
|
||||
column.add_child(badge_row)
|
||||
|
||||
for badge_text in _format_camp_conversation_visible_badges(conversation):
|
||||
var text := str(badge_text).strip_edges()
|
||||
if text.is_empty():
|
||||
continue
|
||||
badge_row.add_child(_make_armory_info_badge(text, tooltip_text))
|
||||
|
||||
|
||||
func _make_camp_conversation_portrait(conversation: Dictionary) -> PanelContainer:
|
||||
func _make_camp_conversation_portrait(conversation: Dictionary, tooltip_text: String = "") -> PanelContainer:
|
||||
var portrait_panel := PanelContainer.new()
|
||||
portrait_panel.custom_minimum_size = CAMP_TALK_PORTRAIT_SIZE
|
||||
portrait_panel.tooltip_text = tooltip_text
|
||||
_apply_panel_style(portrait_panel, "portrait")
|
||||
|
||||
var stack := Control.new()
|
||||
stack.custom_minimum_size = CAMP_TALK_PORTRAIT_SIZE
|
||||
stack.tooltip_text = tooltip_text
|
||||
portrait_panel.add_child(stack)
|
||||
|
||||
var texture_rect := TextureRect.new()
|
||||
texture_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
texture_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
texture_rect.tooltip_text = tooltip_text
|
||||
stack.add_child(texture_rect)
|
||||
|
||||
var initials_label := Label.new()
|
||||
@@ -10057,6 +10069,7 @@ func _make_camp_conversation_portrait(conversation: Dictionary) -> PanelContaine
|
||||
initials_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
initials_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
initials_label.add_theme_font_size_override("font_size", 18)
|
||||
initials_label.tooltip_text = tooltip_text
|
||||
_apply_label_style(initials_label, UI_PARCHMENT_TEXT)
|
||||
stack.add_child(initials_label)
|
||||
|
||||
@@ -10143,16 +10156,37 @@ func _format_camp_conversation_button_text(conversation: Dictionary) -> String:
|
||||
func _format_camp_conversation_row_title(conversation: Dictionary) -> String:
|
||||
var label := str(conversation.get("label", "군막 담화"))
|
||||
var speaker := _camp_conversation_preview_speaker(conversation)
|
||||
var group := _camp_conversation_group_text(str(conversation.get("group", "topic")))
|
||||
var parts := [group, label]
|
||||
var parts := [label]
|
||||
if not speaker.is_empty():
|
||||
parts.append(speaker)
|
||||
var effects_text := _format_camp_conversation_effects_text(conversation)
|
||||
if not effects_text.is_empty():
|
||||
parts.append(effects_text)
|
||||
return _join_strings(parts, " · ")
|
||||
|
||||
|
||||
func _format_camp_conversation_visible_badges(conversation: Dictionary) -> Array:
|
||||
var badges := [
|
||||
_camp_conversation_group_text(str(conversation.get("group", "topic")))
|
||||
]
|
||||
var speaker := _camp_conversation_preview_speaker(conversation)
|
||||
if not speaker.is_empty():
|
||||
badges.append(speaker)
|
||||
if _camp_conversation_has_grant_item_effect(conversation):
|
||||
badges.append(_format_camp_conversation_supply_state_text(conversation))
|
||||
else:
|
||||
badges.append("대화")
|
||||
return badges
|
||||
|
||||
|
||||
func _format_camp_conversation_tooltip_text(conversation: Dictionary) -> String:
|
||||
var lines := [
|
||||
_format_camp_conversation_button_text(conversation)
|
||||
]
|
||||
var preview := _format_camp_conversation_preview_text(conversation)
|
||||
if not preview.is_empty():
|
||||
lines.append(preview)
|
||||
lines.append("클릭하면 군막 대화를 엽니다.")
|
||||
return _join_strings(lines, "\n")
|
||||
|
||||
|
||||
func _format_camp_conversation_preview_text(conversation: Dictionary) -> String:
|
||||
var parts := []
|
||||
var summary := str(conversation.get("summary", "")).strip_edges()
|
||||
@@ -10218,6 +10252,20 @@ func _camp_conversation_preview_portrait_path(conversation: Dictionary) -> Strin
|
||||
return ""
|
||||
|
||||
|
||||
func _camp_conversation_has_grant_item_effect(conversation: Dictionary) -> bool:
|
||||
for effect in conversation.get("effects", []):
|
||||
if typeof(effect) == TYPE_DICTIONARY and str(effect.get("type", "")) == "grant_item":
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _format_camp_conversation_supply_state_text(conversation: Dictionary) -> String:
|
||||
var conversation_id := str(conversation.get("id", ""))
|
||||
if campaign_state.has_claimed_camp_conversation_effects(active_scenario_id, conversation_id):
|
||||
return "보급 완료"
|
||||
return "보급 대기"
|
||||
|
||||
|
||||
func _short_preview_text(text: String, max_length: int) -> String:
|
||||
var normalized := text.strip_edges()
|
||||
if max_length <= 3 or normalized.length() <= max_length:
|
||||
|
||||
@@ -2955,8 +2955,8 @@ func _check_scene_texture_loading(failures: Array[String]) -> void:
|
||||
failures.append("camp conversation preview should resolve Cao Cao portrait")
|
||||
elif scene._load_art_texture(scene._camp_conversation_preview_portrait_path(strategy)) == null:
|
||||
failures.append("camp conversation preview portrait should load")
|
||||
elif not scene._format_camp_conversation_row_title(strategy).contains("장수"):
|
||||
failures.append("camp conversation row title should include group")
|
||||
elif not scene._format_camp_conversation_row_title(strategy).contains("조조 - 군략") or not scene._format_camp_conversation_row_title(strategy).contains("조조"):
|
||||
failures.append("camp conversation row title should stay compact with label/speaker")
|
||||
elif not scene._format_camp_conversation_preview_text(strategy).contains("영천"):
|
||||
failures.append("camp conversation preview should include first dialogue text")
|
||||
var cache := scene._camp_conversation_by_id("northern_woods_cache")
|
||||
@@ -3008,6 +3008,17 @@ func _check_scene_texture_loading(failures: Array[String]) -> void:
|
||||
failures.append("shop row tooltip should retain full item detail: %s" % shop_tooltips)
|
||||
if not _has_descendant_texture(scene.shop_list):
|
||||
failures.append("shop rows should use item icon artwork")
|
||||
scene._rebuild_talk_menu()
|
||||
var talk_visible_text := _collect_child_text(scene.talk_list)
|
||||
var talk_tooltips := _collect_child_tooltips(scene.talk_list)
|
||||
if not talk_visible_text.contains("조조 - 군략") or not talk_visible_text.contains("장수") or not talk_visible_text.contains("보급 대기"):
|
||||
failures.append("talk rows should show compact labels and status badges: %s" % talk_visible_text)
|
||||
if talk_visible_text.contains("영천") or talk_visible_text.contains("첫 행군") or talk_visible_text.contains("보급 콩") or talk_visible_text.contains("수령 가능"):
|
||||
failures.append("talk rows should keep preview and supply details in hover text: %s" % talk_visible_text)
|
||||
if not talk_tooltips.contains("영천") or not talk_tooltips.contains("보급 콩") or not talk_tooltips.contains("수령 가능"):
|
||||
failures.append("talk row tooltip should retain dialogue preview and supply detail: %s" % talk_tooltips)
|
||||
if not _has_descendant_texture(scene.talk_list):
|
||||
failures.append("talk rows should use speaker portrait artwork")
|
||||
scene._rebuild_formation_menu()
|
||||
var formation_visible_text := _collect_child_text(scene.formation_list)
|
||||
var formation_tooltips := _collect_child_tooltips(scene.formation_list)
|
||||
|
||||
Reference in New Issue
Block a user