moss-n-puddles/commands/everyone.py
Howard Abrams f3aef6cc54 Fix bugs with Steve
The 'say' command works with the webclient
Unplugging from the game makes you stand
Trying to sit on someone else's character, now uses the RP system
The fish now gets the right phrasing.
2025-05-13 21:37:37 -07:00

261 lines
8.3 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 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.
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", "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 '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, NumberedTargetCommand):
"""Think a thought out loud.
Usage:
think <message>
Similar to the 'say' or 'pose' commands, this communicates an
inner monologue to other characters in the same area.
"""
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"""{self.caller.name}
<< thinks ^ wonders >> << out loud ^ aloud >>
o O ( {thought} )
"""
)
else:
msg = f"{self.caller.name} . o O ( {thought} )"
self.caller.db.thinking_count = (self.caller.db.thinking_count or 0) + 1
self.caller.location.msg_contents(msg)
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)