66 lines
2.5 KiB
Python
66 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
from src.classes.action import DefineAction, ActualActionMixin
|
|
from src.classes.event import Event
|
|
from src.classes.action import Move
|
|
from src.classes.action_runtime import ActionResult, ActionStatus
|
|
from src.classes.action.move_helper import clamp_manhattan_with_diagonal_priority
|
|
from src.classes.normalize import normalize_avatar_name
|
|
|
|
|
|
class MoveToAvatar(DefineAction, ActualActionMixin):
|
|
"""
|
|
朝另一个角色当前位置移动。
|
|
"""
|
|
|
|
COMMENT = "移动到某个角色所在位置"
|
|
DOABLES_REQUIREMENTS = "任何时候都可以执行"
|
|
PARAMS = {"avatar_name": "str"}
|
|
|
|
def _get_target(self, avatar_name: str):
|
|
"""
|
|
根据名字查找目标角色;找不到返回 None。
|
|
会自动规范化名字(去除括号等附加信息)以提高容错性。
|
|
"""
|
|
normalized_name = normalize_avatar_name(avatar_name)
|
|
for v in self.world.avatar_manager.avatars.values():
|
|
if v.name == normalized_name:
|
|
return v
|
|
return None
|
|
|
|
def _execute(self, avatar_name: str) -> None:
|
|
target = self._get_target(avatar_name)
|
|
if target is None:
|
|
return
|
|
cur_loc = (self.avatar.pos_x, self.avatar.pos_y)
|
|
target_loc = (target.pos_x, target.pos_y)
|
|
raw_dx = target_loc[0] - cur_loc[0]
|
|
raw_dy = target_loc[1] - cur_loc[1]
|
|
step = getattr(self.avatar, "move_step_length", 1)
|
|
dx, dy = clamp_manhattan_with_diagonal_priority(raw_dx, raw_dy, step)
|
|
Move(self.avatar, self.world).execute(dx, dy)
|
|
|
|
def can_start(self, avatar_name: str | None = None) -> tuple[bool, str]:
|
|
return True, ""
|
|
|
|
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
|
|
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)
|
|
target = self._get_target(avatar_name)
|
|
if target is None:
|
|
return ActionResult(status=ActionStatus.COMPLETED, events=[])
|
|
done = self.avatar.tile == target.tile
|
|
return ActionResult(status=(ActionStatus.COMPLETED if done else ActionStatus.RUNNING), events=[])
|
|
|
|
async def finish(self, avatar_name: str) -> list[Event]:
|
|
return []
|
|
|
|
|