From 6cea0e122a0bea9ea5135f0a43c5f1f739be8926 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Mon, 3 Nov 2025 22:08:07 -0800 Subject: [PATCH] Better 'say' command That is easier to use. --- commands/everyone.py | 241 ++++++++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 105 deletions(-) diff --git a/commands/everyone.py b/commands/everyone.py index f050192..5a45056 100755 --- a/commands/everyone.py +++ b/commands/everyone.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from random import random -from re import split, sub, MULTILINE +from re import match, split, sub, MULTILINE from django.core.exceptions import ObjectDoesNotExist from evennia.commands.default.general import CmdGet, NumberedTargetCommand @@ -251,160 +251,191 @@ class CmdWhisper(MuxCommand): self.caller.msg(full_speech, from_obj=self.caller) -class CmdSay(MuxCommand): - """ - Say something to the characters in the same area. +class CmdSay(Command): + """Say something to the characters in the same area. - For instance: + Usage: - |gsay Good evening!|n + |gsay [[] [to] [],] |n - However, you can use an alias and simply type: + This command has many optional strings. You see, the text within + brackets, [...] are optional, while text in <...> are to be + replaced, and this technical jargon probably means little, so + perhaps examples would be better: - |g"Good evening! + |gsay Good evening.|n + |wYou say, "Good evening."|n Or: - |g'Good evening! + |gsay loudly, Good evening!|n + |wYou loudly exclaim, "Good evening!"|n - Creatures and objects in this game can sometimes respond to what you say. + In the second example, the exclamation point changes the 'say' to + an 'exclaim'. A question mark changes 'say' to 'ask'. - Usage: - say phrase - say/to char1 [, char2 ...] = phrase - say[/switches] phrase + Also, you gave an |wadverb|n that ends in -ly, as well as a comma. + The comma is important, as it triggers |wprocessing|n. Without + the comma, you would see: - Where switches can be any of the following: + |gs loudly Good evening! + |wYou exclaim, "loudly Good evening!"|n - - exclaim : To replace 'says' with 'exclaims' - - yell : To replace 'says' with 'yells' - - scream : To replace 'says' with 'screams' - - ask : To replace 'says' with 'asks' - - to : Directs phrase to one or more characters - in the same area. Note others can still hear - the statement (see the 'whisper' command). - - adverb : Any adverb-like word that ends in '-ly' - is added to the say command, for instance: + You can also direct your message to a particular person (or thing), + as in: - say/quietly Hi there. + |gsay to heron, How do you do? + |wYou ask the purple heron, "How do you do?"|n + "What can I do for you?" asks the purple heron. - Shows as: + Again, the comma is important, otherwise, you will see: + + |gsay to heron How do you do? + |wYou ask, "to heron How do you do?"|n + The purple heron questions, "Uhm. I'm not sure how to respond." + + You can replace the 'say' command with any of the following: + + - shout + - scream + - respond + - reply + - yell + - ask + + Because this command is so common, you can also use ", as in: + + |g"What's going on?|n - You quietly say, "Hi there." """ key = "say" + verb = "say" aliases = ["says", "speak", "shout", "yell", "exclaim", "scream", "ask", - "reply", "respond", "\"", "'"] - priority = 0 + "reply", "respond", '"', "'"] locks = "cmd:all()" - rhs_split = ("=") + # don't require a space after `say/'/"` arg_regex = None + adverb = None + target = None + + def parse(self): + """Parse the input into speech parts.""" + self.phrase = self.args.strip() + + m = match(r".+\?.*", self.phrase) + if m: + self.verb = "ask" + m = match(r".+!.*", self.phrase) + if m: + self.verb = "exclaim" + + # Final quotes can be trimmed: + self.phrase = self.phrase.strip('"').strip("'") + + m = match(r"(.*) *, *(.+)", self.phrase) + if m: + self.phrase = m.group(2) + for word in split(r" +", m.group(1)): + if word.endswith("ly") and not self.adverb: + self.adverb = word + elif word == "to": + pass + else: + self.target = self.caller.search(word) def func(self): """Implement the new 'say' command with switches.""" speaker = self.caller - - if not self.args: + if not self.phrase or self.phrase == "": speaker.msg("Say what?") return - if 'to' in self.switches and not self.rhs: - speaker.msg(paragraph(""" - When attempting to say something to one or more - characters, use the '=' character to identify what you - want to say. - For instance, |gsay/to elf = Hi there.|n """)) - return - - if self.rhs: - speech = self.rhs - else: - speech = self.args - # If speech is empty, stop here - if not speaker.at_pre_say(speech): + if not speaker.at_pre_say(self.phrase): return - adverb = '' - for switch in self.switches: - if switch.endswith('ly'): - adverb = switch + ' ' - - if 'scream' in self.switches or self.cmdstring == 'scream': - verb = 'scream' - elif 'shout' in self.switches or self.cmdstring == 'shout': - verb = 'shout' - elif 'respond' in self.switches or self.cmdstring == 'respond': - verb = 'respond' - elif 'reply' in self.switches or self.cmdstring == 'reply': - verb = 'reply' - elif 'yell' in self.switches or self.cmdstring == 'yell': - verb = 'yell' - elif 'exclaim' in self.switches or self.cmdstring == 'exclaim' or speech.endswith('!'): - verb = 'exclaim' - elif 'ask' in self.switches or self.cmdstring == 'ask' or speech.endswith('?'): - verb = 'ask' - else: - verb = "say" + if self.cmdstring == 'scream': + self.verb = 'scream' + elif self.cmdstring == 'shout': + self.verb = 'shout' + elif self.cmdstring == 'respond': + self.verb = 'respond' + elif self.cmdstring == 'reply': + self.verb = 'reply' + elif self.cmdstring == 'yell': + self.verb = 'yell' + elif self.cmdstring == 'ask': + self.verb = 'ask' for_me, for_others, verb = \ - speech_effect(speech, verb, - speaker, + speech_effect(self.phrase, self.verb, speaker, speaker.attributes.get(category="effect", return_obj=True, return_list=True)) + self.to_puppets(speaker, for_others, self.target) + self.to_you(speaker, verb, for_me) + self.to_others(speaker, verb, for_others) - to_who = to_whom = '' - - if 'to' not in self.switches: - for char in speaker.location.contents: - if hasattr(char, 'other_say') and callable(char.other_say): - char.other_say(speaker, for_others) - else: - # Send the message to 'puppets' that have the special 'other_sayto' - # method (if they are the object of the message): - targets = split(r" *, *", self.lhs) - to_chars = [speaker.search(c, quiet=True) for c in targets] - to_chars = [c[0] for c in to_chars if len(c) > 0] - - if to_chars == []: - speaker.msg(f"No match for {', '.join(targets)}") - return - - for char in to_chars: - if hasattr(char, 'other_sayto') and callable(char.other_sayto): - logger.info(f"Found {char.key}: {for_others}") - char.other_sayto(speaker, for_others) - - who = iter_to_str([c.get_display_name(speaker) - if isinstance(c, Character) else c - for c in to_chars]) - whom = iter_to_str([f"/{c}" for c in targets]) + def to_you(self, speaker, verb, phrase): + """Send 'say' message to the speaker. + The `send_emote` is _global_, so if we want to say to 'Bob', + 'You say ...', we have to both send him a message with the + 'You' as well as everyone else with the 'send_emote'. + """ + to_who = "" + if self.target: + who = self.target.get_display_name(speaker) if verb == "ask": to_who = " " + who - to_whom = " " + whom else: to_who = " to " + who - to_whom = " to " + whom - # The `send_emote` is _global_, so if we want to say to 'Bob', - # 'You say ...', we have to both send him a message with the - # 'You' as well as everyone else with the 'send_emote'. - full_speech = f"You {adverb}{verb}{to_who}, \"{for_me}\"" + adverb = self.adverb + " " if self.adverb else "" + + full_speech = f"You {adverb}{verb}{to_who}, \"{phrase}\"" speaker.msg(full_speech, from_obj=speaker) - # English is weird... - if verb == 'reply': - verb = 'replie' + def to_others(self, speaker, verb, phrase): + """Use the 'send_emote' to have speaker 'say' something to others. + We use /me to be replaced by the user's appearance to others. + We also need to deal with weird English usage. + """ + to_whom = "" + if self.target: + whom = f"/{self.target.key}" + if verb == "ask": + to_whom = " " + whom + else: + to_whom = " to " + whom + + adverb = self.adverb + " " if self.adverb else "" + # English is weird... + verb = 'replie' if verb == 'reply' else verb targets = [item for item in speaker.location.contents if item != speaker] - full_speech = f"/me {adverb}{verb}s{to_whom}, \"{for_others}\"" + + full_speech = f"/me {adverb}{verb}s{to_whom}, \"{phrase}\"" send_emote(speaker, targets, full_speech, msg_type="say", anonymous_add=None) + def to_puppets(self, speaker, phrase, target=None): + """Send phrase to puppet, target. + + If target is None, then send to all puppets. + """ + # Speak to everyone in the room: + if not target: + for char in speaker.location.contents: + if hasattr(char, 'other_say') and callable(char.other_say): + char.other_say(speaker, phrase) + else: + if hasattr(target, 'other_sayto') and callable(target.other_sayto): + logger.info(f"Found {target.key}: {phrase}") + target.other_sayto(speaker, phrase) + class CmdThink(Command): """Think a thought out loud.