Refine battle flow prompts and opening
This commit is contained in:
@@ -108,6 +108,7 @@ const HUD_UNIT_BADGE_ROW_SIZE := Vector2(320, 22)
|
||||
const HUD_UNIT_BADGE_SIZE := Vector2(26, 22)
|
||||
const HUD_UNIT_BAR_SIZE := Vector2(252, 12)
|
||||
const TOP_HUD_CHIP_ICON_SIZE := Vector2(28, 28)
|
||||
const SIDE_INFO_CHIP_ICON_SIZE := Vector2(26, 26)
|
||||
const HUD_COMMAND_GRID_SIZE := Vector2(420, 46)
|
||||
const HUD_COMMAND_BUTTON_SIZE := Vector2(72, 42)
|
||||
const HUD_COMMAND_GRID_COLUMNS := 4
|
||||
@@ -334,8 +335,10 @@ var hud_unit_hp_bar: ProgressBar
|
||||
var hud_unit_mp_bar: ProgressBar
|
||||
var selected_label: Label
|
||||
var cell_info_panel: PanelContainer
|
||||
var cell_info_icon: TextureRect
|
||||
var cell_info_label: Label
|
||||
var forecast_panel: PanelContainer
|
||||
var forecast_icon: TextureRect
|
||||
var forecast_label: Label
|
||||
var inventory_label: Label
|
||||
var briefing_panel: PanelContainer
|
||||
@@ -408,6 +411,11 @@ var result_seal_ribbon: HBoxContainer
|
||||
var result_choice_list: VBoxContainer
|
||||
var result_restart_button: Button
|
||||
var next_battle_button: Button
|
||||
var auto_end_turn_prompt_panel: PanelContainer
|
||||
var auto_end_turn_prompt_label: Label
|
||||
var auto_end_turn_yes_button: Button
|
||||
var auto_end_turn_no_button: Button
|
||||
var auto_end_turn_prompt_declined_turn := -1
|
||||
var end_turn_button: Button
|
||||
var wait_button: Button
|
||||
var tactic_button: Button
|
||||
@@ -1137,6 +1145,17 @@ func _make_top_hud_chip_icon(icon_kind: String) -> TextureRect:
|
||||
return icon
|
||||
|
||||
|
||||
func _make_side_info_chip_icon(icon_kind: String) -> TextureRect:
|
||||
var icon := TextureRect.new()
|
||||
icon.name = "SideInfoChipIcon"
|
||||
icon.custom_minimum_size = SIDE_INFO_CHIP_ICON_SIZE
|
||||
icon.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
icon.texture = _make_toolbar_icon(icon_kind)
|
||||
return icon
|
||||
|
||||
|
||||
func _set_top_hud_chip_tooltip(chip: PanelContainer, tooltip: String) -> void:
|
||||
if chip == null:
|
||||
return
|
||||
@@ -1183,6 +1202,21 @@ func _make_toolbar_icon(kind: String) -> Texture2D:
|
||||
_icon_rect(image, Rect2i(10, 15, 10, 2), Color(0.16, 0.07, 0.03, 1.0))
|
||||
_icon_rect(image, Rect2i(10, 20, 8, 2), Color(0.16, 0.07, 0.03, 1.0))
|
||||
_icon_circle(image, Vector2i(24, 9), 3, red)
|
||||
"terrain":
|
||||
_icon_line(image, Vector2i(5, 22), Vector2i(13, 12), shadow, 5)
|
||||
_icon_line(image, Vector2i(13, 12), Vector2i(18, 18), shadow, 5)
|
||||
_icon_line(image, Vector2i(18, 18), Vector2i(25, 8), shadow, 5)
|
||||
_icon_line(image, Vector2i(5, 22), Vector2i(13, 12), ink, 3)
|
||||
_icon_line(image, Vector2i(13, 12), Vector2i(18, 18), ink, 3)
|
||||
_icon_line(image, Vector2i(18, 18), Vector2i(25, 8), ink, 3)
|
||||
_icon_line(image, Vector2i(6, 24), Vector2i(26, 24), red, 3)
|
||||
"forecast":
|
||||
_icon_circle_outline(image, Vector2i(16, 16), 10, shadow, 4)
|
||||
_icon_circle_outline(image, Vector2i(16, 16), 10, ink, 2)
|
||||
_icon_line(image, Vector2i(6, 16), Vector2i(26, 16), red, 2)
|
||||
_icon_line(image, Vector2i(16, 6), Vector2i(16, 26), red, 2)
|
||||
_icon_circle(image, Vector2i(16, 16), 4, red)
|
||||
_icon_circle(image, Vector2i(16, 16), 2, ink)
|
||||
"move":
|
||||
_icon_line(image, Vector2i(8, 22), Vector2i(16, 9), shadow, 5)
|
||||
_icon_line(image, Vector2i(16, 9), Vector2i(24, 22), shadow, 5)
|
||||
@@ -1879,6 +1913,49 @@ func _create_hud() -> void:
|
||||
objective_notice_column.add_child(objective_notice_label)
|
||||
objective_notice_column.add_child(_make_scroll_rod(548, 3))
|
||||
|
||||
auto_end_turn_prompt_panel = PanelContainer.new()
|
||||
auto_end_turn_prompt_panel.name = "AutoEndTurnPrompt"
|
||||
auto_end_turn_prompt_panel.visible = false
|
||||
auto_end_turn_prompt_panel.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
auto_end_turn_prompt_panel.position = Vector2(408, 112)
|
||||
auto_end_turn_prompt_panel.size = Vector2(464, 154)
|
||||
auto_end_turn_prompt_panel.custom_minimum_size = Vector2(464, 154)
|
||||
_apply_panel_style(auto_end_turn_prompt_panel, "command_seal")
|
||||
root.add_child(auto_end_turn_prompt_panel)
|
||||
|
||||
var auto_end_column := VBoxContainer.new()
|
||||
auto_end_column.add_theme_constant_override("separation", 8)
|
||||
auto_end_turn_prompt_panel.add_child(auto_end_column)
|
||||
auto_end_column.add_child(_make_seal_ribbon(420, 10))
|
||||
|
||||
auto_end_turn_prompt_label = Label.new()
|
||||
auto_end_turn_prompt_label.text = "모든 아군이 군령을 마쳤습니다.\n차례를 넘기시겠습니까?"
|
||||
auto_end_turn_prompt_label.custom_minimum_size = Vector2(420, 56)
|
||||
auto_end_turn_prompt_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
auto_end_turn_prompt_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
auto_end_turn_prompt_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_apply_label_style(auto_end_turn_prompt_label, UI_PARCHMENT_TEXT, 17)
|
||||
auto_end_column.add_child(auto_end_turn_prompt_label)
|
||||
|
||||
var auto_end_button_row := HBoxContainer.new()
|
||||
auto_end_button_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
||||
auto_end_button_row.add_theme_constant_override("separation", 12)
|
||||
auto_end_column.add_child(auto_end_button_row)
|
||||
|
||||
auto_end_turn_yes_button = Button.new()
|
||||
auto_end_turn_yes_button.text = "예"
|
||||
auto_end_turn_yes_button.tooltip_text = "아군 차례를 마치고 적군 차례로 넘깁니다."
|
||||
auto_end_turn_yes_button.custom_minimum_size = Vector2(122, 38)
|
||||
auto_end_turn_yes_button.pressed.connect(_on_auto_end_turn_yes_pressed)
|
||||
auto_end_button_row.add_child(auto_end_turn_yes_button)
|
||||
|
||||
auto_end_turn_no_button = Button.new()
|
||||
auto_end_turn_no_button.text = "아니오"
|
||||
auto_end_turn_no_button.tooltip_text = "이번 차례에는 자동 확인을 닫습니다."
|
||||
auto_end_turn_no_button.custom_minimum_size = Vector2(122, 38)
|
||||
auto_end_turn_no_button.pressed.connect(_on_auto_end_turn_no_pressed)
|
||||
auto_end_button_row.add_child(auto_end_turn_no_button)
|
||||
|
||||
var side_panel := PanelContainer.new()
|
||||
side_panel.position = SIDE_PANEL_POSITION
|
||||
side_panel.size = SIDE_PANEL_SIZE
|
||||
@@ -1988,30 +2065,46 @@ func _create_hud() -> void:
|
||||
mission_detail_row.add_child(_make_bamboo_gutter(12, 112))
|
||||
|
||||
cell_info_panel = PanelContainer.new()
|
||||
cell_info_panel.name = "CellInfoChip"
|
||||
cell_info_panel.custom_minimum_size = Vector2(420, 58)
|
||||
cell_info_panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_apply_panel_style(cell_info_panel, "hud_info")
|
||||
side_column.add_child(cell_info_panel)
|
||||
|
||||
var cell_info_row := HBoxContainer.new()
|
||||
cell_info_row.add_theme_constant_override("separation", 8)
|
||||
cell_info_panel.add_child(cell_info_row)
|
||||
|
||||
cell_info_icon = _make_side_info_chip_icon("terrain")
|
||||
cell_info_row.add_child(cell_info_icon)
|
||||
|
||||
cell_info_label = Label.new()
|
||||
cell_info_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
cell_info_label.custom_minimum_size = Vector2(396, 38)
|
||||
cell_info_label.custom_minimum_size = Vector2(354, 38)
|
||||
cell_info_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_apply_label_style(cell_info_label, Color(0.92, 0.78, 0.54, 1.0), 12)
|
||||
cell_info_panel.add_child(cell_info_label)
|
||||
cell_info_row.add_child(cell_info_label)
|
||||
|
||||
forecast_panel = PanelContainer.new()
|
||||
forecast_panel.name = "ForecastChip"
|
||||
forecast_panel.custom_minimum_size = Vector2(420, 66)
|
||||
forecast_panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_apply_panel_style(forecast_panel, "hud_info")
|
||||
side_column.add_child(forecast_panel)
|
||||
|
||||
var forecast_row := HBoxContainer.new()
|
||||
forecast_row.add_theme_constant_override("separation", 8)
|
||||
forecast_panel.add_child(forecast_row)
|
||||
|
||||
forecast_icon = _make_side_info_chip_icon("forecast")
|
||||
forecast_row.add_child(forecast_icon)
|
||||
|
||||
forecast_label = Label.new()
|
||||
forecast_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
forecast_label.custom_minimum_size = Vector2(396, 46)
|
||||
forecast_label.custom_minimum_size = Vector2(354, 46)
|
||||
forecast_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
_apply_label_style(forecast_label, Color(0.95, 0.80, 0.56, 1.0), 13)
|
||||
forecast_panel.add_child(forecast_label)
|
||||
forecast_row.add_child(forecast_label)
|
||||
|
||||
inventory_label = Label.new()
|
||||
inventory_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
@@ -3113,6 +3206,9 @@ func _cancel_pending_move() -> bool:
|
||||
|
||||
|
||||
func _handle_cancel_input() -> bool:
|
||||
if _is_auto_end_turn_prompt_visible():
|
||||
_on_auto_end_turn_no_pressed()
|
||||
return true
|
||||
if _has_pending_move():
|
||||
return _cancel_pending_move()
|
||||
if post_move_picker_panel != null and post_move_picker_panel.visible:
|
||||
@@ -6483,6 +6579,63 @@ func _update_hud() -> void:
|
||||
_update_post_move_menu()
|
||||
_update_post_move_picker()
|
||||
_update_targeting_hint_panel()
|
||||
_update_auto_end_turn_prompt()
|
||||
|
||||
|
||||
func _update_auto_end_turn_prompt() -> void:
|
||||
if auto_end_turn_prompt_panel == null:
|
||||
return
|
||||
if _should_show_auto_end_turn_prompt():
|
||||
auto_end_turn_prompt_panel.visible = true
|
||||
return
|
||||
auto_end_turn_prompt_panel.visible = false
|
||||
|
||||
|
||||
func _should_show_auto_end_turn_prompt() -> bool:
|
||||
if campaign_complete_screen or not battle_started:
|
||||
return false
|
||||
if state.battle_status != BattleState.STATUS_ACTIVE:
|
||||
return false
|
||||
if state.current_team != BattleState.TEAM_PLAYER:
|
||||
return false
|
||||
if auto_end_turn_prompt_declined_turn == state.turn_number:
|
||||
return false
|
||||
if _is_dialogue_visible() or _has_active_battle_presentation_sequence():
|
||||
return false
|
||||
if briefing_panel != null and briefing_panel.visible:
|
||||
return false
|
||||
if result_panel != null and result_panel.visible:
|
||||
return false
|
||||
if _has_pending_move():
|
||||
return false
|
||||
if not selected_skill_id.is_empty() or not selected_item_id.is_empty() or basic_attack_targeting:
|
||||
return false
|
||||
if post_move_menu != null and post_move_menu.visible:
|
||||
return false
|
||||
if post_move_picker_panel != null and post_move_picker_panel.visible:
|
||||
return false
|
||||
if targeting_hint_panel != null and targeting_hint_panel.visible:
|
||||
return false
|
||||
return _all_controllable_player_units_acted()
|
||||
|
||||
|
||||
func _all_controllable_player_units_acted() -> bool:
|
||||
var has_active_unit := false
|
||||
for unit in state.units:
|
||||
if str(unit.get("team", "")) != BattleState.TEAM_PLAYER:
|
||||
continue
|
||||
if not bool(unit.get("alive", true)) or not bool(unit.get("deployed", true)):
|
||||
continue
|
||||
if not bool(unit.get("controllable", true)):
|
||||
continue
|
||||
has_active_unit = true
|
||||
if not bool(unit.get("acted", false)):
|
||||
return false
|
||||
return has_active_unit
|
||||
|
||||
|
||||
func _is_auto_end_turn_prompt_visible() -> bool:
|
||||
return auto_end_turn_prompt_panel != null and auto_end_turn_prompt_panel.visible
|
||||
|
||||
|
||||
func _format_status_hud_text() -> String:
|
||||
@@ -6874,17 +7027,21 @@ func _update_cell_info() -> void:
|
||||
if not state.is_inside(hover_cell):
|
||||
cell_info_label.text = ""
|
||||
cell_info_label.tooltip_text = "전장 칸 위에 올리면 지형과 부대 정보를 볼 수 있습니다."
|
||||
if cell_info_panel != null:
|
||||
_set_control_tree_tooltip(cell_info_panel, cell_info_label.tooltip_text)
|
||||
return
|
||||
var detail_text := _format_cell_info_detail_text(hover_cell)
|
||||
cell_info_label.text = _format_cell_info_summary_text(hover_cell)
|
||||
cell_info_label.tooltip_text = detail_text
|
||||
if cell_info_panel != null:
|
||||
_set_control_tree_tooltip(cell_info_panel, detail_text)
|
||||
|
||||
|
||||
func _format_cell_info_summary_text(cell: Vector2i) -> String:
|
||||
if not state.is_inside(cell):
|
||||
return ""
|
||||
var summary := state.get_cell_summary(cell)
|
||||
var text := "%s · 행군 %d · 방비 +%d · 회피 +%d%%" % [
|
||||
var text := "%s 행%d 방+%d 회+%d%%" % [
|
||||
_terrain_display_name(str(summary["terrain"])),
|
||||
int(summary["move_cost"]),
|
||||
int(summary["defense"]),
|
||||
@@ -6895,14 +7052,14 @@ func _format_cell_info_summary_text(cell: Vector2i) -> String:
|
||||
text += " · 회복 +%d" % heal
|
||||
var objective_cell_label := state.get_objective_cell_label(cell)
|
||||
if not objective_cell_label.is_empty():
|
||||
text += "\n목표: %s" % objective_cell_label
|
||||
text += "\n목표 %s" % objective_cell_label
|
||||
var event_marker_label := state.get_event_marker_label(cell)
|
||||
if not event_marker_label.is_empty():
|
||||
text += "\n표식: %s" % event_marker_label
|
||||
text += "\n표식 %s" % event_marker_label
|
||||
if show_threat_overlay:
|
||||
var threat_names := state.get_threatening_unit_names(cell, BattleState.TEAM_ENEMY)
|
||||
if not threat_names.is_empty():
|
||||
text += "\n감시: %s" % _compact_name_list(threat_names, 3)
|
||||
text += "\n감시 %s" % _compact_name_list(threat_names, 3)
|
||||
return text
|
||||
|
||||
|
||||
@@ -7043,7 +7200,7 @@ func _compact_name_list(names: Array[String], limit: int) -> String:
|
||||
func _update_forecast() -> void:
|
||||
var selected := state.get_selected_unit()
|
||||
if selected.is_empty() or not state.is_inside(hover_cell):
|
||||
forecast_label.text = "전황: -"
|
||||
_clear_forecast()
|
||||
return
|
||||
|
||||
if not selected_skill_id.is_empty():
|
||||
@@ -7055,22 +7212,22 @@ func _update_forecast() -> void:
|
||||
|
||||
var target := state.get_unit_at(hover_cell)
|
||||
if target.is_empty() or target.get("team", "") == selected.get("team", ""):
|
||||
forecast_label.text = "전황: -"
|
||||
_clear_forecast()
|
||||
return
|
||||
|
||||
var preview := state.get_damage_preview(selected["id"], target["id"])
|
||||
if preview.is_empty():
|
||||
forecast_label.text = "전황: -"
|
||||
_clear_forecast()
|
||||
return
|
||||
|
||||
if bool(preview.get("attack_locked", false)):
|
||||
forecast_label.text = "전황: 병장 봉인\n무기로 공격할 수 없습니다."
|
||||
_set_forecast_text("전황: 병장 봉인\n무기로 공격할 수 없습니다.")
|
||||
return
|
||||
|
||||
if not bool(preview.get("in_range", false)):
|
||||
var auto_attack_text := _format_auto_attack_forecast_text(selected, target)
|
||||
if not auto_attack_text.is_empty():
|
||||
forecast_label.text = auto_attack_text
|
||||
var auto_attack_detail := _format_auto_attack_forecast_text(selected, target)
|
||||
if not auto_attack_detail.is_empty():
|
||||
_set_forecast_text(auto_attack_detail)
|
||||
return
|
||||
|
||||
var range_text := "사거리 안" if preview["in_range"] else "사거리 밖"
|
||||
@@ -7091,7 +7248,7 @@ func _update_forecast() -> void:
|
||||
selected["max_hp"],
|
||||
counter_defeat
|
||||
]
|
||||
forecast_label.text = "전황: %s\n피해 %d%s, 명중 %d%%, 적 병력 %d/%d.%s%s" % [
|
||||
var detail_text := "전황: %s\n피해 %d%s, 명중 %d%%, 적 병력 %d/%d.%s%s" % [
|
||||
range_text,
|
||||
preview["damage"],
|
||||
effective_text + directional_text,
|
||||
@@ -7101,6 +7258,54 @@ func _update_forecast() -> void:
|
||||
defeat_text,
|
||||
counter_text
|
||||
]
|
||||
_set_forecast_text(detail_text)
|
||||
|
||||
|
||||
func _clear_forecast() -> void:
|
||||
if forecast_label == null:
|
||||
return
|
||||
forecast_label.text = "전황: -"
|
||||
forecast_label.tooltip_text = "공격, 책략, 도구 대상을 가리키면 전황 예측이 표시됩니다."
|
||||
if forecast_panel != null:
|
||||
_set_control_tree_tooltip(forecast_panel, forecast_label.tooltip_text)
|
||||
|
||||
|
||||
func _set_forecast_text(detail_text: String) -> void:
|
||||
if forecast_label == null:
|
||||
return
|
||||
var compact_text := _format_forecast_summary_text(detail_text)
|
||||
forecast_label.text = compact_text
|
||||
forecast_label.tooltip_text = detail_text
|
||||
if forecast_panel != null:
|
||||
_set_control_tree_tooltip(forecast_panel, detail_text)
|
||||
|
||||
|
||||
func _format_forecast_summary_text(detail_text: String) -> String:
|
||||
var lines := detail_text.split("\n", false)
|
||||
if lines.is_empty():
|
||||
return "전황: -"
|
||||
var first_line := str(lines[0]).strip_edges()
|
||||
var second_line := ""
|
||||
if lines.size() > 1:
|
||||
second_line = str(lines[1]).strip_edges()
|
||||
if first_line == "전황: -":
|
||||
return first_line
|
||||
if second_line.is_empty():
|
||||
return first_line
|
||||
var compact_second := second_line
|
||||
compact_second = compact_second.replace("피해 ", "피")
|
||||
compact_second = compact_second.replace("명중 ", "명")
|
||||
compact_second = compact_second.replace("기력 ", "기")
|
||||
compact_second = compact_second.replace("적 병력 ", "적")
|
||||
compact_second = compact_second.replace("아군 병력 ", "아")
|
||||
compact_second = compact_second.replace("지목 병력 ", "지목")
|
||||
compact_second = compact_second.replace("군기 병력 ", "군")
|
||||
compact_second = compact_second.replace("병력 ", "병")
|
||||
compact_second = compact_second.replace("회복", "회")
|
||||
compact_second = compact_second.replace(", ", " ")
|
||||
compact_second = compact_second.replace("; ", " ")
|
||||
compact_second = compact_second.replace(".", "")
|
||||
return "%s\n%s" % [first_line, _truncate_hud_text(compact_second, 34)]
|
||||
|
||||
|
||||
func _format_auto_attack_forecast_text(selected: Dictionary, target: Dictionary) -> String:
|
||||
@@ -7165,24 +7370,24 @@ func _format_directional_forecast_text(preview: Dictionary, bonus_key: String, l
|
||||
func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
var preview := state.get_skill_preview(selected["id"], selected_skill_id, hover_cell)
|
||||
if preview.is_empty():
|
||||
forecast_label.text = "전황: -"
|
||||
_clear_forecast()
|
||||
return
|
||||
|
||||
var range_text := "사거리 안" if preview["in_range"] else "사거리 밖"
|
||||
var mp_text := "" if preview["has_mp"] else " 기력이 부족합니다."
|
||||
if bool(preview.get("skill_locked", false)):
|
||||
forecast_label.text = "%s: 봉인, 기력 %d.\n책략을 펼칠 수 없습니다." % [
|
||||
_set_forecast_text("%s: 봉인, 기력 %d.\n책략을 펼칠 수 없습니다." % [
|
||||
preview["skill_name"],
|
||||
preview["mp_cost"]
|
||||
]
|
||||
])
|
||||
return
|
||||
if not preview["valid_target"]:
|
||||
forecast_label.text = "%s: %s, 기력 %d.%s\n지목할 대상이 없습니다." % [
|
||||
_set_forecast_text("%s: %s, 기력 %d.%s\n지목할 대상이 없습니다." % [
|
||||
preview["skill_name"],
|
||||
range_text,
|
||||
preview["mp_cost"],
|
||||
mp_text
|
||||
]
|
||||
])
|
||||
return
|
||||
|
||||
var target := state.get_unit(str(preview.get("target_id", "")))
|
||||
@@ -7193,7 +7398,7 @@ func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
if preview["kind"] == "heal":
|
||||
var total_heal := int(preview.get("total_heal", preview.get("heal", 0)))
|
||||
if not has_area:
|
||||
forecast_label.text = "%s: %s, 기력 %d.%s\n병력 %d 회복, 군기 병력 %d/%d." % [
|
||||
_set_forecast_text("%s: %s, 기력 %d.%s\n병력 %d 회복, 군기 병력 %d/%d." % [
|
||||
preview["skill_name"],
|
||||
range_text,
|
||||
preview["mp_cost"],
|
||||
@@ -7201,9 +7406,9 @@ func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
preview["heal"],
|
||||
preview["target_hp_after"],
|
||||
target_max_hp
|
||||
]
|
||||
])
|
||||
return
|
||||
forecast_label.text = "%s: %s, 기력 %d.%s%s\n총 병력 %d 회복, 지목 병력 %d/%d." % [
|
||||
_set_forecast_text("%s: %s, 기력 %d.%s%s\n총 병력 %d 회복, 지목 병력 %d/%d." % [
|
||||
preview["skill_name"],
|
||||
range_text,
|
||||
preview["mp_cost"],
|
||||
@@ -7212,10 +7417,10 @@ func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
total_heal,
|
||||
preview["target_hp_after"],
|
||||
target_max_hp
|
||||
]
|
||||
])
|
||||
elif preview["kind"] == "support":
|
||||
var refresh_text := " 갱신." if bool(preview.get("already_active", false)) else ""
|
||||
forecast_label.text = "%s: %s, 기력 %d.%s%s\n%s.%s" % [
|
||||
_set_forecast_text("%s: %s, 기력 %d.%s%s\n%s.%s" % [
|
||||
preview["skill_name"],
|
||||
range_text,
|
||||
preview["mp_cost"],
|
||||
@@ -7223,14 +7428,14 @@ func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
area_text,
|
||||
preview.get("effect_text", "지원"),
|
||||
refresh_text
|
||||
]
|
||||
])
|
||||
else:
|
||||
var defeat_count := int(preview.get("defeat_count", 0))
|
||||
var defeat_text := " 퇴각 %d군" % defeat_count if defeat_count > 0 else ""
|
||||
var total_damage := int(preview.get("total_damage", preview.get("damage", 0)))
|
||||
if not has_area:
|
||||
var single_defeat_text := " 퇴각" if bool(preview.get("would_defeat", false)) else ""
|
||||
forecast_label.text = "%s: %s, 기력 %d.%s\n피해 %d, 적 병력 %d/%d.%s" % [
|
||||
_set_forecast_text("%s: %s, 기력 %d.%s\n피해 %d, 적 병력 %d/%d.%s" % [
|
||||
preview["skill_name"],
|
||||
range_text,
|
||||
preview["mp_cost"],
|
||||
@@ -7239,9 +7444,9 @@ func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
preview["target_hp_after"],
|
||||
target_max_hp,
|
||||
single_defeat_text
|
||||
]
|
||||
])
|
||||
return
|
||||
forecast_label.text = "%s: %s, 기력 %d.%s%s\n총 피해 %d, 지목 병력 %d/%d.%s" % [
|
||||
_set_forecast_text("%s: %s, 기력 %d.%s%s\n총 피해 %d, 지목 병력 %d/%d.%s" % [
|
||||
preview["skill_name"],
|
||||
range_text,
|
||||
preview["mp_cost"],
|
||||
@@ -7251,35 +7456,35 @@ func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
preview["target_hp_after"],
|
||||
target_max_hp,
|
||||
defeat_text
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
func _update_item_forecast(selected: Dictionary) -> void:
|
||||
var preview := state.get_item_preview(selected["id"], selected_item_id, hover_cell)
|
||||
if preview.is_empty():
|
||||
forecast_label.text = "전황: -"
|
||||
_clear_forecast()
|
||||
return
|
||||
|
||||
var target := state.get_unit_at(hover_cell)
|
||||
var range_text := "사거리 안" if preview["in_range"] else "사거리 밖"
|
||||
var count_text := "잔량 %d" % int(preview.get("count", 0))
|
||||
if target.is_empty() or not preview["valid_target"]:
|
||||
forecast_label.text = "%s: %s, %s\n지목할 대상이 없습니다." % [
|
||||
_set_forecast_text("%s: %s, %s\n지목할 대상이 없습니다." % [
|
||||
preview["item_name"],
|
||||
range_text,
|
||||
count_text
|
||||
]
|
||||
])
|
||||
return
|
||||
|
||||
var hp_heal := int(preview.get("heal", 0))
|
||||
var mp_heal := int(preview.get("mp_heal", 0))
|
||||
var cure_statuses: Array = preview.get("cure_statuses", [])
|
||||
if hp_heal <= 0 and mp_heal <= 0 and cure_statuses.is_empty():
|
||||
forecast_label.text = "%s: %s, %s\n보급 효과가 필요하지 않습니다." % [
|
||||
_set_forecast_text("%s: %s, %s\n보급 효과가 필요하지 않습니다." % [
|
||||
preview["item_name"],
|
||||
range_text,
|
||||
count_text
|
||||
]
|
||||
])
|
||||
return
|
||||
|
||||
var recovery_parts := []
|
||||
@@ -7298,12 +7503,12 @@ func _update_item_forecast(selected: Dictionary) -> void:
|
||||
if not cure_statuses.is_empty():
|
||||
recovery_parts.append("치료 %s" % _join_strings(cure_statuses, ", "))
|
||||
|
||||
forecast_label.text = "%s: %s, %s\n%s." % [
|
||||
_set_forecast_text("%s: %s, %s\n%s." % [
|
||||
preview["item_name"],
|
||||
range_text,
|
||||
count_text,
|
||||
_join_strings(recovery_parts, "; ")
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
func _update_forecast_panel_visibility() -> void:
|
||||
@@ -7844,14 +8049,12 @@ func _update_dialogue_controls() -> void:
|
||||
dialogue_progress_label.text = "대화 %d/%d" % [active_dialogue_index + 1, active_dialogue_lines.size()]
|
||||
if dialogue_previous_button != null:
|
||||
dialogue_previous_button.disabled = active_dialogue_index <= 0
|
||||
dialogue_continue_button.text = "닫기" if active_dialogue_index >= active_dialogue_lines.size() - 1 else "다음"
|
||||
dialogue_continue_button.text = "다음"
|
||||
|
||||
|
||||
func _apply_dialogue_side(side: String) -> void:
|
||||
if dialogue_row == null or dialogue_portrait_panel == null or dialogue_column == null:
|
||||
return
|
||||
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
|
||||
|
||||
@@ -7987,6 +8190,21 @@ func _on_wait_pressed() -> void:
|
||||
_play_ui_confirm()
|
||||
|
||||
|
||||
func _on_auto_end_turn_yes_pressed() -> void:
|
||||
if auto_end_turn_prompt_panel != null:
|
||||
auto_end_turn_prompt_panel.visible = false
|
||||
_on_end_turn_pressed()
|
||||
|
||||
|
||||
func _on_auto_end_turn_no_pressed() -> void:
|
||||
auto_end_turn_prompt_declined_turn = state.turn_number
|
||||
if auto_end_turn_prompt_panel != null:
|
||||
auto_end_turn_prompt_panel.visible = false
|
||||
_play_ui_cancel()
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
|
||||
|
||||
func _on_end_turn_pressed() -> void:
|
||||
if state.can_player_act():
|
||||
_play_ui_confirm()
|
||||
@@ -10023,6 +10241,7 @@ func _is_input_locked() -> bool:
|
||||
return (
|
||||
campaign_complete_screen
|
||||
or _is_dialogue_visible()
|
||||
or _is_auto_end_turn_prompt_visible()
|
||||
or _has_active_battle_presentation_sequence()
|
||||
or not battle_started
|
||||
or state.battle_status != BattleState.STATUS_ACTIVE
|
||||
|
||||
Reference in New Issue
Block a user