This commit is contained in:
bridge
2025-10-03 23:59:12 +08:00
parent 2040537414
commit cece923f66
5 changed files with 44 additions and 8 deletions

View File

@@ -249,7 +249,7 @@ class MoveToAvatar(DefineAction, ActualActionMixin):
for v in self.world.avatar_manager.avatars.values():
if v.name == avatar_name:
return v
raise ValueError(f"未找到名为 {avatar_name} 的角色")
return None
def _execute(self, avatar_name: str) -> None:
target = self._get_target(avatar_name)
@@ -265,6 +265,9 @@ class MoveToAvatar(DefineAction, ActualActionMixin):
Move(self.avatar, self.world).execute(delta_x, delta_y)
def can_start(self, avatar_name: str|None = None) -> bool:
target = self._get_target(avatar_name)
if target is None:
return False
return True
def start(self, avatar_name: str) -> Event:
@@ -837,7 +840,7 @@ class Battle(DefineAction, ActualActionMixin):
if isinstance(res, tuple) and len(res) == 2:
winner, loser = res
return [Event(self.world.month_stamp, f"{winner} 战胜了 {loser}")]
raise ValueError(f"Battle finish error: {res}")
return []
@long_action(step_month=3)

View File

@@ -75,6 +75,8 @@ class Avatar:
mp: MP = field(default_factory=lambda: MP(0, 0)) # 将在__post_init__中初始化
relations: dict["Avatar", Relation] = field(default_factory=dict)
alignment: Alignment = field(default_factory=lambda: random.choice(list(Alignment)))
# 当月/当步新设动作标记:在 commit_next_plan 设为 True首次 tick_action 后清为 False
_new_action_set_this_step: bool = False
def __post_init__(self):
"""
@@ -165,6 +167,8 @@ class Avatar:
# 启动
start_event = action.start(**plan.params)
self.current_action = ActionInstance(action=action, params=plan.params, status="running")
# 标记为“本轮新设动作”,用于本月补充执行
self._new_action_set_this_step = True
return start_event
return None
@@ -205,6 +209,8 @@ class Avatar:
for e in mid_events:
self._pending_events.append(e)
events, self._pending_events = self._pending_events, []
# 本轮已执行过,清除“新设动作”标记
self._new_action_set_this_step = False
return events
def update_cultivation(self, new_level: int):

View File

@@ -65,6 +65,17 @@ class MutualAction(DefineAction, LLMAction):
"""
将反馈决定落地为目标角色的立即动作(清空后加载单步动作链)。
"""
# 若当前已是同类同参动作,直接跳过,避免重复“发起战斗”等事件刷屏
try:
cur = target_avatar.current_action
if cur is not None:
cur_name = getattr(cur.action, "__class__", type(cur.action)).__name__
if cur_name == action_name:
# 简单判断参数等价(键值相等)
if getattr(cur, "params", {}) == dict(action_params):
return
except Exception:
pass
# 抢占:清空后续计划并中断其当前动作
self._preempt_avatar(target_avatar)
# 先加载为计划

View File

@@ -50,11 +50,27 @@ class Simulator:
if start_event is not None and not is_null_event(start_event):
events.append(start_event)
# 执行阶段:推进所有有当前动作的角色
for avatar_id, avatar in self.world.avatar_manager.avatars.items():
new_events = await avatar.tick_action()
if new_events:
events.extend(new_events)
# 执行阶段:推进当前动作,支持同月链式抢占即时结算
# 采用最多3轮的小循环
# - 每轮遍历现有角色执行一次 tick_action
# - 若本轮有角色在遍历过程中被抢占并新设了动作(标记 _new_action_set_this_step=True下一轮继续执行
# - 最多 3 轮以防极端互相抢占导致长链
MAX_LOCAL_ROUNDS = 3
for _ in range(MAX_LOCAL_ROUNDS):
new_action_happened = False
for avatar_id, avatar in list(self.world.avatar_manager.avatars.items()):
# 本轮执行前若标记为新设,则清理,执行后由 Avatar 再统一清除
if getattr(avatar, "_new_action_set_this_step", False):
new_action_happened = True
new_events = await avatar.tick_action()
if new_events:
events.extend(new_events)
# 若在本次执行后产生了新的动作(被别人抢占设立),则标志位会在 commit_next_plan 时被置 True
if getattr(avatar, "_new_action_set_this_step", False):
new_action_happened = True
# 若本轮未检测到新动作产生,则结束本地循环
if not new_action_happened:
break
# 结算战斗等导致的死亡逻辑
for avatar_id, avatar in list(self.world.avatar_manager.avatars.items()):

View File

@@ -1,3 +1,3 @@
id,name,exclusion_ids,prompt
,,和本persona互斥的persona的id,输入给LLM的prompt
12,复仇,11;14,你是一个复仇心强的人,你绝不轻易放下仇怨,为了复仇愿意付出代价与时间。
12,复仇,11;14,你是一个复仇心强的人,你绝不轻易放下仇怨,为了复仇愿意付出代价与时间。你要立刻复仇。
1 id name exclusion_ids prompt
2 和本persona互斥的persona的id 输入给LLM的prompt
3 12 复仇 11;14 你是一个复仇心强的人,你绝不轻易放下仇怨,为了复仇愿意付出代价与时间。 你是一个复仇心强的人,你绝不轻易放下仇怨,为了复仇愿意付出代价与时间。你要立刻复仇。