update events

This commit is contained in:
bridge
2025-10-21 01:06:18 +08:00
parent 00ac87eaaf
commit f7a2e377a1
22 changed files with 193 additions and 44 deletions

View File

@@ -41,7 +41,13 @@ class Battle(InstantAction):
target_name = target.name if target is not None else avatar_name
# 展示双方折算战斗力(基于对手、含克制)
s_att, s_def = get_effective_strength_pair(self.avatar, target)
event = Event(self.world.month_stamp, f"{self.avatar.name}{target_name} 发起战斗(战斗力:{self.avatar.name} {int(s_att)} vs {target_name} {int(s_def)}")
rel_ids = [self.avatar.id]
if target is not None:
try:
rel_ids.append(target.id)
except Exception:
pass
event = Event(self.world.month_stamp, f"{self.avatar.name}{target_name} 发起战斗(战斗力:{self.avatar.name} {int(s_att)} vs {target_name} {int(s_def)}", related_avatars=rel_ids)
# 记录开始事件内容,供故事生成使用
self._start_event_content = event.content
return event
@@ -55,13 +61,20 @@ class Battle(InstantAction):
winner, loser = res[0], res[1]
loser_damage, winner_damage = res[2], res[3]
result_text = f"{winner} 战胜了 {loser}{loser} 受伤{loser_damage}点,{winner} 也受伤{winner_damage}"
result_event = Event(self.world.month_stamp, result_text)
rel_ids = [self.avatar.id]
try:
t = self._get_target(avatar_name)
if t is not None:
rel_ids.append(t.id)
except Exception:
pass
result_event = Event(self.world.month_stamp, result_text, related_avatars=rel_ids)
# 生成战斗小故事:使用便捷方法从参与者直接生成
target = self._get_target(avatar_name)
start_text = getattr(self, "_start_event_content", "") or result_event.content
story = StoryTeller.tell_from_actors(start_text, result_event.content, self.avatar, target, prompt=self.STORY_PROMPT)
story_event = Event(self.world.month_stamp, story)
story_event = Event(self.world.month_stamp, story, related_avatars=rel_ids)
return [result_event, story_event]

View File

@@ -120,7 +120,7 @@ class Breakthrough(TimedAction):
else:
self._calamity = None
self._calamity_other = None
return Event(self.world.month_stamp, f"{self.avatar.name} 开始尝试突破境界")
return Event(self.world.month_stamp, f"{self.avatar.name} 开始尝试突破境界", related_avatars=[self.avatar.id])
# TimedAction 已统一 step 逻辑
@@ -132,18 +132,25 @@ class Breakthrough(TimedAction):
if not getattr(self, "_gen_story", False):
# 不生成故事:不出现劫难,仅简单结果
core_text = f"{self.avatar.name} 突破{'成功' if result_ok else '失败'}"
return [Event(self.world.month_stamp, core_text)]
return [Event(self.world.month_stamp, core_text, related_avatars=[self.avatar.id])]
calamity = getattr(self, "_calamity", "劫难")
core_text = f"{self.avatar.name} 遭遇了{calamity}劫难,突破{'成功' if result_ok else '失败'}"
events: list[Event] = [Event(self.world.month_stamp, core_text)]
rel_ids = [self.avatar.id]
other = getattr(self, "_calamity_other", None)
if other is not None:
try:
rel_ids.append(other.id)
except Exception:
pass
events: list[Event] = [Event(self.world.month_stamp, core_text, related_avatars=rel_ids)]
if True:
# 故事参与者:本体 +(可选)相关角色
desc = CALAMITY_DESCRIPTIONS.get(str(calamity), "")
prompt = (STORY_PROMPT_BASE.format(calamity=str(calamity)) + (" " + desc if desc else "")).strip()
story = StoryTeller.tell_from_actors(core_text, ("突破成功" if result_ok else "突破失败"), self.avatar, getattr(self, "_calamity_other", None), prompt=prompt)
events.append(Event(self.world.month_stamp, story))
events.append(Event(self.world.month_stamp, story, related_avatars=rel_ids))
return events
# ——— 内部:劫难选择与关联角色 ———

View File

@@ -58,7 +58,7 @@ class Cultivate(TimedAction):
return True
def start(self) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name}{self.avatar.tile.region.name} 开始修炼")
return Event(self.world.month_stamp, f"{self.avatar.name}{self.avatar.tile.region.name} 开始修炼", related_avatars=[self.avatar.id])
# TimedAction 已统一 step 逻辑

View File

@@ -28,7 +28,7 @@ class DevourMortals(TimedAction):
return "DevourMortals" in legal
def start(self) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始吞噬凡人")
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始吞噬凡人", related_avatars=[self.avatar.id])
def finish(self) -> list[Event]:
return []

View File

@@ -41,7 +41,7 @@ class Escape(InstantAction):
success = _r.random() < escape_rate
result_text = "成功" if success else "失败"
result_event = Event(self.world.month_stamp, f"{self.avatar.name} 试图从 {target.name} 逃离:{result_text}")
result_event = Event(self.world.month_stamp, f"{self.avatar.name} 试图从 {target.name} 逃离:{result_text}", related_avatars=[self.avatar.id, target.id])
EventHelper.push_pair(result_event, initiator=self.avatar, target=target, to_sidebar_once=True)
if success:
self._preempt_avatar(self.avatar)
@@ -62,7 +62,10 @@ class Escape(InstantAction):
def start(self, avatar_name: str) -> Event:
target = self._find_avatar_by_name(avatar_name)
target_name = target.name if target is not None else avatar_name
return Event(self.world.month_stamp, f"{self.avatar.name} 尝试从 {target_name} 逃离")
rel_ids = [self.avatar.id]
if target is not None:
rel_ids.append(target.id)
return Event(self.world.month_stamp, f"{self.avatar.name} 尝试从 {target_name} 逃离", related_avatars=rel_ids)
# InstantAction 已实现 step 完成

View File

@@ -63,7 +63,7 @@ class Harvest(TimedAction):
def start(self) -> Event:
region = self.avatar.tile.region
return Event(self.world.month_stamp, f"{self.avatar.name}{region.name} 开始采集")
return Event(self.world.month_stamp, f"{self.avatar.name}{region.name} 开始采集", related_avatars=[self.avatar.id])
# TimedAction 已统一 step 逻辑

View File

@@ -50,7 +50,14 @@ class MoveAwayFromAvatar(TimedAction):
target_name = t.name
except Exception:
pass
return Event(self.world.month_stamp, f"{self.avatar.name} 开始远离 {target_name}")
rel_ids = [self.avatar.id]
try:
t = self._find_avatar_by_name(avatar_name)
if t is not None:
rel_ids.append(t.id)
except Exception:
pass
return Event(self.world.month_stamp, f"{self.avatar.name} 开始远离 {target_name}", related_avatars=rel_ids)
# TimedAction 已统一 step 逻辑

View File

@@ -36,7 +36,7 @@ class MoveAwayFromRegion(InstantAction):
return True
def start(self, region: str) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name} 开始离开 {region}")
return Event(self.world.month_stamp, f"{self.avatar.name} 开始离开 {region}", related_avatars=[self.avatar.id])
# InstantAction 已实现 step 完成

View File

@@ -43,7 +43,10 @@ class MoveToAvatar(DefineAction, ActualActionMixin):
def start(self, avatar_name: str) -> Event:
target = self._get_target(avatar_name)
target_name = target.name if target is not None else avatar_name
return Event(self.world.month_stamp, f"{self.avatar.name} 开始移动向 {target_name}")
rel_ids = [self.avatar.id]
if target is not None:
rel_ids.append(target.id)
return Event(self.world.month_stamp, f"{self.avatar.name} 开始移动向 {target_name}", related_avatars=rel_ids)
def step(self, avatar_name: str) -> ActionResult:
self.execute(avatar_name=avatar_name)

View File

@@ -109,7 +109,7 @@ class MoveToRegion(DefineAction, ActualActionMixin):
def start(self, region: Region | str) -> Event:
r = self._resolve_region(region)
region_name = r.name # 仅使用规范化后的区域名
return Event(self.world.month_stamp, f"{self.avatar.name} 开始移动向 {region_name}")
return Event(self.world.month_stamp, f"{self.avatar.name} 开始移动向 {region_name}", related_avatars=[self.avatar.id])
def step(self, region: Region | str) -> ActionResult:
self.execute(region=region)

View File

@@ -33,7 +33,7 @@ class PlunderMortals(TimedAction):
return self.avatar.alignment == Alignment.EVIL
def start(self) -> Event:
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始搜刮凡人")
return Event(self.world.month_stamp, f"{self.avatar.name} 在城镇开始搜刮凡人", related_avatars=[self.avatar.id])
# TimedAction 已统一 step 逻辑

View File

@@ -53,13 +53,13 @@ class SelfHeal(TimedAction):
region_name = getattr(region, "name", "宗门总部")
# 重置累计量
self._healed_total = 0
return Event(self.world.month_stamp, f"{self.avatar.name}{region_name} 开始静养疗伤")
return Event(self.world.month_stamp, f"{self.avatar.name}{region_name} 开始静养疗伤", related_avatars=[self.avatar.id])
# TimedAction 已统一 step 逻辑
def finish(self) -> list[Event]:
healed_total = int(getattr(self, "_healed_total", 0))
# 统一用一次事件简要反馈
return [Event(self.world.month_stamp, f"{self.avatar.name} 疗伤完成HP已回满本次恢复{healed_total}当前HP {self.avatar.hp}")]
return [Event(self.world.month_stamp, f"{self.avatar.name} 疗伤完成HP已回满本次恢复{healed_total}当前HP {self.avatar.hp}", related_avatars=[self.avatar.id])]

View File

@@ -33,7 +33,7 @@ class Talk(InstantAction):
def start(self) -> Event:
self.observed_others = self._get_observed_others()
# 记录开始事件
return Event(self.world.month_stamp, f"{self.avatar.name} 尝试与感知范围内的他人攀谈")
return Event(self.world.month_stamp, f"{self.avatar.name} 尝试与感知范围内的他人攀谈", related_avatars=[self.avatar.id])
def step(self) -> ActionResult:
import random

View File

@@ -2,6 +2,7 @@
event class
"""
from dataclasses import dataclass
from typing import List, Optional
from src.classes.calendar import Month, Year, MonthStamp
@@ -9,6 +10,8 @@ from src.classes.calendar import Month, Year, MonthStamp
class Event:
month_stamp: MonthStamp
content: str
# 相关角色ID列表若与任何角色无关则为 None
related_avatars: Optional[List[str]] = None
def __str__(self) -> str:
year = self.month_stamp.get_year()

View File

@@ -115,8 +115,8 @@ def try_trigger_fortune(avatar: Avatar) -> list[Event]:
story = StoryTeller.tell_from_actors(event_text, res_text, avatar, prompt=story_prompt)
events: list[Event] = [
Event(avatar.world.month_stamp, event_text),
Event(avatar.world.month_stamp, story),
Event(avatar.world.month_stamp, event_text, related_avatars=[avatar.id]),
Event(avatar.world.month_stamp, story, related_avatars=[avatar.id]),
]
return events

View File

@@ -63,7 +63,10 @@ class Conversation(MutualAction):
def start(self, target_avatar: "Avatar|str", **kwargs) -> Event:
target = self._get_target_avatar(target_avatar)
target_name = target.name if target is not None else str(target_avatar)
event = Event(self.world.month_stamp, f"{self.avatar.name}{target_name} 开始交谈")
rel_ids = [self.avatar.id]
if target is not None:
rel_ids.append(target.id)
event = Event(self.world.month_stamp, f"{self.avatar.name}{target_name} 开始交谈", related_avatars=rel_ids)
# 写入历史即可,内容事件稍后生成
self.avatar.add_event(event, to_sidebar=False)
if target is not None:
@@ -89,7 +92,7 @@ class Conversation(MutualAction):
# 仅当明确接受时才记录对话与关系;其余一律视为拒绝
if fb == "Talk":
if talk_content:
content_event = Event(self.world.month_stamp, f"{self.avatar.name}{target.name} 的交谈:{talk_content}")
content_event = Event(self.world.month_stamp, f"{self.avatar.name}{target.name} 的交谈:{talk_content}", related_avatars=[self.avatar.id, target.id])
# 进入侧栏一次,并写入双方历史
EventHelper.push_pair(content_event, initiator=self.avatar, target=target, to_sidebar_once=True)
@@ -97,12 +100,12 @@ class Conversation(MutualAction):
rel = Relation.from_chinese(into_relation_str)
if rel is not None:
self.avatar.set_relation(target, rel)
set_event = Event(self.world.month_stamp, f"{self.avatar.name}{target.name} 的关系变为:{relation_display_names.get(rel, str(rel))}")
set_event = Event(self.world.month_stamp, f"{self.avatar.name}{target.name} 的关系变为:{relation_display_names.get(rel, str(rel))}", related_avatars=[self.avatar.id, target.id])
EventHelper.push_pair(set_event, initiator=self.avatar, target=target, to_sidebar_once=True)
return ActionResult(status=ActionStatus.COMPLETED, events=[])
else:
feedback_event = Event(self.world.month_stamp, f"{target.name} 拒绝与 {self.avatar.name} 交谈")
feedback_event = Event(self.world.month_stamp, f"{target.name} 拒绝与 {self.avatar.name} 交谈", related_avatars=[self.avatar.id, target.id])
EventHelper.push_pair(feedback_event, initiator=self.avatar, target=target, to_sidebar_once=True)
return ActionResult(status=ActionStatus.COMPLETED, events=[])

View File

@@ -51,7 +51,10 @@ class DualCultivation(MutualAction):
def start(self, target_avatar: "Avatar|str") -> Event:
target = self._get_target_avatar(target_avatar)
target_name = target.name if target is not None else str(target_avatar)
event = Event(self.world.month_stamp, f"{self.avatar.name} 邀请 {target_name} 进行双修")
rel_ids = [self.avatar.id]
if target is not None:
rel_ids.append(target.id)
event = Event(self.world.month_stamp, f"{self.avatar.name} 邀请 {target_name} 进行双修", related_avatars=rel_ids)
# 仅写入历史
self.avatar.add_event(event, to_sidebar=False)
if target is not None:
@@ -102,17 +105,17 @@ class DualCultivation(MutualAction):
if success:
gain = int(self._dual_exp_gain)
result_text = f"{self.avatar.name}{target.name} 成功双修,{self.avatar.name} 获得修为经验 +{gain}"
result_event = Event(self.world.month_stamp, result_text)
result_event = Event(self.world.month_stamp, result_text, related_avatars=[self.avatar.id, target.id])
events.append(result_event)
# 生成恋爱/双修小故事:使用 StoryTeller 便捷方法
start_text = self._start_event_content or result_event.content
story = StoryTeller.tell_from_actors(start_text, result_event.content, self.avatar, target, prompt=self.STORY_PROMPT)
story_event = Event(self.world.month_stamp, story)
story_event = Event(self.world.month_stamp, story, related_avatars=[self.avatar.id, target.id])
events.append(story_event)
else:
result_text = f"{target.name} 拒绝了与 {self.avatar.name} 的双修"
result_event = Event(self.world.month_stamp, result_text)
result_event = Event(self.world.month_stamp, result_text, related_avatars=[self.avatar.id, target.id])
events.append(result_event)
return events

View File

@@ -134,7 +134,7 @@ class MutualAction(DefineAction, LLMAction, TargetingMixin):
self._settle_feedback(target_avatar, feedback)
# 3) 反馈事件(进入侧边栏与双方历史,中文化文案)
fb_label = self.FEEDBACK_LABELS.get(str(feedback).strip(), str(feedback))
feedback_event = Event(self.world.month_stamp, f"{target_avatar.name}{self.avatar.name} 的反馈:{fb_label}")
feedback_event = Event(self.world.month_stamp, f"{target_avatar.name}{self.avatar.name} 的反馈:{fb_label}", related_avatars=[self.avatar.id, target_avatar.id])
# 侧边栏仅推送一次,另一侧仅写入历史,避免重复
EventHelper.push_pair(feedback_event, initiator=self.avatar, target=target_avatar, to_sidebar_once=True)
# 4) 记录历史(文本记录)
@@ -160,7 +160,10 @@ class MutualAction(DefineAction, LLMAction, TargetingMixin):
target = self._get_target_avatar(target_avatar)
target_name = target.name if target is not None else str(target_avatar)
action_name = getattr(self, 'ACTION_NAME', self.name)
event = Event(self.world.month_stamp, f"{self.avatar.name}{target_name} 发起 {action_name}")
rel_ids = [self.avatar.id]
if target is not None:
rel_ids.append(target.id)
event = Event(self.world.month_stamp, f"{self.avatar.name}{target_name} 发起 {action_name}", related_avatars=rel_ids)
# 仅写入历史,避免与提交阶段重复推送到侧边栏
self.avatar.add_event(event, to_sidebar=False)
if target is not None: