Improve tactical attack flow
This commit is contained in:
@@ -91,6 +91,9 @@ const SHOP_MERCHANT_BADGE_SIZE := Vector2(50, 50)
|
||||
const SHOP_ITEM_ICON_SIZE := Vector2(48, 48)
|
||||
const HUD_UNIT_PORTRAIT_SIZE := Vector2(92, 104)
|
||||
const HUD_UNIT_PORTRAIT_STACK_SIZE := Vector2(88, 100)
|
||||
const HUD_COMMAND_GRID_SIZE := Vector2(420, 70)
|
||||
const HUD_COMMAND_BUTTON_SIZE := Vector2(132, 30)
|
||||
const HUD_COMMAND_GRID_COLUMNS := 3
|
||||
const POST_MOVE_MENU_SIZE := Vector2(240, 146)
|
||||
const POST_MOVE_TITLE_SIZE := Vector2(196, 22)
|
||||
const POST_MOVE_PICKER_PANEL_SIZE := Vector2(336, 236)
|
||||
@@ -746,6 +749,14 @@ func _apply_button_style(button: Button, important: bool = false) -> void:
|
||||
_apply_control_font(button, important)
|
||||
|
||||
|
||||
func _configure_hud_command_button(button: Button) -> void:
|
||||
if button == null:
|
||||
return
|
||||
button.custom_minimum_size = HUD_COMMAND_BUTTON_SIZE
|
||||
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
button.add_theme_font_size_override("font_size", 13)
|
||||
|
||||
|
||||
func _apply_label_style(label: Label, font_color: Color, font_size: int = 0) -> void:
|
||||
if label == null:
|
||||
return
|
||||
@@ -1364,38 +1375,48 @@ func _create_hud() -> void:
|
||||
_apply_label_style(inventory_label, UI_PARCHMENT_TEXT)
|
||||
side_column.add_child(inventory_label)
|
||||
|
||||
var button_row := HBoxContainer.new()
|
||||
button_row.add_theme_constant_override("separation", 8)
|
||||
var button_row := GridContainer.new()
|
||||
button_row.name = "HudCommandGrid"
|
||||
button_row.columns = HUD_COMMAND_GRID_COLUMNS
|
||||
button_row.custom_minimum_size = HUD_COMMAND_GRID_SIZE
|
||||
button_row.add_theme_constant_override("h_separation", 6)
|
||||
button_row.add_theme_constant_override("v_separation", 5)
|
||||
side_column.add_child(button_row)
|
||||
|
||||
wait_button = Button.new()
|
||||
wait_button.text = "대기령"
|
||||
wait_button.text = "대기"
|
||||
_configure_hud_command_button(wait_button)
|
||||
wait_button.pressed.connect(_on_wait_pressed)
|
||||
button_row.add_child(wait_button)
|
||||
|
||||
tactic_button = Button.new()
|
||||
tactic_button.text = "책략첩"
|
||||
tactic_button.text = "책략"
|
||||
_configure_hud_command_button(tactic_button)
|
||||
tactic_button.pressed.connect(_on_tactic_pressed)
|
||||
button_row.add_child(tactic_button)
|
||||
|
||||
item_button = Button.new()
|
||||
item_button.text = "보급첩"
|
||||
item_button.text = "도구"
|
||||
_configure_hud_command_button(item_button)
|
||||
item_button.pressed.connect(_on_item_pressed)
|
||||
button_row.add_child(item_button)
|
||||
|
||||
equip_button = Button.new()
|
||||
equip_button.text = "병장"
|
||||
_configure_hud_command_button(equip_button)
|
||||
equip_button.pressed.connect(_on_equip_pressed)
|
||||
button_row.add_child(equip_button)
|
||||
|
||||
threat_button = Button.new()
|
||||
threat_button.text = "적진도"
|
||||
threat_button.text = "적정"
|
||||
_configure_hud_command_button(threat_button)
|
||||
threat_button.toggle_mode = true
|
||||
threat_button.pressed.connect(_on_threat_pressed)
|
||||
button_row.add_child(threat_button)
|
||||
|
||||
end_turn_button = Button.new()
|
||||
end_turn_button.text = "군령 봉함"
|
||||
end_turn_button.text = "차례 종료"
|
||||
_configure_hud_command_button(end_turn_button)
|
||||
end_turn_button.pressed.connect(_on_end_turn_pressed)
|
||||
button_row.add_child(end_turn_button)
|
||||
|
||||
@@ -2378,6 +2399,8 @@ func _handle_board_click(screen_position: Vector2) -> void:
|
||||
basic_attack_targeting = false
|
||||
_clear_pending_move_state()
|
||||
return
|
||||
if not _has_pending_move() and not basic_attack_targeting and _try_auto_move_attack(selected_unit, clicked_unit):
|
||||
return
|
||||
|
||||
if not clicked_unit.is_empty() and clicked_unit.get("team", "") == selected_unit.get("team", ""):
|
||||
if _has_pending_move():
|
||||
@@ -3135,7 +3158,7 @@ func _draw_units() -> void:
|
||||
|
||||
draw_circle(center + Vector2(0, 17), 20, Color(0.0, 0.0, 0.0, 0.30))
|
||||
_draw_unit_class_emblem(rect, center, unit, team_color)
|
||||
_draw_pixel_unit_sprite(rect, unit, team_color, sprite_modulate)
|
||||
_draw_pixel_unit_sprite(rect, unit, team_color, sprite_modulate, _unit_pixel_facing(unit))
|
||||
_draw_unit_identity_marks(rect, center, unit, team_color)
|
||||
_draw_unit_class_badge(rect, unit, team_color)
|
||||
|
||||
@@ -3186,12 +3209,14 @@ func _target_selection_marker_entries() -> Array[Dictionary]:
|
||||
return _skill_target_marker_entries()
|
||||
if not selected_item_id.is_empty():
|
||||
return _item_target_marker_entries()
|
||||
if not state.get_selected_unit().is_empty() and not _has_pending_move():
|
||||
return _attack_target_marker_entries()
|
||||
return []
|
||||
|
||||
|
||||
func _attack_target_marker_entries() -> Array[Dictionary]:
|
||||
var result: Array[Dictionary] = []
|
||||
if not basic_attack_targeting:
|
||||
if not basic_attack_targeting and _has_pending_move():
|
||||
return result
|
||||
var selected := state.get_selected_unit()
|
||||
if selected.is_empty():
|
||||
@@ -3270,6 +3295,96 @@ func _has_basic_attack_target(unit_id: String) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func _try_auto_move_attack(selected: Dictionary, target: Dictionary) -> bool:
|
||||
if selected.is_empty() or target.is_empty():
|
||||
return false
|
||||
if bool(selected.get("moved", false)) or bool(selected.get("acted", false)):
|
||||
return false
|
||||
if selected.get("team", "") == target.get("team", ""):
|
||||
return false
|
||||
var unit_id := str(selected.get("id", ""))
|
||||
var target_id := str(target.get("id", ""))
|
||||
if unit_id.is_empty() or target_id.is_empty():
|
||||
return false
|
||||
var attack_origin := _best_auto_attack_origin(selected, target)
|
||||
if attack_origin == Vector2i(-1, -1):
|
||||
return false
|
||||
|
||||
_play_ui_confirm()
|
||||
selected_skill_id = ""
|
||||
selected_item_id = ""
|
||||
basic_attack_targeting = false
|
||||
_hide_tactic_menu()
|
||||
_hide_item_menu()
|
||||
_hide_equip_menu()
|
||||
_hide_post_move_menu()
|
||||
_hide_post_move_picker()
|
||||
_hide_targeting_hint_panel()
|
||||
if selected.get("pos", Vector2i(-1, -1)) != attack_origin:
|
||||
if not state.try_move_selected(attack_origin, true):
|
||||
_refresh_ranges()
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
return false
|
||||
if not state.commit_pending_move_events(unit_id):
|
||||
_refresh_ranges()
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
return true
|
||||
if state.try_attack_selected(target_id):
|
||||
_clear_pending_move_state()
|
||||
_refresh_ranges()
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
return true
|
||||
_refresh_ranges()
|
||||
_update_hud()
|
||||
queue_redraw()
|
||||
return false
|
||||
|
||||
|
||||
func _best_auto_attack_origin(selected: Dictionary, target: Dictionary) -> Vector2i:
|
||||
var unit_id := str(selected.get("id", ""))
|
||||
if unit_id.is_empty():
|
||||
return Vector2i(-1, -1)
|
||||
var current_cell: Vector2i = selected.get("pos", Vector2i(-1, -1))
|
||||
var target_cell: Vector2i = target.get("pos", Vector2i(-1, -1))
|
||||
if not state.is_inside(current_cell) or not state.is_inside(target_cell):
|
||||
return Vector2i(-1, -1)
|
||||
var best_cell := Vector2i(-1, -1)
|
||||
var best_score := -999999
|
||||
for cell in state.get_movement_range(unit_id):
|
||||
if not state.is_inside(cell):
|
||||
continue
|
||||
if cell == target_cell:
|
||||
continue
|
||||
var blocker := state.get_unit_at(cell)
|
||||
if not blocker.is_empty() and str(blocker.get("id", "")) != unit_id:
|
||||
continue
|
||||
if not _can_attack_target_from(selected, cell, target_cell):
|
||||
continue
|
||||
var candidate_attacker := selected.duplicate(true)
|
||||
candidate_attacker["pos"] = cell
|
||||
var damage: int = state.calculate_damage(candidate_attacker, target)
|
||||
var move_distance: int = _manhattan(current_cell, cell)
|
||||
var score: int = damage * 20 - move_distance
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_cell = cell
|
||||
return best_cell
|
||||
|
||||
|
||||
func _can_attack_target_from(unit: Dictionary, origin: Vector2i, target_cell: Vector2i) -> bool:
|
||||
var attack_range: int = maxi(1, int(unit.get("range", 1)))
|
||||
var min_range: int = clampi(int(unit.get("min_range", mini(1, attack_range))), 1, attack_range)
|
||||
var distance: int = _manhattan(origin, target_cell)
|
||||
return distance >= min_range and distance <= attack_range
|
||||
|
||||
|
||||
func _manhattan(a: Vector2i, b: Vector2i) -> int:
|
||||
return absi(a.x - b.x) + absi(a.y - b.y)
|
||||
|
||||
|
||||
func _fit_texture_rect(texture: Texture2D, target: Rect2) -> Rect2:
|
||||
var texture_size := texture.get_size()
|
||||
if texture_size.x <= 0.0 or texture_size.y <= 0.0:
|
||||
@@ -3289,13 +3404,14 @@ func _unit_sprite_modulate(unit: Dictionary, acted: bool) -> Color:
|
||||
return Color.WHITE
|
||||
|
||||
|
||||
func _draw_pixel_unit_sprite(rect: Rect2, unit: Dictionary, team_color: Color, modulate: Color) -> void:
|
||||
func _draw_pixel_unit_sprite(rect: Rect2, unit: Dictionary, team_color: Color, modulate: Color, facing: int = 1) -> void:
|
||||
var profile := _pixel_unit_sprite_profile(unit)
|
||||
var family := str(profile.get("family", _unit_class_family(unit)))
|
||||
var phase := _unit_idle_phase(unit)
|
||||
var bob := _unit_idle_bob(family, phase)
|
||||
var step := _unit_idle_step(family, phase)
|
||||
var pixel := float(profile.get("pixel", 3.0))
|
||||
var safe_facing := -1 if facing < 0 else 1
|
||||
var origin := Vector2(roundf(rect.position.x + 12.0), roundf(rect.position.y + 5.0 + bob))
|
||||
var outline := _unit_pixel_color(Color(0.035, 0.026, 0.018, 1.0), modulate)
|
||||
var skin := _unit_pixel_color(Color(0.86, 0.62, 0.38, 1.0), modulate)
|
||||
@@ -3304,6 +3420,8 @@ func _draw_pixel_unit_sprite(rect: Rect2, unit: Dictionary, team_color: Color, m
|
||||
var class_color := _unit_pixel_color(_unit_class_badge_color(unit, team_color), modulate)
|
||||
var accent := _unit_pixel_color(Color(0.98, 0.76, 0.28, 1.0) if not str(unit.get("officer_id", "")).is_empty() else class_color.lightened(0.25), modulate)
|
||||
|
||||
if safe_facing < 0:
|
||||
draw_set_transform(Vector2(rect.position.x * 2.0 + TILE_SIZE, 0.0), 0.0, Vector2(-1.0, 1.0))
|
||||
_draw_pixel_rect(origin, 2, 11, 8, 2, pixel, Color(0.0, 0.0, 0.0, 0.22 * modulate.a))
|
||||
if family == "cavalry":
|
||||
_draw_pixel_cavalry(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
|
||||
@@ -3315,6 +3433,25 @@ func _draw_pixel_unit_sprite(rect: Rect2, unit: Dictionary, team_color: Color, m
|
||||
_draw_pixel_heavy(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
|
||||
else:
|
||||
_draw_pixel_infantry(origin, pixel, outline, skin, cloth, cloth_dark, class_color, accent, step)
|
||||
if safe_facing < 0:
|
||||
draw_set_transform(Vector2.ZERO, 0.0, Vector2.ONE)
|
||||
|
||||
|
||||
func _unit_pixel_facing(unit: Dictionary) -> int:
|
||||
var unit_id := str(unit.get("id", ""))
|
||||
if not unit_id.is_empty() and unit_action_motion_by_unit.has(unit_id):
|
||||
var action_motion: Dictionary = unit_action_motion_by_unit[unit_id]
|
||||
var from_cell: Vector2i = action_motion.get("from", unit.get("pos", Vector2i.ZERO))
|
||||
var to_cell: Vector2i = action_motion.get("to", from_cell)
|
||||
if to_cell.x < from_cell.x:
|
||||
return -1
|
||||
if to_cell.x > from_cell.x:
|
||||
return 1
|
||||
if unit.has("facing_x"):
|
||||
return state.unit_facing_x(unit)
|
||||
if unit.get("team", "") == BattleState.TEAM_ENEMY:
|
||||
return -1
|
||||
return 1
|
||||
|
||||
|
||||
func _unit_idle_phase(unit: Dictionary) -> float:
|
||||
@@ -4887,11 +5024,13 @@ func _format_physical_threat_preview_text(previews: Array[Dictionary], limit: in
|
||||
var effective_type := _format_move_type(str(preview.get("effective_target_type", "")))
|
||||
var effective_target_text := "" if effective_type.is_empty() else " 대 %s" % effective_type
|
||||
effective_text = " 특효 +%d%s" % [effective_bonus, effective_target_text]
|
||||
parts.append("%s 피해 %d/명중 %d%%%s%s" % [
|
||||
var directional_text := _format_directional_forecast_text(preview, "directional_bonus", "directional_label")
|
||||
parts.append("%s 피해 %d/명중 %d%%%s%s%s" % [
|
||||
str(preview.get("source_name", "부대")),
|
||||
int(preview.get("damage", 0)),
|
||||
int(preview.get("hit_chance", 0)),
|
||||
effective_text,
|
||||
directional_text,
|
||||
defeat_text
|
||||
])
|
||||
if previews.size() > safe_limit:
|
||||
@@ -4977,13 +5116,16 @@ func _update_forecast() -> void:
|
||||
var range_text := "사거리 안" if preview["in_range"] else "사거리 밖"
|
||||
var defeat_text := " 퇴각" if preview["would_defeat"] else ""
|
||||
var effective_text := _format_effective_forecast_text(preview, "effective_bonus", "effective_target_type")
|
||||
var directional_text := _format_directional_forecast_text(preview, "directional_bonus", "directional_label")
|
||||
var counter_text := ""
|
||||
if preview["counter_in_range"]:
|
||||
var counter_defeat := " 퇴각" if preview["counter_would_defeat"] else ""
|
||||
var counter_effective_text := _format_effective_forecast_text(preview, "counter_effective_bonus", "counter_effective_target_type")
|
||||
counter_text = "\n반격 %d%s, 명중 %d%%, 아군 병력 %d/%d.%s" % [
|
||||
var counter_directional_text := _format_directional_forecast_text(preview, "counter_directional_bonus", "counter_directional_label")
|
||||
counter_text = "\n반격 %d%s%s, 명중 %d%%, 아군 병력 %d/%d.%s" % [
|
||||
preview["counter_damage"],
|
||||
counter_effective_text,
|
||||
counter_directional_text,
|
||||
preview.get("counter_hit_chance", 0),
|
||||
preview["attacker_hp_after"],
|
||||
selected["max_hp"],
|
||||
@@ -4992,7 +5134,7 @@ func _update_forecast() -> void:
|
||||
forecast_label.text = "전황: %s\n피해 %d%s, 명중 %d%%, 적 병력 %d/%d.%s%s" % [
|
||||
range_text,
|
||||
preview["damage"],
|
||||
effective_text,
|
||||
effective_text + directional_text,
|
||||
preview.get("hit_chance", 100),
|
||||
preview["target_hp_after"],
|
||||
target["max_hp"],
|
||||
@@ -5011,6 +5153,16 @@ func _format_effective_forecast_text(preview: Dictionary, bonus_key: String, typ
|
||||
return " (특효 +%d 대 %s)" % [bonus, move_type]
|
||||
|
||||
|
||||
func _format_directional_forecast_text(preview: Dictionary, bonus_key: String, label_key: String) -> String:
|
||||
var bonus := int(preview.get(bonus_key, 0))
|
||||
if bonus <= 0:
|
||||
return ""
|
||||
var label := str(preview.get(label_key, "방향")).strip_edges()
|
||||
if label.is_empty():
|
||||
label = "방향"
|
||||
return " (%s +%d)" % [label, bonus]
|
||||
|
||||
|
||||
func _update_skill_forecast(selected: Dictionary) -> void:
|
||||
var preview := state.get_skill_preview(selected["id"], selected_skill_id, hover_cell)
|
||||
if preview.is_empty():
|
||||
@@ -8736,6 +8888,9 @@ func _is_targeting_mode() -> bool:
|
||||
func _show_targeting_hint_panel() -> void:
|
||||
if targeting_hint_panel == null:
|
||||
return
|
||||
if basic_attack_targeting:
|
||||
_hide_targeting_hint_panel()
|
||||
return
|
||||
_update_targeting_hint_panel()
|
||||
if targeting_hint_panel != null and _is_targeting_mode():
|
||||
targeting_hint_panel.visible = true
|
||||
@@ -8751,7 +8906,7 @@ func _hide_targeting_hint_panel() -> void:
|
||||
func _update_targeting_hint_panel() -> void:
|
||||
if targeting_hint_panel == null:
|
||||
return
|
||||
if not _is_targeting_mode():
|
||||
if basic_attack_targeting or not _is_targeting_mode():
|
||||
_hide_targeting_hint_panel()
|
||||
return
|
||||
var selected := state.get_selected_unit()
|
||||
@@ -8854,7 +9009,11 @@ func _set_action_button_state(button: Button, label: String, disabled: bool, too
|
||||
|
||||
|
||||
func _set_action_button_blocked(button: Button, base_label: String, reason_label: String, tooltip: String) -> void:
|
||||
_set_action_button_state(button, "%s|%s" % [base_label, reason_label], true, tooltip)
|
||||
var reason := reason_label.strip_edges()
|
||||
var blocked_tooltip := tooltip
|
||||
if not reason.is_empty():
|
||||
blocked_tooltip = "%s: %s" % [reason, tooltip] if not tooltip.strip_edges().is_empty() else reason
|
||||
_set_action_button_state(button, base_label, true, blocked_tooltip)
|
||||
|
||||
|
||||
func _action_phase_block_reason() -> Dictionary:
|
||||
@@ -8890,16 +9049,16 @@ func _update_wait_button(selected: Dictionary) -> void:
|
||||
if wait_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
_set_action_button_blocked(wait_button, "대기령", "부대 미지정", "명령할 부대를 먼저 고릅니다.")
|
||||
_set_action_button_blocked(wait_button, "대기", "부대 미지정", "명령할 부대를 먼저 고릅니다.")
|
||||
return
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(wait_button, "대기령", "봉인됨", "이 부대는 이미 행동했습니다.")
|
||||
_set_action_button_blocked(wait_button, "대기", "봉인됨", "이 부대는 이미 행동했습니다.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(wait_button, "대기령", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
_set_action_button_blocked(wait_button, "대기", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
_set_action_button_state(wait_button, "대기령", false, "이 부대의 군령을 봉인합니다.")
|
||||
_set_action_button_state(wait_button, "대기", false, "이 부대의 행동을 마칩니다.")
|
||||
|
||||
|
||||
func _update_end_turn_button() -> void:
|
||||
@@ -8907,9 +9066,9 @@ func _update_end_turn_button() -> void:
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(end_turn_button, "군령 봉함", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
_set_action_button_blocked(end_turn_button, "차례 종료", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
_set_action_button_state(end_turn_button, "군령 봉함", false, "아군 군령을 거두고 적군의 차례로 넘깁니다.")
|
||||
_set_action_button_state(end_turn_button, "차례 종료", false, "아군 차례를 마치고 적군에게 넘깁니다.")
|
||||
|
||||
|
||||
func _update_threat_button() -> void:
|
||||
@@ -8917,46 +9076,46 @@ func _update_threat_button() -> void:
|
||||
return
|
||||
threat_button.button_pressed = show_threat_overlay
|
||||
if campaign_complete_screen:
|
||||
_set_action_button_blocked(threat_button, "적진도", "전기 봉인", "전기가 완결되었습니다.")
|
||||
_set_action_button_blocked(threat_button, "적정", "전기 봉인", "전기가 완결되었습니다.")
|
||||
return
|
||||
if not battle_started:
|
||||
_set_action_button_blocked(threat_button, "적진도", "전장도 미개봉", "전장도를 펼친 뒤 적진을 살필 수 있습니다.")
|
||||
_set_action_button_blocked(threat_button, "적정", "전장도 미개봉", "전장도를 펼친 뒤 적진을 살필 수 있습니다.")
|
||||
return
|
||||
if state.battle_status != BattleState.STATUS_ACTIVE:
|
||||
_set_action_button_blocked(threat_button, "적진도", "전장 종결", "전투 중에만 적진을 살필 수 있습니다.")
|
||||
_set_action_button_blocked(threat_button, "적정", "전장 종결", "전투 중에만 적진을 살필 수 있습니다.")
|
||||
return
|
||||
_set_action_button_state(threat_button, "적진도", false, "적의 무기와 책략 사거리를 살핍니다.")
|
||||
_set_action_button_state(threat_button, "적정", false, "적의 무기와 책략 사거리를 살핍니다.")
|
||||
|
||||
|
||||
func _update_tactic_button(selected: Dictionary) -> void:
|
||||
if tactic_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
_set_action_button_blocked(tactic_button, "책략첩", "부대 미지정", "책략을 쓸 부대를 먼저 고릅니다.")
|
||||
_set_action_button_blocked(tactic_button, "책략", "부대 미지정", "책략을 쓸 부대를 먼저 고릅니다.")
|
||||
return
|
||||
|
||||
var skill_ids := state.get_skill_ids(selected["id"])
|
||||
if skill_ids.is_empty():
|
||||
_set_action_button_blocked(tactic_button, "책략첩", "없음", "이 부대는 사용할 책략이 없습니다.")
|
||||
_set_action_button_blocked(tactic_button, "책략", "없음", "이 부대는 사용할 책략이 없습니다.")
|
||||
return
|
||||
if state.is_unit_skill_sealed(selected["id"]):
|
||||
_set_action_button_blocked(tactic_button, "책략첩", "봉인됨", "이 부대는 책략을 쓸 수 없습니다.")
|
||||
_set_action_button_blocked(tactic_button, "책략", "봉인됨", "이 부대는 책략을 쓸 수 없습니다.")
|
||||
return
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(tactic_button, "책략첩", "봉인됨", "이 부대는 이미 행동했습니다.")
|
||||
_set_action_button_blocked(tactic_button, "책략", "봉인됨", "이 부대는 이미 행동했습니다.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(tactic_button, "책략첩", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
_set_action_button_blocked(tactic_button, "책략", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
|
||||
if not selected_skill_id.is_empty():
|
||||
var skill := state.get_skill_def(selected_skill_id)
|
||||
_set_action_button_state(tactic_button, "책략첩|%s" % str(skill.get("name", selected_skill_id)), false, "전장에 책략 대상을 지목합니다.")
|
||||
_set_action_button_state(tactic_button, "책략 선택", false, "%s 대상 지목." % str(skill.get("name", selected_skill_id)))
|
||||
elif tactic_menu != null and tactic_menu.visible:
|
||||
_set_action_button_state(tactic_button, "책략첩 봉함", false, "책략 목록을 닫습니다.")
|
||||
_set_action_button_state(tactic_button, "닫기", false, "책략 목록을 닫습니다.")
|
||||
else:
|
||||
_set_action_button_state(tactic_button, "책략첩", false, "책략 목록을 펼칩니다. %d개." % skill_ids.size())
|
||||
_set_action_button_state(tactic_button, "책략", false, "책략 목록을 펼칩니다. %d개." % skill_ids.size())
|
||||
|
||||
|
||||
func _show_tactic_menu(selected: Dictionary) -> void:
|
||||
@@ -9168,28 +9327,28 @@ func _update_item_button(selected: Dictionary) -> void:
|
||||
if item_button == null:
|
||||
return
|
||||
if selected.is_empty():
|
||||
_set_action_button_blocked(item_button, "보급첩", "부대 미지정", "도구를 쓸 부대를 먼저 고릅니다.")
|
||||
_set_action_button_blocked(item_button, "도구", "부대 미지정", "도구를 쓸 부대를 먼저 고릅니다.")
|
||||
return
|
||||
|
||||
if bool(selected.get("acted", false)):
|
||||
_set_action_button_blocked(item_button, "보급첩", "봉인됨", "이 부대는 이미 행동했습니다.")
|
||||
_set_action_button_blocked(item_button, "도구", "봉인됨", "이 부대는 이미 행동했습니다.")
|
||||
return
|
||||
var phase_block := _action_phase_block_reason()
|
||||
if not phase_block.is_empty():
|
||||
_set_action_button_blocked(item_button, "보급첩", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
_set_action_button_blocked(item_button, "도구", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
var item_ids := state.get_usable_item_ids()
|
||||
if item_ids.is_empty():
|
||||
_set_action_button_blocked(item_button, "보급첩", "비어 있음", "사용할 도구가 없습니다.")
|
||||
_set_action_button_blocked(item_button, "도구", "비어 있음", "사용할 도구가 없습니다.")
|
||||
return
|
||||
|
||||
if not selected_item_id.is_empty():
|
||||
var item := state.get_item_def(selected_item_id)
|
||||
_set_action_button_state(item_button, "보급첩|%s" % str(item.get("name", selected_item_id)), false, "전장에서 도구 대상을 지목합니다.")
|
||||
_set_action_button_state(item_button, "도구 선택", false, "%s 대상 지목." % str(item.get("name", selected_item_id)))
|
||||
elif item_menu != null and item_menu.visible:
|
||||
_set_action_button_state(item_button, "보급첩 봉함", false, "도구 목록을 닫습니다.")
|
||||
_set_action_button_state(item_button, "닫기", false, "도구 목록을 닫습니다.")
|
||||
else:
|
||||
_set_action_button_state(item_button, "보급첩", false, "도구 목록을 펼칩니다. %d종." % item_ids.size())
|
||||
_set_action_button_state(item_button, "도구", false, "도구 목록을 펼칩니다. %d종." % item_ids.size())
|
||||
|
||||
|
||||
func _show_item_menu(selected: Dictionary) -> void:
|
||||
@@ -9313,7 +9472,7 @@ func _update_equip_button(selected: Dictionary) -> void:
|
||||
_set_action_button_blocked(equip_button, "병장", str(phase_block.get("label", "처리 중")), str(phase_block.get("tooltip", "")))
|
||||
return
|
||||
if equip_menu != null and equip_menu.visible:
|
||||
_set_action_button_state(equip_button, "병장 닫기", false, "병장 장부를 닫습니다.")
|
||||
_set_action_button_state(equip_button, "닫기", false, "병장 장부를 닫습니다.")
|
||||
else:
|
||||
_set_action_button_state(equip_button, "병장", false, "행군 전에 무기, 갑옷, 장신구를 바꿉니다.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user