Created a state system. See
http://groups.google.com/group/evennia/browse_thread/thread/66a7ff6cce5303b7 for more detailed description. Created a new folder gamesrc/commands/examples and moved all examples in there. /Griatch
This commit is contained in:
parent
cae925c29b
commit
0efe2c3095
9 changed files with 415 additions and 30 deletions
0
game/gamesrc/commands/examples/__init__.py
Normal file
0
game/gamesrc/commands/examples/__init__.py
Normal file
|
|
@ -4,16 +4,16 @@ in action.
|
||||||
|
|
||||||
You'll need to make sure that this or any new modules you create are added to
|
You'll need to make sure that this or any new modules you create are added to
|
||||||
game/settings.py under CUSTOM_COMMAND_MODULES or CUSTOM_UNLOGGED_COMMAND_MODULES,
|
game/settings.py under CUSTOM_COMMAND_MODULES or CUSTOM_UNLOGGED_COMMAND_MODULES,
|
||||||
which are tuples of module import path strings.
|
which are tuples of module import path strings. See src/config_defaults.py for more details.
|
||||||
See src/config_defaults.py for more details.
|
|
||||||
|
|
||||||
E.g. to add this example command for testing, your entry in game/settings.py would
|
E.g. to add this example command for testing, your entry in game/settings.py would
|
||||||
look like this:
|
look like this:
|
||||||
|
|
||||||
CUSTOM_COMMAND_MODULES = ('game.gamesrc.commands.example',)
|
CUSTOM_COMMAND_MODULES = ('game.gamesrc.commands.examples.example',)
|
||||||
|
|
||||||
(note the extra comma at the end to make this into a Python tuple. It's only
|
(note the extra comma at the end to make this into a Python tuple. It's only
|
||||||
needed if you have only one entry.)
|
needed if you have only one entry.) You need to restart the Evennia server before new
|
||||||
|
files are recognized.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -70,8 +70,6 @@ def cmd_example(command):
|
||||||
# automatically be created for us.
|
# automatically be created for us.
|
||||||
GLOBAL_CMD_TABLE.add_command("example", cmd_example, auto_help=True),
|
GLOBAL_CMD_TABLE.add_command("example", cmd_example, auto_help=True),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#another simple example
|
#another simple example
|
||||||
|
|
||||||
def cmd_emote_smile(command):
|
def cmd_emote_smile(command):
|
||||||
|
|
@ -92,3 +90,7 @@ def cmd_emote_smile(command):
|
||||||
#add to global command table (no auto_help activated)
|
#add to global command table (no auto_help activated)
|
||||||
GLOBAL_CMD_TABLE.add_command('smile', cmd_emote_smile)
|
GLOBAL_CMD_TABLE.add_command('smile', cmd_emote_smile)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
112
game/gamesrc/commands/examples/state_example.py
Normal file
112
game/gamesrc/commands/examples/state_example.py
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
"""
|
||||||
|
Example of using the state system. The Event system allows a player object to be
|
||||||
|
'trapped' in a special environment where different commands are available than normal.
|
||||||
|
This is very useful in order to implement anything from menus to npc-conversational
|
||||||
|
choices and inline text-editors.
|
||||||
|
|
||||||
|
This example uses the State system to create a simple menu.
|
||||||
|
|
||||||
|
To test out this example, add this module to the CUSTOM_COMMAND_MODULES tuple in
|
||||||
|
your game/settings.py as 'game.gamesrc.commands.examples.state_example' (see ./example.py
|
||||||
|
for another example). You need to restart the Evennia server before new files are
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#This is the normal command table, accessible by default
|
||||||
|
from src.cmdtable import GLOBAL_CMD_TABLE
|
||||||
|
|
||||||
|
#The statetable contains sets of cmdtables that is made available
|
||||||
|
#only when we are in a particular state, overriding the GLOBAL_CMD_TABLE
|
||||||
|
from src.statetable import GLOBAL_STATE_TABLE
|
||||||
|
|
||||||
|
#
|
||||||
|
# Implementing a simple 'menu' state
|
||||||
|
#
|
||||||
|
|
||||||
|
#the name of our state, to make sure it's the same everywhere
|
||||||
|
STATENAME = 'menu'
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 'entry' command
|
||||||
|
#
|
||||||
|
def cmd_entermenu(command):
|
||||||
|
"""
|
||||||
|
This is the 'entry' command that takes the player from the normal
|
||||||
|
gameplay mode into the 'menu' state. In order to do this, it
|
||||||
|
must be added to the GLOBAL_CMD_TABLE like any command.
|
||||||
|
"""
|
||||||
|
#get the player object calling the command
|
||||||
|
source_object = command.source_object
|
||||||
|
#this is important: we use the set_state() command
|
||||||
|
#to shift the player into a state named 'menu'.
|
||||||
|
source_object.set_state(STATENAME)
|
||||||
|
#display the menu.
|
||||||
|
print_menu(source_object)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Commands only available while in the 'menu' state. Note that
|
||||||
|
# these have auto_help, so the __doc__ strings of the functions
|
||||||
|
# can be read as help entries when in the menu.
|
||||||
|
#
|
||||||
|
def menu_cmd_option1(command):
|
||||||
|
"""option1
|
||||||
|
This selects the first option.
|
||||||
|
"""
|
||||||
|
source_object = command.source_object
|
||||||
|
print_menu(source_object, 1)
|
||||||
|
def menu_cmd_option2(command):
|
||||||
|
"""option2
|
||||||
|
This selects the second option. Duh.
|
||||||
|
|
||||||
|
<<TOPIC:About>>
|
||||||
|
This is an extra topic to test the auto_help functionality.
|
||||||
|
"""
|
||||||
|
source_object = command.source_object
|
||||||
|
print_menu(source_object, 2)
|
||||||
|
def menu_cmd_clear(command):
|
||||||
|
"""clear
|
||||||
|
Clears the options.
|
||||||
|
"""
|
||||||
|
source_object = command.source_object
|
||||||
|
print_menu(source_object)
|
||||||
|
|
||||||
|
#
|
||||||
|
# helper function
|
||||||
|
#
|
||||||
|
def print_menu(source_obj,choice=None):
|
||||||
|
"""
|
||||||
|
Utility function to print the menu. More interesting things
|
||||||
|
would happen here in a real menu.
|
||||||
|
"""
|
||||||
|
if choice==1:
|
||||||
|
ch = "> option1\n option2"
|
||||||
|
elif choice==2:
|
||||||
|
ch = " option1\n> option2"
|
||||||
|
else:
|
||||||
|
ch = " option1\n option2"
|
||||||
|
|
||||||
|
s ="Menu---------\n%s\n help - get help" % ch
|
||||||
|
source_obj.emit_to(s)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Add the 'entry' command to the normal command table
|
||||||
|
GLOBAL_CMD_TABLE.add_command("entermenu", cmd_entermenu)
|
||||||
|
|
||||||
|
#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, "clear", menu_cmd_clear,auto_help=True)
|
||||||
|
|
@ -8,6 +8,7 @@ from traceback import format_exc
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
import defines_global
|
import defines_global
|
||||||
import cmdtable
|
import cmdtable
|
||||||
|
import statetable
|
||||||
import logger
|
import logger
|
||||||
import comsys
|
import comsys
|
||||||
import alias_mgr
|
import alias_mgr
|
||||||
|
|
@ -318,19 +319,40 @@ def handle(command):
|
||||||
# Not logged in, look through the unlogged-in command table.
|
# Not logged in, look through the unlogged-in command table.
|
||||||
command_table_lookup(command, cmdtable.GLOBAL_UNCON_CMD_TABLE,
|
command_table_lookup(command, cmdtable.GLOBAL_UNCON_CMD_TABLE,
|
||||||
eval_perms=False)
|
eval_perms=False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Match against the 'idle' command.
|
|
||||||
match_idle(command)
|
state_name = command.source_object.get_state()
|
||||||
# See if this is an aliased command.
|
state_cmd_table = statetable.GLOBAL_STATE_TABLE.get_cmd_table(state_name)
|
||||||
match_alias(command)
|
|
||||||
# Check if the user is using a channel command.
|
if state_name and state_cmd_table:
|
||||||
match_channel(command)
|
# we are in a special state.
|
||||||
# See if the user is trying to traverse an exit.
|
|
||||||
match_exits(command)
|
# check idle command.
|
||||||
neighbor_match_found = match_neighbor_ctables(command)
|
match_idle(command)
|
||||||
if not neighbor_match_found:
|
# check for channel commands
|
||||||
# Retrieve the appropriate (if any) command function.
|
prev_command = command.command_string
|
||||||
command_table_lookup(command, cmdtable.GLOBAL_CMD_TABLE)
|
match_channel(command)
|
||||||
|
if prev_command != command.command_string:
|
||||||
|
# a channel command is handled normally also in the state
|
||||||
|
command_table_lookup(command, cmdtable.GLOBAL_CMD_TABLE)
|
||||||
|
else:
|
||||||
|
command_table_lookup(command, state_cmd_table)
|
||||||
|
else:
|
||||||
|
#normal operation
|
||||||
|
|
||||||
|
# Match against the 'idle' command.
|
||||||
|
match_idle(command)
|
||||||
|
# See if this is an aliased command.
|
||||||
|
match_alias(command)
|
||||||
|
# Check if the user is using a channel command.
|
||||||
|
match_channel(command)
|
||||||
|
# See if the user is trying to traverse an exit.
|
||||||
|
match_exits(command)
|
||||||
|
neighbor_match_found = match_neighbor_ctables(command)
|
||||||
|
if not neighbor_match_found:
|
||||||
|
# Retrieve the appropriate (if any) command function.
|
||||||
|
command_table_lookup(command, cmdtable.GLOBAL_CMD_TABLE)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
By this point, we assume that the user has entered a command and not
|
By this point, we assume that the user has entered a command and not
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
"""
|
"""
|
||||||
Command Table Module
|
Command Table Module
|
||||||
---------------------
|
|
||||||
Each command entry consists of a key and a tuple containing a reference to the
|
Each command entry consists of a key and a tuple containing a reference to the
|
||||||
command's function, and a tuple of the permissions to match against. The user
|
command's function, and a tuple of the permissions to match against. The user
|
||||||
only need have one of the permissions in the permissions tuple to gain
|
only need have one of the permissions in the permissions tuple to gain
|
||||||
|
|
@ -19,7 +19,7 @@ from src.helpsys.management.commands.edit_helpfiles import add_help
|
||||||
|
|
||||||
class CommandTable(object):
|
class CommandTable(object):
|
||||||
"""
|
"""
|
||||||
Stores command tables and performs lookups.
|
Stores commands and performs lookups.
|
||||||
"""
|
"""
|
||||||
ctable = None
|
ctable = None
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ class CommandTable(object):
|
||||||
self.ctable = {}
|
self.ctable = {}
|
||||||
|
|
||||||
def add_command(self, command_string, function, priv_tuple=None,
|
def add_command(self, command_string, function, priv_tuple=None,
|
||||||
extra_vals=None, auto_help=False, staff_only=False):
|
extra_vals=None, auto_help=False, staff_help=False, state=None):
|
||||||
"""
|
"""
|
||||||
Adds a command to the command table.
|
Adds a command to the command table.
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ class CommandTable(object):
|
||||||
auto_help (bool): If true, automatically creates/replaces a help topic with the
|
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
|
same name as the command_string, using the functions's __doc__ property
|
||||||
for help text.
|
for help text.
|
||||||
staff_help (bool): Only relevant if help_auto is activated; It True, makes the
|
staff_help (bool): Only relevant if auto_help is activated; If True, makes the
|
||||||
help topic (and all eventual subtopics) only visible to staff.
|
help topic (and all eventual subtopics) only visible to staff.
|
||||||
|
|
||||||
Note: the auto_help system also supports limited markup. If you divide your __doc__
|
Note: the auto_help system also supports limited markup. If you divide your __doc__
|
||||||
|
|
@ -57,7 +57,7 @@ class CommandTable(object):
|
||||||
#add automatic help text from the command's doc string
|
#add automatic help text from the command's doc string
|
||||||
topicstr = command_string
|
topicstr = command_string
|
||||||
entrytext = function.__doc__
|
entrytext = function.__doc__
|
||||||
add_help(topicstr, entrytext, staff_only=staff_only,
|
add_help(topicstr, entrytext, staff_only=staff_help,
|
||||||
force_create=True, auto_help=True)
|
force_create=True, auto_help=True)
|
||||||
|
|
||||||
def get_command_tuple(self, func_name):
|
def get_command_tuple(self, func_name):
|
||||||
|
|
@ -67,6 +67,7 @@ class CommandTable(object):
|
||||||
"""
|
"""
|
||||||
return self.ctable.get(func_name, False)
|
return self.ctable.get(func_name, False)
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Command tables
|
Command tables
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -867,7 +867,7 @@ def cmd_recover(command):
|
||||||
|
|
||||||
|
|
||||||
GLOBAL_CMD_TABLE.add_command("@recover", cmd_recover,
|
GLOBAL_CMD_TABLE.add_command("@recover", cmd_recover,
|
||||||
priv_tuple=("genperms.builder"),auto_help=True,staff_only=True)
|
priv_tuple=("genperms.builder"),auto_help=True,staff_help=True)
|
||||||
|
|
||||||
def cmd_destroy(command):
|
def cmd_destroy(command):
|
||||||
"""
|
"""
|
||||||
|
|
@ -943,4 +943,4 @@ def cmd_destroy(command):
|
||||||
source_object.emit_to("You schedule %s for destruction." % target_obj.get_name())
|
source_object.emit_to("You schedule %s for destruction." % target_obj.get_name())
|
||||||
|
|
||||||
GLOBAL_CMD_TABLE.add_command("@destroy", cmd_destroy,
|
GLOBAL_CMD_TABLE.add_command("@destroy", cmd_destroy,
|
||||||
priv_tuple=("genperms.builder"),auto_help=True,staff_only=True)
|
priv_tuple=("genperms.builder"),auto_help=True,staff_help=True)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ def _create_help(topicstr, entrytext, staff_only=False, force_create=False,
|
||||||
new_entry.save()
|
new_entry.save()
|
||||||
return [new_entry]
|
return [new_entry]
|
||||||
|
|
||||||
def _handle_help_markup(topicstr, entrytext, staff_only, identifier="<<TOPIC:"):
|
def handle_help_markup(topicstr, entrytext, staff_only, identifier="<<TOPIC:"):
|
||||||
"""
|
"""
|
||||||
Handle help markup in order to split help into subsections.
|
Handle help markup in order to split help into subsections.
|
||||||
Handles markup of the form <<TOPIC:STAFF:TopicTitle>> and
|
Handles markup of the form <<TOPIC:STAFF:TopicTitle>> and
|
||||||
|
|
@ -103,7 +103,7 @@ def _handle_help_markup(topicstr, entrytext, staff_only, identifier="<<TOPIC:"):
|
||||||
staff_dict[topic] = staff_only
|
staff_dict[topic] = staff_only
|
||||||
return topic_dict, staff_dict
|
return topic_dict, staff_dict
|
||||||
|
|
||||||
def _format_footer(top, text, topic_dict, staff_dict):
|
def format_footer(top, text, topic_dict, staff_dict):
|
||||||
"""
|
"""
|
||||||
Formats the subtopic with a 'Related Topics:' footer. If mixed
|
Formats the subtopic with a 'Related Topics:' footer. If mixed
|
||||||
staff-only flags are set, those help entries without the staff-only flag
|
staff-only flags are set, those help entries without the staff-only flag
|
||||||
|
|
@ -147,13 +147,13 @@ def add_help(topicstr, entrytext, staff_only=False, force_create=False,
|
||||||
identifier = '<<TOPIC:'
|
identifier = '<<TOPIC:'
|
||||||
if identifier in entrytext:
|
if identifier in entrytext:
|
||||||
#There is markup in the entry, so we should split the doc into separate subtopics
|
#There is markup in the entry, so we should split the doc into separate subtopics
|
||||||
topic_dict, staff_dict = _handle_help_markup(topicstr, entrytext,
|
topic_dict, staff_dict = handle_help_markup(topicstr, entrytext,
|
||||||
staff_only, identifier)
|
staff_only, identifier)
|
||||||
topics = []
|
topics = []
|
||||||
for topic, text in topic_dict.items():
|
for topic, text in topic_dict.items():
|
||||||
|
|
||||||
#format with nice footer
|
#format with nice footer
|
||||||
entry = _format_footer(topic, text, topic_dict, staff_dict)
|
entry = format_footer(topic, text, topic_dict, staff_dict)
|
||||||
|
|
||||||
if entry:
|
if entry:
|
||||||
#create the subtopic
|
#create the subtopic
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,10 @@ class Object(models.Model):
|
||||||
|
|
||||||
objects = ObjectManager()
|
objects = ObjectManager()
|
||||||
|
|
||||||
|
#state system can set a particular command table to be used.
|
||||||
|
state = None
|
||||||
|
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
"""
|
"""
|
||||||
Used to figure out if one object is the same as another.
|
Used to figure out if one object is the same as another.
|
||||||
|
|
@ -981,5 +985,21 @@ class Object(models.Model):
|
||||||
otype = int(self.type)
|
otype = int(self.type)
|
||||||
return defines_global.OBJECT_TYPES[otype][1][0]
|
return defines_global.OBJECT_TYPES[otype][1][0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return self.state
|
||||||
|
|
||||||
|
def set_state(self, cmd_table=None):
|
||||||
|
"""
|
||||||
|
Set the state by defining which cmd_table is currently used.
|
||||||
|
"""
|
||||||
|
if self.is_player():
|
||||||
|
self.state = cmd_table
|
||||||
|
|
||||||
|
def clear_state(self):
|
||||||
|
self.state = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Deferred imports are poopy. This will require some thought to fix.
|
# Deferred imports are poopy. This will require some thought to fix.
|
||||||
from src import cmdhandler
|
from src import cmdhandler
|
||||||
|
|
|
||||||
228
src/statetable.py
Normal file
228
src/statetable.py
Normal file
|
|
@ -0,0 +1,228 @@
|
||||||
|
"""
|
||||||
|
The state system allows the player to enter a state 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)
|
||||||
|
- inline text editors (entering text into a buffer)
|
||||||
|
- npc conversation (select replies)
|
||||||
|
- commands only available while in 'combat mode' etc
|
||||||
|
This allows for more power than using rooms to build 'menus'.
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from cmdtable import CommandTable
|
||||||
|
from logger import log_errmsg
|
||||||
|
import src.helpsys.management.commands.edit_helpfiles as edit_help
|
||||||
|
|
||||||
|
|
||||||
|
class StateTable(object):
|
||||||
|
|
||||||
|
state_table = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.state_table = {}
|
||||||
|
self.help_index = StateHelpIndex()
|
||||||
|
|
||||||
|
def add_command(self, state_name, command_string, function, priv_tuple=None,
|
||||||
|
extra_vals=None, auto_help=False, staff_help=False, help_global=False,
|
||||||
|
exit_command=True):
|
||||||
|
"""
|
||||||
|
Access function; transparently add commands to a specific command table to
|
||||||
|
reprsent a particular state. This command is similar to the normal
|
||||||
|
command_table.add_command() function. See example in gamesrc/commands/examples.
|
||||||
|
|
||||||
|
command_string: (str) command name to run, like look, @list etc
|
||||||
|
function: (reference) command function object
|
||||||
|
state_name: (str) identifier of the state we tie this to.
|
||||||
|
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.
|
||||||
|
help_global: (bool) Also auto_add the help entry to the main help database. Be
|
||||||
|
careful with overwriting same-named help topics if you define special
|
||||||
|
versions of commands inside your state.
|
||||||
|
|
||||||
|
exit_command: (bool) Sets if the default @exit command is added to the state. Only
|
||||||
|
one command needs to include this statement in order to add @exit. This is
|
||||||
|
usually a good idea to make sure the player is not stuck, but you might want
|
||||||
|
to turn this off if you know what you're doing and want to avoid players
|
||||||
|
'escaping' the state (like in a combat state or similar), or when
|
||||||
|
you need to do some special final cleanup or save operations before
|
||||||
|
exiting (like in a text editor).
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not state_name:
|
||||||
|
log_errmsg("Command %s was not given a state. Not added." % command_string)
|
||||||
|
return
|
||||||
|
|
||||||
|
state_name = state_name.strip()
|
||||||
|
if not self.state_table.has_key(state_name):
|
||||||
|
|
||||||
|
#create the state
|
||||||
|
self.state_table[state_name] = CommandTable()
|
||||||
|
#always add a help index even though it might not be used.
|
||||||
|
self.help_index.add_state(state_name)
|
||||||
|
|
||||||
|
if exit_command:
|
||||||
|
#add the @exit command
|
||||||
|
self.state_table[state_name].add_command("@exit",
|
||||||
|
cmd_state_exit,
|
||||||
|
auto_help=True)
|
||||||
|
if auto_help:
|
||||||
|
#add help for @exit command
|
||||||
|
self.help_index.add_state_help(state_name, "@exit",
|
||||||
|
cmd_state_exit.__doc__)
|
||||||
|
|
||||||
|
#handle auto-help for the state
|
||||||
|
if auto_help:
|
||||||
|
|
||||||
|
#make sure the state's help command is in place
|
||||||
|
self.state_table[state_name].add_command('help',cmd_state_help)
|
||||||
|
|
||||||
|
#add the help text
|
||||||
|
helptext = function.__doc__
|
||||||
|
self.help_index.add_state_help(state_name,command_string,
|
||||||
|
helptext,staff_only=staff_help)
|
||||||
|
if not help_global:
|
||||||
|
#if we don't want global help access, we need to
|
||||||
|
#turn off auto_help before adding the command.
|
||||||
|
auto_help = False
|
||||||
|
|
||||||
|
#finally add the new command to the state
|
||||||
|
self.state_table[state_name].add_command(command_string,
|
||||||
|
function, priv_tuple,
|
||||||
|
extra_vals,auto_help,
|
||||||
|
staff_help)
|
||||||
|
|
||||||
|
def get_cmd_table(self, state_name):
|
||||||
|
"""
|
||||||
|
Return the command table for a particular state.
|
||||||
|
"""
|
||||||
|
if self.state_table.has_key(state_name):
|
||||||
|
return self.state_table[state_name]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class StateHelpIndex(object):
|
||||||
|
"""
|
||||||
|
Handles the dynamic state help system.
|
||||||
|
"""
|
||||||
|
help_index = None
|
||||||
|
def __init__(self):
|
||||||
|
self.help_index = {}
|
||||||
|
self.identifier = '<<TOPIC:'
|
||||||
|
|
||||||
|
def add_state(self,state_name):
|
||||||
|
"Create a new state"
|
||||||
|
self.help_index[state_name] = {}
|
||||||
|
|
||||||
|
def add_state_help(self, state,command,text,staff_only=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):
|
||||||
|
|
||||||
|
if self.identifier in text:
|
||||||
|
topic_dict, staff_dict = edit_help.handle_help_markup(command, text, staff_only,
|
||||||
|
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_only, entry)
|
||||||
|
else:
|
||||||
|
self.help_index[state][command] = (staff_only, text)
|
||||||
|
|
||||||
|
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):
|
||||||
|
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
|
||||||
|
|
||||||
|
def get_state_index(self,caller, 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
|
||||||
|
|
||||||
|
#default commands available for all special states
|
||||||
|
|
||||||
|
def cmd_state_exit(command):
|
||||||
|
"""@exit (when in a state)
|
||||||
|
|
||||||
|
This command only works when inside a special game 'state' (like a menu or
|
||||||
|
editor or similar place where you have fewer commands available than normal).
|
||||||
|
|
||||||
|
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.
|
||||||
|
In those cases, read the help when in the state to learn more."""
|
||||||
|
|
||||||
|
source_object = command.source_object
|
||||||
|
source_object.clear_state()
|
||||||
|
source_object.emit_to("... Exited.")
|
||||||
|
source_object.execute_cmd('look')
|
||||||
|
|
||||||
|
def cmd_state_help(command):
|
||||||
|
"""
|
||||||
|
help <topic> (while in a state)
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
source_object = command.source_object
|
||||||
|
state = source_object.get_state()
|
||||||
|
args = command.command_argument
|
||||||
|
help_index = GLOBAL_STATE_TABLE.help_index
|
||||||
|
|
||||||
|
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" % state
|
||||||
|
for i in index:
|
||||||
|
s += " %s\n" % i
|
||||||
|
s = s[:-1]
|
||||||
|
source_object.emit_to(s)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
args = args.strip()
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
GLOBAL_STATE_TABLE = StateTable()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue