60 lines
2.2 KiB
Python
60 lines
2.2 KiB
Python
from __future__ import annotations
|
||
|
||
from src.classes.action import InstantAction
|
||
from src.classes.action_runtime import ActionResult, ActionStatus
|
||
from src.utils.config import CONFIG
|
||
from src.classes.event import Event
|
||
|
||
|
||
class Talk(InstantAction):
|
||
"""
|
||
攀谈:尝试与交互范围内的某个NPC进行交谈。
|
||
- can_start:交互范围内存在其他NPC
|
||
- 发起后:从交互范围内随机选择一个目标,进入 MutualAction: Conversation(允许建立关系)
|
||
"""
|
||
|
||
COMMENT = "与交互范围内的NPC发起攀谈"
|
||
DOABLES_REQUIREMENTS = "交互范围内存在其他NPC"
|
||
PARAMS = {}
|
||
|
||
def _get_observed_others(self) -> list["Avatar"]:
|
||
return self.world.avatar_manager.get_observable_avatars(self.avatar)
|
||
|
||
# 不再限定必须同一 tile,由交互范围统一约束
|
||
|
||
def _execute(self) -> None:
|
||
# Talk 本身不做长期效果,主要在 step 中驱动 Conversation
|
||
return
|
||
|
||
def can_start(self, **kwargs) -> tuple[bool, str]:
|
||
# 交互范围内是否存在其他NPC(用于展示在动作空间)
|
||
ok = len(self._get_observed_others()) > 0
|
||
return (ok, "" if ok else "交互范围内没有可交谈对象")
|
||
|
||
def start(self) -> Event:
|
||
self.observed_others = self._get_observed_others()
|
||
# 记录开始事件
|
||
return Event(self.world.month_stamp, f"{self.avatar.name} 尝试与交互范围内的他人攀谈", related_avatars=[self.avatar.id])
|
||
|
||
def step(self) -> ActionResult:
|
||
import random
|
||
|
||
target = random.choice(self.observed_others)
|
||
|
||
# 进入交谈:由概率决定本次是否允许建立关系
|
||
from src.classes.mutual_action import Conversation
|
||
# 由配置决定本次是否有“有机会进入关系”标记
|
||
prob = CONFIG.social.talk_into_relation_probability
|
||
can_into_relation = random.random() < prob
|
||
|
||
conv = Conversation(self.avatar, self.world)
|
||
# 启动事件写入历史,不入侧边栏
|
||
conv.start(target_avatar=target)
|
||
conv.step(target_avatar=target, can_into_relation=can_into_relation)
|
||
return ActionResult(status=ActionStatus.COMPLETED, events=[])
|
||
|
||
def finish(self) -> list[Event]:
|
||
return []
|
||
|
||
|