mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 17:56:32 +01:00
Bring the event system to Evennia-style compliance
This commit is contained in:
parent
629ac73f2b
commit
81f4c590bd
5 changed files with 174 additions and 171 deletions
|
|
@ -6,12 +6,12 @@ from datetime import datetime
|
|||
|
||||
from django.conf import settings
|
||||
from evennia import Command
|
||||
from evennia.contrib.events.custom import get_event_handler
|
||||
from evennia.utils.ansi import raw
|
||||
from evennia.utils.eveditor import EvEditor
|
||||
from evennia.utils.evtable import EvTable
|
||||
from evennia.utils.utils import class_from_module, time_format
|
||||
from evennia.contrib.events.custom import get_event_handler
|
||||
|
||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||
COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
|
||||
|
||||
# Permissions
|
||||
|
|
@ -20,26 +20,26 @@ WITHOUT_VALIDATION = getattr(settings, "EVENTS_WITHOUT_VALIDATION",
|
|||
"immortals")
|
||||
VALIDATING = getattr(settings, "EVENTS_VALIDATING", "immortals")
|
||||
|
||||
# Split help file
|
||||
# Split help text
|
||||
BASIC_HELP = "Add, edit or delete events."
|
||||
|
||||
BASIC_USAGES = [
|
||||
"@event object name [= event name]",
|
||||
"@event/add object name = event name [parameters]",
|
||||
"@event/edit object name = event name [event number]",
|
||||
"@event/del object name = event name [event number]",
|
||||
"@event/tasks [object name [= event name [event number]]]",
|
||||
"@event <object name> [= <event name>]",
|
||||
"@event/add <object name> = <event name> [parameters]",
|
||||
"@event/edit <object name> = <event name> [event number]",
|
||||
"@event/del <object name> = <event name> [event number]",
|
||||
"@event/tasks [object name [= <event name>]]",
|
||||
]
|
||||
|
||||
BASIC_SWITCHES = [
|
||||
"add - add and edit a new event",
|
||||
"edit - edit an existing event",
|
||||
"del - delete an existing event",
|
||||
"tasks - show the list of differed tasks",
|
||||
"add - add and edit a new event",
|
||||
"edit - edit an existing event",
|
||||
"del - delete an existing event",
|
||||
"tasks - show the list of differed tasks",
|
||||
]
|
||||
|
||||
VALIDATOR_USAGES = [
|
||||
"@event/accept [object name = event name [event number]]",
|
||||
"@event/accept [object name = <event name> [event number]]",
|
||||
]
|
||||
|
||||
VALIDATOR_SWITCHES = [
|
||||
|
|
@ -50,12 +50,12 @@ BASIC_TEXT = """
|
|||
This command is used to manipulate events. An event can be linked to
|
||||
an object, to fire at a specific moment. You can use the command without
|
||||
switches to see what event are active on an object:
|
||||
@event self
|
||||
@event self
|
||||
You can also specify an event name if you want the list of events associated
|
||||
with this object of this name:
|
||||
@event north = can_traverse
|
||||
You might need to specify a number after the event if there are more than one:
|
||||
@event here = say 2
|
||||
@event north = can_traverse
|
||||
You can also add a number after the event name to see details on one event:
|
||||
@event here = say 2
|
||||
You can also add, edit or remove events using the add, edit or del switches.
|
||||
Additionally, you can see the list of differed tasks created by events
|
||||
(chained events to be called) using the /tasks switch.
|
||||
|
|
@ -66,27 +66,26 @@ You can also use this command to validate events. Depending on your game
|
|||
setting, some users might be allowed to add new events, but these events
|
||||
will not be fired until you accept them. To see the events needing
|
||||
validation, enter the /accept switch without argument:
|
||||
@event/accept
|
||||
@event/accept
|
||||
A table will show you the events that are not validated yet, who created
|
||||
it and when. You can then accept a specific event:
|
||||
@event here = enter
|
||||
Or, if more than one events are connected here, specify the number:
|
||||
@event here = enter 3
|
||||
them and when. You can then accept a specific event:
|
||||
@event here = enter 1
|
||||
Use the /del switch to remove events that should not be connected.
|
||||
"""
|
||||
|
||||
class CmdEvent(COMMAND_DEFAULT_CLASS):
|
||||
|
||||
"""Command to edit events."""
|
||||
"""
|
||||
Command to edit events.
|
||||
"""
|
||||
|
||||
key = "@event"
|
||||
locks = "cmd:perm({})".format(VALIDATING)
|
||||
aliases = ["@events", "@ev"]
|
||||
locks = "cmd:perm({})".format(VALIDATING)
|
||||
if WITH_VALIDATION:
|
||||
locks += " or perm({})".format(WITH_VALIDATION)
|
||||
help_category = "Building"
|
||||
|
||||
|
||||
def get_help(self, caller, cmdset):
|
||||
"""
|
||||
Return the help message for this command and this caller.
|
||||
|
|
@ -104,18 +103,18 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
"""
|
||||
lock = "perm({}) or perm(events_validating)".format(VALIDATING)
|
||||
validator = caller.locks.check_lockstring(caller, lock)
|
||||
text = "\n" + BASIC_HELP + "\n\nUsages:\n "
|
||||
text = "\n" + BASIC_HELP + "\n\nUsages:\n "
|
||||
|
||||
# Usages
|
||||
text += "\n ".join(BASIC_USAGES)
|
||||
text += "\n ".join(BASIC_USAGES)
|
||||
if validator:
|
||||
text += "\n " + "\n ".join(VALIDATOR_USAGES)
|
||||
text += "\n " + "\n ".join(VALIDATOR_USAGES)
|
||||
|
||||
# Switches
|
||||
text += "\n\nSwitches:\n "
|
||||
text += "\n ".join(BASIC_SWITCHES)
|
||||
text += "\n\nSwitches:\n "
|
||||
text += "\n ".join(BASIC_SWITCHES)
|
||||
if validator:
|
||||
text += "\n " + "\n".join(VALIDATOR_SWITCHES)
|
||||
text += "\n " + "\n ".join(VALIDATOR_SWITCHES)
|
||||
|
||||
# Text
|
||||
text += "\n" + BASIC_TEXT
|
||||
|
|
@ -146,37 +145,25 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
"access the event system.")
|
||||
return
|
||||
|
||||
# Before the equal sign is always an object name
|
||||
if self.args.strip():
|
||||
# Before the equal sign, there is an object name or nothing
|
||||
if self.lhs:
|
||||
self.obj = caller.search(self.lhs)
|
||||
if not self.obj:
|
||||
return
|
||||
|
||||
# Switches are mutually exclusive
|
||||
switch = self.switches and self.switches[0] or ""
|
||||
if switch == "":
|
||||
if not self.obj:
|
||||
caller.msg("Specify an object's name or #ID.")
|
||||
return
|
||||
if switch in ("", "add", "edit", "del") and self.obj is None:
|
||||
caller.msg("Specify an object's name or #ID.")
|
||||
return
|
||||
|
||||
if switch == "":
|
||||
self.list_events()
|
||||
elif switch == "add":
|
||||
if not self.obj:
|
||||
caller.msg("Specify an object's name or #ID.")
|
||||
return
|
||||
|
||||
self.add_event()
|
||||
elif switch == "edit":
|
||||
if not self.obj:
|
||||
caller.msg("Specify an object's name or #ID.")
|
||||
return
|
||||
|
||||
self.edit_event()
|
||||
elif switch == "del":
|
||||
if not self.obj:
|
||||
caller.msg("Specify an object's name or #ID.")
|
||||
return
|
||||
|
||||
self.del_event()
|
||||
elif switch == "accept" and validator:
|
||||
self.accept_event()
|
||||
|
|
@ -198,16 +185,17 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
# Check that the event name can be found in this object
|
||||
created = events.get(event_name)
|
||||
if created is None:
|
||||
self.msg("No event {} has been set on {}.".format(event_name, obj))
|
||||
self.msg("No event {} has been set on {}.".format(event_name,
|
||||
obj))
|
||||
return
|
||||
|
||||
if parameters:
|
||||
# Check that the parameter points to an existing event
|
||||
try:
|
||||
parameters = int(parameters) - 1
|
||||
assert parameters >= 0
|
||||
event = events[event_name][parameters]
|
||||
except (AssertionError, ValueError):
|
||||
number = int(parameters) - 1
|
||||
assert number >= 0
|
||||
event = events[event_name][number]
|
||||
except (ValueError, AssertionError, IndexError):
|
||||
self.msg("The event {} {} cannot be found in {}.".format(
|
||||
event_name, parameters, obj))
|
||||
return
|
||||
|
|
@ -223,10 +211,9 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
updated_on = event.get("updated_on")
|
||||
updated_on = updated_on.strftime("%Y-%m-%d %H:%M:%S") \
|
||||
if updated_on else "|gUnknown|n"
|
||||
number = parameters + 1
|
||||
msg = "Event {} {} of {}:".format(event_name, number, obj)
|
||||
msg += "\nCreated by {} at {}.".format(author, created_on)
|
||||
msg += "\nUpdated by {} at {}".format(updated_by, updated_on)
|
||||
msg = "Event {} {} of {}:".format(event_name, parameters, obj)
|
||||
msg += "\nCreated by {} on {}.".format(author, created_on)
|
||||
msg += "\nUpdated by {} on {}".format(updated_by, updated_on)
|
||||
|
||||
if self.is_validator:
|
||||
if event.get("valid"):
|
||||
|
|
@ -235,7 +222,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
msg += "\nThis event |rhasn't been|n accepted yet."
|
||||
|
||||
msg += "\nEvent code:\n"
|
||||
msg += "\n".join([l for l in event["code"].splitlines()])
|
||||
msg += raw(event["code"])
|
||||
self.msg(msg)
|
||||
return
|
||||
|
||||
|
|
@ -255,8 +242,9 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
updated_on = event.get("created_on")
|
||||
|
||||
if updated_on:
|
||||
updated_on = time_format(
|
||||
(now - updated_on).total_seconds(), 1)
|
||||
updated_on = "{} ago".format(time_format(
|
||||
(now - updated_on).total_seconds(),
|
||||
4).capitalize())
|
||||
else:
|
||||
updated_on = "|gUnknown|n"
|
||||
parameters = event.get("parameters", "")
|
||||
|
|
@ -330,7 +318,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
# If there's only one event, just edit it
|
||||
if len(events[event_name]) == 1:
|
||||
parameters = 0
|
||||
number = 0
|
||||
event = events[event_name][0]
|
||||
else:
|
||||
if not parameters:
|
||||
|
|
@ -340,10 +328,10 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
# Check that the parameter points to an existing event
|
||||
try:
|
||||
parameters = int(parameters) - 1
|
||||
assert parameters >= 0
|
||||
event = events[event_name][parameters]
|
||||
except (AssertionError, ValueError):
|
||||
number = int(parameters) - 1
|
||||
assert number >= 0
|
||||
event = events[event_name][number]
|
||||
except (ValueError, AssertionError, IndexError):
|
||||
self.msg("The event {} {} cannot be found in {}.".format(
|
||||
event_name, parameters, obj))
|
||||
return
|
||||
|
|
@ -355,10 +343,10 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
# If the event is locked (edited by someone else)
|
||||
if (obj, event_name, parameters) in self.handler.db.locked:
|
||||
if (obj, event_name, number) in self.handler.db.locked:
|
||||
self.msg("This event is locked, you cannot edit it.")
|
||||
return
|
||||
self.handler.db.locked.append((obj, event_name, parameters))
|
||||
self.handler.db.locked.append((obj, event_name, number))
|
||||
|
||||
# Check the definition of the event
|
||||
definition = types.get(event_name, (None, "Chained event"))
|
||||
|
|
@ -369,7 +357,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
event = dict(event)
|
||||
event["obj"] = obj
|
||||
event["name"] = event_name
|
||||
event["number"] = parameters
|
||||
event["number"] = number
|
||||
self.caller.db._event = event
|
||||
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
|
||||
quitfunc=_ev_quit, key="Event {} of {}".format(
|
||||
|
|
@ -396,7 +384,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
# If there's only one event, just delete it
|
||||
if len(events[event_name]) == 1:
|
||||
parameters = 0
|
||||
number = 0
|
||||
event = events[event_name][0]
|
||||
else:
|
||||
if not parameters:
|
||||
|
|
@ -407,10 +395,10 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
# Check that the parameter points to an existing event
|
||||
try:
|
||||
parameters = int(parameters) - 1
|
||||
assert parameters >= 0
|
||||
event = events[event_name][parameters]
|
||||
except (AssertionError, ValueError):
|
||||
number = int(parameters) - 1
|
||||
assert number >= 0
|
||||
event = events[event_name][number]
|
||||
except (ValueError, AssertionError, IndexError):
|
||||
self.msg("The event {} {} cannot be found in {}.".format(
|
||||
event_name, parameters, obj))
|
||||
return
|
||||
|
|
@ -422,14 +410,14 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
return
|
||||
|
||||
# If the event is locked (edited by someone else)
|
||||
if (obj, event_name, parameters) in self.handler.db.locked:
|
||||
if (obj, event_name, number) in self.handler.db.locked:
|
||||
self.msg("This event is locked, you cannot delete it.")
|
||||
return
|
||||
|
||||
# Delete the event
|
||||
self.handler.del_event(obj, event_name, parameters)
|
||||
self.handler.del_event(obj, event_name, number)
|
||||
self.msg("The event {} {} of {} was deleted.".format(
|
||||
obj, event_name, parameters + 1))
|
||||
obj, event_name, parameters))
|
||||
|
||||
def accept_event(self):
|
||||
"""Accept an event."""
|
||||
|
|
@ -461,8 +449,9 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
updated_on = event.get("created_on")
|
||||
|
||||
if updated_on:
|
||||
updated_on = time_format(
|
||||
(now - updated_on).total_seconds(), 1)
|
||||
updated_on = "{} ago".format(time_format(
|
||||
(now - updated_on).total_seconds(),
|
||||
4).capitalize())
|
||||
else:
|
||||
updated_on = "|gUnknown|n"
|
||||
|
||||
|
|
@ -492,10 +481,10 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
|
||||
# Check that the parameter points to an existing event
|
||||
try:
|
||||
parameters = int(parameters) - 1
|
||||
assert parameters >= 0
|
||||
event = events[event_name][parameters]
|
||||
except (AssertionError, ValueError):
|
||||
number = int(parameters) - 1
|
||||
assert number >= 0
|
||||
event = events[event_name][number]
|
||||
except (ValueError, AssertionError, IndexError):
|
||||
self.msg("The event {} {} cannot be found in {}.".format(
|
||||
event_name, parameters, obj))
|
||||
return
|
||||
|
|
@ -504,7 +493,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
|||
if event["valid"]:
|
||||
self.msg("This event has already been accepted.")
|
||||
else:
|
||||
self.handler.accept_event(obj, event_name, parameters)
|
||||
self.handler.accept_event(obj, event_name, number)
|
||||
self.msg("The event {} {} of {} has been accepted.".format(
|
||||
event_name, parameters, obj))
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ from textwrap import dedent
|
|||
from django.conf import settings
|
||||
from evennia import logger
|
||||
from evennia import ScriptDB
|
||||
from evennia.contrib.custom_gametime import UNITS
|
||||
from evennia.contrib.custom_gametime import real_seconds_until as custom_rsu
|
||||
from evennia.utils.create import create_script
|
||||
from evennia.utils.gametime import real_seconds_until as standard_rsu
|
||||
from evennia.contrib.custom_gametime import UNITS
|
||||
from evennia.contrib.custom_gametime import real_seconds_until as custom_rsu
|
||||
|
||||
hooks = []
|
||||
event_types = []
|
||||
|
|
@ -24,7 +24,7 @@ def get_event_handler():
|
|||
try:
|
||||
script = ScriptDB.objects.get(db_key="event_handler")
|
||||
except ScriptDB.DoesNotExist:
|
||||
logger.log_err("Can't get the event handler.")
|
||||
logger.log_trace("Can't get the event handler.")
|
||||
script = None
|
||||
|
||||
return script
|
||||
|
|
@ -39,10 +39,10 @@ def create_event_type(typeclass, event_name, variables, help_text,
|
|||
event_name (str): the name of the event to be added.
|
||||
variables (list of str): a list of variable names.
|
||||
help_text (str): a help text of the event.
|
||||
custom_add (function, default None): a callback to call when adding
|
||||
custom_add (function, optional): a callback to call when adding
|
||||
the new event.
|
||||
custom_xcall (function, default None): a callback to call when
|
||||
preparing to call the events.
|
||||
custom_call (function, optional): a callback to call when
|
||||
preparing to call the event.
|
||||
|
||||
Events obey the inheritance hierarchy: if you set an event on
|
||||
DefaultRoom, for instance, and if your Room typeclass inherits
|
||||
|
|
@ -50,42 +50,23 @@ def create_event_type(typeclass, event_name, variables, help_text,
|
|||
all rooms. Objects of the typeclass set in argument will be
|
||||
able to set one or more events of that name.
|
||||
|
||||
If the event already exists in the typeclass, replace it.
|
||||
If the event type already exists in the typeclass, replace it.
|
||||
|
||||
"""
|
||||
typeclass_name = typeclass.__module__ + "." + typeclass.__name__
|
||||
event_types.append((typeclass_name, event_name, variables, help_text,
|
||||
custom_add, custom_call))
|
||||
|
||||
def del_event_type(typeclass, event_name):
|
||||
"""
|
||||
Delete the event type for this typeclass.
|
||||
|
||||
Args:
|
||||
typeclass (type): the class defining the typeclass.
|
||||
event_name (str): the name of the event to be deleted.
|
||||
|
||||
If you want to delete an event type, you need to remove it from
|
||||
the typeclass that defined it: other typeclasses in the inheritance
|
||||
hierarchy are not affected. This method doesn't remove the
|
||||
already-created events associated with individual objects.
|
||||
|
||||
"""
|
||||
typeclass_name = typeclass.__module__ + "." + typeclass.__name__
|
||||
try:
|
||||
script = ScriptDB.objects.get(db_key="event_handler")
|
||||
except ScriptDB.DoesNotExist:
|
||||
logger.log_err("Can't create event {} in typeclass {}, the " \
|
||||
"script handler isn't defined".format(name, typeclass_name))
|
||||
return
|
||||
|
||||
# Get the event types for this typeclass
|
||||
event_types = script.ndb.event_types.get(typeclass_name, {})
|
||||
if event_name in event_types:
|
||||
del event_types[event_name]
|
||||
|
||||
def patch_hook(typeclass, method_name):
|
||||
"""Decorator to softly patch a hook in a typeclass."""
|
||||
"""
|
||||
Decorator to softly patch a hook in a typeclass.
|
||||
|
||||
This decorator should not be used, unless for good reasons, outside
|
||||
of this contrib. The advantage of using decorated soft patchs is
|
||||
in allowing users to customize typeclasses without changing the
|
||||
inheritance tree for a couple of methods.
|
||||
|
||||
"""
|
||||
hook = getattr(typeclass, method_name)
|
||||
def wrapper(method):
|
||||
"""Wrapper around the hook."""
|
||||
|
|
@ -119,13 +100,14 @@ def connect_event_types():
|
|||
Connect the event types when the script runs.
|
||||
|
||||
This method should be called automatically by the event handler
|
||||
(the script).
|
||||
(the script). It might be useful, however, to call it after adding
|
||||
new event types in typeclasses.
|
||||
|
||||
"""
|
||||
try:
|
||||
script = ScriptDB.objects.get(db_key="event_handler")
|
||||
except ScriptDB.DoesNotExist:
|
||||
logger.log_err("Can't connect event types, the event handler " \
|
||||
logger.log_trace("Can't connect event types, the event handler " \
|
||||
"cannot be found.")
|
||||
return
|
||||
|
||||
|
|
@ -146,7 +128,7 @@ def connect_event_types():
|
|||
types[event_name] = (variables, help_text, custom_add, custom_call)
|
||||
del event_types[0]
|
||||
|
||||
# Custom callbacks for specific events
|
||||
# Custom callbacks for specific event types
|
||||
def get_next_wait(format):
|
||||
"""
|
||||
Get the length of time in seconds before format.
|
||||
|
|
@ -188,7 +170,7 @@ def get_next_wait(format):
|
|||
break
|
||||
|
||||
if not piece.isdigit():
|
||||
logger.log_err("The time specified '{}' in {} isn't " \
|
||||
logger.log_trace("The time specified '{}' in {} isn't " \
|
||||
"a valid number".format(piece, format))
|
||||
return
|
||||
|
||||
|
|
@ -205,13 +187,13 @@ def get_next_wait(format):
|
|||
|
||||
def create_time_event(obj, event_name, number, parameters):
|
||||
"""
|
||||
Create an time-related event.
|
||||
Create a time-related event.
|
||||
|
||||
args:
|
||||
Args:
|
||||
obj (Object): the object on which stands the event.
|
||||
event_name (str): the event's name.
|
||||
number (int): the number of the event.
|
||||
parameter (str): the parameter of the event.
|
||||
parameters (str): the parameter of the event.
|
||||
|
||||
"""
|
||||
seconds, key = get_next_wait(parameters)
|
||||
|
|
@ -229,7 +211,7 @@ def keyword_event(events, parameters):
|
|||
parameter to add the event type when the event supports keywords
|
||||
as parameters. Keywords in parameters are one or more words
|
||||
separated by a comma. For instance, a 'push 1, one' event can
|
||||
be triggered to trigger when the player 'push 1' or 'push one'.
|
||||
be set to trigger when the player 'push 1' or 'push one'.
|
||||
|
||||
Args:
|
||||
events (list of dict): the list of events to be called.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
"""
|
||||
Module defining basic helpers for the event system.
|
||||
|
||||
|
||||
Hlpers are just Python function that can be used inside of events. They
|
||||
Hlpers are just Python functions that can be used inside of events. They
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -70,9 +69,10 @@ def call(obj, event_name, seconds=0):
|
|||
seconds (int or float): the number of seconds to wait before calling
|
||||
the event.
|
||||
|
||||
Notice that chained events are designed for this very purpose: they
|
||||
are never called automatically by the game, rather, they need to be
|
||||
called from inside another event.
|
||||
Note:
|
||||
Chained events are designed for this very purpose: they
|
||||
are never called automatically by the game, rather, they need
|
||||
to be called from inside another event.
|
||||
|
||||
"""
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -8,16 +8,24 @@ from Queue import Queue
|
|||
from django.conf import settings
|
||||
from evennia import DefaultScript, ScriptDB
|
||||
from evennia import logger
|
||||
from evennia.utils.dbserialize import dbserialize
|
||||
from evennia.utils.utils import all_from_module, delay
|
||||
from evennia.contrib.events.custom import connect_event_types, \
|
||||
get_next_wait, patch_hooks
|
||||
from evennia.contrib.events.exceptions import InterruptEvent
|
||||
from evennia.contrib.events import typeclasses
|
||||
from evennia.utils.dbserialize import dbserialize
|
||||
from evennia.utils.utils import all_from_module, delay
|
||||
|
||||
class EventHandler(DefaultScript):
|
||||
|
||||
"""Event handler that contains all events in a global script."""
|
||||
"""
|
||||
The event handler that contains all events in a global script.
|
||||
|
||||
This script shouldn't be created more than once. It contains
|
||||
event types (in a non-persistent attribute) and events (in a
|
||||
persistent attribute). The script method would help adding,
|
||||
editing and deleting these events.
|
||||
|
||||
"""
|
||||
|
||||
def at_script_creation(self):
|
||||
self.key = "event_handler"
|
||||
|
|
@ -41,8 +49,9 @@ class EventHandler(DefaultScript):
|
|||
|
||||
# Generate locals
|
||||
self.ndb.current_locals = {}
|
||||
addresses = ["evennia.contrib.events.helpers"]
|
||||
self.ndb.fresh_locals = {}
|
||||
addresses = ["evennia.contrib.events.helpers"]
|
||||
addresses.extend(getattr(settings, "EVENTS_HELPERS_LOCATIONS", []))
|
||||
for address in addresses:
|
||||
self.ndb.fresh_locals.update(all_from_module(address))
|
||||
|
||||
|
|
@ -56,7 +65,6 @@ class EventHandler(DefaultScript):
|
|||
|
||||
delay(seconds, complete_task, task_id)
|
||||
|
||||
|
||||
def get_events(self, obj):
|
||||
"""
|
||||
Return a dictionary of the object's events.
|
||||
|
|
@ -64,6 +72,13 @@ class EventHandler(DefaultScript):
|
|||
Args:
|
||||
obj (Object): the connected objects.
|
||||
|
||||
Returns:
|
||||
A dictionary of the object's events.
|
||||
|
||||
Note:
|
||||
This method can be useful to override in some contexts,
|
||||
when several objects would share events.
|
||||
|
||||
"""
|
||||
return self.db.events.get(obj, {})
|
||||
|
||||
|
|
@ -74,6 +89,14 @@ class EventHandler(DefaultScript):
|
|||
Args:
|
||||
obj (Object): the connected object.
|
||||
|
||||
Returns:
|
||||
A dictionary of the object's event types.
|
||||
|
||||
Note:
|
||||
Event types would define what the object can have as
|
||||
events. Note, however, that chained events will not
|
||||
appear in event types and are handled separately.
|
||||
|
||||
"""
|
||||
types = {}
|
||||
event_types = self.ndb.event_types
|
||||
|
|
@ -96,11 +119,11 @@ class EventHandler(DefaultScript):
|
|||
Add the specified event.
|
||||
|
||||
Args:
|
||||
obj (Object): the Evennia typeclassed object to be modified.
|
||||
obj (Object): the Evennia typeclassed object to be extended.
|
||||
event_name (str): the name of the event to add.
|
||||
code (str): the Python code associated with this event.
|
||||
author (optional, Character, Player): the author of the event.
|
||||
valid (optional, bool): should the event be connected?
|
||||
author (Character or Player, optional): the author of the event.
|
||||
valid (bool, optional): should the event be connected?
|
||||
parameters (str, optional): optional parameters.
|
||||
|
||||
This method doesn't check that the event type exists.
|
||||
|
|
@ -148,12 +171,15 @@ class EventHandler(DefaultScript):
|
|||
Edit the specified event.
|
||||
|
||||
Args:
|
||||
obj (Object): the Evennia typeclassed object to be modified.
|
||||
event_name (str): the name of the event to add.
|
||||
obj (Object): the Evennia typeclassed object to be edited.
|
||||
event_name (str): the name of the event to edit.
|
||||
number (int): the event number to be changed.
|
||||
code (str): the Python code associated with this event.
|
||||
author (optional, Character, Player): the author of the event.
|
||||
valid (optional, bool): should the event be connected?
|
||||
author (Character or Player, optional): the author of the event.
|
||||
valid (bool, optional): should the event be connected?
|
||||
|
||||
Raises:
|
||||
RuntimeError if the event is locked.
|
||||
|
||||
This method doesn't check that the event type exists.
|
||||
|
||||
|
|
@ -170,7 +196,7 @@ class EventHandler(DefaultScript):
|
|||
|
||||
# If locked, don't edit it
|
||||
if (obj, event_name, number) in self.db.locked:
|
||||
raise RunTimeError("this event is locked.")
|
||||
raise RuntimeError("this event is locked.")
|
||||
|
||||
# Edit the event
|
||||
events[number].update({
|
||||
|
|
@ -186,7 +212,6 @@ class EventHandler(DefaultScript):
|
|||
elif valid and (obj, event_name, number) in self.db.to_valid:
|
||||
self.db.to_valid.remove((obj, event_name, number))
|
||||
|
||||
|
||||
def del_event(self, obj, event_name, number):
|
||||
"""
|
||||
Delete the specified event.
|
||||
|
|
@ -196,13 +221,16 @@ class EventHandler(DefaultScript):
|
|||
event_name (str): the name of the event to delete.
|
||||
number (int): the number of the event to delete.
|
||||
|
||||
Raises:
|
||||
RuntimeError if the event is locked.
|
||||
|
||||
"""
|
||||
obj_events = self.db.events.get(obj, {})
|
||||
events = obj_events.get(event_name, [])
|
||||
|
||||
# If locked, don't edit it
|
||||
if (obj, event_name, number) in self.db.locked:
|
||||
raise RunTimeError("this event is locked.")
|
||||
raise RuntimeError("this event is locked.")
|
||||
|
||||
# Delete the event itself
|
||||
try:
|
||||
|
|
@ -274,9 +302,9 @@ class EventHandler(DefaultScript):
|
|||
*args: additional variables for this event.
|
||||
|
||||
Kwargs:
|
||||
number (int, default None): call just a specific event.
|
||||
parameters (str, default ""): call an event with parameters.
|
||||
locals (dict): a locals replacement.
|
||||
number (int, optional): call just a specific event.
|
||||
parameters (str, optional): call an event with parameters.
|
||||
locals (dict, optional): a locals replacement.
|
||||
|
||||
Returns:
|
||||
True to report the event was called without interruption,
|
||||
|
|
@ -307,7 +335,7 @@ class EventHandler(DefaultScript):
|
|||
try:
|
||||
locals[variable] = args[i]
|
||||
except IndexError:
|
||||
logger.log_err("event {} of {} ({}): need variable " \
|
||||
logger.log_trace("event {} of {} ({}): need variable " \
|
||||
"{} in position {}".format(event_name, obj,
|
||||
type(obj), variable, i))
|
||||
return False
|
||||
|
|
@ -348,15 +376,16 @@ class EventHandler(DefaultScript):
|
|||
the differed delay is called again.
|
||||
|
||||
Args:
|
||||
seconds (int/float): the delay in seconds from now.
|
||||
seconds (int, float): the delay in seconds from now.
|
||||
obj (Object): the typecalssed object connected to the event.
|
||||
event_name (str): the event's name.
|
||||
|
||||
Note that the dictionary of locals is frozen and will be
|
||||
available again when the task runs. This feature, however,
|
||||
is limited by the database: all data cannot be saved. Lambda
|
||||
functions, class methods, objects inside an instance and so
|
||||
on will not be kept in the locals dictionary.
|
||||
Note:
|
||||
The dictionary of locals is frozen and will be available
|
||||
again when the task runs. This feature, however, is limited
|
||||
by the database: all data cannot be saved. Lambda functions,
|
||||
class methods, objects inside an instance and so on will
|
||||
not be kept in the locals dictionary.
|
||||
|
||||
"""
|
||||
now = datetime.now()
|
||||
|
|
@ -399,7 +428,7 @@ class TimeEventScript(DefaultScript):
|
|||
try:
|
||||
script = ScriptDB.objects.get(db_key="event_handler")
|
||||
except ScriptDB.DoesNotExist:
|
||||
logger.log_err("Can't get the event handler.")
|
||||
logger.log_trace("Can't get the event handler.")
|
||||
return
|
||||
|
||||
if self.db.event_name and self.db.number is not None:
|
||||
|
|
@ -434,13 +463,13 @@ def complete_task(task_id):
|
|||
This function should be called automatically for individual tasks.
|
||||
|
||||
Args:
|
||||
task_id (int): the task id.
|
||||
task_id (int): the task ID.
|
||||
|
||||
"""
|
||||
try:
|
||||
script = ScriptDB.objects.get(db_key="event_handler")
|
||||
except ScriptDB.DoesNotExist:
|
||||
logger.log_err("Can't get the event handler.")
|
||||
logger.log_trace("Can't get the event handler.")
|
||||
return
|
||||
|
||||
if task_id not in script.db.tasks:
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ Patched typeclasses for Evennia.
|
|||
|
||||
from evennia import DefaultCharacter, DefaultExit, DefaultObject, DefaultRoom
|
||||
from evennia import ScriptDB
|
||||
from evennia.utils.utils import inherits_from
|
||||
from evennia.contrib.events.custom import create_event_type, patch_hook, \
|
||||
create_time_event
|
||||
from evennia.utils.utils import inherits_from
|
||||
|
||||
class PatchedExit(object):
|
||||
|
||||
|
|
@ -52,10 +52,12 @@ create_event_type(DefaultExit, "can_traverse", ["character", "exit", "room"],
|
|||
Can the character traverse through this exit?
|
||||
This event is called when a character is about to traverse this
|
||||
exit. You can use the deny() function to deny the character from
|
||||
using this exit for the time being. The 'character' variable
|
||||
contains the character who wants to traverse through this exit.
|
||||
The 'exit' variable contains the exit, the 'room' variable
|
||||
contains the room in which the character and exit are.
|
||||
exitting for this time.
|
||||
|
||||
Variables you can use in this event:
|
||||
character: the character that wants to traverse this exit.
|
||||
exit: the exit to be traversed.
|
||||
room: the room in which stands the character before moving.
|
||||
""")
|
||||
create_event_type(DefaultExit, "traverse", ["character", "exit",
|
||||
"origin", "destination"], """
|
||||
|
|
@ -64,11 +66,12 @@ create_event_type(DefaultExit, "traverse", ["character", "exit",
|
|||
exit. Traversing cannot be prevented using 'deny()' at this
|
||||
point. The character will be in a different room and she will
|
||||
have received the room's description when this event is called.
|
||||
The 'character' variable contains the character who has traversed
|
||||
through this exit. The 'exit' variable contains the exit, the
|
||||
'origin' variable contains the room in which the character was
|
||||
before traversing, while 'destination' contains the room in which
|
||||
the character now is.
|
||||
|
||||
Variables you can use in this event:
|
||||
character: the character who has traversed through this exit.
|
||||
exit: the exit that was just traversed through.
|
||||
origin: the exit's location (where the character was before moving).
|
||||
destination: the character's location after moving.
|
||||
""")
|
||||
|
||||
# Room events
|
||||
|
|
@ -82,7 +85,7 @@ create_event_type(DefaultRoom, "time", ["room"], """
|
|||
spaces, colons or dashes. Keep it as close from a recognizable
|
||||
date format, like this:
|
||||
@event/add here = time 06-15 12:20
|
||||
This event will fire every year on June 15th at 12 PM (still
|
||||
This event will fire every year on June the 15th at 12 PM (still
|
||||
game time). Units have to be specified depending on your set calendar
|
||||
(ask a developer for more details).
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue