添加命令冷却时间¶
在某些类型的游戏中,你可能希望限制命令的执行频率。如果一个角色施放了 火焰风暴 法术,你可能不希望他们反复使用这个命令。在一个高级战斗系统中,一个巨大的挥击可能会造成大量伤害,但代价是需要一段时间才能再次使用。
这种效果称为 命令冷却时间。
这个教程展示了一种非常高效的方式来实现冷却时间。另一种更“主动”的方法是使用异步延迟,如 Command-Duration howto 所建议的。如果你想在冷却结束后给用户发送一些信息,可以考虑结合这两个教程。
高效的冷却时间¶
我们的想法是,当一个 Command 运行时,我们存储它运行的时间。下次运行时,我们再次检查当前时间。只有当经过足够的时间后,命令才被允许运行。这是一种 非常 高效的实现,仅在需要时进行检查。
# 在 mygame/commands/spells.py 中
import time
from evennia import default_cmds
class CmdSpellFirestorm(default_cmds.MuxCommand):
"""
法术 - 火焰风暴
用法:
cast firestorm <target>
这将释放一场火焰风暴。你每五分钟只能释放一次火焰风暴(假设你有足够的法力)。
"""
key = "cast firestorm"
rate_of_fire = 60 * 2 # 2 分钟
def func(self):
"实现法术"
now = time.time()
last_cast = self.caller.db.firestorm_last_cast # 可能为 None
if last_cast and (now - last_cast < self.rate_of_fire):
message = "你还不能再次施放这个法术。"
self.caller.msg(message)
return
# [实现法术效果]
# 如果法术成功施放,存储施放时间
self.caller.db.firestorm_last_cast = now
我们指定 rate_of_fire
,然后只需检查 caller
上的一个 Attribute firestorm_last_cast
。它要么是 None
(因为法术从未施放过),要么是表示上次施放时间的时间戳。
非持久性冷却时间¶
上述实现将在重载后生效。如果你不希望这样,你可以让 firestorm_last_cast
成为一个 NAttribute。例如:
last_cast = self.caller.ndb.firestorm_last_cast
# ...
self.caller.ndb.firestorm_last_cast = now
也就是说,使用 .ndb
而不是 .db
。由于 NAttribute
纯粹在内存中,它们可以比 Attribute
更快地读写。因此,如果你的间隔很短且需要经常更改,这可能更优。缺点是如果服务器重载,它们会重置。
创建一个支持冷却时间的命令父类¶
如果你有许多不同的法术或其他带有冷却时间的命令,你不希望每次都添加这段代码。相反,你可以创建一个“冷却时间命令混入”类。混入 是一个你可以“添加”到另一个类的类(通过多重继承)以赋予它某些特殊能力。以下是一个带有持久存储的示例:
# 在 mygame/commands/mixins.py 中
import time
class CooldownCommandMixin:
rate_of_fire = 60
cooldown_storage_key = "last_used"
cooldown_storage_category = "cmd_cooldowns"
def check_cooldown(self):
last_time = self.caller.attributes.get(
key=self.cooldown_storage_key,
category=self.cooldown_storage_category)
return (time.time() - last_time) < self.rate_of_fire
def update_cooldown(self):
self.caller.attributes.add(
key=self.cooldown_storage_key,
value=time.time(),
category=self.cooldown_storage_category
)
这是为了混入一个命令中,所以我们假设 self.caller
存在。我们允许设置用于存储冷却时间的 Attribute 键/类别。
它还使用 Attribute 类别来确保它存储的内容不会与 caller 上的其他 Attribute 混淆。
以下是如何使用它:
# 在 mygame/commands/spells.py 中
from evennia import default_cmds
from .mixins import CooldownCommandMixin
class CmdSpellFirestorm(
CooldownCommandMixin, default_cmds.MuxCommand):
key = "cast firestorm"
cooldown_storage_key = "firestorm_last_cast"
rate_of_fire = 60 * 2
def func(self):
if not self.check_cooldown():
self.caller.msg("你还不能再次施放这个法术。")
return
# [法术效果发生]
self.update_cooldown()
与之前相同,我们只是隐藏了冷却时间检查,你可以将这个混入类用于所有的冷却时间。
命令交叉¶
这个冷却时间检查的例子也适用于不同命令之间。例如,你可以让所有与火相关的法术使用相同的 cooldown_storage_key
(如 fire_spell_last_used
)来存储冷却时间。这意味着施放 火焰风暴 会在一段时间内阻止所有其他与火相关的法术。
同样,当你进行一次大剑挥击时,在你恢复平衡之前,其他类型的攻击可能会被阻止。