This implements a full menu system for Evennia.

To start the menu, just import the EvMenu class from this module. Example usage:

from evennia.utils.evmenu import EvMenu

EvMenu(caller, menu_module_path,
     cmdset_mergetype="Replace", cmdset_priority=1,
     auto_quit=True, cmd_on_exit="look", persistent=True)

Where caller is the Object to use the menu on - it will get a new cmdset while using the Menu. The menu_module_path is the python path to a python module containing function definitions. By adjusting the keyword options of the Menu() initialization call you can start the menu at different places in the menu definition file, adjust if the menu command should overload the normal commands or not, etc.

The persistent keyword will make the menu survive a server reboot. It is False by default. Note that if using persistent mode, every node and callback in the menu must be possible to be pickled, this excludes e.g. callables that are class methods or functions defined dynamically or as part of another function. In non-persistent mode no such restrictions exist.

The menu is defined in a module (this can be the same module as the command definition too) with function definitions:

def node1(caller):
    # (this is the start node if called like above)
    # code
    return text, options

def node_with_other_name(caller, input_string):
    # code
    return text, options

def another_node(caller, input_string, **kwargs):
    # code
    return text, options

Where caller is the object using the menu and input_string is the command entered by the user on the previous node (the command entered to get to this node). The node function code will only be executed once per node-visit and the system will accept nodes with both one or two arguments interchangeably. It also accepts nodes that takes **kwargs.

The menu tree itself is available on the caller as caller.ndb._evmenu. This makes it a convenient place to store temporary state variables between nodes, since this NAttribute is deleted when the menu is exited.

The return values must be given in the above order, but each can be returned as None as well. If the options are returned as None, the menu is immediately exited and the default “look” command is called.

  • text (str, tuple or None): Text shown at this node. If a tuple, the

    second element in the tuple holds either a string or a dict. If a string, this is the help text to show when auto_help is active for the menu and the user presses h. If a dict, this is a mapping of ‘help topic’: ‘help text’ to show in that menu. This can be used to show information without having to switch to another node.

  • options (tuple, dict or None): If None, this exits the menu. If a single dict, this is a single-option node. If a tuple, it should be a tuple of option dictionaries. Option dicts have the following keys:

    • key (str or tuple, optional): What to enter to choose this option. If a tuple, it must be a tuple of strings, where the first string is the key which will be shown to the user and the others are aliases. If unset, the options’ number will be used. The special key _default marks this option as the default fallback when no other option matches the user input. There can only be one _default option per node. It will not be displayed in the list.

    • desc (str, optional): This describes what choosing the option will do.

    • goto (str, tuple or callable): If string, should be the name of node to go to when this option is selected. If a callable, it has the signature callable(caller[,raw_input][,**kwargs]). If a tuple, the first element is the callable and the second is a dict with the **kwargs to pass to the callable. Those kwargs will also be passed into the next node if possible. Such a callable should return either a str or a (str, dict), where the string is the name of the next node to go to and the dict is the new, (possibly modified) kwarg to pass into the next node. If the callable returns None or the empty string, the current node will be revisited.

If key is not given, the option will automatically be identified by its number 1..N.


# in menu_module.py

def node1(caller):
    text = ("This is a node text",
            "This is help text for this node")
    options = ({"key": "testing",
                "desc": "Select this to go to node 2",
                "goto": ("node2", {"foo": "bar"}),
               {"desc": "Go to node 3.",
                "goto": "node3"})
    return text, options

def callback1(caller):
    # this is called when choosing the "testing" option in node1
    # (before going to node2). If it returned a string, say 'node3',
    # then the next node would be node3 instead of node2 as specified
    # by the normal 'goto' option key above.
    caller.msg("Callback called!")

def node2(caller, **kwargs):
    text = '''
        This is node 2. It only allows you to go back
        to the original node1. This extra indent will
        be stripped. We don't include a help text but
        here are the variables passed to us: {}
    options = {"goto": "node1"}
    return text, options

def node3(caller):
    text = "This ends the menu since there are no options."
    return text, None

When starting this menu with Menu(caller, “path.to.menu_module”), the first node will look something like this:

This is a node text

testing: Select this to go to node 2
2: Go to node 3

Where you can both enter “testing” and “1” to select the first option. If the client supports MXP, they may also mouse-click on “testing” to do the same. When making this selection, a function “callback1” in the same Using help will show the help text, otherwise a list of available commands while in menu mode.

The menu tree is exited either by using the in-menu quit command or by reaching a node without any options.

For a menu demo, import CmdTestMenu from this module and add it to your default cmdset. Run it with this module, like testmenu evennia.utils.evmenu.