Files
cultivation-world-simulator/src/classes/avatar/info_presenter.py
2026-02-06 22:46:15 +08:00

336 lines
14 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.
"""
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)