diff --git a/evennia/contrib/menusystem.py b/evennia/contrib/menusystem.py
index 1b2f17317..61764f172 100644
--- a/evennia/contrib/menusystem.py
+++ b/evennia/contrib/menusystem.py
@@ -3,6 +3,10 @@ Evennia menu system.
Contribution - Griatch 2011
+> Note that the evennia/utils/menu.py module is probably a better and
+more flexible implementation of a menu system than this. Try that
+first.
+
This module offers the ability for admins to let their game be fully
or partly menu-driven. Menu choices can be numbered or use arbitrary
keys. There are also some formatting options, such a putting options
diff --git a/evennia/contrib/bettermenusystem.py b/evennia/utils/evmenu.py
similarity index 81%
rename from evennia/contrib/bettermenusystem.py
rename to evennia/utils/evmenu.py
index dc08d1c9a..c5876a72e 100644
--- a/evennia/contrib/bettermenusystem.py
+++ b/evennia/utils/evmenu.py
@@ -1,48 +1,66 @@
"""
-(Better) MenuSystem
+EvMenu
-Evennia contribution - Griatch 2015
+This implements a full menu system for Evennia. It is considerably
+more flexible than the older contrib/menusystem.py and also uses
+menu plugin modules.
+To start the menu, just import the EvMenu class from this module,
-This implements a better menu system for Evennia. Contrary to the old
-contrib menusystem, this is controlled from a simple module with
-function definitions, rather than building a set of classes with
-arguments.
+```python
-To start the menu, just import the Menu class from this module,
-and call
+ from evennia.utils.evmenu import EvMenu
- from evennia.contrib.bettermenusystem import Menu
-
- Menu(caller, menu_module_path,
- startnode="start", allow_quit=True,
- cmdset_mergetype="Replace", cmdset_priority=1):
+ EvMenu(caller, menu_module_path,
+ startnode="start",
+ cmdset_mergetype="Replace", cmdset_priority=1,
+ allow_quit=True, cmd_on_quit="look")
+```
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 defintions. 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.
+menu command should overload the normal commands or not, etc.
-The menu is defined in a module with function defintions:
+The menu is defined in a module (this can be the same module as the
+command definition too) with function defintions:
+
+```python
def nodename1(caller):
# code
return text, options
-The return values must be given in the above order, but each can be
-given as None as well
+ def nodename2(caller, input_string):
+ # code
+ return text, options
+```
- text (str or tuple): Text shown at this node. If a tuple, the second
+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.
+
+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 is a help text to display at this node when
the user enters the menu help command there.
- helptext (str): Help text shown at this node.
- options (tuple): ( {'key': name, # can also be a list of aliases
- 'desc': description, # option description
- 'goto': nodekey, # node to go to when chosen
- 'exec': nodekey, # node or callback to trigger as callback when chosen
- {...}, ...)
+ options (tuple, dict or None): ( {'key': name, # can also be a list of aliases. A special key is "_default", which
+ # marks this option as the default fallback when no other
+ # option matches the user input.
+ 'desc': description, # option description
+ 'goto': nodekey, # node to go to when chosen
+ 'exec': nodekey, # node or callback to trigger as callback when chosen. If a node
+ # key is given the node will be executed once but its return u
+ # values are ignored. If a callable is given, it must accept
+ # one or two args, like any node.
+ {...}, ...)
If key is not given, the option will automatically be identified by
its number 1..N.
@@ -103,7 +121,9 @@ 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 CmdTestDemo form this
+For a menu demo, import CmdTestDemo from this module and add it to
+your default cmdset. Run it with this module, like `testdemo
+evennia.utils.evdemo`.
"""
@@ -113,7 +133,7 @@ from django.conf import settings
from evennia import syscmdkeys
from evennia import Command, CmdSet
from evennia.utils.evtable import EvTable
-from evennia.utils.ansi import ANSIString
+from evennia.utils.ansi import ANSIString, strip_raw_ansi
from evennia.utils.utils import mod_import, make_iter, pad, m_len
# read from protocol NAWS later?
@@ -124,17 +144,18 @@ _CMD_NOINPUT = syscmdkeys.CMD_NOINPUT
# Return messages
-_ERR_NOT_IMPLEMENTED = "Menu node '{nodename}' is not implemented. Make another choice."
-_ERR_GENERAL = "Error in menu node '{nodename}'."
-_ERR_NO_OPTION_DESC = "No description."
-_HELP_FULL = "Commands: