evennia/evennia/commands/default/general.py

496 lines
14 KiB
Python

"""
General Character commands usually availabe to all characters
"""
from django.conf import settings
from evennia.utils import utils, evtable
from evennia.typeclasses.attributes import NickTemplateInvalid
COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
# limit symbol import for API
__all__ = ("CmdHome", "CmdLook", "CmdNick",
"CmdInventory", "CmdGet", "CmdDrop", "CmdGive",
"CmdSay", "CmdPose", "CmdAccess")
class CmdHome(COMMAND_DEFAULT_CLASS):
"""
move to your character's home location
Usage:
home
Teleports you to your home location.
"""
key = "home"
locks = "cmd:perm(home) or perm(Builders)"
arg_regex = r"$"
def func(self):
"Implement the command"
caller = self.caller
home = caller.home
if not home:
caller.msg("You have no home!")
elif home == caller.location:
caller.msg("You are already home!")
else:
caller.msg("There's no place like home ...")
caller.move_to(home)
class CmdLook(COMMAND_DEFAULT_CLASS):
"""
look at location or object
Usage:
look
look <obj>
look *<player>
Observes your location or objects in your vicinity.
"""
key = "look"
aliases = ["l", "ls"]
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"""
Handle the looking.
"""
if not self.args:
target = self.caller.location
if not target:
self.caller.msg("You have no location to look at!")
return
else:
target = self.caller.search(self.args)
if not target:
return
self.msg(self.caller.at_look(target))
class CmdNick(COMMAND_DEFAULT_CLASS):
"""
define a personal alias/nick
Usage:
nick[/switches] <string> [= [replacement_string]]
nick[/switches] <template> = <replacement_template>
nick/delete <string> or number
nick/test <test string>
Switches:
inputline - replace on the inputline (default)
object - replace on object-lookup
player - replace on player-lookup
delete - remove nick by number of by index given by /list
clearall - clear all nicks
list - show all defined aliases (also "nicks" works)
test - test input to see what it matches with
Examples:
nick hi = say Hello, I'm Sarah!
nick/object tom = the tall man
nick build $1 $2 = @create/drop $1;$2 - (template)
nick tell $1 $2=@page $1=$2 - (template)
A 'nick' is a personal string replacement. Use $1, $2, ... to catch arguments.
Put the last $-marker without an ending space to catch all remaining text. You
can also use unix-glob matching:
* - matches everything
? - matches a single character
[seq] - matches all chars in sequence
[!seq] - matches everything not in sequence
Note that no objects are actually renamed or changed by this command - your nicks
are only available to you. If you want to permanently add keywords to an object
for everyone to use, you need build privileges and the @alias command.
"""
key = "nick"
aliases = ["nickname", "nicks", "@nick", "@nicks", "alias"]
locks = "cmd:all()"
def func(self):
"Create the nickname"
caller = self.caller
switches = self.switches
nicktypes = [switch for switch in switches if switch in ("object", "player", "inputline")] or ["inputline"]
nicklist = utils.make_iter(caller.nicks.get(return_obj=True) or [])
if 'list' in switches or self.cmdstring in ("nicks", "@nicks"):
if not nicklist:
string = "{wNo nicks defined.{n"
else:
table = evtable.EvTable("#", "Type", "Nick match", "Replacement")
for inum, nickobj in enumerate(nicklist):
_, _, nickvalue, replacement = nickobj.value
table.add_row(str(inum + 1), nickobj.db_category, nickvalue, replacement)
string = "{wDefined Nicks:{n\n%s" % table
caller.msg(string)
return
if 'clearall' in switches:
caller.nicks.clear()
caller.msg("Cleared all nicks.")
return
if not self.args or not self.lhs:
caller.msg("Usage: nick[/switches] nickname = [realname]")
return
nickstring = self.lhs
replstring = self.rhs
old_nickstring = None
old_replstring = None
if replstring == nickstring:
caller.msg("No point in setting nick same as the string to replace...")
return
# check so we have a suitable nick type
errstring = ""
string = ""
for nicktype in nicktypes:
oldnick = caller.nicks.get(key=nickstring, category=nicktype, return_obj=True)
if oldnick:
_, _, old_nickstring, old_replstring = oldnick.value
else:
# no old nick, see if a number was given
if self.args.isdigit():
# we are given a index in nicklist
delindex = int(self.args)
if 0 < delindex <= len(nicklist):
oldnick = nicklist[delindex-1]
_, _, old_nickstring, old_replstring = oldnick.value
else:
errstring += "Not a valid nick index."
else:
errstring += "Nick not found."
if "delete" in switches or "del" in switches:
# clear the nick
errstring = ""
string += "\nNick removed: '|w%s|n' -> |w%s|n." % (old_nickstring, old_replstring)
caller.nicks.remove(nickstring, category=nicktype)
elif replstring:
# creating new nick
errstring = ""
if oldnick:
string += "\nNick '{w%s{n' updated to map to '{w%s{n'." % (old_nickstring, replstring)
else:
string += "\nNick '{w%s{n' mapped to '{w%s{n'." % (nickstring, replstring)
try:
caller.nicks.add(nickstring, replstring, category=nicktype)
except NickTemplateInvalid:
caller.msg("You must use the same $-markers both in the nick and in the replacement.")
return
elif old_nickstring and old_replstring:
# just looking at the nick
string += "\nNick '{w%s{n' maps to '{w%s{n'." % (old_nickstring, old_replstring)
errstring = ""
string = errstring if errstring else string
caller.msg(string)
class CmdInventory(COMMAND_DEFAULT_CLASS):
"""
view inventory
Usage:
inventory
inv
Shows your inventory.
"""
key = "inventory"
aliases = ["inv", "i"]
locks = "cmd:all()"
arg_regex = r"$"
def func(self):
"check inventory"
items = self.caller.contents
if not items:
string = "You are not carrying anything."
else:
table = evtable.EvTable(border="header")
for item in items:
table.add_row("{C%s{n" % item.name, item.db.desc or "")
string = "{wYou are carrying:\n%s" % table
self.caller.msg(string)
class CmdGet(COMMAND_DEFAULT_CLASS):
"""
pick up something
Usage:
get <obj>
Picks up an object from your location and puts it in
your inventory.
"""
key = "get"
aliases = "grab"
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"implements the command."
caller = self.caller
if not self.args:
caller.msg("Get what?")
return
obj = caller.search(self.args, location=caller.location)
if not obj:
return
if caller == obj:
caller.msg("You can't get yourself.")
return
if not obj.access(caller, 'get'):
if obj.db.get_err_msg:
caller.msg(obj.db.get_err_msg)
else:
caller.msg("You can't get that.")
return
obj.move_to(caller, quiet=True)
caller.msg("You pick up %s." % obj.name)
caller.location.msg_contents("%s picks up %s." %
(caller.name,
obj.name),
exclude=caller)
# calling hook method
obj.at_get(caller)
class CmdDrop(COMMAND_DEFAULT_CLASS):
"""
drop something
Usage:
drop <obj>
Lets you drop an object from your inventory into the
location you are currently in.
"""
key = "drop"
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"Implement command"
caller = self.caller
if not self.args:
caller.msg("Drop what?")
return
# Because the DROP command by definition looks for items
# in inventory, call the search function using location = caller
obj = caller.search(self.args, location=caller,
nofound_string="You aren't carrying %s." % self.args,
multimatch_string="You carry more than one %s:" % self.args)
if not obj:
return
obj.move_to(caller.location, quiet=True)
caller.msg("You drop %s." % (obj.name,))
caller.location.msg_contents("%s drops %s." %
(caller.name, obj.name),
exclude=caller)
# Call the object script's at_drop() method.
obj.at_drop(caller)
class CmdGive(COMMAND_DEFAULT_CLASS):
"""
give away something to someone
Usage:
give <inventory obj> = <target>
Gives an items from your inventory to another character,
placing it in their inventory.
"""
key = "give"
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"Implement give"
caller = self.caller
if not self.args or not self.rhs:
caller.msg("Usage: give <inventory object> = <target>")
return
to_give = caller.search(self.lhs, location=caller,
nofound_string="You aren't carrying %s." % self.lhs,
multimatch_string="You carry more than one %s:" % self.lhs)
target = caller.search(self.rhs)
if not (to_give and target):
return
if target == caller:
caller.msg("You keep %s to yourself." % to_give.key)
return
if not to_give.location == caller:
caller.msg("You are not holding %s." % to_give.key)
return
# give object
caller.msg("You give %s to %s." % (to_give.key, target.key))
to_give.move_to(target, quiet=True)
target.msg("%s gives you %s." % (caller.key, to_give.key))
class CmdDesc(COMMAND_DEFAULT_CLASS):
"""
describe yourself
Usage:
desc <description>
Add a description to yourself. This
will be visible to people when they
look at you.
"""
key = "desc"
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"add the description"
if not self.args:
self.caller.msg("You must add a description.")
return
self.caller.db.desc = self.args.strip()
self.caller.msg("You set your description.")
class CmdSay(COMMAND_DEFAULT_CLASS):
"""
speak as your character
Usage:
say <message>
Talk to those in your current location.
"""
key = "say"
aliases = ['"', "'"]
locks = "cmd:all()"
def func(self):
"Run the say command"
caller = self.caller
if not self.args:
caller.msg("Say what?")
return
speech = self.args
# calling the speech hook on the location
speech = caller.location.at_say(caller, speech)
# Feedback for the object doing the talking.
caller.msg('You say, "%s{n"' % speech)
# Build the string to emit to neighbors.
emit_string = '%s says, "%s{n"' % (caller.name,
speech)
caller.location.msg_contents(emit_string,
exclude=caller)
class CmdPose(COMMAND_DEFAULT_CLASS):
"""
strike a pose
Usage:
pose <pose text>
pose's <pose text>
Example:
pose is standing by the wall, smiling.
-> others will see:
Tom is standing by the wall, smiling.
Describe an action being taken. The pose text will
automatically begin with your name.
"""
key = "pose"
aliases = [":", "emote"]
locks = "cmd:all()"
def parse(self):
"""
Custom parse the cases where the emote
starts with some special letter, such
as 's, at which we don't want to separate
the caller's name and the emote with a
space.
"""
args = self.args
if args and not args[0] in ["'", ",", ":"]:
args = " %s" % args.strip()
self.args = args
def func(self):
"Hook function"
if not self.args:
msg = "What do you want to do?"
self.caller.msg(msg)
else:
msg = "%s%s" % (self.caller.name, self.args)
self.caller.location.msg_contents(msg)
class CmdAccess(COMMAND_DEFAULT_CLASS):
"""
show your current game access
Usage:
access
This command shows you the permission hierarchy and
which permission groups you are a member of.
"""
key = "access"
aliases = ["groups", "hierarchy"]
locks = "cmd:all()"
arg_regex = r"$"
def func(self):
"Load the permission groups"
caller = self.caller
hierarchy_full = settings.PERMISSION_HIERARCHY
string = "\n{wPermission Hierarchy{n (climbing):\n %s" % ", ".join(hierarchy_full)
#hierarchy = [p.lower() for p in hierarchy_full]
if self.caller.player.is_superuser:
cperms = "<Superuser>"
pperms = "<Superuser>"
else:
cperms = ", ".join(caller.permissions.all())
pperms = ", ".join(caller.player.permissions.all())
string += "\n{wYour access{n:"
string += "\nCharacter {c%s{n: %s" % (caller.key, cperms)
if hasattr(caller, 'player'):
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
caller.msg(string)