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.

This commit is contained in:
Griatch 2015-11-01 17:13:00 +01:00
parent c51ccd5bc7
commit c58f858339
5 changed files with 111 additions and 66 deletions

View file

@ -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:

View file

@ -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):

View file

@ -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))

View file

@ -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)

View file

@ -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):