Files
cultivation-world-simulator/src/classes/effect/desc.py
4thfever 84027fc1d7 Feat/retreat (#104)
* feat: add retreat
2026-01-26 23:18:11 +08:00

196 lines
7.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from typing import Any
import re
def get_effect_desc(effect_key: str) -> str:
"""获取 effect 的描述名称(支持国际化)"""
from src.i18n import t
# 映射 effect_key -> msgid
msgid_map = {
"extra_hp_recovery_rate": "effect_extra_hp_recovery_rate",
"extra_max_hp": "effect_extra_max_hp",
"extra_max_lifespan": "effect_extra_max_lifespan",
"extra_weapon_proficiency_gain": "effect_extra_weapon_proficiency_gain",
"extra_dual_cultivation_exp": "effect_extra_dual_cultivation_exp",
"extra_breakthrough_success_rate": "effect_extra_breakthrough_success_rate",
"extra_retreat_success_rate": "effect_extra_retreat_success_rate",
"extra_fortune_probability": "effect_extra_fortune_probability",
"extra_misfortune_probability": "effect_extra_misfortune_probability",
"extra_harvest_materials": "effect_extra_harvest_materials",
"extra_hunt_materials": "effect_extra_hunt_materials",
"extra_mine_materials": "effect_extra_mine_materials",
"extra_item_sell_price_multiplier": "effect_extra_item_sell_price_multiplier",
"shop_buy_price_reduction": "effect_shop_buy_price_reduction",
"extra_weapon_upgrade_chance": "effect_extra_weapon_upgrade_chance",
"extra_plunder_multiplier": "effect_extra_plunder_multiplier",
"extra_catch_success_rate": "effect_extra_catch_success_rate",
"extra_cultivate_exp": "effect_extra_cultivate_exp",
"extra_battle_strength_points": "effect_extra_battle_strength_points",
"extra_escape_success_rate": "effect_extra_escape_success_rate",
"extra_assassinate_success_rate": "effect_extra_assassinate_success_rate",
"extra_observation_radius": "effect_extra_observation_radius",
"extra_move_step": "effect_extra_move_step",
"legal_actions": "effect_legal_actions",
"damage_reduction": "effect_damage_reduction",
"realm_suppression_bonus": "effect_realm_suppression_bonus",
"cultivate_duration_reduction": "effect_cultivate_duration_reduction",
"extra_cast_success_rate": "effect_extra_cast_success_rate",
"extra_refine_success_rate": "effect_extra_refine_success_rate",
}
msgid = msgid_map.get(effect_key, effect_key)
return t(msgid)
def get_action_short_name(action_name: str) -> str:
"""获取 action 的简短名称(复用 Action 系统翻译)"""
from src.i18n import t
# 使用统一的命名规则
msgid = f"action_{action_name.lower()}_short_name"
return t(msgid)
def format_value(key: str, value: Any) -> str:
"""
格式化效果数值
"""
if key == "legal_actions" and isinstance(value, list):
from src.i18n import t
actions = [get_action_short_name(str(a)) for a in value]
sep = t("action_list_separator") # "、" 或 ", "
return sep.join(actions)
if isinstance(value, (int, float)):
# 处理百分比类型的字段
if "rate" in key or "probability" in key or "chance" in key or "multiplier" in key or "gain" in key or "reduction" in key or "bonus" in key:
# 如果是小数,转为百分比。通常 0.1 表示 +10%
# 但有些可能是直接的倍率?代码里 1.0 + value所以 value 是增量
if isinstance(value, float):
percent = value * 100
sign = "+" if percent > 0 else ""
return f"{sign}{percent:.1f}%"
# 处理数值类型的字段
sign = "+" if value > 0 else ""
return f"{sign}{value}"
return str(value)
def translate_condition(condition: str) -> str:
"""
将代码形式的条件表达式转换为易读描述
"""
from src.i18n import t
import re
if not condition:
return t("Conditional effect")
# 1. 处理 Persona 判断 (特质)
# 模式: any(p.key == "CHILD_OF_FORTUNE" for p in avatar.personas)
if "avatar.personas" in condition:
# 优先匹配 key
m_key = re.search(r'p\.key\s*==\s*["\'](.*?)["\']', condition)
if m_key:
key = m_key.group(1)
# 尝试从全局数据中查找对应的 Persona Name
from src.classes.persona import personas_by_id
trait_name = key # 默认显示key如果找到则显示name
for p in personas_by_id.values():
if p.key == key:
trait_name = p.name
break
return t("Has [{trait}] trait", trait=trait_name)
# 兼容旧的 name 匹配
m_name = re.search(r'p\.name\s*==\s*["\'](.*?)["\']', condition)
if m_name:
return t("Has [{trait}] trait", trait=m_name.group(1))
# 2. 处理 Alignment 判断 (阵营)
# 模式: avatar.alignment == Alignment.RIGHTEOUS
if "avatar.alignment" in condition:
m_align = re.search(r'Alignment\.([A-Z_]+)', condition)
if m_align:
align_key = m_align.group(1)
from src.classes.alignment import Alignment
try:
# 获取枚举并调用 str() 进行翻译
align_enum = Alignment[align_key]
return t("When alignment is {align}", align=str(align_enum))
except KeyError:
pass
# 3. 处理 WeaponType 判断 (兵器类型)
# 模式: avatar.weapon.type == WeaponType.SWORD
if "avatar.weapon.type" in condition:
m_weapon = re.search(r'WeaponType\.([A-Z_]+)', condition)
if m_weapon:
w_key = m_weapon.group(1)
from src.classes.weapon_type import WeaponType
try:
w_enum = WeaponType[w_key]
return t("When using {weapon_type}", weapon_type=str(w_enum))
except KeyError:
pass
# 4. 兜底简化
# 移除代码前缀和符号,使未识别的条件稍微可读一些
simple_cond = condition
simple_cond = simple_cond.replace("avatar.", "")
simple_cond = simple_cond.replace("Alignment.", "")
simple_cond = simple_cond.replace("WeaponType.", "")
simple_cond = simple_cond.replace("==", ":")
return t("When {condition}", condition=simple_cond)
def format_effects_to_text(effects: dict[str, Any] | list[dict[str, Any]]) -> str:
"""
将 effects 字典转换为易读的文本描述。
例如:{"extra_max_hp": 100} -> "最大生命值 +100" / "Max HP +100"
"""
from src.i18n import t
if not effects:
return ""
if isinstance(effects, list):
parts = []
for eff in effects:
text = format_effects_to_text(eff)
if text:
parts.append(text)
return "\n".join(parts)
desc_list = []
for k, v in effects.items():
if k in ["when", "duration_month"]:
continue
# 使用翻译函数获取名称
name = get_effect_desc(k)
# 如果是 eval 表达式(字符串形式)或者看起来像代码
if isinstance(v, str):
if v.startswith("eval(") or "avatar." in v or "//" in v:
val_str = t("Special effect (dynamic)")
else:
val_str = format_value(k, v)
else:
val_str = format_value(k, v)
desc_list.append(f"{name} {val_str}")
# 使用翻译的分隔符
sep = t("effect_separator")
text = sep.join(desc_list)
# 如果有条件,添加条件描述
if effects.get("when"):
cond = translate_condition(str(effects["when"]))
return t("[{condition}] {effects}", condition=cond, effects=text)
return text