evennia/docs/6.x/Contribs/Contrib-Building-Menu.html
2026-02-15 19:06:04 +01:00

1476 lines
No EOL
130 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en" data-content_root="../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Building menu &#8212; Evennia latest documentation</title>
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=d75fae25" />
<link rel="stylesheet" type="text/css" href="../_static/nature.css?v=279e0f84" />
<link rel="stylesheet" type="text/css" href="../_static/custom.css?v=e4a91a55" />
<script src="../_static/documentation_options.js?v=c6e86fd7"></script>
<script src="../_static/doctools.js?v=9bcbadda"></script>
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Additional Color markups" href="Contrib-Color-Markups.html" />
<link rel="prev" title="AWSstorage system" href="Contrib-AWSStorage.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Contrib-Color-Markups.html" title="Additional Color markups"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Contrib-AWSStorage.html" title="AWSstorage system"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" accesskey="U">Contribs</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Building menu</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="building-menu">
<h1>Building menu<a class="headerlink" href="#building-menu" title="Link to this heading"></a></h1>
<p>Contrib by vincent-lg, 2018</p>
<p>Building menus are in-game menus, not unlike <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> though using a
different approach. Building menus have been specifically designed to edit
information as a builder. Creating a building menu in a command allows
builders quick-editing of a given object, like a room. If you follow the
steps to add the contrib, you will have access to an <code class="docutils literal notranslate"><span class="pre">edit</span></code> command
that will edit any default object, offering to change its key and description.</p>
<section id="install">
<h2>Install<a class="headerlink" href="#install" title="Link to this heading"></a></h2>
<ol class="arabic">
<li><p>Import the <code class="docutils literal notranslate"><span class="pre">GenericBuildingCmd</span></code> class from this contrib in your
<code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdset.py</span></code> file:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.contrib.base_systems.building_menu</span><span class="w"> </span><span class="kn">import</span> <span class="n">GenericBuildingCmd</span>
</pre></div>
</div>
</li>
<li><p>Below, add the command in the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ... These lines should exist in the file</span>
<span class="k">class</span><span class="w"> </span><span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;DefaultCharacter&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
<span class="c1"># ... add the line below</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">GenericBuildingCmd</span><span class="p">())</span>
</pre></div>
</div>
</li>
</ol>
</section>
<section id="basic-usage">
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Link to this heading"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">edit</span></code> command will allow you to edit any object. You will need to
specify the object name or ID as an argument. For instance: <code class="docutils literal notranslate"><span class="pre">edit</span> <span class="pre">here</span></code>
will edit the current room. However, building menus can perform much more
than this very simple example, read on for more details.</p>
<p>Building menus can be set to edit about anything. Here is an example of
output you could obtain when editing the room:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">Editing</span> <span class="n">the</span> <span class="n">room</span><span class="p">:</span> <span class="n">Limbo</span><span class="p">(</span><span class="c1">#2)</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">the</span> <span class="n">limbo</span> <span class="n">room</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">the</span> <span class="n">limbo</span> <span class="n">room</span><span class="o">.</span> <span class="n">You</span> <span class="n">can</span> <span class="n">easily</span> <span class="n">change</span> <span class="n">this</span> <span class="n">default</span> <span class="n">description</span><span class="p">,</span>
<span class="n">either</span> <span class="n">by</span> <span class="n">using</span> <span class="n">the</span> <span class="o">|</span><span class="n">y</span><span class="nd">@desc</span><span class="o">/</span><span class="n">edit</span><span class="o">|</span><span class="n">n</span> <span class="n">command</span><span class="p">,</span> <span class="ow">or</span> <span class="n">simply</span> <span class="n">by</span> <span class="n">entering</span> <span class="n">this</span>
<span class="n">menu</span> <span class="p">(</span><span class="n">enter</span> <span class="o">|</span><span class="n">yd</span><span class="o">|</span><span class="n">n</span><span class="p">)</span><span class="o">.</span>
<span class="p">[</span><span class="n">E</span><span class="p">]</span><span class="n">xits</span><span class="p">:</span>
<span class="n">north</span> <span class="n">to</span> <span class="n">A</span> <span class="n">parking</span><span class="p">(</span><span class="c1">#4)</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">this</span> <span class="n">menu</span>
</pre></div>
</div>
<p>From there, you can open the title choice by pressing t. You can then
change the room title by simply entering text, and go back to the
main menu entering &#64; (all this is customizable). Press q to quit this menu.</p>
<p>The first thing to do is to create a new module and place a class
inheriting from <code class="docutils literal notranslate"><span class="pre">BuildingMenu</span></code> in it.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">evennia.contrib.base_systems.building_menu</span><span class="w"> </span><span class="kn">import</span> <span class="n">BuildingMenu</span>
<span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>Next, override the <code class="docutils literal notranslate"><span class="pre">init</span></code> method (not <code class="docutils literal notranslate"><span class="pre">__init__</span></code>!). You can add
choices (like the title, description, and exits choices as seen above) by using
the <code class="docutils literal notranslate"><span class="pre">add_choice</span></code> method.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>That will create the first choice, the title choice. If one opens your menu
and enter t, she will be in the title choice. She can change the title
(it will write in the rooms <code class="docutils literal notranslate"><span class="pre">key</span></code> attribute) and then go back to the
main menu using <code class="docutils literal notranslate"><span class="pre">&#64;</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">add_choice</span></code> has a lot of arguments and offers a great deal of
flexibility. The most useful ones is probably the usage of callbacks,
as you can set almost any argument in <code class="docutils literal notranslate"><span class="pre">add_choice</span></code> to be a callback, a
function that you have defined above in your module. This function will be
called when the menu element is triggered.</p>
<p>Notice that in order to edit a description, the best method to call isnt
<code class="docutils literal notranslate"><span class="pre">add_choice</span></code>, but <code class="docutils literal notranslate"><span class="pre">add_choice_edit</span></code>. This is a convenient shortcut
which is available to quickly open an <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code> when entering this choice
and going back to the menu when the editor closes.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;d&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;db.desc&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>When you wish to create a building menu, you just need to import your
class, create it specifying your intended caller and object to edit,
then call <code class="docutils literal notranslate"><span class="pre">open</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="o">&lt;</span><span class="n">wherever</span><span class="o">&gt;</span> <span class="kn">import</span><span class="w"> </span><span class="nn">RoomBuildingMenu</span>
<span class="k">class</span><span class="w"> </span><span class="nc">CmdEdit</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;redit&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">menu</span> <span class="o">=</span> <span class="n">RoomBuildingMenu</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="p">)</span>
<span class="n">menu</span><span class="o">.</span><span class="n">open</span><span class="p">()</span>
</pre></div>
</div>
</section>
<section id="a-simple-menu-example">
<h2>A simple menu example<a class="headerlink" href="#a-simple-menu-example" title="Link to this heading"></a></h2>
<p>Before diving in, there are some things to point out:</p>
<ul class="simple">
<li><p>Building menus work on an object. This object will be edited by manipulations in the menu. So
you can create a menu to add/edit a room, an exit, a character and so on.</p></li>
<li><p>Building menus are arranged in layers of choices. A choice gives access to an option or to a sub-
menu. Choices are linked to commands (usually very short). For instance, in the example shown
below, to edit the room key, after opening the building menu, you can type <code class="docutils literal notranslate"><span class="pre">k</span></code>. That will lead you
to the key choice where you can enter a new key for the room. Then you can enter <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> to leave this
choice and go back to the entire menu. (All of this can be changed).</p></li>
<li><p>To open the menu, you will need something like a command. This contrib offers a basic command for
demonstration, but we will override it in this example, using the same code with more flexibility.</p></li>
</ul>
<p>So lets add a very basic example to begin with.</p>
<section id="a-generic-editing-command">
<h3>A generic editing command<a class="headerlink" href="#a-generic-editing-command" title="Link to this heading"></a></h3>
<p>Lets begin by adding a new command. You could add or edit the following file (theres no trick
here, feel free to organize the code differently):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file: commands/building.py</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia.contrib.building_menu</span><span class="w"> </span><span class="kn">import</span> <span class="n">BuildingMenu</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">commands.command</span><span class="w"> </span><span class="kn">import</span> <span class="n">Command</span>
<span class="k">class</span><span class="w"> </span><span class="nc">EditCmd</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Editing command.</span>
<span class="sd"> Usage:</span>
<span class="sd"> @edit [object]</span>
<span class="sd"> Open a building menu to edit the specified object. This menu allows to</span>
<span class="sd"> specific information about this object.</span>
<span class="sd"> Examples:</span>
<span class="sd"> @edit here</span>
<span class="sd"> @edit self</span>
<span class="sd"> @edit #142</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;@edit&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:id(1) or perm(Builders)&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;Building&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;|rYou should provide an argument to this function: the object to edit.|n&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="n">global_search</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">if</span> <span class="n">obj</span><span class="o">.</span><span class="n">typename</span> <span class="o">==</span> <span class="s2">&quot;Room&quot;</span><span class="p">:</span>
<span class="n">Menu</span> <span class="o">=</span> <span class="n">RoomBuildingMenu</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">obj_name</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;|rThe object </span><span class="si">{</span><span class="n">obj_name</span><span class="si">}</span><span class="s2"> cannot be edited.|n&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">menu</span> <span class="o">=</span> <span class="n">Menu</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
<span class="n">menu</span><span class="o">.</span><span class="n">open</span><span class="p">()</span>
</pre></div>
</div>
<p>This command is rather simple in itself:</p>
<ol class="arabic simple">
<li><p>It has a key <code class="docutils literal notranslate"><span class="pre">&#64;edit</span></code> and a lock to only allow builders to use it.</p></li>
<li><p>In its <code class="docutils literal notranslate"><span class="pre">func</span></code> method, it begins by checking the arguments, returning an error if no argument is
specified.</p></li>
<li><p>It then searches for the given argument. We search globally. The <code class="docutils literal notranslate"><span class="pre">search</span></code> method used in this
way will return the found object or <code class="docutils literal notranslate"><span class="pre">None</span></code>. It will also send the error message to the caller if
necessary.</p></li>
<li><p>Assuming we have found an object, we check the object <code class="docutils literal notranslate"><span class="pre">typename</span></code>. This will be used later when
we want to display several building menus. For the time being, we only handle <code class="docutils literal notranslate"><span class="pre">Room</span></code>. If the
caller specified something else, well display an error.</p></li>
<li><p>Assuming this object is a <code class="docutils literal notranslate"><span class="pre">Room</span></code>, we have defined a <code class="docutils literal notranslate"><span class="pre">Menu</span></code> object containing the class of our
building menu. We build this class (creating an instance), giving it the caller and the object to
edit.</p></li>
<li><p>We then open the building menu, using the <code class="docutils literal notranslate"><span class="pre">open</span></code> method.</p></li>
</ol>
<p>The end might sound a bit surprising at first glance. But the process is still very simple: we
create an instance of our building menu and call its <code class="docutils literal notranslate"><span class="pre">open</span></code> method. Nothing more.</p>
<blockquote>
<div><p>Where is our building menu?</p>
</div></blockquote>
<p>If you go ahead and add this command and test it, youll get an error. We havent defined
<code class="docutils literal notranslate"><span class="pre">RoomBuildingMenu</span></code> yet.</p>
<p>To add this command, edit <code class="docutils literal notranslate"><span class="pre">commands/default_cmdsets.py</span></code>. Import our command, adding an import line
at the top of the file:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">...</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia</span><span class="w"> </span><span class="kn">import</span> <span class="n">default_cmds</span>
<span class="c1"># The following line is to be added</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">commands.building</span><span class="w"> </span><span class="kn">import</span> <span class="n">EditCmd</span>
</pre></div>
</div>
<p>And in the class below (<code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>), add the last line of this code:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The `CharacterCmdSet` contains general in-game commands like `look`,</span>
<span class="sd"> `get`, etc available on in-game Character objects. It is merged with</span>
<span class="sd"> the `AccountCmdSet` when an Account puppets a Character.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;DefaultCharacter&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Populates the cmdset</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
<span class="c1">#</span>
<span class="c1"># any commands you add below will overload the default ones.</span>
<span class="c1">#</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">EditCmd</span><span class="p">())</span>
</pre></div>
</div>
</section>
<section id="our-first-menu">
<h3>Our first menu<a class="headerlink" href="#our-first-menu" title="Link to this heading"></a></h3>
<p>So far, we cant use our building menu. Our <code class="docutils literal notranslate"><span class="pre">&#64;edit</span></code> command will throw an error. We have to define
the <code class="docutils literal notranslate"><span class="pre">RoomBuildingMenu</span></code> class. Open the <code class="docutils literal notranslate"><span class="pre">commands/building.py</span></code> file and add to the end of the file:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ... at the end of commands/building.py</span>
<span class="c1"># Our building menu</span>
<span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> For the time being, we have only one choice: key, to edit the room key.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="s2">&quot;k&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Save these changes, reload your game. You can now use the <code class="docutils literal notranslate"><span class="pre">&#64;edit</span></code> command. Heres what we get
(notice that the commands we enter into the game are prefixed with <code class="docutils literal notranslate"><span class="pre">&gt;</span> </code>, though this prefix will
probably not appear in your MUD client):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt; look
Limbo(#2)
Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need
help, want to contribute, report issues or just join the community.
As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build.
&gt; @edit here
Building menu: Limbo
[K]ey: Limbo
[Q]uit the menu
&gt; q
Closing the building menu.
&gt; @edit here
Building menu: Limbo
[K]ey: Limbo
[Q]uit the menu
&gt; k
-------------------------------------------------------------------------------
key for Limbo(#2)
You can change this value simply by entering it.
Use @ to go back to the main menu.
Current value: Limbo
&gt; A beautiful meadow
-------------------------------------------------------------------------------
key for A beautiful meadow(#2)
You can change this value simply by entering it.
Use @ to go back to the main menu.
Current value: A beautiful meadow
&gt; @
Building menu: A beautiful meadow
[K]ey: A beautiful meadow
[Q]uit the menu
&gt; q
Closing the building menu.
&gt; look
A beautiful meadow(#2)
Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need
help, want to contribute, report issues or just join the community.
As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build.
</pre></div>
</div>
<p>Before diving into the code, lets examine what we have:</p>
<ul class="simple">
<li><p>When we use the <code class="docutils literal notranslate"><span class="pre">&#64;edit</span> <span class="pre">here</span></code> command, a building menu for this room appears.</p></li>
<li><p>This menu has two choices:</p>
<ul>
<li><p>Enter <code class="docutils literal notranslate"><span class="pre">k</span></code> to edit the room key. You will go into a choice where you can simply type the key
room key (the way we have done here). You can use <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> to go back to the menu.</p></li>
<li><p>You can use <code class="docutils literal notranslate"><span class="pre">q</span></code> to quit the menu.</p></li>
</ul>
</li>
</ul>
<p>We then check, with the <code class="docutils literal notranslate"><span class="pre">look</span></code> command, that the menu has modified this room key. So by adding a
class, with a method and a single line of code within, weve added a menu with two choices.</p>
</section>
<section id="code-explanation">
<h3>Code explanation<a class="headerlink" href="#code-explanation" title="Link to this heading"></a></h3>
<p>Lets examine our code again:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> For the time being, we have only one choice: key, to edit the room key.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="s2">&quot;k&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">)</span>
</pre></div>
</div>
<ul class="simple">
<li><p>We first create a class inheriting from <code class="docutils literal notranslate"><span class="pre">BuildingMenu</span></code>. This is usually the case when we want to
create a building menu with this contrib.</p></li>
<li><p>In this class, we override the <code class="docutils literal notranslate"><span class="pre">init</span></code> method, which is called when the menu opens.</p></li>
<li><p>In this <code class="docutils literal notranslate"><span class="pre">init</span></code> method, we call <code class="docutils literal notranslate"><span class="pre">add_choice</span></code>. This takes several arguments, but weve defined only
three here:</p>
<ul>
<li><p>The choice name. This is mandatory and will be used by the building menu to know how to
display this choice.</p></li>
<li><p>The command key to access this choice. Weve given a simple <code class="docutils literal notranslate"><span class="pre">&quot;k&quot;</span></code>. Menu commands usually are
pretty short (thats part of the reason building menus are appreciated by builders). You can also
specify additional aliases, but well see that later.</p></li>
<li><p>Weve added a keyword argument, <code class="docutils literal notranslate"><span class="pre">attr</span></code>. This tells the building menu that when we are in this
choice, the text we enter goes into this attribute name. Its called <code class="docutils literal notranslate"><span class="pre">attr</span></code>, but it could be a room
attribute or a typeclass persistent or non-persistent attribute (well see other examples as well).</p></li>
</ul>
</li>
</ul>
<blockquote>
<div><p>Weve added the menu choice for <code class="docutils literal notranslate"><span class="pre">key</span></code> here, why is another menu choice defined for <code class="docutils literal notranslate"><span class="pre">quit</span></code>?</p>
</div></blockquote>
<p>Our building menu creates a choice at the end of our choice list if its a top-level menu (sub-menus
dont have this feature). You can, however, override it to provide a different “quit” message or to
perform some actions.</p>
<p>I encourage you to play with this code. As simple as it is, it offers some functionalities already.</p>
</section>
</section>
<section id="customizing-building-menus">
<h2>Customizing building menus<a class="headerlink" href="#customizing-building-menus" title="Link to this heading"></a></h2>
<p>This somewhat long section explains how to customize building menus. There are different ways
depending on what you would like to achieve. Well go from specific to more advanced here.</p>
<section id="generic-choices">
<h3>Generic choices<a class="headerlink" href="#generic-choices" title="Link to this heading"></a></h3>
<p>In the previous example, weve used <code class="docutils literal notranslate"><span class="pre">add_choice</span></code>. This is one of three methods you can use to add
choices. The other two are to handle more generic actions:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">add_choice_edit</span></code>: this is called to add a choice which points to the <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code>. It is used to
edit a description in most cases, although you could edit other things. Well see an example
shortly. <code class="docutils literal notranslate"><span class="pre">add_choice_edit</span></code> uses most of the <code class="docutils literal notranslate"><span class="pre">add_choice</span></code> keyword arguments well see, but usually
we specify only two (sometimes three):</p>
<ul>
<li><p>The choice title as usual.</p></li>
<li><p>The choice key (command key) as usual.</p></li>
<li><p>Optionally, the attribute of the object to edit, with the <code class="docutils literal notranslate"><span class="pre">attr</span></code> keyword argument. By
default, <code class="docutils literal notranslate"><span class="pre">attr</span></code> contains <code class="docutils literal notranslate"><span class="pre">db.desc</span></code>. It means that this persistent data attribute will be edited by
the <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code>. You can change that to whatever you want though.</p></li>
</ul>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">add_choice_quit</span></code>: this allows to add a choice to quit the editor. Most advisable! If you dont
do it, the building menu will do it automatically, except if you really tell it not to. Again, you
can specify the title and key of this menu. You can also call a function when this menu closes.</p></li>
</ul>
<p>So heres a more complete example (you can replace your <code class="docutils literal notranslate"><span class="pre">RoomBuildingMenu</span></code> class in
<code class="docutils literal notranslate"><span class="pre">commands/building.py</span></code> to see it):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="s2">&quot;k&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_quit</span><span class="p">(</span><span class="s2">&quot;quit this editor&quot;</span><span class="p">,</span> <span class="s2">&quot;q&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>So far, our building menu class is still thin… and yet we already have some interesting feature.
See for yourself the following MUD client output (again, the commands are prefixed with <code class="docutils literal notranslate"><span class="pre">&gt;</span> </code> to
distinguish them):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt; @reload
&gt; @edit here
Building menu: A beautiful meadow
[K]ey: A beautiful meadow
[D]escription:
Welcome to your new Evennia-based game! Visit https://www.evennia.com if you need
help, want to contribute, report issues or just join the community.
As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build.
[Q]uit this editor
&gt; d
----------Line Editor [editor]----------------------------------------------------
01| Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need
02| help, want to contribute, report issues or just join the community.
03| As Account #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n.
&gt; :DD
----------[l:03 w:034 c:0247]------------(:h for help)----------------------------
Cleared 3 lines from buffer.
&gt; This is a beautiful meadow. But so beautiful I can&#39;t describe it.
01| This is a beautiful meadow. But so beautiful I can&#39;t describe it.
&gt; :wq
Building menu: A beautiful meadow
[K]ey: A beautiful meadow
[D]escription:
This is a beautiful meadow. But so beautiful I can&#39;t describe it.
[Q]uit this editor
&gt; q
Closing the building menu.
&gt; look
A beautiful meadow(#2)
This is a beautiful meadow. But so beautiful I can&#39;t describe it.
</pre></div>
</div>
<p>So by using the <code class="docutils literal notranslate"><span class="pre">d</span></code> shortcut in our building menu, an <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code> opens. You can use the <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code>
commands (like we did here, <code class="docutils literal notranslate"><span class="pre">:DD</span></code> to remove all, <code class="docutils literal notranslate"><span class="pre">:wq</span></code> to save and quit). When you quit the editor,
the description is saved (here, in <code class="docutils literal notranslate"><span class="pre">room.db.desc</span></code>) and you go back to the building menu.</p>
<p>Notice that the choice to quit has changed too, which is due to our adding <code class="docutils literal notranslate"><span class="pre">add_choice_quit</span></code>. In
most cases, you will probably not use this method, since the quit menu is added automatically.</p>
</section>
<section id="add-choice-options">
<h3><code class="docutils literal notranslate"><span class="pre">add_choice</span></code> options<a class="headerlink" href="#add-choice-options" title="Link to this heading"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">add_choice</span></code> and the two methods <code class="docutils literal notranslate"><span class="pre">add_choice_edit</span></code> and <code class="docutils literal notranslate"><span class="pre">add_choice_quit</span></code> take a lot of optional
arguments to make customization easier. Some of these options might not apply to <code class="docutils literal notranslate"><span class="pre">add_choice_edit</span></code>
or <code class="docutils literal notranslate"><span class="pre">add_choice_quit</span></code> however.</p>
<p>Below are the options of <code class="docutils literal notranslate"><span class="pre">add_choice</span></code>, specify them as arguments:</p>
<ul class="simple">
<li><p>The first positional, mandatory argument is the choice title, as we have seen. This will
influence how the choice appears in the menu.</p></li>
<li><p>The second positional, mandatory argument is the command key to access to this menu. It is best
to use keyword arguments for the other arguments.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">aliases</span></code> keyword argument can contain a list of aliases that can be used to access to this
menu. For instance: <code class="docutils literal notranslate"><span class="pre">add_choice(...,</span> <span class="pre">aliases=['t'])</span></code></p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">attr</span></code> keyword argument contains the attribute to edit when this choice is selected. Its a
string, it has to be the name, from the object (specified in the menu constructor) to reach this
attribute. For instance, a <code class="docutils literal notranslate"><span class="pre">attr</span></code> of <code class="docutils literal notranslate"><span class="pre">&quot;key&quot;</span></code> will try to find <code class="docutils literal notranslate"><span class="pre">obj.key</span></code> to read and write the
attribute. You can specify more complex attribute names, for instance, <code class="docutils literal notranslate"><span class="pre">attr=&quot;db.desc&quot;</span></code> to set the
<code class="docutils literal notranslate"><span class="pre">desc</span></code> persistent attribute, or <code class="docutils literal notranslate"><span class="pre">attr=&quot;ndb.something&quot;</span></code> so use a non-persistent data attribute on the
object.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">text</span></code> keyword argument is used to change the text that will be displayed when the menu choice
is selected. Menu choices provide a default text that you can change. Since this is a long text,
its useful to use multi-line strings (see an example below).</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">glance</span></code> keyword argument is used to specify how to display the current information while in
the menu, when the choice hasnt been opened. If you examine the previous examples, you will see
that the current (<code class="docutils literal notranslate"><span class="pre">key</span></code> or <code class="docutils literal notranslate"><span class="pre">db.desc</span></code>) was shown in the menu, next to the command key. This is
useful for seeing at a glance the current value (hence the name). Again, menu choices will provide
a default glance if you dont specify one.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">on_enter</span></code> keyword argument allows to add a callback to use when the menu choice is opened.
This is more advanced, but sometimes useful.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">on_nomatch</span></code> keyword argument is called when, once in the menu, the caller enters some text
that doesnt match any command (including the <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> command). By default, this will edit the
specified <code class="docutils literal notranslate"><span class="pre">attr</span></code>.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">on_leave</span></code> keyword argument allows to specify a callback used when the caller leaves the menu
choice. This can be useful for cleanup as well.</p></li>
</ul>
<p>These are a lot of possibilities, and most of the time you wont need them all. Here is a short
example using some of these arguments (again, replace the <code class="docutils literal notranslate"><span class="pre">RoomBuildingMenu</span></code> class in
<code class="docutils literal notranslate"><span class="pre">commands/building.py</span></code> with the following code to see it working):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> For the time being, we have only one choice: key, to edit the room key.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{obj.key}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> -------------------------------------------------------------------------------</span>
<span class="s2"> Editing the title of {{obj.key}}(#{{obj.id}})</span>
<span class="s2"> You can change the title simply by entering it.</span>
<span class="s2"> Use |y</span><span class="si">{back}</span><span class="s2">|n to go back to the main menu.</span>
<span class="s2"> Current title: |c{{obj.key}}|n</span>
<span class="s2"> &quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">back</span><span class="o">=</span><span class="s2">&quot;|n or |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keys_go_back</span><span class="p">)))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Reload your game and see it in action:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@edit</span> <span class="n">here</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">t</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Editing</span> <span class="n">the</span> <span class="n">title</span> <span class="n">of</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="p">(</span><span class="c1">#2)</span>
<span class="n">You</span> <span class="n">can</span> <span class="n">change</span> <span class="n">the</span> <span class="n">title</span> <span class="n">simply</span> <span class="n">by</span> <span class="n">entering</span> <span class="n">it</span><span class="o">.</span>
<span class="n">Use</span> <span class="o">@</span> <span class="n">to</span> <span class="n">go</span> <span class="n">back</span> <span class="n">to</span> <span class="n">the</span> <span class="n">main</span> <span class="n">menu</span><span class="o">.</span>
<span class="n">Current</span> <span class="n">title</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="o">&gt;</span> <span class="o">@</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">q</span>
<span class="n">Closing</span> <span class="n">the</span> <span class="n">building</span> <span class="n">menu</span><span class="o">.</span>
</pre></div>
</div>
<p>The most surprising part is no doubt the text. We use the multi-line syntax (with <code class="docutils literal notranslate"><span class="pre">&quot;&quot;&quot;</span></code>).
Excessive spaces will be removed from the left for each line automatically. We specify some
information between braces… sometimes using double braces. What might be a bit odd:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">{back}</span></code> is a direct format argument well use (see the <code class="docutils literal notranslate"><span class="pre">.format</span></code> specifiers).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">{{obj...}}</span></code> refers to the object being edited. We use two braces, because <code class="docutils literal notranslate"><span class="pre">.format</span></code> will remove them.</p></li>
</ul>
<p>In <code class="docutils literal notranslate"><span class="pre">glance</span></code>, we also use <code class="docutils literal notranslate"><span class="pre">{obj.key}</span></code> to indicate we want to show the rooms key.</p>
</section>
<section id="everything-can-be-a-function">
<h3>Everything can be a function<a class="headerlink" href="#everything-can-be-a-function" title="Link to this heading"></a></h3>
<p>The keyword arguments of <code class="docutils literal notranslate"><span class="pre">add_choice</span></code> are often strings (type <code class="docutils literal notranslate"><span class="pre">str</span></code>). But each of these arguments
can also be a function. This allows for a lot of customization, since we define the callbacks that
will be executed to achieve such and such an operation.</p>
<p>To demonstrate, we will try to add a new feature. Our building menu for rooms isnt that bad, but
it would be great to be able to edit exits too. So we can add a new menu choice below
description… but how to actually edit exits? Exits are not just an attribute to set: exits are
objects (of type <code class="docutils literal notranslate"><span class="pre">Exit</span></code> by default) which stands between two rooms (object of type <code class="docutils literal notranslate"><span class="pre">Room</span></code>). So how
can we show that?</p>
<p>First lets add a couple of exits in limbo, so we have something to work with:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@tunnel</span> <span class="n">n</span>
<span class="nd">@tunnel</span> <span class="n">s</span>
</pre></div>
</div>
<p>This should create two new rooms, exits leading to them from limbo and back to limbo.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">look</span>
<span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="p">(</span><span class="c1">#2)</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="n">Exits</span><span class="p">:</span> <span class="n">north</span><span class="p">(</span><span class="c1">#4) and south(#7)</span>
</pre></div>
</div>
<p>We can access room exits with the <code class="docutils literal notranslate"><span class="pre">exits</span></code> property:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@py</span> <span class="n">here</span><span class="o">.</span><span class="n">exits</span>
<span class="p">[</span><span class="o">&lt;</span><span class="n">Exit</span><span class="p">:</span> <span class="n">north</span><span class="o">&gt;</span><span class="p">,</span> <span class="o">&lt;</span><span class="n">Exit</span><span class="p">:</span> <span class="n">south</span><span class="o">&gt;</span><span class="p">]</span>
</pre></div>
</div>
<p>So what we need is to display this list in our building menu… and to allow to edit it would be
great. Perhaps even add new exits?</p>
<p>First of all, lets write a function to display the <code class="docutils literal notranslate"><span class="pre">glance</span></code> on existing exits. Heres the code,
its explained below:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{obj.key}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> -------------------------------------------------------------------------------</span>
<span class="s2"> Editing the title of {{obj.key}}(#{{obj.id}})</span>
<span class="s2"> You can change the title simply by entering it.</span>
<span class="s2"> Use |y</span><span class="si">{back}</span><span class="s2">|n to go back to the main menu.</span>
<span class="s2"> Current title: |c{{obj.key}}|n</span>
<span class="s2"> &quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">back</span><span class="o">=</span><span class="s2">&quot;|n or |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keys_go_back</span><span class="p">)))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;exits&quot;</span><span class="p">,</span> <span class="s2">&quot;e&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="n">glance_exits</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;exits&quot;</span><span class="p">)</span>
<span class="c1"># Menu functions</span>
<span class="k">def</span><span class="w"> </span><span class="nf">glance_exits</span><span class="p">(</span><span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y</span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">return</span> <span class="n">glance</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |gNo exit yet|n&quot;</span>
</pre></div>
</div>
<p>When the building menu opens, it displays each choice to the caller. A choice is displayed with its
title (rendered a bit nicely to show the key as well) and the glance. In the case of the <code class="docutils literal notranslate"><span class="pre">exits</span></code>
choice, the glance is a function, so the building menu calls this function giving it the object
being edited (the room here). The function should return the text to see.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@edit</span> <span class="n">here</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">E</span><span class="p">]</span><span class="n">xits</span><span class="p">:</span>
<span class="n">north</span>
<span class="n">south</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">q</span>
<span class="n">Closing</span> <span class="n">the</span> <span class="n">editor</span><span class="o">.</span>
</pre></div>
</div>
<blockquote>
<div><p>How do I know the parameters of the function to give?</p>
</div></blockquote>
<p>The function you give can accept a lot of different parameters. This allows for a flexible approach
but might seem complicated at first. Basically, your function can accept any parameter, and the
building menu will send only the parameter based on their names. If your function defines an
argument named <code class="docutils literal notranslate"><span class="pre">caller</span></code> for instance (like <code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">func(caller):</span></code> ), then the building menu knows that
the first argument should contain the caller of the building menu. Here are the arguments, you
dont have to specify them (if you do, they need to have the same name):</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">menu</span></code>: if your function defines an argument named <code class="docutils literal notranslate"><span class="pre">menu</span></code>, it will contain the building menu
itself.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">choice</span></code>: if your function defines an argument named <code class="docutils literal notranslate"><span class="pre">choice</span></code>, it will contain the <code class="docutils literal notranslate"><span class="pre">Choice</span></code> object
representing this menu choice.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">string</span></code>: if your function defines an argument named <code class="docutils literal notranslate"><span class="pre">string</span></code>, it will contain the user input to
reach this menu choice. This is not very useful, except on <code class="docutils literal notranslate"><span class="pre">nomatch</span></code> callbacks which well see
later.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code>: if your function defines an argument named <code class="docutils literal notranslate"><span class="pre">obj</span></code>, it will contain the building menu edited
object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code>: if your function defines an argument named <code class="docutils literal notranslate"><span class="pre">caller</span></code>, it will contain the caller of the
building menu.</p></li>
<li><p>Anything else: any other argument will contain the object being edited by the building menu.</p></li>
</ul>
<p>So in our case:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">glance_exits</span><span class="p">(</span><span class="n">room</span><span class="p">):</span>
</pre></div>
</div>
<p>The only argument we need is <code class="docutils literal notranslate"><span class="pre">room</span></code>. Its not present in the list of possible arguments, so the
editing object of the building menu (the room, here) is given.</p>
<blockquote>
<div><p>Why is it useful to get the menu or choice object?</p>
</div></blockquote>
<p>Most of the time, you will not need these arguments. In very rare cases, you will use them to get
specific data (like the default attribute that was set). This tutorial will not elaborate on these
possibilities. Just know that they exist.</p>
<p>We should also define a text callback, so that we can enter our menu to see the room exits. Well
see how to edit them in the next section but this is a good opportunity to show a more complete
callback. To see it in action, as usual, replace the class and functions in <code class="docutils literal notranslate"><span class="pre">commands/building.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Our building menu</span>
<span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{obj.key}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> -------------------------------------------------------------------------------</span>
<span class="s2"> Editing the title of {{obj.key}}(#{{obj.id}})</span>
<span class="s2"> You can change the title simply by entering it.</span>
<span class="s2"> Use |y</span><span class="si">{back}</span><span class="s2">|n to go back to the main menu.</span>
<span class="s2"> Current title: |c{{obj.key}}|n</span>
<span class="s2"> &quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">back</span><span class="o">=</span><span class="s2">&quot;|n or |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keys_go_back</span><span class="p">)))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;exits&quot;</span><span class="p">,</span> <span class="s2">&quot;e&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="n">glance_exits</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;exits&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">text_exits</span><span class="p">)</span>
<span class="c1"># Menu functions</span>
<span class="k">def</span><span class="w"> </span><span class="nf">glance_exits</span><span class="p">(</span><span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y</span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">return</span> <span class="n">glance</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |gNo exit yet|n&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">text_exits</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits in the choice itself.&quot;&quot;&quot;</span>
<span class="n">text</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="mi">79</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">Room exits:&quot;</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> Use |y@c|n to create a new exit.&quot;</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">Existing exits:&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y@e </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot; (|y</span><span class="si">{aliases}</span><span class="s2">|n)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">aliases</span><span class="o">=</span><span class="s2">&quot;|n, |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="n">alias</span> <span class="k">for</span> <span class="n">alias</span> <span class="ow">in</span> <span class="n">exit</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="p">))</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot; toward </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2"> |gNo exit has yet been defined.|n&quot;</span>
<span class="k">return</span> <span class="n">text</span>
</pre></div>
</div>
<p>Look at the second callback in particular. It takes an additional argument, the caller (remember,
the argument names are important, their order is not relevant). This is useful for displaying
destination of exits accurately. Here is a demonstration of this menu:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@edit</span> <span class="n">here</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">E</span><span class="p">]</span><span class="n">xits</span><span class="p">:</span>
<span class="n">north</span>
<span class="n">south</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">e</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Room</span> <span class="n">exits</span><span class="p">:</span>
<span class="n">Use</span> <span class="nd">@c</span> <span class="n">to</span> <span class="n">create</span> <span class="n">a</span> <span class="n">new</span> <span class="n">exit</span><span class="o">.</span>
<span class="n">Existing</span> <span class="n">exits</span><span class="p">:</span>
<span class="nd">@e</span> <span class="n">north</span> <span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">toward</span> <span class="n">north</span><span class="p">(</span><span class="c1">#4)</span>
<span class="nd">@e</span> <span class="n">south</span> <span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="n">toward</span> <span class="n">south</span><span class="p">(</span><span class="c1">#7)</span>
<span class="o">&gt;</span> <span class="o">@</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">E</span><span class="p">]</span><span class="n">xits</span><span class="p">:</span>
<span class="n">north</span>
<span class="n">south</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">q</span>
<span class="n">Closing</span> <span class="n">the</span> <span class="n">building</span> <span class="n">menu</span><span class="o">.</span>
</pre></div>
</div>
<p>Using callbacks allows a great flexibility. Well now see how to handle sub-menus.</p>
</section>
<section id="sub-menus-for-complex-menus">
<h3>Sub-menus for complex menus<a class="headerlink" href="#sub-menus-for-complex-menus" title="Link to this heading"></a></h3>
<p>A menu is relatively flat: it has a root (where you see all the menu choices) and individual choices
you can go to using the menu choice keys. Once in a choice you can type some input or go back to
the root menu by entering the return command (usually <code class="docutils literal notranslate"><span class="pre">&#64;</span></code>).</p>
<p>Why shouldnt individual exits have their own menu though? Say, you edit an exit and can change its
key, description or aliases… perhaps even destination? Why ever not? It would make building much
easier!</p>
<p>The building menu system offers two ways to do that. The first is nested keys: nested keys allow to
go beyond just one menu/choice, to have menus with more layers. Using them is quick but might feel
a bit counter-intuitive at first. Another option is to create a different menu class and redirect
from the first to the second. This option might require more lines but is more explicit and can be
re-used for multiple menus. Adopt one of them depending of your taste.</p>
<section id="nested-menu-keys">
<h4>Nested menu keys<a class="headerlink" href="#nested-menu-keys" title="Link to this heading"></a></h4>
<p>So far, weve only used menu keys with one letter. We can add more, of course, but menu keys in
their simple shape are just command keys. Press “e” to go to the “exits” choice.</p>
<p>But menu keys can be nested. Nested keys allow to add choices with sub-menus. For instance, type
“e” to go to the “exits” choice, and then you can type “c” to open a menu to create a new exit, or
“d” to open a menu to delete an exit. The first menu would have the “e.c” key (first e, then c),
the second menu would have key as “e.d”.</p>
<p>Thats more advanced and, if the following code doesnt sound very friendly to you, try the next
section which provides a different approach of the same problem.</p>
<p>So we would like to edit exits. That is, you can type “e” to go into the choice of exits, then
enter <code class="docutils literal notranslate"><span class="pre">&#64;e</span></code> followed by the exit name to edit it… which will open another menu. In this sub-menu
you could change the exit key or description.</p>
<p>So we have a menu hierarchy similar to that:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">t</span> <span class="n">Change</span> <span class="n">the</span> <span class="n">room</span> <span class="n">title</span>
<span class="n">d</span> <span class="n">Change</span> <span class="n">the</span> <span class="n">room</span> <span class="n">description</span>
<span class="n">e</span> <span class="n">Access</span> <span class="n">the</span> <span class="n">room</span> <span class="n">exits</span>
<span class="p">[</span><span class="n">exit</span> <span class="n">name</span><span class="p">]</span> <span class="n">Access</span> <span class="n">the</span> <span class="n">exit</span> <span class="n">name</span> <span class="n">sub</span><span class="o">-</span><span class="n">menu</span>
<span class="p">[</span><span class="n">text</span><span class="p">]</span> <span class="n">Change</span> <span class="n">the</span> <span class="n">exit</span> <span class="n">key</span>
</pre></div>
</div>
<p>Or, if you prefer an example output:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">look</span>
<span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="p">(</span><span class="c1">#2)</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="n">Exits</span><span class="p">:</span> <span class="n">north</span><span class="p">(</span><span class="c1">#4) and south(#7)</span>
<span class="o">&gt;</span> <span class="nd">@edit</span> <span class="n">here</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">E</span><span class="p">]</span><span class="n">xits</span><span class="p">:</span>
<span class="n">north</span>
<span class="n">south</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">e</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Room</span> <span class="n">exits</span> <span class="p">:</span>
<span class="n">Use</span> <span class="nd">@c</span> <span class="n">to</span> <span class="n">create</span> <span class="n">a</span> <span class="n">new</span> <span class="n">exit</span><span class="o">.</span>
<span class="n">Existing</span> <span class="n">exits</span><span class="p">:</span>
<span class="nd">@e</span> <span class="n">north</span> <span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">toward</span> <span class="n">north</span><span class="p">(</span><span class="c1">#4)</span>
<span class="nd">@e</span> <span class="n">south</span> <span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="n">toward</span> <span class="n">south</span><span class="p">(</span><span class="c1">#7)</span>
<span class="o">&gt;</span> <span class="nd">@e</span> <span class="n">north</span>
<span class="n">Editing</span><span class="p">:</span> <span class="n">north</span>
<span class="n">Exit</span> <span class="n">north</span><span class="p">:</span>
<span class="n">Enter</span> <span class="n">the</span> <span class="n">exit</span> <span class="n">key</span> <span class="n">to</span> <span class="n">change</span> <span class="n">it</span><span class="p">,</span> <span class="ow">or</span> <span class="o">@</span> <span class="n">to</span> <span class="n">go</span> <span class="n">back</span><span class="o">.</span>
<span class="n">New</span> <span class="n">exit</span> <span class="n">key</span><span class="p">:</span>
<span class="o">&gt;</span> <span class="n">door</span>
<span class="n">Exit</span> <span class="n">door</span><span class="p">:</span>
<span class="n">Enter</span> <span class="n">the</span> <span class="n">exit</span> <span class="n">key</span> <span class="n">to</span> <span class="n">change</span> <span class="n">it</span><span class="p">,</span> <span class="ow">or</span> <span class="o">@</span> <span class="n">to</span> <span class="n">go</span> <span class="n">back</span><span class="o">.</span>
<span class="n">New</span> <span class="n">exit</span> <span class="n">key</span><span class="p">:</span>
<span class="o">&gt;</span> <span class="o">@</span>
<span class="o">-------------------------------------------------------------------------------</span>
<span class="n">Room</span> <span class="n">exits</span> <span class="p">:</span>
<span class="n">Use</span> <span class="nd">@c</span> <span class="n">to</span> <span class="n">create</span> <span class="n">a</span> <span class="n">new</span> <span class="n">exit</span><span class="o">.</span>
<span class="n">Existing</span> <span class="n">exits</span><span class="p">:</span>
<span class="nd">@e</span> <span class="n">door</span> <span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="n">toward</span> <span class="n">door</span><span class="p">(</span><span class="c1">#4)</span>
<span class="nd">@e</span> <span class="n">south</span> <span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="n">toward</span> <span class="n">south</span><span class="p">(</span><span class="c1">#7)</span>
<span class="o">&gt;</span> <span class="o">@</span>
<span class="n">Building</span> <span class="n">menu</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">T</span><span class="p">]</span><span class="n">itle</span><span class="p">:</span> <span class="n">A</span> <span class="n">beautiful</span> <span class="n">meadow</span>
<span class="p">[</span><span class="n">D</span><span class="p">]</span><span class="n">escription</span><span class="p">:</span>
<span class="n">This</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">beautiful</span> <span class="n">meadow</span><span class="o">.</span> <span class="n">But</span> <span class="n">so</span> <span class="n">beautiful</span> <span class="n">I</span> <span class="n">can</span><span class="s1">&#39;t describe it.</span>
<span class="p">[</span><span class="n">E</span><span class="p">]</span><span class="n">xits</span><span class="p">:</span>
<span class="n">door</span>
<span class="n">south</span>
<span class="p">[</span><span class="n">Q</span><span class="p">]</span><span class="n">uit</span> <span class="n">the</span> <span class="n">menu</span>
<span class="o">&gt;</span> <span class="n">q</span>
<span class="n">Closing</span> <span class="n">the</span> <span class="n">building</span> <span class="n">menu</span><span class="o">.</span>
</pre></div>
</div>
<p>This needs a bit of code and a bit of explanation. So here we go… the code first, the
explanations next!</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ... from commands/building.py</span>
<span class="c1"># Our building menu</span>
<span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> For the time being, we have only one choice: key, to edit the room key.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{obj.key}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> -------------------------------------------------------------------------------</span>
<span class="s2"> Editing the title of {{obj.key}}(#{{obj.id}})</span>
<span class="s2"> You can change the title simply by entering it.</span>
<span class="s2"> Use |y</span><span class="si">{back}</span><span class="s2">|n to go back to the main menu.</span>
<span class="s2"> Current title: |c{{obj.key}}|n</span>
<span class="s2"> &quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">back</span><span class="o">=</span><span class="s2">&quot;|n or |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keys_go_back</span><span class="p">)))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;exits&quot;</span><span class="p">,</span> <span class="s2">&quot;e&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="n">glance_exits</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">text_exits</span><span class="p">,</span> <span class="n">on_nomatch</span><span class="o">=</span><span class="n">nomatch_exits</span><span class="p">)</span>
<span class="c1"># Exit sub-menu</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;exit&quot;</span><span class="p">,</span> <span class="s2">&quot;e.*&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">text_single_exit</span><span class="p">,</span> <span class="n">on_nomatch</span><span class="o">=</span><span class="n">nomatch_single_exit</span><span class="p">)</span>
<span class="c1"># Menu functions</span>
<span class="k">def</span><span class="w"> </span><span class="nf">glance_exits</span><span class="p">(</span><span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y</span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">return</span> <span class="n">glance</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |gNo exit yet|n&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">text_exits</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits in the choice itself.&quot;&quot;&quot;</span>
<span class="n">text</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="mi">79</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">Room exits:&quot;</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> Use |y@c|n to create a new exit.&quot;</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">Existing exits:&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y@e </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot; (|y</span><span class="si">{aliases}</span><span class="s2">|n)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">aliases</span><span class="o">=</span><span class="s2">&quot;|n, |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="n">alias</span> <span class="k">for</span> <span class="n">alias</span> <span class="ow">in</span> <span class="n">exit</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="p">))</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot; toward </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2"> |gNo exit has yet been defined.|n&quot;</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">def</span><span class="w"> </span><span class="nf">nomatch_exits</span><span class="p">(</span><span class="n">menu</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">string</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The user typed something in the list of exits. Maybe an exit name?</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="p">[</span><span class="mi">3</span><span class="p">:]</span>
<span class="n">exit</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">candidates</span><span class="o">=</span><span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">)</span>
<span class="k">if</span> <span class="n">exit</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span>
<span class="c1"># Open a sub-menu, using nested keys</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Editing: </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">menu</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">exit</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="c1"># Exit sub-menu</span>
<span class="k">def</span><span class="w"> </span><span class="nf">text_single_exit</span><span class="p">(</span><span class="n">menu</span><span class="p">,</span> <span class="n">caller</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the text to edit single exits.&quot;&quot;&quot;</span>
<span class="n">exit</span> <span class="o">=</span> <span class="n">menu</span><span class="o">.</span><span class="n">keys</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="n">exit</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;&quot;</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> Exit </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">:</span>
<span class="s2"> Enter the exit key to change it, or |y@|n to go back.</span>
<span class="s2"> New exit key:</span>
<span class="s2"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">nomatch_single_exit</span><span class="p">(</span><span class="n">menu</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">string</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;The user entered something in the exit sub-menu. Replace the exit key.&quot;&quot;&quot;</span>
<span class="c1"># exit is the second key element: keys should contain [&#39;e&#39;, &lt;Exit object&gt;]</span>
<span class="n">exit</span> <span class="o">=</span> <span class="n">menu</span><span class="o">.</span><span class="n">keys</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="n">exit</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;|rCannot find the exit.|n&quot;</span><span class="p">)</span>
<span class="n">menu</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">back</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="n">exit</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">string</span>
<span class="k">return</span> <span class="kc">True</span>
</pre></div>
</div>
<blockquote>
<div><p>Thats a lot of code! And we only handle editing the exit key!</p>
</div></blockquote>
<p>Thats why at some point you might want to write a real sub-menu, instead of using simple nested
keys. But you might need both to build pretty menus too!</p>
<ol class="arabic simple">
<li><p>The first thing new is in our menu class. After creating a <code class="docutils literal notranslate"><span class="pre">on_nomatch</span></code> callback for the exits
menu (that shouldnt be a surprised), we need to add a nested key. We give this menu a key of
<code class="docutils literal notranslate"><span class="pre">&quot;e.*&quot;</span></code>. Thats a bit odd! “e” is our key to the exits menu, . is the separator to indicate a
nested menu, and * means anything. So basically, we create a nested menu that is contains within
the exits menu and anything. Well see what this “anything” is in practice.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">glance_exits</span></code> and <code class="docutils literal notranslate"><span class="pre">text_exits</span></code> are basically the same.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">nomatch_exits</span></code> is short but interesting. Its called when we enter some text in the “exits”
menu (that is, in the list of exits). We have said that the user should enter <code class="docutils literal notranslate"><span class="pre">&#64;e</span></code> followed by the
exit name to edit it. So in the <code class="docutils literal notranslate"><span class="pre">nomatch_exits</span></code> callbac, we check for that input. If the entered
text begins by <code class="docutils literal notranslate"><span class="pre">&#64;e</span></code>, we try to find the exit in the room. If we do…</p></li>
<li><p>We call the <code class="docutils literal notranslate"><span class="pre">menu.move</span></code> method. Thats where things get a bit complicated with nested menus: we
need to use <code class="docutils literal notranslate"><span class="pre">menu.move</span></code> to change from layer to layer. Here, we are in the choice of exits (the
exits menu, of key “e”). We need to go down one layer to edit an exit. So we call <code class="docutils literal notranslate"><span class="pre">menu.move</span></code> and
give it an exit object. The menu system remembers what position the user is based on the keys she
has entered: when the user opens the menu, there is no key. If she selects the exits choice, the
menu key being “e”, the position of the user is <code class="docutils literal notranslate"><span class="pre">[&quot;e&quot;]</span></code> (a list with the menu keys). If we call
<code class="docutils literal notranslate"><span class="pre">menu.move</span></code>, whatever we give to this method will be appended to the list of keys, so that the user
position becomes <code class="docutils literal notranslate"><span class="pre">[&quot;e&quot;,</span> <span class="pre">&lt;Exit</span> <span class="pre">object&gt;]</span></code>.</p></li>
<li><p>In the menu class, we have defined the menu <code class="docutils literal notranslate"><span class="pre">&quot;e.*&quot;</span></code>, meaning “the menu contained in the exits
choice plus anything”. The “anything” here is an exit: we have called <code class="docutils literal notranslate"><span class="pre">menu.move(exit)</span></code>, so the
<code class="docutils literal notranslate"><span class="pre">&quot;e.*&quot;</span></code> menu choice is chosen.</p></li>
<li><p>In this menu, the text is set to a callback. There is also a <code class="docutils literal notranslate"><span class="pre">on_nomatch</span></code> callback that is
called whenever the user enters some text. If so, we change the exit name.</p></li>
</ol>
<p>Using <code class="docutils literal notranslate"><span class="pre">menu.move</span></code> like this is a bit confusing at first. Sometimes its useful. In this case, if
we want a more complex menu for exits, it makes sense to use a real sub-menu, not nested keys like
this. But sometimes, you will find yourself in a situation where you dont need a full menu to
handle a choice.</p>
</section>
</section>
</section>
<section id="full-sub-menu-as-separate-classes">
<h2>Full sub-menu as separate classes<a class="headerlink" href="#full-sub-menu-as-separate-classes" title="Link to this heading"></a></h2>
<p>The best way to handle individual exits is to create two separate classes:</p>
<ul class="simple">
<li><p>One for the room menu.</p></li>
<li><p>One for the individual exit menu.</p></li>
</ul>
<p>The first one will have to redirect on the second. This might be more intuitive and flexible,
depending on what you want to achieve. So lets build two menus:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Still in commands/building.py, replace the menu class and functions by...</span>
<span class="c1"># Our building menus</span>
<span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit a room.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{obj.key}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2"> -------------------------------------------------------------------------------</span>
<span class="s2"> Editing the title of {{obj.key}}(#{{obj.id}})</span>
<span class="s2"> You can change the title simply by entering it.</span>
<span class="s2"> Use |y</span><span class="si">{back}</span><span class="s2">|n to go back to the main menu.</span>
<span class="s2"> Current title: |c{{obj.key}}|n</span>
<span class="s2"> &quot;&quot;&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">back</span><span class="o">=</span><span class="s2">&quot;|n or |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">keys_go_back</span><span class="p">)))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;exits&quot;</span><span class="p">,</span> <span class="s2">&quot;e&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="n">glance_exits</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">text_exits</span><span class="p">,</span>
<span class="n">on_nomatch</span><span class="o">=</span><span class="n">nomatch_exits</span><span class="p">)</span>
<span class="c1"># Menu functions</span>
<span class="k">def</span><span class="w"> </span><span class="nf">glance_exits</span><span class="p">(</span><span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits.&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">glance</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y</span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">return</span> <span class="n">glance</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |gNo exit yet|n&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">text_exits</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Show the room exits in the choice itself.&quot;&quot;&quot;</span>
<span class="n">text</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="o">*</span> <span class="mi">79</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">Room exits:&quot;</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> Use |y@c|n to create a new exit.&quot;</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2">Existing exits:&quot;</span>
<span class="k">if</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2"> |y@e </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">|n&quot;</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot; (|y</span><span class="si">{aliases}</span><span class="s2">|n)&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">aliases</span><span class="o">=</span><span class="s2">&quot;|n, |y&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="n">alias</span> <span class="k">for</span> <span class="n">alias</span> <span class="ow">in</span> <span class="n">exit</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="p">))</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot; toward </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">text</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n\n</span><span class="s2"> |gNo exit has yet been defined.|n&quot;</span>
<span class="k">return</span> <span class="n">text</span>
<span class="k">def</span><span class="w"> </span><span class="nf">nomatch_exits</span><span class="p">(</span><span class="n">menu</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">string</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The user typed something in the list of exits. Maybe an exit name?</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="p">[</span><span class="mi">3</span><span class="p">:]</span>
<span class="n">exit</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">candidates</span><span class="o">=</span><span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">)</span>
<span class="k">if</span> <span class="n">exit</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span>
<span class="c1"># Open a sub-menu, using nested keys</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Editing: </span><span class="si">{</span><span class="n">exit</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="n">menu</span><span class="o">.</span><span class="n">open_submenu</span><span class="p">(</span><span class="s2">&quot;commands.building.ExitBuildingMenu&quot;</span><span class="p">,</span> <span class="n">exit</span><span class="p">,</span> <span class="n">parent_keys</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;e&quot;</span><span class="p">])</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">class</span><span class="w"> </span><span class="nc">ExitBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Building menu to edit an exit.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exit</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;k&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="o">=</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">glance</span><span class="o">=</span><span class="s2">&quot;</span><span class="si">{obj.key}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add_choice_edit</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The code might be much easier to read. But before detailing it, lets see how it behaves in the
game:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt; @edit here
Building menu: A beautiful meadow
[T]itle: A beautiful meadow
[D]escription:
This is a beautiful meadow. But so beautiful I can&#39;t describe it.
[E]xits:
door
south
[Q]uit the menu
&gt; e
-------------------------------------------------------------------------------
Room exits:
Use @c to create a new exit.
Existing exits:
@e door (n) toward door(#4)
@e south (s) toward south(#7)
Editing: door
&gt; @e door
Building menu: door
[K]ey: door
[D]escription:
None
&gt; k
-------------------------------------------------------------------------------
key for door(#4)
You can change this value simply by entering it.
Use @ to go back to the main menu.
Current value: door
&gt; north
-------------------------------------------------------------------------------
key for north(#4)
You can change this value simply by entering it.
Use @ to go back to the main menu.
Current value: north
&gt; @
Building menu: north
[K]ey: north
[D]escription:
None
&gt; d
----------Line Editor [editor]----------------------------------------------------
01| None
----------[l:01 w:001 c:0004]------------(:h for help)----------------------------
&gt; :DD
Cleared 1 lines from buffer.
&gt; This is the northern exit. Cool huh?
01| This is the northern exit. Cool huh?
&gt; :wq
Building menu: north
[K]ey: north
[D]escription:
This is the northern exit. Cool huh?
&gt; @
-------------------------------------------------------------------------------
Room exits:
Use @c to create a new exit.
Existing exits:
@e north (n) toward north(#4)
@e south (s) toward south(#7)
&gt; @
Building menu: A beautiful meadow
[T]itle: A beautiful meadow
[D]escription:
This is a beautiful meadow. But so beautiful I can&#39;t describe it.
[E]xits:
north
south
[Q]uit the menu
&gt; q
Closing the building menu.
&gt; look
A beautiful meadow(#2)
This is a beautiful meadow. But so beautiful I can&#39;t describe it.
Exits: north(#4) and south(#7)
&gt; @py here.exits[0]
&gt;&gt;&gt; here.exits[0]
north
&gt; @py here.exits[0].db.desc
&gt;&gt;&gt; here.exits[0].db.desc
This is the northern exit. Cool huh?
</pre></div>
</div>
<p>Very simply, we created two menus and bridged them together. This needs much less callbacks. There
is only one line in the <code class="docutils literal notranslate"><span class="pre">nomatch_exits</span></code> to add:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">menu</span><span class="o">.</span><span class="n">open_submenu</span><span class="p">(</span><span class="s2">&quot;commands.building.ExitBuildingMenu&quot;</span><span class="p">,</span> <span class="n">exit</span><span class="p">,</span> <span class="n">parent_keys</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;e&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>We have to call <code class="docutils literal notranslate"><span class="pre">open_submenu</span></code> on the menu object (which opens, as its name implies, a sub menu)
with three arguments:</p>
<ul class="simple">
<li><p>The path of the menu class to create. Its the Python class leading to the menu (notice the
dots).</p></li>
<li><p>The object that will be edited by the menu. Here, its our exit, so we give it to the sub-menu.</p></li>
<li><p>The keys of the parent to open when the sub-menu closes. Basically, when were in the root of the
sub-menu and press <code class="docutils literal notranslate"><span class="pre">&#64;</span></code>, well open the parent menu, with the parent keys. So we specify <code class="docutils literal notranslate"><span class="pre">[&quot;e&quot;]</span></code>,
since the parent menus is the “exits” choice.</p></li>
</ul>
<p>And thats it. The new class will be automatically created. As you can see, we have to create a
<code class="docutils literal notranslate"><span class="pre">on_nomatch</span></code> callback to open the sub-menu, but once opened, it automatically close whenever needed.</p>
<section id="generic-menu-options">
<h3>Generic menu options<a class="headerlink" href="#generic-menu-options" title="Link to this heading"></a></h3>
<p>There are some options that can be set on any menu class. These options allow for greater
customization. They are class attributes (see the example below), so just set them in the class
body:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">keys_go_back</span></code> (default to <code class="docutils literal notranslate"><span class="pre">[&quot;&#64;&quot;]</span></code>): the keys to use to go back in the menu hierarchy, from choice
to root menu, from sub-menu to parent-menu. By default, only a <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> is used. You can change this
key for one menu or all of them. You can define multiple return commands if you want.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sep_keys</span></code> (default <code class="docutils literal notranslate"><span class="pre">&quot;.&quot;</span></code>): this is the separator for nested keys. There is no real need to
redefine it except if you really need the dot as a key, and need nested keys in your menu.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">joker_key</span></code> (default to <code class="docutils literal notranslate"><span class="pre">&quot;*&quot;</span></code>): used for nested keys to indicate “any key”. Again, you shouldnt
need to change it unless you want to be able to use the <code class="docutils literal notranslate"><span class="pre">&#64;*&#64;</span></code> in a command key, and also need nested
keys in your menu.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">min_shortcut</span></code> (default to <code class="docutils literal notranslate"><span class="pre">1</span></code>): although we didnt see it here, one can create a menu choice
without giving it a key. If so, the menu system will try to “guess” the key. This option allows to
change the minimum length of any key for security reasons.</p></li>
</ul>
<p>To set one of them just do so in your menu class(es):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">RoomBuildingMenu</span><span class="p">(</span><span class="n">BuildingMenu</span><span class="p">):</span>
<span class="n">keys_go_back</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;/&quot;</span><span class="p">]</span>
<span class="n">min_shortcut</span> <span class="o">=</span> <span class="mi">2</span>
</pre></div>
</div>
</section>
</section>
<section id="conclusion">
<h2>Conclusion<a class="headerlink" href="#conclusion" title="Link to this heading"></a></h2>
<p>Building menus mean to save you time and create a rich yet simple interface. But they can be
complicated to learn and require reading the source code to find out how to do such and such a
thing. This documentation, however long, is an attempt at describing this system, but chances are
youll still have questions about it after reading it, especially if you try to push this system to
a great extent. Do not hesitate to read the documentation of this contrib, its meant to be
exhaustive but user-friendly.</p>
<hr class="docutils" />
<p><small>This document page is generated from <code class="docutils literal notranslate"><span class="pre">evennia/contrib/base_systems/building_menu/README.md</span></code>. Changes to this
file will be overwritten, so edit that file rather than this one.</small></p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo of Evennia"/>
</a></p>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Building menu</a><ul>
<li><a class="reference internal" href="#install">Install</a></li>
<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li>
<li><a class="reference internal" href="#a-simple-menu-example">A simple menu example</a><ul>
<li><a class="reference internal" href="#a-generic-editing-command">A generic editing command</a></li>
<li><a class="reference internal" href="#our-first-menu">Our first menu</a></li>
<li><a class="reference internal" href="#code-explanation">Code explanation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#customizing-building-menus">Customizing building menus</a><ul>
<li><a class="reference internal" href="#generic-choices">Generic choices</a></li>
<li><a class="reference internal" href="#add-choice-options"><code class="docutils literal notranslate"><span class="pre">add_choice</span></code> options</a></li>
<li><a class="reference internal" href="#everything-can-be-a-function">Everything can be a function</a></li>
<li><a class="reference internal" href="#sub-menus-for-complex-menus">Sub-menus for complex menus</a><ul>
<li><a class="reference internal" href="#nested-menu-keys">Nested menu keys</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#full-sub-menu-as-separate-classes">Full sub-menu as separate classes</a><ul>
<li><a class="reference internal" href="#generic-menu-options">Generic menu options</a></li>
</ul>
</li>
<li><a class="reference internal" href="#conclusion">Conclusion</a></li>
</ul>
</li>
</ul>
<div>
<h4>Previous topic</h4>
<p class="topless"><a href="Contrib-AWSStorage.html"
title="previous chapter">AWSstorage system</a></p>
</div>
<div>
<h4>Next topic</h4>
<p class="topless"><a href="Contrib-Color-Markups.html"
title="next chapter">Additional Color markups</a></p>
</div>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Contribs/Contrib-Building-Menu.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li>
<a href="https://www.evennia.com/docs/latest/index.html">latest (main branch)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/6.x/index.html">v6.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/5.x/index.html">v5.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/4.x/index.html">v4.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/3.x/index.html">v3.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/2.x/index.html">v2.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/1.x/index.html">v1.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/0.x/index.html">v0.9.5 branch (outdated)</a>
</li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Contrib-Color-Markups.html" title="Additional Color markups"
>next</a> |</li>
<li class="right" >
<a href="Contrib-AWSStorage.html" title="AWSstorage system"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" >Contribs</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Building menu</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
</div>
</body>
</html>