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