Added the capability of evennia commands to consist of more than one word. So the examples.red_button parent can now be pressed with the command 'push button' instead of 'pushbutton' as before. The variable COMMAND_MAXLEN in the config defines how many words your commands may maximum contain (don't set it higher than needed for efficiency reasons).
The main drawback of multi-word commands are that they can not have any switches; they are intended for in-game use (in states and on objects). Use normal one-word commands for administration and more complex commands with many options. /Griatch
This commit is contained in:
parent
0c29d359f6
commit
a711e07b80
4 changed files with 115 additions and 53 deletions
|
|
@ -104,6 +104,6 @@ def class_factory(source_obj):
|
||||||
"""
|
"""
|
||||||
button = RedButton(source_obj)
|
button = RedButton(source_obj)
|
||||||
# add the object-based commands to the button
|
# add the object-based commands to the button
|
||||||
button.command_table.add_command("pushbutton", cmd_push_button)
|
button.command_table.add_command("push button", cmd_push_button)
|
||||||
button.command_table.add_command("pullbutton", cmd_pull_button)
|
button.command_table.add_command("pull button", cmd_pull_button)
|
||||||
return button
|
return button
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ This is the command processing module. It is instanced once in the main
|
||||||
server module and the handle() function is hit every time a player sends
|
server module and the handle() function is hit every time a player sends
|
||||||
something.
|
something.
|
||||||
"""
|
"""
|
||||||
import time
|
#import time
|
||||||
from traceback import format_exc
|
from traceback import format_exc
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
import defines_global
|
import defines_global
|
||||||
import cmdtable
|
import cmdtable
|
||||||
|
|
@ -13,6 +14,8 @@ import logger
|
||||||
import comsys
|
import comsys
|
||||||
import alias_mgr
|
import alias_mgr
|
||||||
|
|
||||||
|
COMMAND_MAXLEN = settings.COMMAND_MAXLEN
|
||||||
|
|
||||||
class UnknownCommand(Exception):
|
class UnknownCommand(Exception):
|
||||||
"""
|
"""
|
||||||
Throw this when a user enters an an invalid command.
|
Throw this when a user enters an an invalid command.
|
||||||
|
|
@ -47,6 +50,8 @@ class Command(object):
|
||||||
command_switches = []
|
command_switches = []
|
||||||
# The un-parsed argument provided. IE: if input is "look dog", this is "dog".
|
# The un-parsed argument provided. IE: if input is "look dog", this is "dog".
|
||||||
command_argument = None
|
command_argument = None
|
||||||
|
# list of tuples for possible multi-space commands and their arguments
|
||||||
|
command_alternatives = None
|
||||||
# A reference to the command function looked up in a command table.
|
# A reference to the command function looked up in a command table.
|
||||||
command_function = None
|
command_function = None
|
||||||
# An optional dictionary that is passed through the command table as extra_vars.
|
# An optional dictionary that is passed through the command table as extra_vars.
|
||||||
|
|
@ -66,45 +71,63 @@ class Command(object):
|
||||||
Breaks the command up into the main command string, a list of switches,
|
Breaks the command up into the main command string, a list of switches,
|
||||||
and a string containing the argument provided with the command. More
|
and a string containing the argument provided with the command. More
|
||||||
specific processing is left up to the individual command functions.
|
specific processing is left up to the individual command functions.
|
||||||
"""
|
|
||||||
try:
|
|
||||||
"""
|
|
||||||
Break the command in half into command and argument. If the
|
|
||||||
command string can't be parsed, it has no argument and is
|
|
||||||
handled by the except ValueError block below.
|
|
||||||
"""
|
|
||||||
# Lop off the return at the end.
|
|
||||||
self.raw_input = self.raw_input.strip('\r')
|
|
||||||
# Break the command up into the root command and its arguments.
|
|
||||||
(self.command_string, self.command_argument) = self.raw_input.split(' ', 1)
|
|
||||||
# Yank off trailing and leading spaces.
|
|
||||||
self.command_argument = self.command_argument.strip()
|
|
||||||
self.command_string = self.command_string.strip()
|
|
||||||
"""
|
|
||||||
This is a really important behavior to note. If the user enters
|
|
||||||
anything other than a string with some character in it, the value
|
|
||||||
of the argument is None, not an empty string.
|
|
||||||
"""
|
|
||||||
if self.command_string == '':
|
|
||||||
self.command_string = None
|
|
||||||
if self.command_argument == '':
|
|
||||||
self.command_argument = None
|
|
||||||
|
|
||||||
if self.command_string == None:
|
|
||||||
"""
|
|
||||||
This prevents any bad stuff from happening as a result of
|
|
||||||
trying to further parse a None object.
|
|
||||||
"""
|
|
||||||
return
|
|
||||||
except ValueError:
|
|
||||||
"""
|
|
||||||
No arguments. IE: look, who.
|
|
||||||
"""
|
|
||||||
self.command_string = self.raw_input
|
|
||||||
|
|
||||||
# Parse command_string for switches, regardless of what happens.
|
The command can come in two forms:
|
||||||
self.parse_command_switches()
|
command/switches arg
|
||||||
|
command_with_spaces arg
|
||||||
|
|
||||||
|
The first form is the normal one, used for administration and other commands
|
||||||
|
that benefit from the use of switches and options. The drawback is that it
|
||||||
|
can only consist of one single word (no spaces).
|
||||||
|
The second form, which does not accept switches, allows for longer command
|
||||||
|
names (e.g. 'press button' instead of pressbutton) and is mainly useful for
|
||||||
|
object-based commands for roleplay, puzzles etc.
|
||||||
|
"""
|
||||||
|
if not self.raw_input:
|
||||||
|
return
|
||||||
|
|
||||||
|
# add a space after the raw input; this cause split() to always
|
||||||
|
# create a list with at least two entries.
|
||||||
|
raw = "%s " % self.raw_input
|
||||||
|
cmd_words = raw.split()
|
||||||
|
try:
|
||||||
|
if '/' in cmd_words[0]:
|
||||||
|
# if we have switches we directly go for the first command form.
|
||||||
|
command_string, command_argument = \
|
||||||
|
(inp.strip() for inp in raw.split(' ', 1))
|
||||||
|
if command_argument:
|
||||||
|
self.command_argument = command_argument
|
||||||
|
if command_string:
|
||||||
|
# we have a valid command, store and parse switches.
|
||||||
|
self.command_string = command_string
|
||||||
|
self.parse_command_switches()
|
||||||
|
else:
|
||||||
|
# no switches - we need to save a list of all possible command
|
||||||
|
# names up to the max-length allowed.
|
||||||
|
command_maxlen = min(COMMAND_MAXLEN, len(cmd_words))
|
||||||
|
command_alternatives = []
|
||||||
|
for spacecount in reversed(range(command_maxlen)):
|
||||||
|
# store all space-separated possible command names
|
||||||
|
# as tuples (commandname, args). They are stored with
|
||||||
|
# the longest possible name first.
|
||||||
|
try:
|
||||||
|
command_alternatives.append( (" ".join(cmd_words[:spacecount+1]),
|
||||||
|
" ".join(cmd_words[spacecount+1:])) )
|
||||||
|
except IndexError:
|
||||||
|
continue
|
||||||
|
if command_alternatives:
|
||||||
|
# store alternatives. Store the one-word command
|
||||||
|
# as the default command name.
|
||||||
|
one_word_command = command_alternatives.pop()
|
||||||
|
self.command_string = one_word_command[0]
|
||||||
|
self.command_argument = one_word_command[1]
|
||||||
|
self.command_alternatives = command_alternatives
|
||||||
|
except IndexError:
|
||||||
|
# this SHOULD only happen if raw_input is malformed
|
||||||
|
# (like containing only control characters).
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, source_object, raw_input, session=None):
|
def __init__(self, source_object, raw_input, session=None):
|
||||||
"""
|
"""
|
||||||
Instantiates the Command object and does some preliminary parsing.
|
Instantiates the Command object and does some preliminary parsing.
|
||||||
|
|
@ -179,6 +202,16 @@ def match_alias(command):
|
||||||
command.command_string = alias_mgr.CMD_ALIAS_LIST.get(
|
command.command_string = alias_mgr.CMD_ALIAS_LIST.get(
|
||||||
command.command_string,
|
command.command_string,
|
||||||
command.command_string)
|
command.command_string)
|
||||||
|
# Run aliasing on alternative command names (for commands with
|
||||||
|
# spaces in them)
|
||||||
|
if command.command_alternatives:
|
||||||
|
command_alternatives = []
|
||||||
|
for command_alternative in command.command_alternatives:
|
||||||
|
command_alternatives.append( (alias_mgr.CMD_ALIAS_LIST.get(
|
||||||
|
command_alternative[0],
|
||||||
|
command_alternative[0]),
|
||||||
|
command_alternative[1]) )
|
||||||
|
command.command_alternatives = command_alternatives
|
||||||
|
|
||||||
def get_aliased_message():
|
def get_aliased_message():
|
||||||
"""
|
"""
|
||||||
|
|
@ -201,7 +234,6 @@ def match_alias(command):
|
||||||
elif first_char == ':':
|
elif first_char == ':':
|
||||||
command.command_argument = get_aliased_message()
|
command.command_argument = get_aliased_message()
|
||||||
command.command_string = "pose"
|
command.command_string = "pose"
|
||||||
# command.command_string = "emote"
|
|
||||||
# Pose without space alias.
|
# Pose without space alias.
|
||||||
elif first_char == ';':
|
elif first_char == ';':
|
||||||
command.command_argument = get_aliased_message()
|
command.command_argument = get_aliased_message()
|
||||||
|
|
@ -298,13 +330,35 @@ def command_table_lookup(command, command_table, eval_perms=True,
|
||||||
evaluates the permissions tuple.
|
evaluates the permissions tuple.
|
||||||
The test flag only checks without manipulating the command
|
The test flag only checks without manipulating the command
|
||||||
neighbor (object) If this is supplied, we are looking at a object table and
|
neighbor (object) If this is supplied, we are looking at a object table and
|
||||||
must check for locks.
|
must check for locks.
|
||||||
|
|
||||||
|
In the case of one-word commands with switches, this is a
|
||||||
|
quick look-up. For non-switch commands the command might
|
||||||
|
however consist of several words separated by spaces up to
|
||||||
|
a certain max number of words. We don't know beforehand if one
|
||||||
|
of these match an entry in this particular command table. We search
|
||||||
|
them in order longest to shortest before deferring to the normal,
|
||||||
|
one-word assumption.
|
||||||
"""
|
"""
|
||||||
# Get the command's function reference (Or False)
|
cmdtuple = None
|
||||||
cmdtuple = command_table.get_command_tuple(command.command_string)
|
if command.command_alternatives:
|
||||||
|
# we have command alternatives (due to spaces in command definition)
|
||||||
|
for cmd_alternative in command.command_alternatives:
|
||||||
|
# the alternatives are ordered longest -> shortest.
|
||||||
|
cmdtuple = command_table.get_command_tuple(cmd_alternative[0])
|
||||||
|
if cmdtuple:
|
||||||
|
# we have a match, so this is the 'right' command to use
|
||||||
|
# with this particular command table.
|
||||||
|
command.command_string = cmd_alternative[0]
|
||||||
|
command.command_argument = cmd_alternative[1]
|
||||||
|
if not cmdtuple:
|
||||||
|
# None of the alternatives match, go with the default one-word name
|
||||||
|
cmdtuple = command_table.get_command_tuple(command.command_string)
|
||||||
|
|
||||||
if cmdtuple:
|
if cmdtuple:
|
||||||
# Check if this is just a test.
|
# if we get here we have found a command match in the table
|
||||||
if test:
|
if test:
|
||||||
|
# Check if this is just a test.
|
||||||
return True
|
return True
|
||||||
# Check locks
|
# Check locks
|
||||||
if neighbor and not neighbor.scriptlink.use_lock(command.source_object):
|
if neighbor and not neighbor.scriptlink.use_lock(command.source_object):
|
||||||
|
|
|
||||||
|
|
@ -696,10 +696,10 @@ def cmd_setcmdalias(command):
|
||||||
@setcmdalias - define shortcuts for commands
|
@setcmdalias - define shortcuts for commands
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@setcmdalias[/switch] [command = ] alias
|
@setcmdalias[/switch] alias [= command]
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
list - view all command aliases (default)
|
list - view all command aliases
|
||||||
add - add alias
|
add - add alias
|
||||||
del - remove and existing alias
|
del - remove and existing alias
|
||||||
|
|
||||||
|
|
@ -713,22 +713,26 @@ def cmd_setcmdalias(command):
|
||||||
args = command.command_argument
|
args = command.command_argument
|
||||||
switches = command.command_switches
|
switches = command.command_switches
|
||||||
|
|
||||||
if not args or 'list' in switches:
|
if "list" in switches:
|
||||||
# show all aliases
|
# show all aliases
|
||||||
string = "Command aliases defined:"
|
string = "Command aliases defined:"
|
||||||
aliases = CommandAlias.objects.all()
|
aliases = CommandAlias.objects.all()
|
||||||
if not aliases:
|
if not aliases:
|
||||||
string = "No command aliases defined."
|
string = "No command aliases defined."
|
||||||
for alias in aliases:
|
for alias in aliases:
|
||||||
string += "\n %s = %s" % (alias.equiv_command, alias.user_input)
|
string += "\n %s -> %s" % (alias.user_input, alias.equiv_command)
|
||||||
source_object.emit_to(string)
|
source_object.emit_to(string)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not args:
|
||||||
|
source_object.emit_to("Usage: @setcmdalias[/list/add/del] alias [= command]")
|
||||||
|
return
|
||||||
|
|
||||||
equiv_command = ""
|
equiv_command = ""
|
||||||
user_input = ""
|
user_input = ""
|
||||||
# analyze args
|
# analyze args
|
||||||
if '=' in args:
|
if '=' in args:
|
||||||
equiv_command, user_input = [arg.strip() for arg in args.split("=",1)]
|
user_input, equiv_command = [arg.strip() for arg in args.split("=",1)]
|
||||||
else:
|
else:
|
||||||
user_input = args.strip()
|
user_input = args.strip()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,14 @@ DATABASE_HOST = ''
|
||||||
# Empty string defaults to localhost. Not used with sqlite3.
|
# Empty string defaults to localhost. Not used with sqlite3.
|
||||||
DATABASE_PORT = ''
|
DATABASE_PORT = ''
|
||||||
|
|
||||||
|
# How many words a single command name may have (e.g. 'push button' instead of 'pushbutton')
|
||||||
|
# (commands with switches always accept only one word in the name, e.g. @sethelp/add)
|
||||||
|
COMMAND_MAXLEN = 3
|
||||||
|
|
||||||
## Command aliases
|
## Command aliases
|
||||||
# These are convenient aliases set up when the game is started
|
# These are convenient aliases set up when the game is started
|
||||||
# for the very first time. You can add/delete aliases in-game using
|
# for the very first time. You can add/delete aliases in-game using
|
||||||
# the @cmdalias command.
|
# the @setcmdalias command.
|
||||||
COMMAND_ALIASES = {"@desc":"@describe",
|
COMMAND_ALIASES = {"@desc":"@describe",
|
||||||
"@dest":"@destroy", "@nuke":"@destroy",
|
"@dest":"@destroy", "@nuke":"@destroy",
|
||||||
"@tel":"@teleport",
|
"@tel":"@teleport",
|
||||||
|
|
@ -78,7 +82,7 @@ COMMAND_ALIASES = {"@desc":"@describe",
|
||||||
"ex":"examine",
|
"ex":"examine",
|
||||||
"sa":"say",
|
"sa":"say",
|
||||||
"emote":"pose",
|
"emote":"pose",
|
||||||
"p":"page" }
|
"p":"page"}
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
## The variables in this section are used by each evennia subsystem to tell which permissions to define.
|
## The variables in this section are used by each evennia subsystem to tell which permissions to define.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue