From f11e92b2c00c524609c8b6f3ab5d86bcb1722886 Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Tue, 28 Mar 2017 11:23:32 -0700 Subject: [PATCH 1/3] Add more flexibility to the hooks on say --- evennia/commands/default/general.py | 15 +++--- evennia/objects/objects.py | 73 +++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 8 deletions(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index 5070915555..b5cec9930f 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -409,16 +409,15 @@ class CmdSay(COMMAND_DEFAULT_CLASS): speech = self.args - # calling the speech hook on the location - speech = caller.location.at_say(caller, speech) + # Calling the at_before_say hook on the character + speech = caller.at_before_say(speech) - # Feedback for the object doing the talking. - caller.msg('You say, "%s|n"' % speech) - - # Build the string to emit to neighbors. - emit_string = '%s says, "%s|n"' % (caller.name, speech) - caller.location.msg_contents(emit_string, exclude=caller, from_obj=caller) + # If speech is empty, stop here + if not speech: + return + # Call the at_after_say hook on the character + caller.at_after_say(speech) class CmdWhisper(COMMAND_DEFAULT_CLASS): """ diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index d866f2e9af..cba11842cc 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1442,8 +1442,81 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): """ pass + def at_before_say(self, speech): + """ + Before the object says something. + + This hook is called by the 'say' command on the object itself + (probably a character). It is called before the actual say, + and can be used to control the content of the text to be said, + prevent saying altogether or perform some alternative checks. + This hook should return the modified speech. If this return + value is empty (like "" or None), the command is aborted. + + Args: + speech (str): the text to be said by self. + + Returns: + speech (str): the text to be said (can be modified). + + """ + return speech + + def at_after_say(self, speech, msg_self=None, msg_location=None, + mapping=None): + """ + Display the actual say of self. + + This hook should display the actual say of the object in its + location. It should both alert the object (self) and its + location that some text is spoken. The overriding of messages or + `mapping` allows for simple customization of the hook without + re-writing it completely. + + Args: + speech (str): the text to be said by self. + msg_self (str, optional): the replacement message to say to self. + msg_location (str, optional): the replacement message to say + to the location. + mapping (dict, optional): Additional mapping in messages. + + Both `msg_self` and `msg_location` should contain references + to other objects between braces, the way `locaiton.msg_contents` + would allow. For instance: + msg_self = 'You say: "{speech}"' + msg_location = '{object} says: "{speech}"' + + The following mappings can be used in both messages: + object: the object speaking. + location: the location where object is. + speech: the text spoken by self. + + You can use additional mappings if you want to add other + information in your messages. + + """ + if self.location is None: + self.msg("You can't utter a sound in the void.") + return + + msg_self = msg_self or 'You say, "{speech}"|n' + msg_location = msg_location or '{object} says, "{speech}"|n' + mapping = mapping or {} + mapping.update({ + "object": self, + "location": self.location, + "speech": speech, + }) + self_mapping = {k: v.get_display_name(self) if hasattr( + v, "get_display_name") else str(v) for k, v in mapping.items()} + print self_mapping + self.msg(msg_self.format(**self_mapping)) + self.location.msg_contents(msg_location, exclude=(self, ), + mapping=mapping) + def at_say(self, speaker, message): """ + DEPRECATED. Called on this object if an object inside this object speaks. The string returned from this method is the final form of the speech. From a5b26df330088b2a335fe7457e21f3719cb62211 Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Tue, 28 Mar 2017 12:07:17 -0700 Subject: [PATCH 2/3] Create hooks for the whisper command --- evennia/commands/default/general.py | 12 +++-- evennia/commands/default/tests.py | 2 +- evennia/objects/objects.py | 74 ++++++++++++++++++++++++++++- 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/evennia/commands/default/general.py b/evennia/commands/default/general.py index b5cec9930f..edb2e69b94 100644 --- a/evennia/commands/default/general.py +++ b/evennia/commands/default/general.py @@ -452,13 +452,15 @@ class CmdWhisper(COMMAND_DEFAULT_CLASS): return speech = self.rhs + # Call a hook to change the speech before whispering + speech = caller.at_before_whisper(receiver, speech) - # Feedback for the object doing the talking. - caller.msg('You whisper to %s, "%s|n"' % (receiver.key, speech)) + # If the speech is empty, abort the command + if not speech: + return - # Build the string to emit to receiver. - emit_string = '%s whispers, "%s|n"' % (caller.name, speech) - receiver.msg(emit_string, from_obj=caller) + # Call the at_after_whisper hook for feedback + caller.at_after_whisper(receiver, speech) class CmdPose(COMMAND_DEFAULT_CLASS): diff --git a/evennia/commands/default/tests.py b/evennia/commands/default/tests.py index 39f2f8841f..e99e12396b 100644 --- a/evennia/commands/default/tests.py +++ b/evennia/commands/default/tests.py @@ -128,7 +128,7 @@ class TestGeneral(CommandTest): self.call(general.CmdSay(), "Testing", "You say, \"Testing\"") def test_whisper(self): - self.call(general.CmdWhisper(), "Obj = Testing", "You whisper to Obj, \"Testing\"") + self.call(general.CmdWhisper(), "Obj = Testing", "You whisper to Obj, \"Testing\"", caller=self.char2) def test_access(self): self.call(general.CmdAccess(), "", "Permission Hierarchy (climbing):") diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index cba11842cc..1c8d8c132c 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1509,7 +1509,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): }) self_mapping = {k: v.get_display_name(self) if hasattr( v, "get_display_name") else str(v) for k, v in mapping.items()} - print self_mapping self.msg(msg_self.format(**self_mapping)) self.location.msg_contents(msg_location, exclude=(self, ), mapping=mapping) @@ -1533,6 +1532,79 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): """ return message + def at_before_whisper(self, receiver, speech): + """ + Before the object whispers something to receiver. + + This hook is called by the 'whisper' command on the object itself + (probably a character). It is called before the actual whisper, + and can be used to control the content of the text to be whispered, + prevent whispering altogether or perform some alternative checks. + This hook should return the modified speech. If this return + value is empty (like "" or None), the command is aborted. + + Args: + receiver (Object): the object to whisper to. + speech (str): the text to be whispered by self. + + Returns: + speech (str): the text to be whispered (can be modified). + + """ + return speech + + def at_after_whisper(self, receiver, speech, msg_self=None, + msg_receiver=None, mapping=None): + """ + Display the actual whisper of self. + + This hook should display the actual whisper of the object to + receiver. It should both alert the object (self) and the + receiver. You can also notify the location if you want to, + to indicate to others that a message was whispered but you + can't hear it. The overriding of messages or + `mapping` allows for simple customization of the hook without + re-writing it completely. + + Args: + receiver (Objecvt): the object to whisper to. + speech (str): the text to be said by self. + msg_self (str, optional): the replacement message to say to self. + msg_receiver (str, optional): the replacement message to say + to receiver. + mapping (dict, optional): Additional mapping in messages. + + Both `msg_self` and `msg_receiver` should contain references + to other objects between braces, the way `locaiton.msg_contents` + would allow. For instance: + msg_self = 'You whisper to {receiver}, "{speech}"|n' + msg_receiver = '{object} whispers: "{speech}"|n' + + The following mappings can be used in both messages: + object: the object whispering. + receiver: the object whispered to. + speech: the text spoken by self. + + You can use additional mappings if you want to add other + information in your messages. + + """ + msg_self = msg_self or 'You whisper to {receiver}, "{speech}"|n' + msg_receiver = msg_receiver or '{object} whispers: "{speech}"|n' + mapping = mapping or {} + mapping.update({ + "object": self, + "receiver": receiver, + "speech": speech, + }) + self_mapping = {k: v.get_display_name(self) if hasattr( + v, "get_display_name") else str(v) for k, v in mapping.items()} + receiver_mapping = {k: v.get_display_name(receiver) if hasattr( + v, "get_display_name") else str(v) for k, v in mapping.items()} + self.msg(msg_self.format(**self_mapping)) + receiver.msg(msg_receiver.format(**receiver_mapping)) + + # # Base Character object From 117d1b5809826f92040897d63d11da411db64ad4 Mon Sep 17 00:00:00 2001 From: Vincent Le Goff Date: Wed, 29 Mar 2017 12:14:32 -0700 Subject: [PATCH 3/3] Remove the deprecated Object.at_say hook --- evennia/objects/objects.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 1c8d8c132c..ded09d9f42 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1513,25 +1513,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.location.msg_contents(msg_location, exclude=(self, ), mapping=mapping) - def at_say(self, speaker, message): - """ - DEPRECATED. - Called on this object if an object inside this object speaks. - The string returned from this method is the final form of the - speech. - - Args: - speaker (Object): The object speaking. - message (str): The words spoken. - - Notes: - You should not need to add things like 'you say: ' or - similar here, that should be handled by the say command before - this. - - """ - return message - def at_before_whisper(self, receiver, speech): """ Before the object whispers something to receiver.