Also, if you say without ending in punctuation, the "say" command output is reversed. Just to keep everyone on their toes.
314 lines
11 KiB
Python
Executable file
314 lines
11 KiB
Python
Executable file
#!/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 import logger, delay
|
|
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 [[<adverb>] [to <character>],] <message>|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()
|
|
self.reverse = False
|
|
|
|
m = match(r".+\?.*", self.phrase)
|
|
if m:
|
|
self.verb = "ask"
|
|
m = match(r".+!.*", self.phrase)
|
|
if m:
|
|
self.verb = "exclaim"
|
|
m = match(r'.+\w$', self.phrase)
|
|
if m:
|
|
self.reverse = True
|
|
|
|
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 self.reverse:
|
|
if adverb.endswith("ly") and random() < 0.5:
|
|
full_speech = f"\"{phrase},\" you{adverb}{verb}{to_who}."
|
|
else:
|
|
full_speech = f"\"{phrase},\" you{verb}{adverb}{to_who}."
|
|
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)
|
|
if self.target.sdesc:
|
|
whom = f"the /{self.target.sdesc.get()}"
|
|
else:
|
|
whom = f"the /{self.target.name}"
|
|
|
|
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 self.reverse:
|
|
if adverb.endswith("ly") and random() < 0.5:
|
|
full_speech = f"\"{phrase},\" /me{adverb}{verb}s{to_whom}."
|
|
else:
|
|
full_speech = f"\"{phrase},\" /me{verb}s{adverb}{to_whom}."
|
|
else:
|
|
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}\""
|
|
logger.info(f"Full speech: {full_speech}")
|
|
# Full speech: /me asks /Trampoli, "How are you?"
|
|
|
|
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):
|
|
logger.info(f"to_puppets: all: {char}")
|
|
delay(1, char.other_say, speaker, phrase)
|
|
else:
|
|
if hasattr(target, 'other_sayto') and callable(target.other_sayto):
|
|
logger.info(f"Found {target.key}: {phrase}")
|
|
delay(1, target.other_sayto, speaker, phrase)
|