From c58f8583396d67b3a00955029963bd24b4051f29 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 1 Nov 2015 17:13:00 +0100 Subject: [PATCH] Reworked that look() methods on Players and Objects into at_look. They were also changed to accept pre-searched target objects rather than the command string. They also return a processed look string rather than sending it directly. The reason for this is that methods on the typeclass should not be handling command parsing - this should be the exclusive job of Command.parse in order to make command parsing completely contained withing one system. Likewise, it makes for more flexibility to not call self.msg() inside at_look but to let the outside caller do this explicitly - it might want to modify and append to the string before sending it off (something not used anywhere yet but which may be interesting). In order to correctly keep parsing entirely in the command body for the player, I made a custom parent for CmdOOCLook and CmdOOC, which does the parsing of the 'playable' characters already at the parse() step, storing the result in the .playable property on the (player-) command. This technique could probably be applied to other player commands looking up the _playable_characters Attribute, in order to centralize it. --- evennia/commands/default/building.py | 4 +- evennia/commands/default/general.py | 11 ++++- evennia/commands/default/player.py | 65 +++++++++++++++++++++++----- evennia/objects/objects.py | 46 +++++++++----------- evennia/players/players.py | 51 +++++++++++----------- 5 files changed, 111 insertions(+), 66 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 5b632c276..ed49223de 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -2003,7 +2003,7 @@ class CmdExamine(ObjManipCommand): obj = caller.location if not obj.access(caller, 'examine'): #If we don't have special info access, just look at the object instead. - caller.look(obj.name) + self.msg(caller.at_look(obj)) return # using callback for printing result whenever function returns. get_and_merge_cmdsets(obj, self.session, self.player, obj, "object").addCallback(get_cmdset_callback) @@ -2033,7 +2033,7 @@ class CmdExamine(ObjManipCommand): if not obj.access(caller, 'examine'): #If we don't have special info access, just look # at the object instead. - caller.look(obj_name) + self.msg(caller.at_look(obj)) continue if obj_attrs: diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 9b1916181..422648de2 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -58,7 +58,16 @@ class CmdLook(MuxCommand): """ Handle the looking. """ - self.caller.look(self.args) + if not self.args: + target = self.caller.location + if not target: + self.caller.msg("You have no location to look at!") + return + else: + target = self.caller.search(self.args) + if not target: + return + self.msg(self.caller.at_look(target)) class CmdNick(MuxCommand): diff --git a/evennia/commands/default/player.py b/evennia/commands/default/player.py index ec6ad4df9..b61f1c98d 100644 --- a/evennia/commands/default/player.py +++ b/evennia/commands/default/player.py @@ -25,25 +25,52 @@ from evennia.server.sessionhandler import SESSIONS from evennia.commands.default.muxcommand import MuxPlayerCommand from evennia.utils import utils, create, search, prettytable -MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS -MULTISESSION_MODE = settings.MULTISESSION_MODE +_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS +_MULTISESSION_MODE = settings.MULTISESSION_MODE # limit symbol import for API __all__ = ("CmdOOCLook", "CmdIC", "CmdOOC", "CmdPassword", "CmdQuit", "CmdCharCreate", "CmdOption", "CmdSessions", "CmdWho", "CmdColorTest", "CmdQuell") -# force max nr chars to 1 if mode is 0 or 1 -BASE_PLAYER_TYPECLASS = settings.BASE_PLAYER_TYPECLASS -PERMISSION_HIERARCHY = settings.PERMISSION_HIERARCHY -PERMISSION_HIERARCHY_LOWER = [perm.lower() for perm in PERMISSION_HIERARCHY] +class MuxPlayerLookCommand(MuxPlayerCommand): + """ + Custom parent (only) parsing for OOC looking, sets a "playable" + property on the command based on the parsing. + + """ + def parse(self): + "Custom parsing" + + super(MuxPlayerLookCommand, self).parse() + + if _MULTISESSION_MODE < 2: + # only one character allowed - not used in this mode + self.playable = None + return + + playable = self.player.db._playable_characters + if playable is not None: + # clean up list if character object was deleted in between + if None in playable: + playable = [character for character in playable if character] + self.player.db._playable_characters = playable + # store playable property + if self.args: + self.playable = dict((utils.to_str(char.key.lower()), char) + for char in playable).get(self.args.lower(), None) + else: + self.playable = playable + # Obs - these are all intended to be stored on the Player, and as such, # use self.player instead of self.caller, just to be sure. Also self.msg() # is used to make sure returns go to the right session -class CmdOOCLook(MuxPlayerCommand): +# note that this is inheriting from MuxPlayerLookCommand, +# and has the .playable property. +class CmdOOCLook(MuxPlayerLookCommand): """ look while out-of-character @@ -65,7 +92,14 @@ class CmdOOCLook(MuxPlayerCommand): def func(self): "implement the ooc look command" - self.player.look(self.args, sessid=self.sessid) + + if _MULTISESSION_MODE < 2: + # only one character allowed + self.msg("You are out-of-character (OOC).\nUse {w@ic{n to get back into the game.") + return + + # call on-player look helper method + self.msg(self.player.at_look(target=self.playable, sessid=self.sessid)) class CmdCharCreate(MuxPlayerCommand): @@ -93,7 +127,7 @@ class CmdCharCreate(MuxPlayerCommand): key = self.lhs desc = self.rhs - charmax = MAX_NR_CHARACTERS if MULTISESSION_MODE > 1 else 1 + charmax = _MAX_NR_CHARACTERS if _MULTISESSION_MODE > 1 else 1 if not player.is_superuser and \ (player.db._playable_characters and @@ -175,7 +209,9 @@ class CmdIC(MuxPlayerCommand): self.msg("{rYou cannot become {C%s{n: %s" % (new_character.name, exc)) -class CmdOOC(MuxPlayerCommand): +# note that this is inheriting from MuxPlayerLookCommand, +# and as such has the .playable property. +class CmdOOC(MuxPlayerLookCommand): """ stop puppeting and go ooc @@ -210,7 +246,14 @@ class CmdOOC(MuxPlayerCommand): try: player.unpuppet_object(sessid) self.msg("\n{GYou go OOC.{n\n") - player.look(sessid=sessid) + + if _MULTISESSION_MODE < 2: + # only one character allowed + self.msg("You are out-of-character (OOC).\nUse {w@ic{n to get back into the game.") + return + + self.msg(player.at_look(target=self.playable, sessid=sessid)) + except RuntimeError as exc: self.msg("{rCould not unpuppet from {c%s{n: %s" % (old_char, exc)) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 4df6dd144..ffd0fbe46 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1289,34 +1289,27 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): string += "\n{wYou see:{n " + ", ".join(users + things) return string - def look(self, arg_string=None): + def at_look(self, target): """ - This is called whenever this object looks at something. + Called when this object performs a look. It allows to + customize just what this means. It will not itself + send any data. Args: - arg_string (str, optional): The string of what is being looked at. - """ - if arg_string: - # Use search to handle duplicate/nonexistant results. - looking_at_obj = self.search(arg_string, use_nicks=True) - if not looking_at_obj: - return - else: - looking_at_obj = self.location - if not looking_at_obj: - self.msg("You have no location to look at!") - return + target (Object): The target being looked at. This is + commonly an object or the current location. It will + be checked for the "view" type access. - if not hasattr(looking_at_obj, 'return_appearance'): - # this is likely due to us having a player instead - looking_at_obj = looking_at_obj.character - if not looking_at_obj.access(self, "view"): - self.msg("Could not find '%s'." % args) - return - # get object's appearance - self.msg(looking_at_obj.return_appearance(self)) - # the object's at_desc() method. - looking_at_obj.at_desc(looker=self) + Returns: + lookstring (str): A ready-processed look string + potentially ready to return to the looker. + + """ + if not target.access(self, "view"): + return "Could not find '%s'." % target + # the target's at_desc() method. + target.at_desc(looker=self) + return target.return_appearance(self) def at_desc(self, looker=None): """ @@ -1408,7 +1401,7 @@ class DefaultCharacter(DefaultObject): We make sure to look around after a move. """ - self.look() + self.msg(self.at_look(self.location)) def at_pre_puppet(self, player, sessid=None): """ @@ -1440,7 +1433,8 @@ class DefaultCharacter(DefaultObject): """ self.msg("\nYou become {c%s{n.\n" % self.name) - self.look() + self.msg(self.at_look(self.location)) + def message(obj, from_obj): obj.msg("%s has entered the game." % self.get_display_name(obj), from_obj=from_obj) self.location.for_contents(message, exclude=[self], from_obj=self) diff --git a/evennia/players/players.py b/evennia/players/players.py index baf820a69..7c4a30266 100644 --- a/evennia/players/players.py +++ b/evennia/players/players.py @@ -21,7 +21,7 @@ from evennia.comms.models import ChannelDB from evennia.commands import cmdhandler from evennia.utils import logger from evennia.utils.utils import (lazy_property, to_str, - make_iter, to_unicode, + make_iter, to_unicode, is_iter, variable_from_module) from evennia.typeclasses.attributes import NickHandler from evennia.scripts.scripthandler import ScriptHandler @@ -700,7 +700,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): elif _MULTISESSION_MODE in (2, 3): # In this mode we by default end up at a character selection # screen. We execute look on the player. - self.look(sessid=sessid) + self.msg(self.at_look(sessid=sessid)) def at_failed_login(self, session): """ @@ -765,29 +765,28 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): """ pass - def look(self, arg_string=None, sessid=None): - if _MULTISESSION_MODE < 2: - # only one character allowed - string = "You are out-of-character (OOC).\nUse {w@ic{n to get back into the game." - self.msg(string) - elif arg_string: - key = arg_string.lower() - chars = dict((to_str(char.key.lower()), char) - for char in self.db._playable_characters) - looktarget = chars.get(key) - if looktarget: - self.msg(looktarget.return_appearance(self)) - else: - self.msg("No such character.") - else: - # get all our characters and sessions - characters = self.db._playable_characters + def at_look(self, target=None, sessid=None): + """ + Called when this object executes a look. It allows to customize + just what this means. - if characters is not None: - if None in characters: - # clean up list if character object was deleted in between - characters = [character for character in characters if character] - self.db._playable_characters = characters + Args: + target (Object or list, optional): An object or a list + objects to inspect. + sessid (int, optional): Id of the session doing this look. + + Returns: + look_string (str): A prepared look string, ready to send + off to any recipient (usually to ourselves) + + """ + + if target and not is_iter(target): + # single target - just show it + return target.return_appearance() + else: + # list of targets - make list + characters = target sessions = self.get_all_sessions() is_su = self.is_superuser @@ -826,7 +825,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): if csessid: # character is already puppeted sessi = self.get_session(csessid) - for sess in utils.make_iter(sessi): + for sess in make_iter(sessi): sid = sess in sessions and sessions.index(sess) + 1 if sess and sid: string += "\n - {G%s{n [%s] (played by you in session %i)" % (char.key, ", ".join(char.permissions.all()), sid) @@ -836,7 +835,7 @@ class DefaultPlayer(with_metaclass(TypeclassBase, PlayerDB)): # character is "free to puppet" string += "\n - %s [%s]" % (char.key, ", ".join(char.permissions.all())) string = ("-" * 68) + "\n" + string + "\n" + ("-" * 68) - self.msg(string) + return string class DefaultGuest(DefaultPlayer):