Largely rewrote and refactored the help system.
The help entry database structure has changed! You have to resync or purge your database or your will get problems! New features: * Help entry access now fully controlled by evennia permissions * Categories for each help entry * All entries are created dynamically, with a See also: footer calculated after the current state of the database. * Indexes and topic list calculated on the fly (alphabetically/after category) * Added auto-help help entries for all default commands. * Only shows commands _actually implemented_ - MUX help db moved into 'MUX' category which is not shown by default. * More powerful auto-help markup - supports categories and permissions (and inheritance). * Global on/off switch for auto-help, when entering production * Auto_help_override switch for selectively activating auto-help when developing new commands (like the old system). * Refactored State help system; no more risk of overwriting global help entries. * State help now defers to main help db when no match found; makes system more transparent. * State help entries also support categories/permissions (state categories are not used much though). Other updates: * Added more commands to the batch processor * Many bug-fixes. /Griatch
This commit is contained in:
parent
46e2cd3ecb
commit
8074617285
27 changed files with 1995 additions and 1072 deletions
|
|
@ -14,11 +14,10 @@ recognized.
|
|||
Next enter the mud and give the command
|
||||
> entermenu
|
||||
|
||||
Note that the help entries added to the state system with the auto_help flag are NOT
|
||||
part of the normal help database, they are stored with the state and only accessible
|
||||
from inside it (unless you also set the 'global_help' flag in the add_command(), in
|
||||
which case it is also added to the global help system). If you want to describe the
|
||||
state itself in more detail you should add that to the main help index manually.
|
||||
Note that the help entries related to this little menu are not part of the normal
|
||||
help database, they are stored with the state and only accessible
|
||||
from inside it. If you want to describe the state itself in more detail you
|
||||
should add a help entry about it to the main help index manually.
|
||||
|
||||
To further test the state system, try the command
|
||||
> enterstate
|
||||
|
|
@ -58,10 +57,13 @@ def cmd_entermenu(command):
|
|||
#show the menu.
|
||||
s = """
|
||||
Welcome to the Demo menu!
|
||||
In this demo all you can do is select one of the two options so it changes colour.
|
||||
This is just intended to show off the possibility of the state system. More
|
||||
interesting things should of course happen in a real menu. Use @exit to
|
||||
leave the menu."""
|
||||
In this small demo all you can do is select one of
|
||||
the two options so it changes colour.
|
||||
This is just intended to show off the
|
||||
possibilities of the state system. More
|
||||
interesting things should of course happen
|
||||
in a real menu.
|
||||
Use @exit to leave the menu."""
|
||||
source_object.emit_to(s)
|
||||
source_object.execute_cmd('menu')
|
||||
|
||||
|
|
@ -88,7 +90,7 @@ def menu_cmd_menu(command):
|
|||
"""
|
||||
menu
|
||||
Clears the options and redraws the menu.
|
||||
<<TOPIC:autohelp>>
|
||||
[[autohelp]]
|
||||
This is an extra topic to test the auto-help functionality. The state-help
|
||||
system supports nested ('related') topics just like the normal help index does.
|
||||
"""
|
||||
|
|
@ -117,19 +119,15 @@ def print_menu(source_obj,choice=None):
|
|||
#Add the 'entry' command to the normal command table
|
||||
GLOBAL_CMD_TABLE.add_command("entermenu", cmd_entermenu)
|
||||
|
||||
#create the state.
|
||||
#create the state.
|
||||
GLOBAL_STATE_TABLE.add_state(STATENAME,exit_command=True)
|
||||
|
||||
#Add the menu commands to the state table by tying them to the 'menu' state. It is
|
||||
#important that the name of the state matches what we set the player-object to in
|
||||
#the 'entry' command. Since auto_help is on, we will have help entries for all commands
|
||||
#while in the menu.
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME, "option1", menu_cmd_option1,auto_help=True)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME, "option2", menu_cmd_option2,auto_help=True)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME, "menu", menu_cmd_menu,auto_help=True)
|
||||
|
||||
|
||||
|
||||
#the 'entry' command.
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME, "option1", menu_cmd_option1)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME, "option2", menu_cmd_option2)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME, "menu", menu_cmd_menu)
|
||||
|
||||
#-----------------------testing the depth of the state system
|
||||
# This is a test suite that shows off all the features of the state system.
|
||||
|
|
@ -234,7 +232,7 @@ GLOBAL_STATE_TABLE.add_state(TSTATE6,exit_command=True,
|
|||
allow_exits=True,allow_obj_cmds=True)
|
||||
|
||||
#append the "test" function to all states
|
||||
GLOBAL_STATE_TABLE.add_command(TSTATE1,'test',cmd_instate_cmd,auto_help=True)
|
||||
GLOBAL_STATE_TABLE.add_command(TSTATE1,'test',cmd_instate_cmd)
|
||||
GLOBAL_STATE_TABLE.add_command(TSTATE2,'test',cmd_instate_cmd)
|
||||
GLOBAL_STATE_TABLE.add_command(TSTATE3,'test',cmd_instate_cmd)
|
||||
GLOBAL_STATE_TABLE.add_command(TSTATE4,'test',cmd_instate_cmd)
|
||||
|
|
|
|||
|
|
@ -291,7 +291,8 @@ def match_exits(command,test=False):
|
|||
raise ExitCommandHandler
|
||||
|
||||
|
||||
def command_table_lookup(command, command_table, eval_perms=True,test=False,neighbor=None):
|
||||
def command_table_lookup(command, command_table, eval_perms=True,
|
||||
test=False, neighbor=None):
|
||||
"""
|
||||
Performs a command table lookup on the specified command table. Also
|
||||
evaluates the permissions tuple.
|
||||
|
|
@ -329,7 +330,7 @@ def match_neighbor_ctables(command,test=False):
|
|||
Looks through the command tables of neighboring objects for command
|
||||
matches.
|
||||
test mode just checks if the command is a match, without manipulating
|
||||
any commands.
|
||||
any commands.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
if source_object.location != None:
|
||||
|
|
@ -349,7 +350,7 @@ def match_neighbor_ctables(command,test=False):
|
|||
#no matches
|
||||
return False
|
||||
|
||||
def handle(command):
|
||||
def handle(command, ignore_state=False):
|
||||
"""
|
||||
Use the spliced (list) uinput variable to retrieve the correct
|
||||
command, or return an invalid command error.
|
||||
|
|
@ -357,6 +358,8 @@ def handle(command):
|
|||
We're basically grabbing the player's command by tacking
|
||||
their input on to 'cmd_' and looking it up in the GenCommands
|
||||
class.
|
||||
|
||||
ignore_state : ignore eventual statetable lookups completely.
|
||||
"""
|
||||
try:
|
||||
# TODO: Protect against non-standard characters.
|
||||
|
|
@ -379,11 +382,11 @@ def handle(command):
|
|||
state = command.source_object.get_state()
|
||||
state_cmd_table = statetable.GLOBAL_STATE_TABLE.get_cmd_table(state)
|
||||
|
||||
if state and state_cmd_table:
|
||||
if state and state_cmd_table and not ignore_state:
|
||||
# Caller is in a special state.
|
||||
|
||||
state_allow_exits, state_allow_obj_cmds = \
|
||||
statetable.GLOBAL_STATE_TABLE.get_state_flags(state)
|
||||
statetable.GLOBAL_STATE_TABLE.get_exec_rights(state)
|
||||
|
||||
state_lookup = True
|
||||
if match_channel(command):
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ based on the value of settings.COMMAND_MODULES and
|
|||
settings.CUSTOM_COMMAND_MODULES. Each module imports cmdtable.py and runs
|
||||
add_command on the command table each command belongs to.
|
||||
"""
|
||||
|
||||
from src.helpsys.management.commands.edit_helpfiles import add_help
|
||||
from django.conf import settings
|
||||
from src.helpsys import helpsystem
|
||||
|
||||
class CommandTable(object):
|
||||
"""
|
||||
|
|
@ -28,7 +28,8 @@ class CommandTable(object):
|
|||
self.ctable = {}
|
||||
|
||||
def add_command(self, command_string, function, priv_tuple=None,
|
||||
extra_vals=None, auto_help=False, staff_help=False):
|
||||
extra_vals=None, help_category="", priv_help_tuple=None,
|
||||
auto_help_override=None):
|
||||
"""
|
||||
Adds a command to the command table.
|
||||
|
||||
|
|
@ -36,29 +37,45 @@ class CommandTable(object):
|
|||
function: (reference) The command's function.
|
||||
priv_tuple: (tuple) String tuple of permissions required for command.
|
||||
extra_vals: (dict) Dictionary to add to the Command object.
|
||||
|
||||
Auto-help system:
|
||||
auto_help (bool): If true, automatically creates/replaces a help topic with the
|
||||
same name as the command_string, using the functions's __doc__ property
|
||||
for help text.
|
||||
staff_help (bool): Only relevant if auto_help is activated; If True, makes the
|
||||
help topic (and all eventual subtopics) only visible to staff.
|
||||
|
||||
Note: the auto_help system also supports limited markup. If you divide your __doc__
|
||||
with markers of the form <<TOPIC:MyTopic>>, the system will automatically create
|
||||
separate help topics for each topic. Your initial text (if you define no TOPIC)
|
||||
will still default to the name of your command.
|
||||
You can also custon-set the staff_only flag for individual subtopics by
|
||||
using the markup <<TOPIC:STAFF:MyTopic>> and <<TOPIC:NOSTAFF:MyTopic>>.
|
||||
|
||||
Auto-help system: (this is only used if settings.HELP_AUTO_ENABLED is active)
|
||||
help_category (str): An overall help category where auto-help will place
|
||||
the help entry. If not given, 'General' is assumed.
|
||||
priv_help_tuple (tuple) String tuple of permissions required to view this
|
||||
help entry. If nothing is given, priv_tuple is used.
|
||||
auto_help_override (bool): Override the value in settings.AUTO_HELP_ENABLED with the
|
||||
value given. Use None to not override.
|
||||
This can be useful when developing a new routine and
|
||||
has made manual changes to help entries of other
|
||||
commands in the database (and so do not want to use global
|
||||
auto-help). It is also used by e.g. the state system
|
||||
to selectively deactive auto-help.
|
||||
|
||||
Note: the auto_help system also supports limited markup. You can divide your __doc__
|
||||
with markers of any combinations of the forms
|
||||
[[Title]]
|
||||
[[Title, category]]
|
||||
[[Title, (priv_tuple)]]
|
||||
[[Title, category, (priv_tuple)]],
|
||||
If such markers are found, the system will automatically create
|
||||
separate help topics for each topic. Your main help entry will
|
||||
default to the name of your command.
|
||||
"""
|
||||
self.ctable[command_string] = (function, priv_tuple, extra_vals)
|
||||
|
||||
if auto_help:
|
||||
if auto_help_override == None:
|
||||
auto_help_override = settings.HELP_AUTO_ENABLED
|
||||
|
||||
if auto_help_override:
|
||||
#add automatic help text from the command's doc string
|
||||
topicstr = command_string
|
||||
entrytext = function.__doc__
|
||||
add_help(topicstr, entrytext, staff_only=staff_help,
|
||||
force_create=True, auto_help=True)
|
||||
if not help_category:
|
||||
help_category = "General"
|
||||
if not priv_help_tuple:
|
||||
priv_help_tuple = priv_tuple
|
||||
helpsystem.edithelp.add_help_auto(topicstr, help_category,
|
||||
entrytext, priv_help_tuple)
|
||||
|
||||
def get_command_tuple(self, func_name):
|
||||
"""
|
||||
|
|
@ -67,10 +84,6 @@ class CommandTable(object):
|
|||
"""
|
||||
return self.ctable.get(func_name, False)
|
||||
|
||||
|
||||
"""
|
||||
Command tables
|
||||
"""
|
||||
# Global command table, for authenticated users.
|
||||
GLOBAL_CMD_TABLE = CommandTable()
|
||||
# Global unconnected command table, for unauthenticated users.
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ from src.statetable import GLOBAL_STATE_TABLE
|
|||
|
||||
#global defines for storage
|
||||
|
||||
STATENAME="_interactive_batch_processor"
|
||||
STATENAME="interactive batch processor"
|
||||
CMDSTACKS={} # user:cmdstack pairs (for interactive)
|
||||
STACKPTRS={} # user:stackpointer pairs (for interactive)
|
||||
FILENAMES={} # user:filename pairs (for interactive/reload)
|
||||
|
|
@ -161,6 +161,8 @@ def batch_process(source_object, commands):
|
|||
|
||||
def cmd_batchprocess(command):
|
||||
"""
|
||||
@batchprocess - build from batch file
|
||||
|
||||
Usage:
|
||||
@batchprocess[/interactive] <filename with full path>
|
||||
|
||||
|
|
@ -198,16 +200,16 @@ def cmd_batchprocess(command):
|
|||
CMDSTACKS[source_object] = commands
|
||||
STACKPTRS[source_object] = 0
|
||||
FILENAMES[source_object] = filename
|
||||
source_object.emit_to("Interactive mode (h for help).")
|
||||
source_object.emit_to("\nBatch processor - Interactive mode ...")
|
||||
show_curr(source_object)
|
||||
else:
|
||||
source_object.emit_to("Running Batch processor - Automatic mode ...")
|
||||
source_object.clear_state()
|
||||
batch_process(source_object, commands)
|
||||
source_object.emit_to("%s== Batchfile '%s' applied." % (cgreen,filename))
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@batchprocess", cmd_batchprocess,
|
||||
auto_help=True, staff_help=True,
|
||||
priv_tuple=("genperms.process_control"))
|
||||
priv_tuple=("genperms.process_control",), help_category="Building")
|
||||
|
||||
#interactive state commands
|
||||
|
||||
|
|
@ -271,43 +273,71 @@ def reload_stack(source_object):
|
|||
source_object.emit_to("Commands in file could not be reloaded. Was it moved?")
|
||||
|
||||
def move_in_stack(source_object, step=1):
|
||||
"store data in stack"
|
||||
global CMDSTACKS, STACKPTRS
|
||||
N = len(CMDSTACKS[source_object])
|
||||
currpos = STACKPTRS[source_object]
|
||||
STACKPTRS[source_object] = max(0,min(N-1,currpos+step))
|
||||
|
||||
def exit_state(source_object):
|
||||
"Quit the state"
|
||||
global CMDSTACKS,STACKPTRS,FILENAMES
|
||||
del CMDSTACKS[source_object]
|
||||
del STACKPTRS[source_object]
|
||||
del FILENAMES[source_object]
|
||||
try:
|
||||
del CMDSTACKS[source_object]
|
||||
del STACKPTRS[source_object]
|
||||
del FILENAMES[source_object]
|
||||
except KeyError:
|
||||
logger.log_errmsg("Batchprocessor quit error: all state vars could not be deleted.")
|
||||
source_object.clear_state()
|
||||
|
||||
def cmd_state_l(command):
|
||||
"l-ook at current command definition"
|
||||
def cmd_state_ll(command):
|
||||
"""
|
||||
ll
|
||||
|
||||
Look at the full source for the current
|
||||
command definition.
|
||||
"""
|
||||
show_curr(command.source_object,showall=True)
|
||||
|
||||
def cmd_state_p(command):
|
||||
"p-rocess current command definition"
|
||||
def cmd_state_pp(command):
|
||||
"""
|
||||
pp
|
||||
|
||||
Process the currently shown command definition.
|
||||
"""
|
||||
process_commands(command.source_object)
|
||||
command.source_object.emit_to(printfooter())
|
||||
|
||||
def cmd_state_r(command):
|
||||
"r-eload file, keep current stack position"
|
||||
def cmd_state_rr(command):
|
||||
"""
|
||||
rr
|
||||
|
||||
Reload the batch file, keeping the current
|
||||
position in it.
|
||||
"""
|
||||
reload_stack(command.source_object)
|
||||
command.source_object.emit_to("\nFile reloaded. Staying on same command.\n")
|
||||
show_curr(command.source_object)
|
||||
|
||||
def cmd_state_rr(command):
|
||||
"r-eload file, start over"
|
||||
def cmd_state_rrr(command):
|
||||
"""
|
||||
rrr
|
||||
|
||||
Reload the batch file, starting over
|
||||
from the beginning.
|
||||
"""
|
||||
global STACKPTRS
|
||||
reload_stack(command.source_object)
|
||||
STACKPTRS[command.source_object] = 0
|
||||
command.source_object.emit_to("\nFile reloaded. Restarting from top.\n")
|
||||
show_curr(command.source_object)
|
||||
|
||||
def cmd_state_n(command):
|
||||
"n-ext command (no exec)"
|
||||
def cmd_state_nn(command):
|
||||
"""
|
||||
nn
|
||||
|
||||
Go to next command. No commands are executed.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
|
|
@ -317,8 +347,29 @@ def cmd_state_n(command):
|
|||
move_in_stack(source_object, step)
|
||||
show_curr(source_object)
|
||||
|
||||
def cmd_state_b(command):
|
||||
"b-ackwards to previous command (no exec)"
|
||||
def cmd_state_nl(command):
|
||||
"""
|
||||
nl
|
||||
|
||||
Go to next command, viewing its full source.
|
||||
No commands are executed.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
step = int(command.command_argument)
|
||||
else:
|
||||
step = 1
|
||||
move_in_stack(source_object, step)
|
||||
show_curr(source_object, showall=True)
|
||||
|
||||
def cmd_state_bb(command):
|
||||
"""
|
||||
bb
|
||||
|
||||
Backwards to previous command. No commands
|
||||
are executed.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
|
|
@ -328,8 +379,30 @@ def cmd_state_b(command):
|
|||
move_in_stack(source_object, step)
|
||||
show_curr(source_object)
|
||||
|
||||
def cmd_state_s(command):
|
||||
"s-tep to next command (exec)"
|
||||
def cmd_state_bl(command):
|
||||
"""
|
||||
bl
|
||||
|
||||
Backwards to previous command, viewing its full
|
||||
source. No commands are executed.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
step = -int(command.command_argument)
|
||||
else:
|
||||
step = -1
|
||||
move_in_stack(source_object, step)
|
||||
show_curr(source_object, showall=True)
|
||||
|
||||
def cmd_state_ss(command):
|
||||
"""
|
||||
ss [steps]
|
||||
|
||||
Process current command, then step to the next
|
||||
one. If steps is given,
|
||||
process this many commands.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
|
|
@ -339,8 +412,30 @@ def cmd_state_s(command):
|
|||
process_commands(source_object,step)
|
||||
show_curr(source_object)
|
||||
|
||||
def cmd_state_c(command):
|
||||
"c-ontinue to process remaining"
|
||||
def cmd_state_sl(command):
|
||||
"""
|
||||
sl [steps]
|
||||
|
||||
Process current command, then step to the next
|
||||
one, viewing its full source. If steps is given,
|
||||
process this many commands.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
step = int(command.command_argument)
|
||||
else:
|
||||
step = 1
|
||||
process_commands(source_object,step)
|
||||
show_curr(source_object, showall=True)
|
||||
|
||||
def cmd_state_cc(command):
|
||||
"""
|
||||
cc
|
||||
|
||||
Continue to process all remaining
|
||||
commands.
|
||||
"""
|
||||
global CMDSTACKS,STACKPTRS
|
||||
source_object = command.source_object
|
||||
N = len(CMDSTACKS[source_object])
|
||||
|
|
@ -350,8 +445,12 @@ def cmd_state_c(command):
|
|||
exit_state(source_object)
|
||||
source_object.emit_to("Finished processing batch file.")
|
||||
|
||||
def cmd_state_j(command):
|
||||
"j-ump to specific command index"
|
||||
def cmd_state_jj(command):
|
||||
"""
|
||||
j <command number>
|
||||
|
||||
Jump to specific command number
|
||||
"""
|
||||
global STACKPTRS
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
|
|
@ -365,18 +464,44 @@ def cmd_state_j(command):
|
|||
move_in_stack(source_object, step)
|
||||
show_curr(source_object)
|
||||
|
||||
def cmd_state_q(command):
|
||||
"q-uit state."
|
||||
def cmd_state_jl(command):
|
||||
"""
|
||||
jl <command number>
|
||||
|
||||
Jump to specific command number and view its full source.
|
||||
"""
|
||||
global STACKPTRS
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
if arg and arg.isdigit():
|
||||
no = int(command.command_argument)-1
|
||||
else:
|
||||
source_object.emit_to("You must give a number index.")
|
||||
return
|
||||
ptr = STACKPTRS[source_object]
|
||||
step = no - ptr
|
||||
move_in_stack(source_object, step)
|
||||
show_curr(source_object, showall=True)
|
||||
|
||||
def cmd_state_qq(command):
|
||||
"""
|
||||
qq
|
||||
|
||||
Quit the batchprocessor.
|
||||
"""
|
||||
exit_state(command.source_object)
|
||||
command.source_object.emit_to("Aborted interactive batch mode.")
|
||||
|
||||
def cmd_state_h(command):
|
||||
def cmd_state_hh(command):
|
||||
"Help command"
|
||||
s = """
|
||||
Interactive batch processing commands:
|
||||
nn [steps] - next command (no processing)
|
||||
nl [steps] - next & look
|
||||
bb [steps] - back to previous command (no processing)
|
||||
bl [steps] - back & look
|
||||
jj <N> - jump to command no N (no processing)
|
||||
jl <N> - jump & look
|
||||
pp - process currently shown command (no step)
|
||||
ss [steps] - process & step
|
||||
ll - look at full definition of current command
|
||||
|
|
@ -384,8 +509,8 @@ def cmd_state_h(command):
|
|||
rrr - reload batch file (start from first)
|
||||
hh - this help list
|
||||
|
||||
cc - continue processing to end and quit.
|
||||
qq - quit (abort all remaining)
|
||||
cc - continue processing to end, then quit.
|
||||
qq - quit (abort all remaining commands)
|
||||
"""
|
||||
command.source_object.emit_to(s)
|
||||
|
||||
|
|
@ -394,14 +519,18 @@ def cmd_state_h(command):
|
|||
GLOBAL_STATE_TABLE.add_state(STATENAME,global_cmds='all',
|
||||
allow_exits=True,allow_obj_cmds=True)
|
||||
#add state commands
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"nn",cmd_state_n)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"bb",cmd_state_b)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"jj",cmd_state_j)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"pp",cmd_state_p)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"ss",cmd_state_s)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"cc",cmd_state_c)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"ll",cmd_state_l)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"rr",cmd_state_r)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"rrr",cmd_state_rr)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"hh",cmd_state_h)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"qq",cmd_state_q)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"nn",cmd_state_nn)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"nl",cmd_state_nl)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"bb",cmd_state_bb)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"bl",cmd_state_bl)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"jj",cmd_state_jj)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"jl",cmd_state_jl)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"pp",cmd_state_pp)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"ss",cmd_state_ss)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"sl",cmd_state_sl)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"cc",cmd_state_cc)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"ll",cmd_state_ll)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"rr",cmd_state_rr)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"rrr",cmd_state_rrr)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"hh",cmd_state_hh)
|
||||
GLOBAL_STATE_TABLE.add_command(STATENAME,"qq",cmd_state_qq)
|
||||
|
|
|
|||
|
|
@ -1,26 +1,22 @@
|
|||
"""
|
||||
Comsys command module.
|
||||
"""
|
||||
import time
|
||||
from django.conf import settings
|
||||
from src import comsys
|
||||
from src.channels.models import CommChannelMembership, CommChannel
|
||||
from src import defines_global
|
||||
from src import ansi
|
||||
from src.util import functions_general
|
||||
from src.objects.models import Object
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
|
||||
def cmd_addcom(command):
|
||||
"""
|
||||
addcom
|
||||
addcom - join a channel with alias
|
||||
|
||||
Usage:
|
||||
addcom [alias=] <channel>
|
||||
|
||||
Joins a channel. Allows adding an alias for it to make it
|
||||
easier and faster to use. Subsequent calls of this command
|
||||
can be used to add multiple aliases.
|
||||
Allows adding an alias for a channel to make is easier and
|
||||
faster to use. Subsequent calls of this command can
|
||||
be used to add multiple aliases.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
command_argument = command.command_argument
|
||||
|
|
@ -81,11 +77,11 @@ def cmd_addcom(command):
|
|||
except CommChannel.DoesNotExist:
|
||||
# Failed to match iexact on channel's 'name' attribute.
|
||||
source_object.emit_to("Could not find channel %s." % chan_name)
|
||||
GLOBAL_CMD_TABLE.add_command("addcom", cmd_addcom)
|
||||
GLOBAL_CMD_TABLE.add_command("addcom", cmd_addcom, help_category="Comms")
|
||||
|
||||
def cmd_delcom(command):
|
||||
"""
|
||||
delcom
|
||||
delcom - remove a channel alias
|
||||
|
||||
Usage:
|
||||
delcom <alias>
|
||||
|
|
@ -113,10 +109,15 @@ def cmd_delcom(command):
|
|||
leave_msg = "%s has left the channel." % \
|
||||
(source_object.get_name(show_dbref=False),)
|
||||
comsys.send_cmessage(chan_name, leave_msg)
|
||||
GLOBAL_CMD_TABLE.add_command("delcom", cmd_delcom),
|
||||
GLOBAL_CMD_TABLE.add_command("delcom", cmd_delcom,help_category="Comms")
|
||||
|
||||
def cmd_comlist(command):
|
||||
"""
|
||||
comlist - list channel memberships
|
||||
|
||||
Usage:
|
||||
comlist
|
||||
|
||||
Lists the channels a user is subscribed to.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -137,11 +138,14 @@ def cmd_comlist(command):
|
|||
chan.get_name(), chan_on)
|
||||
s = s[:-1]
|
||||
source_object.emit_to(s)
|
||||
GLOBAL_CMD_TABLE.add_command("comlist", cmd_comlist)
|
||||
GLOBAL_CMD_TABLE.add_command("comlist", cmd_comlist,help_category="Comms")
|
||||
|
||||
def cmd_allcom(command):
|
||||
"""
|
||||
allcom [on|off|who|clear]
|
||||
allcom - operate on all channels
|
||||
|
||||
Usage:
|
||||
allcom [on | off | who | clear]
|
||||
|
||||
Allows the user to universally turn off or on all channels they are on,
|
||||
as well as perform a 'who' for all channels they are on. Clear deletes
|
||||
|
|
@ -197,14 +201,18 @@ def cmd_allcom(command):
|
|||
s = s[:-2] + "\n"
|
||||
s = s[:-1]
|
||||
source_object.emit_to(s)
|
||||
GLOBAL_CMD_TABLE.add_command("allcom", cmd_allcom)
|
||||
GLOBAL_CMD_TABLE.add_command("allcom", cmd_allcom, help_category="Comms")
|
||||
|
||||
def cmd_clearcom(command):
|
||||
"""
|
||||
clearcom
|
||||
clearcom - removes all channels
|
||||
|
||||
Effectively runs delcom on all channels the user is on. It will remove their aliases,
|
||||
remove them from the channel, and clear any titles they have set.
|
||||
Usage:
|
||||
clearcom
|
||||
|
||||
Effectively runs delcom on all channels the user is on. It will remove
|
||||
their aliases, remove them from the channel, and clear any titles they
|
||||
have set.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
#get aall subscribed channel memberships
|
||||
|
|
@ -227,7 +235,10 @@ def cmd_clist(command):
|
|||
"""
|
||||
@clist
|
||||
|
||||
Lists all available channels on the game.
|
||||
Usage:
|
||||
@clist
|
||||
|
||||
Lists all available channels in the game.
|
||||
"""
|
||||
session = command.session
|
||||
source_object = command.source_object
|
||||
|
|
@ -248,13 +259,17 @@ def cmd_clist(command):
|
|||
s = s[:-1]
|
||||
#s += "** End of Channel List **"
|
||||
source_object.emit_to(s)
|
||||
GLOBAL_CMD_TABLE.add_command("@clist", cmd_clist),
|
||||
GLOBAL_CMD_TABLE.add_command("@clist", cmd_clist, help_category="Comms")
|
||||
|
||||
|
||||
def cmd_cdestroy(command):
|
||||
"""
|
||||
@cdestroy
|
||||
|
||||
Destroys a channel.
|
||||
Usage:
|
||||
@cdestroy <channel>
|
||||
|
||||
Destroys a channel that you control.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
cname = command.command_argument
|
||||
|
|
@ -275,7 +290,7 @@ def cmd_cdestroy(command):
|
|||
else:
|
||||
source_object.emit_to("Permission denied.")
|
||||
return
|
||||
GLOBAL_CMD_TABLE.add_command("@cdestroy", cmd_cdestroy)
|
||||
GLOBAL_CMD_TABLE.add_command("@cdestroy", cmd_cdestroy, help_category="Comms")
|
||||
|
||||
def cmd_cset(command):
|
||||
"""
|
||||
|
|
@ -297,9 +312,12 @@ def cmd_ccharge(command):
|
|||
|
||||
def cmd_cboot(command):
|
||||
"""
|
||||
@cboot[/quiet] <channel>=<object>
|
||||
@cboot
|
||||
|
||||
Kicks a player or object from the channel
|
||||
Usage:
|
||||
@cboot[/quiet] <channel> = <player or object>
|
||||
|
||||
Kicks a player or object from a channel you control.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
args = command.command_argument
|
||||
|
|
@ -352,14 +370,17 @@ def cmd_cboot(command):
|
|||
for mship in membership:
|
||||
comsys.plr_del_channel(bootobj, mship.user_alias)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@cboot", cmd_cboot)
|
||||
GLOBAL_CMD_TABLE.add_command("@cboot", cmd_cboot, help_category="Comms")
|
||||
|
||||
|
||||
def cmd_cemit(command):
|
||||
"""
|
||||
@cemit <channel>=<message>
|
||||
@cemit/noheader <channel>=<message>
|
||||
@cemit/sendername <channel>=<message>
|
||||
@cemit - send a message to channel
|
||||
|
||||
Usage:
|
||||
@cemit <channel>=<message>
|
||||
@cemit/noheader <channel>=<message>
|
||||
@cemit/sendername <channel>=<message>
|
||||
|
||||
Allows the user to send a message over a channel as long as
|
||||
they own or control it. It does not show the user's name unless they
|
||||
|
|
@ -425,12 +446,12 @@ def cmd_cemit(command):
|
|||
#pipe to external channels (IRC, IMC) eventually mapped to this channel
|
||||
comsys.send_cexternal(cname_parsed, cmessage, caller=source_object)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@cemit", cmd_cemit,priv_tuple=("channels.emit_commchannel",))
|
||||
GLOBAL_CMD_TABLE.add_command("@cemit", cmd_cemit,priv_tuple=("channels.emit_commchannel",),
|
||||
help_category="Comms")
|
||||
|
||||
def cmd_cwho(command):
|
||||
"""
|
||||
@cwho
|
||||
list
|
||||
|
||||
Usage:
|
||||
@cwho channel[/all]
|
||||
|
|
@ -468,15 +489,17 @@ def cmd_cwho(command):
|
|||
else:
|
||||
source_object.emit_to("No channel with that name was found.")
|
||||
return
|
||||
GLOBAL_CMD_TABLE.add_command("@cwho", cmd_cwho),
|
||||
GLOBAL_CMD_TABLE.add_command("@cwho", cmd_cwho, help_category="Comms")
|
||||
|
||||
def cmd_ccreate(command):
|
||||
"""
|
||||
@ccreate
|
||||
|
||||
Creates a new channel with the invoker being the default owner.
|
||||
Usage:
|
||||
@ccreate <new channel>
|
||||
|
||||
Creates a new channel owned by you.
|
||||
"""
|
||||
# TODO: Implement cmd_ccreate
|
||||
source_object = command.source_object
|
||||
cname = command.command_argument
|
||||
|
||||
|
|
@ -496,11 +519,14 @@ def cmd_ccreate(command):
|
|||
# Create and set the object up.
|
||||
new_chan = comsys.create_channel(cname, source_object)
|
||||
source_object.emit_to("Channel %s created." % (new_chan.get_name(),))
|
||||
GLOBAL_CMD_TABLE.add_command("@ccreate", cmd_ccreate)
|
||||
GLOBAL_CMD_TABLE.add_command("@ccreate", cmd_ccreate, help_category="Comms")
|
||||
|
||||
def cmd_cchown(command):
|
||||
"""
|
||||
@cchown <channel>=<player>
|
||||
@cchown
|
||||
|
||||
Usage:
|
||||
@cchown <channel> = <player>
|
||||
|
||||
Changes the owner of a channel.
|
||||
"""
|
||||
|
|
@ -535,4 +561,4 @@ def cmd_cchown(command):
|
|||
channel.set_owner(new_owner)
|
||||
source_object.emit_to("Owner of %s changed from %s to %s." % (cname, old_pname, pname))
|
||||
new_owner.emit_to("%s transfered ownership of channel '%s' to you." % (old_pname, cname))
|
||||
GLOBAL_CMD_TABLE.add_command("@cchown", cmd_cchown)
|
||||
GLOBAL_CMD_TABLE.add_command("@cchown", cmd_cchown, help_category="Comms")
|
||||
|
|
|
|||
|
|
@ -7,17 +7,19 @@ from django.contrib.auth.models import User
|
|||
from src.config.models import ConfigValue
|
||||
from src.helpsys.models import HelpEntry
|
||||
from src.ansi import ANSITable
|
||||
from src import defines_global
|
||||
from src import session_mgr
|
||||
from src.util import functions_general
|
||||
import src.helpsys.management.commands.edit_helpfiles as edit_help
|
||||
from src.helpsys import helpsystem
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
|
||||
def cmd_password(command):
|
||||
"""
|
||||
Changes your own password.
|
||||
|
||||
@password <Oldpass>=<Newpass>
|
||||
@password - set your password
|
||||
|
||||
Usage:
|
||||
@paassword <old password> = <new password>
|
||||
|
||||
Changes your password. Make sure to pick a safe one.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -54,18 +56,27 @@ def cmd_password(command):
|
|||
uaccount.set_password(newpass)
|
||||
uaccount.save()
|
||||
source_object.emit_to("Password changed.")
|
||||
GLOBAL_CMD_TABLE.add_command("@password", cmd_password)
|
||||
GLOBAL_CMD_TABLE.add_command("@password", cmd_password, help_category="System")
|
||||
|
||||
def cmd_pemit(command):
|
||||
"""
|
||||
@pemit
|
||||
|
||||
Emits something to a player.
|
||||
|
||||
(Not yet implemented)
|
||||
"""
|
||||
# TODO: Implement cmd_pemit
|
||||
#GLOBAL_CMD_TABLE.add_command("@pemit", cmd_pemit)
|
||||
|
||||
def cmd_emit(command):
|
||||
"""
|
||||
Emits something to your location.
|
||||
@emit
|
||||
|
||||
Usage:
|
||||
@emit <message>
|
||||
|
||||
Emits a message to your immediate surroundings.
|
||||
"""
|
||||
message = command.command_argument
|
||||
|
||||
|
|
@ -74,10 +85,15 @@ def cmd_emit(command):
|
|||
else:
|
||||
command.source_object.emit_to("Emit what?")
|
||||
GLOBAL_CMD_TABLE.add_command("@emit", cmd_emit,
|
||||
priv_tuple=("genperms.announce")),
|
||||
priv_tuple=("genperms.announce",),help_category="Comms"),
|
||||
|
||||
def cmd_wall(command):
|
||||
"""
|
||||
@wall
|
||||
|
||||
Usage:
|
||||
@wall <message>
|
||||
|
||||
Announces a message to all connected players.
|
||||
"""
|
||||
wallstring = command.command_argument
|
||||
|
|
@ -90,18 +106,29 @@ def cmd_wall(command):
|
|||
command.source_object.get_name(show_dbref=False), wallstring)
|
||||
session_mgr.announce_all(message)
|
||||
GLOBAL_CMD_TABLE.add_command("@wall", cmd_wall,
|
||||
priv_tuple=("genperms.announce"))
|
||||
priv_tuple=("genperms.announce",),help_category="Comms")
|
||||
|
||||
def cmd_idle(command):
|
||||
"""
|
||||
Returns nothing, this lets the player set an idle timer without spamming
|
||||
his screen.
|
||||
idle
|
||||
|
||||
Usage:
|
||||
idle
|
||||
|
||||
Returns and does nothing. You can use this to send idle
|
||||
messages to the game, in order to avoid getting timed out.
|
||||
"""
|
||||
pass
|
||||
GLOBAL_CMD_TABLE.add_command("idle", cmd_idle)
|
||||
GLOBAL_CMD_TABLE.add_command("idle", cmd_idle, help_category="System")
|
||||
|
||||
def cmd_inventory(command):
|
||||
"""
|
||||
inventory
|
||||
|
||||
Usage:
|
||||
inventory
|
||||
inv
|
||||
|
||||
Shows a player's inventory.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -121,7 +148,13 @@ GLOBAL_CMD_TABLE.add_command("inventory", cmd_inventory)
|
|||
|
||||
def cmd_look(command):
|
||||
"""
|
||||
Handle looking at objects.
|
||||
look
|
||||
|
||||
Usage:
|
||||
look
|
||||
look <obj>
|
||||
|
||||
Observers your location or objects in your vicinity.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -144,7 +177,13 @@ GLOBAL_CMD_TABLE.add_command("look", cmd_look)
|
|||
|
||||
def cmd_get(command):
|
||||
"""
|
||||
Get an object and put it in a player's inventory.
|
||||
get
|
||||
|
||||
Usage:
|
||||
get <obj>
|
||||
|
||||
Picks up an object from your location and puts it in
|
||||
your inventory.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
obj_is_staff = source_object.is_staff()
|
||||
|
|
@ -193,11 +232,15 @@ GLOBAL_CMD_TABLE.add_command("get", cmd_get)
|
|||
|
||||
def cmd_drop(command):
|
||||
"""
|
||||
Drop an object from a player's inventory into their current location.
|
||||
drop
|
||||
|
||||
Usage:
|
||||
drop <obj>
|
||||
|
||||
Has you drop an object from your inventory into the
|
||||
location you are currently in.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
obj_is_staff = source_object.is_staff()
|
||||
|
||||
if not command.command_argument:
|
||||
source_object.emit_to("Drop what?")
|
||||
return
|
||||
|
|
@ -219,153 +262,40 @@ def cmd_drop(command):
|
|||
target_obj.get_name(show_dbref=False)),
|
||||
exclude=source_object)
|
||||
|
||||
# SCRIPT: Call the object's script's a_drop() method.
|
||||
# SCRIPT: Call the object script's a_drop() method.
|
||||
target_obj.scriptlink.at_drop(source_object)
|
||||
GLOBAL_CMD_TABLE.add_command("drop", cmd_drop),
|
||||
|
||||
def cmd_examine(command):
|
||||
"""
|
||||
Detailed object examine command
|
||||
"""
|
||||
source_object = command.source_object
|
||||
attr_search = False
|
||||
|
||||
if not command.command_argument:
|
||||
# If no arguments are provided, examine the invoker's location.
|
||||
target_obj = source_object.get_location()
|
||||
else:
|
||||
# Look for a slash in the input, indicating an attribute search.
|
||||
attr_split = command.command_argument.split("/", 1)
|
||||
|
||||
# If the splitting by the "/" character returns a list with more than 1
|
||||
# entry, it's an attribute match.
|
||||
if len(attr_split) > 1:
|
||||
attr_search = True
|
||||
# Strip the object search string from the input with the
|
||||
# object/attribute pair.
|
||||
obj_searchstr = attr_split[0]
|
||||
attr_searchstr = attr_split[1].strip()
|
||||
|
||||
# Protect against stuff like: ex me/
|
||||
if attr_searchstr == '':
|
||||
source_object.emit_to('No attribute name provided.')
|
||||
return
|
||||
else:
|
||||
# No slash in argument, just examine an object.
|
||||
obj_searchstr = command.command_argument
|
||||
|
||||
# Resolve the target object.
|
||||
target_obj = source_object.search_for_object(obj_searchstr)
|
||||
# Use search_for_object to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
# If the user doesn't control the object, just look at it instead.
|
||||
if not source_object.controls_other(target_obj, builder_override=True):
|
||||
command.command_string = 'look'
|
||||
cmd_look(command)
|
||||
return
|
||||
|
||||
if attr_search:
|
||||
"""
|
||||
Player did something like: examine me/* or examine me/TE*. Return
|
||||
each matching attribute with its value.
|
||||
"""
|
||||
attr_matches = target_obj.attribute_namesearch(attr_searchstr)
|
||||
if attr_matches:
|
||||
for attribute in attr_matches:
|
||||
source_object.emit_to(attribute.get_attrline())
|
||||
else:
|
||||
source_object.emit_to("No matching attributes found.")
|
||||
else:
|
||||
"""
|
||||
Player is examining an object. Return a full readout of attributes,
|
||||
along with detailed information about said object.
|
||||
"""
|
||||
s = ""
|
||||
newl = "\r\n"
|
||||
# Format the examine header area with general flag/type info.
|
||||
|
||||
s += str(target_obj.get_name(fullname=True)) + newl
|
||||
s += str("Type: %s Flags: %s" % (target_obj.get_type(),
|
||||
target_obj.get_flags())) + newl
|
||||
s += str("Owner: %s " % target_obj.get_owner()) + newl
|
||||
s += str("Zone: %s" % target_obj.get_zone()) + newl
|
||||
s += str("Parent: %s " % target_obj.get_script_parent()) + newl
|
||||
|
||||
locks = target_obj.get_attribute_value("LOCKS")
|
||||
if locks and "%s" % locks:
|
||||
s += str("Locks: %s" % locks) + newl
|
||||
|
||||
# Contents container lists for sorting by type.
|
||||
con_players = []
|
||||
con_things = []
|
||||
con_exits = []
|
||||
|
||||
# Break each object out into their own list.
|
||||
for obj in target_obj.get_contents():
|
||||
if obj.is_player():
|
||||
con_players.append(obj)
|
||||
elif obj.is_exit():
|
||||
con_exits.append(obj)
|
||||
elif obj.is_thing():
|
||||
con_things.append(obj)
|
||||
|
||||
# Render the object's home or destination (for exits).
|
||||
if not target_obj.is_room():
|
||||
if target_obj.is_exit():
|
||||
# The Home attribute on an exit is really its destination.
|
||||
s += str("Destination: %s" % target_obj.get_home()) + newl
|
||||
else:
|
||||
# For everything else, home is home.
|
||||
s += str("Home: %s" % target_obj.get_home()) + newl
|
||||
# This obviously isn't valid for rooms.
|
||||
s += str("Location: %s" % target_obj.get_location()) + newl
|
||||
|
||||
# Render other attributes
|
||||
for attribute in target_obj.get_all_attributes():
|
||||
s += str(attribute.get_attrline()) + newl
|
||||
|
||||
# Render Contents display.
|
||||
if con_players or con_things:
|
||||
s += str("%sContents:%s" % (ANSITable.ansi["hilite"],
|
||||
ANSITable.ansi["normal"]))
|
||||
for player in con_players:
|
||||
s += str(' %s' % newl + player.get_name(fullname=True))
|
||||
for thing in con_things:
|
||||
s += str(' %s' % newl + thing.get_name(fullname=True))
|
||||
|
||||
# Render Exists display.
|
||||
if con_exits:
|
||||
s += str("%sExits:%s" % (newl + ANSITable.ansi["hilite"],
|
||||
ANSITable.ansi["normal"]))
|
||||
for exit in con_exits:
|
||||
s += str(' %s' % newl + exit.get_name(fullname=True))
|
||||
|
||||
# Send it all
|
||||
source_object.emit_to(s)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("examine", cmd_examine,priv_tuple=("objects.info",))
|
||||
|
||||
def cmd_quit(command):
|
||||
"""
|
||||
Gracefully disconnect the user as per his own request.
|
||||
quit
|
||||
|
||||
Usage:
|
||||
quit
|
||||
|
||||
Gracefully disconnect from the game.
|
||||
"""
|
||||
if command.session:
|
||||
session = command.session
|
||||
session.msg("Quitting. Hope to see you soon again.")
|
||||
session.handle_close()
|
||||
GLOBAL_CMD_TABLE.add_command("quit", cmd_quit)
|
||||
GLOBAL_CMD_TABLE.add_command("quit", cmd_quit, help_category="System")
|
||||
|
||||
def cmd_who(command):
|
||||
"""
|
||||
Generic WHO command.
|
||||
who
|
||||
|
||||
Usage:
|
||||
who
|
||||
|
||||
Shows who is currently online.
|
||||
"""
|
||||
session_list = session_mgr.get_session_list()
|
||||
source_object = command.source_object
|
||||
|
||||
# In the case of the DOING command, don't show session data regardless.
|
||||
if command.extra_vars and command.extra_vars.get("show_session_data", None) == False:
|
||||
if command.extra_vars and \
|
||||
command.extra_vars.get("show_session_data", None) == False:
|
||||
show_session_data = False
|
||||
else:
|
||||
show_session_data = source_object.has_perm("genperms.see_session_data")
|
||||
|
|
@ -412,12 +342,17 @@ def cmd_who(command):
|
|||
|
||||
source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("doing", cmd_who,
|
||||
extra_vals={"show_session_data": False})
|
||||
GLOBAL_CMD_TABLE.add_command("who", cmd_who)
|
||||
extra_vals={"show_session_data": False}, help_category="System")
|
||||
GLOBAL_CMD_TABLE.add_command("who", cmd_who,help_category="System")
|
||||
|
||||
def cmd_say(command):
|
||||
"""
|
||||
Room-based speech command.
|
||||
say
|
||||
|
||||
Usage:
|
||||
say <message>
|
||||
|
||||
Talk to those in your current location.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -441,7 +376,18 @@ GLOBAL_CMD_TABLE.add_command("say", cmd_say)
|
|||
|
||||
def cmd_pose(command):
|
||||
"""
|
||||
Pose/emote command.
|
||||
pose - strike a pose
|
||||
|
||||
Usage:
|
||||
pose <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.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -464,189 +410,134 @@ def cmd_pose(command):
|
|||
GLOBAL_CMD_TABLE.add_command("pose", cmd_pose)
|
||||
|
||||
def cmd_group(command):
|
||||
"""@group
|
||||
"""
|
||||
@group - show your groups
|
||||
|
||||
Usage:
|
||||
@group
|
||||
|
||||
This command shows you which user permission groups you are a member of, if any.
|
||||
This command shows you which user permission groups
|
||||
you are a member of, if any.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
user = User.objects.get(username=source_object.get_name(show_dbref=False,no_ansi=True))
|
||||
s = ""
|
||||
user = User.objects.get(username=source_object.get_name(show_dbref=False, no_ansi=True))
|
||||
string = ""
|
||||
if source_object.is_superuser():
|
||||
s += "\n This is a SUPERUSER account! Group membership does not matter."
|
||||
string += "\n This is a SUPERUSER account! Group membership does not matter."
|
||||
if not user.is_active:
|
||||
s += "\n ACCOUNT NOT ACTIVE."
|
||||
for g in user.groups.all():
|
||||
s += "\n -- %s" % g
|
||||
for p in g.permissions.all():
|
||||
s += "\n --- %s" % p.name
|
||||
if not s:
|
||||
s = "You are not a member of any groups." % source_object.get_name(show_dbref=False)
|
||||
string += "\n ACCOUNT NOT ACTIVE."
|
||||
for group in user.groups.all():
|
||||
string += "\n -- %s" % group
|
||||
for perm in group.permissions.all():
|
||||
string += "\n --- %s" % perm.name
|
||||
if not string:
|
||||
string = "You are not a member of any groups." % source_object.get_name(show_dbref=False)
|
||||
else:
|
||||
s = "\nYour (%s's) group memberships: %s" % (source_object.get_name(show_dbref=False),s)
|
||||
source_object.emit_to(s)
|
||||
GLOBAL_CMD_TABLE.add_command("@group", cmd_group,auto_help=True)
|
||||
|
||||
string = "\nYour (%s's) group memberships: %s" % (source_object.get_name(show_dbref=False), string)
|
||||
source_object.emit_to(string)
|
||||
GLOBAL_CMD_TABLE.add_command("@group", cmd_group)
|
||||
GLOBAL_CMD_TABLE.add_command("@groups", cmd_group, help_category="System")
|
||||
|
||||
def cmd_help(command):
|
||||
"""
|
||||
Help command
|
||||
Usage: help <topic>
|
||||
help - view help database
|
||||
|
||||
Usage:
|
||||
help <topic>
|
||||
|
||||
Examples: help index
|
||||
help topic
|
||||
help 2
|
||||
help 345
|
||||
|
||||
Shows the available help on <topic>. Use without <topic> to
|
||||
get the help index. If more than one topic match your query, you will get a
|
||||
Shows the available help on <topic>. Use without <topic> to get the help
|
||||
index. If more than one topic match your query, you will get a
|
||||
list of topics to choose between. You can also supply a help entry number
|
||||
directly if you know it.
|
||||
|
||||
<<TOPIC:STAFF:help_staff>>
|
||||
Help command extra functions for staff:
|
||||
|
||||
help index - the normal index
|
||||
help index_staff - show only help files unique to staff
|
||||
help index_player - show only help files visible to all players
|
||||
|
||||
The help command has a range of staff-only switches for manipulating the
|
||||
help data base:
|
||||
|
||||
help/add <topic>:<text> - add/replace help topic with text (staff only)
|
||||
help/append <topic>:<text> - add text to the end of a topic (staff only)
|
||||
(use the /newline switch to add a new paragraph
|
||||
to your help entry.)
|
||||
help/delete <topic> - delete help topic (staff only)
|
||||
|
||||
Note: further switches are /force and /staff. /force is used together with /add to
|
||||
always create a help entry, also when they partially match a previous entry. /staff
|
||||
makes the help file visible to staff only. The /append switch can be used to change the
|
||||
/staff setting of an existing help file if required.
|
||||
|
||||
The <text> entry supports markup to automatically divide the help text into
|
||||
sub-entries. These are started by the markup < <TOPIC:MyTopic> > (with no spaces
|
||||
between the << >>), which will create a new subsectioned entry 'MyTopic' for all
|
||||
text to follow it. All subsections to be added this way are automatically
|
||||
referred to in the footer of each help entry. Normally the subsections inherit the
|
||||
staff_only flag from the main entry (so if this is a staff-only help, all subentries
|
||||
will also be staff-only and vice versa). You can override this behaviour using the
|
||||
alternate forms < <TOPIC:STAFF:MyTopic> > and < <TOPIC:ALL:MyTopic> >.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
source_object = command.source_object
|
||||
topicstr = command.command_argument
|
||||
switches = command.command_switches
|
||||
topicstr = command.command_argument
|
||||
|
||||
if not command.command_argument:
|
||||
#display topic index if just help command is given
|
||||
if not switches:
|
||||
topicstr = "topic"
|
||||
else:
|
||||
#avoid applying things to "topic" by mistake
|
||||
source_object.emit_to("You have to supply a topic.")
|
||||
return
|
||||
|
||||
elif len(topicstr) < 2 and not topicstr.isdigit():
|
||||
topicstr = "index"
|
||||
|
||||
if len(topicstr) < 2 and not topicstr.isdigit():
|
||||
#check valid query
|
||||
source_object.emit_to("Your search query must be at least two letters long.")
|
||||
return
|
||||
|
||||
#speciel help index names. These entries are dynamically
|
||||
#created upon request.
|
||||
if topicstr == 'index':
|
||||
#the normal index, affected by permissions
|
||||
edit_help.get_help_index(source_object)
|
||||
# speciel help index names. These entries are dynamically
|
||||
# created upon request.
|
||||
if topicstr in ['topic','topics']:
|
||||
# the full index, affected by permissions
|
||||
text = helpsystem.viewhelp.index_full(source_object)
|
||||
text = " \nHELP TOPICS (By Category):\n\r%s" % text
|
||||
source_object.emit_to(text)
|
||||
return
|
||||
elif topicstr == 'index_staff':
|
||||
#allows staff to view only staff-specific help
|
||||
edit_help.get_help_index(source_object,filter='staff')
|
||||
return
|
||||
elif topicstr == 'index_player':
|
||||
#allows staff to view only the help files a player sees
|
||||
edit_help.get_help_index(source_object,filter='player')
|
||||
return
|
||||
|
||||
#handle special switches
|
||||
|
||||
force_create = 'for' in switches or 'force' in switches
|
||||
staff_only = 'sta' in switches or 'staff' in switches
|
||||
elif 'index' in topicstr:
|
||||
# view the category index
|
||||
text = helpsystem.viewhelp.index_categories()
|
||||
text = " \nHELP CATEGORIES (try 'help <category>' or 'help topics'):\n\r\n\r%s" % text
|
||||
source_object.emit_to(text)
|
||||
return
|
||||
|
||||
if 'add' in switches:
|
||||
#try to add/replace help text for a command
|
||||
if not source_object.has_perm("helpsys.add_help"):
|
||||
source_object.emit_to(defines_global.NOPERMS_MSG)
|
||||
return
|
||||
spl = (topicstr.split(':',1))
|
||||
if len(spl) != 2:
|
||||
source_object.emit_to("Format is help/add <topic>:<helptext>")
|
||||
return
|
||||
topicstr = spl[0]
|
||||
text = spl[1]
|
||||
topics = edit_help.add_help(topicstr,text,staff_only,force_create,source_object)
|
||||
if not topics:
|
||||
source_object.emit_to("No topic(s) added due to errors. Check syntax and that you don't have duplicate subtopics with the same name defined.")
|
||||
# not a special help index entry. Do a search for the help entry.
|
||||
topics = HelpEntry.objects.find_topicmatch(source_object, topicstr)
|
||||
|
||||
# display help entry or handle no/multiple matches
|
||||
|
||||
string = ""
|
||||
if not topics:
|
||||
# no matches.
|
||||
|
||||
# try to see if it is matching the name of a category. If so,
|
||||
# show the topics for this category.
|
||||
text = helpsystem.viewhelp.index_category(source_object, topicstr)
|
||||
if text:
|
||||
# We have category matches, display the index and exit.
|
||||
string = "\n%s%s%s\n\r\n\r%s" % ("---", " Help topics in category %s: " % \
|
||||
topicstr.capitalize(), "-"* (30-len(topicstr)), text)
|
||||
source_object.emit_to(string)
|
||||
return
|
||||
elif len(topics)>1:
|
||||
source_object.emit_to("Added or replaced multiple help entries.")
|
||||
|
||||
# at this point we just give a not-found error and give suggestions.
|
||||
topics = HelpEntry.objects.find_topicsuggestions(source_object,
|
||||
topicstr)
|
||||
if topics:
|
||||
if len(topics) > 3:
|
||||
topics = topics[:3]
|
||||
string += "\n\rMatching similarly named topics (use name or number to refine search):"
|
||||
for entry in topics:
|
||||
string += "\n %i.%s" % (entry.id, entry.topicname)
|
||||
else:
|
||||
source_object.emit_to("Added or replaced help entry for %s." % topicstr )
|
||||
string += "No matching topics found, please refine your search."
|
||||
|
||||
elif 'append' in switches or 'app' in switches:
|
||||
#append text to a help entry
|
||||
if not source_object.has_perm("helpsys.add_help"):
|
||||
source_object.emit_to(defines_global.NOPERMS_MSG)
|
||||
return
|
||||
spl = (topicstr.split(':',1))
|
||||
if len(spl) != 2:
|
||||
source_object.emit_to("""Format is help/append <topic>:<text to add>
|
||||
Use the /newline switch to make a new paragraph.""")
|
||||
return
|
||||
topicstr = spl[0]
|
||||
text = spl[1]
|
||||
topics = HelpEntry.objects.find_topicmatch(source_object, topicstr)
|
||||
if len(topics) == 1:
|
||||
newtext = topics[0].get_entrytext_ingame()
|
||||
if 'newl' in switches or 'newline' in switches:
|
||||
newtext += "\n\r\n\r%s" % text
|
||||
else:
|
||||
newtext += "\n\r%s" % text
|
||||
topics = edit_help.add_help(topicstr,newtext,staff_only,force_create,source_object)
|
||||
if topics:
|
||||
source_object.emit_to("Appended text to help entry for %s." % topicstr)
|
||||
|
||||
elif 'del' in switches or 'delete' in switches:
|
||||
#delete a help entry
|
||||
if not source_object.has_perm("helpsys.del_help"):
|
||||
source_object.emit_to(defines_global.NOPERMS_MSG)
|
||||
return
|
||||
topics = edit_help.del_help(source_object,topicstr)
|
||||
if type(topics) != type(list()):
|
||||
source_object.emit_to("Help entry '%s' deleted." % topicstr)
|
||||
return
|
||||
|
||||
else:
|
||||
#no switch; just try to get the help as normal
|
||||
topics = HelpEntry.objects.find_topicmatch(source_object, topicstr)
|
||||
|
||||
#display help entry or handle no/multiple matches
|
||||
|
||||
if len(topics) == 0:
|
||||
source_object.emit_to("No matching topics found, please refine your search.")
|
||||
suggestions = HelpEntry.objects.find_topicsuggestions(source_object,
|
||||
topicstr)
|
||||
if len(suggestions) > 0:
|
||||
source_object.emit_to("Matching similarly named topics:")
|
||||
for result in suggestions:
|
||||
source_object.emit_to(" %s" % (result,))
|
||||
source_object.emit_to("You may type 'help <#>' to see any of these topics.")
|
||||
|
||||
elif len(topics) > 1:
|
||||
source_object.emit_to("More than one match found:")
|
||||
# multiple matches found
|
||||
string += "More than one match found:"
|
||||
for result in topics:
|
||||
source_object.emit_to(" %3d. %s" % (result.id, result.get_topicname()))
|
||||
source_object.emit_to("You may type 'help <#>' to see any of these topics.")
|
||||
string += " %3d. %s" % (result.id, result.get_topicname())
|
||||
|
||||
else:
|
||||
# a single match found
|
||||
topic = topics[0]
|
||||
source_object.emit_to("\n\r "+ topic.get_entrytext_ingame())
|
||||
GLOBAL_CMD_TABLE.add_command("help", cmd_help, auto_help=True)
|
||||
header = "--- Help entry for '%s' (%s category) " % (topic.get_topicname(),
|
||||
topic.get_category())
|
||||
header = "%s%s" % (header, "-" * (80-len(header)))
|
||||
string += "\n\r%s\n\r\n\r%s" % (header, topic.get_entrytext_ingame())
|
||||
|
||||
# add the 'See also:' footer
|
||||
topics = HelpEntry.objects.find_topicsuggestions(source_object,
|
||||
topicstr)
|
||||
if topics:
|
||||
if len(topics) > 5:
|
||||
topics = topics[:5]
|
||||
topics = [str(topic.topicname) for topic in topics ]
|
||||
string += "\n\r\n\r" + " " * helpsystem.viewhelp.indent + \
|
||||
"See also: " + ", ".join(topics)
|
||||
|
||||
source_object.emit_to(string)
|
||||
GLOBAL_CMD_TABLE.add_command("help", cmd_help)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
"""
|
||||
IMC2 user and administrative commands.
|
||||
"""
|
||||
from time import time
|
||||
from django.conf import settings
|
||||
from src.config.models import ConfigValue
|
||||
from src.objects.models import Object
|
||||
from src import defines_global
|
||||
from src import ansi
|
||||
from src import comsys
|
||||
from src.util import functions_general
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
from src.ansi import parse_ansi
|
||||
from src.imc2.imc_ansi import IMCANSIParser
|
||||
|
|
@ -20,7 +14,12 @@ from src.channels.models import CommChannel
|
|||
|
||||
def cmd_imcwhois(command):
|
||||
"""
|
||||
Shows a player's inventory.
|
||||
imcwhois
|
||||
|
||||
Usage:
|
||||
imcwhois
|
||||
|
||||
IMC2 command. Shows a player's inventory.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
if not command.command_argument:
|
||||
|
|
@ -30,10 +29,15 @@ def cmd_imcwhois(command):
|
|||
source_object.emit_to("Sending IMC whois request. If you receive no response, no matches were found.")
|
||||
packet = IMC2PacketWhois(source_object, command.command_argument)
|
||||
imc2_conn.IMC2_PROTOCOL_INSTANCE.send_packet(packet)
|
||||
GLOBAL_CMD_TABLE.add_command("imcwhois", cmd_imcwhois)
|
||||
GLOBAL_CMD_TABLE.add_command("imcwhois", cmd_imcwhois, help_category="Comms")
|
||||
|
||||
def cmd_imcansi(command):
|
||||
"""
|
||||
imcansi
|
||||
|
||||
Usage:
|
||||
imcansi <string>
|
||||
|
||||
Test IMC ANSI conversion.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -43,20 +47,30 @@ def cmd_imcansi(command):
|
|||
else:
|
||||
retval = parse_ansi(command.command_argument, parser=IMCANSIParser())
|
||||
source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("imcansi", cmd_imcansi)
|
||||
GLOBAL_CMD_TABLE.add_command("imcansi", cmd_imcansi, help_category="Comms")
|
||||
|
||||
def cmd_imcicerefresh(command):
|
||||
"""
|
||||
Semds an ice-refresh packet.
|
||||
imcicerefresh
|
||||
|
||||
Usage:
|
||||
imcicerefresh
|
||||
|
||||
IMC2: Semds an ice-refresh packet.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
packet = IMC2PacketIceRefresh()
|
||||
imc2_conn.IMC2_PROTOCOL_INSTANCE.send_packet(packet)
|
||||
source_object.emit_to("Sent")
|
||||
GLOBAL_CMD_TABLE.add_command("imcicerefresh", cmd_imcicerefresh)
|
||||
GLOBAL_CMD_TABLE.add_command("imcicerefresh", cmd_imcicerefresh, help_category="Comms")
|
||||
|
||||
def cmd_imcchanlist(command):
|
||||
"""
|
||||
imcchanlist
|
||||
|
||||
Usage:
|
||||
imcchanlist
|
||||
|
||||
Shows the list of cached channels from the IMC2 Channel list.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -73,10 +87,15 @@ def cmd_imcchanlist(command):
|
|||
channel.policy)
|
||||
retval += '%s channels found.' % len(IMC2_CHANLIST.chan_list)
|
||||
source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("imcchanlist", cmd_imcchanlist)
|
||||
GLOBAL_CMD_TABLE.add_command("imcchanlist", cmd_imcchanlist, help_category="Comms")
|
||||
|
||||
def cmd_imclist(command):
|
||||
"""
|
||||
imclist
|
||||
|
||||
Usage:
|
||||
imclist
|
||||
|
||||
Shows the list of cached games from the IMC2 Mud list.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -88,10 +107,15 @@ def cmd_imclist(command):
|
|||
retval += '%s\n\r' % mudline[:78]
|
||||
retval += '%s active MUDs found.' % len(IMC2_MUDLIST.mud_list)
|
||||
source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("imclist", cmd_imclist)
|
||||
GLOBAL_CMD_TABLE.add_command("imclist", cmd_imclist, help_category="Comms")
|
||||
|
||||
def cmd_imcstatus(command):
|
||||
"""
|
||||
imcstatus
|
||||
|
||||
Usage:
|
||||
imcstatus
|
||||
|
||||
Shows some status information for your IMC2 connection.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -118,21 +142,24 @@ def cmd_imcstatus(command):
|
|||
|
||||
source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("imcstatus", cmd_imcstatus,
|
||||
priv_tuple=('imc2.admin_imc_channels',))
|
||||
priv_tuple=('imc2.admin_imc_channels',), help_category="Comms")
|
||||
|
||||
|
||||
def cmd_IMC2chan(command):
|
||||
"""
|
||||
@imc2chan IMCServer:IMCchannel channel
|
||||
@imc2chan
|
||||
|
||||
Links an IMC channel to an existing
|
||||
evennia channel. You can link as many existing
|
||||
Usage:
|
||||
@imc2chan <IMCServer> : <IMCchannel> <channel>
|
||||
|
||||
Links an IMC channel to an existing evennia
|
||||
channel. You can link as many existing
|
||||
evennia channels as you like to the
|
||||
IMC channel this way. Running the command with an
|
||||
existing mapping will re-map the channels.
|
||||
|
||||
Use 'imcchanlist' to get a list of IMC channels and servers.
|
||||
Note that both are case sensitive.
|
||||
Use 'imcchanlist' to get a list of IMC channels and
|
||||
servers. Note that both are case sensitive.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
if not settings.IMC2_ENABLED:
|
||||
|
|
@ -179,6 +206,6 @@ def cmd_IMC2chan(command):
|
|||
outstring += "Mapping set: %s." % mapping
|
||||
source_object.emit_to(outstring)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@imc2chan",cmd_IMC2chan,auto_help=True,staff_help=True,
|
||||
priv_tuple=("imc2.admin_imc_channels",))
|
||||
GLOBAL_CMD_TABLE.add_command("@imc2chan",cmd_IMC2chan,
|
||||
priv_tuple=("imc2.admin_imc_channels",), help_category="Comms")
|
||||
|
||||
|
|
|
|||
|
|
@ -17,25 +17,41 @@ from src.cmdtable import GLOBAL_CMD_TABLE
|
|||
|
||||
def cmd_version(command):
|
||||
"""
|
||||
Version info command.
|
||||
@version - game version
|
||||
|
||||
Usage:
|
||||
@version
|
||||
|
||||
Display the game version info
|
||||
"""
|
||||
retval = "-"*50 +"\n\r"
|
||||
retval += " Evennia %s\n\r" % (defines_global.EVENNIA_VERSION,)
|
||||
retval += " Django %s\n\r" % (django.get_version())
|
||||
retval += "-"*50
|
||||
command.source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("version", cmd_version),
|
||||
GLOBAL_CMD_TABLE.add_command("@version", cmd_version, help_category="Admin"),
|
||||
|
||||
def cmd_time(command):
|
||||
"""
|
||||
@time
|
||||
|
||||
Usage:
|
||||
@time
|
||||
|
||||
Server local time.
|
||||
"""
|
||||
command.source_object.emit_to('Current server time : %s' %
|
||||
(time.strftime('%a %b %d %H:%M:%S %Y (%Z)', time.localtime(),)))
|
||||
GLOBAL_CMD_TABLE.add_command("time", cmd_time),
|
||||
GLOBAL_CMD_TABLE.add_command("@time", cmd_time, priv_tuple=("genperms.game_info",),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_uptime(command):
|
||||
"""
|
||||
@uptime
|
||||
|
||||
Usage:
|
||||
@uptime
|
||||
|
||||
Server uptime and stats.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -54,11 +70,18 @@ def cmd_uptime(command):
|
|||
loadavg = os.getloadavg()
|
||||
source_object.emit_to('Server load (1 min) : %.2f' %
|
||||
loadavg[0])
|
||||
GLOBAL_CMD_TABLE.add_command("uptime", cmd_uptime),
|
||||
GLOBAL_CMD_TABLE.add_command("@uptime", cmd_uptime, priv_tuple=("genperms.game_info",),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_list(command):
|
||||
"""
|
||||
Shows some game related information.
|
||||
"""
|
||||
@list - list info
|
||||
|
||||
Usage:
|
||||
@list commands | flags | process
|
||||
|
||||
Shows game related information depending
|
||||
on which argument is given.
|
||||
"""
|
||||
server = command.session.server
|
||||
source_object = command.source_object
|
||||
|
|
@ -99,10 +122,15 @@ def cmd_list(command):
|
|||
source_object.emit_to("Flags: "+" ".join(flags.SERVER_FLAGS))
|
||||
else:
|
||||
source_object.emit_to(msg_invalid)
|
||||
GLOBAL_CMD_TABLE.add_command("@list", cmd_list,priv_tuple=("genperms.game_info",)),
|
||||
GLOBAL_CMD_TABLE.add_command("@list", cmd_list,priv_tuple=("genperms.game_info",), help_category="Admin")
|
||||
|
||||
def cmd_ps(command):
|
||||
"""
|
||||
@ps - list processes
|
||||
|
||||
Usage
|
||||
@ps
|
||||
|
||||
Shows the process/event table.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -115,13 +143,23 @@ def cmd_ps(command):
|
|||
event.description))
|
||||
source_object.emit_to("Totals: %d interval events" % (len(scheduler.schedule),))
|
||||
GLOBAL_CMD_TABLE.add_command("@ps", cmd_ps,
|
||||
priv_tuple=("genperms.process_control")),
|
||||
priv_tuple=("genperms.process_control",), help_category="Admin")
|
||||
|
||||
def cmd_stats(command):
|
||||
"""
|
||||
@stats - show object stats
|
||||
|
||||
Usage:
|
||||
@stats
|
||||
|
||||
Example:
|
||||
@stats
|
||||
->
|
||||
4012 objects = 144 rooms, 212 exits, 613 things, 1878 players. (1165 garbage)
|
||||
|
||||
Shows stats about the database.
|
||||
4012 objects = 144 rooms, 212 exits, 613 things, 1878 players. (1165 garbage)
|
||||
"""
|
||||
|
||||
stats_dict = Object.objects.object_totals()
|
||||
command.source_object.emit_to(
|
||||
"%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" %
|
||||
|
|
@ -131,4 +169,4 @@ def cmd_stats(command):
|
|||
stats_dict["things"],
|
||||
stats_dict["players"],
|
||||
stats_dict["garbage"]))
|
||||
GLOBAL_CMD_TABLE.add_command("@stats", cmd_stats, priv_tuple=("genperms.game_info",)),
|
||||
GLOBAL_CMD_TABLE.add_command("@stats", cmd_stats, priv_tuple=("genperms.game_info",), help_category="Admin"),
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ from src.channels.models import CommChannel
|
|||
|
||||
def cmd_IRC2chan(command):
|
||||
"""
|
||||
@irc2chan IRCchannel channel
|
||||
@irc2chan - link irc to ingame channel
|
||||
|
||||
Usage:
|
||||
@irc2chan <#IRCchannel> <local channel>
|
||||
|
||||
Links an IRC channel (including #) to an existing
|
||||
evennia channel. You can link as many existing
|
||||
|
|
@ -55,12 +58,16 @@ def cmd_IRC2chan(command):
|
|||
outstring += "Mapping set: %s." % mapping
|
||||
source_object.emit_to(outstring)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@irc2chan",cmd_IRC2chan,auto_help=True,staff_help=True,
|
||||
priv_tuple=("irc.admin_irc_channels",))
|
||||
GLOBAL_CMD_TABLE.add_command("@irc2chan",cmd_IRC2chan,
|
||||
priv_tuple=("irc.admin_irc_channels",),
|
||||
help_category="Comms")
|
||||
|
||||
def cmd_IRCjoin(command):
|
||||
"""
|
||||
@ircjoin IRCchannel
|
||||
@ircjoin - join a new irc channel
|
||||
|
||||
Usage:
|
||||
@ircjoin <#IRCchannel>
|
||||
|
||||
Attempts to connect a bot to a new IRC channel (don't forget that
|
||||
IRC channels begin with a #).
|
||||
|
|
@ -99,19 +106,25 @@ def cmd_IRCjoin(command):
|
|||
# irc.setName("%s:%s" % ("IRC",channel))
|
||||
# irc.setServiceParent(mud_service.service_collection)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@ircjoin",cmd_IRCjoin,auto_help=True,
|
||||
staff_help=True,
|
||||
priv_tuple=("irc.admin_irc_channels",))
|
||||
GLOBAL_CMD_TABLE.add_command("@ircjoin",cmd_IRCjoin,
|
||||
priv_tuple=("irc.admin_irc_channels",),
|
||||
help_category="Comms")
|
||||
|
||||
def cmd_IRCchanlist(command):
|
||||
"""
|
||||
ircchanlist
|
||||
|
||||
Usage:
|
||||
ircchanlist
|
||||
|
||||
Lists all externally available IRC channels.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
s = "Available IRC channels:"
|
||||
for c in IRC_CHANNELS:
|
||||
s += "\n %s \t(nick '%s') on %s" % (c.factory.channel,c.factory.nickname,c.factory.network,)
|
||||
s += "\n %s \t(nick '%s') on %s" % (c.factory.channel,
|
||||
c.factory.nickname,
|
||||
c.factory.network,)
|
||||
source_object.emit_to(s)
|
||||
GLOBAL_CMD_TABLE.add_command("ircchanlist", cmd_IRCchanlist, auto_help=True)
|
||||
GLOBAL_CMD_TABLE.add_command("ircchanlist", cmd_IRCchanlist,
|
||||
help_category="Comms")
|
||||
|
|
|
|||
|
|
@ -9,10 +9,21 @@ from src import locks
|
|||
from src import ansi
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
from src import defines_global
|
||||
from src.ansi import ANSITable
|
||||
|
||||
def cmd_teleport(command):
|
||||
"""
|
||||
Teleports an object somewhere.
|
||||
teleport
|
||||
|
||||
Usage:
|
||||
teleport/switch [<object> = <location>]
|
||||
|
||||
Switches:
|
||||
quiet - don't inform the source and target
|
||||
locations about the move.
|
||||
|
||||
Teleports an object somewhere. If no object is
|
||||
given we are teleporting ourselves.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -66,10 +77,15 @@ def cmd_teleport(command):
|
|||
|
||||
source_object.move_to(target_obj, quiet=tel_quietly)
|
||||
GLOBAL_CMD_TABLE.add_command("@teleport", cmd_teleport,
|
||||
priv_tuple=("objects.teleport",))
|
||||
priv_tuple=("objects.teleport",), help_category="Building")
|
||||
|
||||
def cmd_alias(command):
|
||||
"""
|
||||
@alias
|
||||
|
||||
Usage:
|
||||
@alias <player> = <alias>
|
||||
|
||||
Assigns an alias to a player object for ease of paging, etc.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -118,8 +134,17 @@ GLOBAL_CMD_TABLE.add_command("@alias", cmd_alias)
|
|||
|
||||
def cmd_wipe(command):
|
||||
"""
|
||||
Wipes an object's attributes, or optionally only those matching a search
|
||||
string.
|
||||
@wipe - clears attributes
|
||||
|
||||
Usage:
|
||||
@wipe <object> [/attribute-wildcard]
|
||||
|
||||
Example:
|
||||
@wipe box
|
||||
@wipe box/colour
|
||||
|
||||
Wipes all of an object's attributes, or optionally only those
|
||||
matching the given attribute-wildcard search string.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
attr_search = False
|
||||
|
|
@ -166,11 +191,21 @@ def cmd_wipe(command):
|
|||
target_obj.clear_attribute(attr.get_name())
|
||||
source_object.emit_to("%s - %d attributes wiped." % (target_obj.get_name(),
|
||||
len(attr_matches)))
|
||||
GLOBAL_CMD_TABLE.add_command("@wipe", cmd_wipe,priv_tuple=("objects.wipe",))
|
||||
GLOBAL_CMD_TABLE.add_command("@wipe", cmd_wipe,priv_tuple=("objects.wipe",),
|
||||
help_category="Building")
|
||||
|
||||
def cmd_set(command):
|
||||
"""
|
||||
Sets flags or attributes on objects.
|
||||
@set - set attributes and flags
|
||||
|
||||
Usage:
|
||||
@set <obj> = <flag>
|
||||
@set <obj> = <attr> : <value>
|
||||
@set <obj> = !<flag>
|
||||
@set <obj> = <attr> :
|
||||
|
||||
Sets flags or attributes on objects. The two last forms
|
||||
above unsets the flag and clears the attribute, respectively.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
args = command.command_argument
|
||||
|
|
@ -251,16 +286,26 @@ def cmd_set(command):
|
|||
s += '\nFlag %s=%s set.' % (target_name, flag.upper())
|
||||
target.set_flag(flag, True)
|
||||
source_object.emit_to(s[1:])
|
||||
GLOBAL_CMD_TABLE.add_command("@set", cmd_set, priv_tuple=("objects.modify_attributes",))
|
||||
GLOBAL_CMD_TABLE.add_command("@set", cmd_set, priv_tuple=("objects.modify_attributes",),
|
||||
help_category="Building")
|
||||
|
||||
def cmd_cpattr(command):
|
||||
"""
|
||||
copy an attribute to another object
|
||||
|
||||
@cpattr <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]
|
||||
@cpattr <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]
|
||||
@cpattr <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]
|
||||
@cpattr <attr> = <obj1>[,<obj2>,<obj3>,...]
|
||||
@cpattr - copy attributes
|
||||
|
||||
Usage:
|
||||
@cpattr <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]
|
||||
@cpattr <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]
|
||||
@cpattr <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]
|
||||
@cpattr <attr> = <obj1>[,<obj2>,<obj3>,...]
|
||||
|
||||
Example:
|
||||
@cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety
|
||||
->
|
||||
copies the coolness attribute (defined on yourself), to attributes
|
||||
on Anna and Tom.
|
||||
|
||||
Copy the attribute one object to one or more attributes on another object.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
args = command.command_argument
|
||||
|
|
@ -333,14 +378,17 @@ def cmd_cpattr(command):
|
|||
to_objname, to_attr)
|
||||
source_object.emit_to(s)
|
||||
GLOBAL_CMD_TABLE.add_command("@cpattr", cmd_cpattr,
|
||||
priv_tuple=("objects.modify_attributes",))
|
||||
priv_tuple=("objects.modify_attributes",), help_category="Building")
|
||||
|
||||
|
||||
def cmd_mvattr(command):
|
||||
"""
|
||||
@mvattr <object>=<old>,<new>[,<copy1>[, <copy2 ...]]
|
||||
@mvattr - move attributes
|
||||
|
||||
Move attributes around on an object
|
||||
Usage:
|
||||
@mvattr <object>=<old>,<new>[,<copy1>[, <copy2 ...]]
|
||||
|
||||
Move attributes around on the same object.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
|
|
@ -395,10 +443,16 @@ def cmd_mvattr(command):
|
|||
source_object.emit_to(s)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@mvattr", cmd_mvattr,
|
||||
priv_tuple=("objects.modify_attributes",))
|
||||
priv_tuple=("objects.modify_attributes",),
|
||||
help_category="Building")
|
||||
|
||||
def cmd_find(command):
|
||||
"""
|
||||
find
|
||||
|
||||
Usage:
|
||||
find <searchname>
|
||||
|
||||
Searches for an object of a particular name.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -421,13 +475,14 @@ def cmd_find(command):
|
|||
else:
|
||||
source_object.emit_to("No name matches found for: %s" % (searchstring,))
|
||||
GLOBAL_CMD_TABLE.add_command("@find", cmd_find,
|
||||
priv_tuple=("objects.info",))
|
||||
priv_tuple=("objects.info",), help_category="Building")
|
||||
|
||||
def cmd_create(command):
|
||||
"""
|
||||
@create
|
||||
@create - create new objects
|
||||
|
||||
Usage: @create[/drop] objname [:parent]
|
||||
Usage:
|
||||
@create[/drop] objname [:parent]
|
||||
|
||||
switch:
|
||||
drop - automatically drop the new object into your current location (this is not echoed)
|
||||
|
|
@ -477,15 +532,20 @@ def cmd_create(command):
|
|||
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@create", cmd_create,
|
||||
priv_tuple=("objects.create",),auto_help=True,staff_help=True)
|
||||
priv_tuple=("objects.create",),
|
||||
help_category="Building")
|
||||
|
||||
def cmd_copy(command):
|
||||
"""Usage:
|
||||
@copy[/reset] <original obj> [new_name] [, new_location]
|
||||
"""
|
||||
@copy - copy objects
|
||||
|
||||
Usage:
|
||||
@copy[/reset] <original obj> [new_name] [, new_location]
|
||||
|
||||
switch:
|
||||
reset - make a 'clean' copy, without any changes that might have happened to the
|
||||
original since it was first created.
|
||||
reset - make a 'clean' copy off the object's script parent, thus
|
||||
removing any changes that might have been made to the original
|
||||
since it was first created.
|
||||
|
||||
Create an identical copy of an object.
|
||||
"""
|
||||
|
|
@ -542,12 +602,13 @@ def cmd_copy(command):
|
|||
reset_text = " (using default attrs/flags)"
|
||||
source_object.emit_to("Copied object '%s'%s%s%s." % (objname,name_text,loc_text,reset_text))
|
||||
GLOBAL_CMD_TABLE.add_command("@copy", cmd_copy,
|
||||
priv_tuple=("objects.create",),auto_help=True,staff_help=True)
|
||||
|
||||
|
||||
|
||||
priv_tuple=("objects.create",), help_category="Building")
|
||||
|
||||
def cmd_nextfree(command):
|
||||
"""Usage:
|
||||
"""
|
||||
@nextfree
|
||||
|
||||
Usage:
|
||||
@nextfree
|
||||
|
||||
Returns the next free object number.
|
||||
|
|
@ -555,10 +616,12 @@ def cmd_nextfree(command):
|
|||
nextfree = Object.objects.get_nextfree_dbnum()
|
||||
command.source_object.emit_to("Next free object number: #%s" % nextfree)
|
||||
GLOBAL_CMD_TABLE.add_command("@nextfree", cmd_nextfree,
|
||||
priv_tuple=("objects.info",),auto_help=True,staff_help=True)
|
||||
priv_tuple=("objects.info",), help_category="Building")
|
||||
|
||||
def cmd_open(command):
|
||||
"""@open
|
||||
"""
|
||||
@open - create new exit
|
||||
|
||||
Usage:
|
||||
@open <new exit> [:parent] [= <destination> [,<return exit> [:parent]]]
|
||||
|
||||
|
|
@ -670,15 +733,17 @@ def cmd_open(command):
|
|||
source_object.emit_to("Created exit%s back from %s named %s." % \
|
||||
(ptext, destination, new_object))
|
||||
GLOBAL_CMD_TABLE.add_command("@open", cmd_open,
|
||||
priv_tuple=("objects.dig",),auto_help=True,staff_help=True)
|
||||
priv_tuple=("objects.dig",), help_category="Building")
|
||||
|
||||
def cmd_chown(command):
|
||||
"""
|
||||
Changes the ownership of an object. The new owner specified must be a
|
||||
player object.
|
||||
@chown - change ownerships
|
||||
|
||||
Forms:
|
||||
@chown <Object>=<NewOwner>
|
||||
Usage:
|
||||
@chown <Object> = <NewOwner>
|
||||
|
||||
Changes the ownership of an object. The new owner specified must be a
|
||||
player object.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -721,15 +786,19 @@ def cmd_chown(command):
|
|||
# We haven't provided a target.
|
||||
source_object.emit_to("Who should be the new owner of the object?")
|
||||
return
|
||||
GLOBAL_CMD_TABLE.add_command("@chown", cmd_chown, priv_tuple=("objects.modify_attributes","objects.admin_ownership"))
|
||||
GLOBAL_CMD_TABLE.add_command("@chown", cmd_chown, priv_tuple=("objects.modify_attributes",
|
||||
"objects.admin_ownership"),
|
||||
help_category="Building" )
|
||||
|
||||
def cmd_chzone(command):
|
||||
"""
|
||||
@chzone - set zones
|
||||
|
||||
Usage:
|
||||
@chzone <Object> = <NewZone>
|
||||
|
||||
Changes an object's zone. The specified zone may be of any object type, but
|
||||
will typically be a THING.
|
||||
|
||||
Forms:
|
||||
@chzone <Object>=<NewZone>
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -773,10 +842,13 @@ def cmd_chzone(command):
|
|||
# We haven't provided a target zone.
|
||||
source_object.emit_to("What should the object's zone be set to?")
|
||||
return
|
||||
GLOBAL_CMD_TABLE.add_command("@chzone", cmd_chzone, priv_tuple=("objects.dig",))
|
||||
GLOBAL_CMD_TABLE.add_command("@chzone", cmd_chzone, priv_tuple=("objects.dig",),
|
||||
help_category="Building" )
|
||||
|
||||
def cmd_link(command):
|
||||
"""@link
|
||||
"""
|
||||
@link - connect objects
|
||||
|
||||
Usage:
|
||||
@link <object> = <target>
|
||||
@link <object> =
|
||||
|
|
@ -864,13 +936,17 @@ def cmd_link(command):
|
|||
else:
|
||||
source_object.emit_to("You set the home location of %s to %s%s." % (obj, destination, ohome_text))
|
||||
GLOBAL_CMD_TABLE.add_command("@link", cmd_link,
|
||||
priv_tuple=("objects.dig",), auto_help=True, staff_help=True)
|
||||
priv_tuple=("objects.dig",), help_category="Building")
|
||||
|
||||
def cmd_unlink(command):
|
||||
"""
|
||||
Unlinks an object.
|
||||
|
||||
@unlink <Object>
|
||||
@unlink - unconnect objects
|
||||
|
||||
Usage:
|
||||
@unlink <Object>
|
||||
|
||||
Unlinks an object, for example an exit, disconnecting
|
||||
it from whatever it was connected to.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -890,15 +966,19 @@ def cmd_unlink(command):
|
|||
target_obj.set_home(None)
|
||||
source_object.emit_to("You have unlinked %s." % target_obj.get_name())
|
||||
GLOBAL_CMD_TABLE.add_command("@unlink", cmd_unlink,
|
||||
priv_tuple=("objects.dig",))
|
||||
priv_tuple=("objects.dig",), help_category="Building")
|
||||
|
||||
def cmd_dig(command):
|
||||
"""@dig
|
||||
"""
|
||||
@dig - build and connect new rooms
|
||||
|
||||
Usage:
|
||||
@dig[/switches] roomname [:parent] [= exit_to_there [: parent][;alias]] [, exit_to_here [: parent][;alias]]
|
||||
switches:
|
||||
|
||||
Switches:
|
||||
teleport - move yourself to the new room
|
||||
example:
|
||||
|
||||
Example:
|
||||
@dig kitchen = north; n, south; s
|
||||
|
||||
This command is a convenient way to build rooms quickly; it creates the new room and you can optionally
|
||||
|
|
@ -1018,13 +1098,16 @@ def cmd_dig(command):
|
|||
source_object.move_to(new_room)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@dig", cmd_dig,
|
||||
priv_tuple=("objects.dig",), auto_help=True, staff_help=True)
|
||||
priv_tuple=("objects.dig",), help_category="Building")
|
||||
|
||||
def cmd_name(command):
|
||||
"""
|
||||
Handle naming an object.
|
||||
|
||||
@name <Object>=<Value>
|
||||
@name - name objects
|
||||
|
||||
Usage:
|
||||
@name <Object> = <Value>
|
||||
|
||||
Handle naming an object.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -1060,10 +1143,16 @@ def cmd_name(command):
|
|||
source_object.emit_to("You have renamed %s to %s." % (target_obj,
|
||||
ansi_name))
|
||||
target_obj.set_name(new_name)
|
||||
GLOBAL_CMD_TABLE.add_command("@name", cmd_name)
|
||||
GLOBAL_CMD_TABLE.add_command("@name", cmd_name, priv_tuple=("objects.create",),
|
||||
help_category="Building")
|
||||
|
||||
def cmd_description(command):
|
||||
"""
|
||||
@desc
|
||||
|
||||
Usage:
|
||||
@desc [obj =] <descriptive text>
|
||||
|
||||
Set an object's description.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -1099,20 +1188,21 @@ def cmd_description(command):
|
|||
else:
|
||||
source_object.emit_to("%s - description set." % target_obj)
|
||||
target_obj.set_attribute('desc', new_desc)
|
||||
GLOBAL_CMD_TABLE.add_command("@describe", cmd_description)
|
||||
GLOBAL_CMD_TABLE.add_command("@describe", cmd_description, priv_tuple=("objects.create",),
|
||||
help_category="Building")
|
||||
|
||||
def cmd_recover(command):
|
||||
"""
|
||||
@recover
|
||||
|
||||
Recovers @destroyed non-player objects.
|
||||
@recover - undo object deletion
|
||||
|
||||
Usage:
|
||||
@recover[/switches] [obj [,obj2, ...]]
|
||||
@recover[/switches] [obj [,obj2, ...]]
|
||||
|
||||
switches:
|
||||
ROOM - recover as ROOM type instead of THING
|
||||
EXIT - recover as EXIT type instead of THING
|
||||
ROOM - recover as ROOM type instead of THING
|
||||
EXIT - recover as EXIT type instead of THING
|
||||
|
||||
Recovers @destroyed non-player objects.
|
||||
|
||||
If no argument is given, a list of all recoverable objects will be given.
|
||||
|
||||
|
|
@ -1165,14 +1255,12 @@ def cmd_recover(command):
|
|||
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@recover", cmd_recover,
|
||||
priv_tuple=("objects.create",),auto_help=True,staff_help=True)
|
||||
priv_tuple=("objects.create",), help_category="Building")
|
||||
|
||||
def cmd_destroy(command):
|
||||
"""
|
||||
@destroy
|
||||
|
||||
Destroys one or many objects.
|
||||
|
||||
@destroy - send objects to trashbin
|
||||
|
||||
Usage:
|
||||
@destroy[/<switches>] obj [,obj2, obj3, ...]
|
||||
|
||||
|
|
@ -1182,6 +1270,7 @@ def cmd_destroy(command):
|
|||
switch overrides this safety.
|
||||
instant|now - Destroy the object immediately, without delay.
|
||||
|
||||
Destroys one or many objects.
|
||||
The objects are set to GOING and will be permanently destroyed next time the system
|
||||
does cleanup. Until then non-player objects can still be saved by using the
|
||||
@recover command. The contents of a room will be moved out before it is destroyed,
|
||||
|
|
@ -1244,19 +1333,23 @@ def cmd_destroy(command):
|
|||
source_object.emit_to("You schedule %s for destruction." % target_obj.get_name())
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@destroy", cmd_destroy,
|
||||
priv_tuple=("objects.create",),auto_help=True,staff_help=True)
|
||||
priv_tuple=("objects.create",), help_category="Building")
|
||||
|
||||
def cmd_lock(command):
|
||||
"""@lock
|
||||
"""
|
||||
@lock - limit use of objects
|
||||
|
||||
Usage:
|
||||
@lock[/switch] <obj> [:type] [= <key>[,key2,key3,...]]
|
||||
|
||||
switches:
|
||||
Switches:
|
||||
add - add a lock (default) from object
|
||||
del - remove a lock from object
|
||||
list - view all locks on object (default)
|
||||
type:
|
||||
DefaultLock - the default lock type (default)
|
||||
UseLock - prevents usage of objects' commands
|
||||
EnterLock - blocking objects from entering the object
|
||||
|
||||
Locks an object for everyone except those matching the keys.
|
||||
The keys can be of the following types (and searched in this order):
|
||||
|
|
@ -1433,4 +1526,137 @@ def cmd_lock(command):
|
|||
source_object.emit_to("Added lock '%s' to %s with keys%s." % (ltype, obj.get_name(), kstring))
|
||||
|
||||
obj.set_attribute("LOCKS",obj_locks)
|
||||
GLOBAL_CMD_TABLE.add_command("@lock", cmd_lock, priv_tuple=("objects.create",),auto_help=True, staff_help=True)
|
||||
GLOBAL_CMD_TABLE.add_command("@lock", cmd_lock, priv_tuple=("objects.create",), help_category="Building")
|
||||
|
||||
def cmd_examine(command):
|
||||
"""
|
||||
examine - detailed info on objects
|
||||
|
||||
Usage:
|
||||
examine [<object>]
|
||||
|
||||
The examine command shows detailed game info about an
|
||||
object; which attributes/flags it has and what it
|
||||
contains. If object is not specified, the current
|
||||
location is examined.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
attr_search = False
|
||||
|
||||
if not command.command_argument:
|
||||
# If no arguments are provided, examine the invoker's location.
|
||||
target_obj = source_object.get_location()
|
||||
else:
|
||||
# Look for a slash in the input, indicating an attribute search.
|
||||
attr_split = command.command_argument.split("/", 1)
|
||||
|
||||
# If the splitting by the "/" character returns a list with more than 1
|
||||
# entry, it's an attribute match.
|
||||
if len(attr_split) > 1:
|
||||
attr_search = True
|
||||
# Strip the object search string from the input with the
|
||||
# object/attribute pair.
|
||||
obj_searchstr = attr_split[0]
|
||||
attr_searchstr = attr_split[1].strip()
|
||||
|
||||
# Protect against stuff like: ex me/
|
||||
if attr_searchstr == '':
|
||||
source_object.emit_to('No attribute name provided.')
|
||||
return
|
||||
else:
|
||||
# No slash in argument, just examine an object.
|
||||
obj_searchstr = command.command_argument
|
||||
|
||||
# Resolve the target object.
|
||||
target_obj = source_object.search_for_object(obj_searchstr)
|
||||
# Use search_for_object to handle duplicate/nonexistant results.
|
||||
if not target_obj:
|
||||
return
|
||||
|
||||
# If the user doesn't control the object, just look at it instead.
|
||||
if not source_object.controls_other(target_obj, builder_override=True):
|
||||
command.command_string = 'look'
|
||||
cmd_look(command)
|
||||
return
|
||||
|
||||
if attr_search:
|
||||
# Player did something like: examine me/* or examine me/TE*. Return
|
||||
# each matching attribute with its value.
|
||||
attr_matches = target_obj.attribute_namesearch(attr_searchstr)
|
||||
if attr_matches:
|
||||
for attribute in attr_matches:
|
||||
source_object.emit_to(attribute.get_attrline())
|
||||
else:
|
||||
source_object.emit_to("No matching attributes found.")
|
||||
else:
|
||||
|
||||
# Player is examining an object. Return a full readout of attributes,
|
||||
# along with detailed information about said object.
|
||||
|
||||
string = ""
|
||||
newl = "\r\n"
|
||||
# Format the examine header area with general flag/type info.
|
||||
|
||||
string += str(target_obj.get_name(fullname=True)) + newl
|
||||
string += str("Type: %s Flags: %s" % (target_obj.get_type(),
|
||||
target_obj.get_flags())) + newl
|
||||
string += str("Owner: %s " % target_obj.get_owner()) + newl
|
||||
string += str("Zone: %s" % target_obj.get_zone()) + newl
|
||||
string += str("Parent: %s " % target_obj.get_script_parent()) + newl
|
||||
|
||||
locks = target_obj.get_attribute_value("LOCKS")
|
||||
if locks and "%s" % locks:
|
||||
string += str("Locks: %s" % locks) + newl
|
||||
|
||||
# Contents container lists for sorting by type.
|
||||
con_players = []
|
||||
con_things = []
|
||||
con_exits = []
|
||||
|
||||
# Break each object out into their own list.
|
||||
for obj in target_obj.get_contents():
|
||||
if obj.is_player():
|
||||
con_players.append(obj)
|
||||
elif obj.is_exit():
|
||||
con_exits.append(obj)
|
||||
elif obj.is_thing():
|
||||
con_things.append(obj)
|
||||
|
||||
# Render the object's home or destination (for exits).
|
||||
if not target_obj.is_room():
|
||||
if target_obj.is_exit():
|
||||
# The Home attribute on an exit is really its destination.
|
||||
string += str("Destination: %s" % target_obj.get_home()) + newl
|
||||
else:
|
||||
# For everything else, home is home.
|
||||
string += str("Home: %s" % target_obj.get_home()) + newl
|
||||
# This obviously isn't valid for rooms.
|
||||
string += str("Location: %s" % target_obj.get_location()) + newl
|
||||
|
||||
# Render other attributes
|
||||
for attribute in target_obj.get_all_attributes():
|
||||
string += str(attribute.get_attrline()) + newl
|
||||
|
||||
# Render Contents display.
|
||||
if con_players or con_things:
|
||||
string += str("%sContents:%s" % (ANSITable.ansi["hilite"],
|
||||
ANSITable.ansi["normal"]))
|
||||
for player in con_players:
|
||||
string += str(' %s' % newl + player.get_name(fullname=True))
|
||||
for thing in con_things:
|
||||
string += str(' %s' % newl + thing.get_name(fullname=True))
|
||||
|
||||
# Render Exists display.
|
||||
if con_exits:
|
||||
string += str("%sExits:%s" % (newl + ANSITable.ansi["hilite"],
|
||||
ANSITable.ansi["normal"]))
|
||||
for exit in con_exits:
|
||||
string += str(' %s' % newl + exit.get_name(fullname=True))
|
||||
|
||||
# Send it all
|
||||
source_object.emit_to(string)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("examine", cmd_examine, priv_tuple=("objects.info",))
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
Paging command and support functions.
|
||||
"""
|
||||
from src.objects.models import Object
|
||||
from src import defines_global
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
|
||||
def get_last_paged_objects(source_object):
|
||||
|
|
@ -31,7 +30,14 @@ def get_last_paged_objects(source_object):
|
|||
|
||||
def cmd_page(command):
|
||||
"""
|
||||
Send a message to target user (if online).
|
||||
page - send private message
|
||||
|
||||
Usage:
|
||||
page [<user> = <message>]
|
||||
|
||||
Send a message to target user (if online). If no
|
||||
argument is given, you will instead see who was the last
|
||||
person you paged to.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
# Get the last paged person(s)
|
||||
|
|
@ -127,4 +133,4 @@ def cmd_page(command):
|
|||
# Now set the LASTPAGED attribute
|
||||
source_object.set_attribute("LASTPAGED", ','.join(
|
||||
["#%d" % (x.id) for x in targets]))
|
||||
GLOBAL_CMD_TABLE.add_command("page", cmd_page, priv_tuple=('channels.page',))
|
||||
GLOBAL_CMD_TABLE.add_command("page", cmd_page, priv_tuple=('channels.page',), help_category="Comms")
|
||||
|
|
|
|||
|
|
@ -2,10 +2,14 @@
|
|||
Contains commands for managing script parents.
|
||||
"""
|
||||
from src import scripthandler
|
||||
from src import defines_global
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
|
||||
def cmd_scriptcache(command):
|
||||
"""Usage
|
||||
"""
|
||||
@scriptcache
|
||||
|
||||
Usage
|
||||
@scriptcache
|
||||
|
||||
Shows the contents of the script cache.
|
||||
|
|
@ -20,12 +24,21 @@ def cmd_scriptcache(command):
|
|||
retval += "%d cached parents" % len(cache_dict)
|
||||
command.source_object.emit_to(retval)
|
||||
GLOBAL_CMD_TABLE.add_command("@scriptcache", cmd_scriptcache,
|
||||
priv_tuple=("genperms.builder"),
|
||||
auto_help=True,staff_help=True)
|
||||
priv_tuple=("genperms.builder",), help_category="Admin")
|
||||
|
||||
def cmd_parent(command):
|
||||
"""
|
||||
Sets an object's script parent.
|
||||
@parent - set script parent
|
||||
|
||||
Usage:
|
||||
@parent <object> = <parent>
|
||||
|
||||
Example:
|
||||
@parent button = examples.red_button
|
||||
|
||||
Sets an object's script parent. The parent must be identified
|
||||
by its location using dot-notation pointing to the script
|
||||
parent module.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
||||
|
|
@ -80,5 +93,5 @@ def cmd_parent(command):
|
|||
(target_obj,current_parent))
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@parent", cmd_parent,
|
||||
priv_tuple=("genperms.builder"))
|
||||
priv_tuple=("genperms.builder",), help_category="Building" )
|
||||
|
||||
|
|
|
|||
|
|
@ -3,21 +3,30 @@ This file contains commands that require special permissions to use. These
|
|||
are generally @-prefixed commands, but there are exceptions.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import Permission, Group, User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.auth.models import Permission, Group
|
||||
from django.conf import settings
|
||||
from src.objects.models import Object
|
||||
from src import defines_global
|
||||
from src import ansi
|
||||
from src import session_mgr
|
||||
from src import comsys
|
||||
from src.scripthandler import rebuild_cache
|
||||
from src.util import functions_general
|
||||
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||
from src.helpsys.models import HelpEntry
|
||||
from src.helpsys import helpsystem
|
||||
|
||||
def cmd_reload(command):
|
||||
"""
|
||||
Reloads all modules.
|
||||
@reload - reload game subsystems
|
||||
|
||||
Usage:
|
||||
@reload/switches
|
||||
|
||||
Switches:
|
||||
aliases - alias definitions
|
||||
commands - the command modules
|
||||
scripts, parents - the script parent modules
|
||||
all
|
||||
|
||||
Reloads all the identified subsystems.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
switches = command.command_switches
|
||||
|
|
@ -44,12 +53,17 @@ def cmd_reload(command):
|
|||
comsys.cemit_mudinfo("... all Command modules were reloaded.")
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@reload", cmd_reload,
|
||||
priv_tuple=("genperms.process_control",)),
|
||||
priv_tuple=("genperms.process_control",), help_category="Admin")
|
||||
GLOBAL_CMD_TABLE.add_command("@restart", cmd_reload,
|
||||
priv_tuple=("genperms.process_control",)),
|
||||
priv_tuple=("genperms.process_control",), help_category="Admin")
|
||||
|
||||
def cmd_boot(command):
|
||||
"""
|
||||
@boot
|
||||
|
||||
Usage
|
||||
@boot <player obj>
|
||||
|
||||
Boot a player object from the server.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -119,10 +133,16 @@ def cmd_boot(command):
|
|||
session_mgr.remove_session(boot)
|
||||
return
|
||||
GLOBAL_CMD_TABLE.add_command("@boot", cmd_boot,
|
||||
priv_tuple=("genperms.manage_players",))
|
||||
priv_tuple=("genperms.manage_players",),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_newpassword(command):
|
||||
"""
|
||||
@newpassword
|
||||
|
||||
Usage:
|
||||
@newpassword <user obj> = <new password>
|
||||
|
||||
Set a player's password.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -157,10 +177,16 @@ def cmd_newpassword(command):
|
|||
target_obj.emit_to("%s has changed your password." %
|
||||
(source_object.get_name(show_dbref=False),))
|
||||
GLOBAL_CMD_TABLE.add_command("@newpassword", cmd_newpassword,
|
||||
priv_tuple=("genperms.manage_players",))
|
||||
priv_tuple=("genperms.manage_players",),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_home(command):
|
||||
"""
|
||||
home
|
||||
|
||||
Usage:
|
||||
home
|
||||
|
||||
Teleport the player to their home.
|
||||
"""
|
||||
pobject = command.source_object
|
||||
|
|
@ -174,8 +200,18 @@ GLOBAL_CMD_TABLE.add_command("home", cmd_home,
|
|||
|
||||
def cmd_service(command):
|
||||
"""
|
||||
Service management system. Allows for the listing, starting, and stopping
|
||||
of services.
|
||||
@service - manage services
|
||||
|
||||
Usage:
|
||||
@service[/switch] <service>
|
||||
|
||||
Switches:
|
||||
start - activates a service
|
||||
stop - stops a service
|
||||
list - shows all available services
|
||||
|
||||
Service management system. Allows for the listing,
|
||||
starting, and stopping of services.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
switches = command.command_switches
|
||||
|
|
@ -242,17 +278,25 @@ def cmd_service(command):
|
|||
return
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@service", cmd_service,
|
||||
priv_tuple=("genperms.process_control",))
|
||||
priv_tuple=("genperms.process_control",),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_shutdown(command):
|
||||
"""
|
||||
Shut the server down gracefully.
|
||||
@shutdown
|
||||
|
||||
Usage:
|
||||
@shutdown
|
||||
|
||||
Shut the game server down gracefully.
|
||||
"""
|
||||
command.source_object.emit_to('Shutting down...')
|
||||
print 'Server shutdown by %s' % (command.source_object.get_name(show_dbref=False),)
|
||||
command.session.server.shutdown()
|
||||
GLOBAL_CMD_TABLE.add_command("@shutdown", cmd_shutdown,
|
||||
priv_tuple=("genperms.process_control",))
|
||||
priv_tuple=("genperms.process_control",),
|
||||
help_category="Admin")
|
||||
|
||||
|
||||
# permission administration
|
||||
|
||||
|
|
@ -260,6 +304,7 @@ GLOBAL_CMD_TABLE.add_command("@shutdown", cmd_shutdown,
|
|||
# mess with, but which are not very useful from inside the game. While these
|
||||
# permissions are ok to use, we only show the permissions that we have defined
|
||||
# in our settings file in order to give better control.
|
||||
|
||||
APPS_NOSHOW = ("news","admin","auth","config","contentypes",
|
||||
"flatpages","news","sessions","sites")
|
||||
SETTINGS_PERM_NAMES = []
|
||||
|
|
@ -268,7 +313,9 @@ for apps in settings.PERM_ALL_DEFAULTS + settings.PERM_ALL_CUSTOM:
|
|||
SETTINGS_PERM_NAMES.append(permtuples[1])
|
||||
|
||||
def cmd_setperm(command):
|
||||
"""@setperm
|
||||
"""
|
||||
@setperm - set permissions
|
||||
|
||||
Usage:
|
||||
@setperm[/switch] [<user>] = [<permission>]
|
||||
|
||||
|
|
@ -277,9 +324,9 @@ def cmd_setperm(command):
|
|||
del : delete a permission from <user>
|
||||
list : list all permissions, or those set on <user>
|
||||
|
||||
This command sets/clears individual permission bits on a user.
|
||||
Use /list without any arguments to see all available permissions or those
|
||||
defined on the <user> argument.
|
||||
This command sets/clears individual permission bits on a user.
|
||||
Use /list without any arguments to see all available permissions or those
|
||||
defined on the <user> argument.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
args = command.command_argument
|
||||
|
|
@ -380,17 +427,21 @@ def cmd_setperm(command):
|
|||
obj.emit_to("%s removed your permission '%s'." % (source_object.get_name(show_dbref=False,no_ansi=True),
|
||||
permission.name))
|
||||
GLOBAL_CMD_TABLE.add_command("@setperm", cmd_setperm,
|
||||
priv_tuple=("auth.change_permission","genperms.admin_perm"), auto_help=True, staff_help=True)
|
||||
priv_tuple=("auth.change_permission",
|
||||
"genperms.admin_perm"),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_setgroup(command):
|
||||
"""@setgroup
|
||||
"""
|
||||
@setgroup - manage group memberships
|
||||
|
||||
Usage:
|
||||
@setgroup[/switch] [<user>] [= <group>]
|
||||
|
||||
switches
|
||||
add : add user to a group
|
||||
del : remove user from a group
|
||||
list : list all groups a user is part of, or list all available groups if no user is given
|
||||
Switches:
|
||||
add - add user to a group
|
||||
del - remove user from a group
|
||||
list - list all groups a user is part of, or list all available groups if no user is given
|
||||
|
||||
Changes and views the group membership of a user.
|
||||
"""
|
||||
|
|
@ -410,7 +461,8 @@ def cmd_setgroup(command):
|
|||
for p in g.permissions.all():
|
||||
app = p.content_type.app_label
|
||||
if app not in APPS_NOSHOW:
|
||||
s += "\n --- %s.%s%s\t%s" % (app, p.codename, (35 - len(app) - len(p.codename)) * " ", p.name)
|
||||
s += "\n --- %s.%s%s\t%s" % (app, p.codename,
|
||||
(35 - len(app) - len(p.codename)) * " ", p.name)
|
||||
source_object.emit_to(s)
|
||||
return
|
||||
#we have command arguments.
|
||||
|
|
@ -484,5 +536,155 @@ def cmd_setgroup(command):
|
|||
obj.emit_to("%s removed you from group '%s'." % (source_object.get_name(show_dbref=False,no_ansi=True),
|
||||
group.name))
|
||||
GLOBAL_CMD_TABLE.add_command("@setgroup", cmd_setgroup,
|
||||
priv_tuple=("auth.change_group","genperms.admin_group"), auto_help=True, staff_help=True)
|
||||
priv_tuple=("auth.change_group",
|
||||
"genperms.admin_group"),
|
||||
help_category="Admin")
|
||||
|
||||
def cmd_sethelp(command):
|
||||
"""
|
||||
@sethelp - edit the help database
|
||||
|
||||
Usage:
|
||||
@sethelp[/switches] <topic>[,category][(permissions)][:<text>]
|
||||
|
||||
Switches:
|
||||
add - add or replace a new topic with text.
|
||||
append - add text to the end of topic.
|
||||
delete - remove help topic.
|
||||
force - (used with add) create help topic also if the topic
|
||||
already exists.
|
||||
newl - (used with append) add a newline between the old
|
||||
text and the appended text.
|
||||
|
||||
Examples:
|
||||
@sethelp/add throw : This throws something at ...
|
||||
@sethelp/add throw, General (genperms.throwing) : This throws ...
|
||||
@sethelp/add throw : 1st help entry
|
||||
|
||||
[[@sethelp_markup]]
|
||||
|
||||
@sethelp Help markup
|
||||
|
||||
The <text> entry in @sethelp supports markup to automatically divide the help text into
|
||||
several sub-entries. The beginning of each new entry is marked in the form
|
||||
|
||||
[ [Title, category, (privtuple)] ] (with no spaces between the square brackets)
|
||||
|
||||
In the markup header, Title is mandatory, the other parts are optional. A new
|
||||
help entry named Title will be created for each occurence. It is recommended
|
||||
that the help entries should begin similarly since the system will then identify
|
||||
them and better handle a list of recommended topics.
|
||||
"""
|
||||
|
||||
source_object = command.source_object
|
||||
arg = command.command_argument
|
||||
switches = command.command_switches
|
||||
|
||||
if not arg or not switches:
|
||||
source_object.emit_to("Usage: @sethelp/[add|del|append] <topic>[,category][:<text>]")
|
||||
return
|
||||
|
||||
topicstr = ""
|
||||
category = ""
|
||||
text = ""
|
||||
permtuple = ()
|
||||
|
||||
# analyze the argument
|
||||
arg = arg.split(':', 1)
|
||||
if len(arg) < 2:
|
||||
# no : detected; this means we are deleting something.
|
||||
topicstr = arg[0].strip()
|
||||
else:
|
||||
text = arg[1].strip()
|
||||
# we have 4 possibilities:
|
||||
# topicstr
|
||||
# topicstr, category
|
||||
# topicstr (perm1,perm2,...)
|
||||
# topicstr, category, (perm1,perm2,...)
|
||||
arg = arg[0].split('(',1)
|
||||
if len(arg) > 1:
|
||||
# we have a perm tuple
|
||||
arg, permtuple = arg
|
||||
try:
|
||||
permtuple = permtuple.strip()[:-1] # cut last ')'
|
||||
except IndexError:
|
||||
source_object.emit_to("Malformed permission tuple. %s" % permtuple)
|
||||
return
|
||||
permtuple = tuple(permtuple.split(','))
|
||||
else:
|
||||
# no perm tuple
|
||||
arg = arg[0]
|
||||
arg = arg.split(',', 1)
|
||||
if len(arg) > 1:
|
||||
# we have a category
|
||||
category = arg[1].strip()
|
||||
topicstr = arg[0].strip()
|
||||
|
||||
if 'add' in switches:
|
||||
# add a new help entry.
|
||||
if not topicstr or not text:
|
||||
source_object.emit_to("Usage: @sethelp/add <topic>[,category]:<text>")
|
||||
return
|
||||
force_create = ('for' in switches) or ('force' in switches)
|
||||
topics = helpsystem.edithelp.add_help_manual(source_object, topicstr,
|
||||
category, text,
|
||||
permissions=permtuple,
|
||||
force=force_create)
|
||||
if not topics:
|
||||
return
|
||||
if len(topics) == 1:
|
||||
string = "The topic already exists. Use /force to overwrite it."
|
||||
elif len(topics)>1:
|
||||
string = "The following results are similar to '%s'."
|
||||
string += " Make sure you are not misspelling, then "
|
||||
string += "use the /force flag to create a new entry."
|
||||
string += "\n ".join(topics)
|
||||
source_object.emit_to(string)
|
||||
|
||||
elif 'append' in switches or 'app' in switches:
|
||||
# add text to the end of a help topic
|
||||
if not topicstr or not text:
|
||||
source_object.emit_to("Usage: @sethelp/append <topic>:<text>")
|
||||
return
|
||||
# find the topic to append to
|
||||
topics = HelpEntry.objects.find_topicmatch(source_object, topicstr)
|
||||
if not topics:
|
||||
source_object.emit_to("Help topic '%s' not found." % topicstr)
|
||||
elif len(topics) > 1:
|
||||
string = "Multiple matches to this topic. Refine your search."
|
||||
string += "\n ".join(topics)
|
||||
else:
|
||||
# we have exactly one match. Extract all info from it,
|
||||
# append the text and feed it back into the system.
|
||||
newtext = topics[0].get_entrytext_ingame()
|
||||
category = topics[0].category
|
||||
perm_tuple = topics[0].canview
|
||||
if perm_tuple:
|
||||
perm_tuple = tuple(perm for perm in perm_tuple.split(','))
|
||||
|
||||
newl = "\n"
|
||||
if 'newl' in switches or 'newline' in switches:
|
||||
newl = "\n\n"
|
||||
newtext += "%s%s" % (newl, text)
|
||||
|
||||
topics = helpsystem.edithelp.add_help_manual(source_object,
|
||||
topicstr,
|
||||
category,
|
||||
newtext,
|
||||
perm_tuple,
|
||||
force=True)
|
||||
|
||||
elif 'del' in switches or 'delete' in switches:
|
||||
#delete a help entry
|
||||
topics = helpsystem.edithelp.del_help_manual(source_object, topicstr)
|
||||
if not topics:
|
||||
return
|
||||
else:
|
||||
string = "Multiple matches for '%s'. Please specify:" % topicstr
|
||||
string += "\n ".join(topics)
|
||||
|
||||
GLOBAL_CMD_TABLE.add_command("@sethelp", cmd_sethelp,
|
||||
priv_tuple=("helpsys.add_help",
|
||||
"helpsys.del_help",
|
||||
"helpsys.admin_heelp"),
|
||||
help_category="Admin")
|
||||
|
|
|
|||
|
|
@ -146,6 +146,11 @@ def build_query(source_object, search_query, search_player, search_type,
|
|||
|
||||
def cmd_search(command):
|
||||
"""
|
||||
search
|
||||
|
||||
Usage:
|
||||
search <name>
|
||||
|
||||
Searches for owned objects as per MUX2.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
|
|
@ -232,4 +237,5 @@ def cmd_search(command):
|
|||
|
||||
display_results(source_object, search_query)
|
||||
GLOBAL_CMD_TABLE.add_command("@search", cmd_search,
|
||||
priv_tuple=("objects.info")),
|
||||
priv_tuple=("objects.info",),
|
||||
help_category="Building")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Commands that are available from the connect screen.
|
|||
"""
|
||||
import traceback
|
||||
from django.contrib.auth.models import User
|
||||
from src.objects.models import Attribute, Object
|
||||
from src.objects.models import Object
|
||||
from src import defines_global
|
||||
from src.util import functions_general
|
||||
from src.cmdtable import GLOBAL_UNCON_CMD_TABLE
|
||||
|
|
@ -47,7 +47,7 @@ def cmd_connect(command):
|
|||
else:
|
||||
uname = user.username
|
||||
session.login(user)
|
||||
GLOBAL_UNCON_CMD_TABLE.add_command("connect", cmd_connect)
|
||||
GLOBAL_UNCON_CMD_TABLE.add_command("connect", cmd_connect, auto_help_override=False)
|
||||
|
||||
def cmd_create(command):
|
||||
"""
|
||||
|
|
@ -113,7 +113,7 @@ def cmd_create(command):
|
|||
log_errmsg(traceback.format_exc())
|
||||
raise
|
||||
|
||||
GLOBAL_UNCON_CMD_TABLE.add_command("create", cmd_create)
|
||||
GLOBAL_UNCON_CMD_TABLE.add_command("create", cmd_create, auto_help_override=False)
|
||||
|
||||
def cmd_quit(command):
|
||||
"""
|
||||
|
|
@ -124,4 +124,4 @@ def cmd_quit(command):
|
|||
session = command.session
|
||||
session.msg("Good bye! Disconnecting ...")
|
||||
session.handle_close()
|
||||
GLOBAL_UNCON_CMD_TABLE.add_command("quit", cmd_quit)
|
||||
GLOBAL_UNCON_CMD_TABLE.add_command("quit", cmd_quit, auto_help_override=False)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ PERM_CHANNELS = (
|
|||
('page','May page other users.'),)
|
||||
# help system access permissions
|
||||
PERM_HELPSYS = (
|
||||
("admin_help","May admin the help system"),
|
||||
("staff_help", "May see staff help topics."),
|
||||
("add_help", "May add or append to help entries"),
|
||||
("del_help", "May delete help entries"),)
|
||||
|
|
@ -135,31 +136,50 @@ PERM_ALL_CUSTOM = ()
|
|||
|
||||
# A dict defining the groups, on the form {group_name:(perm1,perm2,...),...}
|
||||
PERM_GROUPS = \
|
||||
{"Immortals":('irc.admin_irc_channels','imc2.admin_imc_channels','channels.emit_commchannel',
|
||||
'channels.channel_admin','channels.page','helpsys.staff_help','helpsys.add_help',
|
||||
'helpsys.del_help','objects.teleport','objects.wipe','objects.modify_attributes',
|
||||
'objects.info','objects.create','objects.dig','objects.see_dbref','objects.admin_ownership',
|
||||
'genperms.announce','genperms.admin_perm','genperms.admin_group','genperms.process_control',
|
||||
'genperms.manage_players','genperms.game_info'),
|
||||
"Wizards": ('irc.admin_irc_channels','imc2.admin_imc_channels','channels.emit_commchannel',
|
||||
'channels.channel_admin','channels.page','helpsys.staff_help','helpsys.add_help',
|
||||
'helpsys.del_help','objects.teleport','objects.wipe','objects.see_dbref',
|
||||
'objects.modify_attributes',
|
||||
'objects.info','objects.create','objects.dig','objects.admin_ownership','genperms.announce',
|
||||
'genperms.game_info'),
|
||||
"Builders":('channels.emit_commchannel','channels.page','helpsys.staff_help','helpsys.add_help',
|
||||
'helpsys.del_help','objects.teleport','objects.wipe','objects.see_dbref',
|
||||
'objects.modify_attributes', 'objects.info','objects.create','objects.dig',
|
||||
'genperms.game_info'),
|
||||
"Player Helpers":('channels.emit_commchannel', 'channels.page', 'helpsys.staff_help',
|
||||
'helpsys.add_help','helpsys.del_help'),
|
||||
"Players":('channels.emit_commchannel','channels.page')
|
||||
{"Immortals":('irc.admin_irc_channels', 'imc2.admin_imc_channels', 'channels.emit_commchannel',
|
||||
'channels.channel_admin', 'channels.page', 'helpsys.admin_help',
|
||||
'helpsys.staff_help', 'helpsys.add_help',
|
||||
'helpsys.del_help', 'objects.teleport', 'objects.wipe', 'objects.modify_attributes',
|
||||
'objects.info','objects.create','objects.dig','objects.see_dbref',
|
||||
'objects.admin_ownership', 'genperms.announce', 'genperms.admin_perm',
|
||||
'genperms.admin_group', 'genperms.process_control', 'genperms.manage_players',
|
||||
'genperms.game_info'),
|
||||
"Wizards": ('irc.admin_irc_channels', 'imc2.admin_imc_channels', 'channels.emit_commchannel',
|
||||
'channels.channel_admin', 'channels.page', 'helpsys.admin_help',
|
||||
'helpsys.staff_help', 'helpsys.add_help',
|
||||
'helpsys.del_help', 'objects.teleport', 'objects.wipe', 'objects.see_dbref',
|
||||
'objects.modify_attributes', 'objects.info', 'objects.create', 'objects.dig',
|
||||
'objects.admin_ownership', 'genperms.announce', 'genperms.game_info'),
|
||||
"Builders":('channels.emit_commchannel', 'channels.page', 'helpsys.staff_help',
|
||||
'helpsys.add_help', 'helpsys.del_help',
|
||||
'objects.teleport', 'objects.wipe', 'objects.see_dbref',
|
||||
'objects.modify_attributes', 'objects.info',
|
||||
'objects.create', 'objects.dig', 'genperms.game_info'),
|
||||
"Player Helpers":('channels.emit_commchannel', 'channels.page', 'helpsys.staff_help',
|
||||
'helpsys.add_help', 'helpsys.del_help'),
|
||||
"Players":('channels.emit_commchannel', 'channels.page')
|
||||
}
|
||||
# By defining a default player group, all players may start with some permissions pre-set.
|
||||
PERM_DEFAULT_PLAYER_GROUP = "Players"
|
||||
|
||||
## Help system
|
||||
## Evennia allows automatic help-updating of commands by use of the auto-help system
|
||||
## which use the command's docstrings for documentation, automatically updating it
|
||||
## as commands are reloaded. Auto-help is a powerful way to keep your help database
|
||||
## up-to-date, but it will also overwrite manual changes made
|
||||
## to the help database using other means (@set_help, admin interface etc), so
|
||||
## for a production environment you might want to turn auto-help off. You can
|
||||
## later activate auto-help on a per-command basis (e.g. when developing a new command)
|
||||
## using the auto_help_override argument to add_command().
|
||||
|
||||
# activate the auto-help system
|
||||
HELP_AUTO_ENABLED = True
|
||||
# Add a dynamically calculated 'See also' footer to help entries
|
||||
HELP_SHOW_RELATED = True
|
||||
|
||||
## Channels
|
||||
## Your names of various default comm channels for emitting debug- or informative messages.
|
||||
|
||||
# Your names of various default comm channels for emitting debug- or informative messages.
|
||||
COMMCHAN_MUD_INFO = 'MUDInfo'
|
||||
COMMCHAN_MUD_CONNECTIONS = 'MUDConnections'
|
||||
COMMCHAN_IMC2_INFO = 'MUDInfo'
|
||||
|
|
|
|||
411
src/helpsys/helpsystem.py
Normal file
411
src/helpsys/helpsystem.py
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
"""
|
||||
Support functions for the help system.
|
||||
Allows adding help to the data base from inside the mud as
|
||||
well as creating auto-docs of commands based on their doc strings.
|
||||
The system supports help-markup for multiple help entries as well
|
||||
as a dynamically updating help index.
|
||||
"""
|
||||
import textwrap
|
||||
from django.conf import settings
|
||||
from src.helpsys.models import HelpEntry
|
||||
from src import logger
|
||||
from src import defines_global
|
||||
|
||||
|
||||
class EditHelp(object):
|
||||
"""
|
||||
This sets up an object able to perform normal editing
|
||||
operations on the help database.
|
||||
"""
|
||||
def __init__(self, indent=4, width=70):
|
||||
"""
|
||||
We check if auto-help is active or not and
|
||||
set some formatting options.
|
||||
"""
|
||||
self.indent = indent # indentation of help text
|
||||
self.width = width # width of help text
|
||||
|
||||
def format_help_text(self, help_text):
|
||||
"""
|
||||
This formats the help entry text for proper left-side indentation.
|
||||
|
||||
The first line is adjusted to the proper indentation and the
|
||||
subsequent lines are then adjusted proportionally to the first;
|
||||
so indentation relative this first line remains intact.
|
||||
"""
|
||||
lines = help_text.expandtabs().splitlines()
|
||||
|
||||
# strip empty lines above and below the text
|
||||
while True:
|
||||
if lines and not lines[0].strip():
|
||||
lines.pop(0)
|
||||
else:
|
||||
break
|
||||
while True:
|
||||
if lines and not lines[-1].strip():
|
||||
lines.pop()
|
||||
else:
|
||||
break
|
||||
if not lines:
|
||||
return ""
|
||||
|
||||
# produce a list of the indentations of each line initially
|
||||
indentlist = [len(line) - len(line.lstrip()) for line in lines]
|
||||
|
||||
# use the first line to set the shift
|
||||
lineshift = indentlist[0] - self.indent
|
||||
|
||||
# shift everything to the left
|
||||
indentlist = [max(self.indent, indent-lineshift) for indent in indentlist]
|
||||
trimmed = []
|
||||
for il, line in enumerate(lines):
|
||||
indentstr = " " * indentlist[il]
|
||||
trimmed.append("%s%s" % (indentstr, line.strip()))
|
||||
return "\n".join(trimmed)
|
||||
|
||||
def parse_markup_header(self, subtopic_header):
|
||||
"""
|
||||
The possible markup headers for splitting the help into sections are:
|
||||
[[TopicTitle]]
|
||||
[[TopicTitle,category]]
|
||||
[[TopicTitle(perm1,perm2)]]
|
||||
[[TopicTitle,category(perm1,perm2)]]
|
||||
"""
|
||||
subtitle = ""
|
||||
subcategory = ""
|
||||
subpermissions = ()
|
||||
#identifying the header parts. The header can max have three parts:
|
||||
# topicname, category (perm1,perm2,...)
|
||||
try:
|
||||
# find the permission tuple
|
||||
lindex = subtopic_header.index('(')
|
||||
rindex = subtopic_header.index(')')
|
||||
if lindex < rindex:
|
||||
permtuple = subtopic_header[lindex+1:rindex]
|
||||
subpermissions = tuple([p.strip()
|
||||
for p in permtuple.split(',')])
|
||||
subtopic_header = subtopic_header[:lindex]
|
||||
except ValueError:
|
||||
# no permission tuple found
|
||||
pass
|
||||
# see if we have a name, category pair.
|
||||
try:
|
||||
subtitle, subcategory = subtopic_header.split(',')
|
||||
subtitle, subcategory = subtitle.strip(), subcategory.strip()
|
||||
except ValueError:
|
||||
subtitle = subtopic_header.strip()
|
||||
# we are done, return a tuple with the results
|
||||
return ( subtitle, subcategory, subpermissions )
|
||||
|
||||
def format_help_entry(self, helptopic, category, helptext, permissions=None):
|
||||
"""
|
||||
helptopic (string) - name of the full help entry
|
||||
helptext (string) - the help entry (may contain sections)
|
||||
permissions (tuple) - tuple with permission/group names
|
||||
defined for the entire help entry.
|
||||
(markup permissions override those)
|
||||
Handles help markup in order to split help into subsections.
|
||||
|
||||
These markup markers will be assumed to start a new line, regardless
|
||||
of where they are located in the help entry. If no permission string
|
||||
tuple and/or category is given, the overall permission/category of
|
||||
the entire help entry is used.
|
||||
"""
|
||||
# sanitize input
|
||||
topics = []
|
||||
if '[[' not in helptext:
|
||||
formatted_text = self.format_help_text(helptext)
|
||||
topics.append((helptopic, category,
|
||||
formatted_text, permissions))
|
||||
return topics
|
||||
|
||||
subtopics = helptext.split('[[')
|
||||
|
||||
if subtopics[0]:
|
||||
# the very first entry (before any markup) is the normal
|
||||
# help entry for the helptopic at hand.
|
||||
formatted_text = self.format_help_text(subtopics[0])
|
||||
topics.append((helptopic, category, formatted_text, permissions))
|
||||
|
||||
for subtopic in subtopics[1:]:
|
||||
# handle all extra topics designated with markup
|
||||
try:
|
||||
subtopic_header, subtopic_text = subtopic.split(']]', 1)
|
||||
except ValueError:
|
||||
# if we have no ending, the entry is malformed and
|
||||
# we ignore this entry (better than overwriting
|
||||
# something in the database).
|
||||
logger.log_errmsg("Malformed help markup in %s: '%s'\n (missing end ']]' )" % \
|
||||
(helptopic, subtopic))
|
||||
continue
|
||||
# parse and format the help entry parts
|
||||
subtopic_header = self.parse_markup_header(subtopic_header)
|
||||
if not subtopic_header[0]:
|
||||
# we require a topic title.
|
||||
logger.log_errmsg("Malformed help markup in '%s': Missing title." % subtopic_header)
|
||||
return
|
||||
# parse the header and use defaults
|
||||
subtopic_name = subtopic_header[0]
|
||||
subtopic_category = subtopic_header[1]
|
||||
subtopic_text = self.format_help_text(subtopic_text)
|
||||
subtopic_permissions = subtopic_header[2]
|
||||
if not subtopic_category:
|
||||
# no category set; inherit from main topic
|
||||
subtopic_category = category
|
||||
if not subtopic_permissions:
|
||||
# no permissions set; inherit from main topic
|
||||
subtopic_permissions = permissions
|
||||
|
||||
# We have a finished topic, add it to the list as a topic tuple.
|
||||
topics.append((subtopic_name, subtopic_category,
|
||||
subtopic_text, subtopic_permissions))
|
||||
return topics
|
||||
|
||||
def create_help(self, newtopic):
|
||||
"""
|
||||
Add a help entry to the database, replace an old one if it exists.
|
||||
topic (tuple) - this is a formatted tuple of data as prepared
|
||||
by format_help_entry, on the form (title, category, text, (perm_tuple))
|
||||
"""
|
||||
#sanity checks;
|
||||
topicname = newtopic[0]
|
||||
category = newtopic[1]
|
||||
entrytext = newtopic[2]
|
||||
permissions = newtopic[3]
|
||||
|
||||
if not (topicname or entrytext):
|
||||
# don't create anything if there we
|
||||
# are missing vital parts
|
||||
return
|
||||
if not category:
|
||||
# this will force the default
|
||||
category = "General"
|
||||
if permissions:
|
||||
# the permissions tuple might be mangled;
|
||||
# make sure we build a string properly.
|
||||
if type(permissions) != type(tuple()):
|
||||
permissions = "%s" % permissions
|
||||
else:
|
||||
permissions = ", ".join(permissions)
|
||||
else:
|
||||
permissions = ""
|
||||
|
||||
# check if the help topic already exist.
|
||||
oldtopic = HelpEntry.objects.filter(topicname__iexact=newtopic[0])
|
||||
if oldtopic:
|
||||
#replace an old help file
|
||||
topic = oldtopic[0]
|
||||
topic.category = category
|
||||
topic.entrytext = entrytext
|
||||
topic.canview = permissions
|
||||
topic.save()
|
||||
else:
|
||||
#we have a new topic - create a new help object
|
||||
new_entry = HelpEntry(topicname=topicname,
|
||||
category=category,
|
||||
entrytext=entrytext,
|
||||
canview=permissions)
|
||||
new_entry.save()
|
||||
|
||||
def add_help_auto(self, topicstr, category, entrytext, permissions=()):
|
||||
"""
|
||||
This is used by the auto_help system to add help one or more
|
||||
help entries to the system.
|
||||
"""
|
||||
# sanity checks
|
||||
if permissions and type(permissions) != type(tuple()):
|
||||
string = "Auto-Help: malformed perm_tuple %s: %s -> %s (fixed)" % \
|
||||
(topicstr,permissions, (permissions,))
|
||||
logger.log_errmsg(string)
|
||||
permissions = (permissions,)
|
||||
|
||||
# identify markup and do nice formatting as well as eventual
|
||||
# related entries to the help entries.
|
||||
logger.log_infomsg("auto-help in: %s %s %s %s" % (topicstr, category, entrytext, permissions))
|
||||
topics = self.format_help_entry(topicstr, category,
|
||||
entrytext, permissions)
|
||||
logger.log_infomsg("auto-help: %s -> %s" % (topicstr,topics))
|
||||
# create the help entries:
|
||||
if topics:
|
||||
for topic in topics:
|
||||
self.create_help(topic)
|
||||
|
||||
def add_help_manual(self, pobject, topicstr, category,
|
||||
entrytext, permissions=(), force=False):
|
||||
"""
|
||||
This is used when a player wants to add a help entry to the database
|
||||
manually (most often from inside the game)
|
||||
|
||||
force - this is given by the player and forces an overwrite also if the
|
||||
entry already exists or there are multiple similar matches to
|
||||
the entry.
|
||||
"""
|
||||
# permission check:
|
||||
if not (pobject.is_superuser() or pobject.has_perm("helpsys.add_help")):
|
||||
pobject.emit_to(defines_global.NOPERMS_MSG)
|
||||
return None
|
||||
# do a more fuzzy search to warn in case in case we are misspelling.
|
||||
topic = HelpEntry.objects.find_topicmatch(pobject, topicstr)
|
||||
if topic and not force:
|
||||
return topic
|
||||
self.add_help_auto(topicstr, category, entrytext, permissions)
|
||||
pobject.emit_to("Added/appended help topic '%s'." % topicstr)
|
||||
|
||||
def del_help_auto(self, topicstr):
|
||||
"""
|
||||
Delete a help entry from the data base. Automatic version.
|
||||
"""
|
||||
topic = HelpEntry.objects.filter(topicname__iexact=topicstr)
|
||||
if topic:
|
||||
topic[0].delete()
|
||||
|
||||
def del_help_manual(self, pobject, topicstr):
|
||||
"""
|
||||
Deletes an entry from the database. Interactive version.
|
||||
Note that it makes no sense to delete auto-added help entries this way since
|
||||
they will be re-added on the next @reload. This is mostly useful for cleaning
|
||||
the database from doublet or orphaned entries, or when auto-help is turned off.
|
||||
"""
|
||||
# find topic with permission checks
|
||||
if not (pobject.is_superuser() or pobject.has_perm("helpsys.del_help")):
|
||||
pobject.emit_to(defines_global.NOPERMS_MSG)
|
||||
return None
|
||||
topic = HelpEntry.objects.find_topicmatch(pobject, topicstr)
|
||||
if not topic or len(topic) > 1:
|
||||
return topic
|
||||
# we have an exact match. Delete topic.
|
||||
topic[0].delete()
|
||||
pobject.emit_to("Help entry '%s' deleted." % topicstr)
|
||||
|
||||
def homogenize_database(self, category):
|
||||
"""
|
||||
This sets the entire help database to one category.
|
||||
It can be used to mark an initially loaded help database
|
||||
in a particular category, for later filtering.
|
||||
|
||||
In evennia dev version, this is done with MUX help database.
|
||||
"""
|
||||
entries = HelpEntry.objects.all()
|
||||
for entry in entries:
|
||||
entry.category = category
|
||||
entry.save()
|
||||
logger.log_infomsg("Help database homogenized to category %s" % category)
|
||||
|
||||
def autoclean_database(self, topiclist):
|
||||
"""
|
||||
This syncs the entire help database against a reference topic
|
||||
list, deleting non-used or duplicate help entries that can be
|
||||
the result of auto-help misspellings etc.
|
||||
"""
|
||||
pass
|
||||
|
||||
class ViewHelp(object):
|
||||
"""
|
||||
This class contains ways to view the
|
||||
help database in a dynamical fashion.
|
||||
"""
|
||||
def __init__(self, indent=4, width=78, category_cols=4, entry_cols=6):
|
||||
"""
|
||||
indent (int) - number of spaces to indent tables with
|
||||
width (int) - width of index tables
|
||||
category_cols (int) - number of collumns per row for
|
||||
category tables
|
||||
entry_cols (int) - number of collumns per row for help entries
|
||||
"""
|
||||
self.width = width
|
||||
self.indent = indent
|
||||
self.category_cols = category_cols
|
||||
self.entry_cols = entry_cols
|
||||
self.show_related = settings.HELP_SHOW_RELATED
|
||||
|
||||
def make_table(self, items, cols):
|
||||
"""
|
||||
This takes a list of string items and displays them in collumn order,
|
||||
(sorted horizontally-first), ie
|
||||
A A A A
|
||||
A B B B
|
||||
B B C C
|
||||
C C
|
||||
cols is the number of collumns to format.
|
||||
"""
|
||||
items.sort()
|
||||
if not items or not cols:
|
||||
return []
|
||||
length = len(items)
|
||||
# split the list into sublists of length cols
|
||||
rows = [items[i:i+cols] for i in xrange(0, length, cols)]
|
||||
# build the table
|
||||
string = ""
|
||||
for row in rows:
|
||||
string += self.indent * " " + ", ".join(row) + "\n"
|
||||
return string
|
||||
|
||||
def index_full(self, pobject):
|
||||
"""
|
||||
This lists all available topics in the help index,
|
||||
ordered after category.
|
||||
|
||||
The MUX category is not shown, it is for development
|
||||
reference only.
|
||||
"""
|
||||
entries = HelpEntry.objects.all()
|
||||
|
||||
categories = [e.category for e in entries if e.category != 'MUX']
|
||||
categories = list(set(categories)) # make list unique
|
||||
categories.sort()
|
||||
table = ""
|
||||
for category in categories:
|
||||
topics = [e.topicname.lower() for e in entries.filter(category__iexact=category)
|
||||
if e.can_view(pobject)]
|
||||
|
||||
# pretty-printing the list
|
||||
header = "--- Topics in category %s:" % category
|
||||
nl = self.width - len(header)
|
||||
if not topics:
|
||||
text = self.indent*" " + "[There are no topics relevant to you in this category.]\n\r"
|
||||
else:
|
||||
text = self.make_table(topics, self.entry_cols)
|
||||
table += "\r\n%s%s\n\r\n\r%s" % (header, "-"*nl, text)
|
||||
return table
|
||||
|
||||
def index_categories(self):
|
||||
"""
|
||||
This lists all categories defined in the help index.
|
||||
"""
|
||||
entries = HelpEntry.objects.all()
|
||||
categories = [e.category for e in entries]
|
||||
categories = list(set(categories)) # make list unique
|
||||
return self.make_table(categories, self.category_cols)
|
||||
|
||||
def index_category(self, pobject, category):
|
||||
"""
|
||||
List the help entries within a certain category
|
||||
"""
|
||||
entries = HelpEntry.objects.find_topics_with_category(pobject, category)
|
||||
if not entries:
|
||||
return []
|
||||
# filter out those we can actually view
|
||||
helptopics = [e.topicname.lower() for e in entries if e.can_view(pobject)]
|
||||
if not helptopics:
|
||||
# we don't have permission to view anything in this category
|
||||
return " [There are no topics relevant to you in this category.]\n\r"
|
||||
return self.make_table(helptopics, self.entry_cols)
|
||||
|
||||
def suggest_help(self, pobject, topic):
|
||||
"""
|
||||
This goes through the help database, searching for relatively
|
||||
close matches to this topic. If those are found, they are
|
||||
added as a nice footer to the end of the topic entry.
|
||||
"""
|
||||
if not self.show_related:
|
||||
return None
|
||||
topicname = topic.topicname
|
||||
return HelpEntry.objects.find_topicsuggestions(pobject, topicname)
|
||||
|
||||
# Object instances
|
||||
edithelp = EditHelp(indent=3,
|
||||
width=80)
|
||||
viewhelp = ViewHelp(indent=3,
|
||||
width=80,
|
||||
category_cols=4,
|
||||
entry_cols=4)
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
"""
|
||||
Support commands for a more advanced help system.
|
||||
Allows adding help to the data base from inside the mud as
|
||||
well as creating auto-docs of commands based on their doc strings.
|
||||
The system supports help-markup for multiple help entries as well
|
||||
as a dynamically updating help index.
|
||||
"""
|
||||
from django.contrib.auth.models import User
|
||||
from src.helpsys.models import HelpEntry
|
||||
from src.ansi import ANSITable
|
||||
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
|
||||
def _privileged_help_search(topicstr):
|
||||
"""
|
||||
searches the topic data base without needing to know who calls it. Needed
|
||||
for autohelp functionality. Will show all help entries, also those set to staff
|
||||
only.
|
||||
"""
|
||||
if topicstr.isdigit():
|
||||
t_query = HelpEntry.objects.filter(id=topicstr)
|
||||
else:
|
||||
exact_match = HelpEntry.objects.filter(topicname__iexact=topicstr)
|
||||
if exact_match:
|
||||
t_query = exact_match
|
||||
else:
|
||||
t_query = HelpEntry.objects.filter(topicname__istartswith=topicstr)
|
||||
return t_query
|
||||
|
||||
|
||||
def _create_help(topicstr, entrytext, staff_only=False, force_create=False,
|
||||
pobject=None, noauth=False):
|
||||
"""
|
||||
Add a help entry to the database, replace an old one if it exists.
|
||||
|
||||
Note - noauth=True will bypass permission checks, so do not use this from
|
||||
inside mud, it is needed by the autohelp system only.
|
||||
"""
|
||||
|
||||
if noauth:
|
||||
#do not check permissions (for autohelp)
|
||||
topic = _privileged_help_search(topicstr)
|
||||
elif pobject:
|
||||
#checks access rights before searching (this should have been
|
||||
#done already at the command level)
|
||||
if not pobject.has_perm("helpsys.add_help"): return []
|
||||
topic = HelpEntry.objects.find_topicmatch(pobject, topicstr)
|
||||
else:
|
||||
return []
|
||||
|
||||
if len(topic) == 1:
|
||||
#replace an old help file
|
||||
topic = topic[0]
|
||||
topic.entrytext = entrytext
|
||||
topic.staff_only = staff_only
|
||||
topic.save()
|
||||
return [topic]
|
||||
elif len(topic) > 1 and not force_create:
|
||||
#a partial match, return it for inspection.
|
||||
return topic
|
||||
else:
|
||||
#we have a new topic - create a new help object
|
||||
new_entry = HelpEntry(topicname=topicstr,
|
||||
entrytext=entrytext,
|
||||
staff_only=staff_only)
|
||||
new_entry.save()
|
||||
return [new_entry]
|
||||
|
||||
def handle_help_markup(topicstr, entrytext, staff_only, identifier="<<TOPIC:"):
|
||||
"""
|
||||
Handle help markup in order to split help into subsections.
|
||||
Handles markup of the form <<TOPIC:STAFF:TopicTitle>> and
|
||||
<<TOPIC:ALL:TopicTitle>> to override the staff_only flag on a per-subtopic
|
||||
basis.
|
||||
"""
|
||||
topic_list = entrytext.split(identifier)
|
||||
topic_dict = {}
|
||||
staff_dict = {}
|
||||
for txt in topic_list:
|
||||
txt = txt.rstrip()
|
||||
if txt.count('>>'):
|
||||
topic, text = txt.split('>>',1)
|
||||
text = text.rstrip()
|
||||
topic = topic.lower()
|
||||
|
||||
if topic in topic_dict.keys():
|
||||
#do not allow multiple topics of the same name
|
||||
return {}, []
|
||||
if 'all:' in topic:
|
||||
topic = topic[4:]
|
||||
staff_dict[topic] = False
|
||||
elif 'staff:' in topic:
|
||||
topic = topic[6:]
|
||||
staff_dict[topic] = True
|
||||
else:
|
||||
staff_dict[topic] = staff_only
|
||||
topic_dict[topic] = text
|
||||
else:
|
||||
#no markup, just add the entry as-is
|
||||
topic = topicstr.lower()
|
||||
topic_dict[topic] = txt
|
||||
staff_dict[topic] = staff_only
|
||||
return topic_dict, staff_dict
|
||||
|
||||
def format_footer(top, text, topic_dict, staff_dict):
|
||||
"""
|
||||
Formats the subtopic with a 'Related Topics:' footer. If mixed
|
||||
staff-only flags are set, those help entries without the staff-only flag
|
||||
will not see staff-only help files recommended in the footer. This allows
|
||||
to separate out the staff-only help switches etc into a separate
|
||||
help file so as not to confuse normal players.
|
||||
"""
|
||||
if text:
|
||||
#only include non-staff related footers to non-staff commands
|
||||
if staff_dict[top]:
|
||||
other_topics = other_topics = filter(lambda o: o != top, topic_dict.keys())
|
||||
else:
|
||||
other_topics = other_topics = filter(lambda o: o != top and not staff_dict[o],
|
||||
topic_dict.keys())
|
||||
if other_topics:
|
||||
footer = ANSITable.ansi['normal'] + "\n\r\n\r Related Topics: "
|
||||
for t in other_topics:
|
||||
footer += t + ', '
|
||||
footer = footer[:-2] + '.'
|
||||
return text + footer
|
||||
else:
|
||||
return text
|
||||
else:
|
||||
return False
|
||||
|
||||
#
|
||||
# Access functions
|
||||
#
|
||||
|
||||
def add_help(topicstr, entrytext, staff_only=False, force_create=False,
|
||||
pobject=None, auto_help=False):
|
||||
"""
|
||||
Add a help topic to the database. This is also usable by autohelp, with auto=True.
|
||||
|
||||
Allows <<TOPIC:TopicTitle>> markup in the help text, to automatically spawn
|
||||
subtopics. For creating mixed staff/ordinary subtopics, the <<TOPIC:STAFF:TopicTitle>> and
|
||||
<<TOPIC:ALL:TopicTitle>> commands can override the overall staff_only setting for
|
||||
that entry only.
|
||||
"""
|
||||
identifier = '<<TOPIC:'
|
||||
if identifier in entrytext:
|
||||
#There is markup in the entry, so we should split the doc into separate subtopics
|
||||
topic_dict, staff_dict = handle_help_markup(topicstr, entrytext,
|
||||
staff_only, identifier)
|
||||
topics = []
|
||||
for topic, text in topic_dict.items():
|
||||
|
||||
#format with nice footer
|
||||
entry = format_footer(topic, text, topic_dict, staff_dict)
|
||||
|
||||
if entry:
|
||||
#create the subtopic
|
||||
newtopic = _create_help(topic, entry,staff_only=staff_dict[topic],
|
||||
force_create=force_create,pobject=pobject,noauth=auto_help)
|
||||
topics.extend(newtopic)
|
||||
return topics
|
||||
|
||||
elif entrytext:
|
||||
#if there were no topic sections, just create the help entry as normal
|
||||
return _create_help(topicstr.lower(),entrytext,staff_only=staff_only,
|
||||
force_create=force_create,pobject=pobject,noauth=auto_help)
|
||||
|
||||
def del_help(pobject,topicstr):
|
||||
"""
|
||||
Delete a help entry from the data base.
|
||||
|
||||
Note that it makes no sense to delete auto-added help entries this way since
|
||||
they will just be re-added on the next @reload. Delete such entries by turning
|
||||
off their auto-help functionality first.
|
||||
"""
|
||||
#find topic with permission checks
|
||||
if not pobject.is_staff(): return []
|
||||
topic = HelpEntry.objects.find_topicmatch(pobject, topicstr)
|
||||
if topic:
|
||||
if len(topic) == 1:
|
||||
#delete topic
|
||||
topic.delete()
|
||||
return True
|
||||
else:
|
||||
return topic
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_help_index(pobject,filter=None):
|
||||
"""
|
||||
Dynamically builds a help index depending on who asks for it, so
|
||||
normal players won't see staff-only help files, for example.
|
||||
|
||||
The filter parameter allows staff to limit their view of the help index
|
||||
no filter (default) - view all help files, staff and non-staff
|
||||
filter='staff' - view only staff-specific help files
|
||||
filter='player' - view only those files visible to all
|
||||
"""
|
||||
|
||||
if pobject.has_perm("helpsys.staff_help"):
|
||||
if filter == 'staff':
|
||||
helpentries = HelpEntry.objects.filter(staff_only=True).order_by('topicname')
|
||||
elif filter == 'player':
|
||||
helpentries = HelpEntry.objects.filter(staff_only=False).order_by('topicname')
|
||||
else:
|
||||
helpentries = HelpEntry.objects.all().order_by('topicname')
|
||||
else:
|
||||
helpentries = HelpEntry.objects.filter(staff_only=False).order_by('topicname')
|
||||
|
||||
if not helpentries:
|
||||
pobject.emit_to("No help entries found.")
|
||||
return
|
||||
|
||||
topics = [entry.topicname for entry in helpentries]
|
||||
#format help entries into suitable alphabetized collumns.
|
||||
percollumn = 8
|
||||
s = ""
|
||||
i = 0
|
||||
while True:
|
||||
i += 1
|
||||
try:
|
||||
top = topics.pop(0)
|
||||
s+= " %s " % top
|
||||
if i%percollumn == 0: s += '\n\r'
|
||||
except IndexError:
|
||||
break
|
||||
s += " (%i entries)" % (i-1)
|
||||
pobject.emit_to(s)
|
||||
|
|
@ -4,35 +4,56 @@ Custom manager for HelpEntry objects.
|
|||
from django.db import models
|
||||
|
||||
class HelpEntryManager(models.Manager):
|
||||
def find_topicmatch(self, pobject, topicstr):
|
||||
"""
|
||||
This implements different ways to search for help entries.
|
||||
"""
|
||||
def find_topicmatch(self, pobject, topicstr, exact=False):
|
||||
"""
|
||||
Searches for matching topics based on player's input.
|
||||
"""
|
||||
is_staff = pobject.is_staff()
|
||||
|
||||
"""
|
||||
if topicstr.isdigit():
|
||||
t_query = self.filter(id=topicstr)
|
||||
else:
|
||||
exact_match = self.filter(topicname__iexact=topicstr)
|
||||
if exact_match:
|
||||
t_query = exact_match
|
||||
else:
|
||||
t_query = self.filter(topicname__istartswith=topicstr)
|
||||
|
||||
if not is_staff:
|
||||
return t_query.exclude(staff_only=1)
|
||||
|
||||
return self.filter(id=topicstr)
|
||||
t_query = self.filter(topicname__iexact=topicstr)
|
||||
if not t_query and not exact:
|
||||
t_query = self.filter(topicname__istartswith=topicstr)
|
||||
# check permissions
|
||||
t_query = [topic for topic in t_query if topic.can_view(pobject)]
|
||||
return t_query
|
||||
|
||||
def find_topicsuggestions(self, pobject, topicstr):
|
||||
"""
|
||||
Do a fuzzier "contains" match.
|
||||
"""
|
||||
is_staff = pobject.is_staff()
|
||||
t_query = self.filter(topicname__icontains=topicstr)
|
||||
|
||||
if not is_staff:
|
||||
return t_query.exclude(staff_only=1)
|
||||
|
||||
return t_query
|
||||
Do a fuzzy match, preferably within the category of the
|
||||
current topic.
|
||||
"""
|
||||
basetopic = self.filter(topicname__iexact=topicstr)
|
||||
if not basetopic:
|
||||
# this topic does not exist; just reply partial
|
||||
# matches to the string
|
||||
topics = self.filter(topicname__icontains=topicstr)
|
||||
return [topic for topic in topics if topic.can_view(pobject)]
|
||||
|
||||
# we know that the topic exists, try to find similar ones within
|
||||
# its category.
|
||||
basetopic = basetopic[0]
|
||||
category = basetopic.category
|
||||
topics = []
|
||||
|
||||
#remove the @
|
||||
crop = topicstr.lstrip('@')
|
||||
|
||||
# first we filter for matches with the full name
|
||||
topics = self.filter(category__iexact=category).filter(topicname__icontains=crop)
|
||||
if len(crop) > 4:
|
||||
# next search with a cropped version of the command.
|
||||
ttemp = self.filter(category__iexact=category).filter(topicname__icontains=crop[:4])
|
||||
ttemp = [topic for topic in ttemp if topic not in topics]
|
||||
topics = list(topics) + list(ttemp)
|
||||
# we need to clean away the given help entry.
|
||||
return [topic for topic in topics if topic.topicname.lower() != topicstr.lower()]
|
||||
|
||||
def find_topics_with_category(self, pobject, category):
|
||||
"""
|
||||
Search topics having a particular category
|
||||
"""
|
||||
t_query = self.filter(category__iexact=category)
|
||||
return [topic for topic in t_query if topic.can_view(pobject)]
|
||||
|
|
|
|||
|
|
@ -11,12 +11,21 @@ class HelpEntry(models.Model):
|
|||
A generic help entry.
|
||||
"""
|
||||
topicname = models.CharField(max_length=255, unique=True)
|
||||
entrytext = models.TextField(blank=True, null=True)
|
||||
staff_only = models.BooleanField(default=False)
|
||||
category = models.CharField(max_length=255, default="General")
|
||||
canview = models.CharField(max_length=255, blank=True)
|
||||
entrytext = models.TextField(blank=True)
|
||||
|
||||
#deprecated, only here to allow MUX helpfile load.
|
||||
staff_only = models.BooleanField(default=False)
|
||||
|
||||
objects = HelpEntryManager()
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Permissions here defines access to modifying help
|
||||
entries etc, not which entries can be viewed (that
|
||||
is controlled by the canview field).
|
||||
"""
|
||||
verbose_name_plural = "Help entries"
|
||||
ordering = ['topicname']
|
||||
permissions = settings.PERM_HELPSYS
|
||||
|
|
@ -29,7 +38,24 @@ class HelpEntry(models.Model):
|
|||
Returns the topic's name.
|
||||
"""
|
||||
return self.topicname
|
||||
|
||||
def get_category(self):
|
||||
"""
|
||||
Returns the category of this help entry.
|
||||
"""
|
||||
return self.category
|
||||
|
||||
def can_view(self, pobject):
|
||||
"""
|
||||
Check if the pobject has the necessary permission/group
|
||||
to view this help entry.
|
||||
"""
|
||||
perm = self.canview.split(',')
|
||||
if not perm or (len(perm) == 1 and not perm[0]) or \
|
||||
pobject.has_perm("helpsys.admin_help"):
|
||||
return True
|
||||
return pobject.has_perm_list(perm)
|
||||
|
||||
def get_entrytext_ingame(self):
|
||||
"""
|
||||
Gets the entry text for in-game viewing.
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ from django.conf import settings
|
|||
from src.objects.models import Object
|
||||
from src.config.models import ConfigValue, CommandAlias, ConnectScreen
|
||||
from src import comsys, defines_global, logger
|
||||
from src.helpsys import helpsystem
|
||||
|
||||
def get_god_user():
|
||||
"""
|
||||
Returns the initially created 'god' User object.
|
||||
|
|
@ -131,6 +133,16 @@ def import_help_files():
|
|||
"""
|
||||
management.call_command('loaddata', 'docs/help_files.json', verbosity=0)
|
||||
|
||||
def categorize_initial_helpdb():
|
||||
"""
|
||||
This makes sure that the initially loaded
|
||||
database is separated into its own
|
||||
help category.
|
||||
"""
|
||||
default_category = "MUX"
|
||||
print " Moving initial imported help db to help category '%s'." % default_category
|
||||
helpsystem.edithelp.homogenize_database(default_category)
|
||||
|
||||
def handle_setup():
|
||||
"""
|
||||
Main logic for the module.
|
||||
|
|
@ -142,3 +154,4 @@ def handle_setup():
|
|||
create_groups()
|
||||
create_channels()
|
||||
import_help_files()
|
||||
categorize_initial_helpdb()
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ This is where all of the crucial, core object models reside.
|
|||
import re
|
||||
import traceback
|
||||
|
||||
try: import cPickle as pickle
|
||||
except ImportError: import pickle
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except ImportError:
|
||||
import pickle
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.contrib.auth.models import User
|
||||
from django.conf import settings
|
||||
from src.objects.util import object as util_object
|
||||
from src.objects.managers.object import ObjectManager
|
||||
|
|
@ -24,8 +26,6 @@ from src import logger
|
|||
import src.flags
|
||||
from src.util import functions_general
|
||||
|
||||
from src.logger import log_infomsg
|
||||
|
||||
class Attribute(models.Model):
|
||||
"""
|
||||
Attributes are things that are specific to different types of objects. For
|
||||
|
|
@ -46,9 +46,9 @@ class Attribute(models.Model):
|
|||
def __str__(self):
|
||||
return "%s(%s)" % (self.attr_name, self.id)
|
||||
|
||||
"""
|
||||
BEGIN COMMON METHODS
|
||||
"""
|
||||
#
|
||||
# BEGIN COMMON METHODS
|
||||
#
|
||||
def get_name(self):
|
||||
"""
|
||||
Returns an attribute's name.
|
||||
|
|
@ -74,7 +74,8 @@ class Attribute(models.Model):
|
|||
"""
|
||||
Returns True if the attribute is hidden.
|
||||
"""
|
||||
if self.attr_hidden or self.get_name().upper() in defines_global.HIDDEN_ATTRIBS:
|
||||
if self.attr_hidden or self.get_name().upper() \
|
||||
in defines_global.HIDDEN_ATTRIBS:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
|
@ -83,7 +84,8 @@ class Attribute(models.Model):
|
|||
"""
|
||||
Returns True if the attribute is unsettable.
|
||||
"""
|
||||
if self.get_name().upper() in defines_global.NOSET_ATTRIBS: return True
|
||||
if self.get_name().upper() in defines_global.NOSET_ATTRIBS:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
|
@ -103,21 +105,28 @@ class Object(models.Model):
|
|||
ROOM, or other entities within the database. Pretty much anything in the
|
||||
game is an object. Objects may be one of several different types, and
|
||||
may be parented to allow for differing behaviors.
|
||||
|
||||
We eventually want to find some way to implement object parents via loadable
|
||||
modules or sub-classing.
|
||||
"""
|
||||
name = models.CharField(max_length=255)
|
||||
ansi_name = models.CharField(max_length=255)
|
||||
owner = models.ForeignKey('self', related_name="obj_owner", blank=True, null=True)
|
||||
zone = models.ForeignKey('self', related_name="obj_zone", blank=True, null=True)
|
||||
script_parent = models.CharField(max_length=255, blank=True, null=True)
|
||||
home = models.ForeignKey('self', related_name="obj_home", blank=True, null=True)
|
||||
owner = models.ForeignKey('self',
|
||||
related_name="obj_owner",
|
||||
blank=True, null=True)
|
||||
zone = models.ForeignKey('self',
|
||||
related_name="obj_zone",
|
||||
blank=True, null=True)
|
||||
script_parent = models.CharField(max_length=255,
|
||||
blank=True, null=True)
|
||||
home = models.ForeignKey('self',
|
||||
related_name="obj_home",
|
||||
blank=True, null=True)
|
||||
type = models.SmallIntegerField(choices=defines_global.OBJECT_TYPES)
|
||||
location = models.ForeignKey('self', related_name="obj_location", blank=True, null=True)
|
||||
location = models.ForeignKey('self',
|
||||
related_name="obj_location",
|
||||
blank=True, null=True)
|
||||
flags = models.TextField(blank=True, null=True)
|
||||
nosave_flags = models.TextField(blank=True, null=True)
|
||||
date_created = models.DateField(editable=False, auto_now_add=True)
|
||||
date_created = models.DateField(editable=False,
|
||||
auto_now_add=True)
|
||||
|
||||
# 'scriptlink' is a 'get' property for retrieving a reference to the correct
|
||||
# script object. Defined down by get_scriptlink()
|
||||
|
|
@ -125,10 +134,15 @@ class Object(models.Model):
|
|||
|
||||
objects = ObjectManager()
|
||||
|
||||
#state system can set a particular command table to be used (not persistent).
|
||||
# state system can set a particular command
|
||||
# table to be used (not persistent).
|
||||
state = None
|
||||
|
||||
class Meta:
|
||||
"""
|
||||
Define permission types on the object class and
|
||||
how it is ordered in the database.
|
||||
"""
|
||||
ordering = ['-date_created', 'id']
|
||||
permissions = settings.PERM_OBJECTS
|
||||
|
||||
|
|
@ -147,13 +161,17 @@ class Object(models.Model):
|
|||
"""
|
||||
return "#%s" % str(self.id)
|
||||
|
||||
"""
|
||||
BEGIN COMMON METHODS
|
||||
"""
|
||||
def search_for_object(self, ostring, emit_to_obj=None, search_contents=True,
|
||||
search_location=True, dbref_only=False,
|
||||
limit_types=False, search_aliases=False,
|
||||
attribute_name=None):
|
||||
#
|
||||
# BEGIN COMMON METHODS
|
||||
#
|
||||
def search_for_object(self, ostring,
|
||||
emit_to_obj=None,
|
||||
search_contents=True,
|
||||
search_location=True,
|
||||
dbref_only=False,
|
||||
limit_types=False,
|
||||
search_aliases=False,
|
||||
attribute_name=None):
|
||||
"""
|
||||
Perform a standard object search, handling multiple
|
||||
results and lack thereof gracefully.
|
||||
|
|
@ -187,13 +205,15 @@ class Object(models.Model):
|
|||
attribute_name=attribute_name)
|
||||
|
||||
if len(results) > 1:
|
||||
s = "More than one match for '%s' (please narrow target):" % ostring
|
||||
string = "More than one match for '%s' (please narrow target):" % ostring
|
||||
for num, result in enumerate(results):
|
||||
invtext = ""
|
||||
if result.get_location() == self:
|
||||
invtext = " (carried)"
|
||||
s += "\n %i-%s%s" % (num+1, result.get_name(show_dbref=False),invtext)
|
||||
emit_to_obj.emit_to(s)
|
||||
string += "\n %i-%s%s" % (num+1,
|
||||
result.get_name(show_dbref=False),
|
||||
invtext)
|
||||
emit_to_obj.emit_to(string)
|
||||
return False
|
||||
elif len(results) == 0:
|
||||
emit_to_obj.emit_to("I don't see that here.")
|
||||
|
|
@ -224,13 +244,18 @@ class Object(models.Model):
|
|||
for session in sessions:
|
||||
session.msg(parse_ansi(message))
|
||||
|
||||
def execute_cmd(self, command_str, session=None):
|
||||
def execute_cmd(self, command_str, session=None, ignore_state=False):
|
||||
"""
|
||||
Do something as this object.
|
||||
|
||||
bypass_state - ignore the fact that a player is in a state
|
||||
(means the normal command table will be used
|
||||
no matter what)
|
||||
"""
|
||||
# The Command object has all of the methods for parsing and preparing
|
||||
# for searching and execution. Send it to the handler once populated.
|
||||
cmdhandler.handle(cmdhandler.Command(self, command_str, session=session))
|
||||
cmdhandler.handle(cmdhandler.Command(self, command_str, session=session),
|
||||
ignore_state=ignore_state)
|
||||
|
||||
def emit_to_contents(self, message, exclude=None):
|
||||
"""
|
||||
|
|
@ -384,7 +409,8 @@ class Object(models.Model):
|
|||
|
||||
# When builder_override is enabled, a builder permission means
|
||||
# the object controls the other.
|
||||
if builder_override and not other_obj.is_player() and self.has_group('Builders'):
|
||||
if builder_override and not other_obj.is_player() \
|
||||
and self.has_group('Builders'):
|
||||
return True
|
||||
|
||||
# They've failed to meet any of the above conditions.
|
||||
|
|
@ -466,7 +492,8 @@ class Object(models.Model):
|
|||
uobj.is_active = False
|
||||
uobj.save()
|
||||
except:
|
||||
functions_general.log_errmsg('Destroying object %s but no matching player.' % (self,))
|
||||
string = 'Destroying object %s but no matching player.' % (self,)
|
||||
functions_general.log_errmsg(string)
|
||||
|
||||
# Set the object type to GOING
|
||||
self.type = defines_global.OTYPE_GOING
|
||||
|
|
@ -511,7 +538,7 @@ class Object(models.Model):
|
|||
"""
|
||||
# Gather up everything, other than exits and going/garbage, that is under
|
||||
# the belief this is its location.
|
||||
objs = self.obj_location.filter(type__in=[1,2,3])
|
||||
objs = self.obj_location.filter(type__in=[1, 2, 3])
|
||||
default_home_id = ConfigValue.objects.get_configvalue('default_home')
|
||||
try:
|
||||
default_home = Object.objects.get(id=default_home_id)
|
||||
|
|
@ -644,7 +671,8 @@ class Object(models.Model):
|
|||
"""
|
||||
Returns a QuerySet of an object's attributes.
|
||||
"""
|
||||
return [attr for attr in self.attribute_set.all() if not attr.is_hidden()]
|
||||
return [attr for attr in self.attribute_set.all()
|
||||
if not attr.is_hidden()]
|
||||
|
||||
|
||||
def clear_all_attributes(self):
|
||||
|
|
@ -684,9 +712,11 @@ class Object(models.Model):
|
|||
re.IGNORECASE)
|
||||
# If the regular expression search returns a match object, add to results.
|
||||
if exclude_noset:
|
||||
return [attr for attr in attrs if match_exp.search(attr.get_name()) and not attr.is_hidden() and not attr.is_noset()]
|
||||
return [attr for attr in attrs if match_exp.search(attr.get_name())
|
||||
and not attr.is_hidden() and not attr.is_noset()]
|
||||
else:
|
||||
return [attr for attr in attrs if match_exp.search(attr.get_name()) and not attr.is_hidden()]
|
||||
return [attr for attr in attrs if match_exp.search(attr.get_name())
|
||||
and not attr.is_hidden()]
|
||||
|
||||
|
||||
def has_flag(self, flag):
|
||||
|
|
@ -751,7 +781,10 @@ class Object(models.Model):
|
|||
self.save()
|
||||
|
||||
def unset_flag(self, flag):
|
||||
self.set_flag(flag,value=False)
|
||||
"""
|
||||
Clear the flag.
|
||||
"""
|
||||
self.set_flag(flag, value=False)
|
||||
|
||||
def get_flags(self):
|
||||
"""
|
||||
|
|
@ -815,7 +848,8 @@ class Object(models.Model):
|
|||
try:
|
||||
return self.location
|
||||
except:
|
||||
functions_general.log_errmsg("Object '%s(#%d)' has invalid location: #%s" % (self.name,self.id,self.location_id))
|
||||
functions_general.log_errmsg("Object '%s(#%d)' has invalid location: #%s" % \
|
||||
(self.name,self.id,self.location_id))
|
||||
return False
|
||||
|
||||
def get_scriptlink(self):
|
||||
|
|
@ -827,7 +861,7 @@ class Object(models.Model):
|
|||
|
||||
# Load the script reference into the object's attribute.
|
||||
self.scriptlink_cached = scripthandler.scriptlink(self,
|
||||
script_to_load)
|
||||
script_to_load)
|
||||
if self.scriptlink_cached:
|
||||
# If the scriptlink variable can't be populated, this will fail
|
||||
# silently and let the exception hit in the scripthandler.
|
||||
|
|
@ -857,7 +891,8 @@ class Object(models.Model):
|
|||
script_parent: (string) String pythonic import path of the script parent
|
||||
assuming the python path is game/gamesrc/parents.
|
||||
"""
|
||||
if script_parent != None and scripthandler.scriptlink(self, str(script_parent).strip()):
|
||||
if script_parent != None and scripthandler.scriptlink(self,
|
||||
str(script_parent).strip()):
|
||||
#assigning a custom parent
|
||||
self.script_parent = str(script_parent).strip()
|
||||
self.save()
|
||||
|
|
@ -1046,7 +1081,10 @@ class Object(models.Model):
|
|||
|
||||
#state access functions
|
||||
|
||||
def get_state(self):
|
||||
def get_state(self):
|
||||
"""
|
||||
Returns the player's current state.
|
||||
"""
|
||||
return self.state
|
||||
|
||||
def set_state(self, state_name=None):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import time
|
|||
from django.contrib.auth.models import User
|
||||
from src.config.models import ConfigValue
|
||||
from src import logger
|
||||
from src.util import functions_general
|
||||
|
||||
# Our list of connected sessions.
|
||||
session_list = []
|
||||
|
|
|
|||
|
|
@ -1,32 +1,43 @@
|
|||
"""
|
||||
The state system allows the player to enter states/modes where only a special set of commands
|
||||
are available. This can be used for all sorts of useful things:
|
||||
- in-game menus (picking an option from a list, much more powerful than using 'rooms')
|
||||
- inline text editors (entering text into a buffer)
|
||||
- npc conversation (select replies)
|
||||
- only allowing certain commands in special situations (e.g. special attack commands
|
||||
when in 'combat' mode)
|
||||
- adding special commands to the normal set (e.g. a 'howl' command when in 'werewolf' state)
|
||||
- deactivating certain commands (e.g. removing the 'say' command in said 'werewolf' state ...)
|
||||
State table
|
||||
|
||||
Basically the GLOBAL_STATE_TABLE contains a dict with command tables keyed after the
|
||||
name of the state. To use, a function must set the 'state' variable on a player object
|
||||
using the obj.set_state() function. The GLOBAL_STATE_TABLE will then be searched by the
|
||||
command handler and if the state is defined its command table is used instead
|
||||
The state system allows the player to enter states/modes where only a
|
||||
special set of commands are available. This can be used for all sorts
|
||||
of useful things: - in-game menus (picking an option from a list, much
|
||||
more powerful than using 'rooms') - inline text editors (entering text
|
||||
into a buffer) - npc conversation (select replies) - only allowing
|
||||
certain commands in special situations (e.g. special attack commands
|
||||
when in 'combat' mode) - adding special commands to the normal set
|
||||
(e.g. a 'howl' command when in 'werewolf' state) - deactivating
|
||||
certain commands (e.g. removing the 'say' command in said 'werewolf'
|
||||
state ...)
|
||||
|
||||
Basically the GLOBAL_STATE_TABLE contains a dict with command tables
|
||||
keyed after the name of the state. To use, a function must set the
|
||||
'state' variable on a player object using the obj.set_state()
|
||||
function. The GLOBAL_STATE_TABLE will then be searched by the command
|
||||
handler and if the state is defined its command table is used instead
|
||||
of the normal global command table.
|
||||
|
||||
The state system is pluggable, in the same way that commands are added to the global command
|
||||
table, commands are added to the GLOBAL_STATE_TABLE using add_command supplying in
|
||||
addition the name of the state. The main difference is that new states must first be created
|
||||
using the GLOBAL_STATE_TABLE.add_state() command. See examples in game/gamesrc.
|
||||
The state system is pluggable, in the same way that commands are added
|
||||
to the global command table, commands are added to the
|
||||
GLOBAL_STATE_TABLE using add_command supplying in addition the name of
|
||||
the state. The main difference is that new states must first be
|
||||
created using the GLOBAL_STATE_TABLE.add_state() command. See examples
|
||||
in game/gamesrc.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from cmdtable import CommandTable, GLOBAL_CMD_TABLE
|
||||
from logger import log_errmsg
|
||||
import src.helpsys.management.commands.edit_helpfiles as edit_help
|
||||
from src import defines_global
|
||||
from src.helpsys import helpsystem
|
||||
from src.helpsys.models import HelpEntry
|
||||
|
||||
class StateTable(object):
|
||||
|
||||
"""
|
||||
This implements a variant of the command table handling states.
|
||||
"""
|
||||
state_table = None
|
||||
|
||||
def __init__(self):
|
||||
|
|
@ -35,9 +46,9 @@ class StateTable(object):
|
|||
self.state_flags = {}
|
||||
|
||||
def add_state(self, state_name,
|
||||
global_cmds=None, global_filter=[],
|
||||
global_cmds=None, global_filter=None,
|
||||
allow_exits=False, allow_obj_cmds=False,
|
||||
exit_command=False):
|
||||
help_command=True, exit_command=False):
|
||||
"""
|
||||
Creates a new game state. Each state has its own unique set of commands and
|
||||
can change how the game works.
|
||||
|
|
@ -76,51 +87,58 @@ class StateTable(object):
|
|||
special conditions or clean-up operations before allowing a player
|
||||
to exit (e.g. combat states and text editors), in which case this
|
||||
feature should be turned off and handled by custom exit commands.
|
||||
help_command
|
||||
"""
|
||||
|
||||
state_name = state_name.strip()
|
||||
#create state
|
||||
self.state_table[state_name] = CommandTable()
|
||||
|
||||
if global_cmds != None:
|
||||
if global_cmds == 'all':
|
||||
f = lambda c: True
|
||||
elif global_cmds == 'include':
|
||||
f = lambda c: c in global_filter
|
||||
if not 'help' in global_filter:
|
||||
global_filter.append('help')
|
||||
elif global_cmds == 'exclude':
|
||||
f = lambda c: c not in global_filter
|
||||
else:
|
||||
log_errmsg("ERROR: in statetable, state %s: Unknown global_cmds flag '%s'." %
|
||||
(state_name, global_cmds))
|
||||
return
|
||||
for cmd in filter(f,GLOBAL_CMD_TABLE.ctable.keys()):
|
||||
self.state_table[state_name].ctable[cmd] = \
|
||||
GLOBAL_CMD_TABLE.get_command_tuple(cmd)
|
||||
if exit_command:
|
||||
#if we import global commands, we use the normal help index; thus add
|
||||
#help for @exit to the global index.
|
||||
self.state_table[state_name].add_command("@exit",
|
||||
cmd_state_exit,
|
||||
auto_help=True)
|
||||
else:
|
||||
#when no global cmds are imported, we create a small custom
|
||||
#state-based help index instead
|
||||
self.help_index.add_state(state_name)
|
||||
self.add_command(state_name,'help',cmd_state_help)
|
||||
|
||||
if exit_command:
|
||||
#add the @exit command
|
||||
self.state_table[state_name].add_command("@exit",
|
||||
cmd_state_exit)
|
||||
self.help_index.add_state_help(state_name, "@exit",
|
||||
cmd_state_exit.__doc__)
|
||||
#store special state flags
|
||||
self.state_flags[state_name] = {}
|
||||
self.state_flags[state_name]['globals'] = global_cmds
|
||||
self.state_flags[state_name]['exits'] = allow_exits
|
||||
self.state_flags[state_name]['obj_cmds'] = allow_obj_cmds
|
||||
|
||||
if global_cmds == 'all':
|
||||
# we include all global commands
|
||||
func = lambda c: True
|
||||
elif global_cmds == 'include':
|
||||
# selective global inclusion
|
||||
func = lambda c: c in global_filter
|
||||
if not 'help' in global_filter:
|
||||
global_filter.append('help')
|
||||
elif global_cmds == 'exclude':
|
||||
# selective global exclusion
|
||||
func = lambda c: c not in global_filter
|
||||
else:
|
||||
# no global commands
|
||||
func = lambda c: False
|
||||
|
||||
# add copies of the global command defs to the state's command table.
|
||||
for cmd in filter(func, GLOBAL_CMD_TABLE.ctable.keys()):
|
||||
self.state_table[state_name].ctable[cmd] = \
|
||||
GLOBAL_CMD_TABLE.get_command_tuple(cmd)
|
||||
|
||||
# create a stand-alone state-based help index
|
||||
self.help_index.add_state(state_name)
|
||||
|
||||
# if the auto-help command is not wanted, just make a custom command
|
||||
# overwriting this default 'help' command. Keeps 'info' as a way to have
|
||||
# both a custom help command and state auto-help; replace this too
|
||||
# to completely hide auto-help functionality in the state.
|
||||
self.add_command(state_name, 'help', cmd_state_help)
|
||||
self.add_command(state_name, 'info', cmd_state_help)
|
||||
|
||||
if exit_command:
|
||||
#add the @exit command
|
||||
self.state_table[state_name].add_command("@exit",
|
||||
cmd_state_exit)
|
||||
self.help_index.add_state_help(state_name,
|
||||
"@exit",
|
||||
"General",
|
||||
cmd_state_exit.__doc__)
|
||||
|
||||
def del_state(self, state_name):
|
||||
"""
|
||||
Permanently deletes a state from the state table. Make sure no users are in
|
||||
|
|
@ -147,12 +165,12 @@ class StateTable(object):
|
|||
return
|
||||
try:
|
||||
del self.state_table[state_name].ctable[command_string]
|
||||
err = self.help_index.del_state_help(state_name,command_string)
|
||||
self.help_index.del_state_help(state_name, command_string)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def add_command(self, state_name, command_string, function, priv_tuple=None,
|
||||
extra_vals=None, auto_help=False, staff_help=False):
|
||||
extra_vals=None, help_category="", priv_help_tuple=None):
|
||||
"""
|
||||
Transparently add commands to a specific state.
|
||||
This command is similar to the normal
|
||||
|
|
@ -163,12 +181,12 @@ class StateTable(object):
|
|||
function: (reference) command function object
|
||||
priv_tuple: (tuple) String tuple of permissions required for command.
|
||||
extra_vals: (dict) Dictionary to add to the Command object.
|
||||
auto_help: (bool) Activate the auto_help system. By default this stores the
|
||||
help inside the statetable only (not in the main help database), and so
|
||||
the help entries are only available when the player is actually inside
|
||||
the state. Note that the auto_help system of state-commands do not
|
||||
support <<TOPIC:mytitle>> markup.
|
||||
staff_help: (bool) Help entry is only available for staff players.
|
||||
|
||||
Auto-help functionality: (only used if settings.HELP_AUTO_ENABLED=True)
|
||||
help_category (str): An overall help category where auto-help will place
|
||||
the help entry. If not given, 'General' is assumed.
|
||||
priv_help_tuple (tuple) String tuple of permissions required to view this
|
||||
help entry. If nothing is given, priv_tuple is used.
|
||||
"""
|
||||
|
||||
if state_name not in self.state_table.keys():
|
||||
|
|
@ -177,21 +195,30 @@ class StateTable(object):
|
|||
return
|
||||
|
||||
state_name = state_name.strip()
|
||||
#handle auto-help for the state commands
|
||||
if auto_help:
|
||||
if self.help_index.has_state(state_name):
|
||||
#add the help text to state help index only, don't add
|
||||
#it to the global help index
|
||||
self.help_index.add_state_help(state_name,command_string,
|
||||
function.__doc__,
|
||||
staff_help=staff_help)
|
||||
auto_help = False
|
||||
|
||||
#finally add the new command to the state's command table
|
||||
# handle the creation of an auto-help entry in the
|
||||
# stand-alone help index
|
||||
|
||||
topicstr = command_string
|
||||
if not help_category:
|
||||
help_category = state_name
|
||||
help_category = help_category.capitalize()
|
||||
|
||||
self.help_index.add_state_help(state_name,
|
||||
topicstr,
|
||||
help_category,
|
||||
function.__doc__,
|
||||
priv_help_tuple)
|
||||
|
||||
# finally add the new command to the state's command table
|
||||
|
||||
self.state_table[state_name].add_command(command_string,
|
||||
function, priv_tuple,
|
||||
extra_vals,auto_help=auto_help,
|
||||
staff_help=staff_help)
|
||||
function,
|
||||
priv_tuple,
|
||||
extra_vals,
|
||||
help_category,
|
||||
priv_help_tuple,
|
||||
auto_help_override=False)
|
||||
|
||||
def get_cmd_table(self, state_name):
|
||||
"""
|
||||
|
|
@ -202,150 +229,157 @@ class StateTable(object):
|
|||
else:
|
||||
return None
|
||||
|
||||
def get_state_flags(self, state_name):
|
||||
def get_exec_rights(self, state_name):
|
||||
"""
|
||||
Return the state flags for a particular state.
|
||||
Used by the cmdhandler. Accesses the relevant state flags
|
||||
concerned with execution access for a particular state.
|
||||
"""
|
||||
if self.state_flags.has_key(state_name):
|
||||
return self.state_flags[state_name]['exits'],\
|
||||
self.state_flags[state_name]['obj_cmds']
|
||||
return self.state_flags[state_name]['exits'], \
|
||||
self.state_flags[state_name]['obj_cmds']
|
||||
else:
|
||||
return False, False
|
||||
|
||||
|
||||
return False, False, False
|
||||
|
||||
class StateHelpIndex(object):
|
||||
"""
|
||||
Handles the dynamic state help system.
|
||||
Handles the dynamic state help system. This is
|
||||
a non-db based help system intended for the special
|
||||
commands associated with a state.
|
||||
|
||||
The system gives preference to help matches within
|
||||
the state, but defers to the normal, global help
|
||||
system when it fails to find a help entry match.
|
||||
"""
|
||||
help_index = None
|
||||
def __init__(self):
|
||||
self.help_index = {}
|
||||
self.identifier = '<<TOPIC:'
|
||||
|
||||
def add_state(self,state_name):
|
||||
def add_state(self, state_name):
|
||||
"Create a new state"
|
||||
self.help_index[state_name] = {}
|
||||
|
||||
def has_state(self,state_name):
|
||||
def has_state(self, state_name):
|
||||
"Checks if we have this state"
|
||||
return self.help_index.has_key(state_name)
|
||||
|
||||
def add_state_help(self, state,command,text,staff_help=False):
|
||||
"""Store help for a command under a certain state.
|
||||
Supports <<TOPIC:MyTopic>> and <<TOPIC:STAFF:MyTopic>> markup."""
|
||||
if self.help_index.has_key(state):
|
||||
|
||||
text = text.rstrip()
|
||||
if self.identifier in text:
|
||||
topic_dict, staff_dict = edit_help.handle_help_markup(command, text, staff_help,
|
||||
identifier=self.identifier)
|
||||
for topic, text in topic_dict.items():
|
||||
entry = edit_help.format_footer(topic,text,topic_dict,staff_dict)
|
||||
if entry:
|
||||
self.help_index[state][topic] = (staff_help, entry)
|
||||
else:
|
||||
self.help_index[state][command] = (staff_help, text)
|
||||
|
||||
def del_state_help(self, state, topic):
|
||||
"""Manually delete a help topic from state help system. Note that this is
|
||||
only going to last until the next @reload unless you also turn off auto_help
|
||||
for the relevant topic."""
|
||||
if self.help_index.has_key(state) and self.help_index[state].has_key(topic):
|
||||
del self.help_index[state][topic]
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
def add_state_help(self, state, topicstr, help_category,
|
||||
help_text, priv_help_tuple=()):
|
||||
"""
|
||||
Store help for a command under a certain state.
|
||||
Supports [[Title, category, (priv_tuple)]] markup
|
||||
"""
|
||||
|
||||
def get_state_help(self,caller, state, command):
|
||||
"get help for a particular command within a state"
|
||||
if self.help_index.has_key(state) and self.help_index[state].has_key(command):
|
||||
if not self.help_index.has_key(state):
|
||||
return
|
||||
# produce nicely formatted help entries, taking markup
|
||||
# into account.
|
||||
topics = helpsystem.edithelp.format_help_entry(topicstr,
|
||||
help_category,
|
||||
help_text,
|
||||
priv_help_tuple)
|
||||
# store in state's dict-based database
|
||||
for topic in topics:
|
||||
self.help_index[state][topic[0]] = topic
|
||||
|
||||
def get_state_help(self, caller, state, command):
|
||||
"""
|
||||
Get help for a particular command within a state.
|
||||
"""
|
||||
if self.help_index.has_key(state) and \
|
||||
self.help_index[state].has_key(command):
|
||||
# this is a state help entry.
|
||||
help_tuple = self.help_index[state][command]
|
||||
if caller.is_staff() or not help_tuple[0]:
|
||||
return help_tuple[1]
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
# check permissions
|
||||
if help_tuple and help_tuple[2]:
|
||||
if help_tuple[3] and not caller.has_perm_list(help_tuple[3]):
|
||||
return None
|
||||
return help_tuple[2]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_state_index(self,caller, state):
|
||||
def get_state_index(self, state):
|
||||
"list all help topics for a state"
|
||||
if self.help_index.has_key(state):
|
||||
if caller.is_staff():
|
||||
index = self.help_index[state].keys()
|
||||
else:
|
||||
index = []
|
||||
for key, tup in self.help_index[state].items():
|
||||
if not tup[0]:
|
||||
index.append(key)
|
||||
return sorted(index)
|
||||
else:
|
||||
return None
|
||||
tuples = self.help_index[state].items()
|
||||
items = [tup[0] for tup in tuples]
|
||||
table = helpsystem.viewhelp.make_table(items, 6)
|
||||
return table
|
||||
|
||||
#default commands available for all special states
|
||||
# default commands available for all special states. These
|
||||
# are added to states during the state initialization if
|
||||
# the proper flags are set.
|
||||
|
||||
def cmd_state_exit(command):
|
||||
"""@exit (when in a state)
|
||||
"""
|
||||
@exit - exit from a state
|
||||
|
||||
This command only works when inside certain special game 'states' (like a menu or
|
||||
editor or similar situations).
|
||||
Usage:
|
||||
@exit
|
||||
|
||||
It aborts what you were doing and force-exits back to the normal mode of
|
||||
gameplay. Some states might deactivate the @exit command for various reasons."""
|
||||
This command only works when inside certain special game 'states'
|
||||
(like a menu or editor or similar situations).
|
||||
|
||||
It aborts what you were doing and force-exits back to the normal
|
||||
mode of gameplay. Some states might deactivate the @exit command
|
||||
for various reasons.
|
||||
"""
|
||||
source_object = command.source_object
|
||||
source_object.clear_state()
|
||||
source_object.emit_to("... Exited.")
|
||||
source_object.execute_cmd('look')
|
||||
|
||||
|
||||
## In-state help system. This is NOT tied to the normal help
|
||||
## system and is not stored in the database. It is intended as a quick
|
||||
## reference for users when in the state; if you want a detailed description
|
||||
## of the state itself, you should probably add it to the main help system
|
||||
## so the user can read it at any time.
|
||||
## If you don't want to use the auto-system, turn off auto_help
|
||||
## for all commands in the state. You could then for example make a custom help command
|
||||
## that displays just a short help summary page instead.
|
||||
|
||||
## Note that at this time we are not displaying categories in the state help system;
|
||||
## (although they are stored). Instead the state itself is treated as a
|
||||
## category in itself.
|
||||
|
||||
def cmd_state_help(command):
|
||||
"""
|
||||
help <topic> (while in a special state)
|
||||
help - view help database
|
||||
|
||||
In-state help system. This is NOT tied to the normal help
|
||||
system and is not stored in the database. It is intended as a quick
|
||||
reference for users when in the state; if you want a detailed description
|
||||
of the state itself, you should probably add it to the main help system
|
||||
so the user can read it at any time.
|
||||
If you don't want to use the auto-system, turn off auto_help
|
||||
for all commands in the state. You could then for example make a custom help command
|
||||
that displays just a short help summary page instead.
|
||||
Usage:
|
||||
help <topic>
|
||||
|
||||
Shows the available help on <topic>. Use without a topic
|
||||
to get the index.
|
||||
"""
|
||||
|
||||
source_object = command.source_object
|
||||
state = source_object.get_state()
|
||||
args = command.command_argument
|
||||
switches = command.command_switches
|
||||
|
||||
help_index = GLOBAL_STATE_TABLE.help_index
|
||||
|
||||
state = source_object.get_state()
|
||||
|
||||
if not args:
|
||||
index = help_index.get_state_index(source_object, state)
|
||||
if not index:
|
||||
source_object.emit_to("There is no help available here.")
|
||||
return
|
||||
s = "Help topics for %s:\n\r" % state
|
||||
for i in index:
|
||||
s += " %s\n\r" % i
|
||||
s = s[:-2]
|
||||
source_object.emit_to(s)
|
||||
# first show the normal help index
|
||||
source_object.execute_cmd("help", ignore_state=True)
|
||||
|
||||
text = help_index.get_state_index(state)
|
||||
if text:
|
||||
# Try to list the state-specific help entries after the main list
|
||||
string = "\n%s%s%s\n\r\n\r%s" % ("---", " Help topics for %s: " % \
|
||||
state.capitalize(), "-"*(30-len(state)), text)
|
||||
source_object.emit_to(string)
|
||||
return
|
||||
|
||||
# try to first find a matching state help topic, then defer to global help
|
||||
topicstr = args.strip()
|
||||
helptext = help_index.get_state_help(source_object, state, topicstr)
|
||||
if helptext:
|
||||
source_object.emit_to("\n%s" % helptext)
|
||||
else:
|
||||
args = args.strip()
|
||||
source_object.execute_cmd("help %s" % topicstr, ignore_state=True)
|
||||
|
||||
if 'del' in switches:
|
||||
if not source_object.is_staff():
|
||||
source_object.emit_to("Only staff can delete help topics.")
|
||||
return
|
||||
if help_index.del_state_help(state,args):
|
||||
source_object.emit_to("Topic %s deleted." % args)
|
||||
else:
|
||||
source_object.emit_to("Topic %s not found." % args)
|
||||
return
|
||||
|
||||
help = help_index.get_state_help(source_object, state, args)
|
||||
if help:
|
||||
source_object.emit_to("%s" % help)
|
||||
else:
|
||||
source_object.emit_to("No help available on %s." % args)
|
||||
|
||||
#import this into modules
|
||||
#import this instance into your modules
|
||||
GLOBAL_STATE_TABLE = StateTable()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue