听取发言的 NPC¶
> say hi
你说:“hi”
桥下的巨魔回答:“你好啊。”
本文将解释如何让 NPC 对角色在其当前位置说话做出反应。这一原理适用于其他场景,例如敌人加入战斗或对角色拔出武器作出反应。
# mygame/typeclasses/npc.py
from characters import Character
class Npc(Character):
"""
扩展角色类的 NPC 类型类。
"""
def at_heard_say(self, message, from_obj):
"""
一个简单的监听和响应。这使得子类 NPC 可以轻松地对发言作出不同反应。
"""
# message 的形式为 `<Person> says, "say_text"`
# 我们想要提取 say_text,而不包含引号和任何空格
message = message.split('says, ')[1].strip(' "')
# 我们将在下面的 .msg() 中使用这个
return f"{from_obj} 说:'{message}'"
我们添加了一个简单的方法 at_heard_say
,用于格式化它听到的内容。我们假设传入的方法消息的形式为 某人说,“你好”
,并确保在这个例子中仅提取出 你好
。
我们实际上还没有调用 at_heard_say
。我们将在下一步中处理它。
当房间中的某人对这个 NPC 说话时,它的 msg
方法将被调用。我们将修改 NPC 的 .msg
方法来捕捉发言,以便 NPC 可以回应。
# mygame/typeclasses/npc.py
from characters import Character
class Npc(Character):
# [at_heard_say() goes here]
def msg(self, text=None, from_obj=None, **kwargs):
"自定义 msg() 方法以响应发言。"
if from_obj != self:
# 确保不重复自己说过的话,否则会导致循环
try:
# 如果 text 来自发言,`text` 是 `('say_text', {'type': 'say'})`
say_text, is_say = text[0], text[1]['type'] == 'say'
except Exception:
is_say = False
if is_say:
# 首先获取响应(如果有)
response = self.at_heard_say(say_text, from_obj)
# 如果有响应
if response is not None:
# 说出我们自己的话,使用返回值
self.execute_cmd(f"say {response}")
# 如果任何人有人对这个 NPC 进行操纵,这是必要的——否则你将不会收到来自服务器的任何反馈(连查看结果都会看不到)
super().msg(text=text, from_obj=from_obj, **kwargs)
所以,假如 NPC 收到了发言,并且该发言并不是来自 NPC 本身,它将使用 at_heard_say
钩子回显它。以上示例中的一些注意事项:
第 15 行:
text
输入可以因调用此msg
的位置而异。如果你查看 say 命令的代码,你会发现它会通过("Hello", {"type": "say"})
调用.msg
。我们利用这个知识来判断这是否来自发言。第 24 行:我们使用
execute_cmd
来调用 NPC 的自己的say
命令。这是可行的,因为 NPC 实际上是DefaultCharacter
的子类 - 因此它上会有CharacterCmdSet
!通常你应尽量少用execute_cmd
;直接调用命令使用的实际代码通常更高效。对于本教程,调用命令的做法更简短,同时确保所有钩子都能触发。第 26 行:注意关于
super
的注释在最后。这将触发父类中的“默认”msg
。只要没有人操纵该 NPC(通过@ic <npcname>
),这其实并不必要,但明智的是将其保留在这里,因为操控它的玩家如果msg()
从不向他们返回任何内容,将会完全失去视线!
现在完成这部分内容,让我们创建一个 NPC 并看看它会说些什么。
reload
create/drop Guild Master:npc.Npc
(你也可以将路径给定为 typeclasses.npc.Npc
,但 Evennia 会自动查找 typeclasses
文件夹,因此稍微简短一点)。
> say hi
你说:“hi”
Guild Master 说:“你说:'hi'”
各种说明¶
实现此类功能的方法有很多。一种替代的示例是在 Character 上修改 at_say
钩子。它可以检测到是否发送给 NPC,并直接调用 at_heard_say
钩子。
虽然教程的解决方案有优点,仅在 NPC 类中包含了代码,但将其与使用角色类结合提供了更直接的控制权,以决定 NPC 将如何响应。选择哪种方式取决于你游戏的具体设计需求。