Localize Sishui gate and battle log tone

This commit is contained in:
2026-06-19 06:06:14 +09:00
parent 30ac2479c4
commit 0b599b39be
12 changed files with 314 additions and 190 deletions

View File

@@ -735,12 +735,12 @@ func try_cast_selected_skill(skill_id: String, target_cell: Vector2i) -> bool:
if caster.get("acted", false):
return false
if _unit_has_action_lock(caster, "skill"):
_emit_log("%s cannot use tactics while sealed." % caster["name"])
_emit_log("%s는 봉인되어 책략을 펼치지 못한다." % caster["name"])
return false
if not _unit_has_skill(caster, skill_id):
return false
if int(caster.get("mp", 0)) < int(skill.get("mp_cost", 0)):
_emit_log("%s does not have enough MP." % caster["name"])
_emit_log("%s의 기력이 모자라다." % caster["name"])
return false
if not _skill_cells_from(caster, skill).has(target_cell):
return false
@@ -749,9 +749,9 @@ func try_cast_selected_skill(skill_id: String, target_cell: Vector2i) -> bool:
var targets := _skill_targets_for_cast(caster, skill_id, skill, target_cell)
if targets.is_empty():
if skill_kind == "heal":
_emit_log("%s has no injured targets in range." % skill.get("name", "Skill"))
_emit_log("%s의 범위 안에 다친 아군이 없다." % skill.get("name", "책략"))
else:
_emit_log("%s has no valid targets." % skill.get("name", "Skill"))
_emit_log("%s의 표적이 없다." % skill.get("name", "책략"))
return false
if skill_kind == "support" and not _skill_has_support_effects(skill):
return false
@@ -795,7 +795,7 @@ func try_use_selected_item_on_cell(item_id: String, target_cell: Vector2i) -> bo
if user.get("acted", false):
return false
if int(battle_inventory.get(item_id, 0)) <= 0:
_emit_log("No %s remains." % item.get("name", item_id))
_emit_log("%s은 이미 다하였다." % _item_display_name(item_id))
return false
if str(item.get("kind", "")) != "consumable":
return false
@@ -814,7 +814,7 @@ func try_use_selected_item_on_cell(item_id: String, target_cell: Vector2i) -> bo
user["acted"] = true
user["moved"] = true
selected_unit_id = ""
_emit_log("%s uses %s on %s." % [user["name"], item.get("name", item_id), target["name"]])
_emit_log("%s 사용: %s -> %s." % [user["name"], _item_display_name(item_id), target["name"]])
_check_battle_status()
_notify_changed()
return true
@@ -1126,9 +1126,9 @@ func _resolve_skill_support(caster: Dictionary, target: Dictionary, skill_id: St
"remaining_phases": max(1, int(effect.get("duration_turns", 1)))
})
target["status_effects"] = status_effects
_emit_log("%s casts %s on %s. %s" % [
_emit_log("%s 시전 %s -> %s. %s" % [
caster["name"],
skill.get("name", "Skill"),
skill.get("name", "책략"),
target["name"],
_format_support_effects(skill)
])
@@ -1159,25 +1159,25 @@ func _format_support_effects(skill: Dictionary) -> String:
continue
var effect_type := str(effect.get("type", ""))
var duration: int = maxi(1, int(effect.get("duration_turns", 1)))
var duration_text := "next phase" if duration == 1 else "%d phases" % duration
var duration_text := _support_duration_text(duration)
if effect_type == "stat_bonus":
var stat := str(effect.get("stat", ""))
var amount := int(effect.get("amount", 0))
if not _is_supported_status_stat(stat) or amount == 0:
continue
var sign := "+" if amount > 0 else ""
parts.append("%s %s%d until %s" % [stat.to_upper(), sign, amount, duration_text])
parts.append("%s %s%d, %s 지속" % [_status_stat_display_name(stat), sign, amount, duration_text])
elif effect_type == "damage_over_time":
var damage := int(effect.get("amount", 0))
if damage <= 0:
continue
var status_name := _status_display_name(str(effect.get("status", "poison")))
parts.append("%s -%d HP for %s" % [status_name, damage, duration_text])
parts.append("%s -%d 병력, %s 지속" % [status_name, damage, duration_text])
elif effect_type == "action_lock":
var status_name := _status_display_name(str(effect.get("status", "status")))
parts.append("%s %s for %s" % [status_name, _action_lock_display_name(str(effect.get("action", ""))), duration_text])
parts.append("%s %s, %s 지속" % [status_name, _action_lock_display_name(str(effect.get("action", ""))), duration_text])
if parts.is_empty():
return "No support effect."
return "효험 없음"
return _join_strings(parts, ", ")
@@ -1193,15 +1193,15 @@ func _format_support_popup(skill: Dictionary) -> String:
if not _is_supported_status_stat(stat) or amount == 0:
continue
var sign := "+" if amount > 0 else ""
parts.append("%s %s%d" % [stat.to_upper(), sign, amount])
parts.append("%s %s%d" % [_status_stat_display_name(stat), sign, amount])
elif effect_type == "damage_over_time":
var damage := int(effect.get("amount", 0))
if damage > 0:
parts.append(_status_display_name(str(effect.get("status", "poison"))).to_upper())
parts.append(_status_display_name(str(effect.get("status", "poison"))))
elif effect_type == "action_lock":
parts.append(_status_display_name(str(effect.get("status", "status"))).to_upper())
parts.append(_status_display_name(str(effect.get("status", "status"))))
if parts.is_empty():
return "Support"
return "지원"
return _join_strings(parts, ", ")
@@ -1232,7 +1232,7 @@ func _format_active_status_effects(unit: Dictionary) -> String:
var duration_text := _format_status_remaining_phases(effect)
if effect_type == "damage_over_time":
if amount > 0:
parts.append("%s -%d HP %s" % [
parts.append("%s -%d 병력 %s" % [
_status_display_name(str(effect.get("status", "poison"))),
amount,
duration_text
@@ -1249,23 +1249,53 @@ func _format_active_status_effects(unit: Dictionary) -> String:
if not _is_supported_status_stat(stat) or amount == 0:
continue
var sign := "+" if amount > 0 else ""
parts.append("%s %s%d %s" % [stat.to_upper(), sign, amount, duration_text])
parts.append("%s %s%d %s" % [_status_stat_display_name(stat), sign, amount, duration_text])
return _join_strings(parts, ", ")
func _format_status_remaining_phases(effect: Dictionary) -> String:
var remaining: int = maxi(1, int(effect.get("remaining_phases", 1)))
var label := "phase" if remaining == 1 else "phases"
return "(%d %s)" % [remaining, label]
return "(%d회)" % remaining
func _status_display_name(status: String) -> String:
var normalized := status.strip_edges()
var normalized := status.strip_edges().to_lower()
if normalized.is_empty():
return "Status"
return "상태"
if normalized == "poison":
return ""
if normalized == "seal":
return "봉인"
if normalized == "snare":
return "발묶임"
if normalized == "disarm":
return "무장해제"
if normalized == "debuff":
return "약화"
return normalized.replace("_", " ").capitalize()
func _status_stat_display_name(stat: String) -> String:
var normalized := stat.strip_edges().to_lower()
if normalized == "atk":
return "무력"
if normalized == "def":
return "방비"
if normalized == "int":
return "지략"
if normalized == "agi":
return "순발"
if normalized == "move":
return "행군"
return normalized.to_upper()
func _support_duration_text(duration: int) -> String:
if duration <= 1:
return "다음 차례"
return "%d차례" % duration
func _is_supported_status_stat(stat: String) -> bool:
return stat == "atk" or stat == "def" or stat == "int" or stat == "agi" or stat == "move"
@@ -1282,12 +1312,12 @@ func _unit_has_action_lock(unit: Dictionary, action: String) -> bool:
func _action_lock_display_name(action: String) -> String:
if action == "skill":
return "no tactics"
return "책략 봉인"
if action == "move":
return "no movement"
return "행군 봉인"
if action == "attack":
return "no attacks"
return "no action"
return "타격 봉인"
return "행동 봉인"
func try_wait_selected() -> bool:
@@ -1300,7 +1330,7 @@ func try_wait_selected() -> bool:
unit["acted"] = true
unit["moved"] = true
selected_unit_id = ""
_emit_log("%s waits." % unit["name"])
_emit_log("%s 대기." % unit["name"])
_notify_changed()
return true
@@ -2290,12 +2320,12 @@ func _format_skill_threat_effect_summary(skill: Dictionary) -> String:
if not _is_supported_status_stat(stat) or amount == 0:
continue
var sign := "+" if amount > 0 else ""
parts.append("%s %s%d" % [stat.to_upper(), sign, amount])
parts.append("%s %s%d" % [_status_stat_display_name(stat), sign, amount])
elif effect_type == "damage_over_time":
var damage := int(effect.get("amount", 0))
if damage <= 0:
continue
parts.append("%s -%d HP" % [_status_display_name(str(effect.get("status", "poison"))), damage])
parts.append("%s -%d 병력" % [_status_display_name(str(effect.get("status", "poison"))), damage])
elif effect_type == "action_lock":
var status_name := _status_display_name(str(effect.get("status", "status")))
parts.append("%s %s" % [status_name, _action_lock_display_name(str(effect.get("action", "")))])
@@ -2518,28 +2548,28 @@ func _apply_item_effects(user: Dictionary, target: Dictionary, item: Dictionary)
var healed := _apply_item_heal(target, int(effect.get("amount", 0)))
if healed > 0:
applied = true
_emit_log("%s recovers %d HP." % [target["name"], healed])
_emit_combat_feedback(target, "+%d HP" % healed, "heal")
_emit_log("%s의 병력 %d 회복." % [target["name"], healed])
_emit_combat_feedback(target, "+%d 병력" % healed, "heal")
elif effect_type == "heal_mp":
var restored := _apply_item_mp_heal(target, int(effect.get("amount", 0)))
if restored > 0:
applied = true
_emit_log("%s recovers %d MP." % [target["name"], restored])
_emit_combat_feedback(target, "+%d MP" % restored, "mp")
_emit_log("%s의 기력 %d 회복." % [target["name"], restored])
_emit_combat_feedback(target, "+%d 기력" % restored, "mp")
elif effect_type == "cure_status":
var cured_statuses := _apply_item_status_cure(target, str(effect.get("status", "")))
if not cured_statuses.is_empty():
applied = true
_emit_log("%s is cured of %s." % [target["name"], _join_strings(cured_statuses, ", ")])
_emit_combat_feedback(target, "CURE", "support")
_emit_log("%s %s 해소." % [target["name"], _join_strings(cured_statuses, ", ")])
_emit_combat_feedback(target, "해소", "support")
elif effect_type == "cleanse_debuffs":
var cleansed_debuffs := _apply_item_debuff_cleanse(target)
if not cleansed_debuffs.is_empty():
applied = true
_emit_log("%s is cleansed of %s." % [target["name"], _join_strings(cleansed_debuffs, ", ")])
_emit_combat_feedback(target, "CLEANSE", "support")
_emit_log("%s의 약화 해소: %s." % [target["name"], _join_strings(cleansed_debuffs, ", ")])
_emit_combat_feedback(target, "정화", "support")
if not applied:
_emit_log("%s has no effect on %s." % [item.get("name", "Item"), target["name"]])
_emit_log("%s%s에게 효험이 없었다." % [str(item.get("name", "도구")), target["name"]])
return applied
@@ -2670,8 +2700,8 @@ func _is_negative_stat_bonus_effect(effect: Dictionary) -> bool:
func _stat_debuff_display_name(effect: Dictionary) -> String:
var stat := str(effect.get("stat", "stat"))
if not _is_supported_status_stat(stat):
return "Debuff"
return "%s down" % stat.to_upper()
return "약화"
return "%s 저하" % _status_stat_display_name(stat)
func _equipment_slot_for_item(item: Dictionary) -> String:
@@ -3184,7 +3214,7 @@ func _execute_ai_skill_action(caster: Dictionary, action: Dictionary) -> bool:
if _resolve_skill_damage(caster, area_target, skill):
defeated_count += 1
_grant_experience(caster, EXP_SKILL + defeated_count * EXP_DEFEAT_BONUS)
_emit_log("%s spends %d MP." % [caster["name"], int(skill.get("mp_cost", 0))])
_emit_log("%s 기력 %d 소모." % [caster["name"], int(skill.get("mp_cost", 0))])
return true
@@ -3230,7 +3260,7 @@ func _resolve_combat(attacker: Dictionary, target: Dictionary) -> void:
func _resolve_attack(attacker: Dictionary, target: Dictionary, is_counter := false) -> Dictionary:
var hit_chance := calculate_hit_chance(attacker, target)
var verb := "counterattacks" if is_counter else "attacks"
var verb := "반격" if is_counter else "공격"
unit_action_motion_requested.emit(
str(attacker.get("id", "")),
attacker.get("pos", Vector2i(-1, -1)),
@@ -3238,22 +3268,22 @@ func _resolve_attack(attacker: Dictionary, target: Dictionary, is_counter := fal
"counter" if is_counter else "attack"
)
if rng.randi_range(1, 100) > hit_chance:
_emit_log("%s %s %s but misses. Hit %d%%." % [attacker["name"], verb, target["name"], hit_chance])
_emit_combat_feedback(target, "MISS", "miss")
_emit_log("%s %s %s, 헛쳤다. 명중 %d%%." % [attacker["name"], verb, target["name"], hit_chance])
_emit_combat_feedback(target, "헛침", "miss")
return {"hit": false, "defeated": false}
var damage := calculate_damage(attacker, target)
target["hp"] = max(0, int(target["hp"]) - damage)
var effective_bonus := _weapon_effectiveness_bonus(attacker, target)
var effective_text := ""
if effective_bonus > 0:
effective_text = " Effective +%d vs %s." % [effective_bonus, _format_move_type(_weapon_effectiveness_target_type(target))]
_emit_log("%s %s %s for %d damage. Hit %d%%.%s" % [attacker["name"], verb, target["name"], damage, hit_chance, effective_text])
effective_text = " %s 특효 +%d." % [_format_move_type(_weapon_effectiveness_target_type(target)), effective_bonus]
_emit_log("%s %s %s, %d 피해. 명중 %d%%.%s" % [attacker["name"], verb, target["name"], damage, hit_chance, effective_text])
_emit_combat_feedback(target, "-%d" % damage, "damage")
if int(target["hp"]) <= 0:
target["alive"] = false
_emit_log("%s is defeated." % target["name"])
_emit_combat_feedback(target, "DOWN", "defeat")
_emit_log("%s 퇴각." % target["name"])
_emit_combat_feedback(target, "퇴각", "defeat")
_handle_unit_defeated(target)
return {"hit": true, "defeated": true}
return {"hit": true, "defeated": false}
@@ -3262,9 +3292,9 @@ func _resolve_attack(attacker: Dictionary, target: Dictionary, is_counter := fal
func _resolve_skill_damage(caster: Dictionary, target: Dictionary, skill: Dictionary) -> bool:
var damage := calculate_skill_damage(caster, target, skill)
target["hp"] = max(0, int(target["hp"]) - damage)
_emit_log("%s casts %s on %s for %d damage." % [
_emit_log("%s 시전 %s -> %s, %d 피해." % [
caster["name"],
skill.get("name", "Skill"),
skill.get("name", "책략"),
target["name"],
damage
])
@@ -3272,8 +3302,8 @@ func _resolve_skill_damage(caster: Dictionary, target: Dictionary, skill: Dictio
if int(target["hp"]) <= 0:
target["alive"] = false
_emit_log("%s is defeated." % target["name"])
_emit_combat_feedback(target, "DOWN", "defeat")
_emit_log("%s 퇴각." % target["name"])
_emit_combat_feedback(target, "퇴각", "defeat")
_handle_unit_defeated(target)
return true
return false
@@ -3299,13 +3329,13 @@ func _handle_unit_defeated(unit: Dictionary) -> void:
func _resolve_skill_heal(caster: Dictionary, target: Dictionary, skill: Dictionary) -> int:
var healed := calculate_skill_heal(caster, target, skill)
target["hp"] = min(int(target["max_hp"]), int(target["hp"]) + healed)
_emit_log("%s casts %s on %s, restoring %d HP." % [
_emit_log("%s 시전 %s -> %s, 병력 %d 회복." % [
caster["name"],
skill.get("name", "Skill"),
skill.get("name", "책략"),
target["name"],
healed
])
_emit_combat_feedback(target, "+%d HP" % healed, "heal")
_emit_combat_feedback(target, "+%d 병력" % healed, "heal")
return healed
@@ -3313,7 +3343,7 @@ func _grant_experience(unit: Dictionary, amount: int) -> void:
if unit.is_empty() or not unit.get("alive", false) or amount <= 0:
return
unit["exp"] = int(unit.get("exp", 0)) + amount
_emit_log("%s gains %d EXP." % [unit["name"], amount])
_emit_log("%s 공적 +%d." % [unit["name"], amount])
while int(unit["exp"]) >= EXP_LEVEL:
unit["exp"] = int(unit["exp"]) - EXP_LEVEL
_level_up(unit)
@@ -3330,7 +3360,7 @@ func _level_up(unit: Dictionary) -> void:
unit["mp"] = min(int(unit["max_mp"]), int(unit.get("mp", 0)) + mp_gain)
for stat in ["atk", "def", "int", "agi"]:
unit[stat] = int(unit.get(stat, 0)) + _growth_gain(unit, stat, 1)
_emit_log("%s reaches Lv.%d." % [unit["name"], unit["level"]])
_emit_log("%s Lv.%d에 이르렀다." % [unit["name"], unit["level"]])
_emit_combat_feedback(unit, "Lv.%d" % int(unit["level"]), "progress")
if str(unit.get("team", "")) == TEAM_PLAYER:
_record_progression_event({
@@ -3414,12 +3444,12 @@ func _check_battle_status() -> void:
battle_status = STATUS_DEFEAT
current_team = TEAM_PLAYER
selected_unit_id = ""
_emit_log("Defeat condition met.")
_emit_log("패전의 조짐이 굳어졌다.")
elif _is_condition_group_met(battle_conditions.get("victory", {})):
battle_status = STATUS_VICTORY
current_team = TEAM_PLAYER
selected_unit_id = ""
_emit_log("Victory condition met.")
_emit_log("승전의 군령이 이루어졌다.")
func _is_condition_group_met(condition_group) -> bool:
@@ -4051,9 +4081,9 @@ func _grant_event_item(action: Dictionary, trigger_unit: Dictionary = {}) -> boo
return false
var count: int = maxi(1, int(action.get("count", 1)))
battle_inventory[item_id] = int(battle_inventory.get(item_id, 0)) + count
var item_name: String = str(item.get("name", item_id))
var item_name: String = _item_display_name(item_id)
var count_text: String = "" if count == 1 else " x%d" % count
_emit_log("Received %s%s." % [item_name, count_text])
_emit_log("전리품: %s%s." % [item_name, count_text])
if not trigger_unit.is_empty() and bool(trigger_unit.get("alive", false)):
_emit_combat_feedback(trigger_unit, "+%s" % item_name, "item")
return true
@@ -4067,7 +4097,7 @@ func _grant_event_gold(action: Dictionary, trigger_unit: Dictionary = {}) -> boo
battle_gold_reward += amount
var text := str(action.get("text", "")).strip_edges()
if text.is_empty():
text = "Received %d gold." % amount
text = "군자금: %dG." % amount
_emit_log(text)
if not trigger_unit.is_empty() and bool(trigger_unit.get("alive", false)):
_emit_combat_feedback(trigger_unit, "+%dG" % amount, "gold")
@@ -4230,11 +4260,11 @@ func _withdraw_event_unit(unit_id: String) -> bool:
return false
if selected_unit_id == normalized_id:
selected_unit_id = ""
_emit_combat_feedback(unit, "WITHDRAW", "fade")
_emit_combat_feedback(unit, "퇴각", "fade")
unit["deployed"] = false
unit["acted"] = true
unit["moved"] = true
_emit_log("%s withdraws from the battlefield." % unit.get("name", normalized_id))
_emit_log("%s 전장을 물러났다." % unit.get("name", normalized_id))
_notify_changed()
return true
@@ -4263,12 +4293,13 @@ func _apply_phase_status_effects_for_team(team: String) -> void:
continue
unit["hp"] = max(0, int(unit.get("hp", 0)) - damage)
var status := str(effect.get("status", "poison"))
_emit_log("%s suffers %d %s damage." % [unit["name"], damage, status.replace("_", " ")])
var status_name := _status_display_name(status)
_emit_log("%s, %s으로 병력 %d 손실." % [unit["name"], status_name, damage])
_emit_combat_feedback(unit, "-%d" % damage, status)
if int(unit.get("hp", 0)) <= 0:
unit["alive"] = false
_emit_log("%s is defeated by %s." % [unit["name"], status.replace("_", " ")])
_emit_combat_feedback(unit, "DOWN", "defeat")
_emit_log("%s, %s으로 퇴각." % [unit["name"], status_name])
_emit_combat_feedback(unit, "퇴각", "defeat")
_handle_unit_defeated(unit)
break
@@ -4288,13 +4319,13 @@ func _expire_status_effects_for_team(team: String) -> void:
kept_effect["remaining_phases"] = next_remaining
kept_effects.append(kept_effect)
else:
var effect_name := str(effect.get("name", "Support"))
var effect_name := str(effect.get("name", "지원"))
if not expired_names.has(effect_name):
expired_names.append(effect_name)
unit["status_effects"] = kept_effects
for expired_effect_name in expired_names:
_emit_log("%s's %s fades." % [unit["name"], expired_effect_name])
_emit_combat_feedback(unit, "FADES", "fade")
_emit_log("%s %s이 사라졌다." % [unit["name"], expired_effect_name])
_emit_combat_feedback(unit, "해제", "fade")
func _manhattan(a: Vector2i, b: Vector2i) -> int:
@@ -4316,6 +4347,47 @@ func _format_cells(cells: Array[Vector2i]) -> String:
return _join_strings(labels, ", ")
func _item_display_name(item_id: String) -> String:
match item_id:
"bronze_sword":
return "청동검"
"iron_sword":
return "철검"
"training_spear":
return "연습창"
"short_bow":
return "단궁"
"hand_axe":
return "손도끼"
"war_axe":
return "전부"
"war_drum":
return "전고"
"imperial_seal":
return "옥새"
"yitian_sword":
return "의천검"
"dragon_spear":
return "용담창"
"wind_chaser_bow":
return "추풍궁"
"black_tortoise_robe":
return "현무도포"
"bean":
return ""
"antidote":
return "해독약"
"panacea":
return "만능약"
"wine":
return ""
_:
var item := get_item_def(item_id)
if item.is_empty():
return item_id
return str(item.get("name", item_id))
func _join_strings(values: Array, delimiter: String) -> String:
var text := ""
for value in values:

View File

@@ -1645,25 +1645,25 @@ func _play_ui_cancel() -> void:
func _play_log_sfx(message: String) -> void:
if message.contains(" but misses."):
if message.contains(" but misses.") or message.contains("헛쳤다"):
_play_sfx("guard_block")
elif message.begins_with("Objective updated:") or message.begins_with("Defeat condition updated:"):
elif message.begins_with("Objective updated:") or message.begins_with("Defeat condition updated:") or message.begins_with("군령 갱신:") or message.begins_with("패전 군령 갱신:"):
_play_ui_confirm()
elif message.ends_with(" withdraws from the battlefield."):
elif message.ends_with(" withdraws from the battlefield.") or message.ends_with("전장을 물러났다."):
_play_ui_confirm()
elif message.contains(" attacks ") or message.contains(" counterattacks "):
if message.contains(" for "):
elif message.contains(" attacks ") or message.contains(" counterattacks ") or message.contains(" 공격 ") or message.contains(" 반격 "):
if message.contains(" for ") or message.contains("피해"):
_play_sfx("hit_heavy")
elif message.contains(" casts "):
if message.contains("restoring") or message.contains(" until "):
elif message.contains(" casts ") or message.contains(" 시전 "):
if message.contains("restoring") or message.contains(" until ") or message.contains("회복") or message.contains("지원"):
_play_sfx("skill_cast")
else:
_play_sfx("fire_skill")
elif message.contains(" moved to ") or message.contains(" advances to ") or message.contains(" takes formation at ") or message.contains(" arrives at "):
_play_sfx("footstep")
elif message.contains(" uses ") or message.contains(" equips ") or message.contains(" 매입:") or message.contains(" 매각:") or message.begins_with("Received "):
elif message.contains(" uses ") or message.contains(" equips ") or message.contains(" 사용:") or message.contains(" 장착:") or message.contains(" 매입:") or message.contains(" 매각:") or message.begins_with("Received ") or message.begins_with("전리품:") or message.begins_with("군자금:"):
_play_sfx("item_pickup")
elif message.contains(" reaches Lv.") or message.contains(" promotes to "):
elif message.contains(" reaches Lv.") or message.contains(" promotes to ") or message.contains("공적") or message.contains("승급"):
_play_sfx("menu_confirm")
@@ -3056,9 +3056,9 @@ func _skill_target_preview_badge_for_cell(selected: Dictionary, target: Dictiona
return _make_target_preview_badge_at("가득", "invalid", cell)
if bool(preview.get("has_area", false)):
return _make_target_preview_badge_at("+%d x%d" % [total_heal, target_count], "heal", cell)
return _make_target_preview_badge_at("+%d HP" % heal, "heal", cell)
return _make_target_preview_badge_at("+%d 병력" % heal, "heal", cell)
if kind == "support":
var effect_text := str(preview.get("effect_text", "Support"))
var effect_text := str(preview.get("effect_text", "지원"))
var badge_kind := _support_preview_badge_kind(effect_text)
if bool(preview.get("has_area", false)):
return _make_target_preview_badge_at("%s x%d" % [_compact_support_preview_text(effect_text), target_count], badge_kind, cell)
@@ -3099,8 +3099,8 @@ func _item_target_preview_badge_for_cell(selected: Dictionary, target: Dictionar
if hp_heal > 0 and mp_heal > 0:
return _make_target_preview_badge_at("+%d/%d" % [hp_heal, mp_heal], "heal", cell)
if hp_heal > 0:
return _make_target_preview_badge_at("+%d HP" % hp_heal, "heal", cell)
return _make_target_preview_badge_at("+%d MP" % mp_heal, "mp", cell)
return _make_target_preview_badge_at("+%d 병력" % hp_heal, "heal", cell)
return _make_target_preview_badge_at("+%d 기력" % mp_heal, "mp", cell)
func _hover_intent_preview_badge(selected: Dictionary, target: Dictionary) -> Dictionary:
@@ -3145,7 +3145,10 @@ func _compact_support_preview_text(effect_text: String) -> String:
var for_index := part.find(" for ")
if for_index >= 0:
part = part.substr(0, for_index)
if not part.is_empty() and part != "No support effect.":
var duration_index := part.find(", ")
if duration_index >= 0:
part = part.substr(0, duration_index)
if not part.is_empty() and part != "No support effect." and part != "효험 없음":
parts.append(_compact_support_badge_text(part))
if parts.is_empty():
return "지원"
@@ -3155,27 +3158,27 @@ func _compact_support_preview_text(effect_text: String) -> String:
func _compact_support_badge_text(text: String) -> String:
if text.contains("Disarm"):
if text.contains("Disarm") or text.contains("무장해제"):
return "무장해제"
if text.contains("Snare"):
if text.contains("Snare") or text.contains("발묶임"):
return "속박"
if text.contains("Seal"):
if text.contains("Seal") or text.contains("봉인"):
return "봉인"
if text.contains("Poison"):
if text.contains("Poison") or text.contains(""):
return ""
if text.contains("Cleanse"):
if text.contains("Cleanse") or text.contains("해소"):
return "해소"
return text
func _support_preview_badge_kind(effect_text: String) -> String:
if effect_text.contains("Disarm"):
if effect_text.contains("Disarm") or effect_text.contains("무장해제"):
return "disarm"
if effect_text.contains("Snare"):
if effect_text.contains("Snare") or effect_text.contains("발묶임"):
return "snare"
if effect_text.contains("Seal"):
if effect_text.contains("Seal") or effect_text.contains("봉인"):
return "seal"
if effect_text.contains("Poison"):
if effect_text.contains("Poison") or effect_text.contains(""):
return "poison"
if effect_text.contains("-"):
return "debuff"
@@ -3805,7 +3808,7 @@ func _update_skill_forecast(selected: Dictionary) -> void:
preview["mp_cost"],
mp_text,
area_text,
preview.get("effect_text", "Support effect"),
preview.get("effect_text", "지원"),
refresh_text
]
else:
@@ -4617,7 +4620,7 @@ func _load_pending_post_battle_choice() -> void:
if briefing_panel != null:
briefing_panel.visible = false
if log_box != null:
log_box.append_text("Campaign choice pending.\n")
log_box.append_text("군의 논의가 이어지고 있다.\n")
func _load_scenario(scenario_id: String) -> void:
@@ -6426,10 +6429,10 @@ func _on_post_battle_choice_pressed(choice: Dictionary) -> void:
_append_result_items(choice.get("items", []))
_append_unique_result_values("joined_officers", choice.get("join_officers", []))
_append_unique_result_values("left_officers", choice.get("leave_officers", []))
_on_log_added("Campaign choice saved: %s." % battle_result_summary["choice_label"])
_on_log_added("군령 채택: %s." % battle_result_summary["choice_label"])
else:
_play_ui_cancel()
_on_log_added("Could not save campaign choice.")
_on_log_added("군령을 봉하지 못했다.")
_rebuild_result_choices()
_update_result_next_button_visibility()
if result_label != null and state.battle_status == BattleState.STATUS_VICTORY:
@@ -6825,7 +6828,7 @@ func _show_campaign_complete() -> void:
if briefing_panel != null:
briefing_panel.visible = false
if log_box != null:
log_box.append_text("Campaign complete.\n")
log_box.append_text("전기가 여기서 매듭지어졌다.\n")
func _on_new_campaign_pressed() -> void:
@@ -7109,7 +7112,7 @@ func _format_post_move_tactic_button_text(skill_id: String, skill: Dictionary, s
func _format_post_move_item_button_text(item_id: String, item: Dictionary, count: int) -> String:
var marker := "> " if selected_item_id == item_id else ""
var item_name := str(item.get("name", item_id))
var item_name := _item_display_name(item_id)
return "%s%s x%d %s" % [marker, item_name, count, _format_post_move_item_effect_text(item)]
@@ -7545,13 +7548,13 @@ func _format_tactic_effect_text(skill: Dictionary) -> String:
if amount == 0:
continue
var sign := "+" if amount > 0 else ""
parts.append("%s %s%d" % [str(effect.get("stat", "")).to_upper(), sign, amount])
parts.append("%s %s%d" % [_battle_stat_display_name(str(effect.get("stat", ""))), sign, amount])
elif effect_type == "damage_over_time" and amount > 0:
var status_name := str(effect.get("status", "status")).replace("_", " ").capitalize()
var status_name := _battle_status_display_name(str(effect.get("status", "status")))
parts.append("%s -%d" % [status_name, amount])
elif effect_type == "action_lock":
parts.append("%s %s" % [
str(effect.get("status", "status")).replace("_", " ").capitalize(),
_battle_status_display_name(str(effect.get("status", "status"))),
_action_lock_effect_label(str(effect.get("action", "")))
])
if not parts.is_empty():
@@ -7592,6 +7595,42 @@ func _action_lock_effect_label(action: String) -> String:
return "군령 봉인"
func _battle_stat_display_name(stat: String) -> String:
var normalized := stat.strip_edges().to_lower()
if normalized == "hp":
return "병력"
if normalized == "mp":
return "기력"
if normalized == "atk":
return "무력"
if normalized == "def":
return "방비"
if normalized == "int":
return "지략"
if normalized == "agi":
return "순발"
if normalized == "move":
return "행군"
return _format_identifier_label(stat)
func _battle_status_display_name(status: String) -> String:
var normalized := status.strip_edges().to_lower()
if normalized == "poison":
return ""
if normalized == "seal":
return "봉인"
if normalized == "snare":
return "발묶임"
if normalized == "disarm":
return "무장해제"
if normalized == "debuff":
return "약화"
if normalized.is_empty():
return "상태"
return _format_identifier_label(status)
func _skill_kind_text(kind: String) -> String:
var normalized := kind.strip_edges().to_lower()
if normalized == "damage":
@@ -7714,7 +7753,7 @@ func _clear_item_list() -> void:
func _format_item_button_text(item_id: String, item: Dictionary, count: int) -> String:
var marker := "> " if selected_item_id == item_id else ""
var item_name := str(item.get("name", item_id))
var item_name := _item_display_name(item_id)
return "%s%s x%d %s" % [marker, item_name, count, _format_item_effect_text(item)]
@@ -7728,7 +7767,7 @@ func _format_item_effect_text(item: Dictionary) -> String:
elif str(effect.get("type", "")) == "heal_mp":
parts.append("기력 +%d" % int(effect.get("amount", 0)))
elif str(effect.get("type", "")) == "cure_status":
parts.append("치료 %s" % str(effect.get("status", "status")).replace("_", " ").capitalize())
parts.append("치료 %s" % _battle_status_display_name(str(effect.get("status", "status"))))
elif str(effect.get("type", "")) == "cleanse_debuffs":
parts.append("약화 해소")
if parts.is_empty():
@@ -7872,9 +7911,9 @@ func _format_unit_equipment(unit: Dictionary) -> String:
for slot in ["weapon", "armor", "accessory"]:
var item_id := _equipment_item_id(equipment, slot)
if item_id.is_empty():
parts.append("%s -" % slot.capitalize())
parts.append("%s -" % _equipment_slot_display_name(slot))
else:
parts.append("%s %s" % [slot.capitalize(), _item_display_name(item_id)])
parts.append("%s %s" % [_equipment_slot_display_name(slot), _item_display_name(item_id)])
return _join_strings(parts, ", ")
@@ -7911,7 +7950,7 @@ func _format_equipment_option_text(unit: Dictionary, item_id: String, item: Dict
func _format_equipment_unequip_text(unit: Dictionary, slot: String, item_id: String, item: Dictionary) -> String:
var parts := [
"%s 해제:" % slot.capitalize(),
"%s 해제:" % _equipment_slot_display_name(slot),
_item_display_name(item_id)
]
var change_text := _format_equipment_unequip_change_text(unit, slot, item)
@@ -7929,7 +7968,7 @@ func _format_equipment_unequip_change_text(unit: Dictionary, slot: String, item:
var delta := -int(current_bonuses.get(stat, 0))
if delta == 0:
continue
parts.append("%s %d" % [stat.to_upper(), delta])
parts.append("%s %d" % [_battle_stat_display_name(stat), delta])
if slot == "weapon":
var current_range := _format_equipment_item_range_text(item)
if not current_range.is_empty():
@@ -7960,7 +7999,7 @@ func _format_equipment_change_text(unit: Dictionary, item: Dictionary) -> String
if delta == 0:
continue
var sign := "+" if delta > 0 else ""
parts.append("%s %s%d" % [stat.to_upper(), sign, delta])
parts.append("%s %s%d" % [_battle_stat_display_name(stat), sign, delta])
var range_text := _format_equipment_range_change_text(current_item, item)
if not range_text.is_empty():
@@ -7980,6 +8019,17 @@ func _equipment_slot_for_display(item: Dictionary) -> String:
return ""
func _equipment_slot_display_name(slot: String) -> String:
var normalized := slot.strip_edges().to_lower()
if normalized == "weapon":
return "병장"
if normalized == "armor":
return "갑주"
if normalized == "accessory":
return "보물"
return _format_identifier_label(slot)
func _equipment_bonus_map(item: Dictionary) -> Dictionary:
if item.is_empty() or typeof(item.get("bonuses", {})) != TYPE_DICTIONARY:
return {}
@@ -7995,7 +8045,7 @@ func _format_equipment_range_change_text(current_item: Dictionary, candidate_ite
return ""
if current_range.is_empty():
current_range = "-"
return "RNG %s->%s" % [current_range, candidate_range]
return "사거리 %s->%s" % [current_range, candidate_range]
func _format_equipment_item_range_text(item: Dictionary) -> String:
@@ -8021,10 +8071,10 @@ func _format_equipment_effectiveness_change_text(current_item: Dictionary, candi
if candidate_text == current_text:
return ""
if current_text.is_empty():
return "Gains %s" % candidate_text
return "특효 획득 %s" % candidate_text
if candidate_text.is_empty():
return "Loses %s" % current_text
return "Effect changes"
return "특효 상실 %s" % current_text
return "특효 변화"
func _format_equipment_bonus_text(item: Dictionary) -> String:
@@ -8038,12 +8088,12 @@ func _format_equipment_bonus_text(item: Dictionary) -> String:
if amount == 0:
continue
var sign := "+" if amount > 0 else ""
parts.append("%s %s%d" % [stat.to_upper(), sign, amount])
parts.append("%s %s%d" % [_battle_stat_display_name(stat), sign, amount])
var effective_text := _format_equipment_effectiveness_text(item)
if not effective_text.is_empty():
parts.append(effective_text)
if parts.is_empty():
return str(item.get("kind", "equipment")).capitalize()
return _item_kind_text(str(item.get("kind", "item")))
return _join_strings(parts, ", ")
@@ -8054,7 +8104,7 @@ func _format_equipment_rarity_text(item: Dictionary) -> String:
func _format_item_rarity_text(item: Dictionary) -> String:
var rarity := str(item.get("rarity", ""))
if rarity == "named":
return "Named"
return "명품"
return ""
@@ -8074,7 +8124,7 @@ func _format_equipment_effectiveness_text(item: Dictionary) -> String:
labels.append(label)
if labels.is_empty():
return ""
return "Effective +%d vs %s" % [bonus, _join_strings(labels, "/")]
return "%s 특효 +%d" % [_join_strings(labels, "/"), bonus]
func _format_move_type(move_type: String) -> String: