Add the time-related events and events with parameters
This commit is contained in:
parent
1f4095c625
commit
e898ee0ec2
4 changed files with 165 additions and 17 deletions
|
|
@ -292,7 +292,7 @@ class CmdEvent(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
||||||
# Open the editor
|
# Open the editor
|
||||||
event = self.handler.add_event(obj, event_name, "",
|
event = self.handler.add_event(obj, event_name, "",
|
||||||
self.caller, False)
|
self.caller, False, parameters=self.parameters)
|
||||||
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(
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,13 @@ and are designed to be used more by developers to add event types.
|
||||||
|
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
|
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.gametime import real_seconds_until as standard_rsu
|
||||||
|
|
||||||
hooks = []
|
hooks = []
|
||||||
event_types = []
|
event_types = []
|
||||||
|
|
@ -24,7 +29,8 @@ def get_event_handler():
|
||||||
|
|
||||||
return script
|
return script
|
||||||
|
|
||||||
def create_event_type(typeclass, event_name, variables, help_text):
|
def create_event_type(typeclass, event_name, variables, help_text,
|
||||||
|
custom_add=None):
|
||||||
"""
|
"""
|
||||||
Create a new event type for a specific typeclass.
|
Create a new event type for a specific typeclass.
|
||||||
|
|
||||||
|
|
@ -33,6 +39,8 @@ 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
|
||||||
|
the new 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
|
||||||
|
|
@ -44,7 +52,8 @@ def create_event_type(typeclass, event_name, variables, help_text):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
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))
|
||||||
|
|
||||||
def del_event_type(typeclass, event_name):
|
def del_event_type(typeclass, event_name):
|
||||||
"""
|
"""
|
||||||
|
|
@ -118,7 +127,8 @@ def connect_event_types():
|
||||||
"cannot be found.")
|
"cannot be found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
for typeclass_name, event_name, variables, help_text in event_types:
|
for typeclass_name, event_name, variables, help_text, \
|
||||||
|
custom_add in event_types:
|
||||||
# Get the event types for this typeclass
|
# Get the event types for this typeclass
|
||||||
if typeclass_name not in script.ndb.event_types:
|
if typeclass_name not in script.ndb.event_types:
|
||||||
script.ndb.event_types[typeclass_name] = {}
|
script.ndb.event_types[typeclass_name] = {}
|
||||||
|
|
@ -126,4 +136,80 @@ def connect_event_types():
|
||||||
|
|
||||||
# Add or replace the event
|
# Add or replace the event
|
||||||
help_text = dedent(help_text.strip("\n"))
|
help_text = dedent(help_text.strip("\n"))
|
||||||
types[event_name] = (variables, help_text)
|
types[event_name] = (variables, help_text, custom_add)
|
||||||
|
|
||||||
|
# Custom callbacks for specific events
|
||||||
|
def get_next_wait(format):
|
||||||
|
"""
|
||||||
|
Get the length of time in seconds before format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
format (str): a time format matching the set calendar.
|
||||||
|
|
||||||
|
The time format could be something like "2018-01-08 12:00". The
|
||||||
|
number of units set in the calendar affects the way seconds are
|
||||||
|
calculated.
|
||||||
|
|
||||||
|
"""
|
||||||
|
calendar = getattr(settings, "EVENTS_CALENDAR", None)
|
||||||
|
if calendar is None:
|
||||||
|
logger.log_err("A time-related event has been set whereas " \
|
||||||
|
"the gametime calendar has not been set in the settings.")
|
||||||
|
return
|
||||||
|
elif calendar == "standard":
|
||||||
|
rsu = standard_rsu
|
||||||
|
units = ["min", "hour", "day", "month", "year"]
|
||||||
|
elif calendar == "custom":
|
||||||
|
rsu = custom_rsu
|
||||||
|
back = dict([(value, name) for name, value in UNITS.items()])
|
||||||
|
sorted_units = sorted(back.items())
|
||||||
|
del sorted_units[0]
|
||||||
|
units = [n for v, n in sorted_units]
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
for delimiter in ("-", ":"):
|
||||||
|
format = format.replace(delimiter, " ")
|
||||||
|
|
||||||
|
pieces = list(reversed(format.split()))
|
||||||
|
details = []
|
||||||
|
i = 0
|
||||||
|
for uname in units:
|
||||||
|
try:
|
||||||
|
piece = pieces[i]
|
||||||
|
except IndexError:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not piece.isdigit():
|
||||||
|
logger.log_err("The time specified '{}' in {} isn't " \
|
||||||
|
"a valid number".format(piece, format))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Convert the piece to int
|
||||||
|
piece = int(piece)
|
||||||
|
params[uname] = piece
|
||||||
|
details.append("{}={}".format(uname, piece))
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
params["sec"] = 0
|
||||||
|
details = " ".join(details)
|
||||||
|
seconds = rsu(**params)
|
||||||
|
return seconds, details
|
||||||
|
|
||||||
|
def create_time_event(obj, event_name, number, parameters):
|
||||||
|
"""
|
||||||
|
Create an time-related event.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
"""
|
||||||
|
print "parameters", repr(parameters)
|
||||||
|
seconds, key = get_next_wait(parameters)
|
||||||
|
script = create_script("evennia.contrib.events.scripts.TimeEventScript", interval=seconds, obj=obj)
|
||||||
|
script.key = key
|
||||||
|
script.desc = "time event called regularly on {}".format(key)
|
||||||
|
script.db.time_format = parameters
|
||||||
|
script.db.number = number
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@ Scripts for the event system.
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from Queue import Queue
|
from Queue import Queue
|
||||||
|
|
||||||
from evennia import DefaultScript
|
from django.conf import settings
|
||||||
|
from evennia import DefaultScript, ScriptDB
|
||||||
from evennia import logger
|
from evennia import logger
|
||||||
|
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.exceptions import InterruptEvent
|
||||||
from evennia.contrib.events.custom import connect_event_types, patch_hooks
|
|
||||||
from evennia.contrib.events import typeclasses
|
from evennia.contrib.events import typeclasses
|
||||||
from evennia.utils.utils import all_from_module
|
from evennia.utils.utils import all_from_module
|
||||||
|
|
||||||
|
|
@ -64,7 +66,8 @@ class EventHandler(DefaultScript):
|
||||||
|
|
||||||
return types
|
return types
|
||||||
|
|
||||||
def add_event(self, obj, event_name, code, author=None, valid=False):
|
def add_event(self, obj, event_name, code, author=None, valid=False,
|
||||||
|
parameters=""):
|
||||||
"""
|
"""
|
||||||
Add the specified event.
|
Add the specified event.
|
||||||
|
|
||||||
|
|
@ -74,6 +77,7 @@ class EventHandler(DefaultScript):
|
||||||
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 (optional, Character, Player): the author of the event.
|
||||||
valid (optional, bool): should the event be connected?
|
valid (optional, bool): should the event be connected?
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
@ -100,6 +104,13 @@ class EventHandler(DefaultScript):
|
||||||
if not valid:
|
if not valid:
|
||||||
self.db.to_valid.append((obj, event_name, len(events) - 1))
|
self.db.to_valid.append((obj, event_name, len(events) - 1))
|
||||||
|
|
||||||
|
# Call the custom_add if needed
|
||||||
|
custom_add = self.get_event_types(obj).get(
|
||||||
|
event_name, [None, None, None])[2]
|
||||||
|
print "custom_add", custom_add
|
||||||
|
if custom_add:
|
||||||
|
custom_add(obj, event_name, len(events) - 1, parameters)
|
||||||
|
|
||||||
# Build the definition to return (a dictionary)
|
# Build the definition to return (a dictionary)
|
||||||
definition = dict(events[-1])
|
definition = dict(events[-1])
|
||||||
definition["obj"] = obj
|
definition["obj"] = obj
|
||||||
|
|
@ -163,7 +174,7 @@ class EventHandler(DefaultScript):
|
||||||
if (obj, event_name, number) in self.db.to_valid:
|
if (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 call_event(self, obj, event_name, *args):
|
def call_event(self, obj, event_name, number=None, *args):
|
||||||
"""
|
"""
|
||||||
Call the event.
|
Call the event.
|
||||||
|
|
||||||
|
|
@ -171,6 +182,7 @@ class EventHandler(DefaultScript):
|
||||||
obj (Object): the Evennia typeclassed object.
|
obj (Object): the Evennia typeclassed object.
|
||||||
event_name (str): the event name to call.
|
event_name (str): the event name to call.
|
||||||
*args: additional variables for this event.
|
*args: additional variables for this event.
|
||||||
|
number (int, default None): call just a specific event.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True to report the event was called without interruption,
|
True to report the event was called without interruption,
|
||||||
|
|
@ -198,13 +210,64 @@ class EventHandler(DefaultScript):
|
||||||
|
|
||||||
# Now execute all the valid events linked at this address
|
# Now execute all the valid events linked at this address
|
||||||
events = self.db.events.get(obj, {}).get(event_name, [])
|
events = self.db.events.get(obj, {}).get(event_name, [])
|
||||||
for event in events:
|
for i, event in enumerate(events):
|
||||||
if not event["valid"]:
|
if not event["valid"]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if number is not None and i != number:
|
||||||
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exec(event["code"], locals, locals)
|
exec(event["code"], locals, locals)
|
||||||
except InterruptEvent:
|
except InterruptEvent:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# Script to call time-related events
|
||||||
|
class TimeEventScript(DefaultScript):
|
||||||
|
|
||||||
|
"""Gametime-sensitive script."""
|
||||||
|
|
||||||
|
def at_script_creation(self):
|
||||||
|
"""The script is created."""
|
||||||
|
self.start_delay = True
|
||||||
|
self.persistent = True
|
||||||
|
|
||||||
|
# Script attributes
|
||||||
|
self.db.time_format = None
|
||||||
|
self.db.event_name = "time"
|
||||||
|
self.db.number = None
|
||||||
|
|
||||||
|
def at_repeat(self):
|
||||||
|
"""Call the event and reset interval."""
|
||||||
|
# Get the event handler and call the script
|
||||||
|
try:
|
||||||
|
script = ScriptDB.objects.get(db_key="event_handler")
|
||||||
|
except ScriptDB.DoesNotExist:
|
||||||
|
logger.log_err("Can't get the event handler.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.db.event_name and self.db.number is not None:
|
||||||
|
obj = self.obj
|
||||||
|
event_name = self.db.event_name
|
||||||
|
number = self.db.number
|
||||||
|
events = script.db.events.get(obj, {}).get(event_name)
|
||||||
|
if events is None:
|
||||||
|
logger.log_err("Cannot find the event {} on {}".format(
|
||||||
|
event_name, obj))
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
event = events[number]
|
||||||
|
except IndexError:
|
||||||
|
logger.log_err("Cannot find the event {} {} on {}".format(
|
||||||
|
event_name, number, obj))
|
||||||
|
return
|
||||||
|
|
||||||
|
script.call_event(obj, event_name, number, obj)
|
||||||
|
|
||||||
|
if self.db.time_format:
|
||||||
|
seconds, details = get_next_wait(self.db.time_format)
|
||||||
|
self.restart(interval=seconds)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ 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.contrib.events.custom import create_event_type, patch_hook
|
from evennia.contrib.events.custom import create_event_type, patch_hook, \
|
||||||
|
create_time_event
|
||||||
from evennia.utils.utils import inherits_from
|
from evennia.utils.utils import inherits_from
|
||||||
|
|
||||||
class PatchedExit(object):
|
class PatchedExit(object):
|
||||||
|
|
@ -31,7 +32,7 @@ class PatchedExit(object):
|
||||||
is_character = inherits_from(traversing_object, DefaultCharacter)
|
is_character = inherits_from(traversing_object, DefaultCharacter)
|
||||||
script = ScriptDB.objects.get(db_key="event_handler")
|
script = ScriptDB.objects.get(db_key="event_handler")
|
||||||
if is_character:
|
if is_character:
|
||||||
allow = script.call_event(exit, "can_traverse", traversing_object,
|
allow = script.call_event(exit, "can_traverse", None, traversing_object,
|
||||||
exit, exit.location)
|
exit, exit.location)
|
||||||
if not allow:
|
if not allow:
|
||||||
return
|
return
|
||||||
|
|
@ -40,7 +41,7 @@ class PatchedExit(object):
|
||||||
|
|
||||||
# After traversing
|
# After traversing
|
||||||
if is_character:
|
if is_character:
|
||||||
script.call_event(exit, "traverse", traversing_object,
|
script.call_event(exit, "traverse", None, traversing_object,
|
||||||
exit, exit.location, exit.destination)
|
exit, exit.location, exit.destination)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -71,7 +72,7 @@ create_event_type(DefaultExit, "traverse", ["character", "exit",
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Room events
|
# Room events
|
||||||
create_event_type(DefaultRoom, "time", ["room", "time"], """
|
create_event_type(DefaultRoom, "time", ["room"], """
|
||||||
A repeated event to be called regularly.
|
A repeated event to be called regularly.
|
||||||
This event is scheduled to repeat at different times, specified
|
This event is scheduled to repeat at different times, specified
|
||||||
as parameters. You can set it to run every day at 8:00 AM (game
|
as parameters. You can set it to run every day at 8:00 AM (game
|
||||||
|
|
@ -87,6 +88,4 @@ create_event_type(DefaultRoom, "time", ["room", "time"], """
|
||||||
|
|
||||||
Variables you can use in this event:
|
Variables you can use in this event:
|
||||||
room: the room connected to this event.
|
room: the room connected to this event.
|
||||||
time: a string containing the current time.
|
""", create_time_event)
|
||||||
""")
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue