Files
cultivation-world-simulator/src/classes/action/escape.py
2025-11-29 13:30:06 +08:00

82 lines
3.4 KiB
Python

from __future__ import annotations
from src.classes.action import InstantAction
from src.classes.event import Event
from src.classes.battle import get_escape_success_rate
from src.classes.action.event_helper import EventHelper
from src.classes.normalize import normalize_avatar_name
class Escape(InstantAction):
"""
逃离:尝试从对方身边脱离(有成功率)。
成功:抢占并进入 MoveAwayFromAvatar(6个月)。
失败:抢占并进入 Attack。
"""
COMMENT = "逃离对方(基于成功率判定)"
DOABLES_REQUIREMENTS = "任何时候都可以执行"
PARAMS = {"avatar_name": "AvatarName"}
def _find_avatar_by_name(self, name: str) -> "Avatar|None":
"""
根据名字查找角色;找不到返回 None。
会自动规范化名字(去除括号等附加信息)以提高容错性。
"""
normalized_name = normalize_avatar_name(name)
for v in self.world.avatar_manager.avatars.values():
if v.name == normalized_name:
return v
return None
def _preempt_avatar(self, avatar: "Avatar") -> None:
avatar.clear_plans()
avatar.current_action = None
def _add_event_pair(self, event: Event, initiator: "Avatar", target: "Avatar|None") -> None:
initiator.add_event(event)
if target is not None:
target.add_event(event, to_sidebar=False)
def _execute(self, avatar_name: str) -> None:
target = self._find_avatar_by_name(avatar_name)
if target is None:
return
escape_rate = float(get_escape_success_rate(target, self.avatar))
import random as _r
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}", 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)
self.avatar.load_decide_result_chain([("MoveAwayFromAvatar", {"avatar_name": avatar_name})], self.avatar.thinking, "")
start_event = self.avatar.commit_next_plan()
if start_event is not None:
EventHelper.push_pair(start_event, initiator=self.avatar, target=target, to_sidebar_once=True)
else:
self._preempt_avatar(self.avatar)
self.avatar.load_decide_result_chain([("Attack", {"avatar_name": avatar_name})], self.avatar.thinking, "")
start_event = self.avatar.commit_next_plan()
if start_event is not None:
EventHelper.push_pair(start_event, initiator=self.avatar, target=target, to_sidebar_once=True)
def can_start(self, avatar_name: str | None = None) -> tuple[bool, str]:
return True, ""
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
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 完成
async def finish(self, avatar_name: str) -> list[Event]:
return []