diff --git a/src/classes/avatar/action_mixin.py b/src/classes/avatar/action_mixin.py index e5748d0..db30663 100644 --- a/src/classes/avatar/action_mixin.py +++ b/src/classes/avatar/action_mixin.py @@ -141,9 +141,11 @@ class ActionMixin: for e in result.events: self.add_event(e) events, self._pending_events = self._pending_events, [] - # 本轮已执行过,清除"新设动作"标记(但如果刚刚提交了新动作,commit_next_plan会重新设置为True) - if self.current_action is None: - # 当前无动作时才清除标记,避免清除新提交动作的标记 + # 本轮已执行过,清除"新设动作"标记 + # 1. 动作结束 (None) + # 2. 动作继续执行且未发生切换 (is action_instance_before) + # 注意:如果动作发生了切换(如 Escape -> Attack),则视为新动作,不清除标记以便 Simulator 进行下一轮调度 + if self.current_action is None or self.current_action is action_instance_before: self._new_action_set_this_step = False return events diff --git a/src/sim/simulator.py b/src/sim/simulator.py index b05a7a3..2dcc588 100644 --- a/src/sim/simulator.py +++ b/src/sim/simulator.py @@ -128,26 +128,39 @@ class Simulator: 执行阶段:推进当前动作,支持同月链式抢占即时结算,返回期间产生的事件。 TODO: 为单个角色的 tick_action() 添加 try-except 处理。 - 当前如果任一角色的动作执行抛出异常,整个 step() 会失败, - 导致 month_stamp 不会推进,游戏卡在同一个月份无限循环。 """ events = [] MAX_LOCAL_ROUNDS = 3 - for _ in range(MAX_LOCAL_ROUNDS): - new_action_happened = False - for avatar in self.world.avatar_manager.get_living_avatars(): - # 本轮执行前若标记为新设,则清理,执行后由 Avatar 再统一清除 - if getattr(avatar, "_new_action_set_this_step", False): - new_action_happened = True + + # Round 1: 全员执行一次 + avatars_needing_retry = set() + for avatar in self.world.avatar_manager.get_living_avatars(): + new_events = await avatar.tick_action() + if new_events: + events.extend(new_events) + + # 检查是否有新动作产生(抢占/连招),如果有则加入下一轮 + # 注意:tick_action 内部已处理标记清除逻辑,仅当动作发生切换时才会保留 True + if getattr(avatar, "_new_action_set_this_step", False): + avatars_needing_retry.add(avatar) + + # Round 2+: 仅执行有新动作的角色,避免无辜角色重复执行 + round_count = 1 + while avatars_needing_retry and round_count < MAX_LOCAL_ROUNDS: + current_avatars = list(avatars_needing_retry) + avatars_needing_retry.clear() + + for avatar in current_avatars: 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 + avatars_needing_retry.add(avatar) + + round_count += 1 + return events def _phase_resolve_death(self): diff --git a/src/utils/gather.py b/src/utils/gather.py index 0e43a9d..2feaf95 100644 --- a/src/utils/gather.py +++ b/src/utils/gather.py @@ -68,7 +68,7 @@ def execute_gather( base_quantity = 1 extra_items = int(avatar.effects.get(extra_effect_key, 0) or 0) - total_quantity = max(1, base_quantity + extra_items) + total_quantity = base_quantity + extra_items avatar.add_item(item, total_quantity)