From 6227ebd0e8a4fc7ec6cf2dfefc1b7d8824bd5b94 Mon Sep 17 00:00:00 2001 From: bridge Date: Wed, 26 Nov 2025 18:47:29 +0800 Subject: [PATCH] add spar --- src/classes/avatar.py | 23 ++++-- src/classes/mutual_action/__init__.py | 3 + src/classes/mutual_action/spar.py | 100 ++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 src/classes/mutual_action/spar.py diff --git a/src/classes/avatar.py b/src/classes/avatar.py index e8c73c3..ce29ae1 100644 --- a/src/classes/avatar.py +++ b/src/classes/avatar.py @@ -814,14 +814,23 @@ class Avatar(AvatarSaveMixin, AvatarLoadMixin): def get_other_avatar_info(self, other_avatar: "Avatar") -> str: """ - 仅显示几个字段:名字、境界、关系、宗门、阵营、外貌、装备。 + 仅显示几个字段:名字、绰号、境界、关系、宗门、阵营、外貌、功法、武器、辅助装备、HP """ - relation = self.get_relation(other_avatar) - relation_str = str(relation) - sect_str = other_avatar.sect.name if other_avatar.sect is not None else "散修" - weapon_str = other_avatar.weapon.get_info() if other_avatar.weapon is not None else "无" - auxiliary_str = other_avatar.auxiliary.get_info() if other_avatar.auxiliary is not None else "无" - return f"{other_avatar.name},境界:{other_avatar.cultivation_progress.get_info()},关系:{relation_str},阵营:{other_avatar.alignment},宗门:{sect_str},兵器:{weapon_str},辅助:{auxiliary_str},外貌:{other_avatar.appearance.get_info()}" + nickname = other_avatar.nickname.value if other_avatar.nickname else "无" + sect = other_avatar.sect.name if other_avatar.sect else "散修" + tech = other_avatar.technique.get_info() if other_avatar.technique else "无" + weapon = other_avatar.weapon.get_info() if other_avatar.weapon else "无" + aux = other_avatar.auxiliary.get_info() if other_avatar.auxiliary else "无" + alignment = other_avatar.alignment + + # 关系可能为空 + relation = self.get_relation(other_avatar) or "无" + + return ( + f"{other_avatar.name},绰号:{nickname},境界:{other_avatar.cultivation_progress.get_info()}," + f"关系:{relation},宗门:{sect},阵营:{alignment}," + f"外貌:{other_avatar.appearance.get_info()},功法:{tech},兵器:{weapon},辅助:{aux},HP:{other_avatar.hp}" + ) def update_time_effect(self) -> None: """ diff --git a/src/classes/mutual_action/__init__.py b/src/classes/mutual_action/__init__.py index 8ca412d..b3f126c 100644 --- a/src/classes/mutual_action/__init__.py +++ b/src/classes/mutual_action/__init__.py @@ -8,6 +8,7 @@ from .dual_cultivation import DualCultivation from .talk import Talk from .impart import Impart from .gift_spirit_stone import GiftSpiritStone +from .spar import Spar from src.classes.action.registry import register_action __all__ = [ @@ -19,6 +20,7 @@ __all__ = [ "Talk", "Impart", "GiftSpiritStone", + "Spar", ] # 注册 mutual actions(均为实际动作) @@ -29,5 +31,6 @@ register_action(actual=True)(DualCultivation) register_action(actual=True)(Talk) register_action(actual=True)(Impart) register_action(actual=True)(GiftSpiritStone) +register_action(actual=True)(Spar) diff --git a/src/classes/mutual_action/spar.py b/src/classes/mutual_action/spar.py new file mode 100644 index 0000000..aa10fcd --- /dev/null +++ b/src/classes/mutual_action/spar.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +import random +from typing import TYPE_CHECKING + +from src.classes.mutual_action.mutual_action import MutualAction +from src.classes.battle import decide_battle +from src.classes.event import Event +from src.classes.story_teller import StoryTeller +from src.classes.action.cooldown import cooldown_action + +if TYPE_CHECKING: + from src.classes.avatar import Avatar + + +@cooldown_action +class Spar(MutualAction): + """ + 切磋动作:双方切磋,不造成伤害,增加武器熟练度。 + """ + ACTION_NAME = "切磋" + COMMENT = "与目标切磋武艺,点到为止(大幅增加武器熟练度,不造成伤害)" + DOABLES_REQUIREMENTS = "交互范围内可互动;不能连续执行" + FEEDBACK_ACTIONS = ["Accept", "Reject"] + + # 切磋冷却:12个月 + ACTION_CD_MONTHS: int = 12 + + # 专门的提示词,强调友好比试 + STORY_PROMPT = ( + "这是两人之间的友好切磋,点到为止,没有真正的伤害。" + "重点描写双方招式的精妙和互相的印证启发。" + "不要出现血腥或重伤描述。" + ) + + def _settle_feedback(self, target_avatar: Avatar, feedback_name: str) -> None: + if feedback_name != "Accept": + return + + # 判定胜负(复用战斗逻辑,但忽略返回的伤害值) + winner, loser, _, _ = decide_battle(self.avatar, target_avatar) + + # 计算熟练度增益 + # 参考 NurtureWeapon: random.uniform(5.0, 10.0) + base_gain = random.uniform(5.0, 10.0) + + # 赢家 3 倍,输家 1 倍 + winner_gain = base_gain * 3 + loser_gain = base_gain + + winner.increase_weapon_proficiency(winner_gain) + loser.increase_weapon_proficiency(loser_gain) + + # 记录结果供 finish 使用 + self._last_result = (winner, loser, winner_gain, loser_gain) + + result_text = ( + f"{winner.name} 在切磋中略胜一筹,战胜了 {loser.name}。" + f"({winner.name} 熟练度+{winner_gain:.1f},{loser.name} 熟练度+{loser_gain:.1f})" + ) + + # 添加结果事件 + event = Event( + self.world.month_stamp, + result_text, + related_avatars=[self.avatar.id, target_avatar.id] + ) + self.avatar.add_event(event, to_sidebar=True) + target_avatar.add_event(event, to_sidebar=True) + + async def finish(self, target_avatar: Avatar | str) -> list[Event]: + # 获取目标 + target = self._get_target_avatar(target_avatar) + if target is None or not hasattr(self, "_last_result"): + return [] + + winner, loser, w_gain, l_gain = self._last_result + + # 构造故事输入 + start_text = f"{self.avatar.name} 向 {target.name} 发起切磋" + result_text = f"{winner.name} 战胜了 {loser.name}" + + # 生成故事 + story = await StoryTeller.tell_story( + start_text, + result_text, + self.avatar, + target, + prompt=self.STORY_PROMPT, + allow_relation_changes=True + ) + + story_event = Event( + self.world.month_stamp, + story, + related_avatars=[self.avatar.id, target.id], + is_story=True + ) + + return [story_event]