From 938f85db9ae654ec77d3b8f98613eece7c93fb2f Mon Sep 17 00:00:00 2001 From: bridge Date: Thu, 18 Sep 2025 23:37:19 +0800 Subject: [PATCH] add relationship --- src/classes/avatar.py | 56 ++++++++++++++++++++++++++++++++++++++++- src/classes/relation.py | 25 ++++++++++++++++++ src/front/rendering.py | 11 ++++++++ src/run/run.py | 15 +++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/classes/relation.py diff --git a/src/classes/avatar.py b/src/classes/avatar.py index 94941e7..0d95ff2 100644 --- a/src/classes/avatar.py +++ b/src/classes/avatar.py @@ -21,6 +21,7 @@ from src.classes.magic_stone import MagicStone from src.classes.hp_and_mp import HP, MP, HP_MAX_BY_REALM, MP_MAX_BY_REALM from src.utils.id_generator import get_avatar_id from src.utils.config import CONFIG +from src.classes.relation import Relation persona_num = CONFIG.avatar.persona_num @@ -67,6 +68,7 @@ class Avatar: items: dict[Item, int] = field(default_factory=dict) hp: HP = field(default_factory=lambda: HP(0, 0)) # 将在__post_init__中初始化 mp: MP = field(default_factory=lambda: MP(0, 0)) # 将在__post_init__中初始化 + relations: dict["Avatar", Relation] = field(default_factory=dict) def __post_init__(self): """ @@ -369,8 +371,60 @@ class Avatar: else: items_info = "物品持有情况:无" + # 关系摘要 + relations_summary = self._get_relations_summary_str() + personas_count = len(self.personas) - return f"{info}\n{personas_info}\n{magic_stone_info}\n{items_info}\n决策时需参考这个角色的{personas_count}个个性特点。\n该角色的目前暂时的合法动作为:{action_space}" + return f"{info}\n{personas_info}\n{magic_stone_info}\n{items_info}\n关系:{relations_summary}\n决策时需参考这个角色的{personas_count}个个性特点。\n该角色的目前暂时的合法动作为:{action_space}" + + def set_relation(self, other: "Avatar", relation: Relation) -> None: + """ + 设置与另一个角色的关系(对称)。 + """ + if other is self: + return + self.relations[other] = relation + # 保持对称 + if getattr(other, "relations", None) is not None: + other.relations[self] = relation + + def get_relation(self, other: "Avatar") -> Optional[Relation]: + return self.relations.get(other) + + def clear_relation(self, other: "Avatar") -> None: + self.relations.pop(other, None) + if getattr(other, "relations", None) is not None: + other.relations.pop(self, None) + + def _get_relations_summary_str(self, max_count: int = 8) -> str: + entries: list[str] = [] + for other in self.relations.keys(): + entries.append(self.get_other_avatar_info(other)) + if not entries: + return "无" + return ",".join(entries[:max_count]) + + def get_co_region_avatars(self, avatars: List["Avatar"]) -> List["Avatar"]: + """ + 返回与自己处于同一区域的角色列表(不含自己)。 + """ + if self.tile is None: + return [] + same_region: list[Avatar] = [] + for other in avatars: + if other is self or other.tile is None: + continue + if other.tile.region == self.tile.region: + same_region.append(other) + return same_region + + def get_other_avatar_info(self, other_avatar: "Avatar") -> str: + """ + 仅显示三个字段:名字、境界、关系。 + """ + relation = self.get_relation(other_avatar) + relation_str = str(relation) + return f"{other_avatar.name},境界:{str(other_avatar.cultivation_progress)},关系:{relation_str}" @property def move_step_length(self) -> int: diff --git a/src/classes/relation.py b/src/classes/relation.py new file mode 100644 index 0000000..86536b3 --- /dev/null +++ b/src/classes/relation.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +from enum import Enum + + +class Relation(Enum): + KINSHIP = "kinship" # 亲子/亲属 + LOVERS = "lovers" # 情侣/道侣 + MASTER_APPRENTICE = "mentorship" # 师徒 + FRIEND = "friend" # 朋友 + ENEMY = "enemy" # 仇人 + + def __str__(self) -> str: + return relation_strs.get(self, self.value) + + +relation_strs = { + Relation.KINSHIP: "亲属", + Relation.LOVERS: "情侣", + Relation.MASTER_APPRENTICE: "师徒", + Relation.FRIEND: "朋友", + Relation.ENEMY: "仇人", +} + + diff --git a/src/front/rendering.py b/src/front/rendering.py index 6cfd9af..197bb67 100644 --- a/src/front/rendering.py +++ b/src/front/rendering.py @@ -3,6 +3,7 @@ from typing import List, Optional, Tuple, Callable from src.classes.avatar import Avatar, Gender from src.classes.tile import TileType from src.utils.text_wrap import wrap_text +from src.classes.relation import Relation def draw_grid(pygame_mod, screen, colors, map_obj, ts: int, m: int): @@ -164,6 +165,16 @@ def draw_tooltip_for_avatar(pygame_mod, screen, colors, font, avatar: Avatar): lines.append("目标:") objective_lines = wrap_text(avatar.objective, 20) lines.extend(objective_lines) + + # 关系信息 + relations_list = [f"{other.name}({str(relation)})" for other, relation in getattr(avatar, "relations", {}).items()] + lines.append("") + if relations_list: + lines.append("关系:") + for s in relations_list[:6]: + lines.append(f" {s}") + else: + lines.append("关系: 无") draw_tooltip(pygame_mod, screen, colors, lines, *pygame_mod.mouse.get_pos(), font) diff --git a/src/run/run.py b/src/run/run.py index db57284..0ffef18 100644 --- a/src/run/run.py +++ b/src/run/run.py @@ -23,6 +23,7 @@ from src.utils.names import get_random_name from src.utils.id_generator import get_avatar_id from src.utils.config import CONFIG from src.run.log import get_logger +from src.classes.relation import Relation def clamp(value: int, lo: int, hi: int) -> int: @@ -85,6 +86,20 @@ def make_avatars(world: World, count: int = 12, current_month_stamp: MonthStamp ) avatar.tile = world.map.get_tile(x, y) avatars[avatar.id] = avatar + # —— 为演示添加少量示例关系 —— + avatar_list = list(avatars.values()) + if len(avatar_list) >= 2: + # 朋友 + avatar_list[0].set_relation(avatar_list[1], Relation.FRIEND) + if len(avatar_list) >= 4: + # 仇人 + avatar_list[2].set_relation(avatar_list[3], Relation.ENEMY) + if len(avatar_list) >= 6: + # 师徒(随意指派方向,关系对称) + avatar_list[4].set_relation(avatar_list[5], Relation.MASTER_APPRENTICE) + if len(avatar_list) >= 6: + # 情侣 + avatar_list[6].set_relation(avatar_list[7], Relation.LOVERS) return avatars