diff --git a/evennia/VERSION.txt b/evennia/VERSION.txt index faef31a435..f8d71478f5 100644 --- a/evennia/VERSION.txt +++ b/evennia/VERSION.txt @@ -1 +1 @@ -0.7.0 +0.8.0-dev diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 9feed46d2e..969e8f9d04 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -21,7 +21,7 @@ from evennia.objects.models import ObjectDB from evennia.comms.models import ChannelDB from evennia.commands import cmdhandler from evennia.utils import logger -from evennia.utils.utils import (lazy_property, +from evennia.utils.utils import (lazy_property, to_str, make_iter, to_unicode, is_iter, variable_from_module) from evennia.typeclasses.attributes import NickHandler @@ -421,10 +421,19 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): kwargs["options"] = options + if text is not None: + if not (isinstance(text, basestring) or isinstance(text, tuple)): + # sanitize text before sending across the wire + try: + text = to_str(text, force_string=True) + except Exception: + text = repr(text) + kwargs['text'] = text + # session relay sessions = make_iter(session) if session else self.sessions.all() for session in sessions: - session.data_out(text=text, **kwargs) + session.data_out(**kwargs) def execute_cmd(self, raw_string, session=None, **kwargs): """ @@ -457,7 +466,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): callertype="account", session=session, **kwargs) def search(self, searchdata, return_puppet=False, search_object=False, - typeclass=None, nofound_string=None, multimatch_string=None, **kwargs): + typeclass=None, nofound_string=None, multimatch_string=None, use_nicks=True, **kwargs): """ This is similar to `DefaultObject.search` but defaults to searching for Accounts only. @@ -481,6 +490,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): multimatch_string (str, optional): A one-time error message to echo if `searchdata` leads to multiple matches. If not given, will fall back to the default handler. + use_nicks (bool, optional): Use account-level nick replacement. Return: match (Account, Object or None): A single Account or Object match. @@ -496,8 +506,10 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): if searchdata.lower() in ("me", "*me", "self", "*self",): return self if search_object: - matches = ObjectDB.objects.object_search(searchdata, typeclass=typeclass) + matches = ObjectDB.objects.object_search(searchdata, typeclass=typeclass, use_nicks=use_nicks) else: + searchdata = self.nicks.nickreplace(searchdata, categories=("account", ), include_account=False) + matches = AccountDB.objects.account_search(searchdata, typeclass=typeclass) matches = _AT_SEARCH_RESULT(matches, self, query=searchdata, nofound_string=nofound_string, @@ -616,7 +628,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)): self.basetype_setup() self.at_account_creation() - permissions = settings.PERMISSION_ACCOUNT_DEFAULT + permissions = [settings.PERMISSION_ACCOUNT_DEFAULT] if hasattr(self, "_createdict"): # this will only be set if the utils.create_account # function was used to create the object. diff --git a/evennia/commands/command.py b/evennia/commands/command.py index 48a4b132da..17902b3602 100644 --- a/evennia/commands/command.py +++ b/evennia/commands/command.py @@ -297,7 +297,7 @@ class Command(with_metaclass(CommandMeta, object)): Args: srcobj (Object): Object trying to gain permission access_type (str, optional): The lock type to check. - default (bool, optional): The fallbacl result if no lock + default (bool, optional): The fallback result if no lock of matching `access_type` is found on this Command. """ diff --git a/evennia/commands/default/account.py b/evennia/commands/default/account.py index 90c2fdb954..40805f7465 100644 --- a/evennia/commands/default/account.py +++ b/evennia/commands/default/account.py @@ -455,7 +455,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS): Usage: @option[/save] [name = value] - Switch: + Switches: save - Save the current option settings for future logins. clear - Clear the saved options. @@ -467,6 +467,7 @@ class CmdOption(COMMAND_DEFAULT_CLASS): """ key = "@option" aliases = "@options" + switch_options = ("save", "clear") locks = "cmd:all()" # this is used by the parent @@ -549,8 +550,11 @@ class CmdOption(COMMAND_DEFAULT_CLASS): try: old_val = flags.get(new_name, False) new_val = validator(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)) + if old_val == new_val: + self.msg("Option |w%s|n was kept as '|w%s|n'." % (new_name, old_val)) + else: + 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)) return {new_name: new_val} except Exception as err: self.msg("|rCould not set option |w%s|r:|n %s" % (new_name, err)) @@ -572,7 +576,8 @@ class CmdOption(COMMAND_DEFAULT_CLASS): "TERM": utils.to_str, "UTF-8": validate_bool, "XTERM256": validate_bool, - "INPUTDEBUG": validate_bool} + "INPUTDEBUG": validate_bool, + "FORCEDENDLINE": validate_bool} name = self.lhs.upper() val = self.rhs.strip() @@ -646,6 +651,7 @@ class CmdQuit(COMMAND_DEFAULT_CLASS): game. Use the /all switch to disconnect from all sessions. """ key = "@quit" + switch_options = ("all",) locks = "cmd:all()" # this is used by the parent diff --git a/evennia/commands/default/admin.py b/evennia/commands/default/admin.py index 9da061cc04..4e517b77f9 100644 --- a/evennia/commands/default/admin.py +++ b/evennia/commands/default/admin.py @@ -36,6 +36,7 @@ class CmdBoot(COMMAND_DEFAULT_CLASS): """ key = "@boot" + switch_options = ("quiet", "sid") locks = "cmd:perm(boot) or perm(Admin)" help_category = "Admin" @@ -265,6 +266,7 @@ class CmdDelAccount(COMMAND_DEFAULT_CLASS): """ key = "@delaccount" + switch_options = ("delobj",) locks = "cmd:perm(delaccount) or perm(Developer)" help_category = "Admin" @@ -329,9 +331,9 @@ class CmdEmit(COMMAND_DEFAULT_CLASS): @pemit [, , ... =] Switches: - room : limit emits to rooms only (default) - accounts : limit emits to accounts only - contents : send to the contents of matched objects too + room - limit emits to rooms only (default) + accounts - limit emits to accounts only + contents - send to the contents of matched objects too Emits a message to the selected objects or to your immediate surroundings. If the object is a room, @@ -341,6 +343,7 @@ class CmdEmit(COMMAND_DEFAULT_CLASS): """ key = "@emit" aliases = ["@pemit", "@remit"] + switch_options = ("room", "accounts", "contents") locks = "cmd:perm(emit) or perm(Builder)" help_category = "Admin" @@ -442,14 +445,15 @@ class CmdPerm(COMMAND_DEFAULT_CLASS): @perm[/switch] * [= [,,...]] Switches: - del : delete the given permission from or . - account : set permission on an account (same as adding * to name) + del - delete the given permission from or . + account - set permission on an account (same as adding * to name) This command sets/clears individual permission strings on an object or account. If no permission is given, list all permissions on . """ key = "@perm" aliases = "@setperm" + switch_options = ("del", "account") locks = "cmd:perm(perm) or perm(Developer)" help_category = "Admin" @@ -544,7 +548,8 @@ class CmdWall(COMMAND_DEFAULT_CLASS): Usage: @wall - Announces a message to all connected accounts. + Announces a message to all connected sessions + including all currently unlogged in. """ key = "@wall" locks = "cmd:perm(wall) or perm(Admin)" @@ -556,5 +561,5 @@ class CmdWall(COMMAND_DEFAULT_CLASS): self.caller.msg("Usage: @wall ") return message = "%s shouts \"%s\"" % (self.caller.name, self.args) - self.msg("Announcing to all connected accounts ...") + self.msg("Announcing to all connected sessions ...") SESSIONS.announce_all(message) diff --git a/evennia/commands/default/batchprocess.py b/evennia/commands/default/batchprocess.py index f0b117a816..5970d35887 100644 --- a/evennia/commands/default/batchprocess.py +++ b/evennia/commands/default/batchprocess.py @@ -237,6 +237,7 @@ class CmdBatchCommands(_COMMAND_DEFAULT_CLASS): """ key = "@batchcommands" aliases = ["@batchcommand", "@batchcmd"] + switch_options = ("interactive",) locks = "cmd:perm(batchcommands) or perm(Developer)" help_category = "Building" @@ -347,6 +348,7 @@ class CmdBatchCode(_COMMAND_DEFAULT_CLASS): """ key = "@batchcode" aliases = ["@batchcodes"] + switch_options = ("interactive", "debug") locks = "cmd:superuser()" help_category = "Building" diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index f4a001e6d2..3cda726881 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -106,9 +106,15 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS): Usage: @alias [= [alias[,alias,alias,...]]] @alias = + @alias/category = [alias[,alias,...]: + + Switches: + category - requires ending input with :category, to store the + given aliases with the given category. Assigns aliases to an object so it can be referenced by more - than one name. Assign empty to remove all aliases from object. + than one name. Assign empty to remove all aliases from object. If + assigning a category, all aliases given will be using this category. Observe that this is not the same thing as personal aliases created with the 'nick' command! Aliases set with @alias are @@ -118,6 +124,7 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS): key = "@alias" aliases = "@setobjalias" + switch_options = ("category",) locks = "cmd:perm(setobjalias) or perm(Builder)" help_category = "Building" @@ -138,9 +145,12 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS): return if self.rhs is None: # no =, so we just list aliases on object. - aliases = obj.aliases.all() + aliases = obj.aliases.all(return_key_and_category=True) if aliases: - caller.msg("Aliases for '%s': %s" % (obj.get_display_name(caller), ", ".join(aliases))) + caller.msg("Aliases for %s: %s" % ( + obj.get_display_name(caller), + ", ".join("'%s'%s" % (alias, "" if category is None else "[category:'%s']" % category) + for (alias, category) in aliases))) else: caller.msg("No aliases exist for '%s'." % obj.get_display_name(caller)) return @@ -159,17 +169,27 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS): caller.msg("No aliases to clear.") return + category = None + if "category" in self.switches: + if ":" in self.rhs: + rhs, category = self.rhs.rsplit(':', 1) + category = category.strip() + else: + caller.msg("If specifying the /category switch, the category must be given " + "as :category at the end.") + else: + rhs = self.rhs + # merge the old and new aliases (if any) - old_aliases = obj.aliases.all() - new_aliases = [alias.strip().lower() for alias in self.rhs.split(',') - if alias.strip()] + old_aliases = obj.aliases.get(category=category, return_list=True) + new_aliases = [alias.strip().lower() for alias in rhs.split(',') if alias.strip()] # make the aliases only appear once old_aliases.extend(new_aliases) aliases = list(set(old_aliases)) # save back to object. - obj.aliases.add(aliases) + obj.aliases.add(aliases, category=category) # we need to trigger this here, since this will force # (default) Exits to rebuild their Exit commands with the new @@ -177,7 +197,8 @@ class CmdSetObjAlias(COMMAND_DEFAULT_CLASS): obj.at_cmdset_get(force_init=True) # report all aliases on the object - caller.msg("Alias(es) for '%s' set to %s." % (obj.get_display_name(caller), str(obj.aliases))) + caller.msg("Alias(es) for '%s' set to '%s'%s." % (obj.get_display_name(caller), + str(obj.aliases), " (category: '%s')" % category if category else "")) class CmdCopy(ObjManipCommand): @@ -198,6 +219,7 @@ class CmdCopy(ObjManipCommand): """ key = "@copy" + switch_options = ("reset",) locks = "cmd:perm(copy) or perm(Builder)" help_category = "Building" @@ -279,6 +301,7 @@ class CmdCpAttr(ObjManipCommand): If you don't supply a source object, yourself is used. """ key = "@cpattr" + switch_options = ("move",) locks = "cmd:perm(cpattr) or perm(Builder)" help_category = "Building" @@ -420,6 +443,7 @@ class CmdMvAttr(ObjManipCommand): object. If you don't supply a source object, yourself is used. """ key = "@mvattr" + switch_options = ("copy",) locks = "cmd:perm(mvattr) or perm(Builder)" help_category = "Building" @@ -468,6 +492,7 @@ class CmdCreate(ObjManipCommand): """ key = "@create" + switch_options = ("drop",) locks = "cmd:perm(create) or perm(Builder)" help_category = "Building" @@ -553,6 +578,7 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): """ key = "@desc" aliases = "@describe" + switch_options = ("edit",) locks = "cmd:perm(desc) or perm(Builder)" help_category = "Building" @@ -568,6 +594,9 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): if not obj: return + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + self.caller.msg("You don't have permission to edit the description of %s." % obj.key) + self.caller.db.evmenu_target = obj # launch the editor EvEditor(self.caller, loadfunc=_desc_load, savefunc=_desc_save, @@ -597,7 +626,7 @@ class CmdDesc(COMMAND_DEFAULT_CLASS): if not obj: return desc = self.args - if obj.access(caller, "edit"): + if (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): obj.db.desc = desc caller.msg("The description was set on %s." % obj.get_display_name(caller)) else: @@ -611,11 +640,11 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS): Usage: @destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...] - switches: + Switches: override - The @destroy command will usually avoid accidentally destroying account objects. This switch overrides this safety. force - destroy without confirmation. - examples: + Examples: @destroy house, roof, door, 44-78 @destroy 5-10, flower, 45 @destroy/force north @@ -628,6 +657,7 @@ class CmdDestroy(COMMAND_DEFAULT_CLASS): key = "@destroy" aliases = ["@delete", "@del"] + switch_options = ("override", "force") locks = "cmd:perm(destroy) or perm(Builder)" help_category = "Building" @@ -751,6 +781,7 @@ class CmdDig(ObjManipCommand): would be 'north;no;n'. """ key = "@dig" + switch_options = ("teleport",) locks = "cmd:perm(dig) or perm(Builder)" help_category = "Building" @@ -860,7 +891,7 @@ class CmdDig(ObjManipCommand): new_back_exit.dbref, alias_string) caller.msg("%s%s%s" % (room_string, exit_to_string, exit_back_string)) - if new_room and ('teleport' in self.switches or "tel" in self.switches): + if new_room and 'teleport' in self.switches: caller.move_to(new_room) @@ -893,6 +924,7 @@ class CmdTunnel(COMMAND_DEFAULT_CLASS): key = "@tunnel" aliases = ["@tun"] + switch_options = ("oneway", "tel") locks = "cmd: perm(tunnel) or perm(Builder)" help_category = "Building" @@ -1455,6 +1487,13 @@ class CmdSetAttribute(ObjManipCommand): Switch: edit: Open the line editor (string values only) + script: If we're trying to set an attribute on a script + channel: If we're trying to set an attribute on a channel + account: If we're trying to set an attribute on an account + room: Setting an attribute on a room (global search) + exit: Setting an attribute on an exit (global search) + char: Setting an attribute on a character (global search) + character: Alias for char, as above. Sets attributes on objects. The second form clears a previously set attribute while the last form @@ -1555,6 +1594,38 @@ class CmdSetAttribute(ObjManipCommand): # start the editor EvEditor(self.caller, load, save, key="%s/%s" % (obj, attr)) + def search_for_obj(self, objname): + """ + Searches for an object matching objname. The object may be of different typeclasses. + Args: + objname: Name of the object we're looking for + + Returns: + A typeclassed object, or None if nothing is found. + """ + from evennia.utils.utils import variable_from_module + _AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1)) + caller = self.caller + if objname.startswith('*') or "account" in self.switches: + found_obj = caller.search_account(objname.lstrip('*')) + elif "script" in self.switches: + found_obj = _AT_SEARCH_RESULT(search.search_script(objname), caller) + elif "channel" in self.switches: + found_obj = _AT_SEARCH_RESULT(search.search_channel(objname), caller) + else: + global_search = True + if "char" in self.switches or "character" in self.switches: + typeclass = settings.BASE_CHARACTER_TYPECLASS + elif "room" in self.switches: + typeclass = settings.BASE_ROOM_TYPECLASS + elif "exit" in self.switches: + typeclass = settings.BASE_EXIT_TYPECLASS + else: + global_search = False + typeclass = None + found_obj = caller.search(objname, global_search=global_search, typeclass=typeclass) + return found_obj + def func(self): """Implement the set attribute - a limited form of @py.""" @@ -1568,10 +1639,7 @@ class CmdSetAttribute(ObjManipCommand): objname = self.lhs_objattr[0]['name'] attrs = self.lhs_objattr[0]['attrs'] - if objname.startswith('*'): - obj = caller.search_account(objname.lstrip('*')) - else: - obj = caller.search(objname) + obj = self.search_for_obj(objname) if not obj: return @@ -1581,6 +1649,10 @@ class CmdSetAttribute(ObjManipCommand): result = [] if "edit" in self.switches: # edit in the line editor + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return + if len(attrs) > 1: caller.msg("The Line editor can only be applied " "to one attribute at a time.") @@ -1601,12 +1673,18 @@ class CmdSetAttribute(ObjManipCommand): return else: # deleting the attribute(s) + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return for attr in attrs: if not self.check_attr(obj, attr): continue result.append(self.rm_attr(obj, attr)) else: # setting attribute(s). Make sure to convert to real Python type before saving. + if not (obj.access(self.caller, 'control') or obj.access(self.caller, 'edit')): + caller.msg("You don't have permission to edit %s." % obj.key) + return for attr in attrs: if not self.check_attr(obj, attr): continue @@ -1807,13 +1885,13 @@ class CmdLock(ObjManipCommand): For example: 'get: id(25) or perm(Admin)' - The 'get' access_type is checked by the get command and will - an object locked with this string will only be possible to - pick up by Admins or by object with id=25. + The 'get' lock access_type is checked e.g. by the 'get' command. + An object locked with this example lock will only be possible to pick up + by Admins or by an object with id=25. You can add several access_types after one another by separating them by ';', i.e: - 'get:id(25);delete:perm(Builder)' + 'get:id(25); delete:perm(Builder)' """ key = "@lock" aliases = ["@locks"] @@ -1840,9 +1918,16 @@ class CmdLock(ObjManipCommand): obj = caller.search(objname) if not obj: return - if not (obj.access(caller, 'control') or obj.access(caller, "edit")): + has_control_access = obj.access(caller, 'control') + if access_type == 'control' and not has_control_access: + # only allow to change 'control' access if you have 'control' access already + caller.msg("You need 'control' access to change this type of lock.") + return + + if not has_control_access or obj.access(caller, "edit"): caller.msg("You are not allowed to do that.") return + lockdef = obj.locks.get(access_type) if lockdef: @@ -2182,12 +2267,15 @@ class CmdFind(COMMAND_DEFAULT_CLASS): Usage: @find[/switches] [= dbrefmin[-dbrefmax]] + @locate - this is a shorthand for using the /loc switch. Switches: - room - only look for rooms (location=None) - exit - only look for exits (destination!=None) - char - only look for characters (BASE_CHARACTER_TYPECLASS) - exact- only exact matches are returned. + room - only look for rooms (location=None) + exit - only look for exits (destination!=None) + char - only look for characters (BASE_CHARACTER_TYPECLASS) + exact - only exact matches are returned. + loc - display object location if exists and match has one result + startswith - search for names starting with the string, rather than containing Searches the database for an object of a particular name or exact #dbref. Use *accountname to search for an account. The switches allows for @@ -2198,6 +2286,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS): key = "@find" aliases = "@search, @locate" + switch_options = ("room", "exit", "char", "exact", "loc", "startswith") locks = "cmd:perm(find) or perm(Builder)" help_category = "Building" @@ -2210,6 +2299,9 @@ class CmdFind(COMMAND_DEFAULT_CLASS): caller.msg("Usage: @find [= low [-high]]") return + if "locate" in self.cmdstring: # Use option /loc as a default for @locate command alias + switches.append('loc') + searchstring = self.lhs low, high = 1, ObjectDB.objects.all().order_by("-id")[0].id if self.rhs: @@ -2231,7 +2323,7 @@ class CmdFind(COMMAND_DEFAULT_CLASS): restrictions = "" if self.switches: - restrictions = ", %s" % (",".join(self.switches)) + restrictions = ", %s" % (", ".join(self.switches)) if is_dbref or is_account: @@ -2259,6 +2351,8 @@ class CmdFind(COMMAND_DEFAULT_CLASS): else: result = result[0] string += "\n|g %s - %s|n" % (result.get_display_name(caller), result.path) + if "loc" in self.switches and not is_account and result.location: + string += " (|wlocation|n: |g{}|n)".format(result.location.get_display_name(caller)) else: # Not an account/dbref search but a wider search; build a queryset. # Searchs for key and aliases @@ -2266,10 +2360,14 @@ class CmdFind(COMMAND_DEFAULT_CLASS): keyquery = Q(db_key__iexact=searchstring, id__gte=low, id__lte=high) aliasquery = Q(db_tags__db_key__iexact=searchstring, db_tags__db_tagtype__iexact="alias", id__gte=low, id__lte=high) - else: + elif "startswith" in switches: keyquery = Q(db_key__istartswith=searchstring, id__gte=low, id__lte=high) aliasquery = Q(db_tags__db_key__istartswith=searchstring, db_tags__db_tagtype__iexact="alias", id__gte=low, id__lte=high) + else: + keyquery = Q(db_key__icontains=searchstring, id__gte=low, id__lte=high) + aliasquery = Q(db_tags__db_key__icontains=searchstring, + db_tags__db_tagtype__iexact="alias", id__gte=low, id__lte=high) results = ObjectDB.objects.filter(keyquery | aliasquery).distinct() nresults = results.count() @@ -2294,6 +2392,8 @@ class CmdFind(COMMAND_DEFAULT_CLASS): else: string = "|wOne Match|n(#%i-#%i%s):" % (low, high, restrictions) string += "\n |g%s - %s|n" % (results[0].get_display_name(caller), results[0].path) + if "loc" in self.switches and nresults == 1 and results[0].location: + string += " (|wlocation|n: |g{}|n)".format(results[0].location.get_display_name(caller)) else: string = "|wMatch|n(#%i-#%i%s):" % (low, high, restrictions) string += "\n |RNo matches found for '%s'|n" % searchstring @@ -2307,11 +2407,11 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS): teleport object to another location Usage: - @tel/switch [ =] + @tel/switch [ to||=] Examples: @tel Limbo - @tel/quiet box Limbo + @tel/quiet box = Limbo @tel/tonone box Switches: @@ -2327,9 +2427,12 @@ class CmdTeleport(COMMAND_DEFAULT_CLASS): loc - teleport object to the target's location instead of its contents Teleports an object somewhere. If no object is given, you yourself - is teleported to the target location. """ + is teleported to the target location. + """ key = "@tel" aliases = "@teleport" + switch_options = ("quiet", "intoexit", "tonone", "loc") + rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage. locks = "cmd:perm(teleport) or perm(Builder)" help_category = "Building" @@ -2437,6 +2540,7 @@ class CmdScript(COMMAND_DEFAULT_CLASS): key = "@script" aliases = "@addscript" + switch_options = ("start", "stop") locks = "cmd:perm(script) or perm(Builder)" help_category = "Building" @@ -2536,6 +2640,7 @@ class CmdTag(COMMAND_DEFAULT_CLASS): key = "@tag" aliases = ["@tags"] + options = ("search", "del") locks = "cmd:perm(tag) or perm(Builder)" help_category = "Building" arg_regex = r"(/\w+?(\s|$))|\s|$" @@ -2677,6 +2782,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): """ key = "@spawn" + switch_options = ("noloc", ) locks = "cmd:perm(spawn) or perm(Builder)" help_category = "Building" @@ -2686,7 +2792,7 @@ class CmdSpawn(COMMAND_DEFAULT_CLASS): def _show_prototypes(prototypes): """Helper to show a list of available prototypes""" prots = ", ".join(sorted(prototypes.keys())) - return "\nAvailable prototypes (case sensistive): %s" % ( + return "\nAvailable prototypes (case sensitive): %s" % ( "\n" + utils.fill(prots) if prots else "None") prototypes = spawn(return_prototypes=True) diff --git a/evennia/commands/default/cmdset_account.py b/evennia/commands/default/cmdset_account.py index 4e357a2ce0..d7b887c017 100644 --- a/evennia/commands/default/cmdset_account.py +++ b/evennia/commands/default/cmdset_account.py @@ -11,7 +11,7 @@ command method rather than caller.msg(). from evennia.commands.cmdset import CmdSet from evennia.commands.default import help, comms, admin, system -from evennia.commands.default import building, account +from evennia.commands.default import building, account, general class AccountCmdSet(CmdSet): @@ -39,6 +39,9 @@ class AccountCmdSet(CmdSet): self.add(account.CmdColorTest()) self.add(account.CmdQuell()) + # nicks + self.add(general.CmdNick()) + # testing self.add(building.CmdExamine()) diff --git a/evennia/commands/default/cmdset_unloggedin.py b/evennia/commands/default/cmdset_unloggedin.py index 5e43d5e8c8..1c45d908aa 100644 --- a/evennia/commands/default/cmdset_unloggedin.py +++ b/evennia/commands/default/cmdset_unloggedin.py @@ -23,3 +23,4 @@ class UnloggedinCmdSet(CmdSet): self.add(unloggedin.CmdUnconnectedHelp()) self.add(unloggedin.CmdUnconnectedEncoding()) self.add(unloggedin.CmdUnconnectedScreenreader()) + self.add(unloggedin.CmdUnconnectedInfo()) diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index 37a4934d16..d9fe0b0d20 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -377,7 +377,7 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS): Usage: @cboot[/quiet] = [:reason] - Switches: + Switch: quiet - don't notify the channel Kicks an account or object from a channel you control. @@ -385,6 +385,7 @@ class CmdCBoot(COMMAND_DEFAULT_CLASS): """ key = "@cboot" + switch_options = ("quiet",) locks = "cmd: not pperm(channel_banned)" help_category = "Comms" @@ -453,6 +454,7 @@ class CmdCemit(COMMAND_DEFAULT_CLASS): key = "@cemit" aliases = ["@cmsg"] + switch_options = ("sendername", "quiet") locks = "cmd: not pperm(channel_banned) and pperm(Player)" help_category = "Comms" @@ -683,6 +685,7 @@ class CmdPage(COMMAND_DEFAULT_CLASS): key = "page" aliases = ['tell'] + switch_options = ("last", "list") locks = "cmd:not pperm(page_banned)" help_category = "Comms" @@ -850,6 +853,7 @@ class CmdIRC2Chan(COMMAND_DEFAULT_CLASS): """ key = "@irc2chan" + switch_options = ("delete", "remove", "disconnect", "list", "ssl") locks = "cmd:serversetting(IRC_ENABLED) and pperm(Developer)" help_category = "Comms" @@ -1016,6 +1020,7 @@ class CmdRSS2Chan(COMMAND_DEFAULT_CLASS): """ key = "@rss2chan" + switch_options = ("disconnect", "remove", "list") locks = "cmd:serversetting(RSS_ENABLED) and pperm(Developer)" help_category = "Comms" diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 2f880f3f7f..d72a2006b9 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -1,6 +1,7 @@ """ General Character commands usually available to all characters """ +import re from django.conf import settings from evennia.utils import utils, evtable from evennia.typeclasses.attributes import NickTemplateInvalid @@ -70,42 +71,45 @@ class CmdLook(COMMAND_DEFAULT_CLASS): target = caller.search(self.args) if not target: return - self.msg(caller.at_look(target)) + self.msg((caller.at_look(target), {'type':'look'}), options=None) class CmdNick(COMMAND_DEFAULT_CLASS): """ - define a personal alias/nick + define a personal alias/nick by defining a string to + match and replace it with another on the fly Usage: nick[/switches] [= [replacement_string]] nick[/switches]