From 05a0bb47addf959fd02ed81e1b246d6ccd36906f Mon Sep 17 00:00:00 2001 From: Griatch Date: Sat, 29 Feb 2020 14:00:04 +0100 Subject: [PATCH] Make RPSystem CmdRecog list recogs if given no args. Resolve #2059. --- CHANGELOG.md | 2 ++ evennia/contrib/rpsystem.py | 67 ++++++++++++++++++++++++++++++------- evennia/contrib/tests.py | 45 +++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a22e04dc2..b355e4b6b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ without arguments starts a full interactive Python console. and `SERVER_LOG_MAX_SIZE` (and equivalent for PORTAL) to control log rotation. - Addded `inside_rec` lockfunc - if room is locked, the normal `inside()` lockfunc will fail e.g. for your inventory objs (since their loc is you), whereas this will pass. +- RPSystem contrib's CmdRecog will now list all recogs if no arg is given. Also multiple + bugfixes. ## Evennia 0.9 (2018-2019) diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index 4e2ecf7334..4f68f0dc44 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -798,6 +798,16 @@ class RecogHandler(object): # recog_mask log not passed, disable recog return obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key + def all(self): + """ + Get a mapping of the recogs stored in handler. + + Returns: + recogs (dict): A mapping of {recog: obj} stored in handler. + + """ + return {self.obj2recog[obj]: obj for obj in self.obj2recog.keys()} + def remove(self, obj): """ Clear recog for a given object. @@ -931,6 +941,9 @@ class CmdSdesc(RPCommand): # set/look at own sdesc except SdescError as err: caller.msg(err) return + except AttributeError: + caller.msg(f"Cannot set sdesc on {caller.key}.") + return caller.msg("%s's sdesc was set to '%s'." % (caller.key, sdesc)) @@ -1040,6 +1053,7 @@ class CmdRecog(RPCommand): # assign personal alias to object in room Recognize another person in the same room. Usage: + recog recog sdesc as alias forget alias @@ -1047,8 +1061,8 @@ class CmdRecog(RPCommand): # assign personal alias to object in room recog tall man as Griatch forget griatch - This will assign a personal alias for a person, or - forget said alias. + This will assign a personal alias for a person, or forget said alias. + Using the command without arguments will list all current recogs. """ @@ -1057,6 +1071,7 @@ class CmdRecog(RPCommand): # assign personal alias to object in room def parse(self): "Parse for the sdesc as alias structure" + self.sdesc, self.alias = "", "" if " as " in self.args: self.sdesc, self.alias = [part.strip() for part in self.args.split(" as ", 2)] elif self.args: @@ -1069,22 +1084,47 @@ class CmdRecog(RPCommand): # assign personal alias to object in room def func(self): "Assign the recog" caller = self.caller - if not self.args: - caller.msg("Usage: recog as or forget ") - return - sdesc = self.sdesc alias = self.alias.rstrip(".?!") + sdesc = self.sdesc + + recog_mode = self.cmdstring != "forget" and alias and sdesc + forget_mode = self.cmdstring == "forget" and sdesc + list_mode = not self.args + + if not (recog_mode or forget_mode or list_mode): + caller.msg("Usage: recog, recog as or forget ") + return + + if list_mode: + # list all previously set recogs + all_recogs = caller.recog.all() + if not all_recogs: + caller.msg( + "You recognize no-one. " "(Use 'recog as ' to recognize people." + ) + else: + # note that we don't skip those failing enable_recog lock here, + # because that would actually reveal more than we want. + lst = "\n".join( + " {} ({})".format(key, obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key) + for key, obj in all_recogs.items() + ) + caller.msg( + f"Currently recognized (use 'recog as ' to add " + f"new and 'forget ' to remove):\n{lst}" + ) + return + prefixed_sdesc = sdesc if sdesc.startswith(_PREFIX) else _PREFIX + sdesc candidates = caller.location.contents matches = parse_sdescs_and_recogs(caller, candidates, prefixed_sdesc, search_mode=True) nmatches = len(matches) - # handle 0, 1 and >1 matches + # handle 0 and >1 matches if nmatches == 0: caller.msg(_EMOTE_NOMATCH_ERROR.format(ref=sdesc)) elif nmatches > 1: reflist = [ - "%s%s%s (%s%s)" - % ( + "{}{}{} ({}{})".format( inum + 1, _NUM_SEP, _RE_PREFIX.sub("", sdesc), @@ -1094,17 +1134,20 @@ class CmdRecog(RPCommand): # assign personal alias to object in room for inum, obj in enumerate(matches) ] caller.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=sdesc, reflist="\n ".join(reflist))) + else: + # one single match obj = matches[0] if not obj.access(self.obj, "enable_recog", default=True): # don't apply recog if object doesn't allow it (e.g. by being masked). - caller.msg("Can't recognize someone who is masked.") + caller.msg("It's impossible to recognize them.") return - if self.cmdstring == "forget": + if forget_mode: # remove existing recog caller.recog.remove(obj) - caller.msg("%s will now know only '%s'." % (caller.key, obj.recog.get(obj))) + caller.msg("%s will now know them only as '%s'." % (caller.key, obj.recog.get(obj))) else: + # set recog sdesc = obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key try: alias = caller.recog.add(obj, alias) diff --git a/evennia/contrib/tests.py b/evennia/contrib/tests.py index fa132f6264..d394cd5a3b 100644 --- a/evennia/contrib/tests.py +++ b/evennia/contrib/tests.py @@ -169,6 +169,8 @@ class TestRPSystem(EvenniaTest): self.speaker.recog.remove(self.receiver1) self.assertEqual(self.speaker.recog.get(self.receiver1), sdesc1) + self.assertEqual(self.speaker.recog.all(), {"Mr Receiver2": self.receiver2}) + def test_parse_language(self): self.assertEqual( rpsystem.parse_language(self.speaker, emote), @@ -233,6 +235,49 @@ class TestRPSystem(EvenniaTest): self.assertEqual(self.speaker.search("colliding"), self.receiver2) +class TestRPSystemCommands(CommandTest): + def setUp(self): + super().setUp() + self.char1.swap_typeclass(rpsystem.ContribRPCharacter) + self.char2.swap_typeclass(rpsystem.ContribRPCharacter) + + def test_commands(self): + + self.call( + rpsystem.CmdSdesc(), "Foobar Character", "Char's sdesc was set to 'Foobar Character'." + ) + self.call( + rpsystem.CmdSdesc(), + "BarFoo Character", + "Char2's sdesc was set to 'BarFoo Character'.", + caller=self.char2, + ) + self.call(rpsystem.CmdSay(), "Hello!", 'Char says, "Hello!"') + self.call(rpsystem.CmdEmote(), "/me smiles to /barfoo.", "Char smiles to BarFoo Character") + self.call( + rpsystem.CmdPose(), + "stands by the bar", + "Pose will read 'Foobar Character stands by the bar.'.", + ) + self.call( + rpsystem.CmdRecog(), + "barfoo as friend", + "Char will now remember BarFoo Character as friend.", + ) + self.call( + rpsystem.CmdRecog(), + "", + "Currently recognized (use 'recog as ' to add new " + "and 'forget ' to remove):\n friend (BarFoo Character)", + ) + self.call( + rpsystem.CmdRecog(), + "friend", + "Char will now know them only as 'BarFoo Character'", + cmdstring="forget", + ) + + # Testing of ExtendedRoom contrib from django.conf import settings