298 lines
9.1 KiB
Python
Executable file
298 lines
9.1 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
from random import random
|
|
from re import split
|
|
|
|
from commands.command import Command
|
|
from evennia.commands.default.general import NumberedTargetCommand
|
|
from evennia.commands.default.muxcommand import MuxCommand
|
|
from evennia.contrib.rpg.rpsystem import send_emote
|
|
from evennia.utils import iter_to_str, logger
|
|
|
|
from typeclasses.readables import find_book
|
|
from utils.word_list import routput, paragraph, choices
|
|
|
|
def speech_effect(speech, verb, target, effects):
|
|
"""
|
|
Returns 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 CmdWhisper(MuxCommand):
|
|
"""
|
|
Speak privately as your character to another
|
|
|
|
Usage:
|
|
whisper <character> = <message>
|
|
whisper <char1>, <char2> = <message>
|
|
|
|
Talk privately to one or more characters in your current location, without
|
|
others in the room being informed.
|
|
"""
|
|
key = "whisper"
|
|
priority = 0
|
|
locks = "cmd:all()"
|
|
rhs_split = ("=")
|
|
|
|
def func(self):
|
|
"""
|
|
Implements the new 'whisper' command.
|
|
"""
|
|
if not self.args:
|
|
self.caller.msg("What are you whispering?")
|
|
return
|
|
|
|
if not self.rhs:
|
|
self.caller.msg("Usage: whisper <character> = <message>")
|
|
return
|
|
|
|
targets = [self.caller.search(target) for target in split(r" *, *", self.lhs)]
|
|
full_speech = f"/Me whispers to you, \"{self.rhs}\""
|
|
send_emote(self.caller, targets, full_speech, msg_type="say", anonymous_add=None, quiet=True)
|
|
|
|
to_list = [target.get_display_name(self) for target in targets]
|
|
full_speech = f"You whisper to {iter_to_str(to_list, endsep='and')}, \"{self.rhs}\""
|
|
self.caller.msg(full_speech, from_obj=self.caller)
|
|
|
|
|
|
class CmdSay(MuxCommand):
|
|
"""
|
|
Say something to the characters in the same area. For instance:
|
|
|
|
|gsay Good evening!|n
|
|
|
|
However, you can use an alias and simply type:
|
|
|
|
|g"Good evening!
|
|
|
|
Or:
|
|
|
|
|g'Good evening!
|
|
|
|
Creatures and objects in this game can sometimes respond to what you say.
|
|
|
|
Usage:
|
|
say phrase
|
|
say/to char1, [char2 ...] = phrase
|
|
say[/switches] phrase
|
|
|
|
Where switches can be any of the following:
|
|
|
|
- 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:
|
|
|
|
say/quietly Hi there.
|
|
|
|
Shows as:
|
|
|
|
You quietly say, "Hi there."
|
|
"""
|
|
|
|
key = "say"
|
|
aliases = ["speak", "shout", "yell", "exclaim", "scream", "ask", "reply", "respond", "\"", "'"]
|
|
priority = 0
|
|
locks = "cmd:all()"
|
|
rhs_split = ("=")
|
|
arg_regex = None
|
|
|
|
def func(self):
|
|
"""
|
|
Implements the new 'say' command with switches.
|
|
"""
|
|
def charname(name):
|
|
try:
|
|
results = self.caller.search(name, quiet=True)
|
|
return results.get_display_name(self)
|
|
except:
|
|
return name
|
|
|
|
def chars_for_self(chars):
|
|
return [charname(c) for c in split(r"[ ,]+", chars)]
|
|
|
|
def chars_for_others(chars):
|
|
return [c if c.startswith('/') else '/'+c for c in split(r"[ ,]+", chars)]
|
|
|
|
def chars_list(chars, verb, for_rp=True):
|
|
char_lst = chars_for_others(chars) if for_rp else chars_for_self(chars)
|
|
return (' to ' if verb == 'say' else ' ') + \
|
|
iter_to_str(char_lst, endsep='and')
|
|
|
|
# logger.info(f"CmdSayIt: {self.cmdstring} lhs={self.lhs} switches={self.switches}")
|
|
|
|
if not self.args:
|
|
self.caller.msg("Say what?")
|
|
return
|
|
|
|
if 'to' in self.switches and not self.rhs:
|
|
self.caller.msg(paragraph("""
|
|
When attempting to say something to one or more
|
|
characters, use the '=' character to identify what you
|
|
want to say.
|
|
"""))
|
|
return
|
|
|
|
if self.rhs:
|
|
speech = self.rhs
|
|
else:
|
|
speech = self.args
|
|
|
|
# If speech is empty, stop here
|
|
if not self.caller.at_pre_say(speech):
|
|
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"
|
|
|
|
for_me, for_others, verb = \
|
|
speech_effect(speech, verb,
|
|
self.caller,
|
|
self.caller.attributes.get(category="effect",
|
|
return_obj=True,
|
|
return_list=True))
|
|
|
|
# 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_whom = chars_list(self.lhs, verb, for_rp=False) if 'to' in self.switches else ''
|
|
full_speech = f"You {adverb}{verb}{to_whom}, \"{for_me}\""
|
|
self.caller.msg(full_speech, from_obj=self.caller)
|
|
|
|
# English is weird...
|
|
if verb == 'reply':
|
|
verb = 'replie'
|
|
|
|
targets = [item for item in self.caller.location.contents if item != self.caller]
|
|
to_whom = chars_list(self.lhs, verb) if 'to' in self.switches else ''
|
|
full_speech = f"/me {adverb}{verb}s{to_whom}, \"{for_others}\""
|
|
send_emote(self.caller, targets, full_speech, msg_type="say", anonymous_add=None)
|
|
|
|
|
|
class CmdThink(Command):
|
|
"""Think a thought out loud.
|
|
|
|
Usage:
|
|
think <message>
|
|
|
|
Similar to the 'say' or 'pose' commands, this communicates an
|
|
inner monologue to other players on the 'public' channel.
|
|
"""
|
|
key = "think"
|
|
aliases = ["thinks", "("]
|
|
arg_regex = None
|
|
|
|
def func(self):
|
|
"""
|
|
Implements the think out loud command.
|
|
"""
|
|
if not self.args:
|
|
self.caller.msg("What do you want to think out loud?")
|
|
else:
|
|
thought = self.args.strip()
|
|
if (self.caller.db.thinking_count or 0) < 3 or random() < 0.4:
|
|
msg = routput(
|
|
f"<< thinks ^ wonders >> << out loud ^ aloud >> ... o O ( {thought} )"
|
|
)
|
|
else:
|
|
msg = f". o O ( {thought} )"
|
|
self.caller.db.thinking_count = (self.caller.db.thinking_count or 0) + 1
|
|
|
|
self.caller.execute_cmd(f"pub :{msg}")
|
|
|
|
|
|
class CmdRead(Command):
|
|
"""
|
|
Return the inside contents of a book or other readable object.
|
|
|
|
Usage:
|
|
|
|
read <target>
|
|
|
|
To add something to read on target, use the @set command:
|
|
|
|
@set <target>/inside = 'This is the text to read.'
|
|
"""
|
|
key = "read"
|
|
|
|
def func(self):
|
|
"""Return the 'inside' attribute."""
|
|
|
|
target_str = self.args.strip()
|
|
if target_str == "":
|
|
self.caller.msg("Usage: |gread <object>|n")
|
|
return
|
|
|
|
book = find_book(self.caller, target_str)
|
|
if book:
|
|
self.caller.msg(book.db.inside)
|
|
|
|
|
|
class CmdTake(Command, NumberedTargetCommand):
|
|
"""
|
|
Take an object from another character or NPC.
|
|
|
|
Usage:
|
|
take <thing> from <character>
|
|
|
|
Note that only some things can be stolen.
|
|
For instance, the brass ring from the door knocker.
|
|
"""
|
|
key = "take"
|
|
aliases = ["steal"]
|
|
rhs_split = ("=", " from ")
|
|
|
|
def func(self):
|
|
"""
|
|
Implements the take command. Since this command is designed
|
|
to work on the object, we operate only on self.obj.
|
|
"""
|
|
if not self.args:
|
|
self.caller.msg("What do you want to take?")
|
|
elif not self.rhs:
|
|
self.caller.msg(f"You want to take {self.lhs}, but from whom?")
|
|
else:
|
|
self.caller.do_take(self.lhs, self.rhs)
|