<pclass="last">You are reading an old version of the Evennia documentation. <ahref="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
<h1><spanclass="section-number">6. </span>Character Generation<aclass="headerlink"href="#character-generation"title="Permalink to this headline">¶</a></h1>
<p>In previous lessons we have established how a character looks. Now we need to give the player a
chance to create one.</p>
<sectionid="how-it-will-work">
<h2><spanclass="section-number">6.1. </span>How it will work<aclass="headerlink"href="#how-it-will-work"title="Permalink to this headline">¶</a></h2>
<p>A fresh Evennia install will automatically create a new Character with the same name as your
Account when you log in. This is quick and simple and mimics older MUD styles. You could picture
doing this, and then customizing the Character in-place.</p>
<p>We will be a little more sophisticated though. We want the user to be able to create a character
using a menu when they log in.</p>
<p>We do this by editing <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf/settings.py</span></code> and adding the line</p>
<p>When doing this, connecting with the game with a new account will land you in “OOC” mode. The ooc-version of <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> (sitting in the Account cmdset) will show a list of available characters if you have any. You can also enter <codeclass="docutils literal notranslate"><spanclass="pre">charcreate</span></code> to make a new character. The <codeclass="docutils literal notranslate"><spanclass="pre">charcreate</span></code> is a simple command coming with Evennia that just lets you make a new character with a given name and description. We will later modify that to kick off our chargen. For now we’ll just keep in mind that’s how we’ll start off the menu.</p>
<p>In <em>Knave</em>, most of the character-generation is random. This means this tutorial can be pretty
compact while still showing the basic idea. What we will create is a menu looking like this:</p>
<p>If you enter <codeclass="docutils literal notranslate"><spanclass="pre">WIS</span><spanclass="pre">CHA</span></code> here, WIS will become <codeclass="docutils literal notranslate"><spanclass="pre">+2</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">CHA</span></code><codeclass="docutils literal notranslate"><spanclass="pre">+1</span></code>. You will then again go back
to the main node to see your new character, but this time the option to swap will no longer be
available (you can only do it once).</p>
<p>If you finally select the <codeclass="docutils literal notranslate"><spanclass="pre">Accept</span><spanclass="pre">and</span><spanclass="pre">create</span><spanclass="pre">character</span></code> option, the character will be created
and you’ll leave the menu;</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>Character was created!
</pre></div>
</div>
</section>
<sectionid="random-tables">
<h2><spanclass="section-number">6.2. </span>Random tables<aclass="headerlink"href="#random-tables"title="Permalink to this headline">¶</a></h2>
<p>The tables are just copied from the <em>Knave</em> rules. We group the aspects in a dict
<codeclass="docutils literal notranslate"><spanclass="pre">character_generation</span></code> to separate chargen-only tables from other random tables we’ll also
keep in here.</p>
</section>
<sectionid="storing-state-of-the-menu">
<h2><spanclass="section-number">6.3. </span>Storing state of the menu<aclass="headerlink"href="#storing-state-of-the-menu"title="Permalink to this headline">¶</a></h2>
<asideclass="sidebar">
<p>There is a full implementation of the chargen in
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">ability_changes</span><spanclass="o">=</span><spanclass="mi">0</span><spanclass="c1"># how many times we tried swap abilities</span>
<spanclass="c1"># name will likely be modified later</span>
<spanclass="sa">f</span><spanclass="s2">"You are </span><spanclass="si">{</span><spanclass="n">physique</span><spanclass="si">}</span><spanclass="s2"> with a </span><spanclass="si">{</span><spanclass="n">face</span><spanclass="si">}</span><spanclass="s2"> face, </span><spanclass="si">{</span><spanclass="n">skin</span><spanclass="si">}</span><spanclass="s2"> skin, </span><spanclass="si">{</span><spanclass="n">hair</span><spanclass="si">}</span><spanclass="s2"> hair, </span><spanclass="si">{</span><spanclass="n">speech</span><spanclass="si">}</span><spanclass="s2"> speech,"</span>
<spanclass="sa">f</span><spanclass="s2">" and </span><spanclass="si">{</span><spanclass="n">clothing</span><spanclass="si">}</span><spanclass="s2"> clothing. You were a </span><spanclass="si">{</span><spanclass="n">background</span><spanclass="o">.</span><spanclass="n">title</span><spanclass="p">()</span><spanclass="si">}</span><spanclass="s2">, but you were"</span>
<spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="n">misfortune</span><spanclass="si">}</span><spanclass="s2"> and ended up a knave. You are </span><spanclass="si">{</span><spanclass="n">virtue</span><spanclass="si">}</span><spanclass="s2"> but also </span><spanclass="si">{</span><spanclass="n">vice</span><spanclass="si">}</span><spanclass="s2">. You are of the"</span>
<spanclass="n">_helmet_and_shield</span><spanclass="o">=</span><spanclass="n">dice</span><spanclass="o">.</span><spanclass="n">roll_random_table</span><spanclass="p">(</span><spanclass="s2">"1d20"</span><spanclass="p">,</span><spanclass="n">chargen_tables</span><spanclass="p">[</span><spanclass="s2">"helmets and shields"</span><spanclass="p">])</span>
<p>Here we have followed the <em>Knave</em> rulebook to randomize abilities, description and equipment. The <codeclass="docutils literal notranslate"><spanclass="pre">dice.roll()</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">dice.roll_random_table</span></code> methods now become very useful! Everything here should be easy to follow.</p>
<p>The main difference from baseline <em>Knave</em> is that we make a table of “starting weapon” (in Knave you can pick whatever you like).</p>
<p>We also initialize <codeclass="docutils literal notranslate"><spanclass="pre">.ability_changes</span><spanclass="pre">=</span><spanclass="pre">0</span></code>. Knave only allows us to swap the values of two
Abilities <em>once</em>. We will use this to know if it has been done or not.</p>
<sectionid="showing-the-sheet">
<h3><spanclass="section-number">6.3.1. </span>Showing the sheet<aclass="headerlink"href="#showing-the-sheet"title="Permalink to this headline">¶</a></h3>
<p>Now that we have our temporary character sheet, we should make it easy to visualize it.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in mygame/evadventure/chargen.py </span>
<p>The new <codeclass="docutils literal notranslate"><spanclass="pre">show_sheet</span></code> method collect the data from the temporary sheet and return it in a pretty form. Making a ‘template’ string like <codeclass="docutils literal notranslate"><spanclass="pre">_TEMP_SHEET</span></code> makes it easier to change things later if you want to change how things look.</p>
</section>
<sectionid="apply-character">
<h3><spanclass="section-number">6.3.2. </span>Apply character<aclass="headerlink"href="#apply-character"title="Permalink to this headline">¶</a></h3>
<p>Once we are happy with our character, we need to actually create it with the stats we chose.
This is a bit more involved.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in mygame/evadventure/chargen.py </span>
<p>We use <codeclass="docutils literal notranslate"><spanclass="pre">create_object</span></code> to create a new <codeclass="docutils literal notranslate"><spanclass="pre">EvAdventureCharacter</span></code>. We feed it with all relevant data from the temporary character sheet. This is when these become an actual character.</p>
<asideclass="sidebar">
<p>A prototype is basically a <codeclass="docutils literal notranslate"><spanclass="pre">dict</span></code> describing how the object should be created. Since
it’s just a piece of code, it can stored in a Python module and used to quickly <em>spawn</em> (create)
things from those prototypes.</p>
</aside>
<p>Each piece of equipment is an object in in its own right. We will here assume that all game
items are defined as <aclass="reference internal"href="../../../Components/Prototypes.html"><spanclass="doc std std-doc">Prototypes</span></a> keyed to its name, such as “sword”, “brigandine
armor” etc.</p>
<p>We haven’t actually created those prototypes yet, so for now we’ll need to assume they are there. Once a piece of equipment has been spawned, we make sure to move it into the <codeclass="docutils literal notranslate"><spanclass="pre">EquipmentHandler</span></code> we created in the <aclass="reference internal"href="Beginner-Tutorial-Equipment.html"><spanclass="doc std std-doc">Equipment lesson</span></a>.</p>
</section>
</section>
<sectionid="initializing-evmenu">
<h2><spanclass="section-number">6.4. </span>Initializing EvMenu<aclass="headerlink"href="#initializing-evmenu"title="Permalink to this headline">¶</a></h2>
<p>Evennia comes with a full menu-generation system based on <aclass="reference internal"href="../../../Components/Command-Sets.html"><spanclass="doc std std-doc">Command sets</span></a>, called
<p>This first function is what we will call from elsewhere (for example from a custom <codeclass="docutils literal notranslate"><spanclass="pre">charcreate</span></code>
command) to kick the menu into gear.</p>
<p>It takes the <codeclass="docutils literal notranslate"><spanclass="pre">caller</span></code> (the one to want to start the menu) and a <codeclass="docutils literal notranslate"><spanclass="pre">session</span></code> argument. The latter will help track just which client-connection we are using (depending on Evennia settings, you could be connecting with multiple clients).</p>
<p>We create a <codeclass="docutils literal notranslate"><spanclass="pre">TemporaryCharacterSheet</span></code> and call <codeclass="docutils literal notranslate"><spanclass="pre">.generate()</span></code> to make a random character. We then feed all this into <codeclass="docutils literal notranslate"><spanclass="pre">EvMenu</span></code>.</p>
<p>The moment this happens, the user will be in the menu, there are no further steps needed.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">menutree</span></code> is what we’ll create next. It describes which menu ‘nodes’ are available to jump
between.</p>
</section>
<sectionid="main-node-choosing-what-to-do">
<h2><spanclass="section-number">6.5. </span>Main Node: Choosing what to do<aclass="headerlink"href="#main-node-choosing-what-to-do"title="Permalink to this headline">¶</a></h2>
<p>This is the first menu node. It will act as a central hub, from which one can choose different
actions.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in mygame/evadventure/chargen.py </span>
<spanclass="c1"># ...</span>
<spanclass="c1"># at the end of the module, but before the `start_chargen` function</span>
<spanclass="s2">"desc"</span><spanclass="p">:</span><spanclass="s2">"Swap two of your ability scores (once)"</span><spanclass="p">,</span>
<p>A lot to unpack here! In Evennia, it’s convention to name your node-functions <codeclass="docutils literal notranslate"><spanclass="pre">node_*</span></code>. While
not required, it helps you track what is a node and not.</p>
<p>Every menu-node, should accept <codeclass="docutils literal notranslate"><spanclass="pre">caller,</span><spanclass="pre">raw_string,</span><spanclass="pre">**kwargs</span></code> as arguments. Here <codeclass="docutils literal notranslate"><spanclass="pre">caller</span></code> is the <codeclass="docutils literal notranslate"><spanclass="pre">caller</span></code> you passed into the <codeclass="docutils literal notranslate"><spanclass="pre">EvMenu</span></code> call. <codeclass="docutils literal notranslate"><spanclass="pre">raw_string</span></code> is the input given by the user in order to <em>get to this node</em>, so currently empty. The <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code> are all extra keyword arguments passed into <codeclass="docutils literal notranslate"><spanclass="pre">EvMenu</span></code>. They can also be passed between nodes. In this case, we passed the keyword <codeclass="docutils literal notranslate"><spanclass="pre">tmp_character</span></code> to <codeclass="docutils literal notranslate"><spanclass="pre">EvMenu</span></code>. We now have the temporary character sheet available in the node!</p>
<p>An <codeclass="docutils literal notranslate"><spanclass="pre">EvMenu</span></code> node must always return two things - <codeclass="docutils literal notranslate"><spanclass="pre">text</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">options</span></code>. The <codeclass="docutils literal notranslate"><spanclass="pre">text</span></code> is what will
show to the user when looking at this node. The <codeclass="docutils literal notranslate"><spanclass="pre">options</span></code> are, well, what options should be
presented to move on from here to some other place.</p>
<p>For the text, we simply get a pretty-print of the temporary character sheet. A single option is
defined as a <codeclass="docutils literal notranslate"><spanclass="pre">dict</span></code> like this:</p>
<spanclass="s2">"key"</span><spanclass="p">:</span><spanclass="p">(</span><spanclass="s2">"name"</span><spanclass="o">.</span><spanclass="s2">"alias1"</span><spanclass="p">,</span><spanclass="s2">"alias2"</span><spanclass="p">,</span><spanclass="o">...</span><spanclass="p">),</span><spanclass="c1"># if skipped, auto-show a number</span>
<spanclass="s2">"desc"</span><spanclass="p">:</span><spanclass="s2">"text to describe what happens when selecting option"</span><spanclass="p">,</span><spanclass="o">.</span>
<spanclass="s2">"goto"</span><spanclass="p">:</span><spanclass="p">(</span><spanclass="s2">"name of node or a callable"</span><spanclass="p">,</span><spanclass="n">kwargs_to_pass_into_next_node_or_callable</span><spanclass="p">)</span>
<spanclass="p">}</span>
</pre></div>
</div>
<p>Multiple option-dicts are returned in a list or tuple. The <codeclass="docutils literal notranslate"><spanclass="pre">goto</span></code> option-key is important to
understand. The job of this is to either point directly to another node (by giving its name), or
by pointing to a Python callable (like a function) <em>that then returns that name</em>. You can also
pass kwargs (as a dict). This will be made available as <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code> in the callable or next node.</p>
<p>While an option can have a <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code>, you can also skip it to just get a running number.</p>
<p>In our <codeclass="docutils literal notranslate"><spanclass="pre">node_chargen</span></code> node, we point to three nodes by name: <codeclass="docutils literal notranslate"><spanclass="pre">node_change_name</span></code>,
<codeclass="docutils literal notranslate"><spanclass="pre">node_swap_abilities</span></code>, and <codeclass="docutils literal notranslate"><spanclass="pre">node_apply_character</span></code>. We also make sure to pass along <codeclass="docutils literal notranslate"><spanclass="pre">kwargs</span></code>
to each node, since that contains our temporary character sheet.</p>
<p>The middle of these options only appear if we haven’t already switched two abilities around - to know this, we check the <codeclass="docutils literal notranslate"><spanclass="pre">.ability_changes</span></code> property to make sure it’s still 0.</p>
</section>
<sectionid="node-changing-your-name">
<h2><spanclass="section-number">6.6. </span>Node: Changing your name<aclass="headerlink"href="#node-changing-your-name"title="Permalink to this headline">¶</a></h2>
<p>This is where you end up if you opted to change your name in <codeclass="docutils literal notranslate"><spanclass="pre">node_chargen</span></code>.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in mygame/evadventure/chargen.py</span>
<spanclass="sa">f</span><spanclass="s2">"Your current name is |w</span><spanclass="si">{</span><spanclass="n">tmp_character</span><spanclass="o">.</span><spanclass="n">name</span><spanclass="si">}</span><spanclass="s2">|n. "</span>
<spanclass="s2">"Enter a new name or leave empty to abort."</span>
<p>There are two functions here - the menu node itself (<codeclass="docutils literal notranslate"><spanclass="pre">node_change_name</span></code>) and a
helper <em>goto_function</em> (<codeclass="docutils literal notranslate"><spanclass="pre">_update_name</span></code>) to handle the user’s input.</p>
<p>For the (single) option, we use a special <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code> named <codeclass="docutils literal notranslate"><spanclass="pre">_default</span></code>. This makes this option
a catch-all: If the user enters something that does not match any other option, this is
the option that will be used. Since we have no other options here, we will always use this option no matter what the user enters.</p>
<p>Also note that the <codeclass="docutils literal notranslate"><spanclass="pre">goto</span></code> part of the option points to the <codeclass="docutils literal notranslate"><spanclass="pre">_update_name</span></code> callable rather than to
the name of a node. It’s important we keep passing <codeclass="docutils literal notranslate"><spanclass="pre">kwargs</span></code> along to it!</p>
<p>When a user writes anything at this node, the <codeclass="docutils literal notranslate"><spanclass="pre">_update_name</span></code> callable will be called. This has
the same arguments as a node, but it is <em>not</em> a node - we will only use it to <em>figure out</em> which
node to go to next.</p>
<p>In <codeclass="docutils literal notranslate"><spanclass="pre">_update_name</span></code> we now have a use for the <codeclass="docutils literal notranslate"><spanclass="pre">raw_string</span></code> argument - this is what was written by the user on the previous node, remember? This is now either an empty string (meaning to ignore it) or the new name of the character.</p>
<p>A goto-function like <codeclass="docutils literal notranslate"><spanclass="pre">_update_name</span></code> must return the name of the next node to use. It can also
optionally return the <codeclass="docutils literal notranslate"><spanclass="pre">kwargs</span></code> to pass into that node - we want to always do this, so we don’t
loose our temporary character sheet. Here we will always go back to the <codeclass="docutils literal notranslate"><spanclass="pre">node_chargen</span></code>.</p>
<blockquote>
<div><p>Hint: If returning <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> from a goto-callable, you will always return to the last node you
were at.</p>
</div></blockquote>
</section>
<sectionid="node-swapping-abilities-around">
<h2><spanclass="section-number">6.7. </span>Node: Swapping Abilities around<aclass="headerlink"href="#node-swapping-abilities-around"title="Permalink to this headline">¶</a></h2>
<p>You get here by selecting the second option from the <codeclass="docutils literal notranslate"><spanclass="pre">node_chargen</span></code> node.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in mygame/evadventure/chargen.py </span>
<spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"Not a familiar set of abilites."</span><spanclass="p">)</span>
<p>This is more code, but the logic is the same - we have a node (<codeclass="docutils literal notranslate"><spanclass="pre">node_swap_abilities</span></code>) and
and a goto-callable helper (<codeclass="docutils literal notranslate"><spanclass="pre">_swap_abilities</span></code>). We catch everything the user writes on the
node (such as <codeclass="docutils literal notranslate"><spanclass="pre">WIS</span><spanclass="pre">CON</span></code>) and feed it into the helper.</p>
<p>In <codeclass="docutils literal notranslate"><spanclass="pre">_swap_abilities</span></code>, we need to analyze the <codeclass="docutils literal notranslate"><spanclass="pre">raw_string</span></code> from the user to see what they
want to do.</p>
<p>Most code in the helper is validating the user didn’t enter nonsense. If they did,
we use <codeclass="docutils literal notranslate"><spanclass="pre">caller.msg()</span></code> to tell them and then return <codeclass="docutils literal notranslate"><spanclass="pre">None,</span><spanclass="pre">kwargs</span></code>, which re-runs the same node (the name-selection) all over again.</p>
<p>Since we want users to be able to write “CON” instead of the longer “constitution”, we need a mapping <codeclass="docutils literal notranslate"><spanclass="pre">_ABILITIES</span></code> to easily convert between the two (it’s stored as <codeclass="docutils literal notranslate"><spanclass="pre">consitution</span></code> on the temporary character sheet). Once we know which abilities they want to swap, we do so and tick up the <codeclass="docutils literal notranslate"><spanclass="pre">.ability_changes</span></code> counter. This means this option will no longer be available from the main node.</p>
<p>Finally, we return to <codeclass="docutils literal notranslate"><spanclass="pre">node_chargen</span></code> again.</p>
</section>
<sectionid="node-creating-the-character">
<h2><spanclass="section-number">6.8. </span>Node: Creating the Character<aclass="headerlink"href="#node-creating-the-character"title="Permalink to this headline">¶</a></h2>
<p>We get here from the main node by opting to finish chargen.</p>
<p>When entering the node, we will take the Temporary character sheet and use its <codeclass="docutils literal notranslate"><spanclass="pre">.appy</span></code> method to create a new Character with all equipment.</p>
<p>This is what is called an <em>end node</em>, because it returns <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> instead of options. After this, the menu will exit. We will be back to the default character selection screen. The characters found on that screen are the ones listed in the <codeclass="docutils literal notranslate"><spanclass="pre">_playable_characters</span></code> Attribute, so we need to also the new character to it.</p>
</section>
<sectionid="tying-the-nodes-together">
<h2><spanclass="section-number">6.9. </span>Tying the nodes together<aclass="headerlink"href="#tying-the-nodes-together"title="Permalink to this headline">¶</a></h2>
<p>Now that we have all the nodes, we add them to the <codeclass="docutils literal notranslate"><spanclass="pre">menutree</span></code> we left empty before. We only add the nodes, <em>not</em> the goto-helpers! The keys we set in the <codeclass="docutils literal notranslate"><spanclass="pre">menutree</span></code> dictionary are the names we should use to point to nodes from inside the menu (and we did).</p>
<p>We also add a keyword argument <codeclass="docutils literal notranslate"><spanclass="pre">startnode</span></code> pointing to the <codeclass="docutils literal notranslate"><spanclass="pre">node_chargen</span></code> node. This tells EvMenu to first jump into that node when the menu is starting up.</p>
</section>
<sectionid="conclusions">
<h2><spanclass="section-number">6.10. </span>Conclusions<aclass="headerlink"href="#conclusions"title="Permalink to this headline">¶</a></h2>
<p>This lesson taught us how to use <codeclass="docutils literal notranslate"><spanclass="pre">EvMenu</span></code> to make an interactive character generator. In an RPG more complex than <em>Knave</em>, the menu would be bigger and more intricate, but the same principles apply.</p>
<p>Together with the previous lessons we have now fished most of the basics around player
characters - how they store their stats, handle their equipment and how to create them.</p>
<p>In the next lesson we’ll address how EvAdventure <em>Rooms</em> work.</p>
<pclass="last">You are reading an old version of the Evennia documentation. <ahref="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.