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

@ -47,6 +47,7 @@ manually later.
# Helper functions # Helper functions
def _green(string): def _green(string):
if USE_COLOR: if USE_COLOR:
return "%s%s%s" % (ANSI_GREEN, string, ANSI_NORMAL) return "%s%s%s" % (ANSI_GREEN, string, ANSI_NORMAL)
@ -98,12 +99,12 @@ def _case_sensitive_replace(string, old, new):
all_upper = False all_upper = False
# special cases - keep remaing case) # special cases - keep remaing case)
if new_word.lower() in CASE_WORD_EXCEPTIONS: if new_word.lower() in CASE_WORD_EXCEPTIONS:
result.append(new_word[ind+1:]) result.append(new_word[ind + 1:])
# append any remaining characters from new # append any remaining characters from new
elif all_upper: elif all_upper:
result.append(new_word[ind+1:].upper()) result.append(new_word[ind + 1:].upper())
else: else:
result.append(new_word[ind+1:].lower()) result.append(new_word[ind + 1:].lower())
out.append("".join(result)) out.append("".join(result))
# if we have more new words than old ones, just add them verbatim # if we have more new words than old ones, just add them verbatim
out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)]) out.extend([new_word for ind, new_word in enumerate(new_words) if ind >= len(old_words)])
@ -278,7 +279,7 @@ def rename_in_file(path, in_list, out_list, is_interactive):
raw_input(_HELP_TEXT.format(sources=in_list, targets=out_list)) raw_input(_HELP_TEXT.format(sources=in_list, targets=out_list))
elif ret.startswith("i"): elif ret.startswith("i"):
# ignore one or more lines # ignore one or more lines
ignores = [int(ind)-1 for ind in ret[1:].split(',') if ind.strip().isdigit()] ignores = [int(ind) - 1 for ind in ret[1:].split(',') if ind.strip().isdigit()]
if not ignores: if not ignores:
raw_input("Ignore example: i 2,7,34,133\n (return to continue)") raw_input("Ignore example: i 2,7,34,133\n (return to continue)")
continue continue
@ -287,12 +288,11 @@ def rename_in_file(path, in_list, out_list, is_interactive):
continue continue
if __name__ == "__main__": if __name__ == "__main__":
import argparse import argparse
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Rename text in a source tree, or a single file") description="Rename text in a source tree, or a single file")
parser.add_argument('-i', '--input', action='append', parser.add_argument('-i', '--input', action='append',
help="Source word to rename (quote around multiple words)") help="Source word to rename (quote around multiple words)")

View file

@ -5,12 +5,13 @@ the python bin directory and makes the 'evennia' program available on
the command %path%. the command %path%.
""" """
import os, sys import os
import sys
# for pip install -e # for pip install -e
sys.path.insert(0, os.path.abspath(os.getcwd())) sys.path.insert(0, os.path.abspath(os.getcwd()))
# main library path # main library path
sys.path.insert(0, os.path.join(sys.prefix, "Lib", "site-packages")) sys.path.insert(0, os.path.join(sys.prefix, "Lib", "site-packages"))
from evennia.server.evennia_launcher import main from evennia.server.evennia_launcher import main
main() main()

View file

@ -109,9 +109,11 @@ def _create_version():
pass pass
return version return version
__version__ = _create_version() __version__ = _create_version()
del _create_version del _create_version
def _init(): def _init():
""" """
This function is called automatically by the launcher only after This function is called automatically by the launcher only after
@ -124,7 +126,7 @@ def _init():
global Command, CmdSet, default_cmds, syscmdkeys, InterruptCommand global Command, CmdSet, default_cmds, syscmdkeys, InterruptCommand
global search_object, search_script, search_account, search_channel, search_help, search_tag global search_object, search_script, search_account, search_channel, search_help, search_tag
global create_object, create_script, create_account, create_channel, create_message, create_help_entry global create_object, create_script, create_account, create_channel, create_message, create_help_entry
global settings,lockfuncs, logger, utils, gametime, ansi, spawn, managers global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers
global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, CHANNEL_HANDLER, TASK_HANDLER global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, CHANNEL_HANDLER, TASK_HANDLER
from .accounts.accounts import DefaultAccount from .accounts.accounts import DefaultAccount
@ -191,6 +193,7 @@ def _init():
Parent for other containers Parent for other containers
""" """
def _help(self): def _help(self):
"Returns list of contents" "Returns list of contents"
names = [name for name in self.__class__.__dict__ if not name.startswith('_')] names = [name for name in self.__class__.__dict__ if not name.startswith('_')]
@ -198,7 +201,6 @@ def _init():
print(self.__doc__ + "-" * 60 + "\n" + ", ".join(names)) print(self.__doc__ + "-" * 60 + "\n" + ", ".join(names))
help = property(_help) help = property(_help)
class DBmanagers(_EvContainer): class DBmanagers(_EvContainer):
""" """
Links to instantiated database managers. Links to instantiated database managers.
@ -241,7 +243,6 @@ def _init():
managers = DBmanagers() managers = DBmanagers()
del DBmanagers del DBmanagers
class DefaultCmds(_EvContainer): class DefaultCmds(_EvContainer):
""" """
This container holds direct shortcuts to all default commands in Evennia. This container holds direct shortcuts to all default commands in Evennia.
@ -266,8 +267,8 @@ def _init():
self.__dict__.update(dict([(c.__name__, c) for c in cmdlist])) self.__dict__.update(dict([(c.__name__, c) for c in cmdlist]))
from .commands.default import (admin, batchprocess, from .commands.default import (admin, batchprocess,
building, comms, general, building, comms, general,
account, help, system, unloggedin) account, help, system, unloggedin)
add_cmds(admin) add_cmds(admin)
add_cmds(building) add_cmds(building)
add_cmds(batchprocess) add_cmds(batchprocess)
@ -282,7 +283,6 @@ def _init():
default_cmds = DefaultCmds() default_cmds = DefaultCmds()
del DefaultCmds del DefaultCmds
class SystemCmds(_EvContainer): class SystemCmds(_EvContainer):
""" """
Creating commands with keys set to these constants will make Creating commands with keys set to these constants will make
@ -313,6 +313,7 @@ def _init():
del SystemCmds del SystemCmds
del _EvContainer del _EvContainer
del object del object
del absolute_import del absolute_import
del print_function del print_function

View file

@ -528,7 +528,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
""" """
result = super(DefaultAccount, self).access(accessing_obj, access_type=access_type, result = super(DefaultAccount, self).access(accessing_obj, access_type=access_type,
default=default, no_superuser_bypass=no_superuser_bypass) default=default, no_superuser_bypass=no_superuser_bypass)
self.at_access(result, accessing_obj, access_type, **kwargs) self.at_access(result, accessing_obj, access_type, **kwargs)
return result return result
@ -879,10 +879,10 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
result.append(nsess == 1 and "\n\n|wConnected session:|n" or "\n\n|wConnected sessions (%i):|n" % nsess) result.append(nsess == 1 and "\n\n|wConnected session:|n" or "\n\n|wConnected sessions (%i):|n" % nsess)
for isess, sess in enumerate(sessions): for isess, sess in enumerate(sessions):
csessid = sess.sessid csessid = sess.sessid
addr = "%s (%s)" % (sess.protocol_key, isinstance(sess.address, tuple) addr = "%s (%s)" % (sess.protocol_key, isinstance(sess.address, tuple) and
and str(sess.address[0]) or str(sess.address)) str(sess.address[0]) or str(sess.address))
result.append("\n %s %s" % (session.sessid == csessid and "|w* %s|n" % (isess + 1) result.append("\n %s %s" % (session.sessid == csessid and "|w* %s|n" % (isess + 1) or
or " %s" % (isess + 1), addr)) " %s" % (isess + 1), addr))
result.append("\n\n |whelp|n - more commands") result.append("\n\n |whelp|n - more commands")
result.append("\n |wooc <Text>|n - talk on public channel") result.append("\n |wooc <Text>|n - talk on public channel")
@ -928,6 +928,7 @@ class DefaultGuest(DefaultAccount):
This class is used for guest logins. Unlike Accounts, Guests and This class is used for guest logins. Unlike Accounts, Guests and
their characters are deleted after disconnection. their characters are deleted after disconnection.
""" """
def at_post_login(self, session=None, **kwargs): def at_post_login(self, session=None, **kwargs):
""" """
In theory, guests only have one character regardless of which In theory, guests only have one character regardless of which

View file

@ -155,7 +155,7 @@ class AccountInline(admin.StackedInline):
fieldsets = ( fieldsets = (
("In-game Permissions and Locks", ("In-game Permissions and Locks",
{'fields': ('db_lock_storage',), {'fields': ('db_lock_storage',),
#{'fields': ('db_permissions', 'db_lock_storage'), #{'fields': ('db_permissions', 'db_lock_storage'),
'description': "<i>These are permissions/locks for in-game use. " 'description': "<i>These are permissions/locks for in-game use. "
"They are unrelated to website access rights.</i>"}), "They are unrelated to website access rights.</i>"}),
("In-game Account data", ("In-game Account data",
@ -215,11 +215,11 @@ class AccountDBAdmin(BaseUserAdmin):
'db_lock_storage'), 'db_lock_storage'),
'description': '<i>These are attributes that are more relevant ' 'description': '<i>These are attributes that are more relevant '
'to gameplay.</i>'})) 'to gameplay.</i>'}))
# ('Game Options', {'fields': ( # ('Game Options', {'fields': (
# 'db_typeclass_path', 'db_cmdset_storage', # 'db_typeclass_path', 'db_cmdset_storage',
# 'db_permissions', 'db_lock_storage'), # 'db_permissions', 'db_lock_storage'),
# 'description': '<i>These are attributes that are ' # 'description': '<i>These are attributes that are '
# 'more relevant to gameplay.</i>'})) # 'more relevant to gameplay.</i>'}))
add_fieldsets = ( add_fieldsets = (
(None, (None,
@ -240,7 +240,7 @@ class AccountDBAdmin(BaseUserAdmin):
""" """
obj.save() obj.save()
if not change: if not change:
#calling hooks for new account # calling hooks for new account
obj.set_class_from_typeclass(typeclass_path=settings.BASE_ACCOUNT_TYPECLASS) obj.set_class_from_typeclass(typeclass_path=settings.BASE_ACCOUNT_TYPECLASS)
obj.basetype_setup() obj.basetype_setup()
obj.at_account_creation() obj.at_account_creation()
@ -252,4 +252,5 @@ class AccountDBAdmin(BaseUserAdmin):
return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id])) return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id]))
return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id])) return HttpResponseRedirect(reverse("admin:accounts_accountdb_change", args=[obj.id]))
admin.site.register(AccountDB, AccountDBAdmin) admin.site.register(AccountDB, AccountDBAdmin)

View file

@ -28,6 +28,7 @@ class BotStarter(DefaultScript):
into gear when it is initialized. into gear when it is initialized.
""" """
def at_script_creation(self): def at_script_creation(self):
""" """
Called once, when script is created. Called once, when script is created.
@ -148,6 +149,7 @@ class IRCBot(Bot):
Bot for handling IRC connections. Bot for handling IRC connections.
""" """
def start(self, ev_channel=None, irc_botname=None, irc_channel=None, irc_network=None, irc_port=None, irc_ssl=None): def start(self, ev_channel=None, irc_botname=None, irc_channel=None, irc_network=None, irc_port=None, irc_ssl=None):
""" """
Start by telling the portal to start a new session. Start by telling the portal to start a new session.
@ -359,6 +361,7 @@ class RSSBot(Bot):
its feed at regular intervals. its feed at regular intervals.
""" """
def start(self, ev_channel=None, rss_url=None, rss_rate=None): def start(self, ev_channel=None, rss_url=None, rss_rate=None):
""" """
Start by telling the portal to start a new RSS session Start by telling the portal to start a new RSS session

View file

@ -38,6 +38,7 @@ class AccountDBManager(TypedObjectManager, UserManager):
#swap_character #swap_character
""" """
def num_total_accounts(self): def num_total_accounts(self):
""" """
Get total number of accounts. Get total number of accounts.
@ -91,7 +92,7 @@ class AccountDBManager(TypedObjectManager, UserManager):
tdelta = datetime.timedelta(days) tdelta = datetime.timedelta(days)
start_date = end_date - tdelta start_date = end_date - tdelta
return self.filter(last_login__range=( return self.filter(last_login__range=(
start_date, end_date)).order_by('-last_login') start_date, end_date)).order_by('-last_login')
def get_account_from_email(self, uemail): def get_account_from_email(self, uemail):
""" """

View file

@ -3,12 +3,14 @@ from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
def convert_defaults(apps, schema_editor): def convert_defaults(apps, schema_editor):
AccountDB = apps.get_model("accounts", "AccountDB") AccountDB = apps.get_model("accounts", "AccountDB")
for account in AccountDB.objects.filter(db_typeclass_path="src.accounts.account.Account"): for account in AccountDB.objects.filter(db_typeclass_path="src.accounts.account.Account"):
account.db_typeclass_path = "typeclasses.accounts.Account" account.db_typeclass_path = "typeclasses.accounts.Account"
account.save() account.save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -16,5 +18,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(convert_defaults), migrations.RunPython(convert_defaults),
] ]

View file

@ -89,7 +89,7 @@ class AccountDB(TypedObject, AbstractUser):
help_text="If player is connected to game or not") help_text="If player is connected to game or not")
# database storage of persistant cmdsets. # database storage of persistant cmdsets.
db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True, db_cmdset_storage = models.CharField('cmdset', max_length=255, null=True,
help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.") help_text="optional python path to a cmdset class. If creating a Character, this will default to settings.CMDSET_CHARACTER.")
# marks if this is a "virtual" bot account object # marks if this is a "virtual" bot account object
db_is_bot = models.BooleanField(default=False, verbose_name="is_bot", help_text="Used to identify irc/rss bots") db_is_bot = models.BooleanField(default=False, verbose_name="is_bot", help_text="Used to identify irc/rss bots")

View file

@ -88,41 +88,41 @@ _SEARCH_AT_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit
# is the normal "production message to echo to the account. # is the normal "production message to echo to the account.
_ERROR_UNTRAPPED = ( _ERROR_UNTRAPPED = (
""" """
An untrapped error occurred. An untrapped error occurred.
""", """,
""" """
An untrapped error occurred. Please file a bug report detailing the steps to reproduce. An untrapped error occurred. Please file a bug report detailing the steps to reproduce.
""") """)
_ERROR_CMDSETS = ( _ERROR_CMDSETS = (
""" """
A cmdset merger-error occurred. This is often due to a syntax A cmdset merger-error occurred. This is often due to a syntax
error in one of the cmdsets to merge. error in one of the cmdsets to merge.
""", """,
""" """
A cmdset merger-error occurred. Please file a bug report detailing the A cmdset merger-error occurred. Please file a bug report detailing the
steps to reproduce. steps to reproduce.
""") """)
_ERROR_NOCMDSETS = ( _ERROR_NOCMDSETS = (
""" """
No command sets found! This is a critical bug that can have No command sets found! This is a critical bug that can have
multiple causes. multiple causes.
""", """,
""" """
No command sets found! This is a sign of a critical bug. If No command sets found! This is a sign of a critical bug. If
disconnecting/reconnecting doesn't" solve the problem, try to contact disconnecting/reconnecting doesn't" solve the problem, try to contact
the server admin through" some other means for assistance. the server admin through" some other means for assistance.
""") """)
_ERROR_CMDHANDLER = ( _ERROR_CMDHANDLER = (
""" """
A command handler bug occurred. If this is not due to a local change, A command handler bug occurred. If this is not due to a local change,
please file a bug report with the Evennia project, including the please file a bug report with the Evennia project, including the
traceback and steps to reproduce. traceback and steps to reproduce.
""", """,
""" """
A command handler bug occurred. Please notify staff - they should A command handler bug occurred. Please notify staff - they should
likely file a bug report with the Evennia project. likely file a bug report with the Evennia project.
""") """)
@ -234,19 +234,23 @@ class NoCmdSets(Exception):
class ExecSystemCommand(Exception): class ExecSystemCommand(Exception):
"Run a system command" "Run a system command"
def __init__(self, syscmd, sysarg): def __init__(self, syscmd, sysarg):
self.args = (syscmd, sysarg) # needed by exception error handling self.args = (syscmd, sysarg) # needed by exception error handling
self.syscmd = syscmd self.syscmd = syscmd
self.sysarg = sysarg self.sysarg = sysarg
class ErrorReported(Exception): class ErrorReported(Exception):
"Re-raised when a subsructure already reported the error" "Re-raised when a subsructure already reported the error"
def __init__(self, raw_string): def __init__(self, raw_string):
self.args = (raw_string,) self.args = (raw_string,)
self.raw_string = raw_string self.raw_string = raw_string
# Helper function # Helper function
@inlineCallbacks @inlineCallbacks
def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string): def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string):
""" """
@ -318,11 +322,11 @@ def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string)
# the no_superuser_bypass must be True) # the no_superuser_bypass must be True)
local_obj_cmdsets = \ local_obj_cmdsets = \
yield list(chain.from_iterable( yield list(chain.from_iterable(
lobj.cmdset.cmdset_stack for lobj in local_objlist lobj.cmdset.cmdset_stack for lobj in local_objlist
if (lobj.cmdset.current and if (lobj.cmdset.current and
lobj.access(caller, access_type='call', no_superuser_bypass=True)))) lobj.access(caller, access_type='call', no_superuser_bypass=True))))
for cset in local_obj_cmdsets: for cset in local_obj_cmdsets:
#This is necessary for object sets, or we won't be able to # This is necessary for object sets, or we won't be able to
# separate the command sets from each other in a busy room. We # separate the command sets from each other in a busy room. We
# only keep the setting if duplicates were set to False/True # only keep the setting if duplicates were set to False/True
# explicitly. # explicitly.
@ -333,7 +337,6 @@ def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string)
_msg_err(caller, _ERROR_CMDSETS) _msg_err(caller, _ERROR_CMDSETS)
raise ErrorReported(raw_string) raise ErrorReported(raw_string)
@inlineCallbacks @inlineCallbacks
def _get_cmdsets(obj): def _get_cmdsets(obj):
""" """
@ -346,7 +349,7 @@ def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string)
_msg_err(caller, _ERROR_CMDSETS) _msg_err(caller, _ERROR_CMDSETS)
raise ErrorReported(raw_string) raise ErrorReported(raw_string)
try: try:
returnValue((obj.cmdset.current, list(obj.cmdset.cmdset_stack))) returnValue((obj.cmdset.current, list(obj.cmdset.cmdset_stack)))
except AttributeError: except AttributeError:
returnValue(((None, None, None), [])) returnValue(((None, None, None), []))
@ -550,9 +553,9 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
cmd.session = session cmd.session = session
cmd.account = account cmd.account = account
cmd.raw_string = unformatted_raw_string cmd.raw_string = unformatted_raw_string
#cmd.obj # set via on-object cmdset handler for each command, # cmd.obj # set via on-object cmdset handler for each command,
# since this may be different for every command when # since this may be different for every command when
# merging multuple cmdsets # merging multuple cmdsets
if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'): if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'):
# cmd.obj is automatically made available by the cmdhandler. # cmd.obj is automatically made available by the cmdhandler.
@ -615,7 +618,6 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
finally: finally:
_COMMAND_NESTING[called_by] -= 1 _COMMAND_NESTING[called_by] -= 1
raw_string = to_unicode(raw_string, force_string=True) raw_string = to_unicode(raw_string, force_string=True)
session, account, obj = session, None, None session, account, obj = session, None, None
@ -653,7 +655,7 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
else: else:
# no explicit cmdobject given, figure it out # no explicit cmdobject given, figure it out
cmdset = yield get_and_merge_cmdsets(caller, session, account, obj, cmdset = yield get_and_merge_cmdsets(caller, session, account, obj,
callertype, raw_string) callertype, raw_string)
if not cmdset: if not cmdset:
# this is bad and shouldn't happen. # this is bad and shouldn't happen.
raise NoCmdSets raise NoCmdSets
@ -701,8 +703,8 @@ def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sess
# fallback to default error text # fallback to default error text
sysarg = _("Command '%s' is not available.") % raw_string sysarg = _("Command '%s' is not available.") % raw_string
suggestions = string_suggestions(raw_string, suggestions = string_suggestions(raw_string,
cmdset.get_all_cmd_keys_and_aliases(caller), cmdset.get_all_cmd_keys_and_aliases(caller),
cutoff=0.7, maxnum=3) cutoff=0.7, maxnum=3)
if suggestions: if suggestions:
sysarg += _(" Maybe you meant %s?") % utils.list_to_string(suggestions, _('or'), addquote=True) sysarg += _(" Maybe you meant %s?") % utils.list_to_string(suggestions, _('or'), addquote=True)
else: else:

View file

@ -14,6 +14,7 @@ from evennia.utils.logger import log_trace
_MULTIMATCH_REGEX = re.compile(settings.SEARCH_MULTIMATCH_REGEX, re.I + re.U) _MULTIMATCH_REGEX = re.compile(settings.SEARCH_MULTIMATCH_REGEX, re.I + re.U)
_CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES _CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
def cmdparser(raw_string, cmdset, caller, match_index=None): def cmdparser(raw_string, cmdset, caller, match_index=None):
""" """
This function is called by the cmdhandler once it has This function is called by the cmdhandler once it has
@ -82,10 +83,10 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
# use the cmdname as-is # use the cmdname as-is
for cmd in cmdset: for cmd in cmdset:
matches.extend([create_match(cmdname, raw_string, cmd, cmdname) matches.extend([create_match(cmdname, raw_string, cmd, cmdname)
for cmdname in [cmd.key] + cmd.aliases for cmdname in [cmd.key] + cmd.aliases
if cmdname and l_raw_string.startswith(cmdname.lower()) if cmdname and l_raw_string.startswith(cmdname.lower()) and
and (not cmd.arg_regex or (not cmd.arg_regex or
cmd.arg_regex.match(l_raw_string[len(cmdname):]))]) cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
else: else:
# strip prefixes set in settings # strip prefixes set in settings
for cmd in cmdset: for cmd in cmdset:
@ -133,7 +134,7 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
# See if it helps to analyze the match with preserved case but only if # See if it helps to analyze the match with preserved case but only if
# it leaves at least one match. # it leaves at least one match.
trimmed = [match for match in matches trimmed = [match for match in matches
if raw_string.startswith(match[0])] if raw_string.startswith(match[0])]
if trimmed: if trimmed:
matches = trimmed matches = trimmed
@ -151,10 +152,10 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
quality = [mat[4] for mat in matches] quality = [mat[4] for mat in matches]
matches = matches[-quality.count(quality[-1]):] matches = matches[-quality.count(quality[-1]):]
if len(matches) > 1 and match_index != None and 0 < match_index <= len(matches): if len(matches) > 1 and match_index is not None and 0 < match_index <= len(matches):
# We couldn't separate match by quality, but we have an # We couldn't separate match by quality, but we have an
# index argument to tell us which match to use. # index argument to tell us which match to use.
matches = [matches[match_index-1]] matches = [matches[match_index - 1]]
# no matter what we have at this point, we have to return it. # no matter what we have at this point, we have to return it.
return matches return matches

View file

@ -51,7 +51,7 @@ class _CmdSetMeta(type):
cls.key = cls.__name__ cls.key = cls.__name__
cls.path = "%s.%s" % (cls.__module__, cls.__name__) cls.path = "%s.%s" % (cls.__module__, cls.__name__)
if not type(cls.key_mergetypes) == dict: if not isinstance(cls.key_mergetypes, dict):
cls.key_mergetypes = {} cls.key_mergetypes = {}
super(_CmdSetMeta, cls).__init__(*args, **kwargs) super(_CmdSetMeta, cls).__init__(*args, **kwargs)
@ -188,7 +188,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
# initialize system # initialize system
self.at_cmdset_creation() self.at_cmdset_creation()
self._contains_cache = WeakKeyDictionary()#{} self._contains_cache = WeakKeyDictionary() # {}
# Priority-sensitive merge operations for cmdsets # Priority-sensitive merge operations for cmdsets
@ -214,7 +214,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
cmdset_c.commands.extend(cmdset_b.commands) cmdset_c.commands.extend(cmdset_b.commands)
else: else:
cmdset_c.commands.extend([cmd for cmd in cmdset_b cmdset_c.commands.extend([cmd for cmd in cmdset_b
if not cmd in cmdset_a]) if cmd not in cmdset_a])
return cmdset_c return cmdset_c
def _intersect(self, cmdset_a, cmdset_b): def _intersect(self, cmdset_a, cmdset_b):
@ -280,7 +280,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
""" """
cmdset_c = cmdset_a._duplicate() cmdset_c = cmdset_a._duplicate()
cmdset_c.commands = [cmd for cmd in cmdset_b if not cmd in cmdset_a] cmdset_c.commands = [cmd for cmd in cmdset_b if cmd not in cmdset_a]
return cmdset_c return cmdset_c
def _instantiate(self, cmd): def _instantiate(self, cmd):
@ -411,7 +411,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
cmdset_c = self._replace(self, cmdset_a) cmdset_c = self._replace(self, cmdset_a)
elif mergetype == "Remove": elif mergetype == "Remove":
cmdset_c = self._remove(self, cmdset_a) cmdset_c = self._remove(self, cmdset_a)
else: # Union else: # Union
cmdset_c = self._union(self, cmdset_a) cmdset_c = self._union(self, cmdset_a)
# pass through options whenever they are set, unless the higher-prio # pass through options whenever they are set, unless the higher-prio
@ -426,7 +426,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
# This is used for diagnosis. # This is used for diagnosis.
cmdset_c.actual_mergetype = mergetype cmdset_c.actual_mergetype = mergetype
#print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, cmdset_a.key, cmdset_a.priority) # print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, cmdset_a.key, cmdset_a.priority)
# return the system commands to the cmdset # return the system commands to the cmdset
cmdset_c.add(sys_commands) cmdset_c.add(sys_commands)
@ -604,7 +604,7 @@ class CmdSet(with_metaclass(_CmdSetMeta, object)):
names = [] names = []
if caller: if caller:
[names.extend(cmd._keyaliases) for cmd in self.commands [names.extend(cmd._keyaliases) for cmd in self.commands
if cmd.access(caller)] if cmd.access(caller)]
else: else:
[names.extend(cmd._keyaliases) for cmd in self.commands] [names.extend(cmd._keyaliases) for cmd in self.commands]
return names return names

View file

@ -86,32 +86,32 @@ _CMDSET_FALLBACKS = settings.CMDSET_FALLBACKS
# Output strings # Output strings
_ERROR_CMDSET_IMPORT = _( _ERROR_CMDSET_IMPORT = _(
"""{traceback} """{traceback}
Error loading cmdset '{path}' Error loading cmdset '{path}'
(Traceback was logged {timestamp})""") (Traceback was logged {timestamp})""")
_ERROR_CMDSET_KEYERROR = _( _ERROR_CMDSET_KEYERROR = _(
"""Error loading cmdset: No cmdset class '{classname}' in '{path}'. """Error loading cmdset: No cmdset class '{classname}' in '{path}'.
(Traceback was logged {timestamp})""") (Traceback was logged {timestamp})""")
_ERROR_CMDSET_SYNTAXERROR = _( _ERROR_CMDSET_SYNTAXERROR = _(
"""{traceback} """{traceback}
SyntaxError encountered when loading cmdset '{path}'. SyntaxError encountered when loading cmdset '{path}'.
(Traceback was logged {timestamp})""") (Traceback was logged {timestamp})""")
_ERROR_CMDSET_EXCEPTION = _( _ERROR_CMDSET_EXCEPTION = _(
"""{traceback} """{traceback}
Compile/Run error when loading cmdset '{path}'.", Compile/Run error when loading cmdset '{path}'.",
(Traceback was logged {timestamp})""") (Traceback was logged {timestamp})""")
_ERROR_CMDSET_FALLBACK = _( _ERROR_CMDSET_FALLBACK = _(
""" """
Error encountered for cmdset at path '{path}'. Error encountered for cmdset at path '{path}'.
Replacing with fallback '{fallback_path}'. Replacing with fallback '{fallback_path}'.
""") """)
_ERROR_CMDSET_NO_FALLBACK = _( _ERROR_CMDSET_NO_FALLBACK = _(
"""Fallback path '{fallback_path}' failed to generate a cmdset.""" """Fallback path '{fallback_path}' failed to generate a cmdset."""
) )
@ -122,6 +122,7 @@ class _ErrorCmdSet(CmdSet):
key = "_CMDSET_ERROR" key = "_CMDSET_ERROR"
errmessage = "Error when loading cmdset." errmessage = "Error when loading cmdset."
class _EmptyCmdSet(CmdSet): class _EmptyCmdSet(CmdSet):
""" """
This cmdset represents an empty cmdset This cmdset represents an empty cmdset
@ -130,6 +131,7 @@ class _EmptyCmdSet(CmdSet):
priority = -101 priority = -101
mergetype = "Union" mergetype = "Union"
def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
""" """
This helper function is used by the cmdsethandler to load a cmdset This helper function is used by the cmdsethandler to load a cmdset
@ -154,11 +156,11 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
""" """
python_paths = [path] + ["%s.%s" % (prefix, path) python_paths = [path] + ["%s.%s" % (prefix, path)
for prefix in _CMDSET_PATHS if not path.startswith(prefix)] for prefix in _CMDSET_PATHS if not path.startswith(prefix)]
errstring = "" errstring = ""
for python_path in python_paths: for python_path in python_paths:
if "." in path: if "." in path:
modpath, classname = python_path.rsplit(".", 1) modpath, classname = python_path.rsplit(".", 1)
else: else:
raise ImportError("The path '%s' is not on the form modulepath.ClassName" % path) raise ImportError("The path '%s' is not on the form modulepath.ClassName" % path)
@ -191,7 +193,7 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
continue continue
_CACHED_CMDSETS[python_path] = cmdsetclass _CACHED_CMDSETS[python_path] = cmdsetclass
#instantiate the cmdset (and catch its errors) # instantiate the cmdset (and catch its errors)
if callable(cmdsetclass): if callable(cmdsetclass):
cmdsetclass = cmdsetclass(cmdsetobj) cmdsetclass = cmdsetclass(cmdsetobj)
return cmdsetclass return cmdsetclass
@ -235,7 +237,7 @@ def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False):
err_cmdset = _ErrorCmdSet() err_cmdset = _ErrorCmdSet()
err_cmdset.errmessage = errstring err_cmdset.errmessage = errstring
return err_cmdset return err_cmdset
return None # undefined error return None # undefined error
# classes # classes
@ -278,7 +280,7 @@ class CmdSetHandler(object):
self.permanent_paths = [""] self.permanent_paths = [""]
if init_true: if init_true:
self.update(init_mode=True) #is then called from the object __init__. self.update(init_mode=True) # is then called from the object __init__.
def __str__(self): def __str__(self):
""" """
@ -311,8 +313,8 @@ class CmdSetHandler(object):
if mergelist: if mergelist:
tmpstring = _(" <Merged {mergelist} {mergetype}, prio {prio}>: {current}") tmpstring = _(" <Merged {mergelist} {mergetype}, prio {prio}>: {current}")
string += tmpstring.format(mergelist="+".join(mergelist), string += tmpstring.format(mergelist="+".join(mergelist),
mergetype=mergetype, prio=self.current.priority, mergetype=mergetype, prio=self.current.priority,
current=self.current) current=self.current)
else: else:
permstring = "non-perm" permstring = "non-perm"
if self.current.permanent: if self.current.permanent:
@ -322,7 +324,7 @@ class CmdSetHandler(object):
prio=self.current.priority, prio=self.current.priority,
permstring=permstring, permstring=permstring,
keylist=", ".join(cmd.key for keylist=", ".join(cmd.key for
cmd in sorted(self.current, key=lambda o: o.key))) cmd in sorted(self.current, key=lambda o: o.key)))
return string.strip() return string.strip()
def _import_cmdset(self, cmdset_path, emit_to_obj=None): def _import_cmdset(self, cmdset_path, emit_to_obj=None):
@ -542,7 +544,6 @@ class CmdSetHandler(object):
# legacy alias # legacy alias
delete_default = remove_default delete_default = remove_default
def all(self): def all(self):
""" """
Show all cmdsets. Show all cmdsets.
@ -588,16 +589,16 @@ class CmdSetHandler(object):
else: else:
print [cset.path for cset in self.cmdset_stack], cmdset.path print [cset.path for cset in self.cmdset_stack], cmdset.path
return any([cset for cset in self.cmdset_stack return any([cset for cset in self.cmdset_stack
if cset.path == cmdset.path]) if cset.path == cmdset.path])
else: else:
# try it as a path or key # try it as a path or key
if must_be_default: if must_be_default:
return self.cmdset_stack and ( return self.cmdset_stack and (
self.cmdset_stack[0].key == cmdset or self.cmdset_stack[0].key == cmdset or
self.cmdset_stack[0].path == cmdset) self.cmdset_stack[0].path == cmdset)
else: else:
return any([cset for cset in self.cmdset_stack return any([cset for cset in self.cmdset_stack
if cset.path == cmdset or cset.key == cmdset]) if cset.path == cmdset or cset.key == cmdset])
# backwards-compatability alias # backwards-compatability alias
has_cmdset = has has_cmdset = has

View file

@ -60,7 +60,7 @@ def _init_command(cls, **kwargs):
if "cmd:" not in cls.locks: if "cmd:" not in cls.locks:
cls.locks = "cmd:all();" + cls.locks cls.locks = "cmd:all();" + cls.locks
for lockstring in cls.locks.split(';'): for lockstring in cls.locks.split(';'):
if lockstring and not ':' in lockstring: if lockstring and ':' not in lockstring:
lockstring = "cmd:%s" % lockstring lockstring = "cmd:%s" % lockstring
temp.append(lockstring) temp.append(lockstring)
cls.lock_storage = ";".join(temp) cls.lock_storage = ";".join(temp)

View file

@ -364,7 +364,7 @@ class CmdSessions(COMMAND_DEFAULT_CLASS):
for sess in sorted(sessions, key=lambda x: x.sessid): for sess in sorted(sessions, key=lambda x: x.sessid):
char = account.get_puppet(sess) char = account.get_puppet(sess)
table.add_row(str(sess.sessid), str(sess.protocol_key), table.add_row(str(sess.sessid), str(sess.protocol_key),
type(sess.address) == tuple and sess.address[0] or sess.address, isinstance(sess.address, tuple) and sess.address[0] or sess.address,
char and str(char) or "None", char and str(char) or "None",
char and str(char.location) or "N/A") char and str(char.location) or "N/A")
self.msg("|wYour current session(s):|n\n%s" % table) self.msg("|wYour current session(s):|n\n%s" % table)
@ -508,7 +508,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
options["SCREENHEIGHT"] = options["SCREENHEIGHT"][0] options["SCREENHEIGHT"] = options["SCREENHEIGHT"][0]
else: else:
options["SCREENHEIGHT"] = " \n".join("%s : %s" % (screenid, size) options["SCREENHEIGHT"] = " \n".join("%s : %s" % (screenid, size)
for screenid, size in options["SCREENHEIGHT"].iteritems()) for screenid, size in options["SCREENHEIGHT"].iteritems())
options.pop("TTYPE", None) options.pop("TTYPE", None)
header = ("Name", "Value", "Saved") if saved_options else ("Name", "Value") header = ("Name", "Value", "Saved") if saved_options else ("Name", "Value")
@ -552,7 +552,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
flags[new_name] = new_val flags[new_name] = new_val
self.msg("Option |w%s|n was changed from '|w%s|n' to '|w%s|n'." % (new_name, old_val, new_val)) self.msg("Option |w%s|n was changed from '|w%s|n' to '|w%s|n'." % (new_name, old_val, new_val))
return {new_name: new_val} return {new_name: new_val}
except Exception, err: except Exception as err:
self.msg("|rCould not set option |w%s|r:|n %s" % (new_name, err)) self.msg("|rCould not set option |w%s|r:|n %s" % (new_name, err))
return False return False
@ -578,7 +578,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
val = self.rhs.strip() val = self.rhs.strip()
optiondict = False optiondict = False
if val and name in validators: if val and name in validators:
optiondict = update(name, val, validators[name]) optiondict = update(name, val, validators[name])
else: else:
self.msg("|rNo option named '|w%s|r'." % name) self.msg("|rNo option named '|w%s|r'." % name)
if optiondict: if optiondict:
@ -664,7 +664,7 @@ class CmdQuit(COMMAND_DEFAULT_CLASS):
if nsess == 2: if nsess == 2:
account.msg("|RQuitting|n. One session is still connected.", session=self.session) account.msg("|RQuitting|n. One session is still connected.", session=self.session)
elif nsess > 2: elif nsess > 2:
account.msg("|RQuitting|n. %i sessions are still connected." % (nsess-1), session=self.session) account.msg("|RQuitting|n. %i sessions are still connected." % (nsess - 1), session=self.session)
else: else:
# we are quitting the last available session # we are quitting the last available session
account.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session) account.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session)
@ -732,7 +732,7 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
for code, _ in ap.ansi_map[self.slice_dark_bg]] for code, _ in ap.ansi_map[self.slice_dark_bg]]
bright_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) bright_bg = ["%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", ""))
for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg]] for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg]]
dark_fg.extend(["" for _ in range(len(bright_fg)-len(dark_fg))]) dark_fg.extend(["" for _ in range(len(bright_fg) - len(dark_fg))])
table = utils.format_table([bright_fg, dark_fg, bright_bg, dark_bg]) table = utils.format_table([bright_fg, dark_fg, bright_bg, dark_bg])
string = "ANSI colors:" string = "ANSI colors:"
for row in table: for row in table:
@ -751,16 +751,16 @@ class CmdColorTest(COMMAND_DEFAULT_CLASS):
# foreground table # foreground table
table[ir].append("|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib))) table[ir].append("|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib)))
# background table # background table
table[6+ir].append("|%i%i%i|[%i%i%i%s|n" table[6 + ir].append("|%i%i%i|[%i%i%i%s|n"
% (5 - ir, 5 - ig, 5 - ib, ir, ig, ib, "||[%i%i%i" % (ir, ig, ib))) % (5 - ir, 5 - ig, 5 - ib, ir, ig, ib, "||[%i%i%i" % (ir, ig, ib)))
table = self.table_format(table) table = self.table_format(table)
string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):" string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):"
string += "\n" + "\n".join("".join(row) for row in table) string += "\n" + "\n".join("".join(row) for row in table)
table = [[], [], [], [], [], [], [], [], [], [], [], []] table = [[], [], [], [], [], [], [], [], [], [], [], []]
for ibatch in range(4): for ibatch in range(4):
for igray in range(6): for igray in range(6):
letter = chr(97 + (ibatch*6 + igray)) letter = chr(97 + (ibatch * 6 + igray))
inverse = chr(122 - (ibatch*6 + igray)) inverse = chr(122 - (ibatch * 6 + igray))
table[0 + igray].append("|=%s%s |n" % (letter, "||=%s" % letter)) table[0 + igray].append("|=%s%s |n" % (letter, "||=%s" % letter))
table[6 + igray].append("|=%s|[=%s%s |n" % (inverse, letter, "||[=%s" % letter)) table[6 + igray].append("|=%s|[=%s%s |n" % (inverse, letter, "||[=%s" % letter))
for igray in range(6): for igray in range(6):

View file

@ -171,9 +171,9 @@ class CmdBan(COMMAND_DEFAULT_CLASS):
if not banlist: if not banlist:
banlist = [] banlist = []
if not self.args or (self.switches if not self.args or (self.switches and
and not any(switch in ('ip', 'name') not any(switch in ('ip', 'name')
for switch in self.switches)): for switch in self.switches)):
self.caller.msg(list_bans(banlist)) self.caller.msg(list_bans(banlist))
return return
@ -430,7 +430,7 @@ class CmdNewPassword(COMMAND_DEFAULT_CLASS):
self.msg("%s - new password set to '%s'." % (account.name, self.rhs)) self.msg("%s - new password set to '%s'." % (account.name, self.rhs))
if account.character != caller: if account.character != caller:
account.msg("%s has changed your password to '%s'." % (caller.name, account.msg("%s has changed your password to '%s'." % (caller.name,
self.rhs)) self.rhs))
class CmdPerm(COMMAND_DEFAULT_CLASS): class CmdPerm(COMMAND_DEFAULT_CLASS):

View file

@ -41,6 +41,7 @@ _DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
_PROTOTYPE_PARENTS = None _PROTOTYPE_PARENTS = None
class ObjManipCommand(COMMAND_DEFAULT_CLASS): class ObjManipCommand(COMMAND_DEFAULT_CLASS):
""" """
This is a parent class for some of the defining objmanip commands This is a parent class for some of the defining objmanip commands
@ -73,7 +74,7 @@ class ObjManipCommand(COMMAND_DEFAULT_CLASS):
super(ObjManipCommand, self).parse() super(ObjManipCommand, self).parse()
obj_defs = ([], []) # stores left- and right-hand side of '=' obj_defs = ([], []) # stores left- and right-hand side of '='
obj_attrs = ([], []) # " obj_attrs = ([], []) # "
for iside, arglist in enumerate((self.lhslist, self.rhslist)): for iside, arglist in enumerate((self.lhslist, self.rhslist)):
# lhslist/rhslist is already split by ',' at this point # lhslist/rhslist is already split by ',' at this point
@ -88,8 +89,8 @@ class ObjManipCommand(COMMAND_DEFAULT_CLASS):
objdef, attrs = [part.strip() for part in objdef.split('/', 1)] objdef, attrs = [part.strip() for part in objdef.split('/', 1)]
attrs = [part.strip().lower() for part in attrs.split('/') if part.strip()] attrs = [part.strip().lower() for part in attrs.split('/') if part.strip()]
# store data # store data
obj_defs[iside].append({"name":objdef, 'option':option, 'aliases':aliases}) obj_defs[iside].append({"name": objdef, 'option': option, 'aliases': aliases})
obj_attrs[iside].append({"name":objdef, 'attrs':attrs}) obj_attrs[iside].append({"name": objdef, 'attrs': attrs})
# store for future access # store for future access
self.lhs_objs = obj_defs[0] self.lhs_objs = obj_defs[0]
@ -242,9 +243,9 @@ class CmdCopy(ObjManipCommand):
return return
copiedobj = ObjectDB.objects.copy_object(from_obj, copiedobj = ObjectDB.objects.copy_object(from_obj,
new_key=to_obj_name, new_key=to_obj_name,
new_location=to_obj_location, new_location=to_obj_location,
new_aliases=to_obj_aliases) new_aliases=to_obj_aliases)
if copiedobj: if copiedobj:
string = "Copied %s to '%s' (aliases: %s)." % (from_obj_name, to_obj_name, string = "Copied %s to '%s' (aliases: %s)." % (from_obj_name, to_obj_name,
to_obj_aliases) to_obj_aliases)
@ -350,7 +351,7 @@ class CmdCpAttr(ObjManipCommand):
if not from_obj or not to_objs: if not from_obj or not to_objs:
caller.msg("You have to supply both source object and target(s).") caller.msg("You have to supply both source object and target(s).")
return return
#copy to all to_obj:ects # copy to all to_obj:ects
if "move" in self.switches: if "move" in self.switches:
clear = True clear = True
else: else:
@ -387,7 +388,7 @@ class CmdCpAttr(ObjManipCommand):
value = self.get_attr(from_obj, from_attr) value = self.get_attr(from_obj, from_attr)
to_obj.attributes.add(to_attr, value) to_obj.attributes.add(to_attr, value)
if (clear and not (from_obj == to_obj and if (clear and not (from_obj == to_obj and
from_attr == to_attr)): from_attr == to_attr)):
from_obj.attributes.remove(from_attr) from_obj.attributes.remove(from_attr)
result.append("\nMoved %s.%s -> %s.%s. (value: %s)" % (from_obj.name, result.append("\nMoved %s.%s -> %s.%s. (value: %s)" % (from_obj.name,
from_attr, from_attr,
@ -522,6 +523,7 @@ class CmdCreate(ObjManipCommand):
def _desc_load(caller): def _desc_load(caller):
return caller.db.evmenu_target.db.desc or "" return caller.db.evmenu_target.db.desc or ""
def _desc_save(caller, buf): def _desc_save(caller, buf):
""" """
Save line buffer to the desc prop. This should Save line buffer to the desc prop. This should
@ -531,10 +533,12 @@ def _desc_save(caller, buf):
caller.msg("Saved.") caller.msg("Saved.")
return True return True
def _desc_quit(caller): def _desc_quit(caller):
caller.attributes.remove("evmenu_target") caller.attributes.remove("evmenu_target")
caller.msg("Exited editor.") caller.msg("Exited editor.")
class CmdDesc(COMMAND_DEFAULT_CLASS): class CmdDesc(COMMAND_DEFAULT_CLASS):
""" """
describe an object or the current room. describe an object or the current room.
@ -642,12 +646,12 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS):
objname = obj.name objname = obj.name
if not (obj.access(caller, "control") or obj.access(caller, 'delete')): if not (obj.access(caller, "control") or obj.access(caller, 'delete')):
return "\nYou don't have permission to delete %s." % objname return "\nYou don't have permission to delete %s." % objname
if obj.account and not 'override' in self.switches: if obj.account and 'override' not in self.switches:
return "\nObject %s is controlled by an active account. Use /override to delete anyway." % objname return "\nObject %s is controlled by an active account. Use /override to delete anyway." % objname
if obj.dbid == int(settings.DEFAULT_HOME.lstrip("#")): if obj.dbid == int(settings.DEFAULT_HOME.lstrip("#")):
return "\nYou are trying to delete |c%s|n, which is set as DEFAULT_HOME. " \ return "\nYou are trying to delete |c%s|n, which is set as DEFAULT_HOME. " \
"Re-point settings.DEFAULT_HOME to another " \ "Re-point settings.DEFAULT_HOME to another " \
"object before continuing." % objname "object before continuing." % objname
had_exits = hasattr(obj, "exits") and obj.exits had_exits = hasattr(obj, "exits") and obj.exits
had_objs = hasattr(obj, "contents") and any(obj for obj in obj.contents had_objs = hasattr(obj, "contents") and any(obj for obj in obj.contents
@ -749,7 +753,7 @@ class CmdDig(ObjManipCommand):
if new_room.aliases.all(): if new_room.aliases.all():
alias_string = " (%s)" % ", ".join(new_room.aliases.all()) alias_string = " (%s)" % ", ".join(new_room.aliases.all())
room_string = "Created room %s(%s)%s of type %s." % (new_room, room_string = "Created room %s(%s)%s of type %s." % (new_room,
new_room.dbref, alias_string, typeclass) new_room.dbref, alias_string, typeclass)
# create exit to room # create exit to room
@ -763,7 +767,7 @@ class CmdDig(ObjManipCommand):
"\nNo exit created to new room." "\nNo exit created to new room."
elif not location: elif not location:
exit_to_string = \ exit_to_string = \
"\nYou cannot create an exit from a None-location." "\nYou cannot create an exit from a None-location."
else: else:
# Build the exit to the new room from the current one # Build the exit to the new room from the current one
typeclass = to_exit["option"] typeclass = to_exit["option"]
@ -796,18 +800,18 @@ class CmdDig(ObjManipCommand):
"\nNo back exit created." "\nNo back exit created."
elif not location: elif not location:
exit_back_string = \ exit_back_string = \
"\nYou cannot create an exit back to a None-location." "\nYou cannot create an exit back to a None-location."
else: else:
typeclass = back_exit["option"] typeclass = back_exit["option"]
if not typeclass: if not typeclass:
typeclass = settings.BASE_EXIT_TYPECLASS typeclass = settings.BASE_EXIT_TYPECLASS
new_back_exit = create.create_object(typeclass, new_back_exit = create.create_object(typeclass,
back_exit["name"], back_exit["name"],
new_room, new_room,
aliases=back_exit["aliases"], aliases=back_exit["aliases"],
locks=lockstring, locks=lockstring,
destination=location, destination=location,
report_to=caller) report_to=caller)
alias_string = "" alias_string = ""
if new_back_exit.aliases.all(): if new_back_exit.aliases.all():
alias_string = " (%s)" % ", ".join(new_back_exit.aliases.all()) alias_string = " (%s)" % ", ".join(new_back_exit.aliases.all())
@ -821,6 +825,7 @@ class CmdDig(ObjManipCommand):
if new_room and ('teleport' in self.switches or "tel" in self.switches): if new_room and ('teleport' in self.switches or "tel" in self.switches):
caller.move_to(new_room) caller.move_to(new_room)
class CmdTunnel(COMMAND_DEFAULT_CLASS): class CmdTunnel(COMMAND_DEFAULT_CLASS):
""" """
create new rooms in cardinal directions only create new rooms in cardinal directions only
@ -893,7 +898,7 @@ class CmdTunnel(COMMAND_DEFAULT_CLASS):
if "tel" in self.switches: if "tel" in self.switches:
telswitch = "/teleport" telswitch = "/teleport"
backstring = "" backstring = ""
if not "oneway" in self.switches: if "oneway" not in self.switches:
backstring = ", %s;%s" % (backname, backshort) backstring = ", %s;%s" % (backname, backshort)
# build the string we will use to call @dig # build the string we will use to call @dig
@ -951,7 +956,7 @@ class CmdLink(COMMAND_DEFAULT_CLASS):
string = "" string = ""
if not obj.destination: if not obj.destination:
string += "Note: %s(%s) did not have a destination set before. Make sure you linked the right thing." % (obj.name,obj.dbref) string += "Note: %s(%s) did not have a destination set before. Make sure you linked the right thing." % (obj.name, obj.dbref)
if "twoway" in self.switches: if "twoway" in self.switches:
if not (target.location and obj.location): if not (target.location and obj.location):
string = "To create a two-way link, %s and %s must both have a location" % (obj, target) string = "To create a two-way link, %s and %s must both have a location" % (obj, target)
@ -1199,7 +1204,7 @@ class CmdOpen(ObjManipCommand):
# a custom member method to chug out exits and do checks # a custom member method to chug out exits and do checks
def create_exit(self, exit_name, location, destination, def create_exit(self, exit_name, location, destination,
exit_aliases=None, typeclass=None): exit_aliases=None, typeclass=None):
""" """
Helper function to avoid code duplication. Helper function to avoid code duplication.
At this point we know destination is a valid location At this point we know destination is a valid location
@ -1484,10 +1489,11 @@ class CmdSetAttribute(ObjManipCommand):
old_value = obj.attributes.get(attr) old_value = obj.attributes.get(attr)
if old_value is not None and not isinstance(old_value, basestring): if old_value is not None and not isinstance(old_value, basestring):
typ = type(old_value).__name__ typ = type(old_value).__name__
self.caller.msg("|RWARNING! Saving this buffer will overwrite the "\ self.caller.msg("|RWARNING! Saving this buffer will overwrite the "
"current attribute (of type %s) with a string!|n" % typ) "current attribute (of type %s) with a string!|n" % typ)
return str(old_value) return str(old_value)
return old_value return old_value
def save(caller, buf): def save(caller, buf):
"Called when editor saves its buffer." "Called when editor saves its buffer."
obj.attributes.add(attr, buf) obj.attributes.add(attr, buf)
@ -1495,7 +1501,6 @@ class CmdSetAttribute(ObjManipCommand):
# start the editor # start the editor
EvEditor(self.caller, load, save, key="%s/%s" % (obj, attr)) EvEditor(self.caller, load, save, key="%s/%s" % (obj, attr))
def func(self): def func(self):
"Implement the set attribute - a limited form of @py." "Implement the set attribute - a limited form of @py."
@ -1523,7 +1528,7 @@ class CmdSetAttribute(ObjManipCommand):
if "edit" in self.switches: if "edit" in self.switches:
# edit in the line editor # edit in the line editor
if len(attrs) > 1: if len(attrs) > 1:
caller.msg("The Line editor can only be applied " \ caller.msg("The Line editor can only be applied "
"to one attribute at a time.") "to one attribute at a time.")
return return
self.edit_handler(obj, attrs[0]) self.edit_handler(obj, attrs[0])
@ -1538,7 +1543,7 @@ class CmdSetAttribute(ObjManipCommand):
continue continue
result.append(self.view_attr(obj, attr)) result.append(self.view_attr(obj, attr))
# we view it without parsing markup. # we view it without parsing markup.
self.caller.msg("".join(result).strip(), options={"raw":True}) self.caller.msg("".join(result).strip(), options={"raw": True})
return return
else: else:
# deleting the attribute(s) # deleting the attribute(s)
@ -1644,7 +1649,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
return return
is_same = obj.is_typeclass(new_typeclass, exact=True) is_same = obj.is_typeclass(new_typeclass, exact=True)
if is_same and not 'force' in self.switches: if is_same and 'force' not in self.switches:
string = "%s already has the typeclass '%s'. Use /force to override." % (obj.name, new_typeclass) string = "%s already has the typeclass '%s'. Use /force to override." % (obj.name, new_typeclass)
else: else:
update = "update" in self.switches update = "update" in self.switches
@ -1654,14 +1659,14 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS):
# we let this raise exception if needed # we let this raise exception if needed
obj.swap_typeclass(new_typeclass, clean_attributes=reset, obj.swap_typeclass(new_typeclass, clean_attributes=reset,
clean_cmdsets=reset, run_start_hooks=hooks) clean_cmdsets=reset, run_start_hooks=hooks)
if is_same: if is_same:
string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path) string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path)
else: else:
string = "%s changed typeclass from %s to %s.\n" % (obj.name, string = "%s changed typeclass from %s to %s.\n" % (obj.name,
old_typeclass_path, old_typeclass_path,
obj.typeclass_path) obj.typeclass_path)
if update: if update:
string += "Only the at_object_creation hook was run (update mode)." string += "Only the at_object_creation hook was run (update mode)."
else: else:
@ -1797,8 +1802,8 @@ class CmdLock(ObjManipCommand):
# we have a = separator, so we are assigning a new lock # we have a = separator, so we are assigning a new lock
if self.switches: if self.switches:
swi = ", ".join(self.switches) swi = ", ".join(self.switches)
caller.msg("Switch(es) |w%s|n can not be used with a "\ caller.msg("Switch(es) |w%s|n can not be used with a "
"lock assignment. Use e.g. " \ "lock assignment. Use e.g. "
"|w@lock/del objname/locktype|n instead." % swi) "|w@lock/del objname/locktype|n instead." % swi)
return return
@ -1851,7 +1856,7 @@ class CmdExamine(ObjManipCommand):
""" """
key = "@examine" key = "@examine"
aliases = ["@ex","exam"] aliases = ["@ex", "exam"]
locks = "cmd:perm(examine) or perm(Builder)" locks = "cmd:perm(examine) or perm(Builder)"
help_category = "Building" help_category = "Building"
arg_regex = r"(/\w+?(\s|$))|\s|$" arg_regex = r"(/\w+?(\s|$))|\s|$"
@ -1913,7 +1918,7 @@ class CmdExamine(ObjManipCommand):
string += "\n|wAliases|n: %s" % (", ".join(utils.make_iter(str(obj.aliases)))) string += "\n|wAliases|n: %s" % (", ".join(utils.make_iter(str(obj.aliases))))
if hasattr(obj, "sessions") and obj.sessions.all(): if hasattr(obj, "sessions") and obj.sessions.all():
string += "\n|wSession id(s)|n: %s" % (", ".join("#%i" % sess.sessid string += "\n|wSession id(s)|n: %s" % (", ".join("#%i" % sess.sessid
for sess in obj.sessions.all())) for sess in obj.sessions.all()))
if hasattr(obj, "email") and obj.email: if hasattr(obj, "email") and obj.email:
string += "\n|wEmail|n: |c%s|n" % obj.email string += "\n|wEmail|n: |c%s|n" % obj.email
if hasattr(obj, "has_account") and obj.has_account: if hasattr(obj, "has_account") and obj.has_account:
@ -1957,20 +1962,19 @@ class CmdExamine(ObjManipCommand):
locks_string = " Default" locks_string = " Default"
string += "\n|wLocks|n:%s" % locks_string string += "\n|wLocks|n:%s" % locks_string
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"): if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "_EMPTY_CMDSET"):
# all() returns a 'stack', so make a copy to sort. # all() returns a 'stack', so make a copy to sort.
stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority, reverse=True) stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority, reverse=True)
string += "\n|wStored Cmdset(s)|n:\n %s" % ("\n ".join("%s [%s] (%s, prio %s)" % \ string += "\n|wStored Cmdset(s)|n:\n %s" % ("\n ".join("%s [%s] (%s, prio %s)" %
(cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority) (cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority)
for cmdset in stored_cmdsets if cmdset.key != "_EMPTY_CMDSET")) for cmdset in stored_cmdsets if cmdset.key != "_EMPTY_CMDSET"))
# this gets all components of the currently merged set # this gets all components of the currently merged set
all_cmdsets = [(cmdset.key, cmdset) for cmdset in avail_cmdset.merged_from] all_cmdsets = [(cmdset.key, cmdset) for cmdset in avail_cmdset.merged_from]
# we always at least try to add account- and session sets since these are ignored # we always at least try to add account- and session sets since these are ignored
# if we merge on the object level. # if we merge on the object level.
if hasattr(obj, "account") and obj.account: if hasattr(obj, "account") and obj.account:
all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.account.cmdset.all()]) all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.account.cmdset.all()])
if obj.sessions.count(): if obj.sessions.count():
# if there are more sessions than one on objects it's because of multisession mode 3. # if there are more sessions than one on objects it's because of multisession mode 3.
# we only show the first session's cmdset here (it is -in principle- possible that # we only show the first session's cmdset here (it is -in principle- possible that
@ -1986,14 +1990,13 @@ class CmdExamine(ObjManipCommand):
pass pass
all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()] all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()]
all_cmdsets.sort(key=lambda x: x.priority, reverse=True) all_cmdsets.sort(key=lambda x: x.priority, reverse=True)
string += "\n|wMerged Cmdset(s)|n:\n %s" % ("\n ".join("%s [%s] (%s, prio %s)" % \ string += "\n|wMerged Cmdset(s)|n:\n %s" % ("\n ".join("%s [%s] (%s, prio %s)" %
(cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority) (cmdset.path, cmdset.key, cmdset.mergetype, cmdset.priority)
for cmdset in all_cmdsets)) for cmdset in all_cmdsets))
# list the commands available to this object # list the commands available to this object
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset avail_cmdset = sorted([cmd.key for cmd in avail_cmdset
if cmd.access(obj, "cmd")]) if cmd.access(obj, "cmd")])
cmdsetstr = utils.fill(", ".join(avail_cmdset), indent=2) cmdsetstr = utils.fill(", ".join(avail_cmdset), indent=2)
string += "\n|wCommands available to %s (result of Merged CmdSets)|n:\n %s" % (obj.key, cmdsetstr) string += "\n|wCommands available to %s (result of Merged CmdSets)|n:\n %s" % (obj.key, cmdsetstr)
@ -2005,7 +2008,7 @@ class CmdExamine(ObjManipCommand):
# display Tags # display Tags
tags_string = utils.fill(", ".join("%s[%s]" % (tag, category) tags_string = utils.fill(", ".join("%s[%s]" % (tag, category)
for tag, category in obj.tags.all(return_key_and_category=True)), indent=5) for tag, category in obj.tags.all(return_key_and_category=True)), indent=5)
if tags_string: if tags_string:
string += "\n|wTags[category]|n: %s" % tags_string.strip() string += "\n|wTags[category]|n: %s" % tags_string.strip()
@ -2029,7 +2032,7 @@ class CmdExamine(ObjManipCommand):
string += "\n|wContents|n: %s" % ", ".join(["%s(%s)" % (cont.name, cont.dbref) for cont in obj.contents string += "\n|wContents|n: %s" % ", ".join(["%s(%s)" % (cont.name, cont.dbref) for cont in obj.contents
if cont not in exits and cont not in pobjs]) if cont not in exits and cont not in pobjs])
separator = "-" * _DEFAULT_WIDTH separator = "-" * _DEFAULT_WIDTH
#output info # output info
return '%s\n%s\n%s' % (separator, string.strip(), separator) return '%s\n%s\n%s' % (separator, string.strip(), separator)
def func(self): def func(self):
@ -2053,7 +2056,7 @@ class CmdExamine(ObjManipCommand):
if hasattr(caller, "location"): if hasattr(caller, "location"):
obj = caller.location obj = caller.location
if not obj.access(caller, 'examine'): if not obj.access(caller, 'examine'):
#If we don't have special info access, just look at the object instead. # If we don't have special info access, just look at the object instead.
self.msg(caller.at_look(obj)) self.msg(caller.at_look(obj))
return return
# using callback for printing result whenever function returns. # using callback for printing result whenever function returns.
@ -2070,20 +2073,20 @@ class CmdExamine(ObjManipCommand):
obj_attrs = objdef['attrs'] obj_attrs = objdef['attrs']
self.account_mode = utils.inherits_from(caller, "evennia.accounts.accounts.DefaultAccount") or \ self.account_mode = utils.inherits_from(caller, "evennia.accounts.accounts.DefaultAccount") or \
"account" in self.switches or obj_name.startswith('*') "account" in self.switches or obj_name.startswith('*')
if self.account_mode: if self.account_mode:
try: try:
obj = caller.search_account(obj_name.lstrip('*')) obj = caller.search_account(obj_name.lstrip('*'))
except AttributeError: except AttributeError:
# this means we are calling examine from an account object # this means we are calling examine from an account object
obj = caller.search(obj_name.lstrip('*'), search_object = 'object' in self.switches) obj = caller.search(obj_name.lstrip('*'), search_object='object' in self.switches)
else: else:
obj = caller.search(obj_name) obj = caller.search(obj_name)
if not obj: if not obj:
continue continue
if not obj.access(caller, 'examine'): if not obj.access(caller, 'examine'):
#If we don't have special info access, just look # If we don't have special info access, just look
# at the object instead. # at the object instead.
self.msg(caller.at_look(obj)) self.msg(caller.at_look(obj))
continue continue
@ -2184,7 +2187,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
elif not low <= int(result[0].id) <= high: elif not low <= int(result[0].id) <= high:
string += "\n |RNo match found for '%s' in #dbref interval.|n" % (searchstring) string += "\n |RNo match found for '%s' in #dbref interval.|n" % (searchstring)
else: else:
result=result[0] result = result[0]
string += "\n|g %s - %s|n" % (result.get_display_name(caller), result.path) string += "\n|g %s - %s|n" % (result.get_display_name(caller), result.path)
else: else:
# Not an account/dbref search but a wider search; build a queryset. # Not an account/dbref search but a wider search; build a queryset.
@ -2192,7 +2195,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS):
if "exact" in switches: if "exact" in switches:
keyquery = Q(db_key__iexact=searchstring, id__gte=low, id__lte=high) keyquery = Q(db_key__iexact=searchstring, id__gte=low, id__lte=high)
aliasquery = Q(db_tags__db_key__iexact=searchstring, aliasquery = Q(db_tags__db_key__iexact=searchstring,
db_tags__db_tagtype__iexact="alias",id__gte=low, id__lte=high) db_tags__db_tagtype__iexact="alias", id__gte=low, id__lte=high)
else: else:
keyquery = Q(db_key__istartswith=searchstring, id__gte=low, id__lte=high) keyquery = Q(db_key__istartswith=searchstring, id__gte=low, id__lte=high)
aliasquery = Q(db_tags__db_key__istartswith=searchstring, aliasquery = Q(db_tags__db_key__istartswith=searchstring,
@ -2283,14 +2286,14 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS):
if obj_to_teleport.has_account: if obj_to_teleport.has_account:
caller.msg("Cannot teleport a puppeted object " caller.msg("Cannot teleport a puppeted object "
"(%s, puppeted by %s) to a None-location." % ( "(%s, puppeted by %s) to a None-location." % (
obj_to_teleport.key, obj_to_teleport.account)) obj_to_teleport.key, obj_to_teleport.account))
return return
caller.msg("Teleported %s -> None-location." % obj_to_teleport) caller.msg("Teleported %s -> None-location." % obj_to_teleport)
if obj_to_teleport.location and not tel_quietly: if obj_to_teleport.location and not tel_quietly:
obj_to_teleport.location.msg_contents("%s teleported %s into nothingness." obj_to_teleport.location.msg_contents("%s teleported %s into nothingness."
% (caller, obj_to_teleport), % (caller, obj_to_teleport),
exclude=caller) exclude=caller)
obj_to_teleport.location=None obj_to_teleport.location = None
return return
# not teleporting to None location # not teleporting to None location
@ -2397,7 +2400,7 @@ class CmdScript(COMMAND_DEFAULT_CLASS):
obj.get_display_name(caller))) obj.get_display_name(caller)))
script.stop() script.stop()
obj.scripts.validate() obj.scripts.validate()
else: # rhs exists else: # rhs exists
if not self.switches: if not self.switches:
# adding a new script, and starting it # adding a new script, and starting it
ok = obj.scripts.add(self.rhs, autostart=True) ok = obj.scripts.add(self.rhs, autostart=True)
@ -2478,16 +2481,16 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
nobjs = len(objs) nobjs = len(objs)
if nobjs > 0: if nobjs > 0:
catstr = " (category: '|w%s|n')" % category if category else \ catstr = " (category: '|w%s|n')" % category if category else \
("" if nobjs == 1 else " (may have different tag categories)") ("" if nobjs == 1 else " (may have different tag categories)")
matchstr = ", ".join(o.get_display_name(self.caller) for o in objs) matchstr = ", ".join(o.get_display_name(self.caller) for o in objs)
string = "Found |w%i|n object%s with tag '|w%s|n'%s:\n %s" % (nobjs, string = "Found |w%i|n object%s with tag '|w%s|n'%s:\n %s" % (nobjs,
"s" if nobjs > 1 else "", "s" if nobjs > 1 else "",
tag, tag,
catstr, matchstr) catstr, matchstr)
else: else:
string = "No objects found with tag '%s%s'." % (tag, string = "No objects found with tag '%s%s'." % (tag,
" (category: %s)" % category if category else "") " (category: %s)" % category if category else "")
self.caller.msg(string) self.caller.msg(string)
return return
if "del" in self.switches: if "del" in self.switches:
@ -2504,14 +2507,14 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
if obj.tags.get(tag, category=category): if obj.tags.get(tag, category=category):
obj.tags.remove(tag, category=category) obj.tags.remove(tag, category=category)
string = "Removed tag '%s'%s from %s." % ( string = "Removed tag '%s'%s from %s." % (
tag, tag,
" (category: %s)" % category if category else "", " (category: %s)" % category if category else "",
obj) obj)
else: else:
string = "No tag '%s'%s to delete on %s." % ( string = "No tag '%s'%s to delete on %s." % (
tag, tag,
" (category: %s)" % category if category else "", " (category: %s)" % category if category else "",
obj) obj)
else: else:
# no tag specified, clear all tags # no tag specified, clear all tags
old_tags = ["%s%s" % (tag, " (category: %s" % category if category else "") old_tags = ["%s%s" % (tag, " (category: %s" % category if category else "")
@ -2550,7 +2553,7 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
categories = [" (category: %s)" % tup[1] if tup[1] else "" for tup in tagtuples] categories = [" (category: %s)" % tup[1] if tup[1] else "" for tup in tagtuples]
if ntags: if ntags:
string = "Tag%s on %s: %s" % ("s" if ntags > 1 else "", obj, string = "Tag%s on %s: %s" % ("s" if ntags > 1 else "", obj,
", ".join("'%s'%s" % (tags[i], categories[i]) for i in range(ntags))) ", ".join("'%s'%s" % (tags[i], categories[i]) for i in range(ntags)))
else: else:
string = "No tags attached to %s." % obj string = "No tags attached to %s." % obj
self.caller.msg(string) self.caller.msg(string)
@ -2561,6 +2564,7 @@ class CmdTag(COMMAND_DEFAULT_CLASS):
# Reload the server and the prototypes should be available. # Reload the server and the prototypes should be available.
# #
class CmdSpawn(COMMAND_DEFAULT_CLASS): class CmdSpawn(COMMAND_DEFAULT_CLASS):
""" """
spawn objects from prototype spawn objects from prototype
@ -2608,7 +2612,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
"Helper to show a list of available prototypes" "Helper to show a list of available prototypes"
prots = ", ".join(sorted(prototypes.keys())) prots = ", ".join(sorted(prototypes.keys()))
return "\nAvailable prototypes (case sensistive): %s" % \ return "\nAvailable prototypes (case sensistive): %s" % \
("\n" + utils.fill(prots) if prots else "None") ("\n" + utils.fill(prots) if prots else "None")
prototypes = spawn(return_prototypes=True) prototypes = spawn(return_prototypes=True)
if not self.args: if not self.args:
@ -2628,7 +2632,6 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
self.caller.msg(string) self.caller.msg(string)
return return
if isinstance(prototype, basestring): if isinstance(prototype, basestring):
# A prototype key # A prototype key
keystr = prototype keystr = prototype
@ -2647,9 +2650,8 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS):
self.caller.msg("The prototype must be a prototype key or a Python dictionary.") self.caller.msg("The prototype must be a prototype key or a Python dictionary.")
return return
if not "noloc" in self.switches and not "location" in prototype: if "noloc" in self.switches and not "location" not in prototype:
prototype["location"] = self.caller.location prototype["location"] = self.caller.location
for obj in spawn(prototype): for obj in spawn(prototype):
self.caller.msg("Spawned %s." % obj.get_display_name(self.caller)) self.caller.msg("Spawned %s." % obj.get_display_name(self.caller))

View file

@ -31,7 +31,7 @@ class AccountCmdSet(CmdSet):
self.add(account.CmdOOC()) self.add(account.CmdOOC())
self.add(account.CmdCharCreate()) self.add(account.CmdCharCreate())
self.add(account.CmdCharDelete()) self.add(account.CmdCharDelete())
#self.add(account.CmdSessions()) # self.add(account.CmdSessions())
self.add(account.CmdWho()) self.add(account.CmdWho())
self.add(account.CmdOption()) self.add(account.CmdOption())
self.add(account.CmdQuit()) self.add(account.CmdQuit())

View file

@ -9,6 +9,7 @@ from evennia.commands.default import general, help, admin, system
from evennia.commands.default import building from evennia.commands.default import building
from evennia.commands.default import batchprocess from evennia.commands.default import batchprocess
class CharacterCmdSet(CmdSet): class CharacterCmdSet(CmdSet):
""" """
Implements the default command set. Implements the default command set.
@ -46,7 +47,7 @@ class CharacterCmdSet(CmdSet):
self.add(system.CmdAbout()) self.add(system.CmdAbout())
self.add(system.CmdTime()) self.add(system.CmdTime())
self.add(system.CmdServerLoad()) self.add(system.CmdServerLoad())
#self.add(system.CmdPs()) # self.add(system.CmdPs())
self.add(system.CmdTickers()) self.add(system.CmdTickers())
# Admin commands # Admin commands

View file

@ -4,6 +4,7 @@ This module stores session-level commands.
from evennia.commands.cmdset import CmdSet from evennia.commands.cmdset import CmdSet
from evennia.commands.default import account from evennia.commands.default import account
class SessionCmdSet(CmdSet): class SessionCmdSet(CmdSet):
""" """
Sets up the unlogged cmdset. Sets up the unlogged cmdset.

View file

@ -297,7 +297,7 @@ class CmdChannels(COMMAND_DEFAULT_CLASS):
clower = chan.key.lower() clower = chan.key.lower()
nicks = caller.nicks.get(category="channel", return_obj=True) nicks = caller.nicks.get(category="channel", return_obj=True)
comtable.add_row(*["%s%s" % (chan.key, chan.aliases.all() and comtable.add_row(*["%s%s" % (chan.key, chan.aliases.all() and
"(%s)" % ",".join(chan.aliases.all()) or ""), "(%s)" % ",".join(chan.aliases.all()) or ""),
"%s" % ",".join(nick.db_key for nick in make_iter(nicks) "%s" % ",".join(nick.db_key for nick in make_iter(nicks)
if nick and nick.value[3].lower() == clower), if nick and nick.value[3].lower() == clower),
chan.db.desc]) chan.db.desc])
@ -614,7 +614,7 @@ class CmdClock(COMMAND_DEFAULT_CLASS):
# Try to add the lock # Try to add the lock
try: try:
channel.locks.add(self.rhs) channel.locks.add(self.rhs)
except LockException, err: except LockException as err:
self.msg(err) self.msg(err)
return return
string = "Lock(s) applied. " string = "Lock(s) applied. "
@ -890,7 +890,7 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS):
self.rhs = self.rhs.replace('#', ' ') # to avoid Python comment issues self.rhs = self.rhs.replace('#', ' ') # to avoid Python comment issues
try: try:
irc_network, irc_port, irc_channel, irc_botname = \ irc_network, irc_port, irc_channel, irc_botname = \
[part.strip() for part in self.rhs.split(None, 4)] [part.strip() for part in self.rhs.split(None, 4)]
irc_channel = "#%s" % irc_channel irc_channel = "#%s" % irc_channel
except Exception: except Exception:
string = "IRC bot definition '%s' is not valid." % self.rhs string = "IRC bot definition '%s' is not valid." % self.rhs

View file

@ -170,7 +170,7 @@ class CmdNick(COMMAND_DEFAULT_CLASS):
# we are given a index in nicklist # we are given a index in nicklist
delindex = int(arg) delindex = int(arg)
if 0 < delindex <= len(nicklist): if 0 < delindex <= len(nicklist):
oldnick = nicklist[delindex-1] oldnick = nicklist[delindex - 1]
_, _, old_nickstring, old_replstring = oldnick.value _, _, old_nickstring, old_replstring = oldnick.value
else: else:
errstring += "Not a valid nick index." errstring += "Not a valid nick index."
@ -419,6 +419,7 @@ class CmdSay(COMMAND_DEFAULT_CLASS):
# Call the at_after_say hook on the character # Call the at_after_say hook on the character
caller.at_say(speech) caller.at_say(speech)
class CmdWhisper(COMMAND_DEFAULT_CLASS): class CmdWhisper(COMMAND_DEFAULT_CLASS):
""" """
Speak privately as your character to another Speak privately as your character to another

View file

@ -22,6 +22,7 @@ class MuxCommand(Command):
used by Evennia to create the automatic help entry for used by Evennia to create the automatic help entry for
the command, so make sure to document consistently here. the command, so make sure to document consistently here.
""" """
def has_perm(self, srcobj): def has_perm(self, srcobj):
""" """
This is called by the cmdhandler to determine This is called by the cmdhandler to determine
@ -191,6 +192,7 @@ class MuxAccountCommand(MuxCommand):
creating a new property "character" that is set only if a creating a new property "character" that is set only if a
character is actually attached to this Account and Session. character is actually attached to this Account and Session.
""" """
def parse(self): def parse(self):
""" """
We run the parent parser as usual, then fix the result We run the parent parser as usual, then fix the result

View file

@ -133,11 +133,11 @@ def _py_code(caller, buf):
""" """
measure_time = caller.db._py_measure_time measure_time = caller.db._py_measure_time
string = "Executing code%s ..." % ( string = "Executing code%s ..." % (
" (measure timing)" if measure_time else "") " (measure timing)" if measure_time else "")
caller.msg(string) caller.msg(string)
_run_code_snippet(caller, buf, mode="exec", _run_code_snippet(caller, buf, mode="exec",
measure_time=measure_time, measure_time=measure_time,
show_input=False) show_input=False)
return True return True
@ -147,7 +147,7 @@ def _py_quit(caller):
def _run_code_snippet(caller, pycode, mode="eval", measure_time=False, def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
show_input=True): show_input=True):
""" """
Run code and try to display information to the caller. Run code and try to display information to the caller.
@ -166,18 +166,18 @@ def _run_code_snippet(caller, pycode, mode="eval", measure_time=False,
# import useful variables # import useful variables
import evennia import evennia
available_vars = { available_vars = {
'self': caller, 'self': caller,
'me': caller, 'me': caller,
'here': getattr(caller, "location", None), 'here': getattr(caller, "location", None),
'evennia': evennia, 'evennia': evennia,
'ev': evennia, 'ev': evennia,
'inherits_from': utils.inherits_from, 'inherits_from': utils.inherits_from,
} }
if show_input: if show_input:
try: try:
caller.msg(">>> %s" % pycode, session=session, caller.msg(">>> %s" % pycode, session=session,
options={"raw": True}) options={"raw": True})
except TypeError: except TypeError:
caller.msg(">>> %s" % pycode, options={"raw": True}) caller.msg(">>> %s" % pycode, options={"raw": True})
@ -256,8 +256,8 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
if "edit" in self.switches: if "edit" in self.switches:
caller.db._py_measure_time = "time" in self.switches caller.db._py_measure_time = "time" in self.switches
EvEditor(self.caller, loadfunc=_py_load, savefunc=_py_code, EvEditor(self.caller, loadfunc=_py_load, savefunc=_py_code,
quitfunc=_py_quit, key="Python exec: :w or :!", persistent=True, quitfunc=_py_quit, key="Python exec: :w or :!", persistent=True,
codefunc=_py_code) codefunc=_py_code)
return return
if not pycode: if not pycode:
@ -719,7 +719,7 @@ class CmdServerLoad(COMMAND_DEFAULT_CLASS):
now, _ = _IDMAPPER.cache_size() now, _ = _IDMAPPER.cache_size()
string = "The Idmapper cache freed |w{idmapper}|n database objects.\n" \ string = "The Idmapper cache freed |w{idmapper}|n database objects.\n" \
"The Python garbage collector freed |w{gc}|n Python instances total." "The Python garbage collector freed |w{gc}|n Python instances total."
self.caller.msg(string.format(idmapper=(prev-now), gc=nflushed)) self.caller.msg(string.format(idmapper=(prev - now), gc=nflushed))
return return
# display active processes # display active processes

View file

@ -59,7 +59,7 @@ class CommandTest(EvenniaTest):
cmdobj.caller = caller cmdobj.caller = caller
cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key
cmdobj.raw_cmdname = cmdobj.cmdname cmdobj.raw_cmdname = cmdobj.cmdname
cmdobj.cmdstring = cmdobj.cmdname # deprecated cmdobj.cmdstring = cmdobj.cmdname # deprecated
cmdobj.args = args cmdobj.args = args
cmdobj.cmdset = cmdset cmdobj.cmdset = cmdset
cmdobj.session = SESSIONS.session_from_sessid(1) cmdobj.session = SESSIONS.session_from_sessid(1)
@ -79,17 +79,17 @@ class CommandTest(EvenniaTest):
pass pass
finally: finally:
# clean out evtable sugar. We only operate on text-type # clean out evtable sugar. We only operate on text-type
stored_msg = [args[0] if args and args[0] else kwargs.get("text",utils.to_str(kwargs, force_string=True)) 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 receiver.msg.mock_calls] for name, args, kwargs in receiver.msg.mock_calls]
# Get the first element of a tuple if msg received a tuple instead of a string # 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] stored_msg = [smsg[0] if isinstance(smsg, tuple) else smsg for smsg in stored_msg]
if msg is not None: if msg is not None:
returned_msg = "||".join(_RE.sub("", mess) for mess in stored_msg) returned_msg = "||".join(_RE.sub("", mess) for mess in stored_msg)
returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() returned_msg = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip()
if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()): if msg == "" and returned_msg or not returned_msg.startswith(msg.strip()):
sep1 = "\n" + "="*30 + "Wanted message" + "="*34 + "\n" sep1 = "\n" + "=" * 30 + "Wanted message" + "=" * 34 + "\n"
sep2 = "\n" + "="*30 + "Returned message" + "="*32 + "\n" sep2 = "\n" + "=" * 30 + "Returned message" + "=" * 32 + "\n"
sep3 = "\n" + "="*78 sep3 = "\n" + "=" * 78
retval = sep1 + msg.strip() + sep2 + returned_msg + sep3 retval = sep1 + msg.strip() + sep2 + returned_msg + sep3
raise AssertionError(retval) raise AssertionError(retval)
else: else:
@ -271,7 +271,7 @@ class TestBuilding(CommandTest):
def test_typeclass(self): def test_typeclass(self):
self.call(building.CmdTypeclass(), "Obj = evennia.objects.objects.DefaultExit", self.call(building.CmdTypeclass(), "Obj = evennia.objects.objects.DefaultExit",
"Obj changed typeclass from evennia.objects.objects.DefaultObject to evennia.objects.objects.DefaultExit.") "Obj changed typeclass from evennia.objects.objects.DefaultObject to evennia.objects.objects.DefaultExit.")
def test_lock(self): def test_lock(self):
self.call(building.CmdLock(), "Obj = test:perm(Developer)", "Added lock 'test:perm(Developer)' to Obj.") self.call(building.CmdLock(), "Obj = test:perm(Developer)", "Added lock 'test:perm(Developer)' to Obj.")
@ -294,10 +294,10 @@ class TestComms(CommandTest):
def test_toggle_com(self): def test_toggle_com(self):
self.call(comms.CmdAddCom(), "tc = testchan", "You are already connected to channel testchan. You can now", receiver=self.account) self.call(comms.CmdAddCom(), "tc = testchan", "You are already connected to channel testchan. You can now", receiver=self.account)
self.call(comms.CmdDelCom(), "tc", "Your alias 'tc' for channel testchan was cleared.", receiver=self.account) self.call(comms.CmdDelCom(), "tc", "Your alias 'tc' for channel testchan was cleared.", receiver=self.account)
def test_channels(self): def test_channels(self):
self.call(comms.CmdChannels(), "" ,"Available channels (use comlist,addcom and delcom to manage", receiver=self.account) self.call(comms.CmdChannels(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
def test_all_com(self): def test_all_com(self):
self.call(comms.CmdAllCom(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.account) self.call(comms.CmdAllCom(), "", "Available channels (use comlist,addcom and delcom to manage", receiver=self.account)
@ -322,7 +322,7 @@ class TestComms(CommandTest):
self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] <channel> = <account> [:reason]", receiver=self.account) self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] <channel> = <account> [:reason]", receiver=self.account)
def test_cdestroy(self): def test_cdestroy(self):
self.call(comms.CmdCdestroy(), "testchan" ,"[testchan] TestAccount: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.", receiver=self.account) self.call(comms.CmdCdestroy(), "testchan", "[testchan] TestAccount: testchan is being destroyed. Make sure to change your aliases.|Channel 'testchan' was destroyed.", receiver=self.account)
class TestBatchProcess(CommandTest): class TestBatchProcess(CommandTest):
@ -332,6 +332,7 @@ class TestBatchProcess(CommandTest):
# we make sure to delete the button again here to stop the running reactor # we make sure to delete the button again here to stop the running reactor
self.call(building.CmdDestroy(), "button", "button was destroyed.") self.call(building.CmdDestroy(), "button", "button was destroyed.")
class CmdInterrupt(Command): class CmdInterrupt(Command):
key = "interrupt" key = "interrupt"

View file

@ -147,7 +147,7 @@ def create_normal_account(session, name, password):
account (Account): the account which was created from the name and password. account (Account): the account which was created from the name and password.
""" """
# check for too many login errors too quick. # check for too many login errors too quick.
if _throttle(session, maxlim=5, timeout=5*60): if _throttle(session, maxlim=5, timeout=5 * 60):
# timeout is 5 minutes. # timeout is 5 minutes.
session.msg("|RYou made too many connection attempts. Try again in a few minutes.|n") session.msg("|RYou made too many connection attempts. Try again in a few minutes.|n")
return None return None
@ -168,8 +168,8 @@ def create_normal_account(session, name, password):
# Check IP and/or name bans # Check IP and/or name bans
bans = ServerConfig.objects.conf("server_bans") bans = ServerConfig.objects.conf("server_bans")
if bans and (any(tup[0] == account.name.lower() for tup in bans) if bans and (any(tup[0] == account.name.lower() for tup in bans) or
or
any(tup[2].match(session.address) for tup in bans if tup[2])): any(tup[2].match(session.address) for tup in bans if tup[2])):
# this is a banned IP or name! # this is a banned IP or name!
string = "|rYou have been banned and cannot continue from here." \ string = "|rYou have been banned and cannot continue from here." \
@ -209,7 +209,7 @@ class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS):
session = self.caller session = self.caller
# check for too many login errors too quick. # check for too many login errors too quick.
if _throttle(session, maxlim=5, timeout=5*60, storage=_LATEST_FAILED_LOGINS): if _throttle(session, maxlim=5, timeout=5 * 60, storage=_LATEST_FAILED_LOGINS):
# timeout is 5 minutes. # timeout is 5 minutes.
session.msg("|RYou made too many connection attempts. Try again in a few minutes.|n") session.msg("|RYou made too many connection attempts. Try again in a few minutes.|n")
return return
@ -301,8 +301,8 @@ class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS):
# Check IP and/or name bans # Check IP and/or name bans
bans = ServerConfig.objects.conf("server_bans") bans = ServerConfig.objects.conf("server_bans")
if bans and (any(tup[0] == accountname.lower() for tup in bans) if bans and (any(tup[0] == accountname.lower() for tup in bans) or
or
any(tup[2].match(session.address) for tup in bans if tup[2])): any(tup[2].match(session.address) for tup in bans if tup[2])):
# this is a banned IP or name! # this is a banned IP or name!
string = "|rYou have been banned and cannot continue from here." \ string = "|rYou have been banned and cannot continue from here." \

View file

@ -12,46 +12,67 @@ from evennia.commands.command import Command
class _CmdA(Command): class _CmdA(Command):
key = "A" key = "A"
def __init__(self, cmdset, *args, **kwargs): def __init__(self, cmdset, *args, **kwargs):
super(_CmdA, self).__init__(*args, **kwargs) super(_CmdA, self).__init__(*args, **kwargs)
self.from_cmdset = cmdset self.from_cmdset = cmdset
class _CmdB(Command): class _CmdB(Command):
key = "B" key = "B"
def __init__(self, cmdset, *args, **kwargs): def __init__(self, cmdset, *args, **kwargs):
super(_CmdB, self).__init__(*args, **kwargs) super(_CmdB, self).__init__(*args, **kwargs)
self.from_cmdset = cmdset self.from_cmdset = cmdset
class _CmdC(Command): class _CmdC(Command):
key = "C" key = "C"
def __init__(self, cmdset, *args, **kwargs): def __init__(self, cmdset, *args, **kwargs):
super(_CmdC, self).__init__(*args, **kwargs) super(_CmdC, self).__init__(*args, **kwargs)
self.from_cmdset = cmdset self.from_cmdset = cmdset
class _CmdD(Command): class _CmdD(Command):
key = "D" key = "D"
def __init__(self, cmdset, *args, **kwargs): def __init__(self, cmdset, *args, **kwargs):
super(_CmdD, self).__init__(*args, **kwargs) super(_CmdD, self).__init__(*args, **kwargs)
self.from_cmdset = cmdset self.from_cmdset = cmdset
class _CmdSetA(CmdSet): class _CmdSetA(CmdSet):
key = "A" key = "A"
def at_cmdset_creation(self):
def at_cmdset_creation(self):
self.add(_CmdA("A")) self.add(_CmdA("A"))
self.add(_CmdB("A")) self.add(_CmdB("A"))
self.add(_CmdC("A")) self.add(_CmdC("A"))
self.add(_CmdD("A")) self.add(_CmdD("A"))
class _CmdSetB(CmdSet): class _CmdSetB(CmdSet):
key = "B" key = "B"
def at_cmdset_creation(self):
def at_cmdset_creation(self):
self.add(_CmdA("B")) self.add(_CmdA("B"))
self.add(_CmdB("B")) self.add(_CmdB("B"))
self.add(_CmdC("B")) self.add(_CmdC("B"))
class _CmdSetC(CmdSet): class _CmdSetC(CmdSet):
key = "C" key = "C"
def at_cmdset_creation(self):
def at_cmdset_creation(self):
self.add(_CmdA("C")) self.add(_CmdA("C"))
self.add(_CmdB("C")) self.add(_CmdB("C"))
class _CmdSetD(CmdSet): class _CmdSetD(CmdSet):
key = "D" key = "D"
def at_cmdset_creation(self):
def at_cmdset_creation(self):
self.add(_CmdA("D")) self.add(_CmdA("D"))
self.add(_CmdB("D")) self.add(_CmdB("D"))
self.add(_CmdC("D")) self.add(_CmdC("D"))
@ -59,8 +80,10 @@ class _CmdSetD(CmdSet):
# testing Command Sets # testing Command Sets
class TestCmdSetMergers(TestCase): class TestCmdSetMergers(TestCase):
"Test merging of cmdsets" "Test merging of cmdsets"
def setUp(self): def setUp(self):
super(TestCmdSetMergers, self).setUp() super(TestCmdSetMergers, self).setUp()
self.cmdset_a = _CmdSetA() self.cmdset_a = _CmdSetA()
@ -70,16 +93,16 @@ class TestCmdSetMergers(TestCase):
def test_union(self): def test_union(self):
a, c = self.cmdset_a, self.cmdset_c a, c = self.cmdset_a, self.cmdset_c
cmdset_f = a + c # same-prio cmdset_f = a + c # same-prio
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2)
cmdset_f = c + a # same-prio, inverse order cmdset_f = c + a # same-prio, inverse order
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
a.priority = 1 a.priority = 1
cmdset_f = a + c # high prio A cmdset_f = a + c # high prio A
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
@ -87,16 +110,16 @@ class TestCmdSetMergers(TestCase):
def test_intersect(self): def test_intersect(self):
a, c = self.cmdset_a, self.cmdset_c a, c = self.cmdset_a, self.cmdset_c
a.mergetype = "Intersect" a.mergetype = "Intersect"
cmdset_f = a + c # same-prio - c's Union kicks in cmdset_f = a + c # same-prio - c's Union kicks in
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2)
cmdset_f = c + a # same-prio - a's Intersect kicks in cmdset_f = c + a # same-prio - a's Intersect kicks in
self.assertEqual(len(cmdset_f.commands), 2) self.assertEqual(len(cmdset_f.commands), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
a.priority = 1 a.priority = 1
cmdset_f = a + c # high prio A, intersect kicks in cmdset_f = a + c # high prio A, intersect kicks in
self.assertEqual(len(cmdset_f.commands), 2) self.assertEqual(len(cmdset_f.commands), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
@ -104,16 +127,16 @@ class TestCmdSetMergers(TestCase):
def test_replace(self): def test_replace(self):
a, c = self.cmdset_a, self.cmdset_c a, c = self.cmdset_a, self.cmdset_c
c.mergetype = "Replace" c.mergetype = "Replace"
cmdset_f = a + c # same-prio. C's Replace kicks in cmdset_f = a + c # same-prio. C's Replace kicks in
self.assertEqual(len(cmdset_f.commands), 2) self.assertEqual(len(cmdset_f.commands), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2)
cmdset_f = c + a # same-prio. A's Union kicks in cmdset_f = c + a # same-prio. A's Union kicks in
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
c.priority = 1 c.priority = 1
cmdset_f = c + a # c higher prio. C's Replace kicks in cmdset_f = c + a # c higher prio. C's Replace kicks in
self.assertEqual(len(cmdset_f.commands), 2) self.assertEqual(len(cmdset_f.commands), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 0)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 2)
@ -121,16 +144,16 @@ class TestCmdSetMergers(TestCase):
def test_remove(self): def test_remove(self):
a, c = self.cmdset_a, self.cmdset_c a, c = self.cmdset_a, self.cmdset_c
c.mergetype = "Remove" c.mergetype = "Remove"
cmdset_f = a + c # same-prio. C's Remove kicks in cmdset_f = a + c # same-prio. C's Remove kicks in
self.assertEqual(len(cmdset_f.commands), 2) self.assertEqual(len(cmdset_f.commands), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
cmdset_f = c + a # same-prio. A's Union kicks in cmdset_f = c + a # same-prio. A's Union kicks in
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 4)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
c.priority = 1 c.priority = 1
cmdset_f = c + a # c higher prio. C's Remove kicks in cmdset_f = c + a # c higher prio. C's Remove kicks in
self.assertEqual(len(cmdset_f.commands), 2) self.assertEqual(len(cmdset_f.commands), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "A"), 2)
self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0) self.assertEqual(sum(1 for cmd in cmdset_f.commands if cmd.from_cmdset == "C"), 0)
@ -138,15 +161,15 @@ class TestCmdSetMergers(TestCase):
def test_order(self): def test_order(self):
"Merge in reverse- and forward orders, same priorities" "Merge in reverse- and forward orders, same priorities"
a, b, c, d = self.cmdset_a, self.cmdset_b, self.cmdset_c, self.cmdset_d a, b, c, d = self.cmdset_a, self.cmdset_b, self.cmdset_c, self.cmdset_d
cmdset_f = d + c + b + a # merge in reverse order of priority cmdset_f = d + c + b + a # merge in reverse order of priority
self.assertEqual(cmdset_f.priority, 0) self.assertEqual(cmdset_f.priority, 0)
self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(cmdset_f.mergetype, "Union")
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A")) self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A"))
cmdset_f = a + b + c + d # merge in order of priority cmdset_f = a + b + c + d # merge in order of priority
self.assertEqual(cmdset_f.priority, 0) self.assertEqual(cmdset_f.priority, 0)
self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(cmdset_f.mergetype, "Union")
self.assertEqual(len(cmdset_f.commands), 4) # duplicates setting from A transfers self.assertEqual(len(cmdset_f.commands), 4) # duplicates setting from A transfers
self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "D")) self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "D"))
def test_priority_order(self): def test_priority_order(self):
@ -156,12 +179,12 @@ class TestCmdSetMergers(TestCase):
b.priority = 1 b.priority = 1
c.priority = 0 c.priority = 0
d.priority = -1 d.priority = -1
cmdset_f = d + c + b + a # merge in reverse order of priority cmdset_f = d + c + b + a # merge in reverse order of priority
self.assertEqual(cmdset_f.priority, 2) self.assertEqual(cmdset_f.priority, 2)
self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(cmdset_f.mergetype, "Union")
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A")) self.assertTrue(all(True for cmd in cmdset_f.commands if cmd.from_cmdset == "A"))
cmdset_f = a + b + c + d # merge in order of priority cmdset_f = a + b + c + d # merge in order of priority
self.assertEqual(cmdset_f.priority, 2) self.assertEqual(cmdset_f.priority, 2)
self.assertEqual(cmdset_f.mergetype, "Union") self.assertEqual(cmdset_f.mergetype, "Union")
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
@ -176,13 +199,13 @@ class TestCmdSetMergers(TestCase):
a.no_objs = True a.no_objs = True
a.no_channels = True a.no_channels = True
a.duplicates = True a.duplicates = True
cmdset_f = d + c + b + a # reverse, same-prio cmdset_f = d + c + b + a # reverse, same-prio
self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_exits)
self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
self.assertTrue(cmdset_f.duplicates) self.assertTrue(cmdset_f.duplicates)
self.assertEqual(len(cmdset_f.commands), 8) self.assertEqual(len(cmdset_f.commands), 8)
cmdset_f = a + b + c + d # forward, same-prio cmdset_f = a + b + c + d # forward, same-prio
self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_exits)
self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
@ -192,13 +215,13 @@ class TestCmdSetMergers(TestCase):
b.priority = 1 b.priority = 1
c.priority = 0 c.priority = 0
d.priority = -1 d.priority = -1
cmdset_f = d + c + b + a # reverse, A top priority cmdset_f = d + c + b + a # reverse, A top priority
self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_exits)
self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
self.assertTrue(cmdset_f.duplicates) self.assertTrue(cmdset_f.duplicates)
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
cmdset_f = a + b + c + d # forward, A top priority. This never happens in practice. cmdset_f = a + b + c + d # forward, A top priority. This never happens in practice.
self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_exits)
self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
@ -208,13 +231,13 @@ class TestCmdSetMergers(TestCase):
b.priority = 0 b.priority = 0
c.priority = 1 c.priority = 1
d.priority = 2 d.priority = 2
cmdset_f = d + c + b + a # reverse, A low prio. This never happens in practice. cmdset_f = d + c + b + a # reverse, A low prio. This never happens in practice.
self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_exits)
self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
self.assertFalse(cmdset_f.duplicates) self.assertFalse(cmdset_f.duplicates)
self.assertEqual(len(cmdset_f.commands), 4) self.assertEqual(len(cmdset_f.commands), 4)
cmdset_f = a + b + c + d # forward, A low prio cmdset_f = a + b + c + d # forward, A low prio
self.assertTrue(cmdset_f.no_exits) self.assertTrue(cmdset_f.no_exits)
self.assertTrue(cmdset_f.no_objs) self.assertTrue(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
@ -224,7 +247,7 @@ class TestCmdSetMergers(TestCase):
b.no_objs = False b.no_objs = False
d.duplicates = False d.duplicates = False
# higher-prio sets will change the option up the chain # higher-prio sets will change the option up the chain
cmdset_f = a + b + c + d # forward, A low prio cmdset_f = a + b + c + d # forward, A low prio
self.assertFalse(cmdset_f.no_exits) self.assertFalse(cmdset_f.no_exits)
self.assertFalse(cmdset_f.no_objs) self.assertFalse(cmdset_f.no_objs)
self.assertTrue(cmdset_f.no_channels) self.assertTrue(cmdset_f.no_channels)
@ -235,15 +258,19 @@ class TestCmdSetMergers(TestCase):
c.priority = 0 c.priority = 0
d.priority = 0 d.priority = 0
c.duplicates = True c.duplicates = True
cmdset_f = d + b + c + a # two last mergers duplicates=True cmdset_f = d + b + c + a # two last mergers duplicates=True
self.assertEqual(len(cmdset_f.commands), 10) self.assertEqual(len(cmdset_f.commands), 10)
# test cmdhandler functions # test cmdhandler functions
from evennia.commands import cmdhandler from evennia.commands import cmdhandler
from twisted.trial.unittest import TestCase as TwistedTestCase from twisted.trial.unittest import TestCase as TwistedTestCase
class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest): class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
"Test the cmdhandler.get_and_merge_cmdsets function." "Test the cmdhandler.get_and_merge_cmdsets function."
def setUp(self): def setUp(self):
super(TestGetAndMergeCmdSets, self).setUp() super(TestGetAndMergeCmdSets, self).setUp()
self.cmdset_a = _CmdSetA() self.cmdset_a = _CmdSetA()
@ -261,6 +288,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
a.no_channels = True a.no_channels = True
self.set_cmdsets(self.session, a) self.set_cmdsets(self.session, a)
deferred = cmdhandler.get_and_merge_cmdsets(self.session, self.session, None, None, "session", "") deferred = cmdhandler.get_and_merge_cmdsets(self.session, self.session, None, None, "session", "")
def _callback(cmdset): def _callback(cmdset):
self.assertEqual(cmdset.key, "A") self.assertEqual(cmdset.key, "A")
deferred.addCallback(_callback) deferred.addCallback(_callback)
@ -273,6 +301,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
self.set_cmdsets(self.account, a) self.set_cmdsets(self.account, a)
deferred = cmdhandler.get_and_merge_cmdsets(self.account, None, self.account, None, "account", "") deferred = cmdhandler.get_and_merge_cmdsets(self.account, None, self.account, None, "account", "")
# get_and_merge_cmdsets converts to lower-case internally. # get_and_merge_cmdsets converts to lower-case internally.
def _callback(cmdset): def _callback(cmdset):
pcmdset = AccountCmdSet() pcmdset = AccountCmdSet()
pcmdset.at_cmdset_creation() pcmdset.at_cmdset_creation()
@ -286,7 +315,8 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
self.set_cmdsets(self.obj1, self.cmdset_a) self.set_cmdsets(self.obj1, self.cmdset_a)
deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "") deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "")
# get_and_merge_cmdsets converts to lower-case internally. # get_and_merge_cmdsets converts to lower-case internally.
_callback = lambda cmdset: self.assertEqual(sum(1 for cmd in cmdset.commands if cmd.key in ("a", "b", "c", "d")), 4)
def _callback(cmdset): return self.assertEqual(sum(1 for cmd in cmdset.commands if cmd.key in ("a", "b", "c", "d")), 4)
deferred.addCallback(_callback) deferred.addCallback(_callback)
return deferred return deferred
@ -296,6 +326,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
a.no_channels = True a.no_channels = True
self.set_cmdsets(self.obj1, a, b, c, d) self.set_cmdsets(self.obj1, a, b, c, d)
deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "") deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "")
def _callback(cmdset): def _callback(cmdset):
self.assertTrue(cmdset.no_exits) self.assertTrue(cmdset.no_exits)
self.assertTrue(cmdset.no_channels) self.assertTrue(cmdset.no_channels)
@ -315,6 +346,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
a, b, c, d = self.cmdset_a, self.cmdset_b, self.cmdset_c, self.cmdset_d a, b, c, d = self.cmdset_a, self.cmdset_b, self.cmdset_c, self.cmdset_d
self.set_cmdsets(self.account, a, b, c, d) self.set_cmdsets(self.account, a, b, c, d)
deferred = cmdhandler.get_and_merge_cmdsets(self.session, self.session, self.account, self.char1, "session", "") deferred = cmdhandler.get_and_merge_cmdsets(self.session, self.session, self.account, self.char1, "session", "")
def _callback(cmdset): def _callback(cmdset):
pcmdset = AccountCmdSet() pcmdset = AccountCmdSet()
pcmdset.at_cmdset_creation() pcmdset.at_cmdset_creation()
@ -332,6 +364,7 @@ class TestGetAndMergeCmdSets(TwistedTestCase, EvenniaTest):
d.duplicates = True d.duplicates = True
self.set_cmdsets(self.obj1, a, b, c, d) self.set_cmdsets(self.obj1, a, b, c, d)
deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "") deferred = cmdhandler.get_and_merge_cmdsets(self.obj1, None, None, self.obj1, "object", "")
def _callback(cmdset): def _callback(cmdset):
self.assertEqual(len(cmdset.commands), 9) self.assertEqual(len(cmdset.commands), 9)
deferred.addCallback(_callback) deferred.addCallback(_callback)

View file

@ -59,7 +59,7 @@ class ChannelAdmin(admin.ModelAdmin):
list_select_related = True list_select_related = True
fieldsets = ( fieldsets = (
(None, {'fields': (('db_key',), 'db_lock_storage', 'db_subscriptions')}), (None, {'fields': (('db_key',), 'db_lock_storage', 'db_subscriptions')}),
) )
def subscriptions(self, obj): def subscriptions(self, obj):
""" """

View file

@ -34,6 +34,7 @@ from django.utils.translation import ugettext as _
_CHANNEL_COMMAND_CLASS = None _CHANNEL_COMMAND_CLASS = None
_CHANNELDB = None _CHANNELDB = None
class ChannelCommand(command.Command): class ChannelCommand(command.Command):
""" """
{channelkey} channel {channelkey} channel
@ -130,8 +131,9 @@ class ChannelCommand(command.Command):
if self.history_start is not None: if self.history_start is not None:
# Try to view history # Try to view history
log_file = channel.attributes.get("log_file", default="channel_%s.log" % channel.key) log_file = channel.attributes.get("log_file", default="channel_%s.log" % channel.key)
send_msg = lambda lines: self.msg("".join(line.split("[-]", 1)[1]
if "[-]" in line else line for line in lines)) def send_msg(lines): return self.msg("".join(line.split("[-]", 1)[1]
if "[-]" in line else line for line in lines))
tail_log_file(log_file, self.history_start, 20, callback=send_msg) tail_log_file(log_file, self.history_start, 20, callback=send_msg)
else: else:
caller = caller if not hasattr(caller, 'account') else caller.account caller = caller if not hasattr(caller, 'account') else caller.account
@ -164,6 +166,7 @@ class ChannelHandler(object):
evennia.create_channel()) evennia.create_channel())
""" """
def __init__(self): def __init__(self):
""" """
Initializes the channel handler's internal state. Initializes the channel handler's internal state.
@ -208,12 +211,12 @@ class ChannelHandler(object):
# map the channel to a searchable command # map the channel to a searchable command
cmd = _CHANNEL_COMMAND_CLASS( cmd = _CHANNEL_COMMAND_CLASS(
key=channel.key.strip().lower(), key=channel.key.strip().lower(),
aliases=channel.aliases.all(), aliases=channel.aliases.all(),
locks="cmd:all();%s" % channel.locks, locks="cmd:all();%s" % channel.locks,
help_category="Channel names", help_category="Channel names",
obj=channel, obj=channel,
is_channel=True) is_channel=True)
# format the help entry # format the help entry
key = channel.key key = channel.key
cmd.__doc__ = cmd.__doc__.format(channelkey=key, cmd.__doc__ = cmd.__doc__.format(channelkey=key,
@ -221,7 +224,7 @@ class ChannelHandler(object):
channeldesc=channel.attributes.get("desc", default="").strip()) channeldesc=channel.attributes.get("desc", default="").strip())
self.cached_channel_cmds[channel] = cmd self.cached_channel_cmds[channel] = cmd
self.cached_cmdsets = {} self.cached_cmdsets = {}
add_channel = add # legacy alias add_channel = add # legacy alias
def remove(self, channel): def remove(self, channel):
""" """
@ -269,8 +272,8 @@ class ChannelHandler(object):
# create a new cmdset holding all viable channels # create a new cmdset holding all viable channels
chan_cmdset = None chan_cmdset = None
chan_cmds = [channelcmd for channel, channelcmd in self.cached_channel_cmds.iteritems() chan_cmds = [channelcmd for channel, channelcmd in self.cached_channel_cmds.iteritems()
if channel.subscriptions.has(source_object) and if channel.subscriptions.has(source_object) and
channelcmd.access(source_object, 'send')] channelcmd.access(source_object, 'send')]
if chan_cmds: if chan_cmds:
chan_cmdset = cmdset.CmdSet() chan_cmdset = cmdset.CmdSet()
chan_cmdset.key = 'ChannelCmdSet' chan_cmdset.key = 'ChannelCmdSet'
@ -281,5 +284,6 @@ class ChannelHandler(object):
self.cached_cmdsets[source_object] = chan_cmdset self.cached_cmdsets[source_object] = chan_cmdset
return chan_cmdset return chan_cmdset
CHANNEL_HANDLER = ChannelHandler() CHANNEL_HANDLER = ChannelHandler()
CHANNELHANDLER = CHANNEL_HANDLER # legacy CHANNELHANDLER = CHANNEL_HANDLER # legacy

View file

@ -357,7 +357,6 @@ class DefaultChannel(with_metaclass(TypeclassBase, ChannelDB)):
# hooks # hooks
def channel_prefix(self, msg=None, emit=False, **kwargs): def channel_prefix(self, msg=None, emit=False, **kwargs):
""" """
Hook method. How the channel should prefix itself for users. Hook method. How the channel should prefix itself for users.

View file

@ -74,7 +74,7 @@ def identify_object(inp):
if clsname == "AccountDB": if clsname == "AccountDB":
return inp, "account" return inp, "account"
elif clsname == "ObjectDB": elif clsname == "ObjectDB":
return inp ,"object" return inp, "object"
elif clsname == "ChannelDB": elif clsname == "ChannelDB":
return inp, "channel" return inp, "channel"
if isinstance(inp, basestring): if isinstance(inp, basestring):
@ -202,10 +202,10 @@ class MsgManager(TypedObjectManager):
# explicitly exclude channel recipients # explicitly exclude channel recipients
if typ == 'account': if typ == 'account':
return list(self.filter(db_sender_accounts=obj, return list(self.filter(db_sender_accounts=obj,
db_receivers_channels__isnull=True).exclude(db_hide_from_accounts=obj)) db_receivers_channels__isnull=True).exclude(db_hide_from_accounts=obj))
elif typ == 'object': elif typ == 'object':
return list(self.filter(db_sender_objects=obj, return list(self.filter(db_sender_objects=obj,
db_receivers_channels__isnull=True).exclude(db_hide_from_objects=obj)) db_receivers_channels__isnull=True).exclude(db_hide_from_objects=obj))
else: else:
raise CommError raise CommError
else: else:
@ -332,6 +332,7 @@ class ChannelDBManager(TypedObjectManager):
subscribed to the Channel. subscribed to the Channel.
""" """
def get_all_channels(self): def get_all_channels(self):
""" """
Get all channels. Get all channels.

View file

@ -3,12 +3,14 @@ from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
def convert_defaults(apps, schema_editor): def convert_defaults(apps, schema_editor):
ChannelDB = apps.get_model("comms", "ChannelDB") ChannelDB = apps.get_model("comms", "ChannelDB")
for channel in ChannelDB.objects.filter(db_typeclass_path="src.comms.comms.Channel"): for channel in ChannelDB.objects.filter(db_typeclass_path="src.comms.comms.Channel"):
channel.db_typeclass_path = "typeclasses.channels.Channel" channel.db_typeclass_path = "typeclasses.channels.Channel"
channel.save() channel.save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -16,5 +18,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(convert_defaults), migrations.RunPython(convert_defaults),
] ]

View file

@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.db import migrations from django.db import migrations
def convert_channelnames(apps, schema_editor): def convert_channelnames(apps, schema_editor):
ChannelDB = apps.get_model("comms", "ChannelDB") ChannelDB = apps.get_model("comms", "ChannelDB")
for chan in ChannelDB.objects.filter(db_key="MUDinfo"): for chan in ChannelDB.objects.filter(db_key="MUDinfo"):
@ -13,6 +14,7 @@ def convert_channelnames(apps, schema_editor):
chan.db_key = "MudInfo" chan.db_key = "MudInfo"
chan.save() chan.save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -20,5 +22,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(convert_channelnames), migrations.RunPython(convert_channelnames),
] ]

View file

@ -26,41 +26,41 @@ class Migration(migrations.Migration):
db_cursor = connection.cursor() db_cursor = connection.cursor()
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='channeldb', model_name='channeldb',
name='db_account_subscriptions', name='db_account_subscriptions',
field=models.ManyToManyField(blank=True, db_index=True, related_name='account_subscription_set', to='accounts.AccountDB', verbose_name=b'account subscriptions'), field=models.ManyToManyField(blank=True, db_index=True, related_name='account_subscription_set', to='accounts.AccountDB', verbose_name=b'account subscriptions'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='channeldb', model_name='channeldb',
name='db_object_subscriptions', name='db_object_subscriptions',
field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'object subscriptions'), field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'object subscriptions'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='msg', model_name='msg',
name='db_receivers_scripts', name='db_receivers_scripts',
field=models.ManyToManyField(blank=True, help_text=b'script_receivers', related_name='receiver_script_set', to='scripts.ScriptDB'), field=models.ManyToManyField(blank=True, help_text=b'script_receivers', related_name='receiver_script_set', to='scripts.ScriptDB'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='msg', model_name='msg',
name='db_sender_scripts', name='db_sender_scripts',
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'), field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='channeldb', model_name='channeldb',
name='db_object_subscriptions', name='db_object_subscriptions',
field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'object subscriptions'), field=models.ManyToManyField(blank=True, db_index=True, related_name='object_subscription_set', to='objects.ObjectDB', verbose_name=b'object subscriptions'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='msg', model_name='msg',
name='db_receivers_scripts', name='db_receivers_scripts',
field=models.ManyToManyField(blank=True, help_text=b'script_receivers', related_name='receiver_script_set', to='scripts.ScriptDB'), field=models.ManyToManyField(blank=True, help_text=b'script_receivers', related_name='receiver_script_set', to='scripts.ScriptDB'),
), ),
migrations.AlterField( migrations.AlterField(
model_name='msg', model_name='msg',
name='db_sender_scripts', name='db_sender_scripts',
field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'), field=models.ManyToManyField(blank=True, db_index=True, related_name='sender_script_set', to='scripts.ScriptDB', verbose_name=b'sender(script)'),
), ),
] ]
if _table_exists(db_cursor, 'comms_msg_db_hide_from_players'): if _table_exists(db_cursor, 'comms_msg_db_hide_from_players'):

View file

@ -81,27 +81,27 @@ class Msg(SharedMemoryModel):
# an IRC channel; normally there is only one, but if co-modification of # an IRC channel; normally there is only one, but if co-modification of
# a message is allowed, there may be more than one "author" # a message is allowed, there may be more than one "author"
db_sender_accounts = models.ManyToManyField("accounts.AccountDB", related_name='sender_account_set', db_sender_accounts = models.ManyToManyField("accounts.AccountDB", related_name='sender_account_set',
blank=True, verbose_name='sender(account)', db_index=True) blank=True, verbose_name='sender(account)', db_index=True)
db_sender_objects = models.ManyToManyField("objects.ObjectDB", related_name='sender_object_set', db_sender_objects = models.ManyToManyField("objects.ObjectDB", related_name='sender_object_set',
blank=True, verbose_name='sender(object)', db_index=True) blank=True, verbose_name='sender(object)', db_index=True)
db_sender_scripts = models.ManyToManyField("scripts.ScriptDB", related_name='sender_script_set', db_sender_scripts = models.ManyToManyField("scripts.ScriptDB", related_name='sender_script_set',
blank=True, verbose_name='sender(script)', db_index=True) blank=True, verbose_name='sender(script)', db_index=True)
db_sender_external = models.CharField('external sender', max_length=255, null=True, blank=True, db_index=True, db_sender_external = models.CharField('external sender', max_length=255, null=True, blank=True, db_index=True,
help_text="identifier for external sender, for example a sender over an " help_text="identifier for external sender, for example a sender over an "
"IRC connection (i.e. someone who doesn't have an exixtence in-game).") "IRC connection (i.e. someone who doesn't have an exixtence in-game).")
# The destination objects of this message. Stored as a # The destination objects of this message. Stored as a
# comma-separated string of object dbrefs. Can be defined along # comma-separated string of object dbrefs. Can be defined along
# with channels below. # with channels below.
db_receivers_accounts = models.ManyToManyField('accounts.AccountDB', related_name='receiver_account_set', db_receivers_accounts = models.ManyToManyField('accounts.AccountDB', related_name='receiver_account_set',
blank=True, help_text="account receivers") blank=True, help_text="account receivers")
db_receivers_objects = models.ManyToManyField('objects.ObjectDB', related_name='receiver_object_set', db_receivers_objects = models.ManyToManyField('objects.ObjectDB', related_name='receiver_object_set',
blank=True, help_text="object receivers") blank=True, help_text="object receivers")
db_receivers_scripts = models.ManyToManyField('scripts.ScriptDB', related_name='receiver_script_set', db_receivers_scripts = models.ManyToManyField('scripts.ScriptDB', related_name='receiver_script_set',
blank=True, help_text="script_receivers") blank=True, help_text="script_receivers")
db_receivers_channels = models.ManyToManyField("ChannelDB", related_name='channel_set', db_receivers_channels = models.ManyToManyField("ChannelDB", related_name='channel_set',
blank=True, help_text="channel recievers") blank=True, help_text="channel recievers")
# header could be used for meta-info about the message if your system needs # header could be used for meta-info about the message if your system needs
# it, or as a separate store for the mail subject line maybe. # it, or as a separate store for the mail subject line maybe.
@ -122,7 +122,7 @@ class Msg(SharedMemoryModel):
db_hide_from_channels = models.ManyToManyField("ChannelDB", related_name='hide_from_channels_set', blank=True) db_hide_from_channels = models.ManyToManyField("ChannelDB", related_name='hide_from_channels_set', blank=True)
db_tags = models.ManyToManyField(Tag, blank=True, db_tags = models.ManyToManyField(Tag, blank=True,
help_text='tags on this message. Tags are simple string markers to identify, group and alias messages.') help_text='tags on this message. Tags are simple string markers to identify, group and alias messages.')
# Database manager # Database manager
objects = managers.MsgManager() objects = managers.MsgManager()
@ -156,10 +156,10 @@ class Msg(SharedMemoryModel):
#@property #@property
def __senders_get(self): def __senders_get(self):
"Getter. Allows for value = self.sender" "Getter. Allows for value = self.sender"
return list(self.db_sender_accounts.all()) + \ return list(self.db_sender_accounts.all()) + \
list(self.db_sender_objects.all()) + \ list(self.db_sender_objects.all()) + \
list(self.db_sender_scripts.all()) + \ list(self.db_sender_scripts.all()) + \
self.extra_senders self.extra_senders
#@sender.setter #@sender.setter
def __senders_set(self, senders): def __senders_set(self, senders):
@ -225,9 +225,9 @@ class Msg(SharedMemoryModel):
Returns four lists of receivers: accounts, objects, scripts and channels. Returns four lists of receivers: accounts, objects, scripts and channels.
""" """
return list(self.db_receivers_accounts.all()) + \ return list(self.db_receivers_accounts.all()) + \
list(self.db_receivers_objects.all()) + \ list(self.db_receivers_objects.all()) + \
list(self.db_receivers_scripts.all()) + \ list(self.db_receivers_scripts.all()) + \
list(self.db_receivers_channels.all()) list(self.db_receivers_channels.all())
#@receivers.setter #@receivers.setter
def __receivers_set(self, receivers): def __receivers_set(self, receivers):
@ -250,7 +250,6 @@ class Msg(SharedMemoryModel):
elif clsname == "ChannelDB": elif clsname == "ChannelDB":
self.db_receivers_channels.add(receiver) self.db_receivers_channels.add(receiver)
#@receivers.deleter #@receivers.deleter
def __receivers_del(self): def __receivers_del(self):
"Deleter. Clears all receivers" "Deleter. Clears all receivers"
@ -370,6 +369,7 @@ class Msg(SharedMemoryModel):
# #
#------------------------------------------------------------ #------------------------------------------------------------
class TempMsg(object): class TempMsg(object):
""" """
This is a non-persistent object for sending temporary messages This is a non-persistent object for sending temporary messages
@ -377,6 +377,7 @@ class TempMsg(object):
doesn't require sender to be given. doesn't require sender to be given.
""" """
def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None): def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None):
""" """
Creates the temp message. Creates the temp message.
@ -471,6 +472,7 @@ class SubscriptionHandler(object):
channel and hides away which type of entity is channel and hides away which type of entity is
subscribing (Account or Object) subscribing (Account or Object)
""" """
def __init__(self, obj): def __init__(self, obj):
""" """
Initialize the handler Initialize the handler
@ -620,10 +622,10 @@ class ChannelDB(TypedObject):
""" """
db_account_subscriptions = models.ManyToManyField("accounts.AccountDB", db_account_subscriptions = models.ManyToManyField("accounts.AccountDB",
related_name="account_subscription_set", blank=True, verbose_name='account subscriptions', db_index=True) related_name="account_subscription_set", blank=True, verbose_name='account subscriptions', db_index=True)
db_object_subscriptions = models.ManyToManyField("objects.ObjectDB", db_object_subscriptions = models.ManyToManyField("objects.ObjectDB",
related_name="object_subscription_set", blank=True, verbose_name='object subscriptions', db_index=True) related_name="object_subscription_set", blank=True, verbose_name='object subscriptions', db_index=True)
# Database manager # Database manager
objects = managers.ChannelDBManager() objects = managers.ChannelDBManager()

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 # own code, so somthing needs to be done here. See issue #766. /Griatch
#import evennia #import evennia
#evennia._init() # evennia._init()
#import barter, dice, extended_room, menu_login, talking_npc #import barter, dice, extended_room, menu_login, talking_npc
#import chargen, email_login, gendersub, menusystem, slow_exit #import chargen, email_login, gendersub, menusystem, slow_exit
#import tutorial_world, tutorial_examples #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. This times out the trade request, in case player B did not reply in time.
""" """
def at_script_creation(self): def at_script_creation(self):
""" """
Called when script is first created 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 Objects of this class handles the ongoing trade, notably storing the current
offers from each side and wether both have accepted or not. offers from each side and wether both have accepted or not.
""" """
def __init__(self, part_a, part_b): def __init__(self, part_a, part_b):
""" """
Initializes the trade. This is called when part A tries to 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 Base command for Trade commands to inherit from. Implements the
custom parsing. custom parsing.
""" """
def parse(self): def parse(self):
""" """
Parse the relevant parts and make it easily Parse the relevant parts and make it easily

View file

@ -102,7 +102,7 @@ class CmdOOCLook(default_cmds.CmdLook):
else: else:
charlist = "You have no Characters." charlist = "You have no Characters."
string = \ 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. from you and besides chatting on channels your options are limited.
You need to have a Character in order to interact with the world. 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. Extends the default OOC cmdset.
""" """
def at_cmdset_creation(self): def at_cmdset_creation(self):
"""Install everything from the default set, then overload""" """Install everything from the default set, then overload"""
self.add(CmdOOCLook()) self.add(CmdOOCLook())

View file

@ -88,11 +88,11 @@ CLOTHING_TYPE_ORDER = ['hat', 'jewelry', 'top', 'undershirt', 'gloves', 'fullbod
'underpants', 'socks', 'shoes', 'accessory'] 'underpants', 'socks', 'shoes', 'accessory']
# The maximum number of each type of clothes that can be worn. Unlimited if untyped or not specified. # The maximum number of each type of clothes that can be worn. Unlimited if untyped or not specified.
CLOTHING_TYPE_LIMIT = { CLOTHING_TYPE_LIMIT = {
'hat': 1, 'hat': 1,
'gloves': 1, 'gloves': 1,
'socks': 1, 'socks': 1,
'shoes': 1 'shoes': 1
} }
# The maximum number of clothing items that can be worn, or None for unlimited. # The maximum number of clothing items that can be worn, or None for unlimited.
CLOTHING_OVERALL_LIMIT = 20 CLOTHING_OVERALL_LIMIT = 20
# What types of clothes will automatically cover what other types of clothes when worn. # 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 # on that auto-covers it - for example, it's perfectly possible to have your underpants
# showing if you put them on after your pants! # showing if you put them on after your pants!
CLOTHING_TYPE_AUTOCOVER = { CLOTHING_TYPE_AUTOCOVER = {
'top': ['undershirt'], 'top': ['undershirt'],
'bottom': ['underpants'], 'bottom': ['underpants'],
'fullbody': ['undershirt', 'underpants'], 'fullbody': ['undershirt', 'underpants'],
'shoes': ['socks'] 'shoes': ['socks']
} }
# Types of clothes that can't be used to cover other clothes. # Types of clothes that can't be used to cover other clothes.
CLOTHING_TYPE_CANT_COVER_WITH = ['jewelry'] 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 just copy the return_appearance hook defined below to your own game's
character typeclass. character typeclass.
""" """
def return_appearance(self, looker): def return_appearance(self, looker):
""" """
This formats a description. It is the hook a 'look' command 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_XTERM256_EXTRA_GBG = [r'\{\[=([a-z])'] # |[=a - greyscale background
CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [ CURLY_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
(r'{[r', r'{[500'), (r'{[r', r'{[500'),
(r'{[g', r'{[050'), (r'{[g', r'{[050'),
(r'{[y', r'{[550'), (r'{[y', r'{[550'),
(r'{[b', r'{[005'), (r'{[b', r'{[005'),
(r'{[m', r'{[505'), (r'{[m', r'{[505'),
(r'{[c', r'{[055'), (r'{[c', r'{[055'),
(r'{[w', r'{[555'), # white background (r'{[w', r'{[555'), # white background
(r'{[x', r'{[222'), # dark grey 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 = [ MUX_COLOR_ANSI_EXTRA_MAP = [
(r'%cn', _ANSI_NORMAL), # reset (r'%cn', _ANSI_NORMAL), # reset
(r'%ch', _ANSI_HILITE), # highlight (r'%ch', _ANSI_HILITE), # highlight
(r'%r', _ANSI_RETURN), # line break (r'%r', _ANSI_RETURN), # line break
(r'%R', _ANSI_RETURN), # (r'%R', _ANSI_RETURN), #
(r'%t', _ANSI_TAB), # tab (r'%t', _ANSI_TAB), # tab
(r'%T', _ANSI_TAB), # (r'%T', _ANSI_TAB), #
(r'%b', _ANSI_SPACE), # space (r'%b', _ANSI_SPACE), # space
(r'%B', _ANSI_SPACE), (r'%B', _ANSI_SPACE),
(r'%cf', _ANSI_BLINK), # annoying and not supported by all clients (r'%cf', _ANSI_BLINK), # annoying and not supported by all clients
(r'%ci', _ANSI_INVERSE), # invert (r'%ci', _ANSI_INVERSE), # invert
(r'%cr', _ANSI_RED), (r'%cr', _ANSI_RED),
(r'%cg', _ANSI_GREEN), (r'%cg', _ANSI_GREEN),
(r'%cy', _ANSI_YELLOW), (r'%cy', _ANSI_YELLOW),
(r'%cb', _ANSI_BLUE), (r'%cb', _ANSI_BLUE),
(r'%cm', _ANSI_MAGENTA), (r'%cm', _ANSI_MAGENTA),
(r'%cc', _ANSI_CYAN), (r'%cc', _ANSI_CYAN),
(r'%cw', _ANSI_WHITE), (r'%cw', _ANSI_WHITE),
(r'%cx', _ANSI_BLACK), (r'%cx', _ANSI_BLACK),
(r'%cR', _ANSI_BACK_RED), (r'%cR', _ANSI_BACK_RED),
(r'%cG', _ANSI_BACK_GREEN), (r'%cG', _ANSI_BACK_GREEN),
(r'%cY', _ANSI_BACK_YELLOW), (r'%cY', _ANSI_BACK_YELLOW),
(r'%cB', _ANSI_BACK_BLUE), (r'%cB', _ANSI_BACK_BLUE),
(r'%cM', _ANSI_BACK_MAGENTA), (r'%cM', _ANSI_BACK_MAGENTA),
(r'%cC', _ANSI_BACK_CYAN), (r'%cC', _ANSI_BACK_CYAN),
(r'%cW', _ANSI_BACK_WHITE), (r'%cW', _ANSI_BACK_WHITE),
(r'%cX', _ANSI_BACK_BLACK) (r'%cX', _ANSI_BACK_BLACK)
] ]
MUX_COLOR_XTERM256_EXTRA_FG = [r'%c([0-5])([0-5])([0-5])'] # %c123 - foreground colour 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_XTERM256_EXTRA_GBG = [r'%c\[=([a-z])'] # %c[=a - greyscale background
MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [ MUX_COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP = [
(r'%ch%cR', r'%c[500'), (r'%ch%cR', r'%c[500'),
(r'%ch%cG', r'%c[050'), (r'%ch%cG', r'%c[050'),
(r'%ch%cY', r'%c[550'), (r'%ch%cY', r'%c[550'),
(r'%ch%cB', r'%c[005'), (r'%ch%cB', r'%c[005'),
(r'%ch%cM', r'%c[505'), (r'%ch%cM', r'%c[505'),
(r'%ch%cC', r'%c[055'), (r'%ch%cC', r'%c[055'),
(r'%ch%cW', r'%c[555'), # white background (r'%ch%cW', r'%c[555'), # white background
(r'%ch%cX', r'%c[222'), # dark grey 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. # Each unit must be consistent and expressed in seconds.
UNITS = getattr(settings, "TIME_UNITS", { UNITS = getattr(settings, "TIME_UNITS", {
# default custom calendar # default custom calendar
"sec": 1, "sec": 1,
"min": 60, "min": 60,
"hr": 60 * 60, "hr": 60 * 60,
"hour": 60 * 60, "hour": 60 * 60,
"day": 60 * 60 * 24, "day": 60 * 60 * 24,
"week": 60 * 60 * 24 * 7, "week": 60 * 60 * 24 * 7,
"month": 60 * 60 * 24 * 7 * 4, "month": 60 * 60 * 24 * 7 * 4,
"yr": 60 * 60 * 24 * 7 * 4 * 12, "yr": 60 * 60 * 24 * 7 * 4 * 12,
"year": 60 * 60 * 24 * 7 * 4 * 12, }) "year": 60 * 60 * 24 * 7 * 4 * 12, })
def time_to_tuple(seconds, *divisors): def time_to_tuple(seconds, *divisors):
@ -111,8 +111,8 @@ def gametime_to_realtime(format=False, **kwargs):
name = name[:-1] name = name[:-1]
if name not in UNITS: if name not in UNITS:
raise ValueError("the unit {} isn't defined as a valid " \ raise ValueError("the unit {} isn't defined as a valid "
"game time unit".format(name)) "game time unit".format(name))
rtime += value * UNITS[name] rtime += value * UNITS[name]
rtime /= TIMEFACTOR rtime /= TIMEFACTOR
if format: 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, 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 This method calculates how much in-game time a real-world time
interval would correspond to. This is usually a lot less 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 + gtime = TIMEFACTOR * (secs + mins * 60 + hrs * 3600 + days * 86400 +
weeks * 604800 + months * 2628000 + yrs * 31536000) weeks * 604800 + months * 2628000 + yrs * 31536000)
if format: if format:
units = sorted(set(UNITS.values()), reverse=True) units = sorted(set(UNITS.values()), reverse=True)
# Remove seconds from the tuple # 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 time_to_tuple(gtime, *units)
return gtime return gtime
def custom_gametime(absolute=False): def custom_gametime(absolute=False):
""" """
Return the custom game time as a tuple of units, as defined in settings. 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] del units[-1]
return time_to_tuple(current, *units) return time_to_tuple(current, *units)
def real_seconds_until(**kwargs): def real_seconds_until(**kwargs):
""" """
Return the real seconds until game time. Return the real seconds until game time.
@ -228,6 +230,7 @@ def real_seconds_until(**kwargs):
return (projected - current) / TIMEFACTOR return (projected - current) / TIMEFACTOR
def schedule(callback, repeat=False, **kwargs): def schedule(callback, repeat=False, **kwargs):
""" """
Call the callback when the game time is up. Call the callback when the game time is up.
@ -256,14 +259,16 @@ def schedule(callback, repeat=False, **kwargs):
""" """
seconds = real_seconds_until(**kwargs) seconds = real_seconds_until(**kwargs)
script = create_script("evennia.contrib.custom_gametime.GametimeScript", script = create_script("evennia.contrib.custom_gametime.GametimeScript",
key="GametimeScript", desc="A timegame-sensitive script", key="GametimeScript", desc="A timegame-sensitive script",
interval=seconds, start_delay=True, interval=seconds, start_delay=True,
repeats=-1 if repeat else 1) repeats=-1 if repeat else 1)
script.db.callback = callback script.db.callback = callback
script.db.gametime = kwargs script.db.gametime = kwargs
return script return script
# Scripts dealing in gametime (use `schedule` to create it) # Scripts dealing in gametime (use `schedule` to create it)
class GametimeScript(DefaultScript): class GametimeScript(DefaultScript):
"""Gametime-sensitive script.""" """Gametime-sensitive script."""

View file

@ -118,6 +118,7 @@ def roll_dice(dicenum, dicetype, modifier=None, conditional=None, return_tuple=F
else: else:
return result return result
RE_PARTS = re.compile(r"(d|\+|-|/|\*|<|>|<=|>=|!=|==)") RE_PARTS = re.compile(r"(d|\+|-|/|\*|<|>|<=|>=|!=|==)")
RE_MOD = re.compile(r"(\+|-|/|\*)") RE_MOD = re.compile(r"(\+|-|/|\*)")
RE_COND = re.compile(r"(<|>|<=|>=|!=|==)") RE_COND = re.compile(r"(<|>|<=|>=|!=|==)")
@ -255,6 +256,7 @@ class DiceCmdSet(CmdSet):
a small cmdset for testing purposes. a small cmdset for testing purposes.
Add with @py self.cmdset.add("contrib.dice.DiceCmdSet") Add with @py self.cmdset.add("contrib.dice.DiceCmdSet")
""" """
def at_cmdset_creation(self): def at_cmdset_creation(self):
"""Called when set is created""" """Called when set is created"""
self.add(CmdDice()) 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 Evennia Game Index. Since EGI is in the early goings, this isn't
incredibly configurable as far as what is being sent. incredibly configurable as far as what is being sent.
""" """
def __init__(self, on_bad_request=None): def __init__(self, on_bad_request=None):
""" """
:param on_bad_request: Optional callable to trigger when a bad request :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. Used for pulling the response body out of an HTTP response.
""" """
def __init__(self, status_code, d): def __init__(self, status_code, d):
self.status_code = status_code self.status_code = status_code
self.buf = '' self.buf = ''

View file

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

View file

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

View file

@ -4,6 +4,7 @@ Module containing the CallbackHandler for individual objects.
from collections import namedtuple from collections import namedtuple
class CallbackHandler(object): class CallbackHandler(object):
""" """
@ -99,7 +100,7 @@ class CallbackHandler(object):
handler = type(self).script handler = type(self).script
if handler: if handler:
return self.format_callback(handler.add_callback(self.obj, callback_name, code, 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): def edit(self, callback_name, number, code, author=None, valid=False):
""" """
@ -122,7 +123,7 @@ class CallbackHandler(object):
handler = type(self).script handler = type(self).script
if handler: if handler:
return self.format_callback(handler.edit_callback(self.obj, callback_name, 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): def remove(self, callback_name, number):
""" """
@ -200,5 +201,6 @@ class CallbackHandler(object):
return Callback(**callback) return Callback(**callback)
Callback = namedtuple("Callback", ("obj", "name", "number", "code", "author", 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 # Permissions
WITH_VALIDATION = getattr(settings, "callbackS_WITH_VALIDATION", None) WITH_VALIDATION = getattr(settings, "callbackS_WITH_VALIDATION", None)
WITHOUT_VALIDATION = getattr(settings, "callbackS_WITHOUT_VALIDATION", WITHOUT_VALIDATION = getattr(settings, "callbackS_WITHOUT_VALIDATION",
"developer") "developer")
VALIDATING = getattr(settings, "callbackS_VALIDATING", "developer") VALIDATING = getattr(settings, "callbackS_VALIDATING", "developer")
# Split help text # Split help text
BASIC_HELP = "Add, edit or delete callbacks." BASIC_HELP = "Add, edit or delete callbacks."
BASIC_USAGES = [ BASIC_USAGES = [
"@call <object name> [= <callback name>]", "@call <object name> [= <callback name>]",
"@call/add <object name> = <callback name> [parameters]", "@call/add <object name> = <callback name> [parameters]",
"@call/edit <object name> = <callback name> [callback number]", "@call/edit <object name> = <callback name> [callback number]",
"@call/del <object name> = <callback name> [callback number]", "@call/del <object name> = <callback name> [callback number]",
"@call/tasks [object name [= <callback name>]]", "@call/tasks [object name [= <callback name>]]",
] ]
BASIC_SWITCHES = [ BASIC_SWITCHES = [
@ -39,7 +39,7 @@ BASIC_SWITCHES = [
] ]
VALIDATOR_USAGES = [ VALIDATOR_USAGES = [
"@call/accept [object name = <callback name> [callback number]]", "@call/accept [object name = <callback name> [callback number]]",
] ]
VALIDATOR_SWITCHES = [ 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. Use the /del switch to remove callbacks that should not be connected.
""" """
class CmdCallback(COMMAND_DEFAULT_CLASS): class CmdCallback(COMMAND_DEFAULT_CLASS):
""" """
@ -141,8 +142,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
self.is_validator = validator self.is_validator = validator
self.autovalid = autovalid self.autovalid = autovalid
if self.handler is None: if self.handler is None:
caller.msg("The event handler is not running, can't " \ caller.msg("The event handler is not running, can't "
"access the event system.") "access the event system.")
return return
# Before the equal sign, there is an object name or nothing # 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"]: elif switch in ["tasks", "task"]:
self.list_tasks() self.list_tasks()
else: else:
caller.msg("Mutually exclusive or invalid switches were " \ caller.msg("Mutually exclusive or invalid switches were "
"used, cannot proceed.") "used, cannot proceed.")
def list_callbacks(self): def list_callbacks(self):
"""Display the list of callbacks connected to the object.""" """Display the list of callbacks connected to the object."""
@ -186,7 +187,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
created = callbacks.get(callback_name) created = callbacks.get(callback_name)
if created is None: if created is None:
self.msg("No callback {} has been set on {}.".format(callback_name, self.msg("No callback {} has been set on {}.".format(callback_name,
obj)) obj))
return return
if parameters: if parameters:
@ -197,7 +198,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number] callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError): except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format( self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj)) callback_name, parameters, obj))
return return
# Display the callback's details # Display the callback's details
@ -241,8 +242,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
if updated_on: if updated_on:
updated_on = "{} ago".format(time_format( updated_on = "{} ago".format(time_format(
(now - updated_on).total_seconds(), (now - updated_on).total_seconds(),
4).capitalize()) 4).capitalize())
else: else:
updated_on = "|gUnknown|n" updated_on = "|gUnknown|n"
parameters = callback.get("parameters", "") parameters = callback.get("parameters", "")
@ -256,7 +257,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
else: else:
names = list(set(list(types.keys()) + list(callbacks.keys()))) names = list(set(list(types.keys()) + list(callbacks.keys())))
table = EvTable("Callback name", "Number", "Description", table = EvTable("Callback name", "Number", "Description",
valign="t", width=78) valign="t", width=78)
table.reformat_column(0, width=20) table.reformat_column(0, width=20)
table.reformat_column(1, width=10, align="r") table.reformat_column(1, width=10, align="r")
table.reformat_column(2, width=48) table.reformat_column(2, width=48)
@ -277,9 +278,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
types = self.handler.get_events(obj) types = self.handler.get_events(obj)
# Check that the callback exists # Check that the callback exists
if not callback_name.startswith("chain_") and not callback_name in types: if not callback_name.startswith("chain_") and callback_name not in types:
self.msg("The callback name {} can't be found in {} of " \ self.msg("The callback name {} can't be found in {} of "
"typeclass {}.".format(callback_name, obj, type(obj))) "typeclass {}.".format(callback_name, obj, type(obj)))
return return
definition = types.get(callback_name, (None, "Chained event.")) definition = types.get(callback_name, (None, "Chained event."))
@ -288,7 +289,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# Open the editor # Open the editor
callback = self.handler.add_callback(obj, callback_name, "", 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 # Lock this callback right away
self.handler.db.locked.append((obj, callback_name, callback["number"])) 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 # Open the editor for this callback
self.caller.db._callback = callback self.caller.db._callback = callback
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save, EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
quitfunc=_ev_quit, key="Callback {} of {}".format( quitfunc=_ev_quit, key="Callback {} of {}".format(
callback_name, obj), persistent=True, codefunc=_ev_save) callback_name, obj), persistent=True, codefunc=_ev_save)
def edit_callback(self): def edit_callback(self):
"""Edit a callback.""" """Edit a callback."""
@ -313,9 +314,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
return return
# Check that the callback exists # 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( self.msg("The callback name {} can't be found in {}.".format(
callback_name, obj)) callback_name, obj))
return return
# If there's only one callback, just edit it # If there's only one callback, just edit it
@ -335,7 +336,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number] callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError): except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format( self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj)) callback_name, parameters, obj))
return return
# If caller can't edit without validation, forbid editing # If caller can't edit without validation, forbid editing
@ -361,7 +362,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
self.caller.db._callback = callback self.caller.db._callback = callback
EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save, EvEditor(self.caller, loadfunc=_ev_load, savefunc=_ev_save,
quitfunc=_ev_quit, key="Callback {} of {}".format( 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): def del_callback(self):
"""Delete a callback.""" """Delete a callback."""
@ -377,9 +378,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
return return
# Check that the callback exists # 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( self.msg("The callback name {} can't be found in {}.".format(
callback_name, obj)) callback_name, obj))
return return
# If there's only one callback, just delete it # If there's only one callback, just delete it
@ -388,8 +389,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][0] callback = callbacks[callback_name][0]
else: else:
if not parameters: if not parameters:
self.msg("Which callback do you wish to delete? Specify " \ self.msg("Which callback do you wish to delete? Specify "
"a number.") "a number.")
self.list_callbacks() self.list_callbacks()
return return
@ -400,7 +401,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number] callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError): except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format( self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj)) callback_name, parameters, obj))
return return
# If caller can't edit without validation, forbid deleting # If caller can't edit without validation, forbid deleting
@ -417,7 +418,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# Delete the callback # Delete the callback
self.handler.del_callback(obj, callback_name, number) self.handler.del_callback(obj, callback_name, number)
self.msg("The callback {}[{}] of {} was deleted.".format( self.msg("The callback {}[{}] of {} was deleted.".format(
callback_name, number + 1, obj)) callback_name, number + 1, obj))
def accept_callback(self): def accept_callback(self):
"""Accept a callback.""" """Accept a callback."""
@ -428,7 +429,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
# If no object, display the list of callbacks to be checked # If no object, display the list of callbacks to be checked
if obj is None: if obj is None:
table = EvTable("ID", "Type", "Object", "Name", "Updated by", table = EvTable("ID", "Type", "Object", "Name", "Updated by",
"On", width=78) "On", width=78)
table.reformat_column(0, align="r") table.reformat_column(0, align="r")
now = datetime.now() now = datetime.now()
for obj, name, number in self.handler.db.to_valid: for obj, name, number in self.handler.db.to_valid:
@ -450,8 +451,8 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
if updated_on: if updated_on:
updated_on = "{} ago".format(time_format( updated_on = "{} ago".format(time_format(
(now - updated_on).total_seconds(), (now - updated_on).total_seconds(),
4).capitalize()) 4).capitalize())
else: else:
updated_on = "|gUnknown|n" updated_on = "|gUnknown|n"
@ -469,9 +470,9 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
return return
# Check that the callback exists # 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( self.msg("The callback name {} can't be found in {}.".format(
callback_name, obj)) callback_name, obj))
return return
if not parameters: if not parameters:
@ -486,7 +487,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
callback = callbacks[callback_name][number] callback = callbacks[callback_name][number]
except (ValueError, AssertionError, IndexError): except (ValueError, AssertionError, IndexError):
self.msg("The callback {} {} cannot be found in {}.".format( self.msg("The callback {} {} cannot be found in {}.".format(
callback_name, parameters, obj)) callback_name, parameters, obj))
return return
# Accept the callback # Accept the callback
@ -495,7 +496,7 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
else: else:
self.handler.accept_callback(obj, callback_name, number) self.handler.accept_callback(obj, callback_name, number)
self.msg("The callback {} {} of {} has been accepted.".format( self.msg("The callback {} {} of {} has been accepted.".format(
callback_name, parameters, obj)) callback_name, parameters, obj))
def list_tasks(self): def list_tasks(self):
"""List the active tasks.""" """List the active tasks."""
@ -520,40 +521,44 @@ class CmdCallback(COMMAND_DEFAULT_CLASS):
self.msg(unicode(table)) self.msg(unicode(table))
# Private functions to handle editing # Private functions to handle editing
def _ev_load(caller): def _ev_load(caller):
return caller.db._callback and caller.db._callback.get("code", "") or "" return caller.db._callback and caller.db._callback.get("code", "") or ""
def _ev_save(caller, buf): def _ev_save(caller, buf):
"""Save and add the callback.""" """Save and add the callback."""
lock = "perm({}) or perm(events_without_validation)".format( lock = "perm({}) or perm(events_without_validation)".format(
WITHOUT_VALIDATION) WITHOUT_VALIDATION)
autovalid = caller.locks.check_lockstring(caller, lock) autovalid = caller.locks.check_lockstring(caller, lock)
callback = caller.db._callback callback = caller.db._callback
handler = get_event_handler() handler = get_event_handler()
if not handler or not callback or not all(key in callback for key in \ if not handler or not callback or not all(key in callback for key in
("obj", "name", "number", "valid")): ("obj", "name", "number", "valid")):
caller.msg("Couldn't save this callback.") caller.msg("Couldn't save this callback.")
return False return False
if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked: if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked:
handler.db.locked.remove((callback["obj"], callback["name"], handler.db.locked.remove((callback["obj"], callback["name"],
callback["number"])) callback["number"]))
handler.edit_callback(callback["obj"], callback["name"], callback["number"], buf, handler.edit_callback(callback["obj"], callback["name"], callback["number"], buf,
caller, valid=autovalid) caller, valid=autovalid)
return True return True
def _ev_quit(caller): def _ev_quit(caller):
callback = caller.db._callback callback = caller.db._callback
handler = get_event_handler() handler = get_event_handler()
if not handler or not callback or not all(key in callback for key in \ if not handler or not callback or not all(key in callback for key in
("obj", "name", "number", "valid")): ("obj", "name", "number", "valid")):
caller.msg("Couldn't save this callback.") caller.msg("Couldn't save this callback.")
return False return False
if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked: if (callback["obj"], callback["name"], callback["number"]) in handler.db.locked:
handler.db.locked.remove((callback["obj"], callback["name"], handler.db.locked.remove((callback["obj"], callback["name"],
callback["number"])) callback["number"]))
del caller.db._callback del caller.db._callback
caller.msg("Exited the code editor.") 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 import ObjectDB, ScriptDB
from evennia.contrib.ingame_python.utils import InterruptEvent from evennia.contrib.ingame_python.utils import InterruptEvent
def deny(): def deny():
""" """
Deny, that is stop, the callback here. Deny, that is stop, the callback here.
@ -22,6 +23,7 @@ def deny():
""" """
raise InterruptEvent raise InterruptEvent
def get(**kwargs): def get(**kwargs):
""" """
Return an object with the given search option or None if None is found. Return an object with the given search option or None if None is found.
@ -53,6 +55,7 @@ def get(**kwargs):
return object return object
def call_event(obj, event_name, seconds=0): def call_event(obj, event_name, seconds=0):
""" """
Call the specified event in X seconds. 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 # Constants
RE_LINE_ERROR = re.compile(r'^ File "\<string\>", line (\d+)') RE_LINE_ERROR = re.compile(r'^ File "\<string\>", line (\d+)')
class EventHandler(DefaultScript): class EventHandler(DefaultScript):
""" """
@ -94,7 +95,7 @@ class EventHandler(DefaultScript):
self.ndb.channel = ChannelDB.objects.get(db_key="everror") self.ndb.channel = ChannelDB.objects.get(db_key="everror")
except ChannelDB.DoesNotExist: except ChannelDB.DoesNotExist:
self.ndb.channel = create_channel("everror", desc="Event errors", 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): def get_events(self, obj):
""" """
@ -131,7 +132,7 @@ class EventHandler(DefaultScript):
for key, etype in all_events.get(typeclass_name, {}).items(): for key, etype in all_events.get(typeclass_name, {}).items():
if key in invalid: if key in invalid:
continue continue
if etype[0] is None: # Invalidate if etype[0] is None: # Invalidate
invalid.append(key) invalid.append(key)
continue continue
if key not in events: if key not in events:
@ -200,7 +201,7 @@ class EventHandler(DefaultScript):
return callbacks return callbacks
def add_callback(self, obj, callback_name, code, author=None, valid=False, def add_callback(self, obj, callback_name, code, author=None, valid=False,
parameters=""): parameters=""):
""" """
Add the specified callback. Add the specified callback.
@ -228,11 +229,11 @@ class EventHandler(DefaultScript):
# Add the callback in the list # Add the callback in the list
callbacks.append({ callbacks.append({
"created_on": datetime.now(), "created_on": datetime.now(),
"author": author, "author": author,
"valid": valid, "valid": valid,
"code": code, "code": code,
"parameters": parameters, "parameters": parameters,
}) })
# If not valid, set it in 'to_valid' # If not valid, set it in 'to_valid'
@ -241,7 +242,7 @@ class EventHandler(DefaultScript):
# Call the custom_add if needed # Call the custom_add if needed
custom_add = self.get_events(obj).get( custom_add = self.get_events(obj).get(
callback_name, [None, None, None, None])[3] callback_name, [None, None, None, None])[3]
if custom_add: if custom_add:
custom_add(obj, callback_name, len(callbacks) - 1, parameters) custom_add(obj, callback_name, len(callbacks) - 1, parameters)
@ -253,7 +254,7 @@ class EventHandler(DefaultScript):
return definition return definition
def edit_callback(self, obj, callback_name, number, code, author=None, def edit_callback(self, obj, callback_name, number, code, author=None,
valid=False): valid=False):
""" """
Edit the specified callback. Edit the specified callback.
@ -288,10 +289,10 @@ class EventHandler(DefaultScript):
# Edit the callback # Edit the callback
callbacks[number].update({ callbacks[number].update({
"updated_on": datetime.now(), "updated_on": datetime.now(),
"updated_by": author, "updated_by": author,
"valid": valid, "valid": valid,
"code": code, "code": code,
}) })
# If not valid, set it in 'to_valid' # If not valid, set it in 'to_valid'
@ -334,7 +335,7 @@ class EventHandler(DefaultScript):
return return
else: else:
logger.log_info("Deleting callback {} {} of {}:\n{}".format( logger.log_info("Deleting callback {} {} of {}:\n{}".format(
callback_name, number, obj, code)) callback_name, number, obj, code))
del callbacks[number] del callbacks[number]
# Change IDs of callbacks to be validated # Change IDs of callbacks to be validated
@ -349,7 +350,7 @@ class EventHandler(DefaultScript):
elif t_number > number: elif t_number > number:
# Change the ID for this callback # Change the ID for this callback
self.db.to_valid.insert(i, (t_obj, t_callback_name, self.db.to_valid.insert(i, (t_obj, t_callback_name,
t_number - 1)) t_number - 1))
del self.db.to_valid[i + 1] del self.db.to_valid[i + 1]
i += 1 i += 1
@ -414,13 +415,13 @@ class EventHandler(DefaultScript):
# Errors should not pass silently # Errors should not pass silently
allowed = ("number", "parameters", "locals") allowed = ("number", "parameters", "locals")
if any(k for k in kwargs if k not in allowed): if any(k for k in kwargs if k not in allowed):
raise TypeError("Unknown keyword arguments were specified " \ raise TypeError("Unknown keyword arguments were specified "
"to call callbacks: {}".format(kwargs)) "to call callbacks: {}".format(kwargs))
event = self.get_events(obj).get(callback_name) event = self.get_events(obj).get(callback_name)
if locals is None and not event: if locals is None and not event:
logger.log_err("The callback {} for the object {} (typeclass " \ logger.log_err("The callback {} for the object {} (typeclass "
"{}) can't be found".format(callback_name, obj, type(obj))) "{}) can't be found".format(callback_name, obj, type(obj)))
return False return False
# Prepare the locals if necessary # Prepare the locals if necessary
@ -430,9 +431,9 @@ class EventHandler(DefaultScript):
try: try:
locals[variable] = args[i] locals[variable] = args[i]
except IndexError: except IndexError:
logger.log_trace("callback {} of {} ({}): need variable " \ logger.log_trace("callback {} of {} ({}): need variable "
"{} in position {}".format(callback_name, obj, "{} in position {}".format(callback_name, obj,
type(obj), variable, i)) type(obj), variable, i))
return False return False
else: else:
locals = {key: value for key, value in locals.items()} locals = {key: value for key, value in locals.items()}
@ -482,9 +483,9 @@ class EventHandler(DefaultScript):
number = callback["number"] number = callback["number"]
obj = callback["obj"] obj = callback["obj"]
oid = obj.id oid = obj.id
logger.log_err("An error occurred during the callback {} of " \ logger.log_err("An error occurred during the callback {} of "
"{} (#{}), number {}\n{}".format(callback_name, obj, "{} (#{}), number {}\n{}".format(callback_name, obj,
oid, number + 1, "\n".join(trace))) oid, number + 1, "\n".join(trace)))
# Create the error message # Create the error message
line = "|runknown|n" line = "|runknown|n"
@ -505,8 +506,8 @@ class EventHandler(DefaultScript):
exc = raw(trace[-1].strip("\n").splitlines()[-1]) exc = raw(trace[-1].strip("\n").splitlines()[-1])
err_msg = "Error in {} of {} (#{})[{}], line {}:" \ err_msg = "Error in {} of {} (#{})[{}], line {}:" \
" {}\n{}".format(callback_name, obj, " {}\n{}".format(callback_name, obj,
oid, number + 1, lineno, line, exc) oid, number + 1, lineno, line, exc)
# Inform the last updater if connected # Inform the last updater if connected
updater = callback.get("updated_by") updater = callback.get("updated_by")
@ -517,8 +518,8 @@ class EventHandler(DefaultScript):
updater.msg(err_msg) updater.msg(err_msg)
else: else:
err_msg = "Error in {} of {} (#{})[{}], line {}:" \ err_msg = "Error in {} of {} (#{})[{}], line {}:" \
" {}\n {}".format(callback_name, obj, " {}\n {}".format(callback_name, obj,
oid, number + 1, lineno, line, exc) oid, number + 1, lineno, line, exc)
self.ndb.channel.msg(err_msg) self.ndb.channel.msg(err_msg)
def add_event(self, typeclass, name, variables, help_text, custom_call, custom_add): def add_event(self, typeclass, name, variables, help_text, custom_call, custom_add):
@ -655,8 +656,8 @@ def complete_task(task_id):
return return
if task_id not in script.db.tasks: if task_id not in script.db.tasks:
logger.log_err("The task #{} was scheduled, but it cannot be " \ logger.log_err("The task #{} was scheduled, but it cannot be "
"found".format(task_id)) "found".format(task_id))
return return
delta, obj, callback_name, locals = script.db.tasks.pop(task_id) delta, obj, callback_name, locals = script.db.tasks.pop(task_id)

View file

@ -21,6 +21,7 @@ settings.EVENTS_CALENDAR = "standard"
# Constants # Constants
OLD_EVENTS = {} OLD_EVENTS = {}
class TestEventHandler(EvenniaTest): class TestEventHandler(EvenniaTest):
""" """
@ -31,7 +32,7 @@ class TestEventHandler(EvenniaTest):
"""Create the event handler.""" """Create the event handler."""
super(TestEventHandler, self).setUp() super(TestEventHandler, self).setUp()
self.handler = create_script( self.handler = create_script(
"evennia.contrib.ingame_python.scripts.EventHandler") "evennia.contrib.ingame_python.scripts.EventHandler")
# Copy old events if necessary # Copy old events if necessary
if OLD_EVENTS: if OLD_EVENTS:
@ -64,7 +65,7 @@ class TestEventHandler(EvenniaTest):
"""Add a callback while needing validation.""" """Add a callback while needing validation."""
author = self.char1 author = self.char1
self.handler.add_callback(self.room1, "dummy", 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 = self.handler.get_callbacks(self.room1).get("dummy")
callback = callback[0] callback = callback[0]
self.assertIsNotNone(callback) self.assertIsNotNone(callback)
@ -78,18 +79,18 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10 self.char1.db.strength = 10
locals = {"character": self.char1} locals = {"character": self.char1}
self.assertTrue(self.handler.call( self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals)) self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 10) self.assertEqual(self.char1.db.strength, 10)
def test_edit(self): def test_edit(self):
"""Test editing a callback.""" """Test editing a callback."""
author = self.char1 author = self.char1
self.handler.add_callback(self.room1, "dummy", 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 # Edit it right away
self.handler.edit_callback(self.room1, "dummy", 0, 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 # Check that the callback was written
callback = self.handler.get_callbacks(self.room1).get("dummy") callback = self.handler.get_callbacks(self.room1).get("dummy")
@ -103,35 +104,35 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10 self.char1.db.strength = 10
locals = {"character": self.char1} locals = {"character": self.char1}
self.assertTrue(self.handler.call( self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals)) self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 65) self.assertEqual(self.char1.db.strength, 65)
def test_edit_validation(self): def test_edit_validation(self):
"""Edit a callback when validation isn't automatic.""" """Edit a callback when validation isn't automatic."""
author = self.char1 author = self.char1
self.handler.add_callback(self.room1, "dummy", 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 # Edit it right away
self.handler.edit_callback(self.room1, "dummy", 0, 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) # Run this dummy callback (shouldn't do anything)
self.char1.db.strength = 10 self.char1.db.strength = 10
locals = {"character": self.char1} locals = {"character": self.char1}
self.assertTrue(self.handler.call( self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals)) self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 10) self.assertEqual(self.char1.db.strength, 10)
def test_del(self): def test_del(self):
"""Try to delete a callback.""" """Try to delete a callback."""
# Add 3 callbacks # Add 3 callbacks
self.handler.add_callback(self.room1, "dummy", 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", 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", 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 # Note that the second callback isn't valid
self.assertIn((self.room1, "dummy", 1), self.handler.db.to_valid) self.assertIn((self.room1, "dummy", 1), self.handler.db.to_valid)
@ -160,16 +161,16 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10 self.char1.db.strength = 10
locals = {"character": self.char1} locals = {"character": self.char1}
self.assertTrue(self.handler.call( self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals)) self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 9) self.assertEqual(self.char1.db.strength, 9)
def test_accept(self): def test_accept(self):
"""Accept an callback.""" """Accept an callback."""
# Add 2 callbacks # Add 2 callbacks
self.handler.add_callback(self.room1, "dummy", 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", 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 # Note that the second callback isn't valid
self.assertIn((self.room1, "dummy", 1), self.handler.db.to_valid) self.assertIn((self.room1, "dummy", 1), self.handler.db.to_valid)
@ -185,7 +186,7 @@ class TestEventHandler(EvenniaTest):
self.char1.db.strength = 10 self.char1.db.strength = 10
locals = {"character": self.char1} locals = {"character": self.char1}
self.assertTrue(self.handler.call( self.assertTrue(self.handler.call(
self.room1, "dummy", locals=locals)) self.room1, "dummy", locals=locals))
self.assertEqual(self.char1.db.strength, 8) self.assertEqual(self.char1.db.strength, 8)
def test_call(self): def test_call(self):
@ -201,14 +202,14 @@ class TestEventHandler(EvenniaTest):
character.db.health = 0 character.db.health = 0
""".strip("\n")) """.strip("\n"))
self.handler.add_callback(self.room1, "dummy", code, self.handler.add_callback(self.room1, "dummy", code,
author=self.char1, valid=True) author=self.char1, valid=True)
# Call the dummy callback # Call the dummy callback
self.assertTrue(self.handler.call( 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.assertEqual(self.char1.db.health, 50)
self.assertTrue(self.handler.call( 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) self.assertEqual(self.char2.db.health, 0)
def test_handler(self): def test_handler(self):
@ -217,7 +218,7 @@ class TestEventHandler(EvenniaTest):
# Add an callback # Add an callback
callback = self.room1.callbacks.add("dummy", "pass", author=self.char1, callback = self.room1.callbacks.add("dummy", "pass", author=self.char1,
valid=True) valid=True)
self.assertEqual(callback.obj, self.room1) self.assertEqual(callback.obj, self.room1)
self.assertEqual(callback.name, "dummy") self.assertEqual(callback.name, "dummy")
self.assertEqual(callback.code, "pass") self.assertEqual(callback.code, "pass")
@ -227,13 +228,13 @@ class TestEventHandler(EvenniaTest):
# Edit this very callback # Edit this very callback
new = self.room1.callbacks.edit("dummy", 0, "character.db.say = True", 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.assertIn([new], self.room1.callbacks.all().values())
self.assertNotIn([callback], self.room1.callbacks.all().values()) self.assertNotIn([callback], self.room1.callbacks.all().values())
# Try to call this callback # Try to call this callback
self.assertTrue(self.room1.callbacks.call("dummy", self.assertTrue(self.room1.callbacks.call("dummy",
locals={"character": self.char2})) locals={"character": self.char2}))
self.assertTrue(self.char2.db.say) self.assertTrue(self.char2.db.say)
# Delete the callback # Delete the callback
@ -249,7 +250,7 @@ class TestCmdCallback(CommandTest):
"""Create the callback handler.""" """Create the callback handler."""
super(TestCmdCallback, self).setUp() super(TestCmdCallback, self).setUp()
self.handler = create_script( self.handler = create_script(
"evennia.contrib.ingame_python.scripts.EventHandler") "evennia.contrib.ingame_python.scripts.EventHandler")
# Copy old events if necessary # Copy old events if necessary
if OLD_EVENTS: if OLD_EVENTS:
@ -287,7 +288,7 @@ class TestCmdCallback(CommandTest):
# Add some callback # Add some callback
self.handler.add_callback(self.exit, "traverse", "pass", 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 # Try to obtain more details on a specific callback on exit
table = self.call(CmdCallback(), "out = traverse") table = self.call(CmdCallback(), "out = traverse")
@ -355,18 +356,18 @@ class TestCmdCallback(CommandTest):
def test_del(self): def test_del(self):
"""Add and remove an callback.""" """Add and remove an callback."""
self.handler.add_callback(self.exit, "traverse", "pass", self.handler.add_callback(self.exit, "traverse", "pass",
author=self.char1, valid=True) author=self.char1, valid=True)
# Try to delete the callback # Try to delete the callback
# char2 shouldn't be allowed to do so (that's not HIS 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.call(CmdCallback(), "/del out = traverse 1", caller=self.char2)
self.assertTrue(len(self.handler.get_callbacks(self.exit).get( self.assertTrue(len(self.handler.get_callbacks(self.exit).get(
"traverse", [])) == 1) "traverse", [])) == 1)
# Now, char1 should be allowed to delete it # Now, char1 should be allowed to delete it
self.call(CmdCallback(), "/del out = traverse 1") self.call(CmdCallback(), "/del out = traverse 1")
self.assertTrue(len(self.handler.get_callbacks(self.exit).get( self.assertTrue(len(self.handler.get_callbacks(self.exit).get(
"traverse", [])) == 0) "traverse", [])) == 0)
def test_lock(self): def test_lock(self):
"""Test the lock of multiple editing.""" """Test the lock of multiple editing."""
@ -414,7 +415,7 @@ class TestDefaultCallbacks(CommandTest):
"""Create the callback handler.""" """Create the callback handler."""
super(TestDefaultCallbacks, self).setUp() super(TestDefaultCallbacks, self).setUp()
self.handler = create_script( self.handler = create_script(
"evennia.contrib.ingame_python.scripts.EventHandler") "evennia.contrib.ingame_python.scripts.EventHandler")
# Copy old events if necessary # Copy old events if necessary
if OLD_EVENTS: if OLD_EVENTS:
@ -450,7 +451,7 @@ class TestDefaultCallbacks(CommandTest):
# Try the can_traverse callback # Try the can_traverse callback
self.handler.add_callback(self.exit, "can_traverse", code, 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 # Have char1 move through the exit
self.call(ExitCommand(), "", "You can leave.", obj=self.exit) self.call(ExitCommand(), "", "You can leave.", obj=self.exit)
@ -458,13 +459,13 @@ class TestDefaultCallbacks(CommandTest):
# Have char2 move through this exit # Have char2 move through this exit
self.call(ExitCommand(), "", "You cannot leave.", obj=self.exit, self.call(ExitCommand(), "", "You cannot leave.", obj=self.exit,
caller=self.char2) caller=self.char2)
self.assertIs(self.char2.location, self.room1) self.assertIs(self.char2.location, self.room1)
# Try the traverse callback # Try the traverse callback
self.handler.del_callback(self.exit, "can_traverse", 0) self.handler.del_callback(self.exit, "can_traverse", 0)
self.handler.add_callback(self.exit, "traverse", "character.msg('Fine!')", 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 # Have char2 move through the exit
self.call(ExitCommand(), "", obj=self.exit, caller=self.char2) self.call(ExitCommand(), "", obj=self.exit, caller=self.char2)
@ -478,15 +479,15 @@ class TestDefaultCallbacks(CommandTest):
# Test msg_arrive and msg_leave # Test msg_arrive and msg_leave
code = 'message = "{character} goes out."' code = 'message = "{character} goes out."'
self.handler.add_callback(self.exit, "msg_leave", code, 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 # Have char1 move through the exit
old_msg = self.char2.msg old_msg = self.char2.msg
try: try:
self.char2.msg = Mock() self.char2.msg = Mock()
self.call(ExitCommand(), "", obj=self.exit) 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)) 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] 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 # 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] 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) returned_msg = ansi.parse_ansi("\n".join(stored_msg), strip_ansi=True)
@ -496,18 +497,18 @@ class TestDefaultCallbacks(CommandTest):
# Create a return exit # Create a return exit
back = create_object("evennia.objects.objects.DefaultExit", 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."' code = 'message = "{character} goes in."'
self.handler.add_callback(self.exit, "msg_arrive", code, 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 # Have char1 move through the exit
old_msg = self.char2.msg old_msg = self.char2.msg
try: try:
self.char2.msg = Mock() self.char2.msg = Mock()
self.call(ExitCommand(), "", obj=back) 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)) 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] 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 # 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] 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) 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. character: the character connected to this event.
""" """
@register_events @register_events
class EventCharacter(DefaultCharacter): 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] exits = [o for o in location.contents if o.location is location and o.destination is destination]
mapping = mapping or {} mapping = mapping or {}
mapping.update({ mapping.update({
"character": self, "character": self,
}) })
if exits: if exits:
exits[0].callbacks.call("msg_leave", self, exits[0], exits[0].callbacks.call("msg_leave", self, exits[0],
location, destination, string, mapping) location, destination, string, mapping)
string = exits[0].callbacks.get_variable("message") string = exits[0].callbacks.get_variable("message")
mapping = exits[0].callbacks.get_variable("mapping") mapping = exits[0].callbacks.get_variable("mapping")
@ -261,14 +262,14 @@ class EventCharacter(DefaultCharacter):
exits = [] exits = []
mapping = mapping or {} mapping = mapping or {}
mapping.update({ mapping.update({
"character": self, "character": self,
}) })
if origin: if origin:
exits = [o for o in destination.contents if o.location is destination and o.destination is origin] exits = [o for o in destination.contents if o.location is destination and o.destination is origin]
if exits: if exits:
exits[0].callbacks.call("msg_arrive", self, exits[0], exits[0].callbacks.call("msg_arrive", self, exits[0],
origin, destination, string, mapping) origin, destination, string, mapping)
string = exits[0].callbacks.get_variable("message") string = exits[0].callbacks.get_variable("message")
mapping = exits[0].callbacks.get_variable("mapping") mapping = exits[0].callbacks.get_variable("mapping")
@ -299,7 +300,7 @@ class EventCharacter(DefaultCharacter):
Room = DefaultRoom Room = DefaultRoom
if isinstance(origin, Room) and isinstance(destination, Room): if isinstance(origin, Room) and isinstance(destination, Room):
can = self.callbacks.call("can_move", self, can = self.callbacks.call("can_move", self,
origin, destination) origin, destination)
if can: if can:
can = origin.callbacks.call("can_move", self, origin) can = origin.callbacks.call("can_move", self, origin)
if can: if can:
@ -489,6 +490,7 @@ Variables you can use in this event:
destination: the character's location after moving. destination: the character's location after moving.
""" """
@register_events @register_events
class EventExit(DefaultExit): class EventExit(DefaultExit):
@ -520,7 +522,7 @@ class EventExit(DefaultExit):
is_character = inherits_from(traversing_object, DefaultCharacter) is_character = inherits_from(traversing_object, DefaultCharacter)
if is_character: if is_character:
allow = self.callbacks.call("can_traverse", traversing_object, allow = self.callbacks.call("can_traverse", traversing_object,
self, self.location) self, self.location)
if not allow: if not allow:
return return
@ -529,7 +531,7 @@ class EventExit(DefaultExit):
# After traversing # After traversing
if is_character: if is_character:
self.callbacks.call("traverse", traversing_object, self.callbacks.call("traverse", traversing_object,
self, self.location, self.destination) self, self.location, self.destination)
# Object help # Object help
@ -573,6 +575,7 @@ Variables you can use in this event:
object: the object connected to this event. object: the object connected to this event.
""" """
@register_events @register_events
class EventObject(DefaultObject): class EventObject(DefaultObject):
@ -621,6 +624,7 @@ class EventObject(DefaultObject):
super(EventObject, self).at_drop(dropper) super(EventObject, self).at_drop(dropper)
self.callbacks.call("drop", dropper, self) self.callbacks.call("drop", dropper, self)
# Room help # Room help
ROOM_CAN_DELETE = """ ROOM_CAN_DELETE = """
Can the room be deleted? Can the room be deleted?
@ -742,6 +746,7 @@ Variables you can use in this event:
room: the room connected to this event. room: the room connected to this event.
""" """
@register_events @register_events
class EventRoom(DefaultRoom): class EventRoom(DefaultRoom):
@ -792,7 +797,7 @@ class EventRoom(DefaultRoom):
""" """
allow = self.callbacks.call("can_say", speaker, self, message, allow = self.callbacks.call("can_say", speaker, self, message,
parameters=message) parameters=message)
if not allow: if not allow:
return return
@ -802,7 +807,7 @@ class EventRoom(DefaultRoom):
for present in [o for o in self.contents if isinstance( for present in [o for o in self.contents if isinstance(
o, DefaultCharacter) and o is not speaker]: o, DefaultCharacter) and o is not speaker]:
allow = present.callbacks.call("can_say", speaker, present, allow = present.callbacks.call("can_say", speaker, present,
message, parameters=message) message, parameters=message)
if not allow: if not allow:
return return
@ -811,10 +816,10 @@ class EventRoom(DefaultRoom):
# We force the next event to be called after the message # We force the next event to be called after the message
# This will have to change when the Evennia API adds new hooks # This will have to change when the Evennia API adds new hooks
delay(0, self.callbacks.call, "say", speaker, self, message, delay(0, self.callbacks.call, "say", speaker, self, message,
parameters=message) parameters=message)
for present in [o for o in self.contents if isinstance( for present in [o for o in self.contents if isinstance(
o, DefaultCharacter) and o is not speaker]: o, DefaultCharacter) and o is not speaker]:
delay(0, present.callbacks.call, "say", speaker, present, message, delay(0, present.callbacks.call, "say", speaker, present, message,
parameters=message) parameters=message)
return 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 # Temporary storage for events waiting for the script to be started
EVENTS = [] EVENTS = []
def get_event_handler(): def get_event_handler():
"""Return the event handler or None.""" """Return the event handler or None."""
try: try:
@ -30,6 +31,7 @@ def get_event_handler():
return script return script
def register_events(path_or_typeclass): def register_events(path_or_typeclass):
""" """
Register the events in this typeclass. Register the events in this typeclass.
@ -84,6 +86,8 @@ def register_events(path_or_typeclass):
return typeclass return typeclass
# Custom callbacks for specific event types # Custom callbacks for specific event types
def get_next_wait(format): def get_next_wait(format):
""" """
Get the length of time in seconds before format. Get the length of time in seconds before format.
@ -104,8 +108,8 @@ def get_next_wait(format):
""" """
calendar = getattr(settings, "EVENTS_CALENDAR", None) calendar = getattr(settings, "EVENTS_CALENDAR", None)
if calendar is None: if calendar is None:
logger.log_err("A time-related event has been set whereas " \ logger.log_err("A time-related event has been set whereas "
"the gametime calendar has not been set in the settings.") "the gametime calendar has not been set in the settings.")
return return
elif calendar == "standard": elif calendar == "standard":
rsu = standard_rsu rsu = standard_rsu
@ -131,8 +135,8 @@ def get_next_wait(format):
break break
if not piece.isdigit(): if not piece.isdigit():
logger.log_trace("The time specified '{}' in {} isn't " \ logger.log_trace("The time specified '{}' in {} isn't "
"a valid number".format(piece, format)) "a valid number".format(piece, format))
return return
# Convert the piece to int # Convert the piece to int
@ -154,6 +158,7 @@ def get_next_wait(format):
usual = gametime_to_realtime(**kwargs) usual = gametime_to_realtime(**kwargs)
return until, usual, details return until, usual, details
def time_event(obj, event_name, number, parameters): def time_event(obj, event_name, number, parameters):
""" """
Create a time-related event. Create a time-related event.
@ -173,6 +178,7 @@ def time_event(obj, event_name, number, parameters):
script.db.number = number script.db.number = number
script.ndb.usual = usual script.ndb.usual = usual
def keyword_event(callbacks, parameters): def keyword_event(callbacks, parameters):
""" """
Custom call for events with keywords (like push, or pull, or turn...). Custom call for events with keywords (like push, or pull, or turn...).
@ -201,6 +207,7 @@ def keyword_event(callbacks, parameters):
return to_call return to_call
def phrase_event(callbacks, parameters): def phrase_event(callbacks, parameters):
""" """
Custom call for events with keywords in sentences (like say or whisper). Custom call for events with keywords in sentences (like say or whisper).
@ -236,6 +243,7 @@ def phrase_event(callbacks, parameters):
return to_call return to_call
class InterruptEvent(RuntimeError): class InterruptEvent(RuntimeError):
""" """

View file

@ -22,6 +22,7 @@ _HEAD_CHAR = "|015-|n"
_SUB_HEAD_CHAR = "-" _SUB_HEAD_CHAR = "-"
_WIDTH = 78 _WIDTH = 78
class CmdMail(default_cmds.MuxCommand): class CmdMail(default_cmds.MuxCommand):
""" """
Commands that allow either IC or OOC communications Commands that allow either IC or OOC communications
@ -253,4 +254,3 @@ class CmdMail(default_cmds.MuxCommand):
self.caller.msg(_HEAD_CHAR * _WIDTH) self.caller.msg(_HEAD_CHAR * _WIDTH)
else: else:
self.caller.msg("There are no messages in your inbox.") 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. # This is generally mandatory.
return room return room
# Include your trigger characters and build functions in a legend dict. # Include your trigger characters and build functions in a legend dict.
EXAMPLE1_LEGEND = {("", ""): example1_build_forest, EXAMPLE1_LEGEND = {("", ""): example1_build_forest,
("", "n"): example1_build_mountains, ("", "n"): example1_build_mountains,
@ -225,17 +226,17 @@ def example2_build_verticle_exit(x, y, **kwargs):
if kwargs["iteration"] == 0: if kwargs["iteration"] == 0:
return return
north_room = kwargs["room_dict"][(x, y-1)] north_room = kwargs["room_dict"][(x, y - 1)]
south_room = kwargs["room_dict"][(x, y+1)] south_room = kwargs["room_dict"][(x, y + 1)]
# create exits in the rooms # create exits in the rooms
create_object(exits.Exit, key="south", create_object(exits.Exit, key="south",
aliases=["s"], location=north_room, aliases=["s"], location=north_room,
destination=south_room) destination=south_room)
create_object(exits.Exit, key="north", create_object(exits.Exit, key="north",
aliases=["n"], location=south_room, aliases=["n"], location=south_room,
destination=north_room) destination=north_room)
kwargs["caller"].msg("Connected: " + north_room.key + kwargs["caller"].msg("Connected: " + north_room.key +
" & " + south_room.key) " & " + south_room.key)
@ -247,20 +248,21 @@ def example2_build_horizontal_exit(x, y, **kwargs):
if kwargs["iteration"] == 0: if kwargs["iteration"] == 0:
return return
west_room = kwargs["room_dict"][(x-1, y)] west_room = kwargs["room_dict"][(x - 1, y)]
east_room = kwargs["room_dict"][(x+1, y)] east_room = kwargs["room_dict"][(x + 1, y)]
create_object(exits.Exit, key="east", create_object(exits.Exit, key="east",
aliases=["e"], location=west_room, aliases=["e"], location=west_room,
destination=east_room) destination=east_room)
create_object(exits.Exit, key="west", create_object(exits.Exit, key="west",
aliases=["w"], location=east_room, aliases=["w"], location=east_room,
destination=west_room) destination=west_room)
kwargs["caller"].msg("Connected: " + west_room.key + kwargs["caller"].msg("Connected: " + west_room.key +
" & " + east_room.key) " & " + east_room.key)
# Include your trigger characters and build functions in a legend dict. # Include your trigger characters and build functions in a legend dict.
EXAMPLE2_LEGEND = {("", ""): example2_build_forest, EXAMPLE2_LEGEND = {("", ""): example2_build_forest,
("|"): example2_build_verticle_exit, ("|"): example2_build_verticle_exit,
@ -339,37 +341,38 @@ def build_map(caller, game_map, legend, iterations=1, build_exits=True):
y = loc_key[1] y = loc_key[1]
# north # north
if (x, y-1) in room_dict: if (x, y - 1) in room_dict:
if room_dict[(x, y-1)]: if room_dict[(x, y - 1)]:
create_object(exits.Exit, key="north", create_object(exits.Exit, key="north",
aliases=["n"], location=location, aliases=["n"], location=location,
destination=room_dict[(x, y-1)]) destination=room_dict[(x, y - 1)])
# east # east
if (x+1, y) in room_dict: if (x + 1, y) in room_dict:
if room_dict[(x+1, y)]: if room_dict[(x + 1, y)]:
create_object(exits.Exit, key="east", create_object(exits.Exit, key="east",
aliases=["e"], location=location, aliases=["e"], location=location,
destination=room_dict[(x+1, y)]) destination=room_dict[(x + 1, y)])
# south # south
if (x, y+1) in room_dict: if (x, y + 1) in room_dict:
if room_dict[(x, y+1)]: if room_dict[(x, y + 1)]:
create_object(exits.Exit, key="south", create_object(exits.Exit, key="south",
aliases=["s"], location=location, aliases=["s"], location=location,
destination=room_dict[(x, y+1)]) destination=room_dict[(x, y + 1)])
# west # west
if (x-1, y) in room_dict: if (x - 1, y) in room_dict:
if room_dict[(x-1, y)]: if room_dict[(x - 1, y)]:
create_object(exits.Exit, key="west", create_object(exits.Exit, key="west",
aliases=["w"], location=location, aliases=["w"], location=location,
destination=room_dict[(x-1, y)]) destination=room_dict[(x - 1, y)])
caller.msg("Map Created.") caller.msg("Map Created.")
# access command # access command
class CmdMapBuilder(COMMAND_DEFAULT_CLASS): class CmdMapBuilder(COMMAND_DEFAULT_CLASS):
""" """
Build a map from a 2D ASCII map. 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. # Pass map and legend to the build function.
build_map(caller, game_map, legend, iterations, build_exits) 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 permissions = settings.PERMISSION_ACCOUNT_DEFAULT
typeclass = settings.BASE_CHARACTER_TYPECLASS typeclass = settings.BASE_CHARACTER_TYPECLASS
new_account = unloggedin._create_account(caller, accountname, new_account = unloggedin._create_account(caller, accountname,
password, permissions) password, permissions)
if new_account: if new_account:
if settings.MULTISESSION_MODE < 2: if settings.MULTISESSION_MODE < 2:
default_home = ObjectDB.objects.get_id( 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 # eveditor save/load/quit functions
def _save_editor(caller, buffer): def _save_editor(caller, buffer):
"Called when the editor saves its contents" "Called when the editor saves its contents"
key = caller.db._multidesc_editkey key = caller.db._multidesc_editkey
@ -104,6 +105,7 @@ def _save_editor(caller, buffer):
caller.msg("Saved description to key '%s'." % key) caller.msg("Saved description to key '%s'." % key)
return True return True
def _load_editor(caller): def _load_editor(caller):
"Called when the editor loads contents" "Called when the editor loads contents"
key = caller.db._multidesc_editkey key = caller.db._multidesc_editkey
@ -112,6 +114,7 @@ def _load_editor(caller):
return caller.db.multidesc[match[0]][1] return caller.db.multidesc[match[0]][1]
return "" return ""
def _quit_editor(caller): def _quit_editor(caller):
"Called when the editor quits" "Called when the editor quits"
del caller.db._multidesc_editkey del caller.db._multidesc_editkey
@ -161,13 +164,13 @@ class CmdMultiDesc(default_cmds.MuxCommand):
# list all stored descriptions, either in full or cropped. # list all stored descriptions, either in full or cropped.
# Note that we list starting from 1, not from 0. # Note that we list starting from 1, not from 0.
_update_store(caller) _update_store(caller)
do_crop = not "full" in switches do_crop = "full" not in switches
if do_crop: if do_crop:
outtext = ["|w%s:|n %s" % (key, crop(desc)) outtext = ["|w%s:|n %s" % (key, crop(desc))
for key, desc in caller.db.multidesc] for key, desc in caller.db.multidesc]
else: else:
outtext = ["\n|w%s:|n|n\n%s\n%s" % (key, "-" * (len(key) + 1), desc) 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)) caller.msg("|wStored descs:|n\n" + "\n".join(outtext))
return return
@ -249,6 +252,6 @@ class CmdMultiDesc(default_cmds.MuxCommand):
else: else:
caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc) caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc)
except DescValidateError, err: except DescValidateError as err:
# This is triggered by _key_to_index # This is triggered by _key_to_index
caller.msg(err) caller.msg(err)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -64,6 +64,7 @@ class TestLanguage(EvenniaTest):
# Testing of emoting / sdesc / recog system # Testing of emoting / sdesc / recog system
from evennia import create_object from evennia import create_object
from evennia.contrib import rpsystem from evennia.contrib import rpsystem
@ -176,6 +177,7 @@ from evennia.contrib import extended_room
from evennia import gametime from evennia import gametime
from evennia.objects.objects import DefaultRoom from evennia.objects.objects import DefaultRoom
class ForceUTCDatetime(datetime.datetime): class ForceUTCDatetime(datetime.datetime):
"""Force UTC datetime.""" """Force UTC datetime."""
@ -185,6 +187,7 @@ class ForceUTCDatetime(datetime.datetime):
"""Force fromtimestamp to run with naive datetimes.""" """Force fromtimestamp to run with naive datetimes."""
return datetime.datetime.utcfromtimestamp(timestamp) return datetime.datetime.utcfromtimestamp(timestamp)
@patch('evennia.contrib.extended_room.datetime.datetime', ForceUTCDatetime) @patch('evennia.contrib.extended_room.datetime.datetime', ForceUTCDatetime)
class TestExtendedRoom(CommandTest): class TestExtendedRoom(CommandTest):
room_typeclass = extended_room.ExtendedRoom room_typeclass = extended_room.ExtendedRoom
@ -208,7 +211,7 @@ class TestExtendedRoom(CommandTest):
old_desc = DefaultRoom.return_appearance(self.room1, self.char1) old_desc = DefaultRoom.return_appearance(self.room1, self.char1)
# the new appearance should be the old one, but with the desc switched # 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.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("spring", self.room1.ndb.last_season)
self.assertEqual("evening", self.room1.ndb.last_timeslot) self.assertEqual("evening", self.room1.ndb.last_timeslot)
@ -223,7 +226,7 @@ class TestExtendedRoom(CommandTest):
def test_cmdextendeddesc(self): def test_cmdextendeddesc(self):
self.call(extended_room.CmdExtendedDesc(), "", "Details on Room", cmdstring="detail") self.call(extended_room.CmdExtendedDesc(), "", "Details on Room", cmdstring="detail")
self.call(extended_room.CmdExtendedDesc(), "thingie = newdetail with spaces", 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(), "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(), "/del thingie", "Detail thingie deleted, if it existed.", cmdstring="detail")
self.call(extended_room.CmdExtendedDesc(), "thingie", "Detail 'thingie' not found.", 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 from evennia.contrib import barter
class TestBarter(CommandTest): class TestBarter(CommandTest):
def setUp(self): 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(), "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(), "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.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.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.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.") self.call(barter.CmdDecline(), "", "Your trade action: You change your mind, declining the current offer.")
@ -319,9 +323,11 @@ class TestBarter(CommandTest):
# Test wilderness # Test wilderness
from evennia.contrib import wilderness from evennia.contrib import wilderness
from evennia import DefaultCharacter from evennia import DefaultCharacter
class TestWilderness(EvenniaTest): class TestWilderness(EvenniaTest):
def setUp(self): def setUp(self):
@ -372,8 +378,8 @@ class TestWilderness(EvenniaTest):
# be visible / traversable # be visible / traversable
exits = [i for i in self.char1.location.contents exits = [i for i in self.char1.location.contents
if i.destination and ( if i.destination and (
i.access(self.char1, "view") or i.access(self.char1, "view") or
i.access(self.char1, "traverse"))] i.access(self.char1, "traverse"))]
self.assertEquals(len(exits), 3) self.assertEquals(len(exits), 3)
exitsok = ["north", "northeast", "east"] exitsok = ["north", "northeast", "east"]
@ -385,8 +391,8 @@ class TestWilderness(EvenniaTest):
wilderness.enter_wilderness(self.char1, coordinates=(1, 1)) wilderness.enter_wilderness(self.char1, coordinates=(1, 1))
exits = [i for i in self.char1.location.contents exits = [i for i in self.char1.location.contents
if i.destination and ( if i.destination and (
i.access(self.char1, "view") or i.access(self.char1, "view") or
i.access(self.char1, "traverse"))] i.access(self.char1, "traverse"))]
self.assertEquals(len(exits), 8) self.assertEquals(len(exits), 8)
exitsok = ["north", "northeast", "east", "southeast", "south", exitsok = ["north", "northeast", "east", "southeast", "south",
"southwest", "west", "northwest"] "southwest", "west", "northwest"]
@ -438,9 +444,11 @@ class TestWilderness(EvenniaTest):
new_loc = wilderness.get_new_coordinates(loc, direction) new_loc = wilderness.get_new_coordinates(loc, direction)
self.assertEquals(new_loc, correct_loc, direction) self.assertEquals(new_loc, correct_loc, direction)
# Testing chargen contrib # Testing chargen contrib
from evennia.contrib import chargen from evennia.contrib import chargen
class TestChargen(CommandTest): class TestChargen(CommandTest):
def test_ooclook(self): 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", "The character testchar was successfully created!", caller=self.account)
self.call(chargen.CmdOOCCharacterCreate(), "testchar", "Character testchar already exists.", caller=self.account) self.call(chargen.CmdOOCCharacterCreate(), "testchar", "Character testchar already exists.", caller=self.account)
self.assertTrue(self.account.db._character_dbrefs) 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) self.call(chargen.CmdOOCLook(), "testchar", "testchar(", caller=self.account)
# Testing clothing contrib # Testing clothing contrib
from evennia.contrib import clothing from evennia.contrib import clothing
from evennia.objects.objects import DefaultRoom from evennia.objects.objects import DefaultRoom
class TestClothingCmd(CommandTest): class TestClothingCmd(CommandTest):
def test_clothingcommands(self): def test_clothingcommands(self):
@ -501,6 +511,7 @@ class TestClothingCmd(CommandTest):
# Test inventory command. # Test inventory command.
self.call(clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=wearer) self.call(clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=wearer)
class TestClothingFunc(EvenniaTest): class TestClothingFunc(EvenniaTest):
def test_clothingfunctions(self): def test_clothingfunctions(self):
@ -537,42 +548,50 @@ class TestClothingFunc(EvenniaTest):
test_pants.wear(wearer, True) test_pants.wear(wearer, True)
self.assertEqual(clothing.get_worn_clothes(wearer), [test_hat, test_pants]) 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) self.assertEqual(clothing.single_type_count(clothes_list, 'hat'), 1)
# Testing custom_gametime # Testing custom_gametime
from evennia.contrib import custom_gametime from evennia.contrib import custom_gametime
def _testcallback(): def _testcallback():
pass pass
class TestCustomGameTime(EvenniaTest): class TestCustomGameTime(EvenniaTest):
def setUp(self): def setUp(self):
super(TestCustomGameTime, self).setUp() 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): def tearDown(self):
if hasattr(self, "timescript"): if hasattr(self, "timescript"):
self.timescript.stop() self.timescript.stop()
def test_time_to_tuple(self): 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, 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(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(100000, 239, 24, 3), (418, 4, 0, 2))
def test_gametime_to_realtime(self): 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(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): 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), 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(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)) 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): def test_custom_gametime(self):
self.assertEqual(custom_gametime.custom_gametime(), (102, 5, 2, 6, 21, 8, 18)) 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)) self.assertEqual(custom_gametime.custom_gametime(absolute=True), (102, 5, 2, 6, 21, 8, 18))
def test_real_seconds_until(self): def test_real_seconds_until(self):
self.assertEqual(custom_gametime.real_seconds_until(year=2300, month=11, day=6), 31911667199.77) self.assertEqual(custom_gametime.real_seconds_until(year=2300, month=11, day=6), 31911667199.77)
def test_schedule(self): def test_schedule(self):
self.timescript = custom_gametime.schedule(_testcallback, repeat=True, min=5, sec=0) self.timescript = custom_gametime.schedule(_testcallback, repeat=True, min=5, sec=0)
self.assertEqual(self.timescript.interval, 1700.7699999809265) self.assertEqual(self.timescript.interval, 1700.7699999809265)
@ -585,9 +604,10 @@ class TestDice(CommandTest):
def test_roll_dice(self, mocked_randint): def test_roll_dice(self, mocked_randint):
# we must import dice here for the mocked randint to apply correctly. # we must import dice here for the mocked randint to apply correctly.
from evennia.contrib import dice 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=('<', 35)), True)
self.assertEqual(dice.roll_dice(6, 6, conditional=('>', 33)), False) self.assertEqual(dice.roll_dice(6, 6, conditional=('>', 33)), False)
def test_cmddice(self, mocked_randint): def test_cmddice(self, mocked_randint):
from evennia.contrib import dice 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.") 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 # Test email-login
from evennia.contrib import email_login from evennia.contrib import email_login
class TestEmailLogin(CommandTest): class TestEmailLogin(CommandTest):
def test_connect(self): 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.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.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]) self.call(email_login.CmdUnconnectedConnect(), "mytest@test.com test11111", "", caller=self.account.sessions.get()[0])
def test_quit(self): def test_quit(self):
self.call(email_login.CmdUnconnectedQuit(), "", "", caller=self.account.sessions.get()[0]) self.call(email_login.CmdUnconnectedQuit(), "", "", caller=self.account.sessions.get()[0])
def test_unconnectedlook(self): def test_unconnectedlook(self):
self.call(email_login.CmdUnconnectedLook(), "", "==========") self.call(email_login.CmdUnconnectedLook(), "", "==========")
def test_unconnectedhelp(self): def test_unconnectedhelp(self):
self.call(email_login.CmdUnconnectedHelp(), "", "You are not yet logged into the game.") self.call(email_login.CmdUnconnectedHelp(), "", "You are not yet logged into the game.")
# test gendersub contrib # test gendersub contrib
from evennia.contrib import gendersub from evennia.contrib import gendersub
class TestGenderSub(CommandTest): class TestGenderSub(CommandTest):
def test_setgender(self): def test_setgender(self):
self.call(gendersub.SetGender(), "male", "Your gender was set to male.") 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(), "ambiguous", "Your gender was set to ambiguous.")
self.call(gendersub.SetGender(), "Foo", "Usage: @gender") self.call(gendersub.SetGender(), "Foo", "Usage: @gender")
def test_gendercharacter(self): def test_gendercharacter(self):
char = create_object(gendersub.GenderCharacter, key="Gendered", location=self.room1) char = create_object(gendersub.GenderCharacter, key="Gendered", location=self.room1)
txt = "Test |p gender" txt = "Test |p gender"
@ -626,8 +654,10 @@ class TestGenderSub(CommandTest):
# test mail contrib # test mail contrib
from evennia.contrib import mail from evennia.contrib import mail
class TestMail(CommandTest): class TestMail(CommandTest):
def test_mail(self): def test_mail(self):
self.call(mail.CmdMail(), "2", "'2' is not a valid mail id.", caller=self.account) 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 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(), "Char=Message 2", "You sent your message.", caller=self.char2)
self.call(mail.CmdMail(), "TestAccount2=Message 2", 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 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(), "TestAccount=Message 2", "You sent your message.", caller=self.account2)
self.call(mail.CmdMail(), "", "| ID: From: Subject:", caller=self.account) self.call(mail.CmdMail(), "", "| ID: From: Subject:", caller=self.account)
@ -646,21 +676,23 @@ class TestMail(CommandTest):
# test map builder contrib # test map builder contrib
from evennia.contrib import mapbuilder from evennia.contrib import mapbuilder
class TestMapBuilder(CommandTest): class TestMapBuilder(CommandTest):
def test_cmdmapbuilder(self): def test_cmdmapbuilder(self):
self.call(mapbuilder.CmdMapBuilder(), self.call(mapbuilder.CmdMapBuilder(),
"evennia.contrib.mapbuilder.EXAMPLE1_MAP evennia.contrib.mapbuilder.EXAMPLE1_LEGEND", "evennia.contrib.mapbuilder.EXAMPLE1_MAP evennia.contrib.mapbuilder.EXAMPLE1_LEGEND",
"""Creating Map...|≈≈≈≈≈ """Creating Map...|≈≈≈≈≈
n n
n n
|Creating Landmass...|""") |Creating Landmass...|""")
self.call(mapbuilder.CmdMapBuilder(), self.call(mapbuilder.CmdMapBuilder(),
"evennia.contrib.mapbuilder.EXAMPLE2_MAP evennia.contrib.mapbuilder.EXAMPLE2_LEGEND", "evennia.contrib.mapbuilder.EXAMPLE2_MAP evennia.contrib.mapbuilder.EXAMPLE2_LEGEND",
"""Creating Map...|≈ ≈ ≈ ≈ ≈ """Creating Map...|≈ ≈ ≈ ≈ ≈
@ -674,6 +706,7 @@ class TestMapBuilder(CommandTest):
from evennia.contrib import menu_login from evennia.contrib import menu_login
class TestMenuLogin(CommandTest): class TestMenuLogin(CommandTest):
def test_cmdunloggedlook(self): def test_cmdunloggedlook(self):
self.call(menu_login.CmdUnloggedinLook(), "", "======") self.call(menu_login.CmdUnloggedinLook(), "", "======")
@ -683,28 +716,31 @@ class TestMenuLogin(CommandTest):
from evennia.contrib import multidescer from evennia.contrib import multidescer
class TestMultidescer(CommandTest): class TestMultidescer(CommandTest):
def test_cmdmultidesc(self): def test_cmdmultidesc(self):
self.call(multidescer.CmdMultiDesc(),"/list", "Stored descs:\ncaller:") self.call(multidescer.CmdMultiDesc(), "/list", "Stored descs:\ncaller:")
self.call(multidescer.CmdMultiDesc(),"test = Desc 1", "Stored description 'test': \"Desc 1\"") 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(), "test2 = Desc 2", "Stored description 'test2': \"Desc 2\"")
self.call(multidescer.CmdMultiDesc(),"/swap test-test2", "Swapped descs 'test' and 'test2'.") 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(), "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(), "/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(), "test3 = Desc 3", "Stored description 'test3': \"Desc 3\"")
self.call(multidescer.CmdMultiDesc(),"/set test1 + test2 + + test3", "test1 Desc 2 Desc 3\n\n" self.call(multidescer.CmdMultiDesc(), "/set test1 + test2 + + test3", "test1 Desc 2 Desc 3\n\n"
"The above was set as the current description.") "The above was set as the current description.")
self.assertEqual(self.char1.db.desc, "test1 Desc 2 Desc 3") self.assertEqual(self.char1.db.desc, "test1 Desc 2 Desc 3")
# test simpledoor contrib # test simpledoor contrib
from evennia.contrib import simpledoor from evennia.contrib import simpledoor
class TestSimpleDoor(CommandTest): class TestSimpleDoor(CommandTest):
def test_cmdopen(self): def test_cmdopen(self):
self.call(simpledoor.CmdOpen(), "newdoor;door:contrib.simpledoor.SimpleDoor,backdoor;door = Room2", 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 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 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", "You close newdoor.", cmdstring="close")
self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "newdoor is already closed.", cmdstring="close") self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "newdoor is already closed.", cmdstring="close")
self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "You open newdoor.", cmdstring="open") self.call(simpledoor.CmdOpenCloseDoor(), "newdoor", "You open newdoor.", cmdstring="open")
@ -712,8 +748,10 @@ class TestSimpleDoor(CommandTest):
# test slow_exit contrib # test slow_exit contrib
from evennia.contrib import slow_exit 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): class TestSlowExit(CommandTest):
def test_exit(self): def test_exit(self):
@ -724,12 +762,14 @@ class TestSlowExit(CommandTest):
# test talking npc contrib # test talking npc contrib
from evennia.contrib import talking_npc from evennia.contrib import talking_npc
class TestTalkingNPC(CommandTest): class TestTalkingNPC(CommandTest):
def test_talkingnpc(self): def test_talkingnpc(self):
npc = create_object(talking_npc.TalkingNPC, key="npctalker", location=self.room1) 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() npc.delete()
@ -739,6 +779,7 @@ class TestTalkingNPC(CommandTest):
from evennia.contrib.tutorial_world import mob from evennia.contrib.tutorial_world import mob
class TestTutorialWorldMob(EvenniaTest): class TestTutorialWorldMob(EvenniaTest):
def test_mob(self): def test_mob(self):
mobobj = create_object(mob.Mob, key="mob") mobobj = create_object(mob.Mob, key="mob")
@ -748,28 +789,34 @@ class TestTutorialWorldMob(EvenniaTest):
mobobj.set_dead() mobobj.set_dead()
self.assertEqual(mobobj.db.is_dead, True) self.assertEqual(mobobj.db.is_dead, True)
mobobj._set_ticker(0, "foo", stop=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 # test tutorial_world/objects
from evennia.contrib.tutorial_world import objects as tutobjects from evennia.contrib.tutorial_world import objects as tutobjects
class TestTutorialWorldObjects(CommandTest): class TestTutorialWorldObjects(CommandTest):
def test_tutorialobj(self): def test_tutorialobj(self):
obj1 = create_object(tutobjects.TutorialObject, key="tutobj") obj1 = create_object(tutobjects.TutorialObject, key="tutobj")
obj1.reset() obj1.reset()
self.assertEqual(obj1.location, obj1.home) self.assertEqual(obj1.location, obj1.home)
def test_readable(self): def test_readable(self):
readable = create_object(tutobjects.Readable, key="book", location=self.room1) readable = create_object(tutobjects.Readable, key="book", location=self.room1)
readable.db.readable_text = "Text to read" 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): def test_climbable(self):
climbable = create_object(tutobjects.Climbable, key="tree", location=self.room1) 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.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") self.assertEqual(self.char1.tags.get("tutorial_climbed_tree", category="tutorial_world"), "tutorial_climbed_tree")
def test_obelisk(self): def test_obelisk(self):
obelisk = create_object(tutobjects.Obelisk, key="obelisk", location=self.room1) obelisk = create_object(tutobjects.Obelisk, key="obelisk", location=self.room1)
self.assertEqual(obelisk.return_appearance(self.char1).startswith("|cobelisk("), True) self.assertEqual(obelisk.return_appearance(self.char1).startswith("|cobelisk("), True)
def test_lightsource(self): def test_lightsource(self):
light = create_object(tutobjects.LightSource, key="torch", location=self.room1) light = create_object(tutobjects.LightSource, key="torch", location=self.room1)
self.call(tutobjects.CmdLight(), "", "You light torch.", obj=light) self.call(tutobjects.CmdLight(), "", "You light torch.", obj=light)
@ -777,39 +824,44 @@ class TestTutorialWorldObjects(CommandTest):
if hasattr(light, "deferred"): if hasattr(light, "deferred"):
light.deferred.cancel() light.deferred.cancel()
self.assertFalse(light.pk) self.assertFalse(light.pk)
def test_crumblingwall(self): def test_crumblingwall(self):
wall = create_object(tutobjects.CrumblingWall, key="wall", location=self.room1) wall = create_object(tutobjects.CrumblingWall, key="wall", location=self.room1)
self.assertFalse(wall.db.button_exposed) self.assertFalse(wall.db.button_exposed)
self.assertFalse(wall.db.exit_open) 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", 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", 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", 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", 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(), "", 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.button_exposed)
self.assertTrue(wall.db.exit_open) self.assertTrue(wall.db.exit_open)
wall.reset() wall.reset()
if hasattr(wall, "deferred"): if hasattr(wall, "deferred"):
wall.deferred.cancel() wall.deferred.cancel()
wall.delete() wall.delete()
def test_weapon(self): def test_weapon(self):
weapon = create_object(tutobjects.Weapon, key="sword", location=self.char1) 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 stab with sword.", obj=weapon, cmdstring="stab")
self.call(tutobjects.CmdAttack(), "Char", "You slash with sword.", obj=weapon, cmdstring="slash") self.call(tutobjects.CmdAttack(), "Char", "You slash with sword.", obj=weapon, cmdstring="slash")
def test_weaponrack(self): def test_weaponrack(self):
rack = create_object(tutobjects.WeaponRack, key="rack", location=self.room1) rack = create_object(tutobjects.WeaponRack, key="rack", location=self.room1)
rack.db.available_weapons = ["sword"] rack.db.available_weapons = ["sword"]
self.call(tutobjects.CmdGetWeapon(), "", "You find Rusty sword.", obj=rack) self.call(tutobjects.CmdGetWeapon(), "", "You find Rusty sword.", obj=rack)
# test tutorial_world/ # test tutorial_world/
from evennia.contrib.tutorial_world import rooms as tutrooms from evennia.contrib.tutorial_world import rooms as tutrooms
class TestTutorialWorldRooms(CommandTest): class TestTutorialWorldRooms(CommandTest):
def test_cmdtutorial(self): def test_cmdtutorial(self):
room = create_object(tutrooms.TutorialRoom, key="tutroom") 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(), "detail", "A detail", obj=room)
self.call(tutrooms.CmdTutorialLook(), "foo", "A detail", obj=room) self.call(tutrooms.CmdTutorialLook(), "foo", "A detail", obj=room)
room.delete() room.delete()
def test_weatherroom(self): def test_weatherroom(self):
room = create_object(tutrooms.WeatherRoom, key="weatherroom") room = create_object(tutrooms.WeatherRoom, key="weatherroom")
room.update_weather() room.update_weather()
tutrooms.TICKER_HANDLER.remove(interval=room.db.interval, callback=room.update_weather, idstring="tutorial") tutrooms.TICKER_HANDLER.remove(interval=room.db.interval, callback=room.update_weather, idstring="tutorial")
room.delete() room.delete()
def test_introroom(self): def test_introroom(self):
room = create_object(tutrooms.IntroRoom, key="introroom") room = create_object(tutrooms.IntroRoom, key="introroom")
room.at_object_receive(self.char1, self.room1) room.at_object_receive(self.char1, self.room1)
def test_bridgeroom(self): def test_bridgeroom(self):
room = create_object(tutrooms.BridgeRoom, key="bridgeroom") room = create_object(tutrooms.BridgeRoom, key="bridgeroom")
room.update_weather() room.update_weather()
@ -837,19 +892,24 @@ class TestTutorialWorldRooms(CommandTest):
room.at_object_leave(self.char1, self.room1) room.at_object_leave(self.char1, self.room1)
tutrooms.TICKER_HANDLER.remove(interval=room.db.interval, callback=room.update_weather, idstring="tutorial") tutrooms.TICKER_HANDLER.remove(interval=room.db.interval, callback=room.update_weather, idstring="tutorial")
room.delete() room.delete()
def test_darkroom(self): def test_darkroom(self):
room = create_object(tutrooms.DarkRoom, key="darkroom") room = create_object(tutrooms.DarkRoom, key="darkroom")
self.char1.move_to(room) self.char1.move_to(room)
self.call(tutrooms.CmdDarkHelp(), "", "Can't help you until") self.call(tutrooms.CmdDarkHelp(), "", "Can't help you until")
def test_teleportroom(self): def test_teleportroom(self):
create_object(tutrooms.TeleportRoom, key="teleportroom") create_object(tutrooms.TeleportRoom, key="teleportroom")
def test_outroroom(self): def test_outroroom(self):
create_object(tutrooms.OutroRoom, key="outroroom") create_object(tutrooms.OutroRoom, key="outroroom")
# test turnbattle # test turnbattle
from evennia.contrib import turnbattle from evennia.contrib import turnbattle
from evennia.objects.objects import DefaultRoom from evennia.objects.objects import DefaultRoom
class TestTurnBattleCmd(CommandTest): class TestTurnBattleCmd(CommandTest):
# Test combat commands # 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.CmdDisengage(), "", "You can only do that in combat. (see: help fight)")
self.call(turnbattle.CmdRest(), "", "Char rests to recover HP.") self.call(turnbattle.CmdRest(), "", "Char rests to recover HP.")
class TestTurnBattleFunc(EvenniaTest): class TestTurnBattleFunc(EvenniaTest):
# Test combat functions # Test combat functions
@ -944,6 +1005,7 @@ class TestTurnBattleFunc(EvenniaTest):
from evennia.contrib.unixcommand import UnixCommand from evennia.contrib.unixcommand import UnixCommand
class CmdDummy(UnixCommand): class CmdDummy(UnixCommand):
"""A dummy UnixCommand.""" """A dummy UnixCommand."""
@ -991,6 +1053,7 @@ class TestUnixCommand(CommandTest):
import re import re
from evennia.contrib import color_markups from evennia.contrib import color_markups
class TestColorMarkup(EvenniaTest): class TestColorMarkup(EvenniaTest):
""" """
Note: Normally this would be tested by importing the ansi parser and run 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 many other modules it appears that trying to overload
settings to test it causes issues with unrelated tests. settings to test it causes issues with unrelated tests.
""" """
def test_curly_markup(self): def test_curly_markup(self):
ansi_map = color_markups.CURLY_COLOR_ANSI_EXTRA_MAP ansi_map = color_markups.CURLY_COLOR_ANSI_EXTRA_MAP
self.assertIsNotNone(re.match(re.escape(ansi_map[7][0]), '{r')) 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[0][1], '%c[500')
self.assertEqual(bright_map[-1][1], '%c[222') self.assertEqual(bright_map[-1][1], '%c[222')
from evennia.contrib import random_string_generator from evennia.contrib import random_string_generator
SIMPLE_GENERATOR = random_string_generator.RandomStringGenerator("simple", "[01]{2}") SIMPLE_GENERATOR = random_string_generator.RandomStringGenerator("simple", "[01]{2}")
class TestRandomStringGenerator(EvenniaTest): class TestRandomStringGenerator(EvenniaTest):
def test_generate(self): 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 import random
from evennia import DefaultScript from evennia import DefaultScript
class BodyFunctions(DefaultScript): class BodyFunctions(DefaultScript):
""" """
This class defines the script itself This class defines the script itself
@ -21,7 +22,7 @@ class BodyFunctions(DefaultScript):
self.key = "bodyfunction" self.key = "bodyfunction"
self.desc = "Adds various timed events to a character." self.desc = "Adds various timed events to a character."
self.interval = 20 # seconds 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.start_delay = True # wait self.interval until first call
#self.persistent = True #self.persistent = True

View file

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

View file

@ -39,7 +39,7 @@
# #
#HEADER # HEADER
# everything in this block will be appended to the beginning of # everything in this block will be appended to the beginning of
# all other #CODE blocks when they are executed. # all other #CODE blocks when they are executed.
@ -51,7 +51,7 @@ from evennia import DefaultObject
limbo = search_object('Limbo')[0] limbo = search_object('Limbo')[0]
#CODE # CODE
# This is the first code block. Within each block, Python # This is the first code block. Within each block, Python
# code works as normal. Note how we make use if imports and # 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 # create a red button in limbo
red_button = create_object(red_button.RedButton, key="Red button", 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 # we take a look at what we created
caller.msg("A %s was created." % red_button.key) caller.msg("A %s was created." % red_button.key)
#CODE # CODE
# this code block has 'table' and 'chair' set as deletable # this code block has 'table' and 'chair' set as deletable
# objects. This means that when the batchcode processor runs in # 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 desc_lamp_broken - description when lamp is broken
""" """
def at_object_creation(self): def at_object_creation(self):
""" """
This function is called when object is created. Use this 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 # 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). # to remove itself after a while (and the player recovers their eyesight).
class ClosedLidState(DefaultScript): class ClosedLidState(DefaultScript):
""" """
This manages the cmdset for the "closed" button state. What this This manages the cmdset for the "closed" button state. What this
means is that while this script is valid, we add the RedButtonClosed means is that while this script is valid, we add the RedButtonClosed
cmdset to it (with commands like open, nudge lid etc) cmdset to it (with commands like open, nudge lid etc)
""" """
def at_script_creation(self): def at_script_creation(self):
"Called when script first created." "Called when script first created."
self.desc = "Script that manages the closed-state cmdsets for red button." 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 checked so we don't need to worry about adding the script to an
open lid. 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) self.obj.cmdset.add(cmdsetexamples.LidClosedCmdSet)
def is_valid(self): def is_valid(self):
@ -67,6 +69,7 @@ class OpenLidState(DefaultScript):
This manages the cmdset for the "open" button state. This will add This manages the cmdset for the "open" button state. This will add
the RedButtonOpen the RedButtonOpen
""" """
def at_script_creation(self): def at_script_creation(self):
"Called when script first created." "Called when script first created."
self.desc = "Script that manages the opened-state cmdsets for red button." 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 restored. It's up to the function starting the script to actually
set it on the right account object. set it on the right account object.
""" """
def at_script_creation(self): def at_script_creation(self):
""" """
We set up the script here. We set up the script here.
@ -139,7 +143,7 @@ class BlindedState(DefaultScript):
% self.obj.name, % self.obj.name,
exclude=self.obj) exclude=self.obj)
self.obj.cmdset.delete() # this will clear the latest added cmdset, 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 script that should be started/created when the
lid is opened. lid is opened.
""" """
def at_script_creation(self): def at_script_creation(self):
""" """
Called when script object is first created. Sets things up. 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.start_delay = True # we want to pospone the launch.
self.repeats = 1 # we only close the lid once self.repeats = 1 # we only close the lid once
self.persistent = True # even if the server crashes in those 20 seconds, 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): def is_valid(self):
""" """
@ -194,10 +199,12 @@ class CloseLidEvent(DefaultScript):
""" """
self.obj.close_lid() self.obj.close_lid()
class BlinkButtonEvent(DefaultScript): class BlinkButtonEvent(DefaultScript):
""" """
This timed script lets the button flash at regular intervals. This timed script lets the button flash at regular intervals.
""" """
def at_script_creation(self): def at_script_creation(self):
""" """
Sets things up. We want the button's lamp to blink at Sets things up. We want the button's lamp to blink at
@ -206,9 +213,9 @@ class BlinkButtonEvent(DefaultScript):
""" """
self.key = "blink_button" self.key = "blink_button"
self.desc = "Blinks red buttons" self.desc = "Blinks red buttons"
self.interval = 35 #seconds self.interval = 35 # seconds
self.start_delay = False #blink right away self.start_delay = False # blink right away
self.persistent = True #keep blinking also after server reboot self.persistent = True # keep blinking also after server reboot
def is_valid(self): def is_valid(self):
""" """
@ -223,6 +230,7 @@ class BlinkButtonEvent(DefaultScript):
""" """
self.obj.blink() self.obj.blink()
class DeactivateButtonEvent(DefaultScript): class DeactivateButtonEvent(DefaultScript):
""" """
This deactivates the button for a short while (it won't blink, won't 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* in the AddBlindedCmdSet script since that script is defined on the *account*
whereas this one must be defined on the *button*. whereas this one must be defined on the *button*.
""" """
def at_script_creation(self): def at_script_creation(self):
""" """
Sets things up. Sets things up.
""" """
self.key = "deactivate_button" self.key = "deactivate_button"
self.desc = "Deactivate red button temporarily" 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.start_delay = True # wait with the first repeat for self.interval seconds.
self.persistent = True self.persistent = True
self.repeats = 1 # only do this once 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 __future__ import absolute_import
from . import mob, objects, rooms from . import mob, objects, rooms

View file

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

View file

@ -106,6 +106,7 @@ class CmdSetReadable(CmdSet):
""" """
A CmdSet for readables. A CmdSet for readables.
""" """
def at_cmdset_creation(self): def at_cmdset_creation(self):
""" """
Called when the cmdset is created. Called when the cmdset is created.
@ -117,6 +118,7 @@ class Readable(TutorialObject):
""" """
This simple object defines some attributes and This simple object defines some attributes and
""" """
def at_object_creation(self): def at_object_creation(self):
""" """
Called when object is created. We make sure to set the needed Called when object is created. We make sure to set the needed
@ -176,6 +178,7 @@ class CmdClimb(Command):
class CmdSetClimbable(CmdSet): class CmdSetClimbable(CmdSet):
"""Climbing cmdset""" """Climbing cmdset"""
def at_cmdset_creation(self): def at_cmdset_creation(self):
"""populate set""" """populate set"""
self.add(CmdClimb()) self.add(CmdClimb())
@ -303,6 +306,7 @@ class LightSource(TutorialObject):
When burned out, the object will be deleted. When burned out, the object will be deleted.
""" """
def at_init(self): def at_init(self):
""" """
If this is called with the Attribute is_giving_light already 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 whenever the button is pushed (this hides it as an exit
until it actually is) until it actually is)
""" """
def at_init(self): def at_init(self):
""" """
Called when object is recalled from cache. Called when object is recalled from cache.
@ -838,6 +843,7 @@ class CmdAttack(Command):
class CmdSetWeapon(CmdSet): class CmdSetWeapon(CmdSet):
"""Holds the attack command.""" """Holds the attack command."""
def at_cmdset_creation(self): def at_cmdset_creation(self):
"""called at first object creation.""" """called at first object creation."""
self.add(CmdAttack()) self.add(CmdAttack())
@ -854,6 +860,7 @@ class Weapon(TutorialObject):
type of attack) (0-10) type of attack) (0-10)
""" """
def at_object_creation(self): def at_object_creation(self):
"""Called at first creation of the object""" """Called at first creation of the object"""
super(Weapon, self).at_object_creation() super(Weapon, self).at_object_creation()
@ -987,7 +994,7 @@ WEAPON_PROTOTYPES = {
"hit": 0.85, "hit": 0.85,
"parry": 0.7, "parry": 0.7,
"damage": 11} "damage": 11}
} }
class CmdGetWeapon(Command): class CmdGetWeapon(Command):
@ -1037,6 +1044,7 @@ class WeaponRack(TutorialObject):
grab another one. grab another one.
""" """
def at_object_creation(self): def at_object_creation(self):
""" """
called at creation 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. 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. It defines a cmdset on itself for reading tutorial info about the location.
""" """
def at_object_creation(self): def at_object_creation(self):
"""Called when room is first created""" """Called when room is first created"""
self.db.tutorial_info = "This is a tutorial room. It allows you to use the 'tutorial' command." 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 # These are rainy weather strings
WEATHER_STRINGS = ( WEATHER_STRINGS = (
"The rain coming down from the iron-grey sky intensifies.", "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.", "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.", "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.", "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 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.", "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.", "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.", "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.", "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.", "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.") "Large clouds rush across the sky, throwing their load of rain over the world.")
class WeatherRoom(TutorialRoom): class WeatherRoom(TutorialRoom):
@ -300,6 +301,7 @@ class WeatherRoom(TutorialRoom):
inherit from this. inherit from this.
""" """
def at_object_creation(self): def at_object_creation(self):
""" """
Called when object is first created. Called when object is first created.
@ -355,6 +357,7 @@ class IntroRoom(TutorialRoom):
properties to customize: properties to customize:
char_health - integer > 0 (default 20) char_health - integer > 0 (default 20)
""" """
def at_object_creation(self): def at_object_creation(self):
""" """
Called when the room is first created. Called when the room is first created.
@ -377,7 +380,7 @@ class IntroRoom(TutorialRoom):
character.db.health_max = health character.db.health_max = health
if character.is_superuser: 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")) character.msg("|r%s|n" % string.format(name=character.key, quell="|w@quell|r"))
@ -589,16 +592,16 @@ class BridgeCmdSet(CmdSet):
BRIDGE_WEATHER = ( BRIDGE_WEATHER = (
"The rain intensifies, making the planks of the bridge even more slippery.", "The rain intensifies, making the planks of the bridge even more slippery.",
"A gust of wind throws the rain right in your face.", "A gust of wind throws the rain right in your face.",
"The rainfall eases a bit and the sky momentarily brightens.", "The rainfall eases a bit and the sky momentarily brightens.",
"The bridge shakes under the thunder of a closeby thunder strike.", "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 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.", "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.", "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.", "The bridge sways from side to side in the wind.",
"Below you a particularly large wave crashes into the rocks.", "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.") "From the ruin you hear a distant, otherwordly howl. Or maybe it was just the wind.")
class BridgeRoom(WeatherRoom): class BridgeRoom(WeatherRoom):
@ -625,6 +628,7 @@ class BridgeRoom(WeatherRoom):
the CmdLookBridge command). the CmdLookBridge command).
""" """
def at_object_creation(self): def at_object_creation(self):
"""Setups the room""" """Setups the room"""
# this will start the weather room's ticker and tell # 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. may have been beaten up by the ghostly apparition at this point.
""" """
def at_object_creation(self): def at_object_creation(self):
""" """
Called when object is first created. Called when object is first created.
@ -942,6 +947,7 @@ class TeleportRoom(TutorialRoom):
failure_teleport_msg - message to echo while teleporting to failure failure_teleport_msg - message to echo while teleporting to failure
""" """
def at_object_creation(self): def at_object_creation(self):
"""Called at first creation""" """Called at first creation"""
super(TeleportRoom, self).at_object_creation() super(TeleportRoom, self).at_object_creation()

View file

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

View file

@ -16,6 +16,7 @@ own cmdsets by inheriting from them or directly from `evennia.CmdSet`.
from evennia import default_cmds from evennia import default_cmds
class CharacterCmdSet(default_cmds.CharacterCmdSet): class CharacterCmdSet(default_cmds.CharacterCmdSet):
""" """
The `CharacterCmdSet` contains general in-game commands like `look`, The `CharacterCmdSet` contains general in-game commands like `look`,

View file

@ -25,6 +25,7 @@ line to your settings file:
""" """
def at_search_result(matches, caller, query="", quiet=False, **kwargs): def at_search_result(matches, caller, query="", quiet=False, **kwargs):
""" """
This is a generic hook for handling all processing of a search This is a generic hook for handling all processing of a search

View file

@ -31,6 +31,7 @@ your settings file:
""" """
def cmdparser(raw_string, cmdset, caller, match_index=None): def cmdparser(raw_string, cmdset, caller, match_index=None):
""" """
This function is called by the cmdhandler once it has This function is called by the cmdhandler once it has

View file

@ -45,7 +45,7 @@ and can be used to customize it to each session.
""" """
#def capitalize(text, *args, **kwargs): # def capitalize(text, *args, **kwargs):
# "Silly capitalize example. Used as {capitalize() ... {/capitalize" # "Silly capitalize example. Used as {capitalize() ... {/capitalize"
# session = kwargs.get("session") # session = kwargs.get("session")
# return text.capitalize() # return text.capitalize()

View file

@ -20,7 +20,7 @@ lock functions from evennia.locks.lockfuncs.
""" """
#def myfalse(accessing_obj, accessed_obj, *args, **kwargs): # def myfalse(accessing_obj, accessed_obj, *args, **kwargs):
# """ # """
# called in lockstring with myfalse(). # called in lockstring with myfalse().
# A simple logger that always returns false. Prints to stdout # A simple logger that always returns false. Prints to stdout

View file

@ -13,105 +13,105 @@ affect uptime).
""" """
MSSPTable = { MSSPTable = {
# Required fieldss # Required fieldss
"NAME": "Evennia", "NAME": "Evennia",
# Generic # Generic
"CRAWL DELAY": "-1", # limit how often crawler updates the listing. -1 for no limit "CRAWL DELAY": "-1", # limit how often crawler updates the listing. -1 for no limit
"HOSTNAME": "", # current or new hostname "HOSTNAME": "", # current or new hostname
"PORT": ["4000"], # most important port should be last in list "PORT": ["4000"], # most important port should be last in list
"CODEBASE": "Evennia", "CODEBASE": "Evennia",
"CONTACT": "", # email for contacting the mud "CONTACT": "", # email for contacting the mud
"CREATED": "", # year MUD was created "CREATED": "", # year MUD was created
"ICON": "", # url to icon 32x32 or larger; <32kb. "ICON": "", # url to icon 32x32 or larger; <32kb.
"IP": "", # current or new IP address "IP": "", # current or new IP address
"LANGUAGE": "", # name of language used, e.g. English "LANGUAGE": "", # name of language used, e.g. English
"LOCATION": "", # full English name of server country "LOCATION": "", # full English name of server country
"MINIMUM AGE": "0", # set to 0 if not applicable "MINIMUM AGE": "0", # set to 0 if not applicable
"WEBSITE": "www.evennia.com", "WEBSITE": "www.evennia.com",
# Categorisation # Categorisation
"FAMILY": "Custom", # evennia goes under 'Custom' "FAMILY": "Custom", # evennia goes under 'Custom'
"GENRE": "None", # Adult, Fantasy, Historical, Horror, Modern, None, or Science Fiction "GENRE": "None", # Adult, Fantasy, Historical, Horror, Modern, None, or Science Fiction
"GAMEPLAY": "", # Adventure, Educational, Hack and Slash, None, "GAMEPLAY": "", # Adventure, Educational, Hack and Slash, None,
# Player versus Player, Player versus Environment, # Player versus Player, Player versus Environment,
# Roleplaying, Simulation, Social or Strategy # Roleplaying, Simulation, Social or Strategy
"STATUS": "Open Beta", # Alpha, Closed Beta, Open Beta, Live "STATUS": "Open Beta", # Alpha, Closed Beta, Open Beta, Live
"GAMESYSTEM": "Custom", # D&D, d20 System, World of Darkness, etc. Use Custom if homebrew "GAMESYSTEM": "Custom", # D&D, d20 System, World of Darkness, etc. Use Custom if homebrew
"SUBGENRE": "None", # LASG, Medieval Fantasy, World War II, Frankenstein, "SUBGENRE": "None", # LASG, Medieval Fantasy, World War II, Frankenstein,
# Cyberpunk, Dragonlance, etc. Or None if not available. # Cyberpunk, Dragonlance, etc. Or None if not available.
# World # World
"AREAS": "0", "AREAS": "0",
"HELPFILES": "0", "HELPFILES": "0",
"MOBILES": "0", "MOBILES": "0",
"OBJECTS": "0", "OBJECTS": "0",
"ROOMS": "0", # use 0 if room-less "ROOMS": "0", # use 0 if room-less
"CLASSES": "0", # use 0 if class-less "CLASSES": "0", # use 0 if class-less
"LEVELS": "0", # use 0 if level-less "LEVELS": "0", # use 0 if level-less
"RACES": "0", # use 0 if race-less "RACES": "0", # use 0 if race-less
"SKILLS": "0", # use 0 if skill-less "SKILLS": "0", # use 0 if skill-less
# Protocols set to 1 or 0) # Protocols set to 1 or 0)
"ANSI": "1", "ANSI": "1",
"GMCP": "1", "GMCP": "1",
"ATCP": "0", "ATCP": "0",
"MCCP": "0", "MCCP": "0",
"MCP": "0", "MCP": "0",
"MSDP": "0", "MSDP": "0",
"MSP": "0", "MSP": "0",
"MXP": "0", "MXP": "0",
"PUEBLO": "0", "PUEBLO": "0",
"SSL": "1", "SSL": "1",
"UTF-8": "1", "UTF-8": "1",
"VT100": "0", "VT100": "0",
"ZMP": "0", "ZMP": "0",
"XTERM 256 COLORS": "0", "XTERM 256 COLORS": "0",
# Commercial set to 1 or 0) # Commercial set to 1 or 0)
"PAY TO PLAY": "0", "PAY TO PLAY": "0",
"PAY FOR PERKS": "0", "PAY FOR PERKS": "0",
# Hiring set to 1 or 0) # Hiring set to 1 or 0)
"HIRING BUILDERS": "0", "HIRING BUILDERS": "0",
"HIRING CODERS": "0", "HIRING CODERS": "0",
# Extended variables # Extended variables
# World # World
"DBSIZE": "0", "DBSIZE": "0",
"EXITS": "0", "EXITS": "0",
"EXTRA DESCRIPTIONS": "0", "EXTRA DESCRIPTIONS": "0",
"MUDPROGS": "0", "MUDPROGS": "0",
"MUDTRIGS": "0", "MUDTRIGS": "0",
"RESETS": "0", "RESETS": "0",
# Game (set to 1 or 0, or one of the given alternatives) # Game (set to 1 or 0, or one of the given alternatives)
"ADULT MATERIAL": "0", "ADULT MATERIAL": "0",
"MULTICLASSING": "0", "MULTICLASSING": "0",
"NEWBIE FRIENDLY": "0", "NEWBIE FRIENDLY": "0",
"PLAYER CITIES": "0", "PLAYER CITIES": "0",
"PLAYER CLANS": "0", "PLAYER CLANS": "0",
"PLAYER CRAFTING": "0", "PLAYER CRAFTING": "0",
"PLAYER GUILDS": "0", "PLAYER GUILDS": "0",
"EQUIPMENT SYSTEM": "None", # "None", "Level", "Skill", "Both" "EQUIPMENT SYSTEM": "None", # "None", "Level", "Skill", "Both"
"MULTIPLAYING": "None", # "None", "Restricted", "Full" "MULTIPLAYING": "None", # "None", "Restricted", "Full"
"PLAYERKILLING": "None", # "None", "Restricted", "Full" "PLAYERKILLING": "None", # "None", "Restricted", "Full"
"QUEST SYSTEM": "None", # "None", "Immortal Run", "Automated", "Integrated" "QUEST SYSTEM": "None", # "None", "Immortal Run", "Automated", "Integrated"
"ROLEPLAYING": "None", # "None", "Accepted", "Encouraged", "Enforced" "ROLEPLAYING": "None", # "None", "Accepted", "Encouraged", "Enforced"
"TRAINING SYSTEM": "None", # "None", "Level", "Skill", "Both" "TRAINING SYSTEM": "None", # "None", "Level", "Skill", "Both"
"WORLD ORIGINALITY": "None", # "All Stock", "Mostly Stock", "Mostly Original", "All Original" "WORLD ORIGINALITY": "None", # "All Stock", "Mostly Stock", "Mostly Original", "All Original"
} }

View file

@ -23,6 +23,7 @@ settings file:
from evennia.server.serversession import ServerSession as BaseServerSession from evennia.server.serversession import ServerSession as BaseServerSession
class ServerSession(BaseServerSession): class ServerSession(BaseServerSession):
""" """
This class represents a player's session and is a template for This class represents a player's session and is a template for

View file

@ -26,4 +26,3 @@ def at_webserver_root_creation(web_root):
""" """
return web_root return web_root

View file

@ -24,6 +24,7 @@ several more options for customizing the Guest account system.
from evennia import DefaultAccount, DefaultGuest from evennia import DefaultAccount, DefaultGuest
class Account(DefaultAccount): class Account(DefaultAccount):
""" """
This class describes the actual OOC account (i.e. the user connecting This class describes the actual OOC account (i.e. the user connecting

View file

@ -14,6 +14,7 @@ to be modified.
from evennia import DefaultChannel from evennia import DefaultChannel
class Channel(DefaultChannel): class Channel(DefaultChannel):
""" """
Working methods: Working methods:

View file

@ -9,6 +9,7 @@ creation commands.
""" """
from evennia import DefaultCharacter from evennia import DefaultCharacter
class Character(DefaultCharacter): class Character(DefaultCharacter):
""" """
The Character defaults to reimplementing some of base Object's hook methods with the The Character defaults to reimplementing some of base Object's hook methods with the
@ -22,7 +23,7 @@ class Character(DefaultCharacter):
at_post_unpuppet(account) - when Account disconnects from the Character, we at_post_unpuppet(account) - when Account disconnects from the Character, we
store the current location in the pre_logout_location Attribute and store the current location in the pre_logout_location Attribute and
move it to a None-location so the "unpuppeted" character move it to a None-location so the "unpuppeted" character
object does not need to stay on grid. Echoes "Account has disconnected" object does not need to stay on grid. Echoes "Account has disconnected"
to the room. to the room.
at_pre_puppet - Just before Account re-connects, retrieves the character's at_pre_puppet - Just before Account re-connects, retrieves the character's
pre_logout_location Attribute and move it back on the grid. pre_logout_location Attribute and move it back on the grid.

View file

@ -8,6 +8,7 @@ for allowing Characters to traverse the exit to its destination.
""" """
from evennia import DefaultExit from evennia import DefaultExit
class Exit(DefaultExit): class Exit(DefaultExit):
""" """
Exits are connectors between rooms. Exits are normal Objects except Exits are connectors between rooms. Exits are normal Objects except

View file

@ -12,6 +12,7 @@ inheritance.
""" """
from evennia import DefaultObject from evennia import DefaultObject
class Object(DefaultObject): class Object(DefaultObject):
""" """
This is the root typeclass object, implementing an in-game Evennia This is the root typeclass object, implementing an in-game Evennia

View file

@ -38,7 +38,7 @@ See the `@spawn` command and `evennia.utils.spawner` for more info.
#from random import randint #from random import randint
# #
#GOBLIN = { # GOBLIN = {
# "key": "goblin grunt", # "key": "goblin grunt",
# "health": lambda: randint(20,30), # "health": lambda: randint(20,30),
# "resists": ["cold", "poison"], # "resists": ["cold", "poison"],
@ -46,13 +46,13 @@ See the `@spawn` command and `evennia.utils.spawner` for more info.
# "weaknesses": ["fire", "light"] # "weaknesses": ["fire", "light"]
# } # }
# #
#GOBLIN_WIZARD = { # GOBLIN_WIZARD = {
# "prototype": "GOBLIN", # "prototype": "GOBLIN",
# "key": "goblin wizard", # "key": "goblin wizard",
# "spells": ["fire ball", "lighting bolt"] # "spells": ["fire ball", "lighting bolt"]
# } # }
# #
#GOBLIN_ARCHER = { # GOBLIN_ARCHER = {
# "prototype": "GOBLIN", # "prototype": "GOBLIN",
# "key": "goblin archer", # "key": "goblin archer",
# "attacks": ["short bow"] # "attacks": ["short bow"]
@ -62,12 +62,12 @@ See the `@spawn` command and `evennia.utils.spawner` for more info.
# (nor key) of its own, so it should normally only be # (nor key) of its own, so it should normally only be
# used as a mix-in, as in the example of the goblin # used as a mix-in, as in the example of the goblin
# archwizard below. # archwizard below.
#ARCHWIZARD_MIXIN = { # ARCHWIZARD_MIXIN = {
# "attacks": ["archwizard staff"], # "attacks": ["archwizard staff"],
# "spells": ["greater fire ball", "greater lighting"] # "spells": ["greater fire ball", "greater lighting"]
#} #}
# #
#GOBLIN_ARCHWIZARD = { # GOBLIN_ARCHWIZARD = {
# "key": "goblin archwizard", # "key": "goblin archwizard",
# "prototype" : ("GOBLIN_WIZARD", "ARCHWIZARD_MIXIN") # "prototype" : ("GOBLIN_WIZARD", "ARCHWIZARD_MIXIN")
#} #}

View file

@ -8,12 +8,12 @@ from django.contrib import admin
from evennia.help.models import HelpEntry from evennia.help.models import HelpEntry
from evennia.typeclasses.admin import TagInline from evennia.typeclasses.admin import TagInline
class HelpTagInline(TagInline): class HelpTagInline(TagInline):
model = HelpEntry.db_tags.through model = HelpEntry.db_tags.through
related_field = "helpentry" related_field = "helpentry"
class HelpEntryForm(forms.ModelForm): class HelpEntryForm(forms.ModelForm):
"Defines how to display the help entry" "Defines how to display the help entry"
class Meta(object): class Meta(object):
@ -22,8 +22,9 @@ class HelpEntryForm(forms.ModelForm):
db_help_category = forms.CharField(label="Help category", initial='General', db_help_category = forms.CharField(label="Help category", initial='General',
help_text="organizes help entries in lists") help_text="organizes help entries in lists")
db_lock_storage = forms.CharField(label="Locks", initial='view:all()',required=False, db_lock_storage = forms.CharField(label="Locks", initial='view:all()', required=False,
widget=forms.TextInput(attrs={'size':'40'}),) widget=forms.TextInput(attrs={'size': '40'}),)
class HelpEntryAdmin(admin.ModelAdmin): class HelpEntryAdmin(admin.ModelAdmin):
"Sets up the admin manaager for help entries" "Sets up the admin manaager for help entries"
@ -38,9 +39,9 @@ class HelpEntryAdmin(admin.ModelAdmin):
form = HelpEntryForm form = HelpEntryForm
fieldsets = ( fieldsets = (
(None, {'fields':(('db_key', 'db_help_category'), (None, {'fields': (('db_key', 'db_help_category'),
'db_entrytext', 'db_lock_storage'), 'db_entrytext', 'db_lock_storage'),
'description':"Sets a Help entry. Set lock to <i>view:all()</I> unless you want to restrict it."}),) 'description': "Sets a Help entry. Set lock to <i>view:all()</I> unless you want to restrict it."}),)
admin.site.register(HelpEntry, HelpEntryAdmin) admin.site.register(HelpEntry, HelpEntryAdmin)

View file

@ -24,6 +24,7 @@ class HelpEntryManager(TypedObjectManager):
search_help (equivalent to evennia.search_helpentry) search_help (equivalent to evennia.search_helpentry)
""" """
def find_topicmatch(self, topicstr, exact=False): def find_topicmatch(self, topicstr, exact=False):
""" """
Searches for matching topics or aliases based on player's Searches for matching topics or aliases based on player's

View file

@ -52,14 +52,14 @@ class HelpEntry(SharedMemoryModel):
db_key = models.CharField('help key', max_length=255, unique=True, help_text='key to search for') db_key = models.CharField('help key', max_length=255, unique=True, help_text='key to search for')
# help category # help category
db_help_category = models.CharField("help category", max_length=255, default="General", db_help_category = models.CharField("help category", max_length=255, default="General",
help_text='organizes help entries in lists') help_text='organizes help entries in lists')
# the actual help entry text, in any formatting. # the actual help entry text, in any formatting.
db_entrytext = models.TextField('help entry', blank=True, help_text='the main body of help text') db_entrytext = models.TextField('help entry', blank=True, help_text='the main body of help text')
# lock string storage # lock string storage
db_lock_storage = models.TextField('locks', blank=True, help_text='normally view:all().') db_lock_storage = models.TextField('locks', blank=True, help_text='normally view:all().')
# tags are primarily used for permissions # tags are primarily used for permissions
db_tags = models.ManyToManyField(Tag, blank=True, db_tags = models.ManyToManyField(Tag, blank=True,
help_text='tags on this object. Tags are simple string markers to identify, group and alias objects.') help_text='tags on this object. Tags are simple string markers to identify, group and alias objects.')
# (deprecated, only here to allow MUX helpfile load (don't use otherwise)). # (deprecated, only here to allow MUX helpfile load (don't use otherwise)).
# TODO: remove this when not needed anymore. # TODO: remove this when not needed anymore.
db_staff_only = models.BooleanField(default=False) db_staff_only = models.BooleanField(default=False)

View file

@ -280,8 +280,8 @@ def pid(accessing_obj, accessed_obj, *args, **kwargs):
# this is more efficient than multiple if ... elif statments # this is more efficient than multiple if ... elif statments
CF_MAPPING = {'eq': lambda val1, val2: val1 == val2 or str(val1) == str(val2) or float(val1) == float(val2), CF_MAPPING = {'eq': lambda val1, val2: val1 == val2 or str(val1) == str(val2) or float(val1) == float(val2),
'gt': lambda val1, val2: float(val1) > float(val2), 'gt': lambda val1, val2: float(val1) > float(val2),
'lt': lambda val1, val2: float(val1) < float(val2), 'lt': lambda val1, val2: float(val1) < float(val2),
'ge': lambda val1, val2: float(val1) >= float(val2), 'ge': lambda val1, val2: float(val1) >= float(val2),
'le': lambda val1, val2: float(val1) <= float(val2), 'le': lambda val1, val2: float(val1) <= float(val2),
'ne': lambda val1, val2: float(val1) != float(val2), 'ne': lambda val1, val2: float(val1) != float(val2),
@ -346,8 +346,8 @@ def attr(accessing_obj, accessed_obj, *args, **kwargs):
# check attributes, if they exist # check attributes, if they exist
if (hasattr(accessing_obj, 'attributes') and accessing_obj.attributes.has(attrname)): if (hasattr(accessing_obj, 'attributes') and accessing_obj.attributes.has(attrname)):
if value: if value:
return (hasattr(accessing_obj, 'attributes') return (hasattr(accessing_obj, 'attributes') and
and valcompare(accessing_obj.attributes.get(attrname), value, compare)) valcompare(accessing_obj.attributes.get(attrname), value, compare))
# fails on False/None values # fails on False/None values
return bool(accessing_obj.attributes.get(attrname)) return bool(accessing_obj.attributes.get(attrname))
return False return False
@ -366,6 +366,7 @@ def objattr(accessing_obj, accessed_obj, *args, **kwargs):
""" """
return attr(accessed_obj, accessed_obj, *args, **kwargs) return attr(accessed_obj, accessed_obj, *args, **kwargs)
def locattr(accessing_obj, accessed_obj, *args, **kwargs): def locattr(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Usage: Usage:
@ -386,6 +387,7 @@ def locattr(accessing_obj, accessed_obj, *args, **kwargs):
return attr(accessing_obj.location, accessed_obj, *args, **kwargs) return attr(accessing_obj.location, accessed_obj, *args, **kwargs)
return False return False
def objlocattr(accessing_obj, accessed_obj, *args, **kwargs): def objlocattr(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Usage: Usage:
@ -464,6 +466,7 @@ def attr_ne(accessing_obj, accessed_obj, *args, **kwargs):
""" """
return attr(accessing_obj, accessed_obj, *args, **{'compare': 'ne'}) return attr(accessing_obj, accessed_obj, *args, **{'compare': 'ne'})
def tag(accessing_obj, accessed_obj, *args, **kwargs): def tag(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Usage: Usage:
@ -481,6 +484,7 @@ def tag(accessing_obj, accessed_obj, *args, **kwargs):
category = args[1] if len(args) > 1 else None category = args[1] if len(args) > 1 else None
return accessing_obj.tags.get(tagkey, category=category) return accessing_obj.tags.get(tagkey, category=category)
def objtag(accessing_obj, accessed_obj, *args, **kwargs): def objtag(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Usage: Usage:
@ -492,6 +496,7 @@ def objtag(accessing_obj, accessed_obj, *args, **kwargs):
""" """
return accessed_obj.tags.get(*args) return accessed_obj.tags.get(*args)
def inside(accessing_obj, accessed_obj, *args, **kwargs): def inside(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Usage: Usage:
@ -548,7 +553,7 @@ def holds(accessing_obj, accessed_obj, *args, **kwargs):
if len(args) == 1: if len(args) == 1:
# command is holds(dbref/key) - check if given objname/dbref is held by accessing_ob # command is holds(dbref/key) - check if given objname/dbref is held by accessing_ob
return check_holds(args[0]) return check_holds(args[0])
elif len(args = 2): elif len(args=2):
# command is holds(attrname, value) check if any held object has the given attribute and value # command is holds(attrname, value) check if any held object has the given attribute and value
for obj in contents: for obj in contents:
if obj.attributes.get(args[0]) == args[1]: if obj.attributes.get(args[0]) == args[1]:
@ -566,6 +571,7 @@ def superuser(*args, **kwargs):
""" """
return False return False
def has_account(accessing_obj, accessed_obj, *args, **kwargs): def has_account(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Only returns true if accessing_obj has_account is true, that is, Only returns true if accessing_obj has_account is true, that is,
@ -576,6 +582,7 @@ def has_account(accessing_obj, accessed_obj, *args, **kwargs):
""" """
return hasattr(accessing_obj, "has_account") and accessing_obj.has_account return hasattr(accessing_obj, "has_account") and accessing_obj.has_account
def serversetting(accessing_obj, accessed_obj, *args, **kwargs): def serversetting(accessing_obj, accessed_obj, *args, **kwargs):
""" """
Only returns true if the Evennia settings exists, alternatively has Only returns true if the Evennia settings exists, alternatively has

View file

@ -121,6 +121,7 @@ WARNING_LOG = settings.LOCKWARNING_LOG_FILE
# by errors in lock definitions. # by errors in lock definitions.
# #
class LockException(Exception): class LockException(Exception):
""" """
Raised during an error in a lock. Raised during an error in a lock.
@ -133,6 +134,8 @@ class LockException(Exception):
# #
_LOCKFUNCS = {} _LOCKFUNCS = {}
def _cache_lockfuncs(): def _cache_lockfuncs():
""" """
Updates the cache. Updates the cache.
@ -146,6 +149,7 @@ def _cache_lockfuncs():
# pre-compiled regular expressions # pre-compiled regular expressions
# #
_RE_FUNCS = re.compile(r"\w+\([^)]*\)") _RE_FUNCS = re.compile(r"\w+\([^)]*\)")
_RE_SEPS = re.compile(r"(?<=[ )])AND(?=\s)|(?<=[ )])OR(?=\s)|(?<=[ )])NOT(?=\s)") _RE_SEPS = re.compile(r"(?<=[ )])AND(?=\s)|(?<=[ )])OR(?=\s)|(?<=[ )])NOT(?=\s)")
_RE_OK = re.compile(r"%s|and|or|not") _RE_OK = re.compile(r"%s|and|or|not")
@ -229,7 +233,7 @@ class LockHandler(object):
if not callable(func): if not callable(func):
elist.append(_("Lock: lock-function '%s' is not available.") % funcstring) elist.append(_("Lock: lock-function '%s' is not available.") % funcstring)
continue continue
args = list(arg.strip() for arg in rest.split(',') if arg and not '=' in arg) args = list(arg.strip() for arg in rest.split(',') if arg and '=' not in arg)
kwargs = dict([arg.split('=', 1) for arg in rest.split(',') if arg and '=' in arg]) kwargs = dict([arg.split('=', 1) for arg in rest.split(',') if arg and '=' in arg])
lock_funcs.append((func, args, kwargs)) lock_funcs.append((func, args, kwargs))
evalstring = evalstring.replace(funcstring, '%s') evalstring = evalstring.replace(funcstring, '%s')
@ -244,8 +248,8 @@ class LockHandler(object):
continue continue
if access_type in locks: if access_type in locks:
duplicates += 1 duplicates += 1
wlist.append(_("LockHandler on %(obj)s: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " % \ wlist.append(_("LockHandler on %(obj)s: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " %
{"obj":self.obj, "access_type":access_type, "source":locks[access_type][2], "goal":raw_lockstring})) {"obj": self.obj, "access_type": access_type, "source": locks[access_type][2], "goal": raw_lockstring}))
locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring)
if wlist and WARNING_LOG: if wlist and WARNING_LOG:
# a warning text was set, it's not an error, so only report # a warning text was set, it's not an error, so only report
@ -300,7 +304,7 @@ class LockHandler(object):
""" """
# sanity checks # sanity checks
for lockdef in lockstring.split(';'): for lockdef in lockstring.split(';'):
if not ':' in lockstring: if ':' not in lockstring:
self._log_error(_("Lock: '%s' contains no colon (:).") % lockdef) self._log_error(_("Lock: '%s' contains no colon (:).") % lockdef)
return False return False
access_type, rhs = [part.strip() for part in lockdef.split(':', 1)] access_type, rhs = [part.strip() for part in lockdef.split(':', 1)]
@ -391,7 +395,7 @@ class LockHandler(object):
self._save_locks() self._save_locks()
return True return True
return False return False
delete = remove # alias for historical reasons delete = remove # alias for historical reasons
def clear(self): def clear(self):
""" """
@ -449,9 +453,9 @@ class LockHandler(object):
return True return True
except AttributeError: except AttributeError:
# happens before session is initiated. # happens before session is initiated.
if not no_superuser_bypass and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser) if not no_superuser_bypass and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser) or
or (hasattr(accessing_obj, 'account') and hasattr(accessing_obj.account, 'is_superuser') and accessing_obj.account.is_superuser) (hasattr(accessing_obj, 'account') and hasattr(accessing_obj.account, 'is_superuser') and accessing_obj.account.is_superuser) or
or (hasattr(accessing_obj, 'get_account') and (not accessing_obj.get_account() or accessing_obj.get_account().is_superuser))): (hasattr(accessing_obj, 'get_account') and (not accessing_obj.get_account() or accessing_obj.get_account().is_superuser))):
return True return True
# no superuser or bypass -> normal lock operation # no superuser or bypass -> normal lock operation
@ -510,17 +514,17 @@ class LockHandler(object):
if accessing_obj.locks.lock_bypass and not no_superuser_bypass: if accessing_obj.locks.lock_bypass and not no_superuser_bypass:
return True return True
except AttributeError: except AttributeError:
if no_superuser_bypass and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser) if no_superuser_bypass and ((hasattr(accessing_obj, 'is_superuser') and accessing_obj.is_superuser) or
or (hasattr(accessing_obj, 'account') and hasattr(accessing_obj.account, 'is_superuser') and accessing_obj.account.is_superuser) (hasattr(accessing_obj, 'account') and hasattr(accessing_obj.account, 'is_superuser') and accessing_obj.account.is_superuser) or
or (hasattr(accessing_obj, 'get_account') and (not accessing_obj.get_account() or accessing_obj.get_account().is_superuser))): (hasattr(accessing_obj, 'get_account') and (not accessing_obj.get_account() or accessing_obj.get_account().is_superuser))):
return True return True
if not ":" in lockstring: if ":" not in lockstring:
lockstring = "%s:%s" % ("_dummy", lockstring) lockstring = "%s:%s" % ("_dummy", lockstring)
locks = self._parse_lockstring(lockstring) locks = self._parse_lockstring(lockstring)
if access_type: if access_type:
if not access_type in locks: if access_type not in locks:
return default return default
else: else:
return self._eval_access_type( return self._eval_access_type(
@ -541,7 +545,7 @@ def _test():
obj1 = TestObj() obj1 = TestObj()
obj2 = TestObj() obj2 = TestObj()
#obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Admin);examine:perm(Builder);delete:perm(Admin);get:all()" # obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Admin);examine:perm(Builder);delete:perm(Admin);get:all()"
#obj1.lock_storage = "cmd:all();admin:id(1);listen:all();send:all()" #obj1.lock_storage = "cmd:all();admin:id(1);listen:all();send:all()"
obj1.lock_storage = "listen:perm(Developer)" obj1.lock_storage = "listen:perm(Developer)"
@ -550,7 +554,7 @@ def _test():
obj2.permissions.add("Developer") obj2.permissions.add("Developer")
obj2.id = 4 obj2.id = 4
#obj1.locks.add("edit:attr(test)") # obj1.locks.add("edit:attr(test)")
print("comparing obj2.permissions (%s) vs obj1.locks (%s)" % (obj2.permissions, obj1.locks)) print("comparing obj2.permissions (%s) vs obj1.locks (%s)" % (obj2.permissions, obj1.locks))
print(obj1.locks.check(obj2, 'owner')) print(obj1.locks.check(obj2, 'owner'))

View file

@ -97,18 +97,18 @@ class ObjectDBAdmin(admin.ModelAdmin):
form = ObjectEditForm form = ObjectEditForm
fieldsets = ( fieldsets = (
(None, { (None, {
'fields': (('db_key', 'db_typeclass_path'), ('db_lock_storage', ), 'fields': (('db_key', 'db_typeclass_path'), ('db_lock_storage', ),
('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage' ('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage'
)}), )}),
) )
add_form = ObjectCreateForm add_form = ObjectCreateForm
add_fieldsets = ( add_fieldsets = (
(None, { (None, {
'fields': (('db_key', 'db_typeclass_path'), 'fields': (('db_key', 'db_typeclass_path'),
('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage' ('db_location', 'db_home'), 'db_destination', 'db_cmdset_storage'
)}), )}),
) )
def get_fieldsets(self, request, obj=None): def get_fieldsets(self, request, obj=None):
""" """

View file

@ -261,7 +261,7 @@ class ObjectDBManager(TypedObjectManager):
if exact: if exact:
# exact match - do direct search # exact match - do direct search
return self.filter(cand_restriction & type_restriction & (Q(db_key__iexact=ostring) | return self.filter(cand_restriction & type_restriction & (Q(db_key__iexact=ostring) |
Q(db_tags__db_key__iexact=ostring) & Q(db_tags__db_tagtype__iexact="alias"))).distinct() Q(db_tags__db_key__iexact=ostring) & Q(db_tags__db_tagtype__iexact="alias"))).distinct()
elif candidates: elif candidates:
# fuzzy with candidates # fuzzy with candidates
search_candidates = self.filter(cand_restriction & type_restriction) search_candidates = self.filter(cand_restriction & type_restriction)

View file

@ -3,12 +3,14 @@ from __future__ import unicode_literals
from django.db import models, migrations from django.db import models, migrations
def convert_defaults(apps, schema_editor): def convert_defaults(apps, schema_editor):
ObjectDB = apps.get_model("objects", "ObjectDB") ObjectDB = apps.get_model("objects", "ObjectDB")
for obj in ObjectDB.objects.filter(db_typeclass_path="src.objects.objects.Object"): for obj in ObjectDB.objects.filter(db_typeclass_path="src.objects.objects.Object"):
obj.db_typeclass_path = "typeclasses.objects.Object" obj.db_typeclass_path = "typeclasses.objects.Object"
obj.save() obj.save()
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -16,5 +18,5 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.RunPython(convert_defaults), migrations.RunPython(convert_defaults),
] ]

View file

@ -21,6 +21,7 @@ def forwards(apps, schema_editor):
object.db_account = account object.db_account = account
object.save(update_fields=['db_account']) object.save(update_fields=['db_account'])
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [

View file

@ -33,6 +33,7 @@ class ContentsHandler(object):
for object-cmdsets). It is stored on the 'contents_cache' property for object-cmdsets). It is stored on the 'contents_cache' property
of the ObjectDB. of the ObjectDB.
""" """
def __init__(self, obj): def __init__(self, obj):
""" """
Sets up the contents handler. Sets up the contents handler.
@ -171,12 +172,12 @@ class ObjectDB(TypedObject):
# If this is a character object, the account is connected here. # If this is a character object, the account is connected here.
db_account = models.ForeignKey("accounts.AccountDB", null=True, verbose_name='account', on_delete=models.SET_NULL, db_account = models.ForeignKey("accounts.AccountDB", null=True, verbose_name='account', on_delete=models.SET_NULL,
help_text='an Account connected to this object, if any.') help_text='an Account connected to this object, if any.')
# the session id associated with this account, if any # the session id associated with this account, if any
db_sessid = models.CharField(null=True, max_length=32, validators=[validate_comma_separated_integer_list], db_sessid = models.CharField(null=True, max_length=32, validators=[validate_comma_separated_integer_list],
verbose_name="session id", verbose_name="session id",
help_text="csv list of session ids of connected Account, if any.") help_text="csv list of session ids of connected Account, if any.")
# The location in the game world. Since this one is likely # The location in the game world. Since this one is likely
# to change often, we set this with the 'location' property # to change often, we set this with the 'location' property
# to transparently handle Typeclassing. # to transparently handle Typeclassing.

View file

@ -39,6 +39,7 @@ class ObjectSessionHandler(object):
Handles the get/setting of the sessid Handles the get/setting of the sessid
comma-separated integer field comma-separated integer field
""" """
def __init__(self, obj): def __init__(self, obj):
""" """
Initializes the handler. Initializes the handler.
@ -1211,10 +1212,10 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
mapping = {} mapping = {}
mapping.update({ mapping.update({
"object": self, "object": self,
"exit": exits[0] if exits else "somwhere", "exit": exits[0] if exits else "somwhere",
"origin": location or "nowhere", "origin": location or "nowhere",
"destination": destination or "nowhere", "destination": destination or "nowhere",
}) })
location.msg_contents(string, exclude=(self, ), mapping=mapping) location.msg_contents(string, exclude=(self, ), mapping=mapping)
@ -1267,10 +1268,10 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
mapping = {} mapping = {}
mapping.update({ mapping.update({
"object": self, "object": self,
"exit": exits[0] if exits else "somewhere", "exit": exits[0] if exits else "somewhere",
"origin": origin or "nowhere", "origin": origin or "nowhere",
"destination": destination or "nowhere", "destination": destination or "nowhere",
}) })
destination.msg_contents(string, exclude=(self, ), mapping=mapping) destination.msg_contents(string, exclude=(self, ), mapping=mapping)
@ -1630,20 +1631,20 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
mapping = mapping or {} mapping = mapping or {}
mapping.update({ mapping.update({
"object": self, "object": self,
"location": self.location, "location": self.location,
"speech": message, "speech": message,
"receiver": receiver "receiver": receiver
}) })
if msg_self: if msg_self:
self_mapping = {k: v.get_display_name(self) if hasattr( self_mapping = {k: v.get_display_name(self) if hasattr(
v, "get_display_name") else str(v) for k, v in mapping.items()} v, "get_display_name") else str(v) for k, v in mapping.items()}
self.msg(msg_self.format(**self_mapping)) self.msg(msg_self.format(**self_mapping))
if receiver and msg_receiver: if receiver and msg_receiver:
receiver_mapping = {k: v.get_display_name(receiver) if hasattr( receiver_mapping = {k: v.get_display_name(receiver) if hasattr(
v, "get_display_name") else str(v) for k, v in mapping.items()} v, "get_display_name") else str(v) for k, v in mapping.items()}
receiver.msg(msg_receiver.format(**receiver_mapping)) receiver.msg(msg_receiver.format(**receiver_mapping))
if self.location and msg_location: if self.location and msg_location:
@ -1778,6 +1779,7 @@ class DefaultRoom(DefaultObject):
This is the base room object. It's just like any Object except its This is the base room object. It's just like any Object except its
location is always `None`. location is always `None`.
""" """
def basetype_setup(self): def basetype_setup(self):
""" """
Simple room setup setting locks to make sure the room Simple room setup setting locks to make sure the room

View file

@ -46,10 +46,10 @@ class ScriptDBAdmin(admin.ModelAdmin):
fieldsets = ( fieldsets = (
(None, { (None, {
'fields': (('db_key', 'db_typeclass_path'), 'db_interval', 'fields': (('db_key', 'db_typeclass_path'), 'db_interval',
'db_repeats', 'db_start_delay', 'db_persistent', 'db_repeats', 'db_start_delay', 'db_persistent',
'db_obj')}), 'db_obj')}),
) )
inlines = [ScriptTagInline, ScriptAttributeInline] inlines = [ScriptTagInline, ScriptAttributeInline]
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):

View file

@ -34,6 +34,7 @@ class ScriptDBManager(TypedObjectManager):
copy_script copy_script
""" """
def get_all_scripts_on_obj(self, obj, key=None): def get_all_scripts_on_obj(self, obj, key=None):
""" """
Find all Scripts related to a particular object. Find all Scripts related to a particular object.

Some files were not shown because too many files have changed in this diff Show more