Make PEP8 cleanup of line spaces and character distances as well as indents

This commit is contained in:
Griatch 2017-08-19 23:16:36 +02:00
parent 7ff783fea1
commit b278337172
189 changed files with 2039 additions and 1583 deletions

View file

@ -14,7 +14,7 @@ See README.md for more info.
# own code, so somthing needs to be done here. See issue #766. /Griatch
#import evennia
#evennia._init()
# evennia._init()
#import barter, dice, extended_room, menu_login, talking_npc
#import chargen, email_login, gendersub, menusystem, slow_exit
#import tutorial_world, tutorial_examples

View file

@ -105,6 +105,7 @@ class TradeTimeout(DefaultScript):
"""
This times out the trade request, in case player B did not reply in time.
"""
def at_script_creation(self):
"""
Called when script is first created
@ -136,6 +137,7 @@ class TradeHandler(object):
Objects of this class handles the ongoing trade, notably storing the current
offers from each side and wether both have accepted or not.
"""
def __init__(self, part_a, part_b):
"""
Initializes the trade. This is called when part A tries to
@ -391,6 +393,7 @@ class CmdTradeBase(Command):
Base command for Trade commands to inherit from. Implements the
custom parsing.
"""
def parse(self):
"""
Parse the relevant parts and make it easily

View file

@ -102,7 +102,7 @@ class CmdOOCLook(default_cmds.CmdLook):
else:
charlist = "You have no Characters."
string = \
""" You, %s, are an |wOOC ghost|n without form. The world is hidden
""" You, %s, are an |wOOC ghost|n without form. The world is hidden
from you and besides chatting on channels your options are limited.
You need to have a Character in order to interact with the world.
@ -179,6 +179,7 @@ class OOCCmdSetCharGen(default_cmds.AccountCmdSet):
"""
Extends the default OOC cmdset.
"""
def at_cmdset_creation(self):
"""Install everything from the default set, then overload"""
self.add(CmdOOCLook())

View file

@ -88,11 +88,11 @@ CLOTHING_TYPE_ORDER = ['hat', 'jewelry', 'top', 'undershirt', 'gloves', 'fullbod
'underpants', 'socks', 'shoes', 'accessory']
# The maximum number of each type of clothes that can be worn. Unlimited if untyped or not specified.
CLOTHING_TYPE_LIMIT = {
'hat': 1,
'gloves': 1,
'socks': 1,
'shoes': 1
}
'hat': 1,
'gloves': 1,
'socks': 1,
'shoes': 1
}
# The maximum number of clothing items that can be worn, or None for unlimited.
CLOTHING_OVERALL_LIMIT = 20
# What types of clothes will automatically cover what other types of clothes when worn.
@ -100,11 +100,11 @@ CLOTHING_OVERALL_LIMIT = 20
# on that auto-covers it - for example, it's perfectly possible to have your underpants
# showing if you put them on after your pants!
CLOTHING_TYPE_AUTOCOVER = {
'top': ['undershirt'],
'bottom': ['underpants'],
'fullbody': ['undershirt', 'underpants'],
'shoes': ['socks']
}
'top': ['undershirt'],
'bottom': ['underpants'],
'fullbody': ['undershirt', 'underpants'],
'shoes': ['socks']
}
# Types of clothes that can't be used to cover other clothes.
CLOTHING_TYPE_CANT_COVER_WITH = ['jewelry']
@ -295,6 +295,7 @@ class ClothedCharacter(DefaultCharacter):
just copy the return_appearance hook defined below to your own game's
character typeclass.
"""
def return_appearance(self, looker):
"""
This formats a description. It is the hook a 'look' command

View file

@ -166,14 +166,14 @@ CURLY_COLOR_XTERM256_EXTRA_GFG = [r'\{=([a-z])'] # |=a - greyscale foregrou
CURLY_COLOR_XTERM256_EXTRA_GBG = [r'\{\[=([a-z])'] # |[=a - greyscale background
CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
(r'{[r', r'{[500'),
(r'{[g', r'{[050'),
(r'{[y', r'{[550'),
(r'{[b', r'{[005'),
(r'{[m', r'{[505'),
(r'{[c', r'{[055'),
(r'{[w', r'{[555'), # white background
(r'{[x', r'{[222'), # dark grey background
(r'{[r', r'{[500'),
(r'{[g', r'{[050'),
(r'{[y', r'{[550'),
(r'{[b', r'{[005'),
(r'{[m', r'{[505'),
(r'{[c', r'{[055'),
(r'{[w', r'{[555'), # white background
(r'{[x', r'{[222'), # dark grey background
]
@ -191,34 +191,34 @@ CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
#############################################################
MUX_COLOR_ANSI_EXTRA_MAP = [
(r'%cn', _ANSI_NORMAL), # reset
(r'%ch', _ANSI_HILITE), # highlight
(r'%r', _ANSI_RETURN), # line break
(r'%R', _ANSI_RETURN), #
(r'%t', _ANSI_TAB), # tab
(r'%T', _ANSI_TAB), #
(r'%b', _ANSI_SPACE), # space
(r'%B', _ANSI_SPACE),
(r'%cf', _ANSI_BLINK), # annoying and not supported by all clients
(r'%ci', _ANSI_INVERSE), # invert
(r'%cn', _ANSI_NORMAL), # reset
(r'%ch', _ANSI_HILITE), # highlight
(r'%r', _ANSI_RETURN), # line break
(r'%R', _ANSI_RETURN), #
(r'%t', _ANSI_TAB), # tab
(r'%T', _ANSI_TAB), #
(r'%b', _ANSI_SPACE), # space
(r'%B', _ANSI_SPACE),
(r'%cf', _ANSI_BLINK), # annoying and not supported by all clients
(r'%ci', _ANSI_INVERSE), # invert
(r'%cr', _ANSI_RED),
(r'%cg', _ANSI_GREEN),
(r'%cy', _ANSI_YELLOW),
(r'%cb', _ANSI_BLUE),
(r'%cm', _ANSI_MAGENTA),
(r'%cc', _ANSI_CYAN),
(r'%cw', _ANSI_WHITE),
(r'%cx', _ANSI_BLACK),
(r'%cr', _ANSI_RED),
(r'%cg', _ANSI_GREEN),
(r'%cy', _ANSI_YELLOW),
(r'%cb', _ANSI_BLUE),
(r'%cm', _ANSI_MAGENTA),
(r'%cc', _ANSI_CYAN),
(r'%cw', _ANSI_WHITE),
(r'%cx', _ANSI_BLACK),
(r'%cR', _ANSI_BACK_RED),
(r'%cG', _ANSI_BACK_GREEN),
(r'%cY', _ANSI_BACK_YELLOW),
(r'%cB', _ANSI_BACK_BLUE),
(r'%cM', _ANSI_BACK_MAGENTA),
(r'%cC', _ANSI_BACK_CYAN),
(r'%cW', _ANSI_BACK_WHITE),
(r'%cX', _ANSI_BACK_BLACK)
(r'%cR', _ANSI_BACK_RED),
(r'%cG', _ANSI_BACK_GREEN),
(r'%cY', _ANSI_BACK_YELLOW),
(r'%cB', _ANSI_BACK_BLUE),
(r'%cM', _ANSI_BACK_MAGENTA),
(r'%cC', _ANSI_BACK_CYAN),
(r'%cW', _ANSI_BACK_WHITE),
(r'%cX', _ANSI_BACK_BLACK)
]
MUX_COLOR_XTERM256_EXTRA_FG = [r'%c([0-5])([0-5])([0-5])'] # %c123 - foreground colour
@ -227,12 +227,12 @@ MUX_COLOR_XTERM256_EXTRA_GFG = [r'%c=([a-z])'] # %c=a - greyscale foregroun
MUX_COLOR_XTERM256_EXTRA_GBG = [r'%c\[=([a-z])'] # %c[=a - greyscale background
MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
(r'%ch%cR', r'%c[500'),
(r'%ch%cG', r'%c[050'),
(r'%ch%cY', r'%c[550'),
(r'%ch%cB', r'%c[005'),
(r'%ch%cM', r'%c[505'),
(r'%ch%cC', r'%c[055'),
(r'%ch%cW', r'%c[555'), # white background
(r'%ch%cX', r'%c[222'), # dark grey background
(r'%ch%cR', r'%c[500'),
(r'%ch%cG', r'%c[050'),
(r'%ch%cY', r'%c[550'),
(r'%ch%cB', r'%c[005'),
(r'%ch%cM', r'%c[505'),
(r'%ch%cC', r'%c[055'),
(r'%ch%cW', r'%c[555'), # white background
(r'%ch%cX', r'%c[222'), # dark grey background
]

View file

@ -45,15 +45,15 @@ TIMEFACTOR = settings.TIME_FACTOR
# Each unit must be consistent and expressed in seconds.
UNITS = getattr(settings, "TIME_UNITS", {
# default custom calendar
"sec": 1,
"min": 60,
"hr": 60 * 60,
"hour": 60 * 60,
"day": 60 * 60 * 24,
"week": 60 * 60 * 24 * 7,
"month": 60 * 60 * 24 * 7 * 4,
"yr": 60 * 60 * 24 * 7 * 4 * 12,
"year": 60 * 60 * 24 * 7 * 4 * 12, })
"sec": 1,
"min": 60,
"hr": 60 * 60,
"hour": 60 * 60,
"day": 60 * 60 * 24,
"week": 60 * 60 * 24 * 7,
"month": 60 * 60 * 24 * 7 * 4,
"yr": 60 * 60 * 24 * 7 * 4 * 12,
"year": 60 * 60 * 24 * 7 * 4 * 12, })
def time_to_tuple(seconds, *divisors):
@ -111,8 +111,8 @@ def gametime_to_realtime(format=False, **kwargs):
name = name[:-1]
if name not in UNITS:
raise ValueError("the unit {} isn't defined as a valid " \
"game time unit".format(name))
raise ValueError("the unit {} isn't defined as a valid "
"game time unit".format(name))
rtime += value * UNITS[name]
rtime /= TIMEFACTOR
if format:
@ -121,7 +121,7 @@ def gametime_to_realtime(format=False, **kwargs):
def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, weeks=0,
months=0, yrs=0, format=False):
months=0, yrs=0, format=False):
"""
This method calculates how much in-game time a real-world time
interval would correspond to. This is usually a lot less
@ -140,7 +140,7 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, weeks=0,
"""
gtime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
weeks * 604800 + months * 2628000 + yrs * 31536000)
weeks * 604800 + months * 2628000 + yrs * 31536000)
if format:
units = sorted(set(UNITS.values()), reverse=True)
# Remove seconds from the tuple
@ -149,6 +149,7 @@ def realtime_to_gametime(secs=0, mins=0, hrs=0, days=0, weeks=0,
return time_to_tuple(gtime, *units)
return gtime
def custom_gametime(absolute=False):
"""
Return the custom game time as a tuple of units, as defined in settings.
@ -168,6 +169,7 @@ def custom_gametime(absolute=False):
del units[-1]
return time_to_tuple(current, *units)
def real_seconds_until(**kwargs):
"""
Return the real seconds until game time.
@ -228,6 +230,7 @@ def real_seconds_until(**kwargs):
return (projected - current) / TIMEFACTOR
def schedule(callback, repeat=False, **kwargs):
"""
Call the callback when the game time is up.
@ -256,14 +259,16 @@ def schedule(callback, repeat=False, **kwargs):
"""
seconds = real_seconds_until(**kwargs)
script = create_script("evennia.contrib.custom_gametime.GametimeScript",
key="GametimeScript", desc="A timegame-sensitive script",
interval=seconds, start_delay=True,
repeats=-1 if repeat else 1)
key="GametimeScript", desc="A timegame-sensitive script",
interval=seconds, start_delay=True,
repeats=-1 if repeat else 1)
script.db.callback = callback
script.db.gametime = kwargs
return script
# Scripts dealing in gametime (use `schedule` to create it)
class GametimeScript(DefaultScript):
"""Gametime-sensitive script."""

View file

@ -118,6 +118,7 @@ def roll_dice(dicenum, dicetype, modifier=None, conditional=None, return_tuple=F
else:
return result
RE_PARTS = re.compile(r"(d|\+|-|/|\*|<|>|<=|>=|!=|==)")
RE_MOD = re.compile(r"(\+|-|/|\*)")
RE_COND = re.compile(r"(<|>|<=|>=|!=|==)")
@ -255,6 +256,7 @@ class DiceCmdSet(CmdSet):
a small cmdset for testing purposes.
Add with @py self.cmdset.add("contrib.dice.DiceCmdSet")
"""
def at_cmdset_creation(self):
"""Called when set is created"""
self.add(CmdDice())

View file

@ -24,6 +24,7 @@ class EvenniaGameIndexClient(object):
Evennia Game Index. Since EGI is in the early goings, this isn't
incredibly configurable as far as what is being sent.
"""
def __init__(self, on_bad_request=None):
"""
:param on_bad_request: Optional callable to trigger when a bad request
@ -131,6 +132,7 @@ class SimpleResponseReceiver(protocol.Protocol):
"""
Used for pulling the response body out of an HTTP response.
"""
def __init__(self, status_code, d):
self.status_code = status_code
self.buf = ''

View file

@ -108,6 +108,7 @@ class ExtendedRoom(DefaultRoom):
time. It also allows for "details", together with a slightly modified
look command.
"""
def at_object_creation(self):
"""Called when room is first created only."""
self.db.spring_desc = ""
@ -281,6 +282,7 @@ class CmdExtendedLook(default_cmds.CmdLook):
Observes your location, details at your location or objects in your vicinity.
"""
def func(self):
"""
Handle the looking - add fallback to details.

View file

@ -38,22 +38,23 @@ _GENDER_PRONOUN_MAP = {"male": {"s": "he",
"p": "his",
"a": "his"},
"female": {"s": "she",
"o": "her",
"p": "her",
"a": "hers"},
"o": "her",
"p": "her",
"a": "hers"},
"neutral": {"s": "it",
"o": "it",
"p": "its",
"a": "its"},
"o": "it",
"p": "its",
"a": "its"},
"ambiguous": {"s": "they",
"o": "them",
"p": "their",
"a": "theirs"}
}
}
_RE_GENDER_PRONOUN = re.compile(r'(?<!\|)\|(?!\|)[sSoOpPaA]')
# in-game command for setting the gender
class SetGender(Command):
"""
Sets gender on yourself
@ -72,7 +73,7 @@ class SetGender(Command):
"""
caller = self.caller
arg = self.args.strip().lower()
if not arg in ("male", "female", "neutral", "ambiguous"):
if arg not in ("male", "female", "neutral", "ambiguous"):
caller.msg("Usage: @gender male||female||neutral||ambiguous")
return
caller.db.gender = arg
@ -109,7 +110,7 @@ class GenderCharacter(DefaultCharacter):
- `|a`, `|A`: Absolute Possessive form: his, hers, its, His, Hers, Its, Theirs
"""
typ = regex_match.group()[1] # "s", "O" etc
typ = regex_match.group()[1] # "s", "O" etc
gender = self.attributes.get("gender", default="ambiguous")
gender = gender if gender in ("male", "female", "neutral") else "ambiguous"
pronoun = _GENDER_PRONOUN_MAP[gender][typ.lower()]

