mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 21:36:30 +01:00
574 lines
No EOL
50 KiB
HTML
574 lines
No EOL
50 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||
|
||
<title>3. Player Characters — Evennia latest documentation</title>
|
||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||
<script src="../../../_static/jquery.js"></script>
|
||
<script src="../../../_static/underscore.js"></script>
|
||
<script src="../../../_static/doctools.js"></script>
|
||
<script src="../../../_static/language_data.js"></script>
|
||
<link rel="shortcut 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="4. In-game Objects and items" href="Beginner-Tutorial-Objects.html" />
|
||
<link rel="prev" title="2. Rules and dice rolling" href="Beginner-Tutorial-Rules.html" />
|
||
</head><body>
|
||
|
||
|
||
|
||
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<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="Beginner-Tutorial-Objects.html" title="4. In-game Objects and items"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Beginner-Tutorial-Rules.html" title="2. Rules and dice rolling"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and How-To’s</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Overview.html" >Beginner Tutorial</a> »</li>
|
||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Overview.html" accesskey="U">Part 3: How We Get There (Example Game)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">3. </span>Player Characters</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
|
||
<div class="documentwrapper">
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="../../../index.html">
|
||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div 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" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">3. Player Characters</a><ul>
|
||
<li><a class="reference internal" href="#inheritance-structure">3.1. Inheritance structure</a></li>
|
||
<li><a class="reference internal" href="#living-mixin-class">3.2. Living mixin class</a></li>
|
||
<li><a class="reference internal" href="#character-class">3.3. Character class</a><ul>
|
||
<li><a class="reference internal" href="#funcparser-inlines">3.3.1. Funcparser inlines</a></li>
|
||
<li><a class="reference internal" href="#backtracking">3.3.2. Backtracking</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#connecting-the-character-with-evennia">3.4. Connecting the Character with Evennia</a></li>
|
||
<li><a class="reference internal" href="#unit-testing">3.5. Unit Testing</a></li>
|
||
<li><a class="reference internal" href="#about-races-and-classes">3.6. About races and classes</a></li>
|
||
<li><a class="reference internal" href="#summary">3.7. Summary</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
|
||
title="previous chapter"><span class="section-number">2. </span>Rules and dice rolling</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Beginner-Tutorial-Objects.html"
|
||
title="next chapter"><span class="section-number">4. </span>In-game Objects and items</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Characters.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="Beginner-Tutorial-Characters.html">latest (main branch)</a></li>
|
||
|
||
<li><a href="../4.x/index.html">v4.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../3.x/index.html">v3.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../2.x/index.html">v2.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../1.x/index.html">v1.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../0.x/index.html">v0.9.5 branch (outdated)</a></li>
|
||
|
||
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="player-characters">
|
||
<h1><span class="section-number">3. </span>Player Characters<a class="headerlink" href="#player-characters" title="Permalink to this headline">¶</a></h1>
|
||
<p>In the <a class="reference internal" href="Beginner-Tutorial-Rules.html"><span class="doc std std-doc">previous lesson about rules and dice rolling</span></a> we made some
|
||
assumptions about the “Player Character” entity:</p>
|
||
<ul class="simple">
|
||
<li><p>It should store Abilities on itself as <code class="docutils literal notranslate"><span class="pre">character.strength</span></code>, <code class="docutils literal notranslate"><span class="pre">character.constitution</span></code> etc.</p></li>
|
||
<li><p>It should have a <code class="docutils literal notranslate"><span class="pre">.heal(amount)</span></code> method.</p></li>
|
||
</ul>
|
||
<p>So we have some guidelines of how it should look! A Character is a database entity with values that
|
||
should be able to be changed over time. It makes sense to base it off Evennia’s
|
||
<a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc">DefaultCharacter Typeclass</span></a>. The Character class is like a ‘character sheet’ in a tabletop
|
||
RPG, it will hold everything relevant to that PC.</p>
|
||
<section id="inheritance-structure">
|
||
<h2><span class="section-number">3.1. </span>Inheritance structure<a class="headerlink" href="#inheritance-structure" title="Permalink to this headline">¶</a></h2>
|
||
<p>Player Characters (PCs) are not the only “living” things in our world. We also have <em>NPCs</em>
|
||
(like shopkeepers and other friendlies) as well as <em>monsters</em> (mobs) that can attack us.</p>
|
||
<p>In code, there are a few ways we could structure this. If NPCs/monsters were just special cases of PCs,
|
||
we could use a class inheritance like this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="c1"># stuff </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureNPC</span><span class="p">(</span><span class="n">EvAdventureCharacter</span><span class="p">):</span>
|
||
<span class="c1"># more stuff </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureMob</span><span class="p">(</span><span class="n">EvAdventureNPC</span><span class="p">):</span>
|
||
<span class="c1"># more stuff </span>
|
||
</pre></div>
|
||
</div>
|
||
<p>All code we put on the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class would now be inherited to <code class="docutils literal notranslate"><span class="pre">NPC</span></code> and <code class="docutils literal notranslate"><span class="pre">Mob</span></code> automatically.</p>
|
||
<p>However, in <em>Knave</em>, NPCs and particularly monsters are <em>not</em> using the same rules as PCs - they are
|
||
simplified to use a Hit-Die (HD) concept. So while still character-like, NPCs should be separate from
|
||
PCs like this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="c1"># stuff </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureNPC</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="c1"># separate stuff </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureMob</span><span class="p">(</span><span class="n">EvadventureNPC</span><span class="p">):</span>
|
||
<span class="c1"># more separate stuff</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Nevertheless, there are some things that <em>should</em> be common for all ‘living things’:</p>
|
||
<ul class="simple">
|
||
<li><p>All can take damage.</p></li>
|
||
<li><p>All can die.</p></li>
|
||
<li><p>All can heal</p></li>
|
||
<li><p>All can hold and lose coins</p></li>
|
||
<li><p>All can loot their fallen foes.</p></li>
|
||
<li><p>All can get looted when defeated.</p></li>
|
||
</ul>
|
||
<p>We don’t want to code this separately for every class but we no longer have a common parent
|
||
class to put it on. So instead we’ll use the concept of a <em>mixin</em> class:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
|
||
|
||
<span class="k">class</span> <span class="nc">LivingMixin</span><span class="p">:</span>
|
||
<span class="c1"># stuff common for all living things</span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="c1"># stuff </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureNPC</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="c1"># stuff </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureMob</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">EvadventureNPC</span><span class="p">):</span>
|
||
<span class="c1"># more stuff</span>
|
||
</pre></div>
|
||
</div>
|
||
<aside class="sidebar">
|
||
<p>In <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.characters.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/characters.py</span></a>
|
||
is an example of a character class structure.</p>
|
||
</aside>
|
||
<p>Above, the <code class="docutils literal notranslate"><span class="pre">LivingMixin</span></code> class cannot work on its own - it just ‘patches’ the other classes with some
|
||
extra functionality all living things should be able to do. This is an example of
|
||
<em>multiple inheritance</em>. It’s useful to know about, but one should not over-do multiple inheritance
|
||
since it can also get confusing to follow the code.</p>
|
||
</section>
|
||
<section id="living-mixin-class">
|
||
<h2><span class="section-number">3.2. </span>Living mixin class<a class="headerlink" href="#living-mixin-class" title="Permalink to this headline">¶</a></h2>
|
||
<blockquote>
|
||
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/characters.py</span></code></p>
|
||
</div></blockquote>
|
||
<p>Let’s get some useful common methods all living things should have in our game.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/characters.py </span>
|
||
|
||
<span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
|
||
|
||
<span class="k">class</span> <span class="nc">LivingMixin</span><span class="p">:</span>
|
||
|
||
<span class="c1"># makes it easy for mobs to know to attack PCs</span>
|
||
<span class="n">is_pc</span> <span class="o">=</span> <span class="kc">False</span>
|
||
|
||
<span class="nd">@property</span>
|
||
<span class="k">def</span> <span class="nf">hurt_level</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> String describing how hurt this character is.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="n">percent</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">min</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span> <span class="o">*</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">hp</span> <span class="o">/</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span><span class="p">)))</span>
|
||
<span class="k">if</span> <span class="mi">95</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">100</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|gPerfect|n"</span>
|
||
<span class="k">elif</span> <span class="mi">80</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">95</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|gScraped|n"</span>
|
||
<span class="k">elif</span> <span class="mi">60</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">80</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|GBruised|n"</span>
|
||
<span class="k">elif</span> <span class="mi">45</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">60</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|yHurt|n"</span>
|
||
<span class="k">elif</span> <span class="mi">30</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">45</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|yWounded|n"</span>
|
||
<span class="k">elif</span> <span class="mi">15</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">30</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|rBadly wounded|n"</span>
|
||
<span class="k">elif</span> <span class="mi">1</span> <span class="o"><</span> <span class="n">percent</span> <span class="o"><=</span> <span class="mi">15</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|rBarely hanging on|n"</span>
|
||
<span class="k">elif</span> <span class="n">percent</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="s2">"|RCollapsed!|n"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">heal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">hp</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">""" </span>
|
||
<span class="sd"> Heal hp amount of health, not allowing to exceed our max hp</span>
|
||
<span class="sd"> </span>
|
||
<span class="sd"> """</span>
|
||
<span class="n">damage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp</span>
|
||
<span class="n">healed</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">damage</span><span class="p">,</span> <span class="n">hp</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">hp</span> <span class="o">+=</span> <span class="n">healed</span>
|
||
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You heal for </span><span class="si">{</span><span class="n">healed</span><span class="si">}</span><span class="s2"> HP."</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_pay</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""When paying coins, make sure to never detract more than we have"""</span>
|
||
<span class="n">amount</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">amount</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">coins</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">coins</span> <span class="o">-=</span> <span class="n">amount</span>
|
||
<span class="k">return</span> <span class="n">amount</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_attacked</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attacker</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called when being attacked and combat starts."""</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_damage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">damage</span><span class="p">,</span> <span class="n">attacker</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called when attacked and taking damage."""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">hp</span> <span class="o">-=</span> <span class="n">damage</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_defeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called when defeated. By default this means death."""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">at_death</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_death</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called when this thing dies."""</span>
|
||
<span class="c1"># this will mean different things for different living things</span>
|
||
<span class="k">pass</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_do_loot</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looted</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called when looting another entity"""</span>
|
||
<span class="n">looted</span><span class="o">.</span><span class="n">at_looted</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_looted</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looter</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called when looted by another entity"""</span>
|
||
|
||
<span class="c1"># default to stealing some coins </span>
|
||
<span class="n">max_steal</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d10"</span><span class="p">)</span>
|
||
<span class="n">stolen</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">at_pay</span><span class="p">(</span><span class="n">max_steal</span><span class="p">)</span>
|
||
<span class="n">looter</span><span class="o">.</span><span class="n">coins</span> <span class="o">+=</span> <span class="n">stolen</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Most of these are empty since they will behave differently for characters and npcs. But having them in the mixin means we can expect these methods to be available for all living things.</p>
|
||
<p>Once we create more of our game, we will need to remember to actually call these hook methods so they serve a purpose. For example, once we implement combat, we must remember to call <code class="docutils literal notranslate"><span class="pre">at_attacked</span></code> as well as the other methods involving taking damage, getting defeated or dying.</p>
|
||
</section>
|
||
<section id="character-class">
|
||
<h2><span class="section-number">3.3. </span>Character class<a class="headerlink" href="#character-class" title="Permalink to this headline">¶</a></h2>
|
||
<p>We will now start making the basic Character class, based on what we need from <em>Knave</em>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/characters.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span><span class="p">,</span> <span class="n">AttributeProperty</span>
|
||
<span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
|
||
|
||
<span class="k">class</span> <span class="nc">LivingMixin</span><span class="p">:</span>
|
||
<span class="c1"># ... </span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">""" </span>
|
||
<span class="sd"> A character to use for EvAdventure. </span>
|
||
<span class="sd"> """</span>
|
||
<span class="n">is_pc</span> <span class="o">=</span> <span class="kc">True</span>
|
||
|
||
<span class="n">strength</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">dexterity</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">constitution</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">intelligence</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">wisdom</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">charisma</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
|
||
<span class="n">hp</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
|
||
<span class="n">hp_max</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
|
||
|
||
<span class="n">level</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="n">xp</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||
<span class="n">coins</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_defeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Characters roll on the death table"""</span>
|
||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">allow_death</span><span class="p">:</span>
|
||
<span class="c1"># this allow rooms to have non-lethal battles</span>
|
||
<span class="n">dice</span><span class="o">.</span><span class="n">roll_death</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span>
|
||
<span class="s2">"$You() $conj(collapse) in a heap, alive but beaten."</span><span class="p">,</span>
|
||
<span class="n">from_obj</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_death</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""We rolled 'dead' on the death table."""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span>
|
||
<span class="s2">"$You() collapse in a heap, embraced by death."</span><span class="p">,</span>
|
||
<span class="n">from_obj</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
|
||
<span class="c1"># TODO - go back into chargen to make a new character! </span>
|
||
</pre></div>
|
||
</div>
|
||
<p>We make an assumption about our rooms here - that they have a property <code class="docutils literal notranslate"><span class="pre">.allow_death</span></code>. We need to make a note to actually add such a property to rooms later!</p>
|
||
<p>In our <code class="docutils literal notranslate"><span class="pre">Character</span></code> class we implement all attributes we want to simulate from the <em>Knave</em> ruleset.
|
||
The <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> is one way to add an Attribute in a field-like way; these will be accessible on every character in several ways:</p>
|
||
<ul class="simple">
|
||
<li><p>As <code class="docutils literal notranslate"><span class="pre">character.strength</span></code></p></li>
|
||
<li><p>As <code class="docutils literal notranslate"><span class="pre">character.db.strength</span></code></p></li>
|
||
<li><p>As <code class="docutils literal notranslate"><span class="pre">character.attributes.get("strength")</span></code></p></li>
|
||
</ul>
|
||
<p>See <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> for seeing how Attributes work.</p>
|
||
<p>Unlike in base <em>Knave</em>, we store <code class="docutils literal notranslate"><span class="pre">coins</span></code> as a separate Attribute rather than as items in the inventory, this makes it easier to handle barter and trading later.</p>
|
||
<p>We implement the Player Character versions of <code class="docutils literal notranslate"><span class="pre">at_defeat</span></code> and <code class="docutils literal notranslate"><span class="pre">at_death</span></code>. We also make use of <code class="docutils literal notranslate"><span class="pre">.heal()</span></code> from the <code class="docutils literal notranslate"><span class="pre">LivingMixin</span></code> class.</p>
|
||
<section id="funcparser-inlines">
|
||
<h3><span class="section-number">3.3.1. </span>Funcparser inlines<a class="headerlink" href="#funcparser-inlines" title="Permalink to this headline">¶</a></h3>
|
||
<p>This piece of code is worth some more explanation:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span>
|
||
<span class="s2">"$You() $conj(collapse) in a heap, alive but beaten."</span><span class="p">,</span>
|
||
<span class="n">from_obj</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Remember that <code class="docutils literal notranslate"><span class="pre">self</span></code> is the Character instance here. So <code class="docutils literal notranslate"><span class="pre">self.location.msg_contents</span></code> means “send a message to everything inside my current location”. In other words, send a message to everyone in the same place as the character.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">$You()</span> <span class="pre">$conj(collapse)</span></code> are <a class="reference internal" href="../../../Components/FuncParser.html"><span class="doc std std-doc">FuncParser inlines</span></a>. These are functions that
|
||
execute in the string. The resulting string may look different for different audiences. The <code class="docutils literal notranslate"><span class="pre">$You()</span></code> inline function will use <code class="docutils literal notranslate"><span class="pre">from_obj</span></code> to figure out who ‘you’ are and either show your name or ‘You’. The <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> (verb conjugator) will tweak the (English) verb to match.</p>
|
||
<ul class="simple">
|
||
<li><p>You will see: <code class="docutils literal notranslate"><span class="pre">"You</span> <span class="pre">collapse</span> <span class="pre">in</span> <span class="pre">a</span> <span class="pre">heap,</span> <span class="pre">alive</span> <span class="pre">but</span> <span class="pre">beaten."</span></code></p></li>
|
||
<li><p>Others in the room will see: <code class="docutils literal notranslate"><span class="pre">"Thomas</span> <span class="pre">collapses</span> <span class="pre">in</span> <span class="pre">a</span> <span class="pre">heap,</span> <span class="pre">alive</span> <span class="pre">but</span> <span class="pre">beaten."</span></code></p></li>
|
||
</ul>
|
||
<p>Note how <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> chose <code class="docutils literal notranslate"><span class="pre">collapse/collapses</span></code> to make the sentences grammatically correct.</p>
|
||
</section>
|
||
<section id="backtracking">
|
||
<h3><span class="section-number">3.3.2. </span>Backtracking<a class="headerlink" href="#backtracking" title="Permalink to this headline">¶</a></h3>
|
||
<p>We make our first use of the <code class="docutils literal notranslate"><span class="pre">rules.dice</span></code> roller to roll on the death table! As you may recall, in the previous lesson, we didn’t know just what to do when rolling ‘dead’ on this table. Now we know - we should be calling <code class="docutils literal notranslate"><span class="pre">at_death</span></code> on the character. So let’s add that where we had TODOs before:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/rules.py </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
|
||
|
||
<span class="c1"># ... </span>
|
||
|
||
<span class="k">def</span> <span class="nf">roll_death</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
|
||
<span class="n">ability_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d8"</span><span class="p">,</span> <span class="n">death_table</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="n">ability_name</span> <span class="o">==</span> <span class="s2">"dead"</span><span class="p">:</span>
|
||
<span class="c1"># kill the character!</span>
|
||
<span class="n">character</span><span class="o">.</span><span class="n">at_death</span><span class="p">()</span> <span class="c1"># <------ TODO no more</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># ... </span>
|
||
|
||
<span class="k">if</span> <span class="n">current_ability</span> <span class="o"><</span> <span class="o">-</span><span class="mi">10</span><span class="p">:</span>
|
||
<span class="c1"># kill the character!</span>
|
||
<span class="n">character</span><span class="o">.</span><span class="n">at_death</span><span class="p">()</span> <span class="c1"># <------- TODO no more</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># ... </span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="connecting-the-character-with-evennia">
|
||
<h2><span class="section-number">3.4. </span>Connecting the Character with Evennia<a class="headerlink" href="#connecting-the-character-with-evennia" title="Permalink to this headline">¶</a></h2>
|
||
<p>You can easily make yourself an <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> in-game by using the
|
||
<code class="docutils literal notranslate"><span class="pre">type</span></code> command:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>type self = evadventure.characters.EvAdventureCharacter
|
||
</pre></div>
|
||
</div>
|
||
<p>You can now do <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">self</span></code> to check your type updated.</p>
|
||
<p>If you want <em>all</em> new Characters to be of this type you need to tell Evennia about it. Evennia
|
||
uses a global setting <code class="docutils literal notranslate"><span class="pre">BASE_CHARACTER_TYPECLASS</span></code> to know which typeclass to use when creating
|
||
Characters (when logging in, for example). This defaults to <code class="docutils literal notranslate"><span class="pre">typeclasses.characters.Character</span></code> (that is,
|
||
the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>).</p>
|
||
<p>There are thus two ways to weave your new Character class into Evennia:</p>
|
||
<ol class="simple">
|
||
<li><p>Change <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and add <code class="docutils literal notranslate"><span class="pre">BASE_CHARACTER_TYPECLASS</span> <span class="pre">=</span> <span class="pre">"evadventure.characters.EvAdventureCharacter"</span></code>.</p></li>
|
||
<li><p>Or, change <code class="docutils literal notranslate"><span class="pre">typeclasses.characters.Character</span></code> to inherit from <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code>.</p></li>
|
||
</ol>
|
||
<p>You must always reload the server for changes like this to take effect.</p>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>In this tutorial we are making all changes in a folder <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/</span></code>. This means we can isolate
|
||
our code but means we need to do some extra steps to tie the character (and other objects) into Evennia.
|
||
For your own game it would be just fine to start editing <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> directly
|
||
instead.</p>
|
||
</div>
|
||
</section>
|
||
<section id="unit-testing">
|
||
<h2><span class="section-number">3.5. </span>Unit Testing<a class="headerlink" href="#unit-testing" title="Permalink to this headline">¶</a></h2>
|
||
<blockquote>
|
||
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_characters.py</span></code></p>
|
||
</div></blockquote>
|
||
<p>For testing, we just need to create a new EvAdventure character and check
|
||
that calling the methods on it doesn’t error out.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_characters.py </span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span>
|
||
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">..characters</span> <span class="kn">import</span> <span class="n">EvAdventureCharacter</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TestCharacters</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">character</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">EvAdventureCharacter</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"testchar"</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_heal</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp</span> <span class="o">=</span> <span class="mi">0</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp_max</span> <span class="o">=</span> <span class="mi">8</span>
|
||
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||
<span class="c1"># make sure we can't heal more than max</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_at_pay</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">coins</span> <span class="o">=</span> <span class="mi">100</span>
|
||
|
||
<span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">at_pay</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">coins</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
|
||
|
||
<span class="c1"># can't get more coins than we have </span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">at_pay</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">coins</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||
|
||
<span class="c1"># tests for other methods ... </span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>If you followed the previous lessons, these tests should look familiar. Consider adding
|
||
tests for other methods as practice. Refer to previous lessons for details.</p>
|
||
<p>For running the tests you do:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> evennia test --settings settings.py .evadventure.tests.test_character
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="about-races-and-classes">
|
||
<h2><span class="section-number">3.6. </span>About races and classes<a class="headerlink" href="#about-races-and-classes" title="Permalink to this headline">¶</a></h2>
|
||
<p><em>Knave</em> doesn’t have any D&D-style <em>classes</em> (like Thief, Fighter etc). It also does not bother with
|
||
<em>races</em> (like dwarves, elves etc). This makes the tutorial shorter, but you may ask yourself how you’d
|
||
add these functions.</p>
|
||
<p>In the framework we have sketched out for <em>Knave</em>, it would be simple - you’d add your race/class as
|
||
an Attribute on your Character:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/characters.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span><span class="p">,</span> <span class="n">AttributeProperty</span>
|
||
<span class="c1"># ... </span>
|
||
|
||
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
|
||
<span class="c1"># ... </span>
|
||
|
||
<span class="n">charclass</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="s2">"Fighter"</span><span class="p">)</span>
|
||
<span class="n">charrace</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="s2">"Human"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>We use <code class="docutils literal notranslate"><span class="pre">charclass</span></code> rather than <code class="docutils literal notranslate"><span class="pre">class</span></code> here, because <code class="docutils literal notranslate"><span class="pre">class</span></code> is a reserved Python keyword. Naming
|
||
<code class="docutils literal notranslate"><span class="pre">race</span></code> as <code class="docutils literal notranslate"><span class="pre">charrace</span></code> thus matches in style.</p>
|
||
<p>We’d then need to expand our <a class="reference internal" href="Beginner-Tutorial-Rules.html"><span class="doc std std-doc">rules module</span></a> (and later
|
||
<a class="reference internal" href="Beginner-Tutorial-Chargen.html"><span class="doc std std-doc">character generation</span></a> to check and include what these classes mean.</p>
|
||
</section>
|
||
<section id="summary">
|
||
<h2><span class="section-number">3.7. </span>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||
<p>With the <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> class in place, we have a better understanding of how our PCs will look
|
||
like under <em>Knave</em>.</p>
|
||
<p>For now, we only have bits and pieces and haven’t been testing this code in-game. But if you want
|
||
you can swap yourself into <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> right now. Log into your game and run
|
||
the command</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>type self = evadventure.characters.EvAdventureCharacter
|
||
</pre></div>
|
||
</div>
|
||
<p>If all went well, <code class="docutils literal notranslate"><span class="pre">ex</span> <span class="pre">self</span></code> will now show your typeclass as being <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code>.
|
||
Check out your strength with</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py self.strength = 3
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>When doing <code class="docutils literal notranslate"><span class="pre">ex</span> <span class="pre">self</span></code> you will <em>not</em> see all your Abilities listed yet. That’s because
|
||
Attributes added with <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> are not available until they have been accessed at
|
||
least once. So once you set (or look at) <code class="docutils literal notranslate"><span class="pre">.strength</span></code> above, <code class="docutils literal notranslate"><span class="pre">strength</span></code> will show in <code class="docutils literal notranslate"><span class="pre">examine</span></code> from
|
||
then on.</p>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<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="Beginner-Tutorial-Objects.html" title="4. In-game Objects and items"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Beginner-Tutorial-Rules.html" title="2. Rules and dice rolling"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and How-To’s</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Overview.html" >Beginner Tutorial</a> »</li>
|
||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Overview.html" >Part 3: How We Get There (Example Game)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">3. </span>Player Characters</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> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |