336 lines
14 KiB
Python
336 lines
14 KiB
Python
"""
|
||
Avatar 信息展示模块
|
||
|
||
将信息格式化逻辑从 Avatar 类中分离,作为独立函数提供。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from typing import TYPE_CHECKING, Optional, List
|
||
|
||
if TYPE_CHECKING:
|
||
from src.classes.avatar.core import Avatar
|
||
|
||
from src.classes.battle import get_base_strength
|
||
from src.classes.relation.relation import get_relation_label
|
||
from src.classes.emotions import EMOTION_EMOJIS, EmotionType
|
||
from src.utils.config import CONFIG
|
||
|
||
|
||
def _get_effects_text(avatar: "Avatar") -> str:
|
||
"""获取格式化的效果文本"""
|
||
from src.i18n import t
|
||
from src.classes.effect import format_effects_to_text
|
||
breakdown = avatar.get_effect_breakdown()
|
||
effect_parts = []
|
||
for source_name, effects in breakdown:
|
||
desc_str = format_effects_to_text(effects)
|
||
if desc_str:
|
||
effect_parts.append(f"[{source_name}] {desc_str}")
|
||
return "\n".join(effect_parts) if effect_parts else t("None")
|
||
|
||
|
||
def get_avatar_info(avatar: "Avatar", detailed: bool = False) -> dict:
|
||
"""
|
||
获取 avatar 的信息,返回 dict;根据 detailed 控制信息粒度。
|
||
"""
|
||
from src.i18n import t
|
||
region = avatar.tile.region if avatar.tile is not None else None
|
||
from src.classes.relation.relation import get_relations_strs
|
||
relation_lines = get_relations_strs(avatar, max_lines=8)
|
||
relations_info = t("relation_separator").join(relation_lines) if relation_lines else t("None")
|
||
magic_stone_info = str(avatar.magic_stone)
|
||
|
||
from src.classes.sect import get_sect_info_with_rank
|
||
|
||
if detailed:
|
||
weapon_info = t("{weapon_name}, Proficiency: {proficiency}%",
|
||
weapon_name=avatar.weapon.get_detailed_info(),
|
||
proficiency=f"{avatar.weapon_proficiency:.1f}") if avatar.weapon else t("None")
|
||
auxiliary_info = avatar.auxiliary.get_detailed_info() if avatar.auxiliary else t("None")
|
||
sect_info = get_sect_info_with_rank(avatar, detailed=True)
|
||
alignment_info = avatar.alignment.get_detailed_info() if avatar.alignment is not None else t("Unknown")
|
||
region_info = region.get_detailed_info() if region is not None else t("None")
|
||
root_info = avatar.root.get_detailed_info()
|
||
technique_info = avatar.technique.get_detailed_info() if avatar.technique is not None else t("None")
|
||
cultivation_info = avatar.cultivation_progress.get_detailed_info()
|
||
personas_info = ", ".join([p.get_detailed_info() for p in avatar.personas]) if avatar.personas else t("None")
|
||
materials_info = t("material_separator").join([f"{mat.get_detailed_info()}x{quantity}" for mat, quantity in avatar.materials.items()]) if avatar.materials else t("None")
|
||
appearance_info = avatar.appearance.get_detailed_info(avatar.gender)
|
||
spirit_animal_info = avatar.spirit_animal.get_info() if avatar.spirit_animal is not None else t("None")
|
||
else:
|
||
weapon_info = avatar.weapon.get_info() if avatar.weapon is not None else t("None")
|
||
auxiliary_info = avatar.auxiliary.get_info() if avatar.auxiliary is not None else t("None")
|
||
sect_info = get_sect_info_with_rank(avatar, detailed=False)
|
||
region_info = region.get_info() if region is not None else t("None")
|
||
alignment_info = avatar.alignment.get_info() if avatar.alignment is not None else t("Unknown")
|
||
root_info = avatar.root.get_info()
|
||
technique_info = avatar.technique.get_info() if avatar.technique is not None else t("None")
|
||
cultivation_info = avatar.cultivation_progress.get_info()
|
||
personas_info = ", ".join([p.get_detailed_info() for p in avatar.personas]) if avatar.personas else t("None")
|
||
materials_info = t("material_separator").join([f"{mat.get_info()}x{quantity}" for mat, quantity in avatar.materials.items()]) if avatar.materials else t("None")
|
||
appearance_info = avatar.appearance.get_info()
|
||
spirit_animal_info = avatar.spirit_animal.get_info() if avatar.spirit_animal is not None else t("None")
|
||
|
||
info_dict = {
|
||
t("Name"): avatar.name,
|
||
t("Gender"): str(avatar.gender),
|
||
t("Age"): str(avatar.age),
|
||
t("HP"): str(avatar.hp),
|
||
t("Spirit Stones"): magic_stone_info,
|
||
t("Relations"): relations_info,
|
||
t("Sect"): sect_info,
|
||
t("Alignment"): alignment_info,
|
||
t("Region"): region_info,
|
||
t("Spirit Root"): root_info,
|
||
t("Technique"): technique_info,
|
||
t("Realm"): cultivation_info,
|
||
t("Traits"): personas_info,
|
||
t("Materials"): materials_info,
|
||
t("Appearance"): appearance_info,
|
||
t("Weapon"): weapon_info,
|
||
t("Auxiliary"): auxiliary_info,
|
||
t("Emotion"): t(avatar.emotion.value),
|
||
t("Long-term Goal"): avatar.long_term_objective.content if avatar.long_term_objective else t("None"),
|
||
t("Short-term Goal"): avatar.short_term_objective if avatar.short_term_objective else t("None"),
|
||
}
|
||
|
||
if detailed:
|
||
info_dict[t("Current Effects")] = _get_effects_text(avatar)
|
||
|
||
# 绰号:仅在存在时显示
|
||
if avatar.nickname is not None:
|
||
info_dict[t("Nickname")] = avatar.nickname.value
|
||
# 灵兽:仅在存在时显示
|
||
if avatar.spirit_animal is not None:
|
||
info_dict[t("Spirit Animal")] = spirit_animal_info
|
||
return info_dict
|
||
|
||
|
||
def get_avatar_structured_info(avatar: "Avatar") -> dict:
|
||
"""
|
||
获取结构化的角色信息,用于前端展示和交互。
|
||
"""
|
||
# 基础信息
|
||
from src.i18n import t
|
||
emoji = EMOTION_EMOJIS.get(avatar.emotion, EMOTION_EMOJIS[EmotionType.CALM])
|
||
|
||
info = {
|
||
"id": avatar.id,
|
||
"name": avatar.name,
|
||
"gender": str(avatar.gender),
|
||
"age": avatar.age.age,
|
||
"lifespan": avatar.age.max_lifespan,
|
||
"realm": avatar.cultivation_progress.get_info(),
|
||
"level": avatar.cultivation_progress.level,
|
||
"hp": {"cur": avatar.hp.cur, "max": avatar.hp.max},
|
||
"alignment": str(avatar.alignment) if avatar.alignment else t("Unknown"),
|
||
"magic_stone": avatar.magic_stone.value,
|
||
"base_battle_strength": int(get_base_strength(avatar)),
|
||
"emotion": {
|
||
"name": t(avatar.emotion.value),
|
||
"emoji": emoji,
|
||
"desc": t(avatar.emotion.value)
|
||
},
|
||
"thinking": avatar.thinking,
|
||
"short_term_objective": avatar.short_term_objective,
|
||
"long_term_objective": avatar.long_term_objective.content if avatar.long_term_objective else "",
|
||
"nickname": avatar.nickname.value if avatar.nickname else None,
|
||
"nickname_reason": avatar.nickname.reason if avatar.nickname else None,
|
||
"is_dead": avatar.is_dead,
|
||
"death_info": avatar.death_info,
|
||
"action_state": t("Performing {action}", action=avatar.current_action_name)
|
||
}
|
||
|
||
# 1. 特质 (Personas)
|
||
info["personas"] = [p.get_structured_info() for p in avatar.personas]
|
||
|
||
# 2. 功法 (Technique)
|
||
if avatar.technique:
|
||
info["technique"] = avatar.technique.get_structured_info()
|
||
else:
|
||
info["technique"] = None
|
||
|
||
# 3. 宗门 (Sect)
|
||
if avatar.sect:
|
||
sect_info = avatar.sect.get_structured_info()
|
||
if avatar.sect_rank:
|
||
from src.classes.sect_ranks import get_rank_display_name
|
||
sect_info["rank"] = get_rank_display_name(avatar.sect_rank, avatar.sect)
|
||
else:
|
||
sect_info["rank"] = t("Disciple")
|
||
info["sect"] = sect_info
|
||
else:
|
||
info["sect"] = None
|
||
|
||
# 补充:阵营详情
|
||
from src.classes.alignment import alignment_info_msg_ids
|
||
info["alignment"] = str(avatar.alignment) if avatar.alignment else t("Unknown")
|
||
if avatar.alignment:
|
||
desc_id = alignment_info_msg_ids.get(avatar.alignment, "")
|
||
info["alignment_detail"] = {
|
||
"name": str(avatar.alignment),
|
||
"desc": t(desc_id) if desc_id else "",
|
||
}
|
||
|
||
# 4. 装备 (Weapon & Auxiliary)
|
||
if avatar.weapon:
|
||
w_info = avatar.weapon.get_structured_info()
|
||
w_info["proficiency"] = f"{avatar.weapon_proficiency:.1f}%"
|
||
info["weapon"] = w_info
|
||
else:
|
||
info["weapon"] = None
|
||
|
||
if avatar.auxiliary:
|
||
info["auxiliary"] = avatar.auxiliary.get_structured_info()
|
||
else:
|
||
info["auxiliary"] = None
|
||
|
||
# 5. 材料 (Materials)
|
||
materials_list = []
|
||
for material, count in avatar.materials.items():
|
||
m_info = material.get_structured_info()
|
||
m_info["count"] = count
|
||
materials_list.append(m_info)
|
||
info["materials"] = materials_list
|
||
|
||
# 6. 关系 (Relations)
|
||
relations_list = []
|
||
for other, relation in avatar.relations.items():
|
||
relations_list.append({
|
||
"target_id": other.id,
|
||
"name": other.name,
|
||
"relation": get_relation_label(relation, avatar, other),
|
||
"relation_type": relation.value,
|
||
"realm": other.cultivation_progress.get_info(),
|
||
"sect": other.sect.name if other.sect else t("Rogue Cultivator")
|
||
})
|
||
info["relations"] = relations_list
|
||
|
||
# 7. 外貌
|
||
info["appearance"] = avatar.appearance.get_info()
|
||
|
||
# 8. 灵根
|
||
from src.classes.root import format_root_cn
|
||
root_str = format_root_cn(avatar.root)
|
||
info["root"] = root_str
|
||
info["root_detail"] = {
|
||
"name": root_str,
|
||
"desc": t("Contains elements: {elements}", elements=t("element_separator").join(str(e) for e in avatar.root.elements)),
|
||
"effect_desc": avatar.root.effect_desc
|
||
}
|
||
|
||
# 9. 灵兽
|
||
if avatar.spirit_animal:
|
||
info["spirit_animal"] = avatar.spirit_animal.get_structured_info()
|
||
|
||
# 当前效果
|
||
info[t("Current Effects")] = _get_effects_text(avatar)
|
||
|
||
return info
|
||
|
||
|
||
def get_avatar_expanded_info(
|
||
avatar: "Avatar",
|
||
co_region_avatars: Optional[List["Avatar"]] = None,
|
||
other_avatar: Optional["Avatar"] = None,
|
||
detailed: bool = False
|
||
) -> dict:
|
||
"""
|
||
获取角色的扩展信息,包含基础信息、观察到的角色和事件历史。
|
||
|
||
Args:
|
||
avatar: 目标角色
|
||
co_region_avatars: 同区域的其他角色列表,用于"观察到的角色"字段
|
||
other_avatar: 另一个角色,如果提供则返回两人共同经历的事件,否则返回单人事件
|
||
detailed: 是否返回详细信息
|
||
"""
|
||
from src.i18n import t
|
||
info = get_avatar_info(avatar, detailed=detailed)
|
||
|
||
observed: list[str] = []
|
||
if co_region_avatars:
|
||
for other in co_region_avatars[:8]:
|
||
observed.append(t("{name}, Realm: {realm}", name=other.name, realm=other.cultivation_progress.get_info()))
|
||
|
||
# 历史事件改为从全局事件管理器分类查询
|
||
em = avatar.world.event_manager
|
||
major_limit = CONFIG.social.major_event_context_num
|
||
minor_limit = CONFIG.social.minor_event_context_num
|
||
|
||
# 根据是否提供 other_avatar 决定获取单人事件还是双人共同事件
|
||
if other_avatar is not None:
|
||
major_events = em.get_major_events_between(avatar.id, other_avatar.id, limit=major_limit)
|
||
minor_events = em.get_minor_events_between(avatar.id, other_avatar.id, limit=minor_limit)
|
||
else:
|
||
major_events = em.get_major_events_by_avatar(avatar.id, limit=major_limit)
|
||
minor_events = em.get_minor_events_by_avatar(avatar.id, limit=minor_limit)
|
||
|
||
major_list = [str(e) for e in major_events]
|
||
minor_list = [str(e) for e in minor_events]
|
||
|
||
info[t("Nearby Avatars")] = observed
|
||
info[t("Major Events")] = major_list
|
||
info[t("Recent Events")] = minor_list
|
||
return info
|
||
|
||
|
||
def get_other_avatar_info(from_avatar: "Avatar", to_avatar: "Avatar") -> str:
|
||
"""
|
||
仅显示几个字段:名字、绰号、境界、关系、宗门、阵营、外貌、功法、武器、辅助装备、HP
|
||
"""
|
||
from src.i18n import t
|
||
nickname = to_avatar.nickname.value if to_avatar.nickname else t("None")
|
||
sect = to_avatar.sect.name if to_avatar.sect else t("Rogue Cultivator")
|
||
tech = to_avatar.technique.get_info() if to_avatar.technique else t("None")
|
||
weapon = to_avatar.weapon.get_info() if to_avatar.weapon else t("None")
|
||
aux = to_avatar.auxiliary.get_info() if to_avatar.auxiliary else t("None")
|
||
alignment = to_avatar.alignment
|
||
|
||
# 关系可能为空
|
||
relation = from_avatar.get_relation(to_avatar) or t("None")
|
||
|
||
return t(
|
||
"{name}, Nickname: {nickname}, Realm: {realm}, Relation: {relation}, Sect: {sect}, Alignment: {alignment}, Appearance: {appearance}, Technique: {technique}, Weapon: {weapon}, Auxiliary: {aux}, HP: {hp}",
|
||
name=to_avatar.name,
|
||
nickname=nickname,
|
||
realm=to_avatar.cultivation_progress.get_info(),
|
||
relation=relation,
|
||
sect=sect,
|
||
alignment=alignment,
|
||
appearance=to_avatar.appearance.get_info(),
|
||
technique=tech,
|
||
weapon=weapon,
|
||
aux=aux,
|
||
hp=to_avatar.hp
|
||
)
|
||
|
||
|
||
def get_avatar_desc(avatar: "Avatar", detailed: bool = False) -> str:
|
||
"""
|
||
获取角色的文本描述。
|
||
detailed=True 时包含详细的效果来源分析。
|
||
"""
|
||
from src.i18n import t
|
||
# 基础描述
|
||
lines = [t("【{name}】 {gender} {age} years old", name=avatar.name, gender=avatar.gender, age=avatar.age)]
|
||
lines.append(t("Realm: {realm}", realm=avatar.cultivation_progress.get_info()))
|
||
if avatar.sect:
|
||
lines.append(t("Identity: {identity}", identity=avatar.get_sect_str()))
|
||
|
||
if detailed:
|
||
lines.append(t("\n--- Current Effects Detail ---"))
|
||
breakdown = avatar.get_effect_breakdown()
|
||
|
||
from src.classes.effect import format_effects_to_text
|
||
|
||
if not breakdown:
|
||
lines.append(t("No additional effects"))
|
||
else:
|
||
for source_name, effects in breakdown:
|
||
# 使用现有的 format_effects_to_text 将字典转为中文描述
|
||
desc_str = format_effects_to_text(effects)
|
||
if desc_str:
|
||
lines.append(f"[{source_name}]: {desc_str}")
|
||
|
||
return "\n".join(lines)
|