View file

@ -4,6 +4,7 @@ Module containing the CallbackHandler for individual objects.
from collections import namedtuple
class CallbackHandler(object):
"""
@ -99,7 +100,7 @@ class CallbackHandler(object):
handler = type(self).script
if handler:
return self.format_callback(handler.add_callback(self.obj, callback_name, code,
author=author, valid=valid, parameters=parameters))
author=author, valid=valid, parameters=parameters))
def edit(self, callback_name, number, code, author=None, valid=False):
"""
@ -122,7 +123,7 @@ class CallbackHandler(object):
handler = type(self).script
if handler:
return self.format_callback(handler.edit_callback(self.obj, callback_name,
number, code, author=author, valid=valid))
number, code, author=author, valid=valid))
def remove(self, callback_name, number):
"""
@ -200,5 +201,6 @@ class CallbackHandler(object):
return Callback(**callback)
Callback = namedtuple("Callback", ("obj", "name", "number", "code", "author",
"valid", "parameters", "created_on", "updated_by", "updated_on"))
"valid", "parameters", "created_on", "updated_by", "updated_on"))

View file

@ -17,18 +17,18 @@ COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
# Permissions
WITH_VALIDATION = getattr(settings, "callbackS_WITH_VALIDATION", None)
WITHOUT_VALIDATION = getattr(settings, "callbackS_WITHOUT_VALIDATION",
"developer")
"developer")
VALIDATING = getattr(settings, "callbackS_VALIDATING", "developer")
# Split help text
BASIC_HELP = "Add, edit or delete callbacks."
BASIC_USAGES = [
"@call <object name> [= <callback name>]",
"@call/add <object name> = <callback name> [parameters]",
"@call/edit <object name> = <callback name> [callback number]",
"@call/del <object name> = <callback name> [callback number]",
"@call/tasks [object name [= <callback name>]]",
"@call <object name> [= <callback name>]",
"@call/add <object name> = <callback name> [parameters]",
"@call/edit <object name> = <callback name> [callback number]",
"@call/del <object name> = <callback name> [callback number]",
"@call/tasks [object name [= <callback name>]]",
]
BASIC_SWITCHES = [
@ -39,7 +39,7 @@ BASIC_SWITCHES = [
]
VALIDATOR_USAGES = [
"@call/accept [object name = <callback name> [callback number]]",
"@call/accept [object name = <callback name> [callback number]]",
]
VALIDATOR_SWITCHES = [
@ -73,6 +73,7 @@ them and when. You can then accept a specific callback:
Use the /del switch to remove callbacks that should not be connected.
"""
class CmdCallback(COMMAND_DEFAULT_CLASS):
"""
@ -141,8 +142,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
self.is_validator = validator
self.autovalid = autovalid
if self.handler is None:
caller.msg("The event handler is not running, can't " \
"access the event system.")
caller.msg("The event handler is not running, can't "
"access the event system.")
return
# Before the equal sign, there is an object name or nothing
@ -170,8 +171,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
elif switch in ["tasks", "task"]:
self.list_tasks()
else:
caller.msg("Mutually exclusive or invalid switches were " \
"used, cannot proceed.")
caller.msg("Mutually exclusive or invalid switches were "
"used, cannot proceed.")
def list_callbacks(self):
"""Display the list of callbacks connected to the object."""
@ -186,7 +187,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
created = callbacks.get(callback_name)
if created is None:
self.msg("No callback {} has been set on {}.".format(callback_name,
obj))
obj))
return
if parameters:
@ -197,7 +198,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj))
callback_name, parameters, obj))
return
# Display the callback's details
@ -241,8 +242,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
if updated_on:
updated_on = "{} ago".format(time_format(
(now - updated_on).total_seconds(),
4).capitalize())
(now - updated_on).total_seconds(),
4).capitalize())
else:
updated_on = "|gUnknown|n"
parameters = callback.get("parameters", "")
@ -256,7 +257,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
else:
names = list(set(list(types.keys()) + list(callbacks.keys())))
table = EvTable("Callback name", "Number", "Description",
valign="t", width=78)
valign="t", width=78)
table.reformat_column(0, width=20)
table.reformat_column(1, width=10, align="r")
table.reformat_column(2, width=48)
@ -277,9 +278,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
types = self.handler.get_events(obj)
# Check that the callback exists
if not callback_name.startswith("chain_") and not callback_name in types:
self.msg("The callback name {} can't be found in {} of " \
"typeclass {}.".format(callback_name, obj, type(obj)))
if not callback_name.startswith("chain_") and callback_name not in types:
self.msg("The callback name {} can't be found in {} of "
"typeclass {}.".format(callback_name, obj, type(obj)))
return
definition = types.get(callback_name, (None, "Chained event."))
@ -288,7 +289,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# Open the editor
callback = self.handler.add_callback(obj, callback_name, "",
self.caller, False, parameters=self.parameters)
self.caller, False, parameters=self.parameters)
# Lock this callback right away
self.handler.db.locked.append((obj, callback_name, callback["number"]))
@ -296,8 +297,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# Open the editor for this callback
self.caller.db._callback = callback
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
quitfunc=_ev_quit, key="Callback {} of {}".format(
callback_name, obj), persistent=True, codefunc=_ev_save)
quitfunc=_ev_quit, key="Callback {} of {}".format(
callback_name, obj), persistent=True, codefunc=_ev_save)
def edit_callback(self):
"""Edit a callback."""
@ -313,9 +314,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
return
# Check that the callback exists
if not callback_name in callbacks:
if callback_name not in callbacks:
self.msg("The callback name {} can't be found in {}.".format(
callback_name, obj))
callback_name, obj))
return
# If there's only one callback, just edit it
@ -335,7 +336,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj))
callback_name, parameters, obj))
return
# If caller can't edit without validation, forbid editing
@ -361,7 +362,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
self.caller.db._callback = callback
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
quitfunc=_ev_quit, key="Callback {} of {}".format(
callback_name, obj), persistent=True, codefunc=_ev_save)
callback_name, obj), persistent=True, codefunc=_ev_save)
def del_callback(self):
"""Delete a callback."""
@ -377,9 +378,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
return
# Check that the callback exists
if not callback_name in callbacks:
if callback_name not in callbacks:
self.msg("The callback name {} can't be found in {}.".format(
callback_name, obj))
callback_name, obj))
return
# If there's only one callback, just delete it
@ -388,8 +389,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][0]
else:
if not parameters:
self.msg("Which callback do you wish to delete? Specify " \
"a number.")
self.msg("Which callback do you wish to delete? Specify "
"a number.")
self.list_callbacks()
return
@ -400,7 +401,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj))
callback_name, parameters, obj))
return
# If caller can't edit without validation, forbid deleting
@ -417,7 +418,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# Delete the callback
self.handler.del_callback(obj, callback_name, number)
self.msg("The callback {}[{}] of {} was deleted.".format(
callback_name, number + 1, obj))
callback_name, number + 1, obj))
def accept_callback(self):
"""Accept a callback."""
@ -428,7 +429,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# If no object, display the list of callbacks to be checked
if obj is None:
table = EvTable("ID", "Type", "Object", "Name", "Updated by",
"On", width=78)
"On", width=78)
table.reformat_column(0, align="r")
now = datetime.now()
for obj, name, number in self.handler.db.to_valid:
@ -450,8 +451,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
if updated_on:
updated_on = "{} ago".format(time_format(
(now - updated_on).total_seconds(),
4).capitalize())
(now - updated_on).total_seconds(),
4).capitalize())
else:
updated_on = "|gUnknown|n"
@ -469,9 +470,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
return
# Check that the callback exists
if not callback_name in callbacks:
if callback_name not in callbacks:
self.msg("The callback name {} can't be found in {}.".format(
callback_name, obj))
callback_name, obj))
return
if not parameters:
@ -486,7 +487,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj))
callback_name, parameters, obj))
return
# Accept the callback
@ -495,7 +496,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
else:
self.handler.accept_callback(obj, callback_name, number)
self.msg("The callback {} {} of {} has been accepted.".format(
callback_name, parameters, obj))
callback_name, parameters, obj))
def list_tasks(self):
"""List the active tasks."""
@ -520,40 +521,44 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
self.msg(unicode(table))
# Private functions to handle editing
def _ev_load(caller):
return caller.db._callback and caller.db._callback.get("code", "") or ""
def _ev_save(caller, buf):
"""Save and add the callback."""
lock = "perm({}) or perm(events_without_validation)".format(
WITHOUT_VALIDATION)
WITHOUT_VALIDATION)
autovalid = caller.locks.check_lockstring(caller, lock)
callback = caller.db._callback
handler = get_event_handler()
if not handler or not callback or not all(key in callback for key in \
("obj", "name", "number", "valid")):
if not handler or not callback or not all(key in callback for key in
("obj", "name", "number", "valid")):
caller.msg("Couldn't save this callback.")
return False
if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked:
handler.db.locked.remove((callback["obj"], callback["name"],
callback["number"]))
callback["number"]))
handler.edit_callback(callback["obj"], callback["name"], callback["number"], buf,
caller, valid=autovalid)
caller, valid=autovalid)
return True
def _ev_quit(caller):
callback = caller.db._callback
handler = get_event_handler()
if not handler or not callback or not all(key in callback for key in \
("obj", "name", "number", "valid")):
if not handler or not callback or not all(key in callback for key in
("obj", "name", "number", "valid")):
caller.msg("Couldn't save this callback.")
return False
if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked:
handler.db.locked.remove((callback["obj"], callback["name"],
callback["number"]))
callback["number"]))
del caller.db._callback
caller.msg("Exited the code editor.")

View file

@ -8,6 +8,7 @@ Eventfuncs are just Python functions that can be used inside of calllbacks.
from evennia import ObjectDB, ScriptDB
from evennia.contrib.ingame_python.utils import InterruptEvent
def deny():
"""
Deny, that is stop, the callback here.
@ -22,6 +23,7 @@ def deny():
"""
raise InterruptEvent
def get(**kwargs):
"""
Return an object with the given search option or None if None is found.
@ -53,6 +55,7 @@ def get(**kwargs):
return object
def call_event(obj, event_name, seconds=0):
"""
Call the specified event in X seconds.

View file

@ -21,6 +21,7 @@ from evennia.contrib.ingame_python.utils import get_next_wait, EVENTS, Interrupt
# Constants
RE_LINE_ERROR = re.compile(r'^ File "\<string\>", line (\d+)')
class EventHandler(DefaultScript):
"""
@ -94,7 +95,7 @@ class EventHandler(DefaultScript):
self.ndb.channel = ChannelDB.objects.get(db_key="everror")
except ChannelDB.DoesNotExist:
self.ndb.channel = create_channel("everror", desc="Event errors",
locks="control:false();listen:perm(Builders);send:false()")
locks="control:false();listen:perm(Builders);send:false()")
def get_events(self, obj):
"""
@ -131,7 +132,7 @@ class EventHandler(DefaultScript):
for key, etype in all_events.get(typeclass_name, {}).items():
if key in invalid:
continue
if etype[0] is None: # Invalidate
if etype[0] is None: # Invalidate
invalid.append(key)
continue
if key not in events:
@ -200,7 +201,7 @@ class EventHandler(DefaultScript):
return callbacks
def add_callback(self, obj, callback_name, code, author=None, valid=False,
parameters=""):
parameters=""):
"""
Add the specified callback.
@ -228,11 +229,11 @@ class EventHandler(DefaultScript):
# Add the callback in the list
callbacks.append({
"created_on": datetime.now(),
"author": author,
"valid": valid,
"code": code,
"parameters": parameters,
"created_on": datetime.now(),
"author": author,
"valid": valid,
"code": code,
"parameters": parameters,
})
# If not valid, set it in 'to_valid'
@ -241,7 +242,7 @@ class EventHandler(DefaultScript):
# Call the custom_add if needed
custom_add = self.get_events(obj).get(
callback_name, [None, None, None, None])[3]
callback_name, [None, None, None, None])[3]
if custom_add:
custom_add(obj, callback_name, len(callbacks) - 1, parameters)
@ -253,7 +254,7 @@ class EventHandler(DefaultScript):
return definition
def edit_callback(self, obj, callback_name, number, code, author=None,
valid=False):
valid=False):
"""
Edit the specified callback.
@ -288,10 +289,10 @@ class EventHandler(DefaultScript):
# Edit the callback
callbacks[number].update({
"updated_on": datetime.now(),
"updated_by": author,
"valid": valid,
"code": code,
"updated_on": datetime.now(),
"updated_by": author,
"valid": valid,
"code": code,
})
# If not valid, set it in 'to_valid'
@ -334,7 +335,7 @@ class EventHandler(DefaultScript):
return
else:
logger.log_info("Deleting callback {} {} of {}:\n{}".format(
callback_name, number, obj, code))
callback_name, number, obj, code))
del callbacks[number]
# Change IDs of callbacks to be validated
@ -349,7 +350,7 @@ class EventHandler(DefaultScript):
elif t_number > number:
# Change the ID for this callback
self.db.to_valid.insert(i, (t_obj, t_callback_name,
t_number - 1))
t_number - 1))
del self.db.to_valid[i + 1]
i += 1
@ -414,13 +415,13 @@ class EventHandler(DefaultScript):
# Errors should not pass silently
allowed = ("number", "parameters", "locals")
if any(k for k in kwargs if k not in allowed):
raise TypeError("Unknown keyword arguments were specified " \
"to call callbacks: {}".format(kwargs))
raise TypeError("Unknown keyword arguments were specified "
"to call callbacks: {}".format(kwargs))
event = self.get_events(obj).get(callback_name)
if locals is None and not event:
logger.log_err("The callback {} for the object {} (typeclass " \
"{}) can't be found".format(callback_name, obj, type(obj)))
logger.log_err("The callback {} for the object {} (typeclass "
"{}) can't be found".format(callback_name, obj, type(obj)))
return False
# Prepare the locals if necessary
@ -430,9 +431,9 @@ class EventHandler(DefaultScript):
try:
locals[variable] = args[i]
except IndexError:
logger.log_trace("callback {} of {} ({}): need variable " \
"{} in position {}".format(callback_name, obj,
type(obj), variable, i))
logger.log_trace("callback {} of {} ({}): need variable "
"{} in position {}".format(callback_name, obj,
type(obj), variable, i))
return False
else:
locals = {key: value for key, value in locals.items()}
@ -482,9 +483,9 @@ class EventHandler(DefaultScript):
number = callback["number"]
obj = callback["obj"]
oid = obj.id
logger.log_err("An error occurred during the callback {} of " \
"{} (#{}), number {}\n{}".format(callback_name, obj,
oid, number + 1, "\n".join(trace)))
logger.log_err("An error occurred during the callback {} of "
"{} (#{}), number {}\n{}".format(callback_name, obj,
oid, number + 1, "\n".join(trace)))
# Create the error message
line = "|runknown|n"
@ -505,8 +506,8 @@ class EventHandler(DefaultScript):
exc = raw(trace[-1].strip("\n").splitlines()[-1])
err_msg = "Error in {} of {} (#{})[{}], line {}:" \
" {}\n{}".format(callback_name, obj,
oid, number + 1, lineno, line, exc)
" {}\n{}".format(callback_name, obj,
oid, number + 1, lineno, line, exc)
# Inform the last updater if connected
updater = callback.get("updated_by")
@ -517,8 +518,8 @@ class EventHandler(DefaultScript):
updater.msg(err_msg)
else:
err_msg = "Error in {} of {} (#{})[{}], line {}:" \
" {}\n {}".format(callback_name, obj,
oid, number + 1, lineno, line, exc)
" {}\n {}".format(callback_name, obj,
oid, number + 1, lineno, line, exc)
self.ndb.channel.msg(err_msg)
def add_event(self, typeclass, name, variables, help_text, custom_call, custom_add):
@ -655,8 +656,8 @@ def complete_task(task_id):
return
if task_id not in script.db.tasks:
logger.log_err("The task #{} was scheduled, but it cannot be " \
"found".format(task_id))
logger.log_err("The task #{} was scheduled, but it cannot be "
"found".format(task_id))
return
delta, obj, callback_name, locals = script.db.tasks.pop(task_id)

View file

@ -21,6 +21,7 @@ settings.EVENTS_CALENDAR = "standard"
# Constants
OLD_EVENTS = {}
class TestEventHandler(EvenniaTest):
"""
@ -31,7 +32,7 @@ class TestEventHandler(EvenniaTest):
"""Create the event handler."""
super(TestEventHandler, self).setUp()
self.handler = create_script(
"evennia.contrib.ingame_python.scripts.EventHandler")
"evennia.contrib.ingame_python.scripts.EventHandler")
# Copy old events if necessary
if OLD_EVENTS:
@ -64,7 +65,7 @@ class TestEventHandler(EvenniaTest):
"""Add a callback while needing validation."""
author = self.char1
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 40", author=author, valid=False)
"character.db.strength = 40", author=author, valid=False)
callback = self.handler.get_callbacks(self.room1).get("dummy")
callback = callback[0]
self.assertIsNotNone(callback)
@ -78,18 +79,18 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10
locals = {"character": self.char1}
self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals))
self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 10)
def test_edit(self):
"""Test editing a callback."""
author = self.char1
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 60", author=author, valid=True)
"character.db.strength = 60", author=author, valid=True)
# Edit it right away
self.handler.edit_callback(self.room1, "dummy", 0,
"character.db.strength = 65", author=self.char2, valid=True)
"character.db.strength = 65", author=self.char2, valid=True)
# Check that the callback was written
callback = self.handler.get_callbacks(self.room1).get("dummy")
@ -103,35 +104,35 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10
locals = {"character": self.char1}
self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals))
self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 65)
def test_edit_validation(self):
"""Edit a callback when validation isn't automatic."""
author = self.char1
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 70", author=author, valid=True)
"character.db.strength = 70", author=author, valid=True)
# Edit it right away
self.handler.edit_callback(self.room1, "dummy", 0,
"character.db.strength = 80", author=self.char2, valid=False)
"character.db.strength = 80", author=self.char2, valid=False)
# Run this dummy callback (shouldn't do anything)
self.char1.db.strength = 10
locals = {"character": self.char1}
self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals))
self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 10)
def test_del(self):
"""Try to delete a callback."""
# Add 3 callbacks
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 5", author=self.char1, valid=True)
"character.db.strength = 5", author=self.char1, valid=True)
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 8", author=self.char2, valid=False)
"character.db.strength = 8", author=self.char2, valid=False)
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 9", author=self.char1, valid=True)
"character.db.strength = 9", author=self.char1, valid=True)
# Note that the second callback isn't valid
self.assertIn((self.room1, "dummy", 1), self.handler.db.to_valid)
@ -160,16 +161,16 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10
locals = {"character": self.char1}
self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals))
self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 9)
def test_accept(self):
"""Accept an callback."""
# Add 2 callbacks
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 5", author=self.char1, valid=True)
"character.db.strength = 5", author=self.char1, valid=True)
self.handler.add_callback(self.room1, "dummy",
"character.db.strength = 8", author=self.char2, valid=False)
"character.db.strength = 8", author=self.char2, valid=False)
# Note that the second callback isn't valid
self.assertIn((self.room1, "dummy", 1), self.handler.db.to_valid)
@ -185,7 +186,7 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10
locals = {"character": self.char1}
self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals))
self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 8)
def test_call(self):
@ -201,14 +202,14 @@ class TestEventHandler(EvenniaTest):
character.db.health = 0
""".strip("\n"))
self.handler.add_callback(self.room1, "dummy", code,
author=self.char1, valid=True)
author=self.char1, valid=True)
# Call the dummy callback
self.assertTrue(self.handler.call(
self.room1, "dummy", locals={"character": self.char1}))
self.room1, "dummy", locals={"character": self.char1}))
self.assertEqual(self.char1.db.health, 50)
self.assertTrue(self.handler.call(
self.room1, "dummy", locals={"character": self.char2}))
self.room1, "dummy", locals={"character": self.char2}))
self.assertEqual(self.char2.db.health, 0)
def test_handler(self):
@ -217,7 +218,7 @@ class TestEventHandler(EvenniaTest):
# Add an callback
callback = self.room1.callbacks.add("dummy", "pass", author=self.char1,
valid=True)
valid=True)
self.assertEqual(callback.obj, self.room1)
self.assertEqual(callback.name, "dummy")
self.assertEqual(callback.code, "pass")
@ -227,13 +228,13 @@ class TestEventHandler(EvenniaTest):
# Edit this very callback
new = self.room1.callbacks.edit("dummy", 0, "character.db.say = True",
author=self.char1, valid=True)
author=self.char1, valid=True)
self.assertIn([new], self.room1.callbacks.all().values())
self.assertNotIn([callback], self.room1.callbacks.all().values())
# Try to call this callback
self.assertTrue(self.room1.callbacks.call("dummy",
locals={"character": self.char2}))
locals={"character": self.char2}))
self.assertTrue(self.char2.db.say)
# Delete the callback
@ -249,7 +250,7 @@ class TestCmdCallback(CommandTest):
"""Create the callback handler."""
super(TestCmdCallback, self).setUp()
self.handler = create_script(
"evennia.contrib.ingame_python.scripts.EventHandler")
"evennia.contrib.ingame_python.scripts.EventHandler")
# Copy old events if necessary
if OLD_EVENTS:
@ -287,7 +288,7 @@ class TestCmdCallback(CommandTest):
# Add some callback
self.handler.add_callback(self.exit, "traverse", "pass",
author=self.char1, valid=True)
author=self.char1, valid=True)
# Try to obtain more details on a specific callback on exit
table = self.call(CmdCallback(), "out = traverse")
@ -355,18 +356,18 @@ class TestCmdCallback(CommandTest):
def test_del(self):
"""Add and remove an callback."""
self.handler.add_callback(self.exit, "traverse", "pass",
author=self.char1, valid=True)
author=self.char1, valid=True)
# Try to delete the callback
# char2 shouldn't be allowed to do so (that's not HIS callback)
self.call(CmdCallback(), "/del out = traverse 1", caller=self.char2)
self.assertTrue(len(self.handler.get_callbacks(self.exit).get(
"traverse", [])) == 1)
"traverse", [])) == 1)
# Now, char1 should be allowed to delete it
self.call(CmdCallback(), "/del out = traverse 1")
self.assertTrue(len(self.handler.get_callbacks(self.exit).get(
"traverse", [])) == 0)
"traverse", [])) == 0)
def test_lock(self):
"""Test the lock of multiple editing."""
@ -414,7 +415,7 @@ class TestDefaultCallbacks(CommandTest):
"""Create the callback handler."""
super(TestDefaultCallbacks, self).setUp()
self.handler = create_script(
"evennia.contrib.ingame_python.scripts.EventHandler")
"evennia.contrib.ingame_python.scripts.EventHandler")
# Copy old events if necessary
if OLD_EVENTS:
@ -450,7 +451,7 @@ class TestDefaultCallbacks(CommandTest):
# Try the can_traverse callback
self.handler.add_callback(self.exit, "can_traverse", code,
author=self.char1, valid=True)
author=self.char1, valid=True)
# Have char1 move through the exit
self.call(ExitCommand(), "", "You can leave.", obj=self.exit)
@ -458,13 +459,13 @@ class TestDefaultCallbacks(CommandTest):
# Have char2 move through this exit
self.call(ExitCommand(), "", "You cannot leave.", obj=self.exit,
caller=self.char2)
caller=self.char2)
self.assertIs(self.char2.location, self.room1)
# Try the traverse callback
self.handler.del_callback(self.exit, "can_traverse", 0)
self.handler.add_callback(self.exit, "traverse", "character.msg('Fine!')",
author=self.char1, valid=True)
author=self.char1, valid=True)
# Have char2 move through the exit
self.call(ExitCommand(), "", obj=self.exit, caller=self.char2)
@ -478,15 +479,15 @@ class TestDefaultCallbacks(CommandTest):
# Test msg_arrive and msg_leave
code = 'message = "{character} goes out."'
self.handler.add_callback(self.exit, "msg_leave", code,
author=self.char1, valid=True)
author=self.char1, valid=True)
# Have char1 move through the exit
old_msg = self.char2.msg
try:
self.char2.msg = Mock()
self.call(ExitCommand(), "", obj=self.exit)
stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True))
for name, args, kwargs in self.char2.msg.mock_calls]
stored_msg = [args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs, force_string=True))
for name, args, kwargs in self.char2.msg.mock_calls]
# Get the first element of a tuple if msg received a tuple instead of a string
stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg]
returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True)
@ -496,18 +497,18 @@ class TestDefaultCallbacks(CommandTest):
# Create a return exit
back = create_object("evennia.objects.objects.DefaultExit",
key="in", location=self.room2, destination=self.room1)
key="in", location=self.room2, destination=self.room1)
code = 'message = "{character} goes in."'
self.handler.add_callback(self.exit, "msg_arrive", code,
author=self.char1, valid=True)
author=self.char1, valid=True)
# Have char1 move through the exit
old_msg = self.char2.msg
try:
self.char2.msg = Mock()
self.call(ExitCommand(), "", obj=back)
stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True))
for name, args, kwargs in self.char2.msg.mock_calls]
stored_msg = [args[0] if args and args[0] else kwargs.get("text", utils.to_str(kwargs, force_string=True))
for name, args, kwargs in self.char2.msg.mock_calls]
# Get the first element of a tuple if msg received a tuple instead of a string
stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg]
returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True)

View file

@ -159,6 +159,7 @@ Variables you can use in this event:
character: the character connected to this event.
"""
@register_events
class EventCharacter(DefaultCharacter):
@ -208,12 +209,12 @@ class EventCharacter(DefaultCharacter):
exits = [o for o in location.contents if o.location is location and o.destination is destination]
mapping = mapping or {}
mapping.update({
"character": self,
"character": self,
})
if exits:
exits[0].callbacks.call("msg_leave", self, exits[0],
location, destination, string, mapping)
location, destination, string, mapping)
string = exits[0].callbacks.get_variable("message")
mapping = exits[0].callbacks.get_variable("mapping")
@ -261,14 +262,14 @@ class EventCharacter(DefaultCharacter):
exits = []
mapping = mapping or {}
mapping.update({
"character": self,
"character": self,
})
if origin:
exits = [o for o in destination.contents if o.location is destination and o.destination is origin]
if exits:
exits[0].callbacks.call("msg_arrive", self, exits[0],
origin, destination, string, mapping)
origin, destination, string, mapping)
string = exits[0].callbacks.get_variable("message")
mapping = exits[0].callbacks.get_variable("mapping")
@ -299,7 +300,7 @@ class EventCharacter(DefaultCharacter):
Room = DefaultRoom
if isinstance(origin, Room) and isinstance(destination, Room):
can = self.callbacks.call("can_move", self,
origin, destination)
origin, destination)
if can:
can = origin.callbacks.call("can_move", self, origin)
if can:
@ -489,6 +490,7 @@ Variables you can use in this event:
destination: the character's location after moving.
"""
@register_events
class EventExit(DefaultExit):
@ -520,7 +522,7 @@ class EventExit(DefaultExit):
is_character = inherits_from(traversing_object, DefaultCharacter)
if is_character:
allow = self.callbacks.call("can_traverse", traversing_object,
self, self.location)
self, self.location)
if not allow:
return
@ -529,7 +531,7 @@ class EventExit(DefaultExit):
# After traversing
if is_character:
self.callbacks.call("traverse", traversing_object,
self, self.location, self.destination)
self, self.location, self.destination)
# Object help
@ -573,6 +575,7 @@ Variables you can use in this event:
object: the object connected to this event.
"""
@register_events
class EventObject(DefaultObject):
@ -621,6 +624,7 @@ class EventObject(DefaultObject):
super(EventObject, self).at_drop(dropper)
self.callbacks.call("drop", dropper, self)
# Room help
ROOM_CAN_DELETE = """
Can the room be deleted?
@ -742,6 +746,7 @@ Variables you can use in this event:
room: the room connected to this event.
"""
@register_events
class EventRoom(DefaultRoom):
@ -792,7 +797,7 @@ class EventRoom(DefaultRoom):
"""
allow = self.callbacks.call("can_say", speaker, self, message,
parameters=message)
parameters=message)
if not allow:
return
@ -802,7 +807,7 @@ class EventRoom(DefaultRoom):
for present in [o for o in self.contents if isinstance(
o, DefaultCharacter) and o is not speaker]:
allow = present.callbacks.call("can_say", speaker, present,
message, parameters=message)
message, parameters=message)
if not allow:
return
@ -811,10 +816,10 @@ class EventRoom(DefaultRoom):
# We force the next event to be called after the message
# This will have to change when the Evennia API adds new hooks
delay(0, self.callbacks.call, "say", speaker, self, message,
parameters=message)
parameters=message)
for present in [o for o in self.contents if isinstance(
o, DefaultCharacter) and o is not speaker]:
delay(0, present.callbacks.call, "say", speaker, present, message,
parameters=message)
parameters=message)
return message

View file

@ -20,6 +20,7 @@ from evennia.contrib.custom_gametime import real_seconds_until as custom_rsu
# Temporary storage for events waiting for the script to be started
EVENTS = []
def get_event_handler():
"""Return the event handler or None."""
try:
@ -30,6 +31,7 @@ def get_event_handler():
return script
def register_events(path_or_typeclass):
"""
Register the events in this typeclass.
@ -84,6 +86,8 @@ def register_events(path_or_typeclass):
return typeclass
# Custom callbacks for specific event types
def get_next_wait(format):
"""
Get the length of time in seconds before format.
@ -104,8 +108,8 @@ def get_next_wait(format):
"""
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.")
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
@ -131,8 +135,8 @@ def get_next_wait(format):
break
if not piece.isdigit():
logger.log_trace("The time specified '{}' in {} isn't " \
"a valid number".format(piece, format))
logger.log_trace("The time specified '{}' in {} isn't "
"a valid number".format(piece, format))
return
# Convert the piece to int
@ -154,6 +158,7 @@ def get_next_wait(format):
usual = gametime_to_realtime(**kwargs)
return until, usual, details
def time_event(obj, event_name, number, parameters):
"""
Create a time-related event.
@ -173,6 +178,7 @@ def time_event(obj, event_name, number, parameters):
script.db.number = number
script.ndb.usual = usual
def keyword_event(callbacks, parameters):
"""
Custom call for events with keywords (like push, or pull, or turn...).
@ -201,6 +207,7 @@ def keyword_event(callbacks, parameters):
return to_call
def phrase_event(callbacks, parameters):
"""
Custom call for events with keywords in sentences (like say or whisper).
@ -236,6 +243,7 @@ def phrase_event(callbacks, parameters):
return to_call
class InterruptEvent(RuntimeError):
"""

View file

@ -22,6 +22,7 @@ _HEAD_CHAR = "|015-|n"
_SUB_HEAD_CHAR = "-"
_WIDTH = 78
class CmdMail(default_cmds.MuxCommand):
"""
Commands that allow either IC or OOC communications
@ -253,4 +254,3 @@ class CmdMail(default_cmds.MuxCommand):
self.caller.msg(_HEAD_CHAR * _WIDTH)
else:
self.caller.msg("There are no messages in your inbox.")

View file

@ -173,6 +173,7 @@ def example1_build_temple(x, y, **kwargs):
# This is generally mandatory.
return room
# Include your trigger characters and build functions in a legend dict.
EXAMPLE1_LEGEND = {("", ""): example1_build_forest,
("", "n"): example1_build_mountains,
@ -225,17 +226,17 @@ def example2_build_verticle_exit(x, y, **kwargs):
if kwargs["iteration"] == 0:
return
north_room = kwargs["room_dict"][(x, y-1)]
south_room = kwargs["room_dict"][(x, y+1)]
north_room = kwargs["room_dict"][(x, y - 1)]
south_room = kwargs["room_dict"][(x, y + 1)]
# create exits in the rooms
create_object(exits.Exit, key="south",
aliases=["s"], location=north_room,
destination=south_room)
aliases=["s"], location=north_room,
destination=south_room)
create_object(exits.Exit, key="north",
aliases=["n"], location=south_room,
destination=north_room)
aliases=["n"], location=south_room,
destination=north_room)
kwargs["caller"].msg("Connected: " + north_room.key +
" & " + south_room.key)
@ -247,20 +248,21 @@ def example2_build_horizontal_exit(x, y, **kwargs):
if kwargs["iteration"] == 0:
return
west_room = kwargs["room_dict"][(x-1, y)]
east_room = kwargs["room_dict"][(x+1, y)]
west_room = kwargs["room_dict"][(x - 1, y)]
east_room = kwargs["room_dict"][(x + 1, y)]
create_object(exits.Exit, key="east",
aliases=["e"], location=west_room,
destination=east_room)
aliases=["e"], location=west_room,
destination=east_room)
create_object(exits.Exit, key="west",
aliases=["w"], location=east_room,
destination=west_room)
aliases=["w"], location=east_room,
destination=west_room)
kwargs["caller"].msg("Connected: " + west_room.key +
" & " + east_room.key)
# Include your trigger characters and build functions in a legend dict.
EXAMPLE2_LEGEND = {("", ""): example2_build_forest,
("|"): example2_build_verticle_exit,
@ -339,37 +341,38 @@ def build_map(caller, game_map, legend, iterations=1, build_exits=True):
y = loc_key[1]
# north
if (x, y-1) in room_dict:
if room_dict[(x, y-1)]:
if (x, y - 1) in room_dict:
if room_dict[(x, y - 1)]:
create_object(exits.Exit, key="north",
aliases=["n"], location=location,
destination=room_dict[(x, y-1)])
destination=room_dict[(x, y - 1)])
# east
if (x+1, y) in room_dict:
if room_dict[(x+1, y)]:
if (x + 1, y) in room_dict:
if room_dict[(x + 1, y)]:
create_object(exits.Exit, key="east",
aliases=["e"], location=location,
destination=room_dict[(x+1, y)])
destination=room_dict[(x + 1, y)])
# south
if (x, y+1) in room_dict:
if room_dict[(x, y+1)]:
if (x, y + 1) in room_dict:
if room_dict[(x, y + 1)]:
create_object(exits.Exit, key="south",
aliases=["s"], location=location,
destination=room_dict[(x, y+1)])
destination=room_dict[(x, y + 1)])
# west
if (x-1, y) in room_dict:
if room_dict[(x-1, y)]:
if (x - 1, y) in room_dict:
if room_dict[(x - 1, y)]:
create_object(exits.Exit, key="west",
aliases=["w"], location=location,
destination=room_dict[(x-1, y)])
destination=room_dict[(x - 1, y)])
caller.msg("Map Created.")
# access command
class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
"""
Build a map from a 2D ASCII map.
@ -478,4 +481,3 @@ class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
# Pass map and legend to the build function.
build_map(caller, game_map, legend, iterations, build_exits)

View file

@ -276,7 +276,7 @@ def create_password(caller, string_input):
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
typeclass = settings.BASE_CHARACTER_TYPECLASS
new_account = unloggedin._create_account(caller, accountname,
password, permissions)
password, permissions)
if new_account:
if settings.MULTISESSION_MODE < 2:
default_home = ObjectDB.objects.get_id(

View file

@ -97,6 +97,7 @@ def _update_store(caller, key=None, desc=None, delete=False, swapkey=None):
# eveditor save/load/quit functions
def _save_editor(caller, buffer):
"Called when the editor saves its contents"
key = caller.db._multidesc_editkey
@ -104,6 +105,7 @@ def _save_editor(caller, buffer):
caller.msg("Saved description to key '%s'." % key)
return True
def _load_editor(caller):
"Called when the editor loads contents"
key = caller.db._multidesc_editkey
@ -112,6 +114,7 @@ def _load_editor(caller):
return caller.db.multidesc[match[0]][1]
return ""
def _quit_editor(caller):
"Called when the editor quits"
del caller.db._multidesc_editkey
@ -161,13 +164,13 @@ class CmdMultiDesc(default_cmds.MuxCommand):
# list all stored descriptions, either in full or cropped.
# Note that we list starting from 1, not from 0.
_update_store(caller)
do_crop = not "full" in switches
do_crop = "full" not in switches
if do_crop:
outtext = ["|w%s:|n %s" % (key, crop(desc))
for key, desc in caller.db.multidesc]
for key, desc in caller.db.multidesc]
else:
outtext = ["\n|w%s:|n|n\n%s\n%s" % (key, "-" * (len(key) + 1), desc)
for key, desc in caller.db.multidesc]
for key, desc in caller.db.multidesc]
caller.msg("|wStored descs:|n\n" + "\n".join(outtext))
return
@ -249,6 +252,6 @@ class CmdMultiDesc(default_cmds.MuxCommand):
else:
caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc)
except DescValidateError, err:
except DescValidateError as err:
# This is triggered by _key_to_index
caller.msg(err)

View file

@ -57,6 +57,7 @@ import time
from evennia import DefaultScript, ScriptDB
from evennia.utils.create import create_script
class RejectedRegex(RuntimeError):
"""The provided regular expression has been rejected.
@ -331,7 +332,7 @@ class RandomStringGenerator(object):
generated = script.db.generated.get(self.name, [])
if element not in generated:
raise ValueError("the string {} isn't stored as generated by the generator {}".format(
element, self.name))
element, self.name))
generated.remove(element)

View file

@ -148,13 +148,13 @@ class LanguageHandler(DefaultScript):
don't know the language well enough).
"""
def at_script_creation(self):
"Called when script is first started"
self.key = "language_handler"
self.persistent = True
self.db.language_storage = {}
def add(self, key="default", phonemes=_PHONEMES,
grammar=_GRAMMAR, word_length_variance=0, noun_prefix="",
noun_postfix="", vowels=_VOWELS, manual_translations=None,
@ -240,8 +240,8 @@ class LanguageHandler(DefaultScript):
word = word.strip()
lword = len(word)
new_word = ""
wlen = max(0, lword + sum(randint(-1,1) for i
in range(word_length_variance)))
wlen = max(0, lword + sum(randint(-1, 1) for i
in range(word_length_variance)))
if wlen not in grammar:
# always create a translation, use random length
structure = choice(grammar[choice(list(grammar))])
@ -257,7 +257,7 @@ class LanguageHandler(DefaultScript):
translation.update(dict((key.lower(), value.lower()) for key, value in manual_translations.items()))
# store data
storage = {"translation" : translation,
storage = {"translation": translation,
"grammar": grammar,
"grammar2phonemes": dict(grammar2phonemes),
"word_length_variance": word_length_variance,
@ -296,8 +296,8 @@ class LanguageHandler(DefaultScript):
else:
# make up translation on the fly. Length can
# vary from un-translated word.
wlen = max(0, lword + sum(randint(-1,1) for i
in range(self.language["word_length_variance"])))
wlen = max(0, lword + sum(randint(-1, 1) for i
in range(self.language["word_length_variance"])))
grammar = self.language["grammar"]
if wlen not in grammar:
# this word has no direct translation!
@ -347,6 +347,8 @@ class LanguageHandler(DefaultScript):
# Language access functions
_LANGUAGE_HANDLER = None
def obfuscate_language(text, level=0.0, language="default"):
"""
Main access method for the language parser.
@ -412,7 +414,6 @@ def available_languages():
return list(_LANGUAGE_HANDLER.attributes.get("language_storage", {}))
#------------------------------------------------------------
#
# Whisper obscuration
@ -427,6 +428,7 @@ def available_languages():
#
#------------------------------------------------------------
_RE_WHISPER_OBSCURE = [
re.compile(r"^$", _RE_FLAGS), # This is a Test! #0 full whisper
re.compile(r"[ae]", _RE_FLAGS), # This -s - Test! #1 add uy
@ -434,7 +436,7 @@ _RE_WHISPER_OBSCURE = [
re.compile(r"[aeiouy]", _RE_FLAGS), # Th-s -s - T-st! #3 add all consonants
re.compile(r"[aeiouybdhjlmnpqrv]", _RE_FLAGS), # T--s -s - T-st! #4 add hard consonants
re.compile(r"[a-eg-rt-z]", _RE_FLAGS), # T--s -s - T-s-! #5 add all capitals
re.compile(r"[A-EG-RT-Za-eg-rt-z]", _RE_FLAGS), # ---s -s - --s-! #6 add f
re.compile(r"[A-EG-RT-Za-eg-rt-z]", _RE_FLAGS), # ---s -s - --s-! #6 add f
re.compile(r"[A-EG-RT-Za-rt-z]", _RE_FLAGS), # ---s -s - --s-! #7 add s
re.compile(r"[A-EG-RT-Za-z]", _RE_FLAGS), # ---- -- - ----! #8 add capital F
re.compile(r"[A-RT-Za-z]", _RE_FLAGS), # ---- -- - ----! #9 add capital S
@ -460,4 +462,3 @@ def obfuscate_whisper(whisper, level=0.0):
level = min(max(0.0, level), 1.0)
olevel = int(13.0 * level)
return _RE_WHISPER_OBSCURE[olevel].sub('...' if olevel == 13.0 else '-', whisper)

View file

@ -127,10 +127,10 @@ _NUM_SEP = "-"
# Texts
_EMOTE_NOMATCH_ERROR = \
"""|RNo match for |r{ref}|R.|n"""
"""|RNo match for |r{ref}|R.|n"""
_EMOTE_MULTIMATCH_ERROR = \
"""|RMultiple possibilities for {ref}:
"""|RMultiple possibilities for {ref}:
|r{reflist}|n"""
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
@ -142,7 +142,7 @@ _RE_PREFIX = re.compile(r"^%s" % _PREFIX, re.UNICODE)
# marker. So entering "/tall man" will return groups ("", "tall")
# and "/2-tall man" will return groups ("2", "tall").
_RE_OBJ_REF_START = re.compile(r"%s(?:([0-9]+)%s)*(\w+)" %
(_PREFIX, _NUM_SEP), _RE_FLAGS)
(_PREFIX, _NUM_SEP), _RE_FLAGS)
_RE_LEFT_BRACKETS = re.compile(r"\{+", _RE_FLAGS)
_RE_RIGHT_BRACKETS = re.compile(r"\}+", _RE_FLAGS)
@ -168,6 +168,7 @@ _RE_LANGUAGE = re.compile(r"(?:\((\w+)\))*(\".+?\")")
# 2) for every person seeing the emote, parse this
# intermediary form into the one valid for that char.
class EmoteError(Exception):
pass
@ -240,6 +241,7 @@ def ordered_permutation_regex(sentence):
regex = r"|".join(sorted(set(solution), key=len, reverse=True))
return regex
def regex_tuple_from_key_alias(obj):
"""
This will build a regex tuple for any object, not just from those
@ -358,13 +360,13 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False):
"""
# Load all candidate regex tuples [(regex, obj, sdesc/recog),...]
candidate_regexes = \
([(_RE_SELF_REF, sender, sender.sdesc.get())] if hasattr(sender, "sdesc") else [])+ \
([sender.recog.get_regex_tuple(obj) for obj in candidates] if hasattr(sender, "recog") else []) + \
[obj.sdesc.get_regex_tuple()
for obj in candidates if hasattr(obj, "sdesc")] + \
[regex_tuple_from_key_alias(obj) # handle objects without sdescs
for obj in candidates if not (hasattr(obj, "recog") and
hasattr(obj, "sdesc"))]
([(_RE_SELF_REF, sender, sender.sdesc.get())] if hasattr(sender, "sdesc") else []) + \
([sender.recog.get_regex_tuple(obj) for obj in candidates] if hasattr(sender, "recog") else []) + \
[obj.sdesc.get_regex_tuple()
for obj in candidates if hasattr(obj, "sdesc")] + \
[regex_tuple_from_key_alias(obj) # handle objects without sdescs
for obj in candidates if not (hasattr(obj, "recog") and
hasattr(obj, "sdesc"))]
# filter out non-found data
candidate_regexes = [tup for tup in candidate_regexes if tup]
@ -387,7 +389,7 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False):
# start index forward for all candidates.
# first see if there is a number given (e.g. 1-tall)
num_identifier, _ = marker_match.groups("") # return "" if no match, rather than None
num_identifier, _ = marker_match.groups("") # return "" if no match, rather than None
istart0 = marker_match.start()
istart = istart0
@ -418,7 +420,7 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False):
else:
# multi-match.
# was a numerical identifier given to help us separate the multi-match?
inum = min(max(0, int(num_identifier) - 1), nmatches-1) if num_identifier else None
inum = min(max(0, int(num_identifier) - 1), nmatches - 1) if num_identifier else None
if inum is not None:
# A valid inum is given. Use this to separate data.
obj = bestmatches[inum][0]
@ -438,10 +440,10 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False):
mapping[key] = obj
else:
refname = marker_match.group()
reflist = ["%s%s%s (%s%s)" % (inum+1, _NUM_SEP,
_RE_PREFIX.sub("", refname), text,
" (%s)" % sender.key if sender == ob else "")
for inum, (ob, text) in enumerate(obj)]
reflist = ["%s%s%s (%s%s)" % (inum + 1, _NUM_SEP,
_RE_PREFIX.sub("", refname), text,
" (%s)" % sender.key if sender == ob else "")
for inum, (ob, text) in enumerate(obj)]
errors.append(_EMOTE_MULTIMATCH_ERROR.format(
ref=marker_match.group(), reflist="\n ".join(reflist)))
if search_mode:
@ -532,8 +534,8 @@ def send_emote(sender, receivers, emote, anonymous_add="first"):
receiver_sdesc_mapping = dict((ref, process_recog(recog_get(obj), obj)) for ref, obj in obj_mapping.items())
except AttributeError:
receiver_sdesc_mapping = dict((ref, process_sdesc(obj.sdesc.get(), obj)
if hasattr(obj, "sdesc") else process_sdesc(obj.key, obj))
for ref, obj in obj_mapping.items())
if hasattr(obj, "sdesc") else process_sdesc(obj.key, obj))
for ref, obj in obj_mapping.items())
# make sure receiver always sees their real name
rkey = "#%i" % receiver.id
if rkey in receiver_sdesc_mapping:
@ -546,6 +548,7 @@ def send_emote(sender, receivers, emote, anonymous_add="first"):
# Handlers for sdesc and recog
#------------------------------------------------------------
class SdescHandler(object):
"""
This Handler wraps all operations with sdescs. We
@ -559,6 +562,7 @@ class SdescHandler(object):
_regex - an empty dictionary
"""
def __init__(self, obj):
"""
Initialize the handler
@ -600,10 +604,10 @@ class SdescHandler(object):
"""
# strip emote components from sdesc
sdesc = _RE_REF.sub(r"\1",
_RE_REF_LANG.sub(r"\1",
_RE_SELF_REF.sub(r"",
_RE_LANGUAGE.sub(r"",
_RE_OBJ_REF_START.sub(r"", sdesc)))))
_RE_REF_LANG.sub(r"\1",
_RE_SELF_REF.sub(r"",
_RE_LANGUAGE.sub(r"",
_RE_OBJ_REF_START.sub(r"", sdesc)))))
# make an sdesc clean of ANSI codes
cleaned_sdesc = ansi.strip_ansi(sdesc)
@ -656,6 +660,7 @@ class RecogHandler(object):
_recog_obj2regex
"""
def __init__(self, obj):
"""
Initialize the handler
@ -679,9 +684,9 @@ class RecogHandler(object):
obj2regex = self.obj.attributes.get("_recog_obj2regex", default={})
obj2recog = self.obj.attributes.get("_recog_obj2recog", default={})
self.obj2regex = dict((obj, re.compile(regex, _RE_FLAGS))
for obj, regex in obj2regex.items() if obj)
for obj, regex in obj2regex.items() if obj)
self.obj2recog = dict((obj, recog)
for obj, recog in obj2recog.items() if obj)
for obj, recog in obj2recog.items() if obj)
def add(self, obj, recog, max_length=60):
"""
@ -705,10 +710,10 @@ class RecogHandler(object):
"""
# strip emote components from recog
recog = _RE_REF.sub(r"\1",
_RE_REF_LANG.sub(r"\1",
_RE_SELF_REF.sub(r"",
_RE_LANGUAGE.sub(r"",
_RE_OBJ_REF_START.sub(r"", recog)))))
_RE_REF_LANG.sub(r"\1",
_RE_SELF_REF.sub(r"",
_RE_LANGUAGE.sub(r"",
_RE_OBJ_REF_START.sub(r"", recog)))))
# make an recog clean of ANSI codes
cleaned_recog = ansi.strip_ansi(recog)
@ -751,7 +756,7 @@ class RecogHandler(object):
# to avoid revealing masked characters. If lock
# does not exist, pass automatically.
return self.obj2recog.get(obj, obj.sdesc.get()
if hasattr(obj, "sdesc") else obj.key)
if hasattr(obj, "sdesc") else obj.key)
else:
# recog_mask log not passed, disable recog
return obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key
@ -785,6 +790,7 @@ class RecogHandler(object):
class RPCommand(Command):
"simple parent"
def parse(self):
"strip extra whitespace"
self.args = self.args.strip()
@ -828,7 +834,7 @@ class CmdEmote(RPCommand): # replaces the main emote
send_emote(self.caller, targets, emote, anonymous_add='first')
class CmdSay(RPCommand): # replaces standard say
class CmdSay(RPCommand): # replaces standard say
"""
speak as your character
@ -843,7 +849,6 @@ class CmdSay(RPCommand): # replaces standard say
locks = "cmd:all()"
def func(self):
"Run the say command"
caller = self.caller
@ -860,7 +865,7 @@ class CmdSay(RPCommand): # replaces standard say
send_emote(self.caller, targets, speech, anonymous_add=None)
class CmdSdesc(RPCommand): # set/look at own sdesc
class CmdSdesc(RPCommand): # set/look at own sdesc
"""
Assign yourself a short description (sdesc).
@ -884,13 +889,13 @@ class CmdSdesc(RPCommand): # set/look at own sdesc
sdesc = _RE_CHAREND.sub("", self.args)
try:
sdesc = caller.sdesc.add(sdesc)
except SdescError, err:
except SdescError as err:
caller.msg(err)
return
caller.msg("%s's sdesc was set to '%s'." % (caller.key, sdesc))
class CmdPose(RPCommand): # set current pose and default pose
class CmdPose(RPCommand): # set current pose and default pose
"""
Set a static pose
@ -976,7 +981,7 @@ class CmdPose(RPCommand): # set current pose and default pose
# set the pose. We do one-time ref->sdesc mapping here.
parsed, mapping = parse_sdescs_and_recogs(caller, caller.location.contents, pose)
mapping = dict((ref, obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key)
for ref, obj in mapping.iteritems())
for ref, obj in mapping.iteritems())
pose = parsed.format(**mapping)
if len(target_name) + len(pose) > 60:
@ -988,7 +993,7 @@ class CmdPose(RPCommand): # set current pose and default pose
caller.msg("Pose will read '%s %s'." % (target_name, pose))
class CmdRecog(RPCommand): # assign personal alias to object in room
class CmdRecog(RPCommand): # assign personal alias to object in room
"""
Recognize another person in the same room.
@ -1034,11 +1039,11 @@ class CmdRecog(RPCommand): # assign personal alias to object in room
if nmatches == 0:
caller.msg(_EMOTE_NOMATCH_ERROR.format(ref=sdesc))
elif nmatches > 1:
reflist = ["%s%s%s (%s%s)" % (inum+1, _NUM_SEP,
_RE_PREFIX.sub("", sdesc), caller.recog.get(obj),
" (%s)" % caller.key if caller == obj else "")
for inum, obj in enumerate(matches)]
caller.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=sdesc,reflist="\n ".join(reflist)))
reflist = ["%s%s%s (%s%s)" % (inum + 1, _NUM_SEP,
_RE_PREFIX.sub("", sdesc), caller.recog.get(obj),
" (%s)" % caller.key if caller == obj else "")
for inum, obj in enumerate(matches)]
caller.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=sdesc, reflist="\n ".join(reflist)))
else:
obj = matches[0]
if not obj.access(self.obj, "enable_recog", default=True):
@ -1053,7 +1058,7 @@ class CmdRecog(RPCommand): # assign personal alias to object in room
sdesc = obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key
try:
alias = caller.recog.add(obj, alias)
except RecogError, err:
except RecogError as err:
caller.msg(err)
return
caller.msg("%s will now remember |w%s|n as |w%s|n." % (caller.key, sdesc, alias))
@ -1095,7 +1100,7 @@ class CmdMask(RPCommand):
caller.sdesc.add(sdesc)
caller.msg("You wear a mask as '%s'." % sdesc)
else:
#unmask
# unmask
old_sdesc = caller.db.unmasked_sdesc
if not old_sdesc:
caller.msg("You are not wearing a mask.")
@ -1110,6 +1115,7 @@ class RPSystemCmdSet(CmdSet):
"""
Mix-in for adding rp-commands to default cmdset.
"""
def at_cmdset_creation(self):
self.add(CmdEmote())
self.add(CmdSay())
@ -1231,7 +1237,7 @@ class ContribRPObject(DefaultObject):
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "account"), include_account=True)
if(global_search or (is_string and searchdata.startswith("#") and
len(searchdata) > 1 and searchdata[1:].isdigit())):
len(searchdata) > 1 and searchdata[1:].isdigit())):
# only allow exact matching if searching the entire database
# or unique #dbrefs
exact = True
@ -1258,16 +1264,17 @@ class ContribRPObject(DefaultObject):
# the sdesc-related substitution
is_builder = self.locks.check_lockstring(self, "perm(Builder)")
use_dbref = is_builder if use_dbref is None else use_dbref
search_obj = lambda string: ObjectDB.objects.object_search(string,
attribute_name=attribute_name,
typeclass=typeclass,
candidates=candidates,
exact=exact,
use_dbref=use_dbref)
def search_obj(string): return ObjectDB.objects.object_search(string,
attribute_name=attribute_name,
typeclass=typeclass,
candidates=candidates,
exact=exact,
use_dbref=use_dbref)
if candidates:
candidates = parse_sdescs_and_recogs(self, candidates,
_PREFIX + searchdata, search_mode=True)
_PREFIX + searchdata, search_mode=True)
results = []
for candidate in candidates:
# we search by candidate keys here; this allows full error
@ -1288,8 +1295,8 @@ class ContribRPObject(DefaultObject):
if quiet:
return results
return _AT_SEARCH_RESULT(results, self, query=searchdata,
nofound_string=nofound_string, multimatch_string=multimatch_string)
return _AT_SEARCH_RESULT(results, self, query=searchdata,
nofound_string=nofound_string, multimatch_string=multimatch_string)
def get_display_name(self, looker, **kwargs):
"""
@ -1336,7 +1343,7 @@ class ContribRPObject(DefaultObject):
return ""
# get and identify all objects
visible = (con for con in self.contents if con != looker and
con.access(looker, "view"))
con.access(looker, "view"))
exits, users, things = [], [], []
for con in visible:
key = con.get_display_name(looker, pose=True)
@ -1488,4 +1495,4 @@ class ContribRPCharacter(DefaultCharacter, ContribRPObject):
return "%s|w%s|n" % ("|W(%s)" % language if language else "", text)
#from evennia.contrib import rplanguage
#return "|w%s|n" % rplanguage.obfuscate_language(text, level=1.0)
# return "|w%s|n" % rplanguage.obfuscate_language(text, level=1.0)

View file

@ -40,6 +40,7 @@ class SimpleDoor(DefaultExit):
sides using `exitname.setlock("traverse:false())`
"""
def at_object_creation(self):
"""
Called the very first time the door is created.
@ -115,7 +116,7 @@ class CmdOpen(default_cmds.CmdOpen):
self.caller.msg("Note: A door-type exit was created - ignored eventual custom return-exit type.")
self.return_exit_already_created = True
back_exit = self.create_exit(exit_name, destination, location,
exit_aliases=exit_aliases, typeclass=typeclass)
exit_aliases=exit_aliases, typeclass=typeclass)
new_exit.db.return_exit = back_exit
back_exit.db.return_exit = new_exit
return new_exit
@ -159,10 +160,9 @@ class CmdOpenCloseDoor(default_cmds.MuxCommand):
else:
door.setlock("traverse:true()")
self.caller.msg("You open %s." % door.key)
else: # close
else: # close
if not door.locks.check(self.caller, "traverse"):
self.caller.msg("%s is already closed." % door.key)
else:
door.setlock("traverse:false()")
self.caller.msg("You close %s." % door.key)

View file

@ -42,10 +42,12 @@ MOVE_DELAY = {"stroll": 6,
"run": 2,
"sprint": 1}
class SlowExit(DefaultExit):
"""
This overloads the way moving happens.
"""
def at_traverse(self, traversing_object, target_location):
"""
Implements the actual traversal, using utils.delay to delay the move_to.
@ -87,6 +89,7 @@ SPEED_DESCS = {"stroll": "strolling",
"run": "running",
"sprint": "sprinting"}
class CmdSetSpeed(Command):
"""
set your movement speed

View file

@ -48,6 +48,7 @@ def info1(caller):
return text, options
def info2(caller):
text = "'My name is not really important ... I'm just an NPC after all.'"
@ -67,7 +68,6 @@ def info3(caller):
{"desc": "Wait, why don't you tell me your name first?",
"goto": "info2"})
return text, options
@ -82,6 +82,7 @@ def END(caller):
# The talk command (sits on the NPC)
#
class CmdTalk(default_cmds.MuxCommand):
"""
Talks to an npc
@ -112,6 +113,7 @@ class CmdTalk(default_cmds.MuxCommand):
class TalkingCmdSet(CmdSet):
"Stores the talk command."
key = "talkingcmdset"
def at_cmdset_creation(self):
"populates the cmdset"
self.add(CmdTalk())
@ -122,6 +124,7 @@ class TalkingNPC(DefaultObject):
This implements a simple Object using the talk command and using
the conversation defined above.
"""
def at_object_creation(self):
"This is called when object is first created."
self.db.desc = "This is a talkative NPC."

View file

@ -64,6 +64,7 @@ class TestLanguage(EvenniaTest):
# Testing of emoting / sdesc / recog system
from evennia import create_object
from evennia.contrib import rpsystem
@ -176,6 +177,7 @@ from evennia.contrib import extended_room
from evennia import gametime
from evennia.objects.objects import DefaultRoom
class ForceUTCDatetime(datetime.datetime):
"""Force UTC datetime."""
@ -185,6 +187,7 @@ class ForceUTCDatetime(datetime.datetime):
"""Force fromtimestamp to run with naive datetimes."""
return datetime.datetime.utcfromtimestamp(timestamp)
@patch('evennia.contrib.extended_room.datetime.datetime', ForceUTCDatetime)
class TestExtendedRoom(CommandTest):
room_typeclass = extended_room.ExtendedRoom
@ -208,7 +211,7 @@ class TestExtendedRoom(CommandTest):
old_desc = DefaultRoom.return_appearance(self.room1, self.char1)
# the new appearance should be the old one, but with the desc switched
self.assertEqual(old_desc.replace(self.OLD_DESC, self.SPRING_DESC),
self.room1.return_appearance(self.char1))
self.room1.return_appearance(self.char1))
self.assertEqual("spring", self.room1.ndb.last_season)
self.assertEqual("evening", self.room1.ndb.last_timeslot)
@ -223,7 +226,7 @@ class TestExtendedRoom(CommandTest):
def test_cmdextendeddesc(self):
self.call(extended_room.CmdExtendedDesc(), "", "Details on Room", cmdstring="detail")
self.call(extended_room.CmdExtendedDesc(), "thingie = newdetail with spaces",
"Set Detail thingie to 'newdetail with spaces'.", cmdstring="detail")
"Set Detail thingie to 'newdetail with spaces'.", cmdstring="detail")
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' on Room:\n", cmdstring="detail")
self.call(extended_room.CmdExtendedDesc(), "/del thingie", "Detail thingie deleted, if it existed.", cmdstring="detail")
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' not found.", cmdstring="detail")
@ -237,6 +240,7 @@ class TestExtendedRoom(CommandTest):
from evennia.contrib import barter
class TestBarter(CommandTest):
def setUp(self):
@ -295,7 +299,7 @@ class TestBarter(CommandTest):
self.call(barter.CmdTrade(), "Char decline : Nope!", "You say, \"Nope!\"", caller=self.char2)
self.call(barter.CmdTrade(), "Char2 : Hey wanna trade?", "You say, \"Hey wanna trade?\"", caller=self.char1)
self.call(barter.CmdTrade(), "Char accept : Sure!", "You say, \"Sure!\"", caller=self.char2)
self.call(barter.CmdOffer(), "TradeItem3", "Your trade action: You offer TradeItem3",caller=self.char2)
self.call(barter.CmdOffer(), "TradeItem3", "Your trade action: You offer TradeItem3", caller=self.char2)
self.call(barter.CmdOffer(), "TradeItem1 : Here's my offer.", "You say, \"Here's my offer.\"\n [You offer TradeItem1]")
self.call(barter.CmdAccept(), "", "Your trade action: You accept the offer. Char2 must now also accept")
self.call(barter.CmdDecline(), "", "Your trade action: You change your mind, declining the current offer.")
@ -319,9 +323,11 @@ class TestBarter(CommandTest):
# Test wilderness
from evennia.contrib import wilderness
from evennia import DefaultCharacter
class TestWilderness(EvenniaTest):
def setUp(self):
@ -372,8 +378,8 @@ class TestWilderness(EvenniaTest):
# be visible / traversable
exits = [i for i in self.char1.location.contents
if i.destination and (
i.access(self.char1, "view") or
i.access(self.char1, "traverse"))]
i.access(self.char1, "view") or
i.access(self.char1, "traverse"))]
self.assertEquals(len(exits), 3)
exitsok = ["north", "northeast", "east"]
@ -385,8 +391,8 @@ class TestWilderness(EvenniaTest):
wilderness.enter_wilderness(self.char1, coordinates=(1, 1))
exits = [i for i in self.char1.location.contents
if i.destination and (
i.access(self.char1, "view") or
i.access(self.char1, "traverse"))]
i.access(self.char1, "view") or
i.access(self.char1, "traverse"))]
self.assertEquals(len(exits), 8)
exitsok = ["north", "northeast", "east", "southeast", "south",
"southwest", "west", "northwest"]
@ -438,9 +444,11 @@ class TestWilderness(EvenniaTest):
new_loc = wilderness.get_new_coordinates(loc, direction)
self.assertEquals(new_loc, correct_loc, direction)
# Testing chargen contrib
from evennia.contrib import chargen
class TestChargen(CommandTest):
def test_ooclook(self):
@ -451,13 +459,15 @@ class TestChargen(CommandTest):
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "The character testchar was successfully created!", caller=self.account)
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "Character testchar already exists.", caller=self.account)
self.assertTrue(self.account.db._character_dbrefs)
self.call(chargen.CmdOOCLook(), "", "You, TestAccount, are an OOC ghost without form.",caller=self.account)
self.call(chargen.CmdOOCLook(), "", "You, TestAccount, are an OOC ghost without form.", caller=self.account)
self.call(chargen.CmdOOCLook(), "testchar", "testchar(", caller=self.account)
# Testing clothing contrib
from evennia.contrib import clothing
from evennia.objects.objects import DefaultRoom
class TestClothingCmd(CommandTest):
def test_clothingcommands(self):
@ -501,6 +511,7 @@ class TestClothingCmd(CommandTest):
# Test inventory command.
self.call(clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=wearer)
class TestClothingFunc(EvenniaTest):
def test_clothingfunctions(self):
@ -537,42 +548,50 @@ class TestClothingFunc(EvenniaTest):
test_pants.wear(wearer, True)
self.assertEqual(clothing.get_worn_clothes(wearer), [test_hat, test_pants])
self.assertEqual(clothing.clothing_type_count(clothes_list), {'hat':1, 'top':1, 'bottom':1})
self.assertEqual(clothing.clothing_type_count(clothes_list), {'hat': 1, 'top': 1, 'bottom': 1})
self.assertEqual(clothing.single_type_count(clothes_list, 'hat'), 1)
# Testing custom_gametime
from evennia.contrib import custom_gametime
def _testcallback():
pass
class TestCustomGameTime(EvenniaTest):
def setUp(self):
super(TestCustomGameTime, self).setUp()
gametime.gametime = Mock(return_value=2975000898.46) # does not seem to work
gametime.gametime = Mock(return_value=2975000898.46) # does not seem to work
def tearDown(self):
if hasattr(self, "timescript"):
self.timescript.stop()
def test_time_to_tuple(self):
self.assertEqual(custom_gametime.time_to_tuple(10000, 34,2,4,6,1), (294, 2, 0, 0, 0, 0))
self.assertEqual(custom_gametime.time_to_tuple(10000, 3,3,4), (3333, 0, 0, 1))
self.assertEqual(custom_gametime.time_to_tuple(100000, 239,24,3), (418, 4, 0, 2))
self.assertEqual(custom_gametime.time_to_tuple(10000, 34, 2, 4, 6, 1), (294, 2, 0, 0, 0, 0))
self.assertEqual(custom_gametime.time_to_tuple(10000, 3, 3, 4), (3333, 0, 0, 1))
self.assertEqual(custom_gametime.time_to_tuple(100000, 239, 24, 3), (418, 4, 0, 2))
def test_gametime_to_realtime(self):
self.assertEqual(custom_gametime.gametime_to_realtime(days=2, mins=4), 86520.0)
self.assertEqual(custom_gametime.gametime_to_realtime(format=True, days=2), (0,0,0,1,0,0,0))
self.assertEqual(custom_gametime.gametime_to_realtime(format=True, days=2), (0, 0, 0, 1, 0, 0, 0))
def test_realtime_to_gametime(self):
self.assertEqual(custom_gametime.realtime_to_gametime(days=2, mins=34), 349680.0)
self.assertEqual(custom_gametime.realtime_to_gametime(days=2, mins=34, format=True), (0, 0, 0, 4, 1, 8, 0))
self.assertEqual(custom_gametime.realtime_to_gametime(format=True, days=2, mins=4), (0, 0, 0, 4, 0, 8, 0))
def test_custom_gametime(self):
self.assertEqual(custom_gametime.custom_gametime(), (102, 5, 2, 6, 21, 8, 18))
self.assertEqual(custom_gametime.custom_gametime(absolute=True), (102, 5, 2, 6, 21, 8, 18))
def test_real_seconds_until(self):
self.assertEqual(custom_gametime.real_seconds_until(year=2300, month=11, day=6), 31911667199.77)
def test_schedule(self):
self.timescript = custom_gametime.schedule(_testcallback, repeat=True, min=5, sec=0)
self.assertEqual(self.timescript.interval, 1700.7699999809265)
@ -585,9 +604,10 @@ class TestDice(CommandTest):
def test_roll_dice(self, mocked_randint):
# we must import dice here for the mocked randint to apply correctly.
from evennia.contrib import dice
self.assertEqual(dice.roll_dice(6, 6, modifier=('+', 4)), mocked_randint()*6 + 4)
self.assertEqual(dice.roll_dice(6, 6, modifier=('+', 4)), mocked_randint() * 6 + 4)
self.assertEqual(dice.roll_dice(6, 6, conditional=('<', 35)), True)
self.assertEqual(dice.roll_dice(6, 6, conditional=('>', 33)), False)
def test_cmddice(self, mocked_randint):
from evennia.contrib import dice
self.call(dice.CmdDice(), "3d6 + 4", "You roll 3d6 + 4.| Roll(s): 5, 5 and 5. Total result is 19.")
@ -596,29 +616,37 @@ class TestDice(CommandTest):
# Test email-login
from evennia.contrib import email_login
class TestEmailLogin(CommandTest):
def test_connect(self):
self.call(email_login.CmdUnconnectedConnect(), "mytest@test.com test", "The email 'mytest@test.com' does not match any accounts.")
self.call(email_login.CmdUnconnectedCreate(), '"mytest" mytest@test.com test11111', "A new account 'mytest' was created. Welcome!")
self.call(email_login.CmdUnconnectedConnect(), "mytest@test.com test11111", "", caller=self.account.sessions.get()[0])
def test_quit(self):
self.call(email_login.CmdUnconnectedQuit(), "", "", caller=self.account.sessions.get()[0])
def test_unconnectedlook(self):
self.call(email_login.CmdUnconnectedLook(), "", "==========")
def test_unconnectedhelp(self):
self.call(email_login.CmdUnconnectedHelp(), "", "You are not yet logged into the game.")
# test gendersub contrib
from evennia.contrib import gendersub
class TestGenderSub(CommandTest):
def test_setgender(self):
self.call(gendersub.SetGender(), "male", "Your gender was set to male.")
self.call(gendersub.SetGender(), "ambiguous", "Your gender was set to ambiguous.")
self.call(gendersub.SetGender(), "Foo", "Usage: @gender")
def test_gendercharacter(self):
char = create_object(gendersub.GenderCharacter, key="Gendered", location=self.room1)
txt = "Test |p gender"
@ -626,8 +654,10 @@ class TestGenderSub(CommandTest):
# test mail contrib
from evennia.contrib import mail
class TestMail(CommandTest):
def test_mail(self):
self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account)
@ -635,7 +665,7 @@ class TestMail(CommandTest):
self.call(mail.CmdMail(), "Char=Message 1", "You have received a new @mail from Char|You sent your message.", caller=self.char1)
self.call(mail.CmdMail(), "Char=Message 2", "You sent your message.", caller=self.char2)
self.call(mail.CmdMail(), "TestAccount2=Message 2",
"You have received a new @mail from TestAccount2(account 2)|You sent your message.", caller=self.account2)
"You have received a new @mail from TestAccount2(account 2)|You sent your message.", caller=self.account2)
self.call(mail.CmdMail(), "TestAccount=Message 1", "You sent your message.", caller=self.account2)
self.call(mail.CmdMail(), "TestAccount=Message 2", "You sent your message.", caller=self.account2)
self.call(mail.CmdMail(), "", "| ID: From: Subject:", caller=self.account)
@ -646,21 +676,23 @@ class TestMail(CommandTest):
# test map builder contrib
from evennia.contrib import mapbuilder
class TestMapBuilder(CommandTest):
def test_cmdmapbuilder(self):
self.call(mapbuilder.CmdMapBuilder(),
"evennia.contrib.mapbuilder.EXAMPLE1_MAP evennia.contrib.mapbuilder.EXAMPLE1_LEGEND",
"""Creating Map...|≈≈≈≈≈
"evennia.contrib.mapbuilder.EXAMPLE1_MAP evennia.contrib.mapbuilder.EXAMPLE1_LEGEND",
"""Creating Map...|≈≈≈≈≈
n
n
|Creating Landmass...|""")
self.call(mapbuilder.CmdMapBuilder(),
"evennia.contrib.mapbuilder.EXAMPLE2_MAP evennia.contrib.mapbuilder.EXAMPLE2_LEGEND",
"""Creating Map...|≈ ≈ ≈ ≈ ≈
"evennia.contrib.mapbuilder.EXAMPLE2_MAP evennia.contrib.mapbuilder.EXAMPLE2_LEGEND",
"""Creating Map...|≈ ≈ ≈ ≈ ≈
@ -674,6 +706,7 @@ class TestMapBuilder(CommandTest):
from evennia.contrib import menu_login
class TestMenuLogin(CommandTest):
def test_cmdunloggedlook(self):
self.call(menu_login.CmdUnloggedinLook(), "", "======")
@ -683,28 +716,31 @@ class TestMenuLogin(CommandTest):
from evennia.contrib import multidescer
class TestMultidescer(CommandTest):
def test_cmdmultidesc(self):
self.call(multidescer.CmdMultiDesc(),"/list", "Stored descs:\ncaller:")
self.call(multidescer.CmdMultiDesc(),"test = Desc 1", "Stored description 'test': \"Desc 1\"")
self.call(multidescer.CmdMultiDesc(),"test2 = Desc 2", "Stored description 'test2': \"Desc 2\"")
self.call(multidescer.CmdMultiDesc(),"/swap test-test2", "Swapped descs 'test' and 'test2'.")
self.call(multidescer.CmdMultiDesc(),"test3 = Desc 3init", "Stored description 'test3': \"Desc 3init\"")
self.call(multidescer.CmdMultiDesc(),"/list", "Stored descs:\ntest3: Desc 3init\ntest: Desc 1\ntest2: Desc 2\ncaller:")
self.call(multidescer.CmdMultiDesc(),"test3 = Desc 3", "Stored description 'test3': \"Desc 3\"")
self.call(multidescer.CmdMultiDesc(),"/set test1 + test2 + + test3", "test1 Desc 2 Desc 3\n\n"
"The above was set as the current description.")
self.call(multidescer.CmdMultiDesc(), "/list", "Stored descs:\ncaller:")
self.call(multidescer.CmdMultiDesc(), "test = Desc 1", "Stored description 'test': \"Desc 1\"")
self.call(multidescer.CmdMultiDesc(), "test2 = Desc 2", "Stored description 'test2': \"Desc 2\"")
self.call(multidescer.CmdMultiDesc(), "/swap test-test2", "Swapped descs 'test' and 'test2'.")
self.call(multidescer.CmdMultiDesc(), "test3 = Desc 3init", "Stored description 'test3': \"Desc 3init\"")
self.call(multidescer.CmdMultiDesc(), "/list", "Stored descs:\ntest3: Desc 3init\ntest: Desc 1\ntest2: Desc 2\ncaller:")
self.call(multidescer.CmdMultiDesc(), "test3 = Desc 3", "Stored description 'test3': \"Desc 3\"")
self.call(multidescer.CmdMultiDesc(), "/set test1 + test2 + + test3", "test1 Desc 2 Desc 3\n\n"
"The above was set as the current description.")
self.assertEqual(self.char1.db.desc, "test1 Desc 2 Desc 3")
# test simpledoor contrib
from evennia.contrib import simpledoor
class TestSimpleDoor(CommandTest):
def test_cmdopen(self):
self.call(simpledoor.CmdOpen(), "newdoor;door:contrib.simpledoor.SimpleDoor,backdoor;door = Room2",
"Created new Exit 'newdoor' from Room to Room2 (aliases: door).|Note: A doortype exit was "
"created ignored eventual custom returnexit type.|Created new Exit 'newdoor' from Room2 to Room (aliases: door).")
"Created new Exit 'newdoor' from Room to Room2 (aliases: door).|Note: A doortype exit was "
"created ignored eventual custom returnexit type.|Created new Exit 'newdoor' from Room2 to Room (aliases: door).")
self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "You close newdoor.", cmdstring="close")
self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "newdoor is already closed.", cmdstring="close")
self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "You open newdoor.", cmdstring="open")
@ -712,8 +748,10 @@ class TestSimpleDoor(CommandTest):
# test slow_exit contrib
from evennia.contrib import slow_exit
slow_exit.MOVE_DELAY = {"stroll":0, "walk": 0, "run": 0, "sprint": 0}
slow_exit.MOVE_DELAY = {"stroll": 0, "walk": 0, "run": 0, "sprint": 0}
class TestSlowExit(CommandTest):
def test_exit(self):
@ -724,12 +762,14 @@ class TestSlowExit(CommandTest):
# test talking npc contrib
from evennia.contrib import talking_npc
class TestTalkingNPC(CommandTest):
def test_talkingnpc(self):
npc = create_object(talking_npc.TalkingNPC, key="npctalker", location=self.room1)
self.call(talking_npc.CmdTalk(), "","(You walk up and talk to Char.)|")
self.call(talking_npc.CmdTalk(), "", "(You walk up and talk to Char.)|")
npc.delete()
@ -739,6 +779,7 @@ class TestTalkingNPC(CommandTest):
from evennia.contrib.tutorial_world import mob
class TestTutorialWorldMob(EvenniaTest):
def test_mob(self):
mobobj = create_object(mob.Mob, key="mob")
@ -748,28 +789,34 @@ class TestTutorialWorldMob(EvenniaTest):
mobobj.set_dead()
self.assertEqual(mobobj.db.is_dead, True)
mobobj._set_ticker(0, "foo", stop=True)
#TODO should be expanded with further tests of the modes and damage etc.
# TODO should be expanded with further tests of the modes and damage etc.
# test tutorial_world/objects
from evennia.contrib.tutorial_world import objects as tutobjects
class TestTutorialWorldObjects(CommandTest):
def test_tutorialobj(self):
obj1 = create_object(tutobjects.TutorialObject, key="tutobj")
obj1.reset()
self.assertEqual(obj1.location, obj1.home)
def test_readable(self):
readable = create_object(tutobjects.Readable, key="book", location=self.room1)
readable.db.readable_text = "Text to read"
self.call(tutobjects.CmdRead(), "book","You read book:\n Text to read", obj=readable)
self.call(tutobjects.CmdRead(), "book", "You read book:\n Text to read", obj=readable)
def test_climbable(self):
climbable = create_object(tutobjects.Climbable, key="tree", location=self.room1)
self.call(tutobjects.CmdClimb(), "tree", "You climb tree. Having looked around, you climb down again.", obj=climbable)
self.assertEqual(self.char1.tags.get("tutorial_climbed_tree", category="tutorial_world"), "tutorial_climbed_tree")
def test_obelisk(self):
obelisk = create_object(tutobjects.Obelisk, key="obelisk", location=self.room1)
self.assertEqual(obelisk.return_appearance(self.char1).startswith("|cobelisk("), True)
def test_lightsource(self):
light = create_object(tutobjects.LightSource, key="torch", location=self.room1)
self.call(tutobjects.CmdLight(), "", "You light torch.", obj=light)
@ -777,39 +824,44 @@ class TestTutorialWorldObjects(CommandTest):
if hasattr(light, "deferred"):
light.deferred.cancel()
self.assertFalse(light.pk)
def test_crumblingwall(self):
wall = create_object(tutobjects.CrumblingWall, key="wall", location=self.room1)
self.assertFalse(wall.db.button_exposed)
self.assertFalse(wall.db.exit_open)
wall.db.root_pos = {"yellow":0, "green":0,"red":0,"blue":0}
wall.db.root_pos = {"yellow": 0, "green": 0, "red": 0, "blue": 0}
self.call(tutobjects.CmdShiftRoot(), "blue root right",
"You shove the root adorned with small blue flowers to the right.", obj=wall)
"You shove the root adorned with small blue flowers to the right.", obj=wall)
self.call(tutobjects.CmdShiftRoot(), "red root left",
"You shift the reddish root to the left.", obj=wall)
"You shift the reddish root to the left.", obj=wall)
self.call(tutobjects.CmdShiftRoot(), "yellow root down",
"You shove the root adorned with small yellow flowers downwards.", obj=wall)
"You shove the root adorned with small yellow flowers downwards.", obj=wall)
self.call(tutobjects.CmdShiftRoot(), "green root up",
"You shift the weedy green root upwards.|Holding aside the root you think you notice something behind it ...", obj=wall)
"You shift the weedy green root upwards.|Holding aside the root you think you notice something behind it ...", obj=wall)
self.call(tutobjects.CmdPressButton(), "",
"You move your fingers over the suspicious depression, then gives it a decisive push. First", obj=wall)
"You move your fingers over the suspicious depression, then gives it a decisive push. First", obj=wall)
self.assertTrue(wall.db.button_exposed)
self.assertTrue(wall.db.exit_open)
wall.reset()
if hasattr(wall, "deferred"):
wall.deferred.cancel()
wall.delete()
def test_weapon(self):
weapon = create_object(tutobjects.Weapon, key="sword", location=self.char1)
self.call(tutobjects.CmdAttack(), "Char", "You stab with sword.", obj=weapon, cmdstring="stab")
self.call(tutobjects.CmdAttack(), "Char", "You slash with sword.", obj=weapon, cmdstring="slash")
def test_weaponrack(self):
rack = create_object(tutobjects.WeaponRack, key="rack", location=self.room1)
rack.db.available_weapons = ["sword"]
self.call(tutobjects.CmdGetWeapon(), "", "You find Rusty sword.", obj=rack)
# test tutorial_world/
from evennia.contrib.tutorial_world import rooms as tutrooms
class TestTutorialWorldRooms(CommandTest):
def test_cmdtutorial(self):
room = create_object(tutrooms.TutorialRoom, key="tutroom")
@ -820,14 +872,17 @@ class TestTutorialWorldRooms(CommandTest):
self.call(tutrooms.CmdTutorialLook(), "detail", "A detail", obj=room)
self.call(tutrooms.CmdTutorialLook(), "foo", "A detail", obj=room)
room.delete()
def test_weatherroom(self):
room = create_object(tutrooms.WeatherRoom, key="weatherroom")
room.update_weather()
tutrooms.TICKER_HANDLER.remove(interval=room.db.interval, callback=room.update_weather, idstring="tutorial")
room.delete()
def test_introroom(self):
room = create_object(tutrooms.IntroRoom, key="introroom")
room.at_object_receive(self.char1, self.room1)
def test_bridgeroom(self):
room = create_object(tutrooms.BridgeRoom, key="bridgeroom")
room.update_weather()
@ -837,19 +892,24 @@ class TestTutorialWorldRooms(CommandTest):
room.at_object_leave(self.char1, self.room1)
tutrooms.TICKER_HANDLER.remove(interval=room.db.interval, callback=room.update_weather, idstring="tutorial")
room.delete()
def test_darkroom(self):
room = create_object(tutrooms.DarkRoom, key="darkroom")
self.char1.move_to(room)
self.call(tutrooms.CmdDarkHelp(), "", "Can't help you until")
def test_teleportroom(self):
create_object(tutrooms.TeleportRoom, key="teleportroom")
def test_outroroom(self):
create_object(tutrooms.OutroRoom, key="outroroom")
# test turnbattle
from evennia.contrib import turnbattle
from evennia.objects.objects import DefaultRoom
class TestTurnBattleCmd(CommandTest):
# Test combat commands
@ -860,6 +920,7 @@ class TestTurnBattleCmd(CommandTest):
self.call(turnbattle.CmdDisengage(), "", "You can only do that in combat. (see: help fight)")
self.call(turnbattle.CmdRest(), "", "Char rests to recover HP.")
class TestTurnBattleFunc(EvenniaTest):
# Test combat functions
@ -944,6 +1005,7 @@ class TestTurnBattleFunc(EvenniaTest):
from evennia.contrib.unixcommand import UnixCommand
class CmdDummy(UnixCommand):
"""A dummy UnixCommand."""
@ -991,6 +1053,7 @@ class TestUnixCommand(CommandTest):
import re
from evennia.contrib import color_markups
class TestColorMarkup(EvenniaTest):
"""
Note: Normally this would be tested by importing the ansi parser and run
@ -999,6 +1062,7 @@ class TestColorMarkup(EvenniaTest):
many other modules it appears that trying to overload
settings to test it causes issues with unrelated tests.
"""
def test_curly_markup(self):
ansi_map = color_markups.CURLY_COLOR_ANSI_EXTRA_MAP
self.assertIsNotNone(re.match(re.escape(ansi_map[7][0]), '{r'))
@ -1047,10 +1111,12 @@ class TestColorMarkup(EvenniaTest):
self.assertEqual(bright_map[0][1], '%c[500')
self.assertEqual(bright_map[-1][1], '%c[222')
from evennia.contrib import random_string_generator
SIMPLE_GENERATOR = random_string_generator.RandomStringGenerator("simple", "[01]{2}")
class TestRandomStringGenerator(EvenniaTest):
def test_generate(self):

View file

@ -12,6 +12,7 @@ make sure to put it on yourself or you won't see any messages!
import random
from evennia import DefaultScript
class BodyFunctions(DefaultScript):
"""
This class defines the script itself
@ -21,7 +22,7 @@ class BodyFunctions(DefaultScript):
self.key = "bodyfunction"
self.desc = "Adds various timed events to a character."
self.interval = 20 # seconds
#self.repeats = 5 # repeat only a certain number of times
# self.repeats = 5 # repeat only a certain number of times
self.start_delay = True # wait self.interval until first call
#self.persistent = True

View file

@ -119,7 +119,7 @@ class CmdSmashGlass(Command):
string += " you should just try to open the lid instead?"
self.caller.msg(string)
self.caller.location.msg_contents("%s tries to smash the glass of the button." %
(self.caller.name), exclude=self.caller)
(self.caller.name), exclude=self.caller)
class CmdOpenLid(Command):
@ -146,7 +146,7 @@ class CmdOpenLid(Command):
string += "the lid will soon close again."
self.caller.msg(string)
self.caller.location.msg_contents("%s opens the lid of the button." %
(self.caller.name), exclude=self.caller)
(self.caller.name), exclude=self.caller)
# add the relevant cmdsets to button
self.obj.cmdset.add(LidClosedCmdSet)
# call object method
@ -213,7 +213,7 @@ class CmdBlindLook(Command):
string += "Until it wears off, all you can do is feel around blindly."
self.caller.msg(string)
self.caller.location.msg_contents("%s stumbles around, blinded." %
(self.caller.name), exclude=self.caller)
(self.caller.name), exclude=self.caller)
class CmdBlindHelp(Command):

View file

@ -39,7 +39,7 @@
#
#HEADER
# HEADER
# everything in this block will be appended to the beginning of
# all other #CODE blocks when they are executed.
@ -51,7 +51,7 @@ from evennia import DefaultObject
limbo = search_object('Limbo')[0]
#CODE
# CODE
# This is the first code block. Within each block, Python
# code works as normal. Note how we make use if imports and
@ -61,12 +61,12 @@ limbo = search_object('Limbo')[0]
# create a red button in limbo
red_button = create_object(red_button.RedButton, key="Red button",
location=limbo, aliases=["button"])
location=limbo, aliases=["button"])
# we take a look at what we created
caller.msg("A %s was created." % red_button.key)
#CODE
# CODE
# this code block has 'table' and 'chair' set as deletable
# objects. This means that when the batchcode processor runs in

View file

@ -33,6 +33,7 @@ class RedButton(DefaultObject):
desc_lamp_broken - description when lamp is broken
"""
def at_object_creation(self):
"""
This function is called when object is created. Use this

View file

@ -26,12 +26,14 @@ from evennia.contrib.tutorial_examples import cmdset_red_button as cmdsetexample
# a bright light. The last one also has a timer component that allows it
# to remove itself after a while (and the player recovers their eyesight).
class ClosedLidState(DefaultScript):
"""
This manages the cmdset for the "closed" button state. What this
means is that while this script is valid, we add the RedButtonClosed
cmdset to it (with commands like open, nudge lid etc)
"""
def at_script_creation(self):
"Called when script first created."
self.desc = "Script that manages the closed-state cmdsets for red button."
@ -44,7 +46,7 @@ class ClosedLidState(DefaultScript):
checked so we don't need to worry about adding the script to an
open lid.
"""
#All we do is add the cmdset for the closed state.
# All we do is add the cmdset for the closed state.
self.obj.cmdset.add(cmdsetexamples.LidClosedCmdSet)
def is_valid(self):
@ -67,6 +69,7 @@ class OpenLidState(DefaultScript):
This manages the cmdset for the "open" button state. This will add
the RedButtonOpen
"""
def at_script_creation(self):
"Called when script first created."
self.desc = "Script that manages the opened-state cmdsets for red button."
@ -105,6 +108,7 @@ class BlindedState(DefaultScript):
restored. It's up to the function starting the script to actually
set it on the right account object.
"""
def at_script_creation(self):
"""
We set up the script here.
@ -139,7 +143,7 @@ class BlindedState(DefaultScript):
% self.obj.name,
exclude=self.obj)
self.obj.cmdset.delete() # this will clear the latest added cmdset,
# (which is the blinded one).
# (which is the blinded one).
#
@ -158,6 +162,7 @@ class CloseLidEvent(DefaultScript):
script that should be started/created when the
lid is opened.
"""
def at_script_creation(self):
"""
Called when script object is first created. Sets things up.
@ -172,7 +177,7 @@ class CloseLidEvent(DefaultScript):
self.start_delay = True # we want to pospone the launch.
self.repeats = 1 # we only close the lid once
self.persistent = True # even if the server crashes in those 20 seconds,
# the lid will still close once the game restarts.
# the lid will still close once the game restarts.
def is_valid(self):
"""
@ -194,10 +199,12 @@ class CloseLidEvent(DefaultScript):
"""
self.obj.close_lid()
class BlinkButtonEvent(DefaultScript):
"""
This timed script lets the button flash at regular intervals.
"""
def at_script_creation(self):
"""
Sets things up. We want the button's lamp to blink at
@ -206,9 +213,9 @@ class BlinkButtonEvent(DefaultScript):
"""
self.key = "blink_button"
self.desc = "Blinks red buttons"
self.interval = 35 #seconds
self.start_delay = False #blink right away
self.persistent = True #keep blinking also after server reboot
self.interval = 35 # seconds
self.start_delay = False # blink right away
self.persistent = True # keep blinking also after server reboot
def is_valid(self):
"""
@ -223,6 +230,7 @@ class BlinkButtonEvent(DefaultScript):
"""
self.obj.blink()
class DeactivateButtonEvent(DefaultScript):
"""
This deactivates the button for a short while (it won't blink, won't
@ -231,13 +239,14 @@ class DeactivateButtonEvent(DefaultScript):
in the AddBlindedCmdSet script since that script is defined on the *account*
whereas this one must be defined on the *button*.
"""
def at_script_creation(self):
"""
Sets things up.
"""
self.key = "deactivate_button"
self.desc = "Deactivate red button temporarily"
self.interval = 21 #seconds
self.interval = 21 # seconds
self.start_delay = True # wait with the first repeat for self.interval seconds.
self.persistent = True
self.repeats = 1 # only do this once

View file

@ -5,4 +5,3 @@ This package holds the demo game of Evennia.
from __future__ import absolute_import
from . import mob, objects, rooms

View file

@ -13,6 +13,7 @@ from evennia import Command, CmdSet
from evennia import logger
from evennia.contrib.tutorial_world import objects as tut_objects
class CmdMobOnOff(Command):
"""
Activates/deactivates Mob
@ -51,9 +52,11 @@ class MobCmdSet(CmdSet):
"""
Holds the admin command controlling the mob
"""
def at_cmdset_creation(self):
self.add(CmdMobOnOff())
class Mob(tut_objects.TutorialObject):
"""
This is a state-machine AI mobile. It has several states which are
@ -91,6 +94,7 @@ class Mob(tut_objects.TutorialObject):
happen to roam into a room with no exits.
"""
def at_init(self):
"""
When initialized from cache (after a server reboot), set up
@ -122,7 +126,7 @@ class Mob(tut_objects.TutorialObject):
self.db.patrolling_pace = 6
self.db.aggressive_pace = 2
self.db.hunting_pace = 1
self.db.death_pace = 100 # stay dead for 100 seconds
self.db.death_pace = 100 # stay dead for 100 seconds
# we store the call to the tickerhandler
# so we can easily deactivate the last
@ -179,19 +183,19 @@ class Mob(tut_objects.TutorialObject):
we need to remember this across reloads.
"""
idstring = "tutorial_mob" # this doesn't change
idstring = "tutorial_mob" # this doesn't change
last_interval = self.db.last_ticker_interval
last_hook_key = self.db.last_hook_key
if last_interval and last_hook_key:
# we have a previous subscription, kill this first.
TICKER_HANDLER.remove(interval=last_interval,
callback=getattr(self, last_hook_key), idstring=idstring)
callback=getattr(self, last_hook_key), idstring=idstring)
self.db.last_ticker_interval = interval
self.db.last_hook_key = hook_key
if not stop:
# set the new ticker
TICKER_HANDLER.add(interval=interval,
callback=getattr(self, hook_key), idstring=idstring)
callback=getattr(self, hook_key), idstring=idstring)
def _find_target(self, location):
"""
@ -206,7 +210,7 @@ class Mob(tut_objects.TutorialObject):
"""
targets = [obj for obj in location.contents_get(exclude=self)
if obj.has_account and not obj.is_superuser]
if obj.has_account and not obj.is_superuser]
return targets[0] if targets else None
def set_alive(self, *args, **kwargs):
@ -379,7 +383,6 @@ class Mob(tut_objects.TutorialObject):
else:
logger.log_err("Mob: mob.db.send_defeated_to not found: %s" % self.db.send_defeated_to)
# response methods - called by other objects
def at_hit(self, weapon, attacker, damage):

View file

@ -106,6 +106,7 @@ class CmdSetReadable(CmdSet):
"""
A CmdSet for readables.
"""
def at_cmdset_creation(self):
"""
Called when the cmdset is created.
@ -117,6 +118,7 @@ class Readable(TutorialObject):
"""
This simple object defines some attributes and
"""
def at_object_creation(self):
"""
Called when object is created. We make sure to set the needed
@ -176,6 +178,7 @@ class CmdClimb(Command):
class CmdSetClimbable(CmdSet):
"""Climbing cmdset"""
def at_cmdset_creation(self):
"""populate set"""
self.add(CmdClimb())
@ -303,6 +306,7 @@ class LightSource(TutorialObject):
When burned out, the object will be deleted.
"""
def at_init(self):
"""
If this is called with the Attribute is_giving_light already
@ -589,6 +593,7 @@ class CrumblingWall(TutorialObject, DefaultExit):
whenever the button is pushed (this hides it as an exit
until it actually is)
"""
def at_init(self):
"""
Called when object is recalled from cache.
@ -838,6 +843,7 @@ class CmdAttack(Command):
class CmdSetWeapon(CmdSet):
"""Holds the attack command."""
def at_cmdset_creation(self):
"""called at first object creation."""
self.add(CmdAttack())
@ -854,6 +860,7 @@ class Weapon(TutorialObject):
type of attack) (0-10)
"""
def at_object_creation(self):
"""Called at first creation of the object"""
super(Weapon, self).at_object_creation()
@ -987,7 +994,7 @@ WEAPON_PROTOTYPES = {
"hit": 0.85,
"parry": 0.7,
"damage": 11}
}
}
class CmdGetWeapon(Command):
@ -1037,6 +1044,7 @@ class WeaponRack(TutorialObject):
grab another one.
"""
def at_object_creation(self):
"""
called at creation

View file

@ -215,6 +215,7 @@ class TutorialRoom(DefaultRoom):
This is the base room type for all rooms in the tutorial world.
It defines a cmdset on itself for reading tutorial info about the location.
"""
def at_object_creation(self):
"""Called when room is first created"""
self.db.tutorial_info = "This is a tutorial room. It allows you to use the 'tutorial' command."
@ -278,17 +279,17 @@ class TutorialRoom(DefaultRoom):
# These are rainy weather strings
WEATHER_STRINGS = (
"The rain coming down from the iron-grey sky intensifies.",
"A gust of wind throws the rain right in your face. Despite your cloak you shiver.",
"The rainfall eases a bit and the sky momentarily brightens.",
"For a moment it looks like the rain is slowing, then it begins anew with renewed force.",
"The rain pummels you with large, heavy drops. You hear the rumble of thunder in the distance.",
"The wind is picking up, howling around you, throwing water droplets in your face. It's cold.",
"Bright fingers of lightning flash over the sky, moments later followed by a deafening rumble.",
"It rains so hard you can hardly see your hand in front of you. You'll soon be drenched to the bone.",
"Lightning strikes in several thundering bolts, striking the trees in the forest to your west.",
"You hear the distant howl of what sounds like some sort of dog or wolf.",
"Large clouds rush across the sky, throwing their load of rain over the world.")
"The rain coming down from the iron-grey sky intensifies.",
"A gust of wind throws the rain right in your face. Despite your cloak you shiver.",
"The rainfall eases a bit and the sky momentarily brightens.",
"For a moment it looks like the rain is slowing, then it begins anew with renewed force.",
"The rain pummels you with large, heavy drops. You hear the rumble of thunder in the distance.",
"The wind is picking up, howling around you, throwing water droplets in your face. It's cold.",
"Bright fingers of lightning flash over the sky, moments later followed by a deafening rumble.",
"It rains so hard you can hardly see your hand in front of you. You'll soon be drenched to the bone.",
"Lightning strikes in several thundering bolts, striking the trees in the forest to your west.",
"You hear the distant howl of what sounds like some sort of dog or wolf.",
"Large clouds rush across the sky, throwing their load of rain over the world.")
class WeatherRoom(TutorialRoom):
@ -300,6 +301,7 @@ class WeatherRoom(TutorialRoom):
inherit from this.
"""
def at_object_creation(self):
"""
Called when object is first created.
@ -355,6 +357,7 @@ class IntroRoom(TutorialRoom):
properties to customize:
char_health - integer > 0 (default 20)
"""
def at_object_creation(self):
"""
Called when the room is first created.
@ -377,7 +380,7 @@ class IntroRoom(TutorialRoom):
character.db.health_max = health
if character.is_superuser:
string = "-"*78 + SUPERUSER_WARNING + "-"*78
string = "-" * 78 + SUPERUSER_WARNING + "-" * 78
character.msg("|r%s|n" % string.format(name=character.key, quell="|w@quell|r"))
@ -589,16 +592,16 @@ class BridgeCmdSet(CmdSet):
BRIDGE_WEATHER = (
"The rain intensifies, making the planks of the bridge even more slippery.",
"A gust of wind throws the rain right in your face.",
"The rainfall eases a bit and the sky momentarily brightens.",
"The bridge shakes under the thunder of a closeby thunder strike.",
"The rain pummels you with large, heavy drops. You hear the distinct howl of a large hound in the distance.",
"The wind is picking up, howling around you and causing the bridge to sway from side to side.",
"Some sort of large bird sweeps by overhead, giving off an eery screech. Soon it has disappeared in the gloom.",
"The bridge sways from side to side in the wind.",
"Below you a particularly large wave crashes into the rocks.",
"From the ruin you hear a distant, otherwordly howl. Or maybe it was just the wind.")
"The rain intensifies, making the planks of the bridge even more slippery.",
"A gust of wind throws the rain right in your face.",
"The rainfall eases a bit and the sky momentarily brightens.",
"The bridge shakes under the thunder of a closeby thunder strike.",
"The rain pummels you with large, heavy drops. You hear the distinct howl of a large hound in the distance.",
"The wind is picking up, howling around you and causing the bridge to sway from side to side.",
"Some sort of large bird sweeps by overhead, giving off an eery screech. Soon it has disappeared in the gloom.",
"The bridge sways from side to side in the wind.",
"Below you a particularly large wave crashes into the rocks.",
"From the ruin you hear a distant, otherwordly howl. Or maybe it was just the wind.")
class BridgeRoom(WeatherRoom):
@ -625,6 +628,7 @@ class BridgeRoom(WeatherRoom):
the CmdLookBridge command).
"""
def at_object_creation(self):
"""Setups the room"""
# this will start the weather room's ticker and tell
@ -827,6 +831,7 @@ class DarkRoom(TutorialRoom):
may have been beaten up by the ghostly apparition at this point.
"""
def at_object_creation(self):
"""
Called when object is first created.
@ -942,6 +947,7 @@ class TeleportRoom(TutorialRoom):
failure_teleport_msg - message to echo while teleporting to failure
"""
def at_object_creation(self):
"""Called at first creation"""
super(TeleportRoom, self).at_object_creation()

View file

@ -111,8 +111,8 @@ class UnixCommandParser(argparse.ArgumentParser):
"""
prog = prog or command.key
super(UnixCommandParser, self).__init__(
prog=prog, description=description,
conflict_handler='resolve', add_help=False, **kwargs)
prog=prog, description=description,
conflict_handler='resolve', add_help=False, **kwargs)
self.command = command
self.post_help = epilog