Improve battle notice marker chips
This commit is contained in:
@@ -169,7 +169,7 @@ const TITLE_MENU_ICON_MAX_WIDTH := 42
|
|||||||
const OPENING_STORY_PROGRESS_CARD_SIZE := Vector2(50, 24)
|
const OPENING_STORY_PROGRESS_CARD_SIZE := Vector2(50, 24)
|
||||||
const OPENING_STORY_PROGRESS_KNOT_SIZE := Vector2(18, 18)
|
const OPENING_STORY_PROGRESS_KNOT_SIZE := Vector2(18, 18)
|
||||||
const COMMAND_NOTICE_ICON_SIZE := Vector2(32, 32)
|
const COMMAND_NOTICE_ICON_SIZE := Vector2(32, 32)
|
||||||
const COMMAND_NOTICE_MAX_ICONS := 4
|
const COMMAND_NOTICE_MAX_ICONS := 5
|
||||||
const CHAPTER_SEAL_BADGE_SIZE := Vector2(54, 54)
|
const CHAPTER_SEAL_BADGE_SIZE := Vector2(54, 54)
|
||||||
const CHAPTER_SCENARIO_THUMBNAIL_SIZE := Vector2(72, 50)
|
const CHAPTER_SCENARIO_THUMBNAIL_SIZE := Vector2(72, 50)
|
||||||
const CHAPTER_INFO_BADGE_SIZE := Vector2(86, 22)
|
const CHAPTER_INFO_BADGE_SIZE := Vector2(86, 22)
|
||||||
@@ -11220,18 +11220,15 @@ func _command_notice_icon_entries(title: String, body: String) -> Array[Dictiona
|
|||||||
var entries: Array[Dictionary] = []
|
var entries: Array[Dictionary] = []
|
||||||
var seen := {}
|
var seen := {}
|
||||||
var combined_text := "%s\n%s" % [title, body]
|
var combined_text := "%s\n%s" % [title, body]
|
||||||
if combined_text.contains("아군"):
|
var is_player_turn_notice := title.contains("아군") or body.contains("아군 차례")
|
||||||
|
var is_enemy_turn_notice := title.contains("적군") or body.contains("적군 차례")
|
||||||
|
if is_player_turn_notice:
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "move", "행군")
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "move", "행군")
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "attack", "타격")
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "attack", "타격")
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "wait", "대기")
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "wait", "대기")
|
||||||
elif combined_text.contains("적군"):
|
elif is_enemy_turn_notice:
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "threat", "적세")
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "threat", "적세")
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "forecast", "예측")
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "forecast", "예측")
|
||||||
if combined_text.contains("증원") or combined_text.contains("잔병") or combined_text.contains("약탈대") or combined_text.contains("잔당") or combined_text.contains("반격"):
|
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "threat", "적세")
|
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "status", "주의")
|
|
||||||
if combined_text.contains("경계") or combined_text.contains("표적") or combined_text.contains("노린다") or combined_text.contains("시선"):
|
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "threat", "적세")
|
|
||||||
if combined_text.contains("목표") or combined_text.contains("성채") or combined_text.contains("깃발"):
|
if combined_text.contains("목표") or combined_text.contains("성채") or combined_text.contains("깃발"):
|
||||||
_append_command_notice_icon_entry(entries, seen, "badge", "objective", "목표")
|
_append_command_notice_icon_entry(entries, seen, "badge", "objective", "목표")
|
||||||
if combined_text.contains("유인"):
|
if combined_text.contains("유인"):
|
||||||
@@ -11242,10 +11239,19 @@ func _command_notice_icon_entries(title: String, body: String) -> Array[Dictiona
|
|||||||
_append_command_notice_icon_entry(entries, seen, "badge", "recover", "회복")
|
_append_command_notice_icon_entry(entries, seen, "badge", "recover", "회복")
|
||||||
if combined_text.contains("군자금"):
|
if combined_text.contains("군자금"):
|
||||||
_append_command_notice_icon_entry(entries, seen, "badge", "gold", "군자금")
|
_append_command_notice_icon_entry(entries, seen, "badge", "gold", "군자금")
|
||||||
|
if combined_text.contains("증원") or combined_text.contains("잔병") or combined_text.contains("약탈대") or combined_text.contains("잔당") or combined_text.contains("반격"):
|
||||||
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "threat", "적세")
|
||||||
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "status", "주의")
|
||||||
|
if combined_text.contains("경계") or combined_text.contains("표적") or combined_text.contains("노린다") or combined_text.contains("시선"):
|
||||||
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "threat", "적세")
|
||||||
if combined_text.contains("퇴각") or combined_text.contains("주의"):
|
if combined_text.contains("퇴각") or combined_text.contains("주의"):
|
||||||
_append_command_notice_icon_entry(entries, seen, "toolbar", "status", "주의")
|
_append_command_notice_icon_entry(entries, seen, "toolbar", "status", "주의")
|
||||||
if entries.is_empty():
|
if entries.is_empty():
|
||||||
_append_command_notice_icon_entry(entries, seen, "badge", "event", "군령")
|
_append_command_notice_icon_entry(entries, seen, "badge", "event", "군령")
|
||||||
|
for index in range(entries.size()):
|
||||||
|
var entry := entries[index]
|
||||||
|
entry["tooltip"] = _command_notice_icon_entry_tooltip(entry, title, body)
|
||||||
|
entries[index] = entry
|
||||||
return entries
|
return entries
|
||||||
|
|
||||||
|
|
||||||
@@ -11265,9 +11271,11 @@ func _append_command_notice_icon_entry(entries: Array[Dictionary], seen: Diction
|
|||||||
|
|
||||||
func _make_command_notice_icon_chip(entry: Dictionary) -> PanelContainer:
|
func _make_command_notice_icon_chip(entry: Dictionary) -> PanelContainer:
|
||||||
var label_text := str(entry.get("label", "군령"))
|
var label_text := str(entry.get("label", "군령"))
|
||||||
|
var tooltip_text := str(entry.get("tooltip", label_text))
|
||||||
var chip := PanelContainer.new()
|
var chip := PanelContainer.new()
|
||||||
chip.name = "CommandNoticeIconChip"
|
chip.name = "CommandNoticeIconChip"
|
||||||
chip.custom_minimum_size = COMMAND_NOTICE_ICON_SIZE
|
chip.custom_minimum_size = COMMAND_NOTICE_ICON_SIZE
|
||||||
|
chip.tooltip_text = tooltip_text
|
||||||
chip.mouse_filter = Control.MOUSE_FILTER_PASS
|
chip.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
_apply_panel_style(chip, "caption")
|
_apply_panel_style(chip, "caption")
|
||||||
var chip_style := chip.get_theme_stylebox("panel")
|
var chip_style := chip.get_theme_stylebox("panel")
|
||||||
@@ -11277,16 +11285,41 @@ func _make_command_notice_icon_chip(entry: Dictionary) -> PanelContainer:
|
|||||||
chip_style.content_margin_top = 2
|
chip_style.content_margin_top = 2
|
||||||
chip_style.content_margin_bottom = 2
|
chip_style.content_margin_bottom = 2
|
||||||
|
|
||||||
|
chip.add_child(_make_command_notice_icon_art(entry, tooltip_text))
|
||||||
|
_set_control_tree_tooltip(chip, tooltip_text)
|
||||||
|
return chip
|
||||||
|
|
||||||
|
|
||||||
|
func _make_command_notice_icon_art(entry: Dictionary, tooltip_text: String) -> Control:
|
||||||
|
var stack := Control.new()
|
||||||
|
stack.name = "CommandNoticeIconArt"
|
||||||
|
stack.custom_minimum_size = COMMAND_NOTICE_ICON_SIZE
|
||||||
|
stack.tooltip_text = tooltip_text
|
||||||
|
stack.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
|
var source := str(entry.get("source", "toolbar"))
|
||||||
|
if source == "badge":
|
||||||
|
var marker_texture := _load_tile_marker_texture(_command_notice_tile_marker_key(str(entry.get("key", "event"))))
|
||||||
|
if marker_texture != null:
|
||||||
|
var marker_rect := TextureRect.new()
|
||||||
|
marker_rect.name = "CommandNoticeTileMarkerImage"
|
||||||
|
marker_rect.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
|
marker_rect.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
marker_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
marker_rect.modulate = Color(1.0, 1.0, 1.0, 0.42)
|
||||||
|
marker_rect.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
|
marker_rect.texture = marker_texture
|
||||||
|
marker_rect.tooltip_text = tooltip_text
|
||||||
|
stack.add_child(marker_rect)
|
||||||
var icon := TextureRect.new()
|
var icon := TextureRect.new()
|
||||||
icon.name = "CommandNoticeIconImage"
|
icon.name = "CommandNoticeIconImage"
|
||||||
icon.custom_minimum_size = COMMAND_NOTICE_ICON_SIZE
|
icon.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
icon.mouse_filter = Control.MOUSE_FILTER_PASS
|
icon.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
icon.texture = _command_notice_icon_texture(entry)
|
icon.texture = _command_notice_icon_texture(entry)
|
||||||
chip.add_child(icon)
|
icon.tooltip_text = tooltip_text
|
||||||
_set_control_tree_tooltip(chip, label_text)
|
stack.add_child(icon)
|
||||||
return chip
|
return stack
|
||||||
|
|
||||||
|
|
||||||
func _command_notice_icon_texture(entry: Dictionary) -> Texture2D:
|
func _command_notice_icon_texture(entry: Dictionary) -> Texture2D:
|
||||||
@@ -11297,6 +11330,61 @@ func _command_notice_icon_texture(entry: Dictionary) -> Texture2D:
|
|||||||
return _make_toolbar_icon(key)
|
return _make_toolbar_icon(key)
|
||||||
|
|
||||||
|
|
||||||
|
func _command_notice_tile_marker_key(key: String) -> String:
|
||||||
|
match key:
|
||||||
|
"objective":
|
||||||
|
return "objective"
|
||||||
|
"tactic":
|
||||||
|
return "target"
|
||||||
|
"supply":
|
||||||
|
return "recover"
|
||||||
|
"recover":
|
||||||
|
return "recover"
|
||||||
|
"gold":
|
||||||
|
return "select"
|
||||||
|
_:
|
||||||
|
return "select"
|
||||||
|
|
||||||
|
|
||||||
|
func _command_notice_icon_entry_tooltip(entry: Dictionary, title: String, body: String) -> String:
|
||||||
|
var label_text := str(entry.get("label", "군령"))
|
||||||
|
var key := str(entry.get("key", "status"))
|
||||||
|
var detail := ""
|
||||||
|
match key:
|
||||||
|
"objective":
|
||||||
|
detail = _first_notice_body_line(body, ["목표", "성채", "깃발"])
|
||||||
|
"status":
|
||||||
|
detail = _first_notice_body_line(body, ["주의", "퇴각", "위험", "패"])
|
||||||
|
"tactic":
|
||||||
|
detail = _first_notice_body_line(body, ["유인", "표식"])
|
||||||
|
"supply":
|
||||||
|
detail = _first_notice_body_line(body, ["보급", "마을"])
|
||||||
|
"recover":
|
||||||
|
detail = _first_notice_body_line(body, ["회복", "마을"])
|
||||||
|
"gold":
|
||||||
|
detail = _first_notice_body_line(body, ["군자금"])
|
||||||
|
"threat", "forecast":
|
||||||
|
detail = _first_notice_body_line(body, ["적군", "증원", "잔병", "경계", "표적", "주의"])
|
||||||
|
"move", "attack", "wait":
|
||||||
|
detail = _first_notice_body_line(body, ["아군", "군령", "차례"])
|
||||||
|
if detail.is_empty():
|
||||||
|
detail = body.strip_edges()
|
||||||
|
if detail.is_empty():
|
||||||
|
detail = title.strip_edges()
|
||||||
|
return "%s\n%s" % [label_text, _short_preview_text(detail, 110)]
|
||||||
|
|
||||||
|
|
||||||
|
func _first_notice_body_line(body: String, keywords: Array[String]) -> String:
|
||||||
|
for line in body.split("\n", false):
|
||||||
|
var normalized_line := str(line).strip_edges()
|
||||||
|
if normalized_line.is_empty():
|
||||||
|
continue
|
||||||
|
for keyword in keywords:
|
||||||
|
if normalized_line.contains(keyword):
|
||||||
|
return normalized_line
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
func _on_dialogue_requested(lines: Array) -> void:
|
func _on_dialogue_requested(lines: Array) -> void:
|
||||||
var normalized_lines := _normalized_dialogue_lines(lines)
|
var normalized_lines := _normalized_dialogue_lines(lines)
|
||||||
if normalized_lines.is_empty():
|
if normalized_lines.is_empty():
|
||||||
|
|||||||
@@ -580,6 +580,12 @@ func _check_battle_start_notice_sequence(failures: Array[String]) -> void:
|
|||||||
failures.append("battle start notice should not expose raw grid coordinates: %s" % start_notice_text)
|
failures.append("battle start notice should not expose raw grid coordinates: %s" % start_notice_text)
|
||||||
if scene.objective_notice_icon_strip == null or scene.objective_notice_icon_strip.get_child_count() < 3:
|
if scene.objective_notice_icon_strip == null or scene.objective_notice_icon_strip.get_child_count() < 3:
|
||||||
failures.append("battle start notice should use generated objective, warning, and marker icons")
|
failures.append("battle start notice should use generated objective, warning, and marker icons")
|
||||||
|
else:
|
||||||
|
var notice_icon_tooltips := _collect_tooltips(scene.objective_notice_icon_strip)
|
||||||
|
if not notice_icon_tooltips.contains("목표:") or not notice_icon_tooltips.contains("주의:") or not notice_icon_tooltips.contains("유인선") or not notice_icon_tooltips.contains("북숲 보급고") or not notice_icon_tooltips.contains("마을 보급"):
|
||||||
|
failures.append("battle start notice icon hover should explain objective, risk, and tactical markers: %s" % notice_icon_tooltips)
|
||||||
|
if _count_descendants_by_name(scene.objective_notice_icon_strip, "CommandNoticeTileMarkerImage") < 3:
|
||||||
|
failures.append("battle start marker notice chips should layer generated map marker art behind objective/tactic/supply icons")
|
||||||
scene.free()
|
scene.free()
|
||||||
|
|
||||||
|
|
||||||
@@ -1971,3 +1977,31 @@ func _check_pixel_unit_idle_state(scene, failures: Array[String]) -> void:
|
|||||||
failures.append("pixel idle clock should not advance while dialogue is visible")
|
failures.append("pixel idle clock should not advance while dialogue is visible")
|
||||||
scene.dialogue_panel.free()
|
scene.dialogue_panel.free()
|
||||||
scene.dialogue_panel = null
|
scene.dialogue_panel = null
|
||||||
|
|
||||||
|
|
||||||
|
func _collect_tooltips(root: Node) -> String:
|
||||||
|
var parts: Array[String] = []
|
||||||
|
_collect_tooltips_into(root, parts)
|
||||||
|
return "\n".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
func _collect_tooltips_into(root: Node, parts: Array[String]) -> void:
|
||||||
|
if root == null:
|
||||||
|
return
|
||||||
|
if root is Control:
|
||||||
|
var tooltip := str((root as Control).tooltip_text).strip_edges()
|
||||||
|
if not tooltip.is_empty():
|
||||||
|
parts.append(tooltip)
|
||||||
|
for child in root.get_children():
|
||||||
|
_collect_tooltips_into(child, parts)
|
||||||
|
|
||||||
|
|
||||||
|
func _count_descendants_by_name(root: Node, node_name: String) -> int:
|
||||||
|
if root == null:
|
||||||
|
return 0
|
||||||
|
var count := 0
|
||||||
|
for child in root.get_children():
|
||||||
|
if child.name == node_name:
|
||||||
|
count += 1
|
||||||
|
count += _count_descendants_by_name(child, node_name)
|
||||||
|
return count
|
||||||
|
|||||||
Reference in New Issue
Block a user