mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
1363 lines
No EOL
136 KiB
HTML
1363 lines
No EOL
136 KiB
HTML
<!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>EvMenu — 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="EvMore" href="EvMore.html" />
|
||
<link rel="prev" title="EvForm" href="EvForm.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="EvMore.html" title="EvMore"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="EvForm.html" title="EvForm"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">EvMenu</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="evmenu">
|
||
<h1>EvMenu<a class="headerlink" href="#evmenu" title="Link to this heading">¶</a></h1>
|
||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>Is<span class="w"> </span>your<span class="w"> </span>answer<span class="w"> </span>yes<span class="w"> </span>or<span class="w"> </span>no?
|
||
_________________________________________
|
||
<span class="o">[</span>Y<span class="o">]</span>es!<span class="w"> </span>-<span class="w"> </span>Answer<span class="w"> </span>yes.
|
||
<span class="o">[</span>N<span class="o">]</span>o!<span class="w"> </span>-<span class="w"> </span>Answer<span class="w"> </span>no.
|
||
<span class="o">[</span>A<span class="o">]</span>bort<span class="w"> </span>-<span class="w"> </span>Answer<span class="w"> </span>neither,<span class="w"> </span>and<span class="w"> </span>abort.
|
||
|
||
><span class="w"> </span>Y
|
||
You<span class="w"> </span>chose<span class="w"> </span>yes!
|
||
|
||
Thanks<span class="w"> </span><span class="k">for</span><span class="w"> </span>your<span class="w"> </span>answer.<span class="w"> </span>Goodbye!
|
||
</pre></div>
|
||
</div>
|
||
<p><em>EvMenu</em> is used for generate branching multi-choice menus. Each menu ‘node’ can
|
||
accepts specific options as input or free-form input. Depending what the player
|
||
chooses, they are forwarded to different nodes in the menu.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> utility class is located in <a class="reference internal" href="../api/evennia.utils.evmenu.html#evennia-utils-evmenu"><span class="std std-ref">evennia/utils/evmenu.py</span></a>.
|
||
It allows for easily adding interactive menus to the game; for example to implement Character creation, building commands or similar. Below is an example of offering NPC conversation choices:</p>
|
||
<p>This is how the example menu at the top of this page will look in code:</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.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">evmenu</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_handle_answer</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_input</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">answer</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"answer"</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="sa">f</span><span class="s2">"You chose </span><span class="si">{</span><span class="n">answer</span><span class="si">}</span><span class="s2">!"</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="s2">"end"</span> <span class="c1"># name of next node</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_question</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_input</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Is your answer yes or no?"</span>
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"[Y]es!"</span><span class="p">,</span> <span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"y"</span><span class="p">),</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="n">Answer</span> <span class="n">yes</span><span class="o">.</span><span class="s2">",</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="n">_handle_answer</span><span class="p">,</span> <span class="p">{</span><span class="s2">"answer"</span><span class="p">:</span> <span class="s2">"yes"</span><span class="p">}},</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"[N]o!"</span><span class="p">,</span> <span class="s2">"no"</span><span class="p">,</span> <span class="s2">"n"</span><span class="p">),</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Answer no."</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="n">_handle_answer</span><span class="p">,</span> <span class="p">{</span><span class="s2">"answer"</span><span class="p">:</span> <span class="s2">"no"</span><span class="p">}},</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"[A]bort"</span><span class="p">,</span> <span class="s2">"abort"</span><span class="p">,</span> <span class="s2">"a"</span><span class="p">),</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Answer neither, and abort."</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"end"</span><span class="p">}</span>
|
||
<span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_end</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_input</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="s2">"Thanks for your answer. Goodbye!"</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="kc">None</span> <span class="c1"># empty options ends the menu</span>
|
||
|
||
<span class="n">evmenu</span><span class="o">.</span><span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="p">{</span><span class="s2">"start"</span><span class="p">:</span> <span class="n">node_question</span><span class="p">,</span> <span class="s2">"end"</span><span class="p">:</span> <span class="n">node_end</span><span class="p">})</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Note the call to <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> at the end; this immediately creates the menu for the
|
||
<code class="docutils literal notranslate"><span class="pre">caller</span></code>. It also assigns the two node-functions to menu node-names <code class="docutils literal notranslate"><span class="pre">start</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">end</span></code>, which is what the menu then uses to reference the nodes.</p>
|
||
<p>Each node of the menu is a function that returns the text and a list of dicts
|
||
describing the choices you can make on that node.</p>
|
||
<p>Each option details what it should show (key/desc) as well as which node to go
|
||
to (goto) next. The “goto” should be the name of the next node to go (if <code class="docutils literal notranslate"><span class="pre">None</span></code>,
|
||
the same node will be rerun again).</p>
|
||
<p>Above, the <code class="docutils literal notranslate"><span class="pre">Abort</span></code> option gives the “end” node name just as a string whereas the
|
||
yes/no options instead uses the callable <code class="docutils literal notranslate"><span class="pre">_handle_answer</span></code> but pass different
|
||
arguments to it. <code class="docutils literal notranslate"><span class="pre">_handle_answer</span></code> then returns the name of the next node (this
|
||
allows you to perform actions when making a choice before you move on to the
|
||
next node the menu). Note that <code class="docutils literal notranslate"><span class="pre">_handle_answer</span></code> is <em>not</em> a node in the menu,
|
||
it’s just a helper function.</p>
|
||
<p>When choosing ‘yes’ (or ‘no’) what happens here is that <code class="docutils literal notranslate"><span class="pre">_handle_answer</span></code> gets
|
||
called and echoes your choice before directing to the “end” node, which exits
|
||
the menu (since it doesn’t return any options).</p>
|
||
<p>You can also write menus using the <a class="reference internal" href="#evmenu-templating-language">EvMenu templating language</a>. This
|
||
allows you to use a text string to generate simpler menus with less boiler
|
||
plate. Let’s create exactly the same menu using the templating language:</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.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">evmenu</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_handle_answer</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_input</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">answer</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"answer"</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="sa">f</span><span class="s2">"You chose </span><span class="si">{</span><span class="n">answer</span><span class="si">}</span><span class="s2">!"</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="s2">"end"</span> <span class="c1"># name of next node</span>
|
||
|
||
<span class="n">menu_template</span> <span class="o">=</span> <span class="s2">"""</span>
|
||
|
||
<span class="s2">## node start</span>
|
||
|
||
<span class="s2">Is your answer yes or no?</span>
|
||
|
||
<span class="s2">## options</span>
|
||
|
||
<span class="s2">[Y]es!;yes;y: Answer yes. -> handle_answer(answer=yes)</span>
|
||
<span class="s2">[N]o!;no;n: Answer no. -> handle_answer(answer=no)</span>
|
||
<span class="s2">[A]bort;abort;a: Answer neither, and abort. -> end</span>
|
||
|
||
<span class="s2">## node end</span>
|
||
|
||
<span class="s2">Thanks for your answer. Goodbye!</span>
|
||
|
||
<span class="s2">"""</span>
|
||
|
||
<span class="n">evmenu</span><span class="o">.</span><span class="n">template2menu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menu_template</span><span class="p">,</span> <span class="p">{</span><span class="s2">"handle_answer"</span><span class="p">:</span> <span class="n">_handle_answer</span><span class="p">})</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>As seen, the <code class="docutils literal notranslate"><span class="pre">_handle_answer</span></code> is the same, but the menu structure is
|
||
described in the <code class="docutils literal notranslate"><span class="pre">menu_template</span></code> string. The <code class="docutils literal notranslate"><span class="pre">template2menu</span></code> helper
|
||
uses the template-string and a mapping of callables (we must add
|
||
<code class="docutils literal notranslate"><span class="pre">_handle_answer</span></code> here) to build a full EvMenu for us.</p>
|
||
<p>Here’s another menu example, where we can choose how to interact with an NPC:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">The</span> <span class="n">guard</span> <span class="n">looks</span> <span class="n">at</span> <span class="n">you</span> <span class="n">suspiciously</span><span class="o">.</span>
|
||
<span class="s2">"No one is supposed to be in here ..."</span>
|
||
<span class="n">he</span> <span class="n">says</span><span class="p">,</span> <span class="n">a</span> <span class="n">hand</span> <span class="n">on</span> <span class="n">his</span> <span class="n">weapon</span><span class="o">.</span>
|
||
<span class="n">_______________________________________________</span>
|
||
<span class="mf">1.</span> <span class="n">Try</span> <span class="n">to</span> <span class="n">bribe</span> <span class="n">him</span> <span class="p">[</span><span class="n">Cha</span> <span class="o">+</span> <span class="mi">10</span> <span class="n">gold</span><span class="p">]</span>
|
||
<span class="mf">2.</span> <span class="n">Convince</span> <span class="n">him</span> <span class="n">you</span> <span class="n">work</span> <span class="n">here</span> <span class="p">[</span><span class="n">Int</span><span class="p">]</span>
|
||
<span class="mf">3.</span> <span class="n">Appeal</span> <span class="n">to</span> <span class="n">his</span> <span class="n">vanity</span> <span class="p">[</span><span class="n">Cha</span><span class="p">]</span>
|
||
<span class="mf">4.</span> <span class="n">Try</span> <span class="n">to</span> <span class="n">knock</span> <span class="n">him</span> <span class="n">out</span> <span class="p">[</span><span class="n">Luck</span> <span class="o">+</span> <span class="n">Dex</span><span class="p">]</span>
|
||
<span class="mf">5.</span> <span class="n">Try</span> <span class="n">to</span> <span class="n">run</span> <span class="n">away</span> <span class="p">[</span><span class="n">Dex</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_skill_check</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">skills</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"skills"</span><span class="p">,</span> <span class="p">[])</span>
|
||
<span class="n">gold</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"gold"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||
|
||
<span class="c1"># perform skill check here, decide if check passed or not</span>
|
||
<span class="c1"># then decide which node-name to return based on</span>
|
||
<span class="c1"># the result ...</span>
|
||
|
||
<span class="k">return</span> <span class="n">next_node_name</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_guard</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwarg</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="s1">'The guard looks at you suspiciously.</span><span class="se">\n</span><span class="s1">'</span>
|
||
<span class="s1">'"No one is supposed to be in here ..."</span><span class="se">\n</span><span class="s1">'</span>
|
||
<span class="s1">'he says, a hand on his weapon.'</span>
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Try to bribe on [Cha + 10 gold]"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_skill_check</span><span class="p">,</span> <span class="p">{</span><span class="s2">"skills"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"Cha"</span><span class="p">],</span> <span class="s2">"gold"</span><span class="p">:</span> <span class="mi">10</span><span class="p">})},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Convince him you work here [Int]."</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_skill_check</span><span class="p">,</span> <span class="p">{</span><span class="s2">"skills"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"Int"</span><span class="p">]})},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Appeal to his vanity [Cha]"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_skill_check</span><span class="p">,</span> <span class="p">{</span><span class="s2">"skills"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"Cha"</span><span class="p">]})},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Try to knock him out [Luck + Dex]"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_skill_check</span><span class="p">,</span> <span class="p">{</span><span class="s2">"skills"" ["</span><span class="n">Luck</span><span class="s2">", "</span><span class="n">Dex</span><span class="s2">"]})},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Try to run away [Dex]"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_skill_check</span><span class="p">,</span> <span class="p">{</span><span class="s2">"skills"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"Dex"</span><span class="p">]})}</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
<span class="p">)</span>
|
||
|
||
<span class="c1"># EvMenu called below, with all the nodes ...</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that by skipping the <code class="docutils literal notranslate"><span class="pre">key</span></code> of the options, we instead get an
|
||
(auto-generated) list of numbered options to choose from.</p>
|
||
<p>Here the <code class="docutils literal notranslate"><span class="pre">_skill_check</span></code> helper will check (roll your stats, exactly what this
|
||
means depends on your game) to decide if your approach succeeded. It may then
|
||
choose to point you to nodes that continue the conversation or maybe dump you
|
||
into combat!</p>
|
||
<section id="launching-the-menu">
|
||
<h2>Launching the menu<a class="headerlink" href="#launching-the-menu" title="Link to this heading">¶</a></h2>
|
||
<p>Initializing the menu is done using a call to the <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmenu.EvMenu</span></code> class. This is the most common way to do so - from inside a <a class="reference internal" href="Commands.html"><span class="std std-doc">Command</span></a>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in, for example gamedir/commands/command.py</span>
|
||
|
||
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils.evmenu</span><span class="w"> </span><span class="kn">import</span> <span class="n">EvMenu</span>
|
||
|
||
<span class="k">class</span><span class="w"> </span><span class="nc">CmdTestMenu</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">"testcommand"</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">EvMenu</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="s2">"world.mymenu"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>When running this command, the menu will start using the menu nodes loaded from
|
||
<code class="docutils literal notranslate"><span class="pre">mygame/world/mymenu.py</span></code>. See next section on how to define menu nodes.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> has the following optional callsign:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menu_data</span><span class="p">,</span>
|
||
<span class="n">startnode</span><span class="o">=</span><span class="s2">"start"</span><span class="p">,</span>
|
||
<span class="n">cmdset_mergetype</span><span class="o">=</span><span class="s2">"Replace"</span><span class="p">,</span> <span class="n">cmdset_priority</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
|
||
<span class="n">auto_quit</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">auto_look</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">auto_help</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||
<span class="n">cmd_on_exit</span><span class="o">=</span><span class="s2">"look"</span><span class="p">,</span>
|
||
<span class="n">persistent</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||
<span class="n">startnode_input</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span>
|
||
<span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||
<span class="n">debug</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||
<span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> (Object or Account): is a reference to the object using the menu. This object will get a new <a class="reference internal" href="Command-Sets.html"><span class="std std-doc">CmdSet</span></a> assigned to it, for handling the menu.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">menu_data</span></code> (str, module or dict): is a module or python path to a module where the global-level functions will each be considered to be a menu node. Their names in the module will be the names by which they are referred to in the module. Importantly, function names starting with an underscore <code class="docutils literal notranslate"><span class="pre">_</span></code> will be ignored by the loader. Alternatively, this can be a direct mapping
|
||
<code class="docutils literal notranslate"><span class="pre">{"nodename":function,</span> <span class="pre">...}</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">startnode</span></code> (str): is the name of the menu-node to start the menu at. Changing this means that you can jump into a menu tree at different positions depending on circumstance and thus possibly re-use menu entries.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset_mergetype</span></code> (str): This is usually one of “Replace” or “Union” (see [CmdSets](Command- Sets). The first means that the menu is exclusive - the user has no access to any other commands while in the menu. The Union mergetype means the menu co-exists with previous commands (and may overload them, so be careful as to what to name your menu entries in this case).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset_priority</span></code> (int): The priority with which to merge in the menu cmdset. This allows for advanced usage.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">auto_quit</span></code>, <code class="docutils literal notranslate"><span class="pre">auto_look</span></code>, <code class="docutils literal notranslate"><span class="pre">auto_help</span></code> (bool): If either of these are <code class="docutils literal notranslate"><span class="pre">True</span></code>, the menu automatically makes a <code class="docutils literal notranslate"><span class="pre">quit</span></code>, <code class="docutils literal notranslate"><span class="pre">look</span></code> or <code class="docutils literal notranslate"><span class="pre">help</span></code> command available to the user. The main reason why you’d want to turn this off is if you want to use the aliases “q”, “l” or “h” for something in your menu. The <code class="docutils literal notranslate"><span class="pre">auto_help</span></code> also activates the ability to have arbitrary “tool tips” in your menu node (see below), At least <code class="docutils literal notranslate"><span class="pre">quit</span></code> is highly recommend - if <code class="docutils literal notranslate"><span class="pre">False</span></code>, the menu <em>must</em> itself supply an “exit node” (a node without any options), or the user will be stuck in the menu until the server reloads (or eternally if the menu is <code class="docutils literal notranslate"><span class="pre">persistent</span></code>)!</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">cmd_on_exit</span></code> (str): This command string will be executed right <em>after</em> the menu has closed down. From experience, it’s useful to trigger a “look” command to make sure the user is aware of the change of state; but any command can be used. If set to <code class="docutils literal notranslate"><span class="pre">None</span></code>, no command will be triggered after exiting the menu.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (bool) - if <code class="docutils literal notranslate"><span class="pre">True</span></code>, the menu will survive a reload (so the user will not be kicked
|
||
out by the reload - make sure they can exit on their own!)</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">startnode_input</span></code> (str or (str, dict) tuple): Pass an input text or a input text + kwargs to the
|
||
start node as if it was entered on a fictional previous node. This can be very useful in order to
|
||
start a menu differently depending on the Command’s arguments in which it was initialized.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">session</span></code> (Session): Useful when calling the menu from an <a class="reference internal" href="Accounts.html"><span class="std std-doc">Account</span></a> in
|
||
<code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> higher than 2, to make sure only the right Session sees the menu output.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">debug</span></code> (bool): If set, the <code class="docutils literal notranslate"><span class="pre">menudebug</span></code> command will be made available in the menu. Use it to
|
||
list the current state of the menu and use <code class="docutils literal notranslate"><span class="pre">menudebug</span> <span class="pre"><variable></span></code> to inspect a specific state
|
||
variable from the list.</p></li>
|
||
<li><p>All other keyword arguments will be available as initial data for the nodes. They will be available in all nodes as properties on <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> (see below). These will also survive a <code class="docutils literal notranslate"><span class="pre">reload</span></code> if the menu is <code class="docutils literal notranslate"><span class="pre">persistent</span></code>.</p></li>
|
||
</ul>
|
||
<p>You don’t need to store the EvMenu instance anywhere - the very act of initializing it will store it
|
||
as <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> on the <code class="docutils literal notranslate"><span class="pre">caller</span></code>. This object will be deleted automatically when the menu
|
||
is exited and you can also use it to store your own temporary variables for access throughout the
|
||
menu. Temporary variables you store on a persistent <code class="docutils literal notranslate"><span class="pre">_evmenu</span></code> as it runs will
|
||
<em>not</em> survive a <code class="docutils literal notranslate"><span class="pre">@reload</span></code>, only those you set as part of the original <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> call.</p>
|
||
</section>
|
||
<section id="the-menu-nodes">
|
||
<h2>The Menu nodes<a class="headerlink" href="#the-menu-nodes" title="Link to this heading">¶</a></h2>
|
||
<p>The EvMenu nodes consist of functions on one of these forms.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">menunodename1</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="c1"># code</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">menunodename2</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">):</span>
|
||
<span class="c1"># code</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">menunodename3</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="c1"># code</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<blockquote>
|
||
<div><p>While all of the above forms are okay, it’s recommended to stick to the third and last form since it gives the most flexibility. The previous forms are mainly there for backwards compatibility with existing menus from a time when EvMenu was less able and may become deprecated at some time in the future.</p>
|
||
</div></blockquote>
|
||
<section id="input-arguments-to-the-node">
|
||
<h3>Input arguments to the node<a class="headerlink" href="#input-arguments-to-the-node" title="Link to this heading">¶</a></h3>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> (Object or Account): The object using the menu - usually a Character but could also be a Session or Account depending on where the menu is used.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">raw_string</span></code> (str): If this is given, it will be set to the exact text the user entered on the
|
||
<em>previous</em> node (that is, the command entered to get to this node). On the starting-node of the menu, this will be an empty string, unless <code class="docutils literal notranslate"><span class="pre">startnode_input</span></code> was set.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">kwargs</span></code> (dict): These extra keyword arguments are extra optional arguments passed to the node when the user makes a choice on the <em>previous</em> node. This may include things like status flags and details about which exact option was chosen (which can be impossible to determine from
|
||
<code class="docutils literal notranslate"><span class="pre">raw_string</span></code> alone). Just what is passed in <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> is up to you when you create the previous node.</p></li>
|
||
</ul>
|
||
</section>
|
||
<section id="return-values-from-the-node">
|
||
<h3>Return values from the node<a class="headerlink" href="#return-values-from-the-node" title="Link to this heading">¶</a></h3>
|
||
<p>Each node function must return two variables, <code class="docutils literal notranslate"><span class="pre">text</span></code> and <code class="docutils literal notranslate"><span class="pre">options</span></code>.</p>
|
||
<section id="text">
|
||
<h4>text<a class="headerlink" href="#text" title="Link to this heading">¶</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">text</span></code> variable is either a string or a tuple. This is the simplest form:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="o">=</span> <span class="s2">"Node text"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This is what will be displayed as text in the menu node when entering it. You can modify this dynamically in the node if you want. Returning a <code class="docutils literal notranslate"><span class="pre">None</span></code> node text text is allowed - this leads to a node with no text and only options.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"Node text"</span><span class="p">,</span> <span class="s2">"help text to show with h|elp"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In this form, we also add an optional help text. If <code class="docutils literal notranslate"><span class="pre">auto_help=True</span></code> when initializing the EvMenu, the user will be able to use <code class="docutils literal notranslate"><span class="pre">h</span></code> or <code class="docutils literal notranslate"><span class="pre">help</span></code> to see this text when viewing this node. If the user were to provide a custom option overriding <code class="docutils literal notranslate"><span class="pre">h</span></code> or <code class="docutils literal notranslate"><span class="pre">help</span></code>, that will be shown instead.</p>
|
||
<p>If <code class="docutils literal notranslate"><span class="pre">auto_help=True</span></code> and no help text is provided, using <code class="docutils literal notranslate"><span class="pre">h|elp</span></code> will give a generic error message.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"Node text"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"help topic 1"</span><span class="p">:</span> <span class="s2">"Help 1"</span><span class="p">,</span>
|
||
<span class="p">(</span><span class="s2">"help topic 2"</span><span class="p">,</span> <span class="s2">"alias1"</span><span class="p">,</span> <span class="o">...</span><span class="p">):</span> <span class="s2">"Help 2"</span><span class="p">,</span> <span class="o">...</span><span class="p">})</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This is ‘tooltip’ or ‘multi-help category’ mode. This also requires <code class="docutils literal notranslate"><span class="pre">auto_help=True</span></code> when initializing the EvMenu. By providing a <code class="docutils literal notranslate"><span class="pre">dict</span></code> as the second element of the <code class="docutils literal notranslate"><span class="pre">text</span></code> tuple, the user will be able to help about any of these topics. Use a tuple as key to add multiple aliases to the same help entry. This allows the user to get more detailed help text without leaving the given node.</p>
|
||
<p>Note that in ‘tooltip’ mode, the normal <code class="docutils literal notranslate"><span class="pre">h|elp</span></code> command won’t work. The <code class="docutils literal notranslate"><span class="pre">h|elp</span></code> entry must be added manually in the dict. As an example, this would reproduce the normal help functionality:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"Node text"</span><span class="p">,</span> <span class="p">{(</span><span class="s2">"help"</span><span class="p">,</span> <span class="s2">"h"</span><span class="p">):</span> <span class="s2">"Help entry..."</span><span class="p">,</span> <span class="o">...</span><span class="p">})</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="options">
|
||
<h4>options<a class="headerlink" href="#options" title="Link to this heading">¶</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">options</span></code> list describe all the choices available to the user when viewing this node. If <code class="docutils literal notranslate"><span class="pre">options</span></code> is returned as <code class="docutils literal notranslate"><span class="pre">None</span></code>, it means that this node is an <em>Exit node</em> - any text is displayed and then the menu immediately exits, running the <code class="docutils literal notranslate"><span class="pre">exit_cmd</span></code> if given.</p>
|
||
<p>Otherwise, <code class="docutils literal notranslate"><span class="pre">options</span></code> should be a list (or tuple) of dictionaries, one for each option. If only one option is available, a single dictionary can also be returned. This is how it could look:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">node_test</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"A goblin attacks you!"</span>
|
||
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"Attack"</span><span class="p">,</span> <span class="s2">"a"</span><span class="p">,</span> <span class="s2">"att"</span><span class="p">),</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Strike the enemy with all your might"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"node_attack"</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"Defend"</span><span class="p">,</span> <span class="s2">"d"</span><span class="p">,</span> <span class="s2">"def"</span><span class="p">),</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Hold back and defend yourself"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_defend</span><span class="p">,</span> <span class="p">{</span><span class="s2">"str"</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span> <span class="s2">"enemyname"</span><span class="p">:</span> <span class="s2">"Goblin"</span><span class="p">})})</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>This will produce a menu node looking like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>A goblin attacks you!
|
||
________________________________
|
||
|
||
Attack: Strike the enemy with all your might
|
||
Defend: Hold back and defend yourself
|
||
|
||
</pre></div>
|
||
</div>
|
||
<section id="option-key-key">
|
||
<h5>option-key ‘key’<a class="headerlink" href="#option-key-key" title="Link to this heading">¶</a></h5>
|
||
<p>The option’s <code class="docutils literal notranslate"><span class="pre">key</span></code> is what the user should enter in order to choose that option. If given as a tuple, the first string of that tuple will be what is shown on-screen while the rest are aliases for picking that option. In the above example, the user could enter “Attack” (or “attack”, it’s not case-sensitive), “a” or “att” in order to attack the goblin. Aliasing is useful for adding custom coloring to the choice. The first element of the aliasing tuple should then be the colored version, followed by a version without color - since otherwise the user would have to enter the color codes to select that choice.</p>
|
||
<p>Note that the <code class="docutils literal notranslate"><span class="pre">key</span></code> is <em>optional</em>. If no key is given, it will instead automatically be replaced
|
||
with a running number starting from <code class="docutils literal notranslate"><span class="pre">1</span></code>. If removing the <code class="docutils literal notranslate"><span class="pre">key</span></code> part of each option, the resulting
|
||
menu node would look like this instead:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>A goblin attacks you!
|
||
________________________________
|
||
|
||
1: Strike the enemy with all your might
|
||
2: Hold back and defend yourself
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Whether you want to use a key or rely on numbers is mostly a matter of style and the type of menu.</p>
|
||
<p>EvMenu accepts one important special <code class="docutils literal notranslate"><span class="pre">key</span></code> given only as <code class="docutils literal notranslate"><span class="pre">"_default"</span></code>. This key is used when a user enters something that does not match any other fixed keys. It is particularly useful for getting user input:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">node_readuser</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Please enter your name"</span>
|
||
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"_default"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"node_parse_input"</span><span class="p">}</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>A <code class="docutils literal notranslate"><span class="pre">"_default"</span></code> option does not show up in the menu, so the above will just be a node saying
|
||
<code class="docutils literal notranslate"><span class="pre">"Please</span> <span class="pre">enter</span> <span class="pre">your</span> <span class="pre">name"</span></code>. The name they entered will appear as <code class="docutils literal notranslate"><span class="pre">raw_string</span></code> in the next node.</p>
|
||
</section>
|
||
</section>
|
||
<section id="option-key-desc">
|
||
<h4>option-key ‘desc’<a class="headerlink" href="#option-key-desc" title="Link to this heading">¶</a></h4>
|
||
<p>This simply contains the description as to what happens when selecting the menu option. For <code class="docutils literal notranslate"><span class="pre">"_default"</span></code> options or if the <code class="docutils literal notranslate"><span class="pre">key</span></code> is already long or descriptive, it is not strictly needed. But usually it’s better to keep the <code class="docutils literal notranslate"><span class="pre">key</span></code> short and put more detail in <code class="docutils literal notranslate"><span class="pre">desc</span></code>.</p>
|
||
</section>
|
||
<section id="option-key-goto">
|
||
<h4>option-key ‘goto’<a class="headerlink" href="#option-key-goto" title="Link to this heading">¶</a></h4>
|
||
<p>This is the operational part of the option and fires only when the user chooses said option. Here are three ways to write it</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_action_two</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="c1"># do things ...</span>
|
||
<span class="k">return</span> <span class="s2">"calculated_node_to_go_to"</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_action_three</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="c1"># do things ...</span>
|
||
<span class="k">return</span> <span class="s2">"node_four"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"mode"</span><span class="p">:</span> <span class="mi">4</span><span class="p">}</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_select</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
|
||
<span class="n">text</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"select one"</span><span class="p">,</span>
|
||
<span class="s2">"help - they all do different things ..."</span><span class="p">)</span>
|
||
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">({</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Option one"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"node_one"</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Option two"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="n">_action_two</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Option three"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_action_three</span><span class="p">,</span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">"key2"</span><span class="p">:</span> <span class="mi">2</span><span class="p">})}</span>
|
||
<span class="p">)</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>As seen above, <code class="docutils literal notranslate"><span class="pre">goto</span></code> could just be pointing to a single <code class="docutils literal notranslate"><span class="pre">nodename</span></code> string - the name of the node to go to. When given like this, EvMenu will look for a node named like this and call its associated function as</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">nodename</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Here, <code class="docutils literal notranslate"><span class="pre">raw_string</span></code> is always the input the user entered to make that choice and <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> are the same as those <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> that already entered the <em>current</em> node (they are passed on).</p>
|
||
<p>Alternatively the <code class="docutils literal notranslate"><span class="pre">goto</span></code> could point to a “goto-callable”. Such callables are usually defined in the same module as the menu nodes and given names starting with <code class="docutils literal notranslate"><span class="pre">_</span></code> (to avoid being parsed as nodes themselves). These callables will be called the same as a node function - <code class="docutils literal notranslate"><span class="pre">callable(caller,</span> <span class="pre">raw_string,</span> <span class="pre">**kwargs)</span></code>, where <code class="docutils literal notranslate"><span class="pre">raw_string</span></code> is what the user entered on this node and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> is forwarded from the node’s own input.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">goto</span></code> option key could also point to a tuple <code class="docutils literal notranslate"><span class="pre">(callable,</span> <span class="pre">kwargs)</span></code> - this allows for customizing the kwargs passed into the goto-callable, for example you could use the same callable but change the kwargs passed into it depending on which option was actually chosen.</p>
|
||
<p>The “goto callable” must either return a string <code class="docutils literal notranslate"><span class="pre">"nodename"</span></code> or a tuple <code class="docutils literal notranslate"><span class="pre">("nodename",</span> <span class="pre">mykwargs)</span></code>. This will lead to the next node being called as either <code class="docutils literal notranslate"><span class="pre">nodename(caller,</span> <span class="pre">raw_string,</span> <span class="pre">**kwargs)</span></code> or <code class="docutils literal notranslate"><span class="pre">nodename(caller,</span> <span class="pre">raw_string,</span> <span class="pre">**mykwargs)</span></code> - so this allows changing (or replacing) the options going into the next node depending on what option was chosen.</p>
|
||
<p>There is one important case - if the goto-callable returns <code class="docutils literal notranslate"><span class="pre">None</span></code> for a <code class="docutils literal notranslate"><span class="pre">nodename</span></code>, <em>the current node will run again</em>, possibly with different kwargs. This makes it very easy to re-use a node over and over, for example allowing different options to update some text form being passed and manipulated for every iteration.</p>
|
||
</section>
|
||
</section>
|
||
<section id="temporary-storage">
|
||
<h3>Temporary storage<a class="headerlink" href="#temporary-storage" title="Link to this heading">¶</a></h3>
|
||
<p>When the menu starts, the EvMenu instance is stored on the caller as <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code>. Through this object you can in principle reach the menu’s internal state if you know what you are doing. This is also a good place to store temporary, more global variables that may be cumbersome to keep passing from node to node via the <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>. The <code class="docutils literal notranslate"><span class="pre">_evmnenu</span></code> will be deleted automatically when the menu closes, meaning you don’t need to worry about cleaning anything up.</p>
|
||
<p>If you want <em>permanent</em> state storage, it’s instead better to use an Attribute on <code class="docutils literal notranslate"><span class="pre">caller</span></code>. Remember that this will remain after the menu closes though, so you need to handle any needed cleanup yourself.</p>
|
||
</section>
|
||
<section id="customizing-menu-formatting">
|
||
<h3>Customizing Menu formatting<a class="headerlink" href="#customizing-menu-formatting" title="Link to this heading">¶</a></h3>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> display of nodes, options etc are controlled by a series of formatting methods on the <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> class. To customize these, simply create a new child class of <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> and override as needed. Here is an example:</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.utils.evmenu</span><span class="w"> </span><span class="kn">import</span> <span class="n">EvMenu</span>
|
||
|
||
<span class="k">class</span><span class="w"> </span><span class="nc">MyEvMenu</span><span class="p">(</span><span class="n">EvMenu</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">nodetext_formatter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nodetext</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Format the node text itself.</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> nodetext (str): The full node text (the text describing the node).</span>
|
||
|
||
<span class="sd"> Returns:</span>
|
||
<span class="sd"> nodetext (str): The formatted node text.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">helptext_formatter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">helptext</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Format the node's help text</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> helptext (str): The unformatted help text for the node.</span>
|
||
|
||
<span class="sd"> Returns:</span>
|
||
<span class="sd"> helptext (str): The formatted help text.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">options_formatter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">optionlist</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Formats the option block.</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> optionlist (list): List of (key, description) tuples for every</span>
|
||
<span class="sd"> option related to this node.</span>
|
||
<span class="sd"> caller (Object, Account or None, optional): The caller of the node.</span>
|
||
|
||
<span class="sd"> Returns:</span>
|
||
<span class="sd"> options (str): The formatted option display.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_formatter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nodetext</span><span class="p">,</span> <span class="n">optionstext</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Formats the entirety of the node.</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> nodetext (str): The node text as returned by `self.nodetext_formatter`.</span>
|
||
<span class="sd"> optionstext (str): The options display as returned by `self.options_formatter`.</span>
|
||
<span class="sd"> caller (Object, Account or None, optional): The caller of the node.</span>
|
||
|
||
<span class="sd"> Returns:</span>
|
||
<span class="sd"> node (str): The formatted node to display.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>See <code class="docutils literal notranslate"><span class="pre">evennia/utils/evmenu.py</span></code> for the details of their default implementations.</p>
|
||
</section>
|
||
</section>
|
||
<section id="evmenu-templating-language">
|
||
<h2>EvMenu templating language<a class="headerlink" href="#evmenu-templating-language" title="Link to this heading">¶</a></h2>
|
||
<p>In <code class="docutils literal notranslate"><span class="pre">evmenu.py</span></code> are two helper functions <code class="docutils literal notranslate"><span class="pre">parse_menu_template</span></code> and <code class="docutils literal notranslate"><span class="pre">template2menu</span></code> that is used to parse a <em>menu template</em> string into an EvMenu:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evmenu.template2menu(caller, menu_template, goto_callables)
|
||
</pre></div>
|
||
</div>
|
||
<p>One can also do it in two steps, by generate a menutree and using that to call
|
||
EvMenu normally:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>menutree = evmenu.parse_menu_template(caller, menu_template, goto_callables)
|
||
EvMenu(caller, menutree)
|
||
</pre></div>
|
||
</div>
|
||
<p>With this latter solution, one could mix and match normally created menu nodes
|
||
with those generated by the template engine.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">goto_callables</span></code> is a mapping <code class="docutils literal notranslate"><span class="pre">{"funcname":</span> <span class="pre">callable,</span> <span class="pre">...}</span></code>, where each
|
||
callable must be a module-global function on the form
|
||
<code class="docutils literal notranslate"><span class="pre">funcname(caller,</span> <span class="pre">raw_string,</span> <span class="pre">**kwargs)</span></code> (like any goto-callable). The
|
||
<code class="docutils literal notranslate"><span class="pre">menu_template</span></code> is a multi-line string on the following form:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">menu_template</span> <span class="o">=</span> <span class="s2">"""</span>
|
||
|
||
<span class="s2">## node node1</span>
|
||
|
||
<span class="s2">Text for node</span>
|
||
|
||
<span class="s2">## options</span>
|
||
|
||
<span class="s2">key1: desc1 -> node2</span>
|
||
<span class="s2">key2: desc2 -> node3</span>
|
||
<span class="s2">key3: desc3 -> node4</span>
|
||
<span class="s2">"""</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Each menu node is defined by a <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">node</span> <span class="pre"><name></span></code> containing the text of the node,
|
||
followed by <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">options</span></code> Also <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">NODE</span></code> and <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">OPTIONS</span></code> work. No python code
|
||
logics is allowed in the template, this code is not evaluated but parsed. More
|
||
advanced dynamic usage requires a full node-function.</p>
|
||
<p>Except for defining the node/options, <code class="docutils literal notranslate"><span class="pre">#</span></code> act as comments - everything following
|
||
will be ignored by the template parser.</p>
|
||
<section id="template-options">
|
||
<h3>Template Options<a class="headerlink" href="#template-options" title="Link to this heading">¶</a></h3>
|
||
<p>The option syntax is</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span><key>: [desc ->] nodename or function-call
|
||
</pre></div>
|
||
</div>
|
||
<p>The ‘desc’ part is optional, and if that is not given, the <code class="docutils literal notranslate"><span class="pre">-></span></code> can be skipped
|
||
too:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>key: nodename
|
||
</pre></div>
|
||
</div>
|
||
<p>The key can both be strings and numbers. Separate the aliases with <code class="docutils literal notranslate"><span class="pre">;</span></code>.</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>key: node1
|
||
1: node2
|
||
key;k: node3
|
||
foobar;foo;bar;f;b: node4
|
||
</pre></div>
|
||
</div>
|
||
<p>Starting the key with the special letter <code class="docutils literal notranslate"><span class="pre">></span></code> indicates that what follows is a
|
||
glob/regex matcher.</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>>: node1 - matches empty input
|
||
> foo*: node1 - everything starting with foo
|
||
> *foo: node3 - everything ending with foo
|
||
> [0-9]+?: node4 - regex (all numbers)
|
||
> *: node5 - catches everything else (put as last option)
|
||
</pre></div>
|
||
</div>
|
||
<p>Here’s how to call a goto-function from an option:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>key: desc -> myfunc(foo=bar)
|
||
</pre></div>
|
||
</div>
|
||
<p>For this to work <code class="docutils literal notranslate"><span class="pre">template2menu</span></code> or <code class="docutils literal notranslate"><span class="pre">parse_menu_template</span></code> must be given a dict
|
||
that includes <code class="docutils literal notranslate"><span class="pre">{"myfunc":</span> <span class="pre">_actual_myfunc_callable}</span></code>. All callables to be
|
||
available in the template must be mapped this way. Goto callables act like
|
||
normal EvMenu goto-callables and should have a callsign of
|
||
<code class="docutils literal notranslate"><span class="pre">_actual_myfunc_callable(caller,</span> <span class="pre">raw_string,</span> <span class="pre">**kwargs)</span></code> and return the next node
|
||
(passing dynamic kwargs into the next node does not work with the template</p>
|
||
<ul class="simple">
|
||
<li><p>use the full EvMenu if you want advanced dynamic data passing).</p></li>
|
||
</ul>
|
||
<p>Only no or named keywords are allowed in these callables. So</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>myfunc() # OK
|
||
myfunc(foo=bar) # OK
|
||
myfunc(foo) # error!
|
||
</pre></div>
|
||
</div>
|
||
<p>This is because these properties are passed as <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> into the goto callable.</p>
|
||
</section>
|
||
<section id="templating-example">
|
||
<h3>Templating example<a class="headerlink" href="#templating-example" title="Link to this heading">¶</a></h3>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">random</span><span class="w"> </span><span class="kn">import</span> <span class="n">random</span>
|
||
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">evmenu</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_gamble</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</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">"You roll the dice ..."</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">random</span><span class="p">()</span> <span class="o"><</span> <span class="mf">0.5</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"loose"</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"win"</span>
|
||
|
||
<span class="n">template_string</span> <span class="o">=</span> <span class="s2">"""</span>
|
||
|
||
<span class="s2">## node start</span>
|
||
|
||
<span class="s2">Death patiently holds out a set of bone dice to you.</span>
|
||
|
||
<span class="s2">"ROLL"</span>
|
||
|
||
<span class="s2">he says.</span>
|
||
|
||
<span class="s2">## options</span>
|
||
|
||
<span class="s2">1: Roll the dice -> gamble()</span>
|
||
<span class="s2">2: Try to talk yourself out of rolling -> start</span>
|
||
|
||
<span class="s2">## node win</span>
|
||
|
||
<span class="s2">The dice clatter over the stones.</span>
|
||
|
||
<span class="s2">"LOOKS LIKE YOU WIN THIS TIME"</span>
|
||
|
||
<span class="s2">says Death.</span>
|
||
|
||
<span class="s2"># (this ends the menu since there are no options)</span>
|
||
|
||
<span class="s2">## node loose</span>
|
||
|
||
<span class="s2">The dice clatter over the stones.</span>
|
||
|
||
<span class="s2">"YOUR LUCK RAN OUT"</span>
|
||
|
||
<span class="s2">says Death.</span>
|
||
|
||
<span class="s2">"YOU ARE COMING WITH ME."</span>
|
||
|
||
<span class="s2"># (this ends the menu, but what happens next - who knows!)</span>
|
||
|
||
<span class="s2">"""</span>
|
||
|
||
<span class="c1"># map the in-template callable-name to real python code</span>
|
||
<span class="n">goto_callables</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"gamble"</span><span class="p">:</span> <span class="n">_gamble</span><span class="p">}</span>
|
||
<span class="c1"># this starts the evmenu for the caller</span>
|
||
<span class="n">evmenu</span><span class="o">.</span><span class="n">template2menu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">template_string</span><span class="p">,</span> <span class="n">goto_callables</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="asking-for-one-line-input">
|
||
<h2>Asking for one-line input<a class="headerlink" href="#asking-for-one-line-input" title="Link to this heading">¶</a></h2>
|
||
<p>This describes two ways for asking for simple questions from the user. Using Python’s <code class="docutils literal notranslate"><span class="pre">input</span></code>
|
||
will <em>not</em> work in Evennia. <code class="docutils literal notranslate"><span class="pre">input</span></code> will <em>block</em> the entire server for <em>everyone</em> until that one
|
||
player has entered their text, which is not what you want.</p>
|
||
<section id="the-yield-way">
|
||
<h3>The <code class="docutils literal notranslate"><span class="pre">yield</span></code> way<a class="headerlink" href="#the-yield-way" title="Link to this heading">¶</a></h3>
|
||
<p>In the <code class="docutils literal notranslate"><span class="pre">func</span></code> method of your Commands (only) you can use Python’s built-in <code class="docutils literal notranslate"><span class="pre">yield</span></code> command to
|
||
request input in a similar way to <code class="docutils literal notranslate"><span class="pre">input</span></code>. It looks like this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">result</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Please enter your answer:"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This will send “Please enter your answer” to the Command’s <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> and then pause at that
|
||
point. All other players at the server will be unaffected. Once caller enteres a reply, the code
|
||
execution will continue and you can do stuff with the <code class="docutils literal notranslate"><span class="pre">result</span></code>. Here is an example:</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</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">CmdTestInput</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">"test"</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">result</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Please enter something:"</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">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You entered </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||
<span class="n">result2</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Now enter something else:"</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">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You now entered </span><span class="si">{</span><span class="n">result2</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Using <code class="docutils literal notranslate"><span class="pre">yield</span></code> is simple and intuitive, but it will only access input from <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> and you
|
||
cannot abort or time out the pause until the player has responded. Under the hood, it is actually
|
||
just a wrapper calling <code class="docutils literal notranslate"><span class="pre">get_input</span></code> described in the following section.</p>
|
||
<blockquote>
|
||
<div><p>Important Note: In Python you <em>cannot mix <code class="docutils literal notranslate"><span class="pre">yield</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code> in the same method</em>. It has
|
||
to do with <code class="docutils literal notranslate"><span class="pre">yield</span></code> turning the method into a
|
||
<a class="reference external" href="https://www.learnpython.org/en/Generators">generator</a>. A <code class="docutils literal notranslate"><span class="pre">return</span></code> without an argument works, you
|
||
can just not do <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code>. This is usually not something you need to do in <code class="docutils literal notranslate"><span class="pre">func()</span></code> anyway,
|
||
but worth keeping in mind.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="the-get-input-way">
|
||
<h3>The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> way<a class="headerlink" href="#the-get-input-way" title="Link to this heading">¶</a></h3>
|
||
<p>The evmenu module offers a helper function named <code class="docutils literal notranslate"><span class="pre">get_input</span></code>. This is wrapped by the <code class="docutils literal notranslate"><span class="pre">yield</span></code>
|
||
statement which is often easier and more intuitive to use. But <code class="docutils literal notranslate"><span class="pre">get_input</span></code> offers more flexibility
|
||
and power if you need it. While in the same module as <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>, <code class="docutils literal notranslate"><span class="pre">get_input</span></code> is technically unrelated
|
||
to it. The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> allows you to ask and receive simple one-line input from the user without
|
||
launching the full power of a menu to do so. To use, call <code class="docutils literal notranslate"><span class="pre">get_input</span></code> like this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Here <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the entity that should receive the prompt for input given as <code class="docutils literal notranslate"><span class="pre">prompt</span></code>. The
|
||
<code class="docutils literal notranslate"><span class="pre">callback</span></code> is a callable <code class="docutils literal notranslate"><span class="pre">function(caller,</span> <span class="pre">prompt,</span> <span class="pre">user_input)</span></code> that you define to handle the answer
|
||
from the user. When run, the caller will see <code class="docutils literal notranslate"><span class="pre">prompt</span></code> appear on their screens and <em>any</em> text they
|
||
enter will be sent into the callback for whatever processing you want.</p>
|
||
<p>Below is a fully explained callback and example call:</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</span><span class="w"> </span><span class="kn">import</span> <span class="n">Command</span>
|
||
<span class="kn">from</span><span class="w"> </span><span class="nn">evennia.utils.evmenu</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_input</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> This is a callback you define yourself.</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> caller (Account or Object): The one being asked</span>
|
||
<span class="sd"> for input</span>
|
||
<span class="sd"> prompt (str): A copy of the current prompt</span>
|
||
<span class="sd"> user_input (str): The input from the account.</span>
|
||
|
||
<span class="sd"> Returns:</span>
|
||
<span class="sd"> repeat (bool): If not set or False, exit the</span>
|
||
<span class="sd"> input prompt and clean up. If returning anything</span>
|
||
<span class="sd"> True, stay in the prompt, which means this callback</span>
|
||
<span class="sd"> will be called again with the next user input.</span>
|
||
<span class="sd"> """</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">"When asked '</span><span class="si">{</span><span class="n">prompt</span><span class="si">}</span><span class="s2">', you answered '</span><span class="si">{</span><span class="n">user_input</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
|
||
|
||
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"Write something! "</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This will show as</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Write something!
|
||
> Hello
|
||
When asked 'Write something!', you answered 'Hello'.
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Normally, the <code class="docutils literal notranslate"><span class="pre">get_input</span></code> function quits after any input, but as seen in the example docs, you could
|
||
return True from the callback to repeat the prompt until you pass whatever check you want.</p>
|
||
<blockquote>
|
||
<div><p>Note: You <em>cannot</em> link consecutive questions by putting a new <code class="docutils literal notranslate"><span class="pre">get_input</span></code> call inside the
|
||
callback If you want that you should use an EvMenu instead (see the <a class="reference internal" href="#example-repeating-the-same-node"><span class="std std-ref">Repeating the same
|
||
node</span></a> example above). Otherwise you can either peek at the
|
||
implementation of <code class="docutils literal notranslate"><span class="pre">get_input</span></code> and implement your own mechanism (it’s just using cmdset nesting) or
|
||
you can look at <a class="reference external" href="https://groups.google.com/forum/#!category-topic/evennia/evennia-questions/16pi0SfMO5U">this extension suggested on the mailing
|
||
list</a>.</p>
|
||
</div></blockquote>
|
||
<section id="example-yes-no-prompt">
|
||
<h4>Example: Yes/No prompt<a class="headerlink" href="#example-yes-no-prompt" title="Link to this heading">¶</a></h4>
|
||
<p>Below is an example of a Yes/No prompt using the <code class="docutils literal notranslate"><span class="pre">get_input</span></code> function:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">yesno</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">result</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"n"</span><span class="p">,</span> <span class="s2">"no"</span><span class="p">):</span>
|
||
<span class="c1"># do stuff to handle the yes/no answer</span>
|
||
<span class="c1"># ...</span>
|
||
<span class="c1"># if we return None/False the prompt state</span>
|
||
<span class="c1"># will quit after this</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># the answer is not on the right yes/no form</span>
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Please answer Yes or No. </span><span class="se">\n</span><span class="si">{prompt}</span><span class="s2">"</span><span class="p">)</span>
|
||
<span class="o">@</span> <span class="c1"># returning True will make sure the prompt state is not exited</span>
|
||
<span class="k">return</span> <span class="kc">True</span>
|
||
|
||
<span class="c1"># ask the question</span>
|
||
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"Is Evennia great (Yes/No)?"</span><span class="p">,</span> <span class="n">yesno</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="the-list-node-decorator">
|
||
<h2>The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator<a class="headerlink" href="#the-list-node-decorator" title="Link to this heading">¶</a></h2>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmenu.list_node</span></code> is an advanced decorator for use with <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> node functions.
|
||
It is used to quickly create menus for manipulating large numbers of items.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="n">here</span>
|
||
<span class="n">______________________________________________</span>
|
||
|
||
<span class="mf">1.</span> <span class="n">option1</span> <span class="mf">7.</span> <span class="n">option7</span> <span class="mf">13.</span> <span class="n">option13</span>
|
||
<span class="mf">2.</span> <span class="n">option2</span> <span class="mf">8.</span> <span class="n">option8</span> <span class="mf">14.</span> <span class="n">option14</span>
|
||
<span class="mf">3.</span> <span class="n">option3</span> <span class="mf">9.</span> <span class="n">option9</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="n">revius</span> <span class="n">page</span>
|
||
<span class="mf">4.</span> <span class="n">option4</span> <span class="mf">10.</span> <span class="n">option10</span> <span class="n">page</span> <span class="mi">2</span>
|
||
<span class="mf">5.</span> <span class="n">option5</span> <span class="mf">11.</span> <span class="n">option11</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="n">ext</span> <span class="n">page</span>
|
||
<span class="mf">6.</span> <span class="n">option6</span> <span class="mf">12.</span> <span class="n">option12</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>The menu will automatically create an multi-page option listing that one can flip through. One can
|
||
inpect each entry and then select them with prev/next. This is how it is used:</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.utils.evmenu</span><span class="w"> </span><span class="kn">import</span> <span class="n">list_node</span>
|
||
|
||
|
||
<span class="o">...</span>
|
||
|
||
<span class="n">_options</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="p">[</span><span class="s1">'option1'</span><span class="p">,</span> <span class="s1">'option2'</span><span class="p">,</span> <span class="o">...</span> <span class="s1">'option100'</span><span class="p">]</span>
|
||
|
||
<span class="n">_select</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menuchoice</span><span class="p">,</span> <span class="n">available_choices</span><span class="p">):</span>
|
||
<span class="c1"># analyze choice</span>
|
||
<span class="k">return</span> <span class="s2">"next_node"</span>
|
||
|
||
<span class="nd">@list_node</span><span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">select</span><span class="o">=</span><span class="n">_select</span><span class="p">,</span> <span class="n">pagesize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_mylist</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">options</span></code> argument to <code class="docutils literal notranslate"><span class="pre">list_node</span></code> is either a list, a generator or a callable returning a list
|
||
of strings for each option that should be displayed in the node.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">select</span></code> is a callable in the example above but could also be the name of a menu node. If a
|
||
callable, the <code class="docutils literal notranslate"><span class="pre">menuchoice</span></code> argument holds the selection done and <code class="docutils literal notranslate"><span class="pre">available_choices</span></code> holds all the
|
||
options available. The callable should return the menu to go to depending on the selection (or
|
||
<code class="docutils literal notranslate"><span class="pre">None</span></code> to rerun the same node). If the name of a menu node, the selection will be passed as
|
||
<code class="docutils literal notranslate"><span class="pre">selection</span></code> kwarg to that node.</p>
|
||
<p>The decorated node itself should return <code class="docutils literal notranslate"><span class="pre">text</span></code> to display in the node. It must return at least an
|
||
empty dictionary for its options. It returning options, those will supplement the options
|
||
auto-created by the <code class="docutils literal notranslate"><span class="pre">list_node</span></code> decorator.</p>
|
||
</section>
|
||
<section id="example-menus">
|
||
<h2>Example Menus<a class="headerlink" href="#example-menus" title="Link to this heading">¶</a></h2>
|
||
<p>Here is a diagram to help visualize the flow of data from node to node, including goto-callables in-between:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> ┌─
|
||
│ def nodeA(caller, raw_string, **kwargs):
|
||
│ text = "Choose how to operate on 2 and 3."
|
||
│ options = (
|
||
│ {
|
||
│ "key": "A",
|
||
│ "desc": "Multiply 2 with 3",
|
||
│ "goto": (_callback, {"type": "mult", "a": 2, "b": 3})
|
||
│ }, ───────────────────┬────────────
|
||
│ { │
|
||
│ "key": "B", └───────────────┐
|
||
│ "desc": "Add 2 and 3", │
|
||
Node A│ "goto": (_callback, {"type": "add", "a": 2, "b": 3}) │
|
||
│ }, ─────────────────┬───────────── │
|
||
│ { │ │
|
||
│ "key": "C", │ │
|
||
│ "desc": "Show the value 5", │ │
|
||
│ "goto": ("node_B", {"c": 5}) │ │
|
||
│ } ───────┐ │ │
|
||
│ ) └──────────┼─────────────────┼───┐
|
||
│ return text, options │ │ │
|
||
└─ ┌──────────┘ │ │
|
||
│ │ │
|
||
│ ┌──────────────────────────┘ │
|
||
┌─ ▼ ▼ │
|
||
│ def _callback(caller, raw_string, **kwargs): │
|
||
│ if kwargs["type"] == "mult": │
|
||
│ return "node_B", {"c": kwargs["a"] * kwargs["b"]} │
|
||
Goto- │ ───────────────┬──────────────── │
|
||
callable│ │ │
|
||
│ └───────────────────┐ │
|
||
│ │ │
|
||
│ elif kwargs["type"] == "add": │ │
|
||
│ return "node_B", {"c": kwargs["a"] + kwargs["b"]} │ │
|
||
└─ ────────┬─────────────────────── │ │
|
||
│ │ │
|
||
│ ┌────────────────────────┼──────────┘
|
||
│ │ │
|
||
│ │ ┌──────────────────────┘
|
||
┌─ ▼ ▼ ▼
|
||
│ def nodeB(caller, raw_string, **kwargs):
|
||
Node B│ text = "Result of operation: " + kwargs["c"]
|
||
│ return text, {}
|
||
└─
|
||
|
||
┌─
|
||
Menu │ EvMenu(caller, {"node_A": nodeA, "node_B": nodeB}, startnode="node_A")
|
||
Start│
|
||
└─
|
||
</pre></div>
|
||
</div>
|
||
<p>Above we create a very simple/stupid menu (in the <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> call at the end) where we map the node identifier <code class="docutils literal notranslate"><span class="pre">"node_A"</span></code> to the Python function <code class="docutils literal notranslate"><span class="pre">nodeA</span></code> and <code class="docutils literal notranslate"><span class="pre">"node_B"</span></code> to the function <code class="docutils literal notranslate"><span class="pre">nodeB</span></code>.</p>
|
||
<p>We start the menu in <code class="docutils literal notranslate"><span class="pre">"node_A"</span></code> where we get three options A, B and C. Options A and B will route via a a goto-callable <code class="docutils literal notranslate"><span class="pre">_callback</span></code> that either multiples or adds the numbers 2 and 3 together before continuing to <code class="docutils literal notranslate"><span class="pre">"node_B"</span></code>. Option C routes directly to <code class="docutils literal notranslate"><span class="pre">"node_B"</span></code>, passing the number 5.</p>
|
||
<p>In every step, we pass a dict which becomes the ingoing <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> in the next step. If we didn’t pass anything (it’s optional), the next step’s <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> would just be empty.</p>
|
||
<p>More examples:</p>
|
||
<ul class="simple">
|
||
<li><p><strong><a class="reference internal" href="#example-simple-branching-menu"><span class="std std-ref">Simple branching menu</span></a></strong> - choose from options</p></li>
|
||
<li><p><strong><a class="reference internal" href="#example-dynamic-goto"><span class="std std-ref">Dynamic goto</span></a></strong> - jumping to different nodes based on response</p></li>
|
||
<li><p><strong><a class="reference internal" href="#example-set-caller-properties"><span class="std std-ref">Set caller properties</span></a></strong> - a menu that changes things</p></li>
|
||
<li><p><strong><a class="reference internal" href="#example-get-arbitrary-input"><span class="std std-ref">Getting arbitrary input</span></a></strong> - entering text</p></li>
|
||
<li><p><strong><a class="reference internal" href="#example-storing-data-between-nodes"><span class="std std-ref">Storing data between nodes</span></a></strong> - keeping states and
|
||
information while in the menu</p></li>
|
||
<li><p><strong><a class="reference internal" href="#example-repeating-the-same-node"><span class="std std-ref">Repeating the same node</span></a></strong> - validating within the node
|
||
before moving to the next</p></li>
|
||
<li><p><strong><a class="reference internal" href="#example-yes-no-prompt">Yes/No prompt</a></strong> - entering text with limited possible responses
|
||
(this is <em>not</em> using EvMenu but the conceptually similar yet technically unrelated <code class="docutils literal notranslate"><span class="pre">get_input</span></code>
|
||
helper function accessed as <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmenu.get_input</span></code>).</p></li>
|
||
</ul>
|
||
<section id="example-simple-branching-menu">
|
||
<h3>Example: Simple branching menu<a class="headerlink" href="#example-simple-branching-menu" title="Link to this heading">¶</a></h3>
|
||
<p>Below is an example of a simple branching menu node leading to different other nodes depending on choice:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/world/mychargen.py</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">define_character</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> \
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> What aspect of your character do you want</span>
|
||
<span class="sd"> to change next?</span>
|
||
<span class="sd"> """</span>
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">({</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Change the name"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"set_name"</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Change the description"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"set_description"</span><span class="p">})</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"world.mychargen"</span><span class="p">,</span> <span class="n">startnode</span><span class="o">=</span><span class="s2">"define_character"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>This will result in the following node display:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>What aspect of your character do you want
|
||
to change next?
|
||
_________________________
|
||
1: Change the name
|
||
2: Change the description
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that since we didn’t specify the “name” key, EvMenu will let the user enter numbers instead. In
|
||
the following examples we will not include the <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> call but just show nodes running inside the
|
||
menu. Also, since <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> also takes a dictionary to describe the menu, we could have called it
|
||
like this instead in the example:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="p">{</span><span class="s2">"define_character"</span><span class="p">:</span> <span class="n">define_character</span><span class="p">},</span> <span class="n">startnode</span><span class="o">=</span><span class="s2">"define_character"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="example-dynamic-goto">
|
||
<h3>Example: Dynamic goto<a class="headerlink" href="#example-dynamic-goto" title="Link to this heading">¶</a></h3>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_is_in_mage_guild</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">caller</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'mage'</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"guild_member"</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="s2">"mage_guild_welcome"</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"mage_guild_blocked"</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">enter_guild</span><span class="p">:</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s1">'You say to the mage guard:'</span>
|
||
<span class="n">options</span> <span class="p">({</span><span class="s1">'desc'</span><span class="p">:</span> <span class="s1">'I need to get in there.'</span><span class="p">,</span>
|
||
<span class="s1">'goto'</span><span class="p">:</span> <span class="n">_is_in_mage_guild</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s1">'desc'</span><span class="p">:</span> <span class="s1">'Never mind'</span><span class="p">,</span>
|
||
<span class="s1">'goto'</span><span class="p">:</span> <span class="s1">'end_conversation'</span><span class="p">})</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This simple callable goto will analyse what happens depending on who the <code class="docutils literal notranslate"><span class="pre">caller</span></code> is. The
|
||
<code class="docutils literal notranslate"><span class="pre">enter_guild</span></code> node will give you a choice of what to say to the guard. If you try to enter, you will
|
||
end up in different nodes depending on (in this example) if you have the right <a class="reference internal" href="Tags.html"><span class="std std-doc">Tag</span></a> set on
|
||
yourself or not. Note that since we don’t include any ‘key’s in the option dictionary, you will just
|
||
get to pick between numbers.</p>
|
||
</section>
|
||
<section id="example-set-caller-properties">
|
||
<h3>Example: Set caller properties<a class="headerlink" href="#example-set-caller-properties" title="Link to this heading">¶</a></h3>
|
||
<p>Here is an example of passing arguments into the <code class="docutils literal notranslate"><span class="pre">goto</span></code> callable and use that to influence
|
||
which node it should go to next:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_set_attribute</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="s2">"Get which attribute to modify and set it"</span>
|
||
|
||
<span class="n">attrname</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"attr"</span><span class="p">,</span> <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">))</span>
|
||
<span class="n">next_node</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"next_node"</span><span class="p">)</span>
|
||
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">attrname</span><span class="p">,</span> <span class="n">attrvalue</span><span class="p">)</span>
|
||
|
||
<span class="k">return</span> <span class="n">next_node</span>
|
||
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_background</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> \
|
||
<span class="sa">f</span><span class="s2">"""</span>
|
||
<span class="s2"> </span><span class="si">{</span><span class="n">caller</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> experienced a traumatic event</span>
|
||
<span class="s2"> in their childhood. What was it?</span>
|
||
<span class="s2"> """</span>
|
||
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">({</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"death"</span><span class="p">,</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"A violent death in the family"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_set_attribute</span><span class="p">,</span> <span class="p">{</span><span class="s2">"attr"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"experienced_violence"</span><span class="p">,</span> <span class="kc">True</span><span class="p">),</span>
|
||
<span class="s2">"next_node"</span><span class="p">:</span> <span class="s2">"node_violent_background"</span><span class="p">})},</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"betrayal"</span><span class="p">,</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"The betrayal of a trusted grown-up"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_set_attribute</span><span class="p">,</span> <span class="p">{</span><span class="s2">"attr"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"experienced_betrayal"</span><span class="p">,</span> <span class="kc">True</span><span class="p">),</span>
|
||
<span class="s2">"next_node"</span><span class="p">:</span> <span class="s2">"node_betrayal_background"</span><span class="p">})})</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This will give the following output:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Kovash the magnificent experienced a traumatic event
|
||
in their childhood. What was it?
|
||
____________________________________________________
|
||
death: A violent death in the family
|
||
betrayal: The betrayal of a trusted grown-up
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Note above how we use the <code class="docutils literal notranslate"><span class="pre">_set_attribute</span></code> helper function to set the attribute depending on the
|
||
User’s choice. In thie case the helper function doesn’t know anything about what node called it - we
|
||
even tell it which nodename it should return, so the choices leads to different paths in the menu.
|
||
We could also imagine the helper function analyzing what other choices</p>
|
||
</section>
|
||
<section id="example-get-arbitrary-input">
|
||
<h3>Example: Get arbitrary input<a class="headerlink" href="#example-get-arbitrary-input" title="Link to this heading">¶</a></h3>
|
||
<p>An example of the menu asking the user for input - any input.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_set_name</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
|
||
<span class="n">inp</span> <span class="o">=</span> <span class="n">raw_string</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||
|
||
<span class="n">prev_entry</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"prev_entry"</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">inp</span><span class="p">:</span>
|
||
<span class="c1"># a blank input either means OK or Abort</span>
|
||
<span class="k">if</span> <span class="n">prev_entry</span><span class="p">:</span>
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">prev_entry</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">"Set name to </span><span class="si">{</span><span class="n">prev_entry</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="s2">"node_background"</span>
|
||
<span class="k">else</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">"Aborted."</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="s2">"node_exit"</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># re-run old node, but pass in the name given</span>
|
||
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="p">{</span><span class="s2">"prev_entry"</span><span class="p">:</span> <span class="n">inp</span><span class="p">}</span>
|
||
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">enter_name</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
|
||
<span class="c1"># check if we already entered a name before</span>
|
||
<span class="n">prev_entry</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"prev_entry"</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="n">prev_entry</span><span class="p">:</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Current name: </span><span class="si">{}</span><span class="s2">.</span><span class="se">\n</span><span class="s2">Enter another name or <return> to accept."</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Enter your character's name or <return> to abort."</span>
|
||
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"_default"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_set_name</span><span class="p">,</span> <span class="p">{</span><span class="s2">"prev_entry"</span><span class="p">:</span> <span class="n">prev_entry</span><span class="p">})}</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>This will display as</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Enter</span> <span class="n">your</span> <span class="n">character</span><span class="s1">'s name or <return> to abort.</span>
|
||
|
||
<span class="o">></span> <span class="n">Gandalf</span>
|
||
|
||
<span class="n">Current</span> <span class="n">name</span><span class="p">:</span> <span class="n">Gandalf</span>
|
||
<span class="n">Enter</span> <span class="n">another</span> <span class="n">name</span> <span class="ow">or</span> <span class="o"><</span><span class="k">return</span><span class="o">></span> <span class="n">to</span> <span class="n">accept</span><span class="o">.</span>
|
||
|
||
<span class="o">></span>
|
||
|
||
<span class="n">Set</span> <span class="n">name</span> <span class="n">to</span> <span class="n">Gandalf</span><span class="o">.</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Here we re-use the same node twice for reading the input data from the user. Whatever we enter will
|
||
be caught by the <code class="docutils literal notranslate"><span class="pre">_default</span></code> option and passed into the helper function. We also pass along whatever
|
||
name we have entered before. This allows us to react correctly on an “empty” input - continue to the
|
||
node named <code class="docutils literal notranslate"><span class="pre">"node_background"</span></code> if we accept the input or go to an exit node if we presses Return
|
||
without entering anything. By returning <code class="docutils literal notranslate"><span class="pre">None</span></code> from the helper function we automatically re-run the
|
||
previous node, but updating its ingoing kwargs to tell it to display a different text.</p>
|
||
</section>
|
||
<section id="example-storing-data-between-nodes">
|
||
<h3>Example: Storing data between nodes<a class="headerlink" href="#example-storing-data-between-nodes" title="Link to this heading">¶</a></h3>
|
||
<p>A convenient way to store data is to store it on the <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> which you can reach from
|
||
every node. The advantage of doing this is that the <code class="docutils literal notranslate"><span class="pre">_evmenu</span></code> NAttribute will be deleted
|
||
automatically when you exit the menu.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_set_name</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">_evmenu</span><span class="o">.</span><span class="n">charactersheet</span> <span class="o">=</span> <span class="p">{}</span>
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">_evmenu</span><span class="o">.</span><span class="n">charactersheet</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">=</span> <span class="n">raw_string</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">"You set your name to </span><span class="si">{</span><span class="n">raw_string</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="s2">"background"</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_set_name</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s1">'Enter your name:'</span>
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'key'</span><span class="p">:</span> <span class="s1">'_default'</span><span class="p">,</span>
|
||
<span class="s1">'goto'</span><span class="p">:</span> <span class="n">_set_name</span><span class="p">}</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
<span class="o">...</span>
|
||
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_view_sheet</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Character sheet:</span><span class="se">\n</span><span class="s2"> </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">_evmenu</span><span class="o">.</span><span class="n">charactersheet</span><span class="si">}</span><span class="s2">"</span>
|
||
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">({</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"Accept"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"finish_chargen"</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"Decline"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"start_over"</span><span class="p">})</span>
|
||
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Instead of passing the character sheet along from node to node through the <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> we instead
|
||
set it up temporarily on <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu.charactersheet</span></code>. This makes it easy to reach from
|
||
all nodes. At the end we look at it and, if we accept the character the menu will likely save the
|
||
result to permanent storage and exit.</p>
|
||
<blockquote>
|
||
<div><p>One point to remember though is that storage on <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> is not persistent across
|
||
<code class="docutils literal notranslate"><span class="pre">@reloads</span></code>. If you are using a persistent menu (using <code class="docutils literal notranslate"><span class="pre">EvMenu(...,</span> <span class="pre">persistent=True)</span></code> you should
|
||
use
|
||
<code class="docutils literal notranslate"><span class="pre">caller.db</span></code> to store in-menu data like this as well. You must then yourself make sure to clean it
|
||
when the user exits the menu.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="example-repeating-the-same-node">
|
||
<h3>Example: Repeating the same node<a class="headerlink" href="#example-repeating-the-same-node" title="Link to this heading">¶</a></h3>
|
||
<p>Sometimes you want to make a chain of menu nodes one after another, but you don’t want the user to be able to continue to the next node until you have verified that what they input in the previous node is ok. A common example is a login menu:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_check_username</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="c1"># we assume lookup_username() exists</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">lookup_username</span><span class="p">(</span><span class="n">raw_string</span><span class="p">):</span>
|
||
<span class="c1"># re-run current node by returning `None`</span>
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"|rUsername not found. Try again."</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="kc">None</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># username ok - continue to next node</span>
|
||
<span class="k">return</span> <span class="s2">"node_password"</span>
|
||
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_username</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Please enter your user name."</span>
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"_default"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="n">_check_username</span><span class="p">}</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">_check_password</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
|
||
<span class="n">nattempts</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"nattempts"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">nattempts</span> <span class="o">></span> <span class="mi">3</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">"Too many failed attempts. Logging out"</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="s2">"node_abort"</span>
|
||
<span class="k">elif</span> <span class="ow">not</span> <span class="n">validate_password</span><span class="p">(</span><span class="n">raw_string</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">"Password error. Try again."</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="p">{</span><span class="s2">"nattempts"</span><span class="p">,</span> <span class="n">nattempts</span> <span class="o">+</span> <span class="mi">1</span><span class="p">}</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># password accepted</span>
|
||
<span class="k">return</span> <span class="s2">"node_login"</span>
|
||
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">node_password</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Enter your password."</span>
|
||
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"_default"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="n">_check_password</span><span class="p">}</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>This will display something like</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">---------------------------</span>
|
||
<span class="n">Please</span> <span class="n">enter</span> <span class="n">your</span> <span class="n">username</span><span class="o">.</span>
|
||
<span class="o">---------------------------</span>
|
||
|
||
<span class="o">></span> <span class="n">Fo</span>
|
||
|
||
<span class="o">------------------------------</span>
|
||
<span class="n">Username</span> <span class="ow">not</span> <span class="n">found</span><span class="o">.</span> <span class="n">Try</span> <span class="n">again</span><span class="o">.</span>
|
||
<span class="n">______________________________</span>
|
||
<span class="n">abort</span><span class="p">:</span> <span class="p">(</span><span class="n">back</span> <span class="n">to</span> <span class="n">start</span><span class="p">)</span>
|
||
<span class="o">------------------------------</span>
|
||
|
||
<span class="o">></span> <span class="n">Foo</span>
|
||
|
||
<span class="o">---------------------------</span>
|
||
<span class="n">Please</span> <span class="n">enter</span> <span class="n">your</span> <span class="n">password</span><span class="o">.</span>
|
||
<span class="o">---------------------------</span>
|
||
|
||
<span class="o">></span> <span class="n">Bar</span>
|
||
|
||
<span class="o">--------------------------</span>
|
||
<span class="n">Password</span> <span class="n">error</span><span class="o">.</span> <span class="n">Try</span> <span class="n">again</span><span class="o">.</span>
|
||
<span class="o">--------------------------</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>And so on.</p>
|
||
<p>Here the goto-callables will return to the previous node if there is an error. In the case of
|
||
password attempts, this will tick up the <code class="docutils literal notranslate"><span class="pre">nattempts</span></code> argument that will get passed on from iteration
|
||
to iteration until too many attempts have been made.</p>
|
||
</section>
|
||
<section id="defining-nodes-in-a-dictionary">
|
||
<h3>Defining nodes in a dictionary<a class="headerlink" href="#defining-nodes-in-a-dictionary" title="Link to this heading">¶</a></h3>
|
||
<p>You can also define your nodes directly in a dictionary to feed into the <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> creator.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">mynode</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
<span class="c1"># a normal menu node function</span>
|
||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||
|
||
<span class="n">menu_data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"node1"</span><span class="p">:</span> <span class="n">mynode</span><span class="p">,</span>
|
||
<span class="s2">"node2"</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">caller</span><span class="p">:</span> <span class="p">(</span>
|
||
<span class="s2">"This is the node text"</span><span class="p">,</span>
|
||
<span class="p">({</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"lambda node 1"</span><span class="p">,</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"go to node 1 (mynode)"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"node1"</span><span class="p">},</span>
|
||
<span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"lambda node 2"</span><span class="p">,</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"go to thirdnode"</span><span class="p">,</span>
|
||
<span class="s2">"goto"</span><span class="p">:</span> <span class="s2">"node3"</span><span class="p">})),</span>
|
||
<span class="s2">"node3"</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">:</span> <span class="p">(</span>
|
||
<span class="c1"># ... etc ) }</span>
|
||
|
||
<span class="c1"># start menu, assuming 'caller' is available from earlier</span>
|
||
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menu_data</span><span class="p">,</span> <span class="n">startnode</span><span class="o">=</span><span class="s2">"node1"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>The keys of the dictionary become the node identifiers. You can use any callable on the right form
|
||
to describe each node. If you use Python <code class="docutils literal notranslate"><span class="pre">lambda</span></code> expressions you can make nodes really on the fly.
|
||
If you do, the lambda expression must accept one or two arguments and always return a tuple with two
|
||
elements (the text of the node and its options), same as any menu node function.</p>
|
||
<p>Creating menus like this is one way to present a menu that changes with the circumstances - you
|
||
could for example remove or add nodes before launching the menu depending on some criteria. The
|
||
drawback is that a <code class="docutils literal notranslate"><span class="pre">lambda</span></code> expression <a class="reference external" href="https://docs.python.org/2/tutorial/controlflow.html#lambda-expressions">is much more
|
||
limited</a> than a full
|
||
function - for example you can’t use other Python keywords like <code class="docutils literal notranslate"><span class="pre">if</span></code> inside the body of the
|
||
<code class="docutils literal notranslate"><span class="pre">lambda</span></code>.</p>
|
||
<p>Unless you are dealing with a relatively simple dynamic menu, defining menus with lambda’s is
|
||
probably more work than it’s worth: You can create dynamic menus by instead making each node
|
||
function more clever. See the <a class="reference internal" href="../Howtos/Tutorial-NPC-Merchants.html"><span class="std std-doc">NPC shop tutorial</span></a> for an example of this.</p>
|
||
</section>
|
||
</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="#">EvMenu</a><ul>
|
||
<li><a class="reference internal" href="#launching-the-menu">Launching the menu</a></li>
|
||
<li><a class="reference internal" href="#the-menu-nodes">The Menu nodes</a><ul>
|
||
<li><a class="reference internal" href="#input-arguments-to-the-node">Input arguments to the node</a></li>
|
||
<li><a class="reference internal" href="#return-values-from-the-node">Return values from the node</a><ul>
|
||
<li><a class="reference internal" href="#text">text</a></li>
|
||
<li><a class="reference internal" href="#options">options</a><ul>
|
||
<li><a class="reference internal" href="#option-key-key">option-key ‘key’</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#option-key-desc">option-key ‘desc’</a></li>
|
||
<li><a class="reference internal" href="#option-key-goto">option-key ‘goto’</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#temporary-storage">Temporary storage</a></li>
|
||
<li><a class="reference internal" href="#customizing-menu-formatting">Customizing Menu formatting</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#evmenu-templating-language">EvMenu templating language</a><ul>
|
||
<li><a class="reference internal" href="#template-options">Template Options</a></li>
|
||
<li><a class="reference internal" href="#templating-example">Templating example</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#asking-for-one-line-input">Asking for one-line input</a><ul>
|
||
<li><a class="reference internal" href="#the-yield-way">The <code class="docutils literal notranslate"><span class="pre">yield</span></code> way</a></li>
|
||
<li><a class="reference internal" href="#the-get-input-way">The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> way</a><ul>
|
||
<li><a class="reference internal" href="#example-yes-no-prompt">Example: Yes/No prompt</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#the-list-node-decorator">The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator</a></li>
|
||
<li><a class="reference internal" href="#example-menus">Example Menus</a><ul>
|
||
<li><a class="reference internal" href="#example-simple-branching-menu">Example: Simple branching menu</a></li>
|
||
<li><a class="reference internal" href="#example-dynamic-goto">Example: Dynamic goto</a></li>
|
||
<li><a class="reference internal" href="#example-set-caller-properties">Example: Set caller properties</a></li>
|
||
<li><a class="reference internal" href="#example-get-arbitrary-input">Example: Get arbitrary input</a></li>
|
||
<li><a class="reference internal" href="#example-storing-data-between-nodes">Example: Storing data between nodes</a></li>
|
||
<li><a class="reference internal" href="#example-repeating-the-same-node">Example: Repeating the same node</a></li>
|
||
<li><a class="reference internal" href="#defining-nodes-in-a-dictionary">Defining nodes in a dictionary</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<div>
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="EvForm.html"
|
||
title="previous chapter">EvForm</a></p>
|
||
</div>
|
||
<div>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="EvMore.html"
|
||
title="next chapter">EvMore</a></p>
|
||
</div>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Components/EvMenu.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/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="EvMore.html" title="EvMore"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="EvForm.html" title="EvForm"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">EvMenu</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2024, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
|
||
</div>
|
||
</body>
|
||
</html> |