#!/usr/bin/env python from random import random from re import match, split, sub, MULTILINE from evennia.contrib.rpg.rpsystem import send_emote from evennia.utils.verb_conjugation.pronouns import PRONOUN_MAPPING from commands.command import Command from utils.word_list import routput, paragraph, choices ADVERBS = [ "aloud", "abruptly", "actually", "angrily", "animatedly", "bitterly", "boldly", "cheerfully", "clearly", "confidently", "continuously", "cruelly", "defiantly", "desperately", "earnestly", "elaborately", "emphatically", "excitedly", "frantically", "frequently", "gently", "gravely", "hesitantly", "impatiently", "insistently", "intelligently", "jokingly", "joyfully", "loudly", "mockingly", "nonchalantly", "passionately", "playfully", "quietly", "reassuringly", "reluctantly", "seriously", "sharply", "sharply", "simply", "silently", "sincerely", "softly", "suddenly", "surprisingly", "thoughtfully", "unexpectedly", "voraciously", "whimsically", "wistfully", ] def get_adverb(phrase): """Return tuple of initial adverb (or None) and the phrase.""" m = match(r"(\w+)[, ]+(.*)", phrase) if m: first_word = m.group(1) rest_words = m.group(2) if first_word in ADVERBS: return first_word, rest_words return None, phrase def get_say_direction(phrase): """Return tuple of object of communication and the rest of the phrase.""" m = match(r"to (\w+)[, ]+(.*)", phrase) if m: first_word = m.group(1) rest_words = m.group(2) if first_word.endswith("self"): return "self", rest_words else: return first_word, rest_words return None, phrase def speech_effect(speech, verb, target, effects): """ Return speech after applying 'effects'. Return a tuple for what a user thinks he said, and what others actually here. If no effect, just return speech twice. Effects: - mute ... can't talk - donkied ... target and others hear the value of effect - sloshed ... slurred speech To administer: @set woman/donkied:effect = "Heehaw! ;; Heehaw, heehaw!" """ for effect in effects: if effect: if effect.db_key == 'donkied': msg = choices(effect.value) return (msg, msg, "bray") return (speech, speech, verb) class CmdSay(Command): """Say something to the characters in the same area. Usage: |gsay [[] [to ],] |n This command has a couple optional strings. as 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: |gsay Good evening.|n |wYou say, "Good evening."|n Or: |gsay loudly, Good evening!|n |wYou loudly exclaim, "Good evening!"|n In the second example, you gave an |wadverb|n that ends in |w-ly|n. Also, the exclamation point changes the 'say' to an 'exclaim'. A question mark changes 'say' to 'ask'. If you start your message with an adverb, but want that adverb |win|n the message and not |waffecting|n the message, surround it with quotes. For instance: |gsay actually, it is pronounced gah-nome. |wYou say actually, "it is pronounced gah-nome." |gsay "actually, it is pronounced gah-nome." |wYou say, "actually, it is pronounced gah-nome."|n Of course, adverbs that affect the message are lowercase, and messages usually begin with an uppercase, as in: |gsay Actually, it is pronounced Gah-nome. |wYou say, "Actually, it is pronounced Gah-nome."|n Because this command is so common, you can also use ", as in: |g"What's going on?|n You can also direct your message to a particular person (or thing), as in: |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. Since you might be having a conversation with a character, you can use the |gsayto|n to target the same person. For instance: |gsay to pet Who's a widdle cutie? |wYou ask wee beastie, "Who's a widdle cutie?" |gsayto You are! |wYou exclaim to wee beastie, "You are!"|n You can replace the 'say' command with any of the following: - shout - scream - respond - reply - yell - ask """ key = "say" verb = "say" aliases = ["says", "speak", "shout", "yell", "exclaim", "scream", "ask", "reply", "respond", '"', "'", "sayto"] locks = "cmd:all()" # 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" m = match(r'.*".+".*', self.phrase) if not m: # No overriding quotes? Process adverbs... self.adverb, self.phrase = get_adverb(self.phrase) target, self.phrase = get_say_direction(self.phrase) if target: if target == "self": self.target = self.caller else: self.target = self.caller.search(target) self.caller.db.say_target = self.target # Final quotes can be trimmed: self.phrase = self.phrase.strip('"').strip("'") def func(self): """Implement the new 'say' command with switches.""" speaker = self.caller if not self.phrase or self.phrase == "": speaker.msg("Say what?") return # If speech is empty, stop here if not speaker.at_pre_say(self.phrase): return if self.cmdstring == 'sayto': self.target = self.caller.db.say_target 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(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) 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: if self.target == self.caller: who = "yourself" else: who = self.target.get_display_name(speaker) if verb == "ask": to_who = " " + who else: to_who = " to " + who verb = " " + verb adverb = " " + self.adverb if self.adverb else "" if adverb.endswith("ly") and random() < 0.5: full_speech = f"You{adverb}{verb}{to_who}, \"{phrase}\"" else: full_speech = f"You{verb}{adverb}{to_who}, \"{phrase}\"" speaker.msg(full_speech, from_obj=speaker) 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: if self.target == self.caller: whom = PRONOUN_MAPPING['3rd person']['reflexive pronoun'][self.caller.db.gender] else: who = self.target.get_display_name(speaker) whom = f"/{self.target.key}" if verb == "ask": to_whom = " " + whom else: to_whom = " to " + whom # English is weird... verb = ' replie' if verb == 'reply' else " " + verb adverb = " " + self.adverb if self.adverb else "" targets = [item for item in speaker.location.contents if item != speaker] if adverb.endswith("ly") and random() < 0.5: full_speech = f"/me{adverb}{verb}s{to_whom}, \"{phrase}\"" else: full_speech = f"/me{verb}s{adverb}{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)