Add visual reward strip to results

This commit is contained in:
2026-06-19 23:57:44 +09:00
parent c410b06d6c
commit 5132d2b4eb
3 changed files with 229 additions and 2 deletions

View File

@@ -119,6 +119,7 @@ const BRIEFING_CAMP_THUMBNAIL_SIZE := Vector2(188, 86)
const CAMP_TALK_PORTRAIT_SIZE := Vector2(58, 58)
const SHOP_MERCHANT_BADGE_SIZE := Vector2(50, 50)
const SHOP_ITEM_ICON_SIZE := Vector2(48, 48)
const RESULT_REWARD_ICON_SIZE := Vector2(48, 48)
const HUD_UNIT_PORTRAIT_SIZE := Vector2(92, 104)
const HUD_UNIT_PORTRAIT_STACK_SIZE := Vector2(88, 100)
const HUD_UNIT_INFO_SIZE := Vector2(320, 126)
@@ -428,7 +429,9 @@ var dialogue_progress_label: Label
var dialogue_previous_button: Button
var dialogue_continue_button: Button
var result_panel: PanelContainer
var result_reward_strip: HBoxContainer
var result_label: Label
var result_text_scroll: ScrollContainer
var result_seal_ribbon: HBoxContainer
var result_choice_list: VBoxContainer
var result_restart_button: Button
@@ -3261,15 +3264,36 @@ func _create_hud() -> void:
result_body_panel.add_child(result_body_row)
result_body_row.add_child(_make_edict_marker_stack(["", "", ""], 198))
var result_middle_column := VBoxContainer.new()
result_middle_column.custom_minimum_size = Vector2(436, 198)
result_middle_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
result_middle_column.size_flags_vertical = Control.SIZE_EXPAND_FILL
result_middle_column.add_theme_constant_override("separation", 8)
result_body_row.add_child(result_middle_column)
result_reward_strip = HBoxContainer.new()
result_reward_strip.visible = false
result_reward_strip.custom_minimum_size = Vector2(436, 52)
result_reward_strip.add_theme_constant_override("separation", 8)
result_reward_strip.tooltip_text = "이번 전투에서 정리된 전리품과 명부 변화입니다."
result_middle_column.add_child(result_reward_strip)
result_text_scroll = ScrollContainer.new()
result_text_scroll.custom_minimum_size = Vector2(436, 138)
result_text_scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL
result_text_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
result_text_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
result_middle_column.add_child(result_text_scroll)
result_label = Label.new()
result_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
result_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP
result_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
result_label.custom_minimum_size = Vector2(436, 198)
result_label.custom_minimum_size = Vector2(420, 138)
result_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
result_label.size_flags_vertical = Control.SIZE_EXPAND_FILL
_apply_label_style(result_label, UI_AGED_INK, 16)
result_body_row.add_child(result_label)
result_text_scroll.add_child(result_label)
result_body_row.add_child(_make_edict_marker_stack(["", "", ""], 198))
result_column.add_child(_make_scroll_rod(520, 3))
@@ -8377,6 +8401,7 @@ func _update_result_panel() -> void:
if campaign_complete_screen:
_clear_dialogue()
_clear_result_choices()
_clear_result_reward_strip()
_apply_panel_style(result_panel, "result_victory_tablet")
result_panel.visible = true
if result_restart_button != null:
@@ -8404,6 +8429,7 @@ func _update_result_panel() -> void:
_apply_panel_style(result_panel, "result_victory_tablet")
result_panel.visible = true
_rebuild_result_choices()
_rebuild_result_reward_strip()
if result_restart_button != null:
result_restart_button.visible = true
_update_result_next_button_visibility()
@@ -8411,6 +8437,7 @@ func _update_result_panel() -> void:
elif state.battle_status == BattleState.STATUS_DEFEAT:
_clear_dialogue()
_clear_result_choices()
_clear_result_reward_strip()
_apply_panel_style(result_panel, "result_defeat_tablet")
result_panel.visible = true
if result_restart_button != null:
@@ -8420,6 +8447,7 @@ func _update_result_panel() -> void:
result_label.text = _format_defeat_result_text()
else:
_clear_result_choices()
_clear_result_reward_strip()
result_panel.visible = false
if result_restart_button != null:
result_restart_button.visible = true
@@ -8428,6 +8456,172 @@ func _update_result_panel() -> void:
_refresh_screen_backdrop_visibility()
func _clear_result_reward_strip() -> void:
if result_reward_strip == null:
return
for child in result_reward_strip.get_children():
result_reward_strip.remove_child(child)
child.queue_free()
result_reward_strip.visible = false
func _rebuild_result_reward_strip() -> void:
_clear_result_reward_strip()
if result_reward_strip == null or battle_result_summary.is_empty():
return
if bool(battle_result_summary.get("pending_choice", false)):
return
if bool(battle_result_summary.get("already_completed", false)):
result_reward_strip.add_child(_make_result_reward_text_chip("수령", "이미 수령한 전리품입니다."))
elif bool(battle_result_summary.get("rewards_applied", false)):
var gold_reward := int(battle_result_summary.get("gold", 0))
if gold_reward > 0:
result_reward_strip.add_child(_make_result_reward_text_chip("", "군자금 +%d" % gold_reward))
var item_counts := _result_item_counts(battle_result_summary.get("items", []))
var item_ids := item_counts.keys()
item_ids.sort()
for item_id in item_ids:
var key := str(item_id)
result_reward_strip.add_child(_make_result_reward_item_chip(key, int(item_counts.get(key, 0))))
else:
result_reward_strip.add_child(_make_result_reward_text_chip("보류", "전리품이 아직 기록되지 않았습니다."))
var joined_officers: Array = battle_result_summary.get("joined_officers", [])
for officer_id in joined_officers:
result_reward_strip.add_child(_make_result_reward_officer_chip(str(officer_id), true))
var left_officers: Array = battle_result_summary.get("left_officers", [])
for officer_id in left_officers:
result_reward_strip.add_child(_make_result_reward_officer_chip(str(officer_id), false))
result_reward_strip.visible = result_reward_strip.get_child_count() > 0
func _result_item_counts(values) -> Dictionary:
var counts := {}
if typeof(values) != TYPE_ARRAY:
return counts
for value in values:
var key := str(value)
if key.is_empty():
continue
counts[key] = int(counts.get(key, 0)) + 1
return counts
func _make_result_reward_text_chip(label_text: String, tooltip_text: String) -> PanelContainer:
var panel := _make_result_reward_chip_shell(tooltip_text)
var label := Label.new()
label.set_anchors_preset(Control.PRESET_FULL_RECT)
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
label.text = label_text
label.tooltip_text = tooltip_text
_apply_label_style(label, UI_PARCHMENT_TEXT, 14)
panel.add_child(label)
return panel
func _make_result_reward_item_chip(item_id: String, count: int) -> PanelContainer:
var item := state.get_item_def(item_id)
var display_name := _item_inventory_display_name(item_id)
var detail := _format_shop_item_effect_text(item)
var tooltip := "물자: %s %d" % [display_name, count]
if not detail.is_empty():
tooltip += "\n%s" % detail
var panel := _make_result_reward_chip_shell(tooltip)
var stack := Control.new()
stack.set_anchors_preset(Control.PRESET_FULL_RECT)
stack.tooltip_text = tooltip
panel.add_child(stack)
var icon_rect := TextureRect.new()
icon_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
icon_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
icon_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
icon_rect.texture = _load_art_texture(str(item.get("icon", "")))
icon_rect.visible = icon_rect.texture != null
icon_rect.tooltip_text = tooltip
stack.add_child(icon_rect)
var fallback_label := Label.new()
fallback_label.set_anchors_preset(Control.PRESET_FULL_RECT)
fallback_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
fallback_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
fallback_label.text = _dialogue_portrait_initials(display_name)
fallback_label.visible = icon_rect.texture == null
fallback_label.tooltip_text = tooltip
_apply_label_style(fallback_label, UI_PARCHMENT_TEXT, 16)
stack.add_child(fallback_label)
if count > 1:
stack.add_child(_make_result_reward_count_badge(count, tooltip))
return panel
func _make_result_reward_officer_chip(officer_id: String, joined: bool) -> PanelContainer:
var officer_name := _officer_display_name_from_id(officer_id)
var action_text := "합류" if joined else "이탈"
var tooltip := "%s: %s" % [action_text, officer_name]
var panel := _make_result_reward_chip_shell(tooltip)
var stack := Control.new()
stack.set_anchors_preset(Control.PRESET_FULL_RECT)
stack.tooltip_text = tooltip
panel.add_child(stack)
var portrait := TextureRect.new()
portrait.set_anchors_preset(Control.PRESET_FULL_RECT)
portrait.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
portrait.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
portrait.texture = _load_art_texture(state.data_catalog.get_portrait_for_officer(officer_id))
portrait.visible = portrait.texture != null
portrait.tooltip_text = tooltip
stack.add_child(portrait)
var fallback_label := Label.new()
fallback_label.set_anchors_preset(Control.PRESET_FULL_RECT)
fallback_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
fallback_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
fallback_label.text = _dialogue_portrait_initials(officer_name)
fallback_label.visible = portrait.texture == null
fallback_label.tooltip_text = tooltip
_apply_label_style(fallback_label, UI_PARCHMENT_TEXT, 16)
stack.add_child(fallback_label)
var badge_text := "+" if joined else "-"
stack.add_child(_make_result_reward_corner_badge(badge_text, tooltip))
return panel
func _make_result_reward_chip_shell(tooltip_text: String) -> PanelContainer:
var panel := PanelContainer.new()
panel.custom_minimum_size = RESULT_REWARD_ICON_SIZE
panel.mouse_filter = Control.MOUSE_FILTER_STOP
panel.tooltip_text = tooltip_text
_apply_panel_style(panel, "portrait")
return panel
func _make_result_reward_count_badge(count: int, tooltip_text: String) -> Label:
return _make_result_reward_corner_badge("x%d" % count, tooltip_text)
func _make_result_reward_corner_badge(text: String, tooltip_text: String) -> Label:
var badge := Label.new()
badge.text = text
badge.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
badge.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
badge.position = Vector2(25, 28)
badge.size = Vector2(23, 18)
badge.add_theme_color_override("font_color", UI_PARCHMENT_TEXT)
badge.add_theme_color_override("font_shadow_color", UI_AGED_INK)
badge.add_theme_constant_override("shadow_offset_x", 1)
badge.add_theme_constant_override("shadow_offset_y", 1)
badge.add_theme_font_size_override("font_size", 12)
badge.tooltip_text = tooltip_text
return badge
func _format_victory_result_text() -> String:
var lines := ["승리"]
_append_edict_clause(lines, "승리 조건", "완료", str(state.objectives.get("victory", "")))