mirror of
https://github.com/evennia/evennia.git
synced 2026-03-29 12:07:17 +02:00
parent
51d5840b8b
commit
e34f258a92
2504 changed files with 820160 additions and 0 deletions
|
|
@ -0,0 +1,540 @@
|
|||
|
||||
<!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>Player Characters — Evennia 1.0-dev 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="In-game Objects and items" href="Beginner-Tutorial-Objects.html" />
|
||||
<link rel="prev" title="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="In-game Objects and items"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Rules.html" title="Rules and dice rolling"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Player Characters</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">Player Characters</a><ul>
|
||||
<li><a class="reference internal" href="#inheritance-structure">Inheritance structure</a></li>
|
||||
<li><a class="reference internal" href="#living-mixin-class">Living mixin class</a></li>
|
||||
<li><a class="reference internal" href="#character-class">Character class</a><ul>
|
||||
<li><a class="reference internal" href="#funcparser-inlines">Funcparser inlines</a></li>
|
||||
<li><a class="reference internal" href="#backtracking">Backtracking</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#connecting-the-character-with-evennia">Connecting the Character with Evennia</a></li>
|
||||
<li><a class="reference internal" href="#unit-testing">Unit Testing</a></li>
|
||||
<li><a class="reference internal" href="#about-races-and-classes">About races and classes</a></li>
|
||||
<li><a class="reference internal" href="#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
|
||||
title="previous chapter">Rules and dice rolling</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Objects.html"
|
||||
title="next chapter">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">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Characters.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="player-characters">
|
||||
<h1>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>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>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="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="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="s2">"You heal for </span><span class="si">{healed}</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="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_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="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="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="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="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="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>
|
||||
</section>
|
||||
<section id="character-class">
|
||||
<h2>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="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="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="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>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>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>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_CLASS</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>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>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>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="In-game Objects and items"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Rules.html" title="Rules and dice rolling"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Player Characters</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,808 @@
|
|||
|
||||
<!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>Character Generation — Evennia 1.0-dev 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="In-game Rooms" href="Beginner-Tutorial-Rooms.html" />
|
||||
<link rel="prev" title="Handling Equipment" href="Beginner-Tutorial-Equipment.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-Rooms.html" title="In-game Rooms"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Equipment.html" title="Handling Equipment"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Character Generation</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">Character Generation</a><ul>
|
||||
<li><a class="reference internal" href="#how-it-will-work">How it will work</a></li>
|
||||
<li><a class="reference internal" href="#random-tables">Random tables</a></li>
|
||||
<li><a class="reference internal" href="#storing-state-of-the-menu">Storing state of the menu</a><ul>
|
||||
<li><a class="reference internal" href="#showing-the-sheet">Showing the sheet</a></li>
|
||||
<li><a class="reference internal" href="#apply-character">Apply character</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#initializing-evmenu">Initializing EvMenu</a></li>
|
||||
<li><a class="reference internal" href="#main-node-choosing-what-to-do">Main Node: Choosing what to do</a></li>
|
||||
<li><a class="reference internal" href="#node-changing-your-name">Node: Changing your name</a></li>
|
||||
<li><a class="reference internal" href="#node-swapping-abilities-around">Node: Swapping Abilities around</a></li>
|
||||
<li><a class="reference internal" href="#node-creating-the-character">Node: Creating the Character</a></li>
|
||||
<li><a class="reference internal" href="#tying-the-nodes-together">Tying the nodes together</a></li>
|
||||
<li><a class="reference internal" href="#conclusions">Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Equipment.html"
|
||||
title="previous chapter">Handling Equipment</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Rooms.html"
|
||||
title="next chapter">In-game Rooms</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-Chargen.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Chargen.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="character-generation">
|
||||
<h1>Character Generation<a class="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>
|
||||
<section id="how-it-will-work">
|
||||
<h2>How it will work<a class="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 <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and adding the line</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>AUTO_CREATE_CHARACTER_WITH_ACCOUNT = False
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>When doing this, connecting with the game with a new account will land you in “OOC” mode. The
|
||||
ooc-version of <code class="docutils literal notranslate"><span class="pre">look</span></code> (sitting in the Account cmdset) will show a list of available characters
|
||||
if you have any. You can also enter <code class="docutils literal notranslate"><span class="pre">charcreate</span></code> to make a new character. The <code class="docutils literal notranslate"><span class="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>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Silas</span>
|
||||
|
||||
<span class="n">STR</span> <span class="o">+</span><span class="mi">1</span>
|
||||
<span class="n">DEX</span> <span class="o">+</span><span class="mi">2</span>
|
||||
<span class="n">CON</span> <span class="o">+</span><span class="mi">1</span>
|
||||
<span class="n">INT</span> <span class="o">+</span><span class="mi">3</span>
|
||||
<span class="n">WIS</span> <span class="o">+</span><span class="mi">1</span>
|
||||
<span class="n">CHA</span> <span class="o">+</span><span class="mi">2</span>
|
||||
|
||||
<span class="n">You</span> <span class="n">are</span> <span class="n">lanky</span> <span class="k">with</span> <span class="n">a</span> <span class="n">sunken</span> <span class="n">face</span> <span class="ow">and</span> <span class="n">filthy</span> <span class="n">hair</span><span class="p">,</span> <span class="n">breathy</span> <span class="n">speech</span><span class="p">,</span> <span class="ow">and</span> <span class="n">foreign</span> <span class="n">clothing</span><span class="o">.</span>
|
||||
<span class="n">You</span> <span class="n">were</span> <span class="n">a</span> <span class="n">herbalist</span><span class="p">,</span> <span class="n">but</span> <span class="n">you</span> <span class="n">were</span> <span class="n">pursued</span> <span class="ow">and</span> <span class="n">ended</span> <span class="n">up</span> <span class="n">a</span> <span class="n">knave</span><span class="o">.</span> <span class="n">You</span> <span class="n">are</span> <span class="n">honest</span> <span class="n">but</span> <span class="n">also</span>
|
||||
<span class="n">suspicious</span><span class="o">.</span> <span class="n">You</span> <span class="n">are</span> <span class="n">of</span> <span class="n">the</span> <span class="n">neutral</span> <span class="n">alignment</span><span class="o">.</span>
|
||||
|
||||
<span class="n">Your</span> <span class="n">belongings</span><span class="p">:</span>
|
||||
<span class="n">Brigandine</span> <span class="n">armor</span><span class="p">,</span> <span class="n">ration</span><span class="p">,</span> <span class="n">ration</span><span class="p">,</span> <span class="n">sword</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span>
|
||||
<span class="n">tinderbox</span><span class="p">,</span> <span class="n">chisel</span><span class="p">,</span> <span class="n">whistle</span>
|
||||
|
||||
<span class="o">----------------------------------------------------------------------------------------</span>
|
||||
<span class="mf">1.</span> <span class="n">Change</span> <span class="n">your</span> <span class="n">name</span>
|
||||
<span class="mf">2.</span> <span class="n">Swap</span> <span class="n">two</span> <span class="n">of</span> <span class="n">your</span> <span class="n">ability</span> <span class="n">scores</span> <span class="p">(</span><span class="n">once</span><span class="p">)</span>
|
||||
<span class="mf">3.</span> <span class="n">Accept</span> <span class="ow">and</span> <span class="n">create</span> <span class="n">character</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you select 1, you get a new menu node:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Your</span> <span class="n">current</span> <span class="n">name</span> <span class="ow">is</span> <span class="n">Silas</span><span class="o">.</span> <span class="n">Enter</span> <span class="n">a</span> <span class="n">new</span> <span class="n">name</span> <span class="ow">or</span> <span class="n">leave</span> <span class="n">empty</span> <span class="n">to</span> <span class="n">abort</span><span class="o">.</span>
|
||||
<span class="o">-----------------------------------------------------------------------------------------</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can now enter a new name. When pressing return you’ll get back to the first menu node
|
||||
showing your character, now with the new name.</p>
|
||||
<p>If you select 2, you go to another menu node:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Your current abilities:
|
||||
|
||||
STR +1
|
||||
DEX +2
|
||||
CON +1
|
||||
INT +3
|
||||
WIS +1
|
||||
CHA +2
|
||||
|
||||
You can swap the values of two abilities around.
|
||||
You can only do this once, so choose carefully!
|
||||
|
||||
To swap the values of e.g. STR and INT, write 'STR INT'. Empty to abort.
|
||||
------------------------------------------------------------------------------------------
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you enter <code class="docutils literal notranslate"><span class="pre">WIS</span> <span class="pre">CHA</span></code> here, WIS will become <code class="docutils literal notranslate"><span class="pre">+2</span></code> and <code class="docutils literal notranslate"><span class="pre">CHA</span></code> <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">Accept</span> <span class="pre">and</span> <span class="pre">create</span> <span class="pre">character</span></code> option, the character will be created
|
||||
and you’ll leave the menu;</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Character was created!
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="random-tables">
|
||||
<h2>Random tables<a class="headerlink" href="#random-tables" title="Permalink to this headline">¶</a></h2>
|
||||
<aside class="sidebar">
|
||||
<p>Full Knave random tables are found in
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.random_tables.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/random_tables.py</span></a>.</p>
|
||||
</aside>
|
||||
<blockquote>
|
||||
<div><p>Make a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/random_tables.py</span></code>.</p>
|
||||
</div></blockquote>
|
||||
<p>Since most of <em>Knave</em>’s character generation is random we will need to roll on random tables
|
||||
from the <em>Knave</em> rulebook. While we added the ability to roll on a random table back in the
|
||||
<a class="reference internal" href="Beginner-Tutorial-Rules.html"><span class="doc std std-doc">Rules Tutorial</span></a>, we haven’t added the relevant tables yet.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/random_tables.py </span>
|
||||
|
||||
<span class="n">chargen_tables</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"physique"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="s2">"athletic"</span><span class="p">,</span> <span class="s2">"brawny"</span><span class="p">,</span> <span class="s2">"corpulent"</span><span class="p">,</span> <span class="s2">"delicate"</span><span class="p">,</span> <span class="s2">"gaunt"</span><span class="p">,</span> <span class="s2">"hulking"</span><span class="p">,</span> <span class="s2">"lanky"</span><span class="p">,</span>
|
||||
<span class="s2">"ripped"</span><span class="p">,</span> <span class="s2">"rugged"</span><span class="p">,</span> <span class="s2">"scrawny"</span><span class="p">,</span> <span class="s2">"short"</span><span class="p">,</span> <span class="s2">"sinewy"</span><span class="p">,</span> <span class="s2">"slender"</span><span class="p">,</span> <span class="s2">"flabby"</span><span class="p">,</span>
|
||||
<span class="s2">"statuesque"</span><span class="p">,</span> <span class="s2">"stout"</span><span class="p">,</span> <span class="s2">"tiny"</span><span class="p">,</span> <span class="s2">"towering"</span><span class="p">,</span> <span class="s2">"willowy"</span><span class="p">,</span> <span class="s2">"wiry"</span><span class="p">,</span>
|
||||
<span class="p">],</span>
|
||||
<span class="s2">"face"</span><span class="p">:</span> <span class="p">[</span>
|
||||
<span class="s2">"bloated"</span><span class="p">,</span> <span class="s2">"blunt"</span><span class="p">,</span> <span class="s2">"bony"</span><span class="p">,</span> <span class="c1"># ... </span>
|
||||
<span class="p">],</span> <span class="c1"># ... </span>
|
||||
<span class="p">}</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The tables are just copied from the <em>Knave</em> rules. We group the aspects in a dict
|
||||
<code class="docutils literal notranslate"><span class="pre">character_generation</span></code> to separate chargen-only tables from other random tables we’ll also
|
||||
keep in here.</p>
|
||||
</section>
|
||||
<section id="storing-state-of-the-menu">
|
||||
<h2>Storing state of the menu<a class="headerlink" href="#storing-state-of-the-menu" title="Permalink to this headline">¶</a></h2>
|
||||
<aside class="sidebar">
|
||||
<p>There is a full implementation of the chargen in
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.chargen.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/chargen.py</span></a>.</p>
|
||||
</aside>
|
||||
<blockquote>
|
||||
<div><p>create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/chargen.py</span></code>.</p>
|
||||
</div></blockquote>
|
||||
<p>During character generation we will need an entity to store/retain the changes, like a
|
||||
‘temporary character sheet’.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.random_tables</span> <span class="kn">import</span> <span class="n">chargen_tables</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">TemporaryCharacterSheet</span><span class="p">:</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_random_ability</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="nb">min</span><span class="p">(</span><span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d6"</span><span class="p">),</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d6"</span><span class="p">),</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d6"</span><span class="p">))</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</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">ability_changes</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># how many times we tried swap abilities</span>
|
||||
|
||||
<span class="c1"># name will likely be modified later</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d282"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"name"</span><span class="p">])</span>
|
||||
|
||||
<span class="c1"># base attribute values</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">strength</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">constitution</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">charisma</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># physical attributes (only for rp purposes)</span>
|
||||
<span class="n">physique</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"physique"</span><span class="p">])</span>
|
||||
<span class="n">face</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"face"</span><span class="p">])</span>
|
||||
<span class="n">skin</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"skin"</span><span class="p">])</span>
|
||||
<span class="n">hair</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"hair"</span><span class="p">])</span>
|
||||
<span class="n">clothing</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"clothing"</span><span class="p">])</span>
|
||||
<span class="n">speech</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"speech"</span><span class="p">])</span>
|
||||
<span class="n">virtue</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"virtue"</span><span class="p">])</span>
|
||||
<span class="n">vice</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"vice"</span><span class="p">])</span>
|
||||
<span class="n">background</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"background"</span><span class="p">])</span>
|
||||
<span class="n">misfortune</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"misfortune"</span><span class="p">])</span>
|
||||
<span class="n">alignment</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"alignment"</span><span class="p">])</span>
|
||||
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"You are </span><span class="si">{</span><span class="n">physique</span><span class="si">}</span><span class="s2"> with a </span><span class="si">{</span><span class="n">face</span><span class="si">}</span><span class="s2"> face, </span><span class="si">{</span><span class="n">skin</span><span class="si">}</span><span class="s2"> skin, </span><span class="si">{</span><span class="n">hair</span><span class="si">}</span><span class="s2"> hair, </span><span class="si">{</span><span class="n">speech</span><span class="si">}</span><span class="s2"> speech,"</span>
|
||||
<span class="sa">f</span><span class="s2">" and </span><span class="si">{</span><span class="n">clothing</span><span class="si">}</span><span class="s2"> clothing. You were a </span><span class="si">{</span><span class="n">background</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="si">}</span><span class="s2">, but you were"</span>
|
||||
<span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">misfortune</span><span class="si">}</span><span class="s2"> and ended up a knave. You are </span><span class="si">{</span><span class="n">virtue</span><span class="si">}</span><span class="s2"> but also </span><span class="si">{</span><span class="n">vice</span><span class="si">}</span><span class="s2">. You are of the"</span>
|
||||
<span class="sa">f</span><span class="s2">" </span><span class="si">{</span><span class="n">alignment</span><span class="si">}</span><span class="s2"> alignment."</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># </span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d8"</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="bp">self</span><span class="o">.</span><span class="n">xp</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="c1"># random equipment</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">armor</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"armor"</span><span class="p">])</span>
|
||||
|
||||
<span class="n">_helmet_and_shield</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"helmets and shields"</span><span class="p">])</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">helmet</span> <span class="o">=</span> <span class="s2">"helmet"</span> <span class="k">if</span> <span class="s2">"helmet"</span> <span class="ow">in</span> <span class="n">_helmet_and_shield</span> <span class="k">else</span> <span class="s2">"none"</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">shield</span> <span class="o">=</span> <span class="s2">"shield"</span> <span class="k">if</span> <span class="s2">"shield"</span> <span class="ow">in</span> <span class="n">_helmet_and_shield</span> <span class="k">else</span> <span class="s2">"none"</span>
|
||||
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">weapon</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"starting weapon"</span><span class="p">])</span>
|
||||
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">backpack</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="s2">"ration"</span><span class="p">,</span>
|
||||
<span class="s2">"ration"</span><span class="p">,</span>
|
||||
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"dungeoning gear"</span><span class="p">]),</span>
|
||||
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"dungeoning gear"</span><span class="p">]),</span>
|
||||
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"general gear 1"</span><span class="p">]),</span>
|
||||
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">"general gear 2"</span><span class="p">]),</span>
|
||||
<span class="p">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we have followed the <em>Knave</em> rulebook to randomize abilities, description and equipment.
|
||||
The <code class="docutils literal notranslate"><span class="pre">dice.roll()</span></code> and <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">.ability_changes</span> <span class="pre">=</span> <span class="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>
|
||||
<section id="showing-the-sheet">
|
||||
<h3>Showing the sheet<a class="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>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
|
||||
|
||||
<span class="n">_TEMP_SHEET</span> <span class="o">=</span> <span class="s2">"""</span>
|
||||
<span class="si">{name}</span><span class="s2"></span>
|
||||
|
||||
<span class="s2">STR +</span><span class="si">{strength}</span><span class="s2"></span>
|
||||
<span class="s2">DEX +</span><span class="si">{dexterity}</span><span class="s2"></span>
|
||||
<span class="s2">CON +</span><span class="si">{constitution}</span><span class="s2"></span>
|
||||
<span class="s2">INT +</span><span class="si">{intelligence}</span><span class="s2"></span>
|
||||
<span class="s2">WIS +</span><span class="si">{wisdom}</span><span class="s2"></span>
|
||||
<span class="s2">CHA +</span><span class="si">{charisma}</span><span class="s2"></span>
|
||||
|
||||
<span class="si">{description}</span><span class="s2"></span>
|
||||
<span class="s2"> </span>
|
||||
<span class="s2">Your belongings:</span>
|
||||
<span class="si">{equipment}</span><span class="s2"></span>
|
||||
<span class="s2">"""</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">TemporaryCharacterSheet</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">show_sheet</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="n">equipment</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="nb">str</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">armor</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">shield</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpack</span>
|
||||
<span class="k">if</span> <span class="n">item</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">_TEMP_SHEET</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
|
||||
<span class="n">name</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
|
||||
<span class="n">strength</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">strength</span><span class="p">,</span>
|
||||
<span class="n">dexterity</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span><span class="p">,</span>
|
||||
<span class="n">constitution</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">constitution</span><span class="p">,</span>
|
||||
<span class="n">intelligence</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span><span class="p">,</span>
|
||||
<span class="n">wisdom</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span><span class="p">,</span>
|
||||
<span class="n">charisma</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">charisma</span><span class="p">,</span>
|
||||
<span class="n">description</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">desc</span><span class="p">,</span>
|
||||
<span class="n">equipment</span><span class="o">=</span><span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">equipment</span><span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The new <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">_TEMP_SHEET</span></code> makes it easier to change things later if you want
|
||||
to change how things look.</p>
|
||||
</section>
|
||||
<section id="apply-character">
|
||||
<h3>Apply character<a class="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>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.characters</span> <span class="kn">import</span> <span class="n">EvAdventureCharacter</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.prototypes.spawner</span> <span class="kn">import</span> <span class="n">spawn</span>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">TemporaryCharacterSheet</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">apply</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="c1"># create character object with given abilities</span>
|
||||
<span class="n">new_character</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="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
|
||||
<span class="n">attrs</span><span class="o">=</span><span class="p">(</span>
|
||||
<span class="p">(</span><span class="s2">"strength"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">strength</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"dexterity"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"constitution"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">constitution</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"intelligence"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"wisdom"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"charisma"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"hp"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"hp_max"</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="p">(</span><span class="s2">"desc"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">desc</span><span class="p">),</span>
|
||||
<span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="c1"># spawn equipment (will require prototypes created before it works)</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="n">weapon</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">)</span>
|
||||
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">weapon</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">shield</span><span class="p">:</span>
|
||||
<span class="n">shield</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">shield</span><span class="p">)</span>
|
||||
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">shield</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">armor</span><span class="p">:</span>
|
||||
<span class="n">armor</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">armor</span><span class="p">)</span>
|
||||
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">armor</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">:</span>
|
||||
<span class="n">helmet</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">)</span>
|
||||
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">helmet</span><span class="p">)</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpack</span><span class="p">:</span>
|
||||
<span class="n">item</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
|
||||
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">store</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">new_character</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We use <code class="docutils literal notranslate"><span class="pre">create_object</span></code> to create a new <code class="docutils literal notranslate"><span class="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>
|
||||
<aside class="sidebar">
|
||||
<p>A prototype is basically a <code class="docutils literal notranslate"><span class="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 <a class="reference internal" href="../../../Components/Prototypes.html"><span class="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 <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> we
|
||||
created in the <a class="reference internal" href="Beginner-Tutorial-Equipment.html"><span class="doc std std-doc">Equipment lesson</span></a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="initializing-evmenu">
|
||||
<h2>Initializing EvMenu<a class="headerlink" href="#initializing-evmenu" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Evennia comes with a full menu-generation system based on <a class="reference internal" href="../../../Components/Command-Sets.html"><span class="doc std std-doc">Command sets</span></a>, called
|
||||
<a class="reference internal" href="../../../Components/EvMenu.html"><span class="doc std std-doc">EvMenu</span></a>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">EvMenu</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="c1"># chargen menu </span>
|
||||
|
||||
|
||||
<span class="c1"># this goes to the bottom of the module</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">start_chargen</span><span class="p">(</span><span class="n">caller</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="sd">"""</span>
|
||||
<span class="sd"> This is a start point for spinning up the chargen from a command later.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">menutree</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># TODO!</span>
|
||||
|
||||
<span class="c1"># this generates all random components of the character</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">TemporaryCharacterSheet</span><span class="p">()</span>
|
||||
|
||||
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menutree</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="n">tmp_character</span><span class="o">=</span><span class="n">tmp_character</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This first function is what we will call from elsewhere (for example from a custom <code class="docutils literal notranslate"><span class="pre">charcreate</span></code>
|
||||
command) to kick the menu into gear.</p>
|
||||
<p>It takes the <code class="docutils literal notranslate"><span class="pre">caller</span></code> (the one to want to start the menu) and a <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">TemporaryCharacterSheet</span></code> and call <code class="docutils literal notranslate"><span class="pre">.generate()</span></code> to make a random character. We then
|
||||
feed all this into <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">menutree</span></code> is what we’ll create next. It describes which menu ‘nodes’ are available to jump
|
||||
between.</p>
|
||||
</section>
|
||||
<section id="main-node-choosing-what-to-do">
|
||||
<h2>Main Node: Choosing what to do<a class="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>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="c1"># at the end of the module, but before the `start_chargen` function</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">node_chargen</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">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">"tmp_character"</span><span class="p">]</span>
|
||||
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="n">tmp_character</span><span class="o">.</span><span class="n">show_sheet</span><span class="p">()</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">"Change your name"</span><span class="p">,</span>
|
||||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"node_change_name"</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">]</span>
|
||||
<span class="k">if</span> <span class="n">tmp_character</span><span class="o">.</span><span class="n">ability_changes</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="n">options</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Swap two of your ability scores (once)"</span><span class="p">,</span>
|
||||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"node_swap_abilities"</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">),</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">options</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
|
||||
<span class="p">{</span>
|
||||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Accept and create character"</span><span class="p">,</span>
|
||||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"node_apply_character"</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</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="c1"># ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A lot to unpack here! In Evennia, it’s convention to name your node-functions <code class="docutils literal notranslate"><span class="pre">node_*</span></code>. While
|
||||
not required, it helps you track what is a node and not.</p>
|
||||
<p>Every menu-node, should accept <code class="docutils literal notranslate"><span class="pre">caller,</span> <span class="pre">raw_string,</span> <span class="pre">**kwargs</span></code> as arguments. Here <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the
|
||||
<code class="docutils literal notranslate"><span class="pre">caller</span></code> you passed into the <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> call. <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> are all extra keyword arguments passed
|
||||
into <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>. They can also be passed between nodes. In this case, we passed the
|
||||
keyword <code class="docutils literal notranslate"><span class="pre">tmp_character</span></code> to <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>. We now have the temporary character sheet available in the
|
||||
node!</p>
|
||||
<p>An <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> node must always return two things - <code class="docutils literal notranslate"><span class="pre">text</span></code> and <code class="docutils literal notranslate"><span class="pre">options</span></code>. The <code class="docutils literal notranslate"><span class="pre">text</span></code> is what will
|
||||
show to the user when looking at this node. The <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">dict</span></code> like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||||
<span class="s2">"key"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"name"</span><span class="o">.</span> <span class="s2">"alias1"</span><span class="p">,</span> <span class="s2">"alias2"</span><span class="p">,</span> <span class="o">...</span><span class="p">),</span> <span class="c1"># if skipped, auto-show a number</span>
|
||||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"text to describe what happens when selecting option"</span><span class="p">,</span><span class="o">.</span>
|
||||
<span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="s2">"name of node or a callable"</span><span class="p">,</span> <span class="n">kwargs_to_pass_into_next_node_or_callable</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Multiple option-dicts are returned in a list or tuple. The <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> in the callable or next node.</p>
|
||||
<p>While an option can have a <code class="docutils literal notranslate"><span class="pre">key</span></code>, you can also skip it to just get a running number.</p>
|
||||
<p>In our <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> node, we point to three nodes by name: <code class="docutils literal notranslate"><span class="pre">node_change_name</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">node_swap_abilities</span></code>, and <code class="docutils literal notranslate"><span class="pre">node_apply_character</span></code>. We also make sure to pass along <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">.ability_changes</span></code> property to make sure it’s still 0.</p>
|
||||
</section>
|
||||
<section id="node-changing-your-name">
|
||||
<h2>Node: Changing your name<a class="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 <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="c1"># after previous node </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_update_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="sd">"""</span>
|
||||
<span class="sd"> Used by node_change_name below to check what user </span>
|
||||
<span class="sd"> entered and update the name if appropriate.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="n">raw_string</span><span class="p">:</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">"tmp_character"</span><span class="p">]</span>
|
||||
<span class="n">tmp_character</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">raw_string</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span>
|
||||
|
||||
<span class="k">return</span> <span class="s2">"node_chargen"</span><span class="p">,</span> <span class="n">kwargs</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">node_change_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="sd">"""</span>
|
||||
<span class="sd"> Change the random name of the character.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">"tmp_character"</span><span class="p">]</span>
|
||||
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"Your current name is |w</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">|n. "</span>
|
||||
<span class="s2">"Enter a new name or leave empty to abort."</span>
|
||||
<span class="p">)</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">_update_name</span><span class="p">,</span> <span class="n">kwargs</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>There are two functions here - the menu node itself (<code class="docutils literal notranslate"><span class="pre">node_change_name</span></code>) and a
|
||||
helper <em>goto_function</em> (<code class="docutils literal notranslate"><span class="pre">_update_name</span></code>) to handle the user’s input.</p>
|
||||
<p>For the (single) option, we use a special <code class="docutils literal notranslate"><span class="pre">key</span></code> named <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">goto</span></code> part of the option points to the <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> callable rather than to
|
||||
the name of a node. It’s important we keep passing <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> along to it!</p>
|
||||
<p>When a user writes anything at this node, the <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> we now have a use for the <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> must return the name of the next node to use. It can also
|
||||
optionally return the <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code>.</p>
|
||||
<blockquote>
|
||||
<div><p>Hint: If returning <code class="docutils literal notranslate"><span class="pre">None</span></code> from a goto-callable, you will always return to the last node you
|
||||
were at.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="node-swapping-abilities-around">
|
||||
<h2>Node: Swapping Abilities around<a class="headerlink" href="#node-swapping-abilities-around" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You get here by selecting the second option from the <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> node.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="c1"># after previous node </span>
|
||||
|
||||
<span class="n">_ABILITIES</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"STR"</span><span class="p">:</span> <span class="s2">"strength"</span><span class="p">,</span>
|
||||
<span class="s2">"DEX"</span><span class="p">:</span> <span class="s2">"dexterity"</span><span class="p">,</span>
|
||||
<span class="s2">"CON"</span><span class="p">:</span> <span class="s2">"constitution"</span><span class="p">,</span>
|
||||
<span class="s2">"INT"</span><span class="p">:</span> <span class="s2">"intelligence"</span><span class="p">,</span>
|
||||
<span class="s2">"WIS"</span><span class="p">:</span> <span class="s2">"wisdom"</span><span class="p">,</span>
|
||||
<span class="s2">"CHA"</span><span class="p">:</span> <span class="s2">"charisma"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">_swap_abilities</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="sd">"""</span>
|
||||
<span class="sd"> Used by node_swap_abilities to parse the user's input and swap ability</span>
|
||||
<span class="sd"> values.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="n">raw_string</span><span class="p">:</span>
|
||||
<span class="n">abi1</span><span class="p">,</span> <span class="o">*</span><span class="n">abi2</span> <span class="o">=</span> <span class="n">raw_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">abi2</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">"That doesn't look right."</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="n">kwargs</span>
|
||||
<span class="n">abi2</span> <span class="o">=</span> <span class="n">abi2</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<span class="n">abi1</span><span class="p">,</span> <span class="n">abi2</span> <span class="o">=</span> <span class="n">abi1</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="n">abi2</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">abi1</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_ABILITIES</span> <span class="ow">or</span> <span class="n">abi2</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_ABILITIES</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">"Not a familiar set of abilites."</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="n">kwargs</span>
|
||||
|
||||
<span class="c1"># looks okay = swap values. We need to convert STR to strength etc</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">"tmp_character"</span><span class="p">]</span>
|
||||
<span class="n">abi1</span> <span class="o">=</span> <span class="n">_ABILITIES</span><span class="p">[</span><span class="n">abi1</span><span class="p">]</span>
|
||||
<span class="n">abi2</span> <span class="o">=</span> <span class="n">_ABILITIES</span><span class="p">[</span><span class="n">abi2</span><span class="p">]</span>
|
||||
<span class="n">abival1</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi1</span><span class="p">)</span>
|
||||
<span class="n">abival2</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi2</span><span class="p">)</span>
|
||||
|
||||
<span class="nb">setattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi1</span><span class="p">,</span> <span class="n">abival2</span><span class="p">)</span>
|
||||
<span class="nb">setattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi2</span><span class="p">,</span> <span class="n">abival1</span><span class="p">)</span>
|
||||
|
||||
<span class="n">tmp_character</span><span class="o">.</span><span class="n">ability_changes</span> <span class="o">+=</span> <span class="mi">1</span>
|
||||
|
||||
<span class="k">return</span> <span class="s2">"node_chargen"</span><span class="p">,</span> <span class="n">kwargs</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">node_swap_abilities</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="sd">""" </span>
|
||||
<span class="sd"> One is allowed to swap the values of two abilities around, once.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">"tmp_character"</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">Your current abilities:</span>
|
||||
|
||||
<span class="s2">STR +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">strength</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2">DEX +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">dexterity</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2">CON +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">constitution</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2">INT +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">intelligence</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2">WIS +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">wisdom</span><span class="si">}</span><span class="s2"></span>
|
||||
<span class="s2">CHA +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">charisma</span><span class="si">}</span><span class="s2"></span>
|
||||
|
||||
<span class="s2">You can swap the values of two abilities around.</span>
|
||||
<span class="s2">You can only do this once, so choose carefully!</span>
|
||||
|
||||
<span class="s2">To swap the values of e.g. STR and INT, write |wSTR INT|n. Empty to abort.</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">"_default"</span><span class="p">,</span> <span class="s2">"goto"</span><span class="p">:</span> <span class="p">(</span><span class="n">_swap_abilities</span><span class="p">,</span> <span class="n">kwargs</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 is more code, but the logic is the same - we have a node (<code class="docutils literal notranslate"><span class="pre">node_swap_abilities</span></code>) and
|
||||
and a goto-callable helper (<code class="docutils literal notranslate"><span class="pre">_swap_abilities</span></code>). We catch everything the user writes on the
|
||||
node (such as <code class="docutils literal notranslate"><span class="pre">WIS</span> <span class="pre">CON</span></code>) and feed it into the helper.</p>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">_swap_abilities</span></code>, we need to analyze the <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">caller.msg()</span></code> to tell them and then return <code class="docutils literal notranslate"><span class="pre">None,</span> <span class="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 <code class="docutils literal notranslate"><span class="pre">_ABILITIES</span></code> to easily convert between the two (it’s stored as <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> again.</p>
|
||||
</section>
|
||||
<section id="node-creating-the-character">
|
||||
<h2>Node: Creating the Character<a class="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>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">node_apply_character</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="sd">""" </span>
|
||||
<span class="sd"> End chargen and create the character. We will also puppet it.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">"tmp_character"</span><span class="p">]</span>
|
||||
<span class="n">new_character</span> <span class="o">=</span> <span class="n">tmp_character</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span>
|
||||
|
||||
<span class="n">caller</span><span class="o">.</span><span class="n">account</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">_playable_characters</span> <span class="o">=</span> <span class="p">[</span><span class="n">new_character</span><span class="p">]</span>
|
||||
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="s2">"Character created!"</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="kc">None</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>When entering the node, we will take the Temporary character sheet and use its <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">_playable_characters</span></code> Attribute, so we need to
|
||||
also the new character to it.</p>
|
||||
</section>
|
||||
<section id="tying-the-nodes-together">
|
||||
<h2>Tying the nodes together<a class="headerlink" href="#tying-the-nodes-together" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">start_chargen</span><span class="p">(</span><span class="n">caller</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="sd">"""</span>
|
||||
<span class="sd">This is a start point for spinning up the chargen from a command later.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">menutree</span> <span class="o">=</span> <span class="p">{</span> <span class="c1"># <----- can now add this!</span>
|
||||
<span class="s2">"node_chargen"</span><span class="p">:</span> <span class="n">node_chargen</span><span class="p">,</span>
|
||||
<span class="s2">"node_change_name"</span><span class="p">:</span> <span class="n">node_change_name</span><span class="p">,</span>
|
||||
<span class="s2">"node_swap_abilities"</span><span class="p">:</span> <span class="n">node_swap_abilities</span><span class="p">,</span>
|
||||
<span class="s2">"node_apply_character"</span><span class="p">:</span> <span class="n">node_apply_character</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="c1"># this generates all random components of the character</span>
|
||||
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">TemporaryCharacterSheet</span><span class="p">()</span>
|
||||
<span class="n">tmp_character</span><span class="o">.</span><span class="n">generate</span><span class="p">()</span>
|
||||
|
||||
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menutree</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
||||
<span class="n">startnode</span><span class="o">=</span><span class="s2">"node_chargen"</span><span class="p">,</span> <span class="c1"># <----- </span>
|
||||
<span class="n">tmp_character</span><span class="o">=</span><span class="n">tmp_character</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now that we have all the nodes, we add them to the <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">startnode</span></code> pointing to the <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> node. This tells EvMenu
|
||||
to first jump into that node when the menu is starting up.</p>
|
||||
</section>
|
||||
<section id="conclusions">
|
||||
<h2>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This lesson taught us how to use <code class="docutils literal notranslate"><span class="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>
|
||||
</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-Rooms.html" title="In-game Rooms"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Equipment.html" title="Handling Equipment"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Character Generation</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
<!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>In-game Commands — Evennia 1.0-dev 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="Part 4: Using what we created" href="../Part4/Beginner-Tutorial-Part4-Intro.html" />
|
||||
<link rel="prev" title="Dynamically generated Dungeon" href="Beginner-Tutorial-Dungeon.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="../Part4/Beginner-Tutorial-Part4-Intro.html" title="Part 4: Using what we created"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Dungeon.html" title="Dynamically generated Dungeon"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Commands</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Dungeon.html"
|
||||
title="previous chapter">Dynamically generated Dungeon</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="../Part4/Beginner-Tutorial-Part4-Intro.html"
|
||||
title="next chapter">Part 4: Using what we created</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-Commands.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Commands.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="in-game-commands">
|
||||
<h1>In-game Commands<a class="headerlink" href="#in-game-commands" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This part of the Beginner tutorial is still being developed.</p>
|
||||
</div>
|
||||
</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="../Part4/Beginner-Tutorial-Part4-Intro.html" title="Part 4: Using what we created"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Dungeon.html" title="Dynamically generated Dungeon"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Commands</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
<!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>Dynamically generated Dungeon — Evennia 1.0-dev 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="In-game Commands" href="Beginner-Tutorial-Commands.html" />
|
||||
<link rel="prev" title="In-game Shops" href="Beginner-Tutorial-Shops.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-Commands.html" title="In-game Commands"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Shops.html" title="In-game Shops"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Dynamically generated Dungeon</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Shops.html"
|
||||
title="previous chapter">In-game Shops</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Commands.html"
|
||||
title="next chapter">In-game Commands</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-Dungeon.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Dungeon.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="dynamically-generated-dungeon">
|
||||
<h1>Dynamically generated Dungeon<a class="headerlink" href="#dynamically-generated-dungeon" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This part of the Beginner tutorial is still being developed.</p>
|
||||
</div>
|
||||
</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-Commands.html" title="In-game Commands"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Shops.html" title="In-game Shops"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Dynamically generated Dungeon</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,708 @@
|
|||
|
||||
<!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>Handling Equipment — Evennia 1.0-dev 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="Character Generation" href="Beginner-Tutorial-Chargen.html" />
|
||||
<link rel="prev" title="In-game Objects and items" href="Beginner-Tutorial-Objects.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-Chargen.html" title="Character Generation"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Objects.html" title="In-game Objects and items"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Handling Equipment</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">Handling Equipment</a><ul>
|
||||
<li><a class="reference internal" href="#equipmenthandler-that-saves">EquipmentHandler that saves</a></li>
|
||||
<li><a class="reference internal" href="#connecting-the-equipmenthandler">Connecting the EquipmentHandler</a></li>
|
||||
<li><a class="reference internal" href="#expanding-the-equipmenthandler">Expanding the Equipmenthandler</a></li>
|
||||
<li><a class="reference internal" href="#validate-slot-usage"><code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code></a><ul>
|
||||
<li><a class="reference internal" href="#max-slots"><code class="docutils literal notranslate"><span class="pre">.max_slots</span></code></a></li>
|
||||
<li><a class="reference internal" href="#count-slots"><code class="docutils literal notranslate"><span class="pre">.count_slots</span></code></a></li>
|
||||
<li><a class="reference internal" href="#validating-slots">Validating slots</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#add-and-remove"><code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code></a></li>
|
||||
<li><a class="reference internal" href="#moving-things-around">Moving things around</a></li>
|
||||
<li><a class="reference internal" href="#get-everything">Get everything</a></li>
|
||||
<li><a class="reference internal" href="#weapon-and-armor">Weapon and armor</a></li>
|
||||
<li><a class="reference internal" href="#extra-credits">Extra credits</a></li>
|
||||
<li><a class="reference internal" href="#unit-testing">Unit Testing</a></li>
|
||||
<li><a class="reference internal" href="#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Objects.html"
|
||||
title="previous chapter">In-game Objects and items</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Chargen.html"
|
||||
title="next chapter">Character Generation</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-Equipment.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Equipment.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="handling-equipment">
|
||||
<h1>Handling Equipment<a class="headerlink" href="#handling-equipment" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In <em>Knave</em>, you have a certain number of inventory “slots”. The amount of slots is given by <code class="docutils literal notranslate"><span class="pre">CON</span> <span class="pre">+</span> <span class="pre">10</span></code>.
|
||||
All items (except coins) have a <code class="docutils literal notranslate"><span class="pre">size</span></code>, indicating how many slots it uses. You can’t carry more items
|
||||
than you have slot-space for. Also items wielded or worn count towards the slots.</p>
|
||||
<p>We still need to track what the character is using however: What weapon they have readied affects the damage
|
||||
they can do. The shield, helmet and armor they use affects their defense.</p>
|
||||
<p>We have already set up the possible ‘wear/wield locations’ when we defined our Objects
|
||||
<a class="reference internal" href="Beginner-Tutorial-Objects.html"><span class="doc std std-doc">in the previous lesson</span></a>. This is what we have in <code class="docutils literal notranslate"><span class="pre">enums.py</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">WieldLocation</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||||
|
||||
<span class="n">BACKPACK</span> <span class="o">=</span> <span class="s2">"backpack"</span>
|
||||
<span class="n">WEAPON_HAND</span> <span class="o">=</span> <span class="s2">"weapon_hand"</span>
|
||||
<span class="n">SHIELD_HAND</span> <span class="o">=</span> <span class="s2">"shield_hand"</span>
|
||||
<span class="n">TWO_HANDS</span> <span class="o">=</span> <span class="s2">"two_handed_weapons"</span>
|
||||
<span class="n">BODY</span> <span class="o">=</span> <span class="s2">"body"</span> <span class="c1"># armor</span>
|
||||
<span class="n">HEAD</span> <span class="o">=</span> <span class="s2">"head"</span> <span class="c1"># helmets</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Basically, all the weapon/armor locations are exclusive - you can only have one item in each (or none).
|
||||
The BACKPACK is special - it contains any number of items (up to the maximum slot usage).</p>
|
||||
<section id="equipmenthandler-that-saves">
|
||||
<h2>EquipmentHandler that saves<a class="headerlink" href="#equipmenthandler-that-saves" title="Permalink to this headline">¶</a></h2>
|
||||
<blockquote>
|
||||
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/equipment.py</span></code>.</p>
|
||||
</div></blockquote>
|
||||
<aside class="sidebar">
|
||||
<p>If you want to understand more about behind how Evennia uses handlers, there is a
|
||||
<a class="reference internal" href="../../Tutorial-Persistent-Handler.html"><span class="doc std std-doc">dedicated tutorial</span></a> talking about the principle.</p>
|
||||
</aside>
|
||||
<p>In default Evennia, everything you pick up will end up “inside” your character object (that is, have
|
||||
you as its <code class="docutils literal notranslate"><span class="pre">.location</span></code>). This is called your <em>inventory</em> and has no limit. We will keep ‘moving items into us’
|
||||
when we pick them up, but we will add more functionality using an <em>Equipment handler</em>.</p>
|
||||
<p>A handler is (for our purposes) an object that sits “on” another entity, containing functionality
|
||||
for doing one specific thing (managing equipment, in our case).</p>
|
||||
<p>This is the start of our handler:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/equipment.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
|
||||
<span class="n">save_attribute</span> <span class="o">=</span> <span class="s2">"inventory_slots"</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||||
<span class="c1"># here obj is the character we store the handler on </span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">obj</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_load</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_load</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Load our data from an Attribute on `self.obj`"""</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">save_attribute</span><span class="p">,</span>
|
||||
<span class="n">category</span><span class="o">=</span><span class="s2">"inventory"</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="p">{</span>
|
||||
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span> <span class="p">[]</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Save our data back to the same Attribute"""</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</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="bp">self</span><span class="o">.</span><span class="n">save_attribute</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"inventory"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is a compact and functional little handler. Before analyzing how it works, this is how
|
||||
we will add it to the Character:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/characters.py</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">lazy_property</span>
|
||||
<span class="kn">from</span> <span class="nn">.equipment</span> <span class="kn">import</span> <span class="n">EquipmentHandler</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="nd">@lazy_property</span>
|
||||
<span class="k">def</span> <span class="nf">equipment</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="n">EquipmentHandler</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>After reloading the server, the equipment-handler will now be accessible on character-instances as</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>character.equipment
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">@lazy_property</span></code> works such that it will not load the handler until someone actually tries to
|
||||
fetch it with <code class="docutils literal notranslate"><span class="pre">character.equipment</span></code>. When that
|
||||
happens, we start up the handler and feed it <code class="docutils literal notranslate"><span class="pre">self</span></code> (the <code class="docutils literal notranslate"><span class="pre">Character</span></code> instance itself). This is what
|
||||
enters <code class="docutils literal notranslate"><span class="pre">__init__</span></code> as <code class="docutils literal notranslate"><span class="pre">.obj</span></code> in the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> code above.</p>
|
||||
<p>So we now have a handler on the character, and the handler has a back-reference to the character it sits
|
||||
on.</p>
|
||||
<p>Since the handler itself is just a regular Python object, we need to use the <code class="docutils literal notranslate"><span class="pre">Character</span></code> to store
|
||||
our data - our <em>Knave</em> “slots”. We must save them to the database, because we want the server to remember
|
||||
them even after reloading.</p>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">self.obj.attributes.add()</span></code> and <code class="docutils literal notranslate"><span class="pre">.get()</span></code> we save the data to the Character in a specially named
|
||||
<a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a>. Since we use a <code class="docutils literal notranslate"><span class="pre">category</span></code>, we are unlikely to collide with
|
||||
other Attributes.</p>
|
||||
<p>Our storage structure is a <code class="docutils literal notranslate"><span class="pre">dict</span></code> with keys after our available <code class="docutils literal notranslate"><span class="pre">WieldLocation</span></code> enums. Each can only
|
||||
have one item except <code class="docutils literal notranslate"><span class="pre">WieldLocation.BACKPACK</span></code>, which is a list.</p>
|
||||
</section>
|
||||
<section id="connecting-the-equipmenthandler">
|
||||
<h2>Connecting the EquipmentHandler<a class="headerlink" href="#connecting-the-equipmenthandler" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Whenever an object leaves from one location to the next, Evennia will call a set of <em>hooks</em> (methods) on the
|
||||
object that moves, on the source-location and on its destination. This is the same for all moving things -
|
||||
whether it’s a character moving between rooms or an item being dropping from your hand to the ground.</p>
|
||||
<p>We need to tie our new <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> into this system. By reading the doc page on <a class="reference internal" href="../../../Components/Objects.html"><span class="doc std std-doc">Objects</span></a>,
|
||||
or looking at the <a class="reference internal" href="../../../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.move_to" title="evennia.objects.objects.DefaultObject.move_to"><span class="xref myst py py-meth">DefaultObject.move_to</span></a> docstring, we’ll
|
||||
find out what hooks Evennia will call. Here <code class="docutils literal notranslate"><span class="pre">self</span></code> is the object being moved from
|
||||
<code class="docutils literal notranslate"><span class="pre">source_location</span></code> to <code class="docutils literal notranslate"><span class="pre">destination</span></code>:</p>
|
||||
<ol class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">self.at_pre_move(destination)</span></code> (abort if return False)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">source_location.at_pre_object_leave(self,</span> <span class="pre">destination)</span></code> (abort if return False)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">destination.at_pre_object_receive(self,</span> <span class="pre">source_location)</span></code> (abort if return False)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">source_location.at_object_leave(self,</span> <span class="pre">destination)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">self.announce_move_from(destination)</span></code></p></li>
|
||||
<li><p>(move happens here)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">self.announce_move_to(source_location)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">destination.at_object_receive(self,</span> <span class="pre">source_location)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">self.at_post_move(source_location)</span></code></p></li>
|
||||
</ol>
|
||||
<p>All of these hooks can be overridden to customize movement behavior. In this case we are interested in
|
||||
controlling how items ‘enter’ and ‘leave’ our character - being ‘inside’ the character is the same as
|
||||
them ‘carrying’ it. We have three good hook-candidates to use for this.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.at_pre_object_receive</span></code> - used to check if you can actually pick something up, or if your equipment-store is full.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.at_object_receive</span></code> - used to add the item to the equipmenthandler</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.at_object_leave</span></code> - used to remove the item from the equipmenthandler</p></li>
|
||||
</ul>
|
||||
<p>You could also picture using <code class="docutils literal notranslate"><span class="pre">.at_pre_object_leave</span></code> to restrict dropping (cursed?) items, but
|
||||
we will skip that for this tutorial.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/character.py </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="k">def</span> <span class="nf">at_pre_object_receive</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">moved_object</span><span class="p">,</span> <span class="n">source_location</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">"""Called by Evennia before object arrives 'in' this character (that is,</span>
|
||||
<span class="sd"> if they pick up something). If it returns False, move is aborted.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">validate_slot_usage</span><span class="p">(</span><span class="n">moved_object</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_object_receive</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">moved_object</span><span class="p">,</span> <span class="n">source_location</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Called by Evennia when an object arrives 'in' the character.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">moved_object</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_object_leave</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">moved_object</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Called by Evennia when object leaves the Character. </span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">moved_object</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Above we have assumed the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> (<code class="docutils literal notranslate"><span class="pre">.equipment</span></code>) has methods <code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code>. But we haven’t actually added them yet - we just put some reasonable names! Before
|
||||
we can use this, we need to go actually adding those methods.</p>
|
||||
</section>
|
||||
<section id="expanding-the-equipmenthandler">
|
||||
<h2>Expanding the Equipmenthandler<a class="headerlink" href="#expanding-the-equipmenthandler" title="Permalink to this headline">¶</a></h2>
|
||||
</section>
|
||||
<section id="validate-slot-usage">
|
||||
<h2><code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code><a class="headerlink" href="#validate-slot-usage" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Let’s start with implementing the first method we came up with above, <code class="docutils literal notranslate"><span class="pre">validate_slot_usage</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentError</span><span class="p">(</span><span class="ne">TypeError</span><span class="p">):</span>
|
||||
<span class="sd">"""All types of equipment-errors"""</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">max_slots</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Max amount of slots, based on CON defense (CON + 10)"""</span>
|
||||
<span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">count_slots</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Count current slot usage"""</span>
|
||||
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
|
||||
<span class="n">wield_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
|
||||
<span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">"size"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">or</span> <span class="mi">0</span>
|
||||
<span class="k">for</span> <span class="n">slot</span><span class="p">,</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">backpack_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
|
||||
<span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">"size"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">or</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">return</span> <span class="n">wield_usage</span> <span class="o">+</span> <span class="n">backpack_usage</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">validate_slot_usage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Check if obj can fit in equipment, based on its size.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="c1"># in case we mix with non-evadventure objects</span>
|
||||
<span class="k">raise</span> <span class="n">EquipmentError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is not something that can be equipped."</span><span class="p">)</span>
|
||||
|
||||
<span class="n">size</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">size</span>
|
||||
<span class="n">max_slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_slots</span>
|
||||
<span class="n">current_slot_usage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">count_slots</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">current_slot_usage</span> <span class="o">+</span> <span class="n">size</span> <span class="o"><=</span> <span class="n">max_slots</span><span class="p">:</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">@property</span></code> decorator turns a method into a property so you don’t need to ‘call’ it.
|
||||
That is, you can access <code class="docutils literal notranslate"><span class="pre">.max_slots</span></code> instead of <code class="docutils literal notranslate"><span class="pre">.max_slots()</span></code>. In this case, it’s just a
|
||||
little less to type.</p>
|
||||
</aside>
|
||||
<p>We add two helpers - the <code class="docutils literal notranslate"><span class="pre">max_slots</span></code> <em>property</em> and <code class="docutils literal notranslate"><span class="pre">count_slots</span></code>, a method that calculate the current
|
||||
slots being in use. Let’s figure out how they work.</p>
|
||||
<section id="max-slots">
|
||||
<h3><code class="docutils literal notranslate"><span class="pre">.max_slots</span></code><a class="headerlink" href="#max-slots" title="Permalink to this headline">¶</a></h3>
|
||||
<p>For <code class="docutils literal notranslate"><span class="pre">max_slots</span></code>, remember that <code class="docutils literal notranslate"><span class="pre">.obj</span></code> on the handler is a back-reference to the <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> we
|
||||
put this handler on. <code class="docutils literal notranslate"><span class="pre">getattr</span></code> is a Python method for retrieving a named property on an object.
|
||||
The <code class="docutils literal notranslate"><span class="pre">Enum</span></code> <code class="docutils literal notranslate"><span class="pre">Ability.CON.value</span></code> is the string <code class="docutils literal notranslate"><span class="pre">Constitution</span></code> (check out the
|
||||
<a class="reference internal" href="Beginner-Tutorial-Utilities.html"><span class="doc std std-doc">first Utility and Enums tutorial</span></a> if you don’t recall).</p>
|
||||
<p>So to be clear,</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>is the same as writing</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">getattr</span><span class="p">(</span><span class="n">your_character</span><span class="p">,</span> <span class="s2">"Constitution"</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>which is the same as doing something like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">your_character</span><span class="o">.</span><span class="n">Constitution</span> <span class="o">+</span> <span class="mi">10</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In our code we write <code class="docutils literal notranslate"><span class="pre">getattr(self.obj,</span> <span class="pre">Ability.CON.value,</span> <span class="pre">1)</span></code> - that extra <code class="docutils literal notranslate"><span class="pre">1</span></code> means that if there
|
||||
should happen to <em>not</em> be a property “Constitution” on <code class="docutils literal notranslate"><span class="pre">self.obj</span></code>, we should not error out but just
|
||||
return 1.</p>
|
||||
</section>
|
||||
<section id="count-slots">
|
||||
<h3><code class="docutils literal notranslate"><span class="pre">.count_slots</span></code><a class="headerlink" href="#count-slots" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In this helper we use two Python tools - the <code class="docutils literal notranslate"><span class="pre">sum()</span></code> function and a
|
||||
<a class="reference external" href="https://www.w3schools.com/python/python_lists_comprehension.asp">list comprehension</a>. The former
|
||||
simply adds the values of any iterable together. The latter is a more efficient way to create a list:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>new_list = [item for item in some_iterable if condition]
|
||||
all_above_5 = [num for num in range(10) if num > 5] # [6, 7, 8, 9]
|
||||
all_below_5 = [num for num in range(10) if num < 5] # [0, 1, 2, 3, 4]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To make it easier to understand, try reading the last line above as “for every number in the range 0-9,
|
||||
pick all with a value below 5 and make a list of them”. You can also embed such comprehensions
|
||||
directly in a function call like <code class="docutils literal notranslate"><span class="pre">sum()</span></code> without using <code class="docutils literal notranslate"><span class="pre">[]</span></code> around it.</p>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">count_slots</span></code> we have this code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">wield_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
|
||||
<span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">"size"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="k">for</span> <span class="n">slot</span><span class="p">,</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We should be able to follow all except <code class="docutils literal notranslate"><span class="pre">slots.items()</span></code>. Since <code class="docutils literal notranslate"><span class="pre">slots</span></code> is a <code class="docutils literal notranslate"><span class="pre">dict</span></code>, we can use <code class="docutils literal notranslate"><span class="pre">.items()</span></code>
|
||||
to get a sequence of <code class="docutils literal notranslate"><span class="pre">(key,</span> <span class="pre">value)</span></code> pairs. We store these in <code class="docutils literal notranslate"><span class="pre">slot</span></code> and <code class="docutils literal notranslate"><span class="pre">slotobj</span></code>. So the above can
|
||||
be understood as “for every <code class="docutils literal notranslate"><span class="pre">slot</span></code> and <code class="docutils literal notranslate"><span class="pre">slotobj</span></code>-pair in <code class="docutils literal notranslate"><span class="pre">slots</span></code>, check which slot location it is.
|
||||
If it is <em>not</em> in the backpack, get its size and add it to the list. Sum over all these
|
||||
sizes”.</p>
|
||||
<p>A less compact but maybe more readonable way to write this would be:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">backpack_item_sizes</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">slot</span><span class="p">,</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span>
|
||||
<span class="n">size</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">"size"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">backpack_item_sizes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
|
||||
<span class="n">wield_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">backpack_item_sizes</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The same is done for the items actually in the BACKPACK slot. The total sizes are added
|
||||
together.</p>
|
||||
</section>
|
||||
<section id="validating-slots">
|
||||
<h3>Validating slots<a class="headerlink" href="#validating-slots" title="Permalink to this headline">¶</a></h3>
|
||||
<p>With these helpers in place, <code class="docutils literal notranslate"><span class="pre">validate_slot_usage</span></code> now becomes simple. We use <code class="docutils literal notranslate"><span class="pre">max_slots</span></code> to see how much we can carry.
|
||||
We then get how many slots we are already using (with <code class="docutils literal notranslate"><span class="pre">count_slots</span></code>) and see if our new <code class="docutils literal notranslate"><span class="pre">obj</span></code>’s size
|
||||
would be too much for us.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="add-and-remove">
|
||||
<h2><code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code><a class="headerlink" href="#add-and-remove" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We will make it so <code class="docutils literal notranslate"><span class="pre">.add</span></code> puts something in the <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code> location and <code class="docutils literal notranslate"><span class="pre">remove</span></code> drops it, wherever
|
||||
it is (even if it was in your hands).</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Put something in the backpack.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">validate_slot_usage</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">slot</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Remove contents of a particular slot, for</span>
|
||||
<span class="sd"> example `equipment.remove(WieldLocation.SHIELD_HAND)`</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
|
||||
<span class="n">ret</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span>
|
||||
<span class="c1"># empty entire backpack! </span>
|
||||
<span class="n">ret</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">])</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">ret</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">])</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">ret</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">ret</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Both of these should be straight forward to follow. In <code class="docutils literal notranslate"><span class="pre">.add</span></code>, we make use of <code class="docutils literal notranslate"><span class="pre">validate_slot_usage</span></code> to
|
||||
double-check we can actually fit the thing, then we add the item to the backpack.</p>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">.delete</span></code>, we allow emptying by <code class="docutils literal notranslate"><span class="pre">WieldLocation</span></code> - we figure out what slot it is and return
|
||||
the item within (if any). If we gave <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code> as the slot, we empty the backpack and
|
||||
return all items.</p>
|
||||
<p>Whenever we change the equipment loadout we must make sure to <code class="docutils literal notranslate"><span class="pre">._save()</span></code> the result, or it will
|
||||
be lost after a server reload.</p>
|
||||
</section>
|
||||
<section id="moving-things-around">
|
||||
<h2>Moving things around<a class="headerlink" href="#moving-things-around" title="Permalink to this headline">¶</a></h2>
|
||||
<p>With the help of <code class="docutils literal notranslate"><span class="pre">.remove()</span></code> and <code class="docutils literal notranslate"><span class="pre">.add()</span></code> we can get things in and out of the <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code> equipment
|
||||
location. We also need to grab stuff from the backpack and wield or wear it. We add a <code class="docutils literal notranslate"><span class="pre">.move</span></code> method
|
||||
on the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> to do this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||||
<span class="sd">"""Move object from backpack to its intended `inventory_use_slot`."""</span>
|
||||
|
||||
<span class="c1"># make sure to remove from equipment/backpack first, to avoid double-adding</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
|
||||
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
|
||||
<span class="n">use_slot</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">"inventory_use_slot"</span><span class="p">,</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">)</span>
|
||||
|
||||
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="n">use_slot</span> <span class="ow">is</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">:</span>
|
||||
<span class="c1"># two-handed weapons can't co-exist with weapon/shield-hand used items</span>
|
||||
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">],</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">]]</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">]</span> <span class="o">=</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
|
||||
<span class="k">elif</span> <span class="n">use_slot</span> <span class="ow">in</span> <span class="p">(</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">,</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">):</span>
|
||||
<span class="c1"># can't keep a two-handed weapon if adding a one-handed weapon or shield</span>
|
||||
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">]]</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
|
||||
<span class="k">elif</span> <span class="n">use_slot</span> <span class="ow">is</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span>
|
||||
<span class="c1"># it belongs in backpack, so goes back to it</span>
|
||||
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span><span class="p">]</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># for others (body, head), just replace whatever's there</span>
|
||||
<span class="n">replaced</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span><span class="p">]</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">to_backpack_obj</span> <span class="ow">in</span> <span class="n">to_backpack</span><span class="p">:</span>
|
||||
<span class="c1"># put stuff in backpack</span>
|
||||
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">to_backpack_obj</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># store new state</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we remember that every <code class="docutils literal notranslate"><span class="pre">EvAdventureObject</span></code> has an <code class="docutils literal notranslate"><span class="pre">inventory_use_slot</span></code> property that tells us where
|
||||
it goes. So we just need to move the object to that slot, replacing whatever is in that place
|
||||
from before. Anything we replace goes back to the backpack.</p>
|
||||
</section>
|
||||
<section id="get-everything">
|
||||
<h2>Get everything<a class="headerlink" href="#get-everything" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In order to visualize our inventory, we need some method to get everything we are carrying.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">all</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Get all objects in inventory, regardless of location.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
|
||||
<span class="n">lst</span> <span class="o">=</span> <span class="p">[</span>
|
||||
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">),</span>
|
||||
<span class="p">]</span> <span class="o">+</span> <span class="p">[(</span><span class="n">item</span><span class="p">,</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">]]</span>
|
||||
<span class="k">return</span> <span class="n">lst</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we get all the equipment locations and add their contents together into a list of tuples
|
||||
<code class="docutils literal notranslate"><span class="pre">[(item,</span> <span class="pre">WieldLocation),</span> <span class="pre">...]</span></code>. This is convenient for display.</p>
|
||||
</section>
|
||||
<section id="weapon-and-armor">
|
||||
<h2>Weapon and armor<a class="headerlink" href="#weapon-and-armor" title="Permalink to this headline">¶</a></h2>
|
||||
<p>It’s convenient to have the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> easily tell you what weapon is currently wielded
|
||||
and what <em>armor</em> level all worn equipment provides. Otherwise you’d need to figure out what item is
|
||||
in which wield-slot and to add up armor slots manually every time you need to know.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.objects</span> <span class="kn">import</span> <span class="n">WeaponEmptyHand</span>
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">armor</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
|
||||
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span>
|
||||
<span class="p">(</span>
|
||||
<span class="c1"># armor is listed using its defense, so we remove 10 from it</span>
|
||||
<span class="c1"># (11 is base no-armor value in Knave)</span>
|
||||
<span class="nb">getattr</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">],</span> <span class="s2">"armor"</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span>
|
||||
<span class="c1"># shields and helmets are listed by their bonus to armor</span>
|
||||
<span class="nb">getattr</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">],</span> <span class="s2">"armor"</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
|
||||
<span class="nb">getattr</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">],</span> <span class="s2">"armor"</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
|
||||
<span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="nd">@property</span>
|
||||
<span class="k">def</span> <span class="nf">weapon</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="c1"># first checks two-handed wield, then one-handed; the two</span>
|
||||
<span class="c1"># should never appear simultaneously anyhow (checked in `move` method).</span>
|
||||
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
|
||||
<span class="n">weapon</span> <span class="o">=</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="n">weapon</span> <span class="o">=</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">]</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="n">weapon</span> <span class="o">=</span> <span class="n">WeaponEmptyHand</span><span class="p">()</span>
|
||||
<span class="k">return</span> <span class="n">weapon</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In the <code class="docutils literal notranslate"><span class="pre">.armor()</span></code> method we get the item (if any) out of each relevant wield-slot (body, shield, head),
|
||||
and grab their <code class="docutils literal notranslate"><span class="pre">armor</span></code> Attribute. We then <code class="docutils literal notranslate"><span class="pre">sum()</span></code> them all up.</p>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">.weapon()</span></code>, we simply check which of the possible weapon slots (weapon-hand or two-hands) have
|
||||
something in them. If not we fall back to the ‘fake’ weapon <code class="docutils literal notranslate"><span class="pre">WeaponEmptyHand</span></code> which is just a ‘dummy’
|
||||
object that represents your bare hands with damage and all.
|
||||
(created in <a class="reference internal" href="Beginner-Tutorial-Objects.html#your-bare-hands"><span class="std std-doc">The Object tutorial</span></a> earlier).</p>
|
||||
</section>
|
||||
<section id="extra-credits">
|
||||
<h2>Extra credits<a class="headerlink" href="#extra-credits" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This covers the basic functionality of the equipment handler. There are other useful methods that
|
||||
can be added:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Given an item, figure out which equipment slot it is currently in</p></li>
|
||||
<li><p>Make a string representing the current loadout</p></li>
|
||||
<li><p>Get everything in the backpack (only)</p></li>
|
||||
<li><p>Get all wieldable items (weapons, shields) from backpack</p></li>
|
||||
<li><p>Get all usable items (items with a use-location of <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code>) from the backpack</p></li>
|
||||
</ul>
|
||||
<p>Experiment with adding those. A full example is found in
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.equipment.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/equipment.py</span></a>.</p>
|
||||
</section>
|
||||
<section id="unit-testing">
|
||||
<h2>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_equipment.py</span></code>.</p>
|
||||
</div></blockquote>
|
||||
<aside class="sidebar">
|
||||
<p>See <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_equipment.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/tests/test_equipment.py</span></a>
|
||||
for a finished testing example.</p>
|
||||
</aside>
|
||||
<p>To test the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code>, easiest is create an <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> (this should by now
|
||||
have <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> available on itself as <code class="docutils literal notranslate"><span class="pre">.equipment</span></code>) and a few test objects; then test
|
||||
passing these into the handler’s methods.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_equipment.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">..objects</span> <span class="kn">import</span> <span class="n">EvAdventureRoom</span>
|
||||
<span class="kn">from</span> <span class="nn">..enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">TestEquipment</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="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="s1">'testchar'</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">helmet</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">EvAdventureHelmet</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"helmet"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">weapon</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">EvAdventureWeapon</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"weapon"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">test_add_remove</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">equipment</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</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">equipment</span><span class="o">.</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">],</span>
|
||||
<span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">]</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">equipment</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</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">equipment</span><span class="o">.</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">],</span> <span class="p">[])</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="summary">
|
||||
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p><em>Handlers</em> are useful for grouping functionality together. Now that we spent our time making the
|
||||
<code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code>, we shouldn’t need to worry about item-slots anymore - the handler ‘handles’ all
|
||||
the details for us. As long as we call its methods, the details can be forgotten about.</p>
|
||||
<p>We also learned to use <em>hooks</em> to tie <em>Knave</em>’s custom equipment handling into Evennia.</p>
|
||||
<p>With <code class="docutils literal notranslate"><span class="pre">Characters</span></code>, <code class="docutils literal notranslate"><span class="pre">Objects</span></code> and now <code class="docutils literal notranslate"><span class="pre">Equipment</span></code> in place, we should be able to move on to character
|
||||
generation - where players get to make their own character!</p>
|
||||
</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-Chargen.html" title="Character Generation"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Objects.html" title="In-game Objects and items"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Handling Equipment</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
<!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>Non-Player-Characters (NPCs) — Evennia 1.0-dev 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="Game Quests" href="Beginner-Tutorial-Quests.html" />
|
||||
<link rel="prev" title="In-game Rooms" href="Beginner-Tutorial-Rooms.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-Quests.html" title="Game Quests"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Rooms.html" title="In-game Rooms"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Non-Player-Characters (NPCs)</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Rooms.html"
|
||||
title="previous chapter">In-game Rooms</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Quests.html"
|
||||
title="next chapter">Game Quests</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-NPCs.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-NPCs.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="non-player-characters-npcs">
|
||||
<h1>Non-Player-Characters (NPCs)<a class="headerlink" href="#non-player-characters-npcs" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This part of the Beginner tutorial is still being developed.</p>
|
||||
</div>
|
||||
</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-Quests.html" title="Game Quests"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Rooms.html" title="In-game Rooms"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Non-Player-Characters (NPCs)</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,484 @@
|
|||
|
||||
<!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>In-game Objects and items — Evennia 1.0-dev 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="Handling Equipment" href="Beginner-Tutorial-Equipment.html" />
|
||||
<link rel="prev" title="Player Characters" href="Beginner-Tutorial-Characters.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-Equipment.html" title="Handling Equipment"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Characters.html" title="Player Characters"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Objects and items</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">In-game Objects and items</a><ul>
|
||||
<li><a class="reference internal" href="#new-enums">New Enums</a></li>
|
||||
<li><a class="reference internal" href="#the-base-object">The base object</a><ul>
|
||||
<li><a class="reference internal" href="#using-attributes-or-not">Using Attributes or not</a></li>
|
||||
<li><a class="reference internal" href="#creating-tags-in-at-object-creation">Creating tags in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#other-object-types">Other object types</a></li>
|
||||
<li><a class="reference internal" href="#consumables">Consumables</a></li>
|
||||
<li><a class="reference internal" href="#weapons">Weapons</a></li>
|
||||
<li><a class="reference internal" href="#magic">Magic</a></li>
|
||||
<li><a class="reference internal" href="#armor">Armor</a></li>
|
||||
<li><a class="reference internal" href="#your-bare-hands">Your Bare hands</a></li>
|
||||
<li><a class="reference internal" href="#testing-and-extra-credits">Testing and Extra credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Characters.html"
|
||||
title="previous chapter">Player Characters</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Equipment.html"
|
||||
title="next chapter">Handling Equipment</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-Objects.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Objects.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="in-game-objects-and-items">
|
||||
<h1>In-game Objects and items<a class="headerlink" href="#in-game-objects-and-items" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In the previous lesson we established what a ‘Character’ is in our game. Before we continue
|
||||
we also need to have a notion what an ‘item’ or ‘object’ is.</p>
|
||||
<p>Looking at <em>Knave</em>’s item lists, we can get some ideas of what we need to track:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">size</span></code> - this is how many ‘slots’ the item uses in the character’s inventory.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">value</span></code> - a base value if we want to sell or buy the item.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">inventory_use_slot</span></code> - some items can be worn or wielded. For example, a helmet needs to be
|
||||
worn on the head and a shield in the shield hand. Some items can’t be used this way at all, but
|
||||
only belong in the backpack.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">obj_type</span></code> - Which ‘type’ of item this is.</p></li>
|
||||
</ul>
|
||||
<section id="new-enums">
|
||||
<h2>New Enums<a class="headerlink" href="#new-enums" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We added a few enumberations for Abilities back in the <a class="reference internal" href="Beginner-Tutorial-Utilities.html"><span class="doc std std-doc">Utilities tutorial</span></a>.
|
||||
Before we continue, let’s expand with enums for use-slots and object types.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">WieldLocation</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||||
|
||||
<span class="n">BACKPACK</span> <span class="o">=</span> <span class="s2">"backpack"</span>
|
||||
<span class="n">WEAPON_HAND</span> <span class="o">=</span> <span class="s2">"weapon_hand"</span>
|
||||
<span class="n">SHIELD_HAND</span> <span class="o">=</span> <span class="s2">"shield_hand"</span>
|
||||
<span class="n">TWO_HANDS</span> <span class="o">=</span> <span class="s2">"two_handed_weapons"</span>
|
||||
<span class="n">BODY</span> <span class="o">=</span> <span class="s2">"body"</span> <span class="c1"># armor</span>
|
||||
<span class="n">HEAD</span> <span class="o">=</span> <span class="s2">"head"</span> <span class="c1"># helmets</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">ObjType</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||||
|
||||
<span class="n">WEAPON</span> <span class="o">=</span> <span class="s2">"weapon"</span>
|
||||
<span class="n">ARMOR</span> <span class="o">=</span> <span class="s2">"armor"</span>
|
||||
<span class="n">SHIELD</span> <span class="o">=</span> <span class="s2">"shield"</span>
|
||||
<span class="n">HELMET</span> <span class="o">=</span> <span class="s2">"helmet"</span>
|
||||
<span class="n">CONSUMABLE</span> <span class="o">=</span> <span class="s2">"consumable"</span>
|
||||
<span class="n">GEAR</span> <span class="o">=</span> <span class="s2">"gear"</span>
|
||||
<span class="n">MAGIC</span> <span class="o">=</span> <span class="s2">"magic"</span>
|
||||
<span class="n">QUEST</span> <span class="o">=</span> <span class="s2">"quest"</span>
|
||||
<span class="n">TREASURE</span> <span class="o">=</span> <span class="s2">"treasure"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Once we have these enums, we will use them for referencing things.</p>
|
||||
</section>
|
||||
<section id="the-base-object">
|
||||
<h2>The base object<a class="headerlink" href="#the-base-object" title="Permalink to this headline">¶</a></h2>
|
||||
<blockquote>
|
||||
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/objects.py</span></code></p>
|
||||
</div></blockquote>
|
||||
<aside class="sidebar">
|
||||
<p><a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.objects.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/objects.py</span></a> has
|
||||
a full set of objects implemented.</p>
|
||||
</aside>
|
||||
<div style="clear: right;"></div>
|
||||
<p>We will make a base <code class="docutils literal notranslate"><span class="pre">EvAdventureObject</span></code> class off Evennia’s standard <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. We will then add
|
||||
child classes to represent the relevant types:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AttributeProperty</span><span class="p">,</span> <span class="n">DefaultObject</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">make_iter</span>
|
||||
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">get_obj_stats</span>
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">ObjType</span>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Base for all evadventure objects. </span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
|
||||
<span class="n">size</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">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">value</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">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># this can be either a single type or a list of types (for objects able to be </span>
|
||||
<span class="c1"># act as multiple). This is used to tag this object during creation.</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">GEAR</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Called when this object is first created. We convert the .obj_type </span>
|
||||
<span class="sd"> property to a database tag."""</span>
|
||||
|
||||
<span class="k">for</span> <span class="n">obj_type</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"obj_type"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">get_help</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Get any help text for this item"""</span>
|
||||
<span class="k">return</span> <span class="s2">"No help for this item"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="using-attributes-or-not">
|
||||
<h3>Using Attributes or not<a class="headerlink" href="#using-attributes-or-not" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In theory, <code class="docutils literal notranslate"><span class="pre">size</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code> does not change and <em>could</em> also be just set as a regular Python
|
||||
property on the class:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">EvAdventureObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
|
||||
<span class="n">size</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
<span class="n">value</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The problem with this is that if we want to make a new object of <code class="docutils literal notranslate"><span class="pre">size</span> <span class="pre">3</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">20</span></code>, we have to
|
||||
make a new class for it. We can’t change it on the fly because the change would only be in memory and
|
||||
be lost on next server reload.</p>
|
||||
<p>Because we use <code class="docutils literal notranslate"><span class="pre">AttributeProperties</span></code>, we can set <code class="docutils literal notranslate"><span class="pre">size</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code> to whatever we like when we
|
||||
create the object (or later), and the Attributes will remember our changes to that object indefinitely.</p>
|
||||
<p>To make this a little more efficient, we use <code class="docutils literal notranslate"><span class="pre">autocreate=False</span></code>. Normally when you create a
|
||||
new object with defined <code class="docutils literal notranslate"><span class="pre">AttributeProperties</span></code>, a matching <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> is immediately created at
|
||||
the same time. So normally, the object would be created along with two Attributes <code class="docutils literal notranslate"><span class="pre">size</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code>.
|
||||
With <code class="docutils literal notranslate"><span class="pre">autocreate=False</span></code>, no Attribute will be created <em>unless the default is changed</em>. That is, as
|
||||
long as your object has <code class="docutils literal notranslate"><span class="pre">size=1</span></code> no database <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> will be created at all. This saves time and
|
||||
resources when creating large number of objects.</p>
|
||||
<p>The drawback is that since no Attribute is created you can’t refer to it
|
||||
with <code class="docutils literal notranslate"><span class="pre">obj.db.size</span></code> or <code class="docutils literal notranslate"><span class="pre">obj.attributes.get("size")</span></code> <em>unless you change its default</em>. You also can’t query
|
||||
the database for all objects with <code class="docutils literal notranslate"><span class="pre">size=1</span></code>, since most objects would not yet have an in-database
|
||||
<code class="docutils literal notranslate"><span class="pre">size</span></code> Attribute to search for.</p>
|
||||
<p>In our case, we’ll only refer to these properties as <code class="docutils literal notranslate"><span class="pre">obj.size</span></code> etc, and have no need to find
|
||||
all objects of a particular size. So we should be safe.</p>
|
||||
</section>
|
||||
<section id="creating-tags-in-at-object-creation">
|
||||
<h3>Creating tags in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code><a class="headerlink" href="#creating-tags-in-at-object-creation" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> is a method Evennia calls on every child of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> whenever it is
|
||||
first created.</p>
|
||||
<p>We do a tricky thing here, converting our <code class="docutils literal notranslate"><span class="pre">.obj_type</span></code> to one or more <a class="reference internal" href="../../../Components/Tags.html"><span class="doc std std-doc">Tags</span></a>. Tagging the
|
||||
object like this means you can later efficiently find all objects of a given type (or combination of
|
||||
types) with Evennia’s search functions:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">ObjType</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">search</span>
|
||||
|
||||
<span class="c1"># get all shields in the game</span>
|
||||
<span class="n">all_shields</span> <span class="o">=</span> <span class="n">search</span><span class="o">.</span><span class="n">search_object_by_tag</span><span class="p">(</span><span class="n">ObjType</span><span class="o">.</span><span class="n">SHIELD</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"obj_type"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We allow <code class="docutils literal notranslate"><span class="pre">.obj_type</span></code> to be given as a single value or a list of values. We use <code class="docutils literal notranslate"><span class="pre">make_iter</span></code> from the
|
||||
evennia utility library to make sure we don’t balk at either. This means you could have a Shield that
|
||||
is also Magical, for example.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="other-object-types">
|
||||
<h2>Other object types<a class="headerlink" href="#other-object-types" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Some of the other object types are very simple so far.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AttributeProperty</span><span class="p">,</span> <span class="n">DefaultObject</span>
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">ObjType</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureQuestObject</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="sd">"""Quest objects should usually not be possible to sell or trade."""</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">QUEST</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureTreasure</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="sd">"""Treasure is usually just for selling for coin"""</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">TREASURE</span>
|
||||
<span class="n">value</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="consumables">
|
||||
<h2>Consumables<a class="headerlink" href="#consumables" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A ‘consumable’ is an item that has a certain number of ‘uses’. Once fully consumed, it can’t be used
|
||||
anymore. An example would be a health potion.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureConsumable</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="sd">"""An item that can be used up"""</span>
|
||||
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">CONSUMABLE</span>
|
||||
<span class="n">value</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">uses</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">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_pre_use</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">"""Called before using. If returning False, abort use."""</span>
|
||||
<span class="k">return</span> <span class="n">uses</span> <span class="o">></span> <span class="mi">0</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_use</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">"""Called when using the item"""</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_post_use</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">"""Called after using the item"""</span>
|
||||
<span class="c1"># detract a usage, deleting the item if used up.</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">-=</span> <span class="mi">1</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o"><=</span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="n">user</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> was used up."</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>What exactly each consumable does will vary - we will need to implement children of this class
|
||||
later, overriding <code class="docutils literal notranslate"><span class="pre">at_use</span></code> with different effects.</p>
|
||||
</section>
|
||||
<section id="weapons">
|
||||
<h2>Weapons<a class="headerlink" href="#weapons" title="Permalink to this headline">¶</a></h2>
|
||||
<p>All weapons need properties that describe how efficient they are in battle.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">ObjType</span><span class="p">,</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureWeapon</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="sd">"""Base class for all weapons"""</span>
|
||||
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">WEAPON</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="n">attack_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">defend_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">ARMOR</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="n">damage_roll</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="s2">"1d6"</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">quality</span></code> is something we need to track in <em>Knave</em>. When getting critical failures on attacks,
|
||||
a weapon’s quality will go down. When it reaches 0, it will break.</p>
|
||||
<p>The attack/defend type tracks how we resolve attacks with the weapon, like <code class="docutils literal notranslate"><span class="pre">roll</span> <span class="pre">+</span> <span class="pre">STR</span> <span class="pre">vs</span> <span class="pre">ARMOR</span> <span class="pre">+</span> <span class="pre">10</span></code>.</p>
|
||||
</section>
|
||||
<section id="magic">
|
||||
<h2>Magic<a class="headerlink" href="#magic" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In <em>Knave</em>, anyone can use magic if they are wielding a rune stone (our name for spell books) in both
|
||||
hands. You can only use a rune stone once per rest. So a rune stone is an example of a ‘magical weapon’
|
||||
that is also a ‘consumable’ of sorts.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
<span class="k">class</span> <span class="nc">EvAdventureConsumable</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureWeapon</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureRuneStone</span><span class="p">(</span><span class="n">EvAdventureWeapon</span><span class="p">,</span> <span class="n">EvAdventureConsumable</span><span class="p">):</span>
|
||||
<span class="sd">"""Base for all magical rune stones"""</span>
|
||||
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="p">(</span><span class="n">ObjType</span><span class="o">.</span><span class="n">WEAPON</span><span class="p">,</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">MAGIC</span><span class="p">)</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span> <span class="c1"># always two hands for magic</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="n">attack_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">INT</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">defend_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">DEX</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="n">damage_roll</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="s2">"1d8"</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_post_use</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">"""Called after usage/spell was cast"""</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">-=</span> <span class="mi">1</span>
|
||||
<span class="c1"># we don't delete the rune stone here, but </span>
|
||||
<span class="c1"># it must be reset on next rest.</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">refresh</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Refresh the rune stone (normally after rest)"""</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">=</span> <span class="mi">1</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We make the rune stone a mix of weapon and consumable. Note that we don’t have to add <code class="docutils literal notranslate"><span class="pre">.uses</span></code>
|
||||
again, it’s inherited from <code class="docutils literal notranslate"><span class="pre">EvAdventureConsumable</span></code> parent. The <code class="docutils literal notranslate"><span class="pre">at_pre_use</span></code> and <code class="docutils literal notranslate"><span class="pre">at_use</span></code> methods
|
||||
are also inherited; we only override <code class="docutils literal notranslate"><span class="pre">at_post_use</span></code> since we don’t want the runestone to be deleted
|
||||
when it runs out of uses.</p>
|
||||
<p>We add a little convenience method <code class="docutils literal notranslate"><span class="pre">refresh</span></code> - we should call this when the character rests, to
|
||||
make the runestone active again.</p>
|
||||
<p>Exactly what rune stones <em>do</em> will be implemented in the <code class="docutils literal notranslate"><span class="pre">at_use</span></code> methods of subclasses to this
|
||||
base class. Since magic in <em>Knave</em> tends to be pretty custom, it makes sense that it will lead to a lot
|
||||
of custom code.</p>
|
||||
</section>
|
||||
<section id="armor">
|
||||
<h2>Armor<a class="headerlink" href="#armor" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Armor, shields and helmets increase the <code class="docutils literal notranslate"><span class="pre">ARMOR</span></code> stat of the character. In <em>Knave</em>, what is stored is the
|
||||
defense value of the armor (values 11-20). We will instead store the ‘armor bonus’ (1-10). As we know,
|
||||
defending is always <code class="docutils literal notranslate"><span class="pre">bonus</span> <span class="pre">+</span> <span class="pre">10</span></code>, so the result will be the same - this means
|
||||
we can use <code class="docutils literal notranslate"><span class="pre">Ability.ARMOR</span></code> as any other defensive ability without worrying about a special case.</p>
|
||||
<p>``</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureAmor</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">ARMOR</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span>
|
||||
|
||||
<span class="n">armor</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">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureShield</span><span class="p">(</span><span class="n">EvAdventureArmor</span><span class="p">):</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">SHIELD</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureHelmet</span><span class="p">(</span><span class="n">EvAdventureArmor</span><span class="p">):</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">HELMET</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="your-bare-hands">
|
||||
<h2>Your Bare hands<a class="headerlink" href="#your-bare-hands" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This is a ‘dummy’ object that is not stored in the database. We will use this in the upcoming
|
||||
<a class="reference internal" href="Beginner-Tutorial-Equipment.html"><span class="doc std std-doc">Equipment tutorial lesson</span></a> to represent when you have ‘nothing’
|
||||
in your hands. This way we don’t need to add any special case for this.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">WeaponEmptyHand</span><span class="p">:</span>
|
||||
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">WEAPON</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"Empty Fists"</span>
|
||||
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span>
|
||||
<span class="n">attack_type</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">STR</span>
|
||||
<span class="n">defense_type</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">ARMOR</span>
|
||||
<span class="n">damage_roll</span> <span class="o">=</span> <span class="s2">"1d4"</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="mi">100000</span> <span class="c1"># let's assume fists are always available ...</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="s2">"<WeaponEmptyHand>"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="testing-and-extra-credits">
|
||||
<h2>Testing and Extra credits<a class="headerlink" href="#testing-and-extra-credits" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Remember the <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> function from the <a class="reference internal" href="Beginner-Tutorial-Utilities.html"><span class="doc std std-doc">Utility Tutorial</span></a> earlier?
|
||||
We had to use dummy-values since we didn’t yet know how we would store properties on Objects in the game.</p>
|
||||
<p>Well, we just figured out all we need! You can go back and update <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> to properly read the data
|
||||
from the object it receives.</p>
|
||||
<p>When you change this function you must also update the related unit test - so your existing test becomes a
|
||||
nice way to test your new Objects as well! Add more tests showing the output of feeding different object-types
|
||||
to <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code>.</p>
|
||||
<p>Try it out yourself. If you need help, a finished utility example is found in <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.utils.html#evennia.contrib.tutorials.evadventure.utils.get_obj_stats" title="evennia.contrib.tutorials.evadventure.utils.get_obj_stats"><span class="xref myst py py-func">evennia/contrib/tutorials/evadventure/utils.py</span></a>.</p>
|
||||
</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-Equipment.html" title="Handling Equipment"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Characters.html" title="Player Characters"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Objects and items</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
|
||||
<!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>Part 3: How we get there — Evennia 1.0-dev 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="Code structure and Utilities" href="Beginner-Tutorial-Utilities.html" />
|
||||
<link rel="prev" title="Planning our tutorial game" href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.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-Utilities.html" title="Code structure and Utilities"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" accesskey="U">Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Part 3: How we get there</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">Part 3: How we get there</a><ul>
|
||||
<li><a class="reference internal" href="#lessons">Lessons</a></li>
|
||||
<li><a class="reference internal" href="#table-of-contents">Table of Contents</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html"
|
||||
title="previous chapter">Planning our tutorial game</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Utilities.html"
|
||||
title="next chapter">Code structure and Utilities</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-Part3-Intro.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Part3-Intro.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="part-3-how-we-get-there">
|
||||
<h1>Part 3: How we get there<a class="headerlink" href="#part-3-how-we-get-there" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>The tutorial game is under development and is not yet complete, nor tested. Use the existing
|
||||
lessons as inspiration and to help get you going, but don’t expect out-of-the-box perfection
|
||||
from it at this time.</p>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Beginner Tutorial Parts</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../Beginner-Tutorial-Intro.html"><span class="doc std std-doc">Introduction</span></a>
|
||||
<br>Getting set up.</p></li>
|
||||
<li><p>Part 1: <a class="reference internal" href="../Part1/Beginner-Tutorial-Part1-Intro.html"><span class="doc std std-doc">What we have</span></a>
|
||||
<br>A tour of Evennia and how to use the tools, including an introduction to Python.</p></li>
|
||||
<li><p>Part 2: <a class="reference internal" href="../Part2/Beginner-Tutorial-Part2-Intro.html"><span class="doc std std-doc">What we want</span></a>
|
||||
<br>Planning our tutorial game and what to think about when planning your own in the future.</p></li>
|
||||
<li><p><strong>Part 3: <a class="reference internal" href="#"><span class="doc std std-doc">How we get there</span></a></strong>
|
||||
<br>Getting down to the meat of extending Evennia to make our game</p></li>
|
||||
<li><p>Part 4: <a class="reference internal" href="../Part4/Beginner-Tutorial-Part4-Intro.html"><span class="doc std std-doc">Using what we created</span></a>
|
||||
<br>Building a tech-demo and world content to go with our code</p></li>
|
||||
<li><p>Part 5: <a class="reference internal" href="../Part5/Beginner-Tutorial-Part5-Intro.html"><span class="doc std std-doc">Showing the world</span></a>
|
||||
<br>Taking our new game online and let players try it out</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p>In part three of the Evennia Beginner tutorial we will go through the actual creation of
|
||||
our tutorial game <em>EvAdventure</em>, based on the <a class="reference external" href="https://www.drivethrurpg.com/product/250888/Knave">Knave</a>
|
||||
RPG ruleset.</p>
|
||||
<p>This is a big part. You’ll be seeing a lot of code and there are plenty of lessons to go through.
|
||||
Take your time!</p>
|
||||
<p>If you followed the previous parts of this tutorial you will have some notions about Python and where to
|
||||
find and make use of things in Evennia. We also have a good idea of the type of game we will
|
||||
create.</p>
|
||||
<p>Even if this is not the game-style you are interested in, following along will give you a lot
|
||||
of experience using Evennia and be really helpful for doing your own thing later!</p>
|
||||
<p>Fully coded examples of all code we make in this part can be found in the
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure</span></a> package.</p>
|
||||
<section id="lessons">
|
||||
<h2>Lessons<a class="headerlink" href="#lessons" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Utilities.html">Code structure and Utilities</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rules.html">Rules and dice rolling</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Characters.html">Player Characters</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Objects.html">In-game Objects and items</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Equipment.html">Handling Equipment</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Chargen.html">Character Generation</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rooms.html">In-game Rooms</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-NPCs.html">Non-Player-Characters (NPCs)</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Quests.html">Game Quests</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Shops.html">In-game Shops</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Dungeon.html">Dynamically generated Dungeon</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Commands.html">In-game Commands</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section id="table-of-contents">
|
||||
<h2>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Utilities.html">Code structure and Utilities</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#folder-structure">Folder structure</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#enums">Enums</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#utility-module">Utility module</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#testing">Testing</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#running-your-test">Running your test</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rules.html">Rules and dice rolling</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#summary-of-knave-rules">Summary of <em>Knave</em> rules</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#making-a-rule-module">Making a rule module</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#rolling-dice">Rolling dice</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#generic-dice-roller">Generic dice roller</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#rolling-with-advantage">Rolling with advantage</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#saving-throws">Saving throws</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#opposed-saving-throw">Opposed saving throw</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#morale-check">Morale check</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#roll-for-healing">Roll for Healing</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#rolling-on-a-table">Rolling on a table</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#roll-for-death">Roll for death</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#testing">Testing</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#mocking-and-patching">Mocking and patching</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Characters.html">Player Characters</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#inheritance-structure">Inheritance structure</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#living-mixin-class">Living mixin class</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#character-class">Character class</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Characters.html#funcparser-inlines">Funcparser inlines</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Characters.html#backtracking">Backtracking</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#connecting-the-character-with-evennia">Connecting the Character with Evennia</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#unit-testing">Unit Testing</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#about-races-and-classes">About races and classes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Objects.html">In-game Objects and items</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#new-enums">New Enums</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#the-base-object">The base object</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Objects.html#using-attributes-or-not">Using Attributes or not</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Objects.html#creating-tags-in-at-object-creation">Creating tags in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#other-object-types">Other object types</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#consumables">Consumables</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#weapons">Weapons</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#magic">Magic</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#armor">Armor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#your-bare-hands">Your Bare hands</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#testing-and-extra-credits">Testing and Extra credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Equipment.html">Handling Equipment</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#equipmenthandler-that-saves">EquipmentHandler that saves</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#connecting-the-equipmenthandler">Connecting the EquipmentHandler</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#expanding-the-equipmenthandler">Expanding the Equipmenthandler</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#validate-slot-usage"><code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code></a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#max-slots"><code class="docutils literal notranslate"><span class="pre">.max_slots</span></code></a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#count-slots"><code class="docutils literal notranslate"><span class="pre">.count_slots</span></code></a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#validating-slots">Validating slots</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#add-and-remove"><code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code></a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#moving-things-around">Moving things around</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#get-everything">Get everything</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#weapon-and-armor">Weapon and armor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#extra-credits">Extra credits</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#unit-testing">Unit Testing</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Chargen.html">Character Generation</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#how-it-will-work">How it will work</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#random-tables">Random tables</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#storing-state-of-the-menu">Storing state of the menu</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#showing-the-sheet">Showing the sheet</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#apply-character">Apply character</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#initializing-evmenu">Initializing EvMenu</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#main-node-choosing-what-to-do">Main Node: Choosing what to do</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#node-changing-your-name">Node: Changing your name</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#node-swapping-abilities-around">Node: Swapping Abilities around</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#node-creating-the-character">Node: Creating the Character</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#tying-the-nodes-together">Tying the nodes together</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#conclusions">Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rooms.html">In-game Rooms</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-NPCs.html">Non-Player-Characters (NPCs)</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Quests.html">Game Quests</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Shops.html">In-game Shops</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Dungeon.html">Dynamically generated Dungeon</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Commands.html">In-game Commands</a></li>
|
||||
</ul>
|
||||
</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-Utilities.html" title="Code structure and Utilities"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Part 3: How we get there</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
<!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>Game Quests — Evennia 1.0-dev 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="In-game Shops" href="Beginner-Tutorial-Shops.html" />
|
||||
<link rel="prev" title="Non-Player-Characters (NPCs)" href="Beginner-Tutorial-NPCs.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-Shops.html" title="In-game Shops"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-NPCs.html" title="Non-Player-Characters (NPCs)"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Game Quests</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-NPCs.html"
|
||||
title="previous chapter">Non-Player-Characters (NPCs)</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Shops.html"
|
||||
title="next chapter">In-game Shops</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-Quests.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Quests.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="game-quests">
|
||||
<h1>Game Quests<a class="headerlink" href="#game-quests" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This part of the Beginner tutorial is still being developed.</p>
|
||||
</div>
|
||||
</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-Shops.html" title="In-game Shops"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-NPCs.html" title="Non-Player-Characters (NPCs)"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Game Quests</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
<!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>In-game Rooms — Evennia 1.0-dev 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="Non-Player-Characters (NPCs)" href="Beginner-Tutorial-NPCs.html" />
|
||||
<link rel="prev" title="Character Generation" href="Beginner-Tutorial-Chargen.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-NPCs.html" title="Non-Player-Characters (NPCs)"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Chargen.html" title="Character Generation"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Rooms</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Chargen.html"
|
||||
title="previous chapter">Character Generation</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-NPCs.html"
|
||||
title="next chapter">Non-Player-Characters (NPCs)</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-Rooms.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Rooms.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="in-game-rooms">
|
||||
<h1>In-game Rooms<a class="headerlink" href="#in-game-rooms" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This part of the Beginner tutorial is still being developed.</p>
|
||||
</div>
|
||||
</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-NPCs.html" title="Non-Player-Characters (NPCs)"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Chargen.html" title="Character Generation"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Rooms</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,793 @@
|
|||
|
||||
<!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>Rules and dice rolling — Evennia 1.0-dev 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="Player Characters" href="Beginner-Tutorial-Characters.html" />
|
||||
<link rel="prev" title="Code structure and Utilities" href="Beginner-Tutorial-Utilities.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-Characters.html" title="Player Characters"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Utilities.html" title="Code structure and Utilities"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Rules and dice rolling</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">Rules and dice rolling</a><ul>
|
||||
<li><a class="reference internal" href="#summary-of-knave-rules">Summary of <em>Knave</em> rules</a></li>
|
||||
<li><a class="reference internal" href="#making-a-rule-module">Making a rule module</a></li>
|
||||
<li><a class="reference internal" href="#rolling-dice">Rolling dice</a><ul>
|
||||
<li><a class="reference internal" href="#generic-dice-roller">Generic dice roller</a></li>
|
||||
<li><a class="reference internal" href="#rolling-with-advantage">Rolling with advantage</a></li>
|
||||
<li><a class="reference internal" href="#saving-throws">Saving throws</a></li>
|
||||
<li><a class="reference internal" href="#opposed-saving-throw">Opposed saving throw</a></li>
|
||||
<li><a class="reference internal" href="#morale-check">Morale check</a></li>
|
||||
<li><a class="reference internal" href="#roll-for-healing">Roll for Healing</a></li>
|
||||
<li><a class="reference internal" href="#rolling-on-a-table">Rolling on a table</a></li>
|
||||
<li><a class="reference internal" href="#roll-for-death">Roll for death</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#testing">Testing</a><ul>
|
||||
<li><a class="reference internal" href="#mocking-and-patching">Mocking and patching</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Utilities.html"
|
||||
title="previous chapter">Code structure and Utilities</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Characters.html"
|
||||
title="next chapter">Player Characters</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-Rules.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Rules.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="rules-and-dice-rolling">
|
||||
<h1>Rules and dice rolling<a class="headerlink" href="#rules-and-dice-rolling" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In <em>EvAdventure</em> we have decided to use the <a class="reference external" href="https://www.drivethrurpg.com/product/250888/Knave">Knave</a>
|
||||
RPG ruleset. This is commercial, but released under Creative Commons 4.0, meaning it’s okay to share and
|
||||
adapt <em>Knave</em> for any purpose, even commercially. If you don’t want to buy it but still follow
|
||||
along, you can find a <a class="reference external" href="http://abominablefancy.blogspot.com/2018/10/knaves-fancypants.html">free fan-version here</a>.</p>
|
||||
<section id="summary-of-knave-rules">
|
||||
<h2>Summary of <em>Knave</em> rules<a class="headerlink" href="#summary-of-knave-rules" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Knave, being inspired by early Dungeons & Dragons, is very simple.</p>
|
||||
<ul class="simple">
|
||||
<li><p>It uses six Ability bonuses
|
||||
<em>Strength</em> (STR), <em>Dexterity</em> (DEX), <em>Constitution</em> (CON), <em>Intelligence</em> (INT), <em>Wisdom</em> (WIS)
|
||||
and <em>Charisma</em> (CHA). These are rated from <code class="docutils literal notranslate"><span class="pre">+1</span></code> to <code class="docutils literal notranslate"><span class="pre">+10</span></code>.</p></li>
|
||||
<li><p>Rolls are made with a twenty-sided die (<code class="docutils literal notranslate"><span class="pre">1d20</span></code>), usually adding a suitable Ability bonus to the roll.</p></li>
|
||||
<li><p>If you roll <em>with advantage</em>, you roll <code class="docutils literal notranslate"><span class="pre">2d20</span></code> and pick the
|
||||
<em>highest</em> value, If you roll <em>with disadvantage</em>, you roll <code class="docutils literal notranslate"><span class="pre">2d20</span></code> and pick the <em>lowest</em>.</p></li>
|
||||
<li><p>Rolling a natural <code class="docutils literal notranslate"><span class="pre">1</span></code> is a <em>critical failure</em>. A natural <code class="docutils literal notranslate"><span class="pre">20</span></code> is a <em>critical success</em>. Rolling such
|
||||
in combat means your weapon or armor loses quality, which will eventually destroy it.</p></li>
|
||||
<li><p>A <em>saving throw</em> (trying to succeed against the environment) means making a roll to beat <code class="docutils literal notranslate"><span class="pre">15</span></code> (always).
|
||||
So if you are lifting a heavy stone and have <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+2</span></code>, you’d roll <code class="docutils literal notranslate"><span class="pre">1d20</span> <span class="pre">+</span> <span class="pre">2</span></code> and hope the result
|
||||
is higher than <code class="docutils literal notranslate"><span class="pre">15</span></code>.</p></li>
|
||||
<li><p>An <em>opposed saving throw</em> means beating the enemy’s suitable Ability ‘defense’, which is always their
|
||||
<code class="docutils literal notranslate"><span class="pre">Ability</span> <span class="pre">bonus</span> <span class="pre">+</span> <span class="pre">10</span></code>. So if you have <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+1</span></code> and are arm wrestling someone with <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+2</span></code>, you roll
|
||||
<code class="docutils literal notranslate"><span class="pre">1d20</span> <span class="pre">+</span> <span class="pre">1</span></code> and hope to roll higher than <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">+</span> <span class="pre">10</span> <span class="pre">=</span> <span class="pre">12</span></code>.</p></li>
|
||||
<li><p>A special bonus is <code class="docutils literal notranslate"><span class="pre">Armor</span></code>, <code class="docutils literal notranslate"><span class="pre">+1</span></code> is unarmored, additional armor is given by equipment. Melee attacks
|
||||
test <code class="docutils literal notranslate"><span class="pre">STR</span></code> versus the <code class="docutils literal notranslate"><span class="pre">Armor</span></code> defense value while ranged attacks uses <code class="docutils literal notranslate"><span class="pre">WIS</span></code> vs <code class="docutils literal notranslate"><span class="pre">Armor</span></code>.</p></li>
|
||||
<li><p><em>Knave</em> has no skills or classes. Everyone can use all items and using magic means having a special
|
||||
‘rune stone’ in your hands; one spell per stone and day.</p></li>
|
||||
<li><p>A character has <code class="docutils literal notranslate"><span class="pre">CON</span> <span class="pre">+</span> <span class="pre">10</span></code> carry ‘slots’. Most normal items uses one slot, armor and large weapons uses
|
||||
two or three.</p></li>
|
||||
<li><p>Healing is random, <code class="docutils literal notranslate"><span class="pre">1d8</span> <span class="pre">+</span> <span class="pre">CON</span></code> health healed after food and sleep.</p></li>
|
||||
<li><p>Monster difficulty is listed by hy many 1d8 HP they have; this is called their “hit die” or HD. If
|
||||
needing to test Abilities, monsters have HD bonus in every Ability.</p></li>
|
||||
<li><p>Monsters have a <em>morale rating</em>. When things go bad, they have a chance to panic and flee if
|
||||
rolling <code class="docutils literal notranslate"><span class="pre">2d6</span></code> over their morale rating.</p></li>
|
||||
<li><p>All Characters in <em>Knave</em> are mostly randomly generated. HP is <code class="docutils literal notranslate"><span class="pre"><level>d8</span></code> but we give every
|
||||
new character max HP to start.</p></li>
|
||||
<li><p><em>Knave</em> also have random tables, such as for starting equipment and to see if dying when
|
||||
hitting 0. Death, if it happens, is permanent.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="making-a-rule-module">
|
||||
<h2>Making a rule module<a class="headerlink" href="#making-a-rule-module" title="Permalink to this headline">¶</a></h2>
|
||||
<blockquote>
|
||||
<div><p>Create a new module mygame/evadventure/rules.py</p>
|
||||
</div></blockquote>
|
||||
<aside class="sidebar">
|
||||
<p>A complete version of the rule module is found in
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.rules.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/rules.py</span></a>.</p>
|
||||
</aside>
|
||||
<p>There are three broad sets of rules for most RPGS:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Character generation rules, often only used during character creation</p></li>
|
||||
<li><p>Regular gameplay rules - rolling dice and resolving game situations</p></li>
|
||||
<li><p>Character improvement - getting and spending experience to improve the character</p></li>
|
||||
</ul>
|
||||
<p>We want our <code class="docutils literal notranslate"><span class="pre">rules</span></code> module to cover as many aspeects of what we’d otherwise would have to look up
|
||||
in a rulebook.</p>
|
||||
</section>
|
||||
<section id="rolling-dice">
|
||||
<h2>Rolling dice<a class="headerlink" href="#rolling-dice" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We will start by making a dice roller. Let’s group all of our dice rolling into a structure like this
|
||||
(not functional code yet):</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># get result of one generic roll, for any type and number of dice</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
|
||||
<span class="c1"># get result of normal d20 roll, with advantage/disadvantage (or not)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">saving_throw</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># do a saving throw against a specific target number</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">opposed_saving_throw</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># do an opposed saving throw against a target's defense</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll_random_table</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># make a roll against a random table (loaded elsewere)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">morale_check</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># roll a 2d6 morale check for a target</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">heal_from_rest</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># heal 1d8 when resting+eating, but not more than max value.</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll_death</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># roll to determine penalty when hitting 0 HP. </span>
|
||||
|
||||
|
||||
<span class="n">dice</span> <span class="o">=</span> <span class="n">EvAdventureRollEngine</span><span class="p">()</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p>This groups all dice-related code into one ‘container’ that is easy to import. But it’s mostly a matter
|
||||
of taste. You <em>could</em> also break up the class’ methods into normal functions at the top-level of the
|
||||
module if you wanted.</p>
|
||||
</aside>
|
||||
<p>This structure (called a <em>singleton</em>) means we group all dice rolls into one class that we then initiate
|
||||
into a variable <code class="docutils literal notranslate"><span class="pre">dice</span></code> at the end of the module. This means that we can do the following from other
|
||||
modules:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
|
||||
|
||||
<span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d8"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="generic-dice-roller">
|
||||
<h3>Generic dice roller<a class="headerlink" href="#generic-dice-roller" title="Permalink to this headline">¶</a></h3>
|
||||
<p>We want to be able to do <code class="docutils literal notranslate"><span class="pre">roll("1d20")</span></code> and get a random result back from the roll.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">roll_string</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Roll XdY dice, where X is the number of dice </span>
|
||||
<span class="sd"> and Y the number of sides per die. </span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> roll_string (str): A dice string on the form XdY.</span>
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> int: The result of the roll. </span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="c1"># split the XdY input on the 'd' one time</span>
|
||||
<span class="n">number</span><span class="p">,</span> <span class="n">diesize</span> <span class="o">=</span> <span class="n">roll_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"d"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># convert from string to integers</span>
|
||||
<span class="n">number</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
|
||||
<span class="n">diesize</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">diesize</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># make the roll</span>
|
||||
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">diesize</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p>For this tutorial we have opted to not use any contribs, so we create
|
||||
our own dice roller. But normally you could instead use the <a class="reference internal" href="../../../Contribs/Contrib-Dice.html"><span class="doc std std-doc">dice</span></a> contrib for this.
|
||||
We’ll point out possible helpful contribs in sidebars as we proceed.</p>
|
||||
</aside>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">randint</span></code> standard Python library module produces a random integer<br />
|
||||
in a specific range. The line</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">sum</span><span class="p">(</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">diesize</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>works like this:</p>
|
||||
<ul class="simple">
|
||||
<li><p>For a certain <code class="docutils literal notranslate"><span class="pre">number</span></code> of times …</p></li>
|
||||
<li><p>… create a random integer between <code class="docutils literal notranslate"><span class="pre">1</span></code> and <code class="docutils literal notranslate"><span class="pre">diesize</span></code> …</p></li>
|
||||
<li><p>… and <code class="docutils literal notranslate"><span class="pre">sum</span></code> all those integers together.</p></li>
|
||||
</ul>
|
||||
<p>You could write the same thing less compactly like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">rolls</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number</span><span class="p">):</span>
|
||||
<span class="n">random_result</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">diesize</span><span class="p">)</span>
|
||||
<span class="n">rolls</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">random_result</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">rolls</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p>Note that <code class="docutils literal notranslate"><span class="pre">range</span></code> generates a value <code class="docutils literal notranslate"><span class="pre">0...number-1</span></code>. We use <code class="docutils literal notranslate"><span class="pre">_</span></code> in the <code class="docutils literal notranslate"><span class="pre">for</span></code> loop to
|
||||
indicate we don’t really care what this value is - we just want to repeat the loop
|
||||
a certain amount of times.</p>
|
||||
</aside>
|
||||
<p>We don’t ever expect end users to call this method; if we did, we would have to validate the inputs
|
||||
much more - We would have to make sure that <code class="docutils literal notranslate"><span class="pre">number</span></code> or <code class="docutils literal notranslate"><span class="pre">diesize</span></code> are valid inputs and not
|
||||
crazy big so the loop takes forever!</p>
|
||||
</section>
|
||||
<section id="rolling-with-advantage">
|
||||
<h3>Rolling with advantage<a class="headerlink" href="#rolling-with-advantage" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Now that we have the generic roller, we can start using it to do a more complex roll.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="n">roll_string</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">advantage</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">advantage</span> <span class="ow">or</span> <span class="n">disadvantage</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">advantage</span> <span class="ow">and</span> <span class="n">disadvantage</span><span class="p">):</span>
|
||||
<span class="c1"># normal roll - advantage/disadvantage not set or they cancel </span>
|
||||
<span class="c1"># each other out </span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">advantage</span><span class="p">:</span>
|
||||
<span class="c1"># highest of two d20 rolls</span>
|
||||
<span class="k">return</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">))</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># disadvantage - lowest of two d20 rolls </span>
|
||||
<span class="k">return</span> <span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d20"</span><span class="p">))</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">min()</span></code> and <code class="docutils literal notranslate"><span class="pre">max()</span></code> functions are standard Python fare for getting the biggest/smallest
|
||||
of two arguments.</p>
|
||||
</section>
|
||||
<section id="saving-throws">
|
||||
<h3>Saving throws<a class="headerlink" href="#saving-throws" title="Permalink to this headline">¶</a></h3>
|
||||
<p>We want the saving throw to itself figure out if it succeeded or not. This means it needs to know
|
||||
the Ability bonus (like STR <code class="docutils literal notranslate"><span class="pre">+1</span></code>). It would be convenient if we could just pass the entity
|
||||
doing the saving throw to this method, tell it what type of save was needed, and then
|
||||
have it figure things out:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">,</span> <span class="n">quality</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">saving_throw</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The return will be a boolean <code class="docutils literal notranslate"><span class="pre">True/False</span></code> if they pass, as well as a <code class="docutils literal notranslate"><span class="pre">quality</span></code> that tells us if
|
||||
a perfect fail/success was rolled or not.</p>
|
||||
<p>To make the saving throw method this clever, we need to think some more about how we want to store our
|
||||
data on the character.</p>
|
||||
<p>For our purposes it sounds reasonable that we will be using <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> for storing
|
||||
the Ability scores. To make it easy, we will name them the same as the
|
||||
<a class="reference internal" href="Beginner-Tutorial-Utilities.html#enums"><span class="std std-doc">Enum values</span></a> we set up in the previous lesson. So if we have
|
||||
an enum <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">=</span> <span class="pre">"strength"</span></code>, we want to store the Ability on the character as an Attribute <code class="docutils literal notranslate"><span class="pre">strength</span></code>.</p>
|
||||
<p>From the Attribute documentation, we can see that we can use <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> to make it so the
|
||||
Attribute is available as <code class="docutils literal notranslate"><span class="pre">character.strength</span></code>, and this is what we will do.</p>
|
||||
<p>So, in short, we’ll create the saving throws method with the assumption that we will be able to do
|
||||
<code class="docutils literal notranslate"><span class="pre">character.strength</span></code>, <code class="docutils literal notranslate"><span class="pre">character.constitution</span></code>, <code class="docutils literal notranslate"><span class="pre">character.charisma</span></code> etc to get the relevant Abilities.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
<span class="c1"># ...</span>
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">saving_throw</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">bonus_type</span><span class="o">=</span><span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span>
|
||||
<span class="n">advantage</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Do a saving throw, trying to beat a target.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> character (Character): A character (assumed to have Ability bonuses</span>
|
||||
<span class="sd"> stored on itself as Attributes).</span>
|
||||
<span class="sd"> bonus_type (Ability): A valid Ability bonus enum.</span>
|
||||
<span class="sd"> target (int): The target number to beat. Always 15 in Knave.</span>
|
||||
<span class="sd"> advantage (bool): If character has advantage on this roll.</span>
|
||||
<span class="sd"> disadvantage (bool): If character has disadvantage on this roll.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> tuple: A tuple (bool, Ability), showing if the throw succeeded and </span>
|
||||
<span class="sd"> the quality is one of None or Ability.CRITICAL_FAILURE/SUCCESS</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="c1"># make a roll </span>
|
||||
<span class="n">dice_roll</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="n">advantage</span><span class="p">,</span> <span class="n">disadvantage</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># figure out if we had critical failure/success</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">dice_roll</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CRITICAL_FAILURE</span>
|
||||
<span class="k">elif</span> <span class="n">dice_roll</span> <span class="o">==</span> <span class="mi">20</span><span class="p">:</span>
|
||||
<span class="n">quality</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CRITICAL_SUCCESS</span>
|
||||
|
||||
<span class="c1"># figure out bonus</span>
|
||||
<span class="n">bonus</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">bonus_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># return a tuple (bool, quality)</span>
|
||||
<span class="k">return</span> <span class="p">(</span><span class="n">dice_roll</span> <span class="o">+</span> <span class="n">bonus</span><span class="p">)</span> <span class="o">></span> <span class="n">target</span><span class="p">,</span> <span class="n">quality</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">getattr(obj,</span> <span class="pre">attrname,</span> <span class="pre">default)</span></code> function is a very useful Python tool for getting an attribute
|
||||
off an object and getting a default value if the attribute is not defined.</p>
|
||||
</section>
|
||||
<section id="opposed-saving-throw">
|
||||
<h3>Opposed saving throw<a class="headerlink" href="#opposed-saving-throw" title="Permalink to this headline">¶</a></h3>
|
||||
<p>With the building pieces we already created, this method is simple. Remember that the defense you have
|
||||
to beat is always the relevant bonus + 10 in <em>Knave</em>. So if the enemy defends with <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+3</span></code>, you must
|
||||
roll higher than <code class="docutils literal notranslate"><span class="pre">13</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">saving_throw</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">opposed_saving_throw</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="n">defender</span><span class="p">,</span>
|
||||
<span class="n">attack_type</span><span class="o">=</span><span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">,</span> <span class="n">defense_type</span><span class="o">=</span><span class="n">Ability</span><span class="o">.</span><span class="n">ARMOR</span><span class="p">,</span>
|
||||
<span class="n">advantage</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||||
<span class="n">defender_defense</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">defender</span><span class="p">,</span> <span class="n">defense_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
|
||||
<span class="n">result</span><span class="p">,</span> <span class="n">quality</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">saving_throw</span><span class="p">(</span><span class="n">attacker</span><span class="p">,</span> <span class="n">bonus_type</span><span class="o">=</span><span class="n">attack_type</span><span class="p">,</span>
|
||||
<span class="n">target</span><span class="o">=</span><span class="n">defender_defense</span><span class="p">,</span>
|
||||
<span class="n">advantage</span><span class="o">=</span><span class="n">advantave</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="n">disadvantage</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">result</span><span class="p">,</span> <span class="n">quality</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="morale-check">
|
||||
<h3>Morale check<a class="headerlink" href="#morale-check" title="Permalink to this headline">¶</a></h3>
|
||||
<p>We will make the assumption that the <code class="docutils literal notranslate"><span class="pre">morale</span></code> value is available from the creature simply as
|
||||
<code class="docutils literal notranslate"><span class="pre">monster.morale</span></code> - we need to remember to make this so later!</p>
|
||||
<p>In <em>Knave</em>, a creature have roll with <code class="docutils literal notranslate"><span class="pre">2d6</span></code> equal or under its morale to not flee or surrender
|
||||
when things go south. The standard morale value is 9.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in 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">morale_check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">defender</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"2d6"</span><span class="p">)</span> <span class="o"><=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">defender</span><span class="p">,</span> <span class="s2">"morale"</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="roll-for-healing">
|
||||
<h3>Roll for Healing<a class="headerlink" href="#roll-for-healing" title="Permalink to this headline">¶</a></h3>
|
||||
<p>To be able to handle healing, we need to make some more assumptions about how we store
|
||||
health on game entities. We will need <code class="docutils literal notranslate"><span class="pre">hp_max</span></code> (the total amount of available HP) and <code class="docutils literal notranslate"><span class="pre">hp</span></code>
|
||||
(the current health value). We again assume these will be available as <code class="docutils literal notranslate"><span class="pre">obj.hp</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.hp_max</span></code>.</p>
|
||||
<p>According to the rules, after consuming a ration and having a full night’s sleep, a character regains
|
||||
<code class="docutils literal notranslate"><span class="pre">1d8</span> <span class="pre">+</span> <span class="pre">CON</span></code> HP.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</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">heal_from_rest</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="sd">""" </span>
|
||||
<span class="sd"> A night's rest retains 1d8 + CON HP </span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">con_bonus</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">character</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">roll</span><span class="p">(</span><span class="s2">"1d8"</span><span class="p">)</span> <span class="o">+</span> <span class="n">con_bonus</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We make another assumption here - that <code class="docutils literal notranslate"><span class="pre">character.heal()</span></code> is a thing. We tell this function how
|
||||
much the character should heal, and it will do so, making sure to not heal more than its max
|
||||
number of HPs</p>
|
||||
<blockquote>
|
||||
<div><p>Knowing what is available on the character and what rule rolls we need is a bit of a chicken-and-egg
|
||||
problem. We will make sure to implement the matching <em>Character</em> class next lesson.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="rolling-on-a-table">
|
||||
<h3>Rolling on a table<a class="headerlink" href="#rolling-on-a-table" title="Permalink to this headline">¶</a></h3>
|
||||
<p>We occasionally need to roll on a ‘table’ - a selection of choices. There are two main table-types
|
||||
we need to support:</p>
|
||||
<p>Simply one element per row of the table (same odds to get each result).</p>
|
||||
<table class="colwidths-auto docutils align-default">
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="text-align:center head"><p>Result</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td class="text-align:center"><p>item1</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>item2</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td class="text-align:center"><p>item3</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>item4</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>This we will simply represent as a plain list</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="s2">"item1"</span><span class="p">,</span> <span class="s2">"item2"</span><span class="p">,</span> <span class="s2">"item3"</span><span class="p">,</span> <span class="s2">"item4"</span><span class="p">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Ranges per item (varying odds per result):</p>
|
||||
<table class="colwidths-auto docutils align-default">
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="text-align:center head"><p>Range</p></th>
|
||||
<th class="text-align:center head"><p>Result</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td class="text-align:center"><p>1-5</p></td>
|
||||
<td class="text-align:center"><p>item1</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>6-15</p></td>
|
||||
<td class="text-align:center"><p>item2</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td class="text-align:center"><p>16-19</p></td>
|
||||
<td class="text-align:center"><p>item3</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>20</p></td>
|
||||
<td class="text-align:center"><p>item4</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>This we will represent as a list of tuples:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">[(</span><span class="s2">"1-5"</span><span class="p">,</span> <span class="s2">"item1"</span><span class="p">),</span> <span class="p">(</span><span class="s2">"6-15"</span><span class="p">,</span> <span class="s2">"item2"</span><span class="p">),</span> <span class="p">(</span><span class="s2">"16-19"</span><span class="p">,</span> <span class="s2">"item4"</span><span class="p">),</span> <span class="p">(</span><span class="s2">"20"</span><span class="p">,</span> <span class="s2">"item5"</span><span class="p">)]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We also need to know what die to roll to get a result on the table (it may not always
|
||||
be obvious, and in some games you could be asked to roll a lower dice to only get
|
||||
early table results, for example).</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span><span class="p">,</span> <span class="n">choice</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_random_table</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dieroll</span><span class="p">,</span> <span class="n">table_choices</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Args: </span>
|
||||
<span class="sd"> dieroll (str): A die roll string, like "1d20".</span>
|
||||
<span class="sd"> table_choices (iterable): A list of either single elements or </span>
|
||||
<span class="sd"> of tuples.</span>
|
||||
<span class="sd"> Returns: </span>
|
||||
<span class="sd"> Any: A random result from the given list of choices.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> Raises:</span>
|
||||
<span class="sd"> RuntimeError: If rolling dice giving results outside the table.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">roll_result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="n">dieroll</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">table_choices</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">(</span><span class="nb">tuple</span><span class="p">,</span> <span class="nb">list</span><span class="p">)):</span>
|
||||
<span class="c1"># the first element is a tuple/list; treat as on the form [("1-5", "item"),...]</span>
|
||||
<span class="k">for</span> <span class="p">(</span><span class="n">valrange</span><span class="p">,</span> <span class="n">choice</span><span class="p">)</span> <span class="ow">in</span> <span class="n">table_choices</span><span class="p">:</span>
|
||||
<span class="n">minval</span><span class="p">,</span> <span class="o">*</span><span class="n">maxval</span> <span class="o">=</span> <span class="n">valrange</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"-"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">minval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">minval</span><span class="p">))</span>
|
||||
<span class="n">maxval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">maxval</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">maxval</span> <span class="k">else</span> <span class="n">minval</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">minval</span> <span class="o"><=</span> <span class="n">roll_result</span> <span class="o"><=</span> <span class="n">maxval</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">choice</span>
|
||||
|
||||
<span class="c1"># if we get here we must have set a dieroll producing a value </span>
|
||||
<span class="c1"># outside of the table boundaries - raise error</span>
|
||||
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">"roll_random_table: Invalid die roll"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># a simple regular list</span>
|
||||
<span class="n">roll_result</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">min</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">table_choices</span><span class="p">),</span> <span class="n">roll_result</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">table_choices</span><span class="p">[</span><span class="n">roll_result</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Check that you understand what this does.</p>
|
||||
<p>This may be confusing:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">minval</span><span class="p">,</span> <span class="o">*</span><span class="n">maxval</span> <span class="o">=</span> <span class="n">valrange</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"-"</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="n">minval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">minval</span><span class="p">))</span>
|
||||
<span class="n">maxval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">maxval</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">maxval</span> <span class="k">else</span> <span class="n">minval</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If <code class="docutils literal notranslate"><span class="pre">valrange</span></code> is the string <code class="docutils literal notranslate"><span class="pre">1-5</span></code>, then <code class="docutils literal notranslate"><span class="pre">valrange.split("-",</span> <span class="pre">1)</span></code> would result in a tuple <code class="docutils literal notranslate"><span class="pre">("1",</span> <span class="pre">"5")</span></code>.
|
||||
But if the string was in fact just <code class="docutils literal notranslate"><span class="pre">"20"</span></code> (possible for a single entry in an RPG table), this would
|
||||
lead to an error since it would only split out a single element - and we expected two.</p>
|
||||
<p>By using <code class="docutils literal notranslate"><span class="pre">*maxval</span></code> (with the <code class="docutils literal notranslate"><span class="pre">*</span></code>), <code class="docutils literal notranslate"><span class="pre">maxval</span></code> is told to expect <em>0 or more</em> elements in a tuple.
|
||||
So the result for <code class="docutils literal notranslate"><span class="pre">1-5</span></code> will be <code class="docutils literal notranslate"><span class="pre">("1",</span> <span class="pre">("5",))</span></code> and for <code class="docutils literal notranslate"><span class="pre">20</span></code> it will become <code class="docutils literal notranslate"><span class="pre">("20",</span> <span class="pre">())</span></code>. In the line</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">maxval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">maxval</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">maxval</span> <span class="k">else</span> <span class="n">minval</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>we check if <code class="docutils literal notranslate"><span class="pre">maxval</span></code> actually has a value <code class="docutils literal notranslate"><span class="pre">("5",)</span></code> or if its empty <code class="docutils literal notranslate"><span class="pre">()</span></code>. The result is either
|
||||
<code class="docutils literal notranslate"><span class="pre">"5"</span></code> or the value of <code class="docutils literal notranslate"><span class="pre">minval</span></code>.</p>
|
||||
</section>
|
||||
<section id="roll-for-death">
|
||||
<h3>Roll for death<a class="headerlink" href="#roll-for-death" title="Permalink to this headline">¶</a></h3>
|
||||
<p>While original Knave suggests hitting 0 HP means insta-death, we will grab the optional “death table”
|
||||
from the “prettified” Knave’s optional rules to make it a little less punishing. We also changed the
|
||||
result of <code class="docutils literal notranslate"><span class="pre">2</span></code> to ‘dead’ since we don’t simulate ‘dismemberment’ in this tutorial:</p>
|
||||
<table class="colwidths-auto docutils align-default">
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="text-align:center head"><p>Roll</p></th>
|
||||
<th class="text-align:center head"><p>Result</p></th>
|
||||
<th class="text-align:center head"><p>-1d4 Loss of Ability</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td class="text-align:center"><p>1-2</p></td>
|
||||
<td class="text-align:center"><p>dead</p></td>
|
||||
<td class="text-align:center"><p>-</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>3</p></td>
|
||||
<td class="text-align:center"><p>weakened</p></td>
|
||||
<td class="text-align:center"><p>STR</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td class="text-align:center"><p>4</p></td>
|
||||
<td class="text-align:center"><p>unsteady</p></td>
|
||||
<td class="text-align:center"><p>DEX</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>5</p></td>
|
||||
<td class="text-align:center"><p>sickly</p></td>
|
||||
<td class="text-align:center"><p>CON</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td class="text-align:center"><p>6</p></td>
|
||||
<td class="text-align:center"><p>addled</p></td>
|
||||
<td class="text-align:center"><p>INT</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td class="text-align:center"><p>7</p></td>
|
||||
<td class="text-align:center"><p>rattled</p></td>
|
||||
<td class="text-align:center"><p>WIS</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td class="text-align:center"><p>8</p></td>
|
||||
<td class="text-align:center"><p>disfigured</p></td>
|
||||
<td class="text-align:center"><p>CHA</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>All the non-dead values map to a loss of 1d4 in one of the six Abilities (but you get HP back).
|
||||
We need to map back to this from the above table. One also cannot have less than -10 Ability bonus,
|
||||
if you do, you die too.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
|
||||
|
||||
<span class="n">death_table</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="p">(</span><span class="s2">"1-2"</span><span class="p">,</span> <span class="s2">"dead"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"3"</span><span class="p">:</span> <span class="s2">"strength"</span><span class="p">,</span>
|
||||
<span class="p">(</span><span class="s2">"4"</span><span class="p">:</span> <span class="s2">"dexterity"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"5"</span><span class="p">:</span> <span class="s2">"constitution"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"6"</span><span class="p">:</span> <span class="s2">"intelligence"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"7"</span><span class="p">:</span> <span class="s2">"wisdom"</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"8"</span><span class="p">:</span> <span class="s2">"charisma"</span><span class="p">),</span>
|
||||
<span class="p">)</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_random_table</span><span class="p">(</span><span class="o">...</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"># TODO - kill the character! </span>
|
||||
<span class="k">pass</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">loss</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d4"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">current_ability</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">ability_name</span><span class="p">)</span>
|
||||
<span class="n">current_ability</span> <span class="o">-=</span> <span class="n">loss</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"># TODO - kill the character!</span>
|
||||
<span class="k">pass</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># refresh 1d4 health, but suffer 1d4 ability loss</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d4"</span><span class="p">)</span>
|
||||
<span class="nb">setattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">ability_name</span><span class="p">,</span> <span class="n">current_ability</span><span class="p">)</span>
|
||||
|
||||
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span>
|
||||
<span class="s2">"You survive your brush with death, and while you recover "</span>
|
||||
<span class="sa">f</span><span class="s2">"some health, you permanently lose </span><span class="si">{</span><span class="n">loss</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">ability_name</span><span class="si">}</span><span class="s2"> instead."</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">dice</span> <span class="o">=</span> <span class="n">EvAdventureRollEngine</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we roll on the ‘death table’ from the rules to see what happens. We give the character
|
||||
a message if they survive, to let them know what happened.</p>
|
||||
<p>We don’t yet know what ‘killing the character’ technically means, so we mark this as <code class="docutils literal notranslate"><span class="pre">TODO</span></code> and
|
||||
return to it in a later lesson. We just know that we need to do <em>something</em> here to kill off the
|
||||
character!</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="testing">
|
||||
<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2>
|
||||
<blockquote>
|
||||
<div><p>Make a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_rules.py</span></code></p>
|
||||
</div></blockquote>
|
||||
<p>Testing the <code class="docutils literal notranslate"><span class="pre">rules</span></code> module will also showcase some very useful tools when testing.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_rules.py </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">unittest.mock</span> <span class="kn">import</span> <span class="n">patch</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">..</span> <span class="kn">import</span> <span class="n">rules</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">TestEvAdventureRuleEngine</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="sd">"""Called before every test method"""</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">roll_engine</span> <span class="o">=</span> <span class="n">rules</span><span class="o">.</span><span class="n">EvAdventureRollEngine</span><span class="p">()</span>
|
||||
|
||||
<span class="nd">@patch</span><span class="p">(</span><span class="s2">"evadventure.rules.randint"</span><span class="p">)</span>
|
||||
<span class="k">def</span> <span class="nf">test_roll</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mock_randint</span><span class="p">):</span>
|
||||
<span class="n">mock_randint</span><span class="o">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="mi">4</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">roll_engine</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"1d6"</span><span class="p">,</span> <span class="mi">4</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">roll_engine</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">"2d6"</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="mi">4</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># test of the other rule methods below ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As before, run the specific test with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests.test_rules
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="mocking-and-patching">
|
||||
<h3>Mocking and patching<a class="headerlink" href="#mocking-and-patching" title="Permalink to this headline">¶</a></h3>
|
||||
<aside class="sidebar">
|
||||
<p>In <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_rules.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/tests/test_rules.py</span></a>
|
||||
has a complete example of rule testing.</p>
|
||||
</aside>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">setUp</span></code> method is a special method of the testing class. It will be run before every
|
||||
test method. We use <code class="docutils literal notranslate"><span class="pre">super().setUp()</span></code> to make sure the parent class’ version of this method
|
||||
always fire. Then we create a fresh <code class="docutils literal notranslate"><span class="pre">EvAdventureRollEngine</span></code> we can test with.</p>
|
||||
<p>In our test, we import <code class="docutils literal notranslate"><span class="pre">patch</span></code> from the <code class="docutils literal notranslate"><span class="pre">unittest.mock</span></code> library. This is a very useful tool for testing.
|
||||
Normally the <code class="docutils literal notranslate"><span class="pre">randint</span></code> function we imported in <code class="docutils literal notranslate"><span class="pre">rules</span></code> will return a random value. That’s very hard to
|
||||
test for, since the value will be different every test.</p>
|
||||
<p>With <code class="docutils literal notranslate"><span class="pre">@patch</span></code> (this is called a <em>decorator</em>), we temporarily replace <code class="docutils literal notranslate"><span class="pre">rules.randint</span></code> with a ‘mock’ - a
|
||||
dummy entity. This mock is passed into the testing method. We then take this <code class="docutils literal notranslate"><span class="pre">mock_randint</span></code> and set
|
||||
<code class="docutils literal notranslate"><span class="pre">.return_value</span> <span class="pre">=</span> <span class="pre">4</span></code> on it.</p>
|
||||
<p>Adding <code class="docutils literal notranslate"><span class="pre">return_value</span></code> to the mock means that every time this mock is called, it will return 4. For the
|
||||
duration of the test we can now check with <code class="docutils literal notranslate"><span class="pre">self.assertEqual</span></code> that our <code class="docutils literal notranslate"><span class="pre">roll</span></code> method always returns a
|
||||
result as-if the random result was 4.</p>
|
||||
<p>There are <a class="reference external" href="https://realpython.com/python-mock-library/">many resources for understanding mock</a>, refer to
|
||||
them for further help.</p>
|
||||
<blockquote>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">EvAdventureRollEngine</span></code> have many methods to test. We leave this as an extra exercise!</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
</section>
|
||||
<section id="summary">
|
||||
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This concludes all the core rule mechanics of <em>Knave</em> - the rules used during play. We noticed here
|
||||
that we are going to soon need to establish how our <em>Character</em> actually stores data. So we will
|
||||
address that next.</p>
|
||||
</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-Characters.html" title="Player Characters"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Utilities.html" title="Code structure and Utilities"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Rules and dice rolling</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
|
||||
<!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>In-game Shops — Evennia 1.0-dev 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="Dynamically generated Dungeon" href="Beginner-Tutorial-Dungeon.html" />
|
||||
<link rel="prev" title="Game Quests" href="Beginner-Tutorial-Quests.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-Dungeon.html" title="Dynamically generated Dungeon"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Quests.html" title="Game Quests"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Shops</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Quests.html"
|
||||
title="previous chapter">Game Quests</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Dungeon.html"
|
||||
title="next chapter">Dynamically generated Dungeon</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-Shops.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Shops.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="in-game-shops">
|
||||
<h1>In-game Shops<a class="headerlink" href="#in-game-shops" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This part of the Beginner tutorial is still being developed.</p>
|
||||
</div>
|
||||
</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-Dungeon.html" title="Dynamically generated Dungeon"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Quests.html" title="Game Quests"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">In-game Shops</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,435 @@
|
|||
|
||||
<!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>Code structure and Utilities — Evennia 1.0-dev 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="Rules and dice rolling" href="Beginner-Tutorial-Rules.html" />
|
||||
<link rel="prev" title="Part 3: How we get there" href="Beginner-Tutorial-Part3-Intro.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-Rules.html" title="Rules and dice rolling"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Code structure and Utilities</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</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="#">Code structure and Utilities</a><ul>
|
||||
<li><a class="reference internal" href="#folder-structure">Folder structure</a></li>
|
||||
<li><a class="reference internal" href="#enums">Enums</a></li>
|
||||
<li><a class="reference internal" href="#utility-module">Utility module</a></li>
|
||||
<li><a class="reference internal" href="#testing">Testing</a><ul>
|
||||
<li><a class="reference internal" href="#running-your-test">Running your test</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#summary">Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Part3-Intro.html"
|
||||
title="previous chapter">Part 3: How we get there</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
|
||||
title="next chapter">Rules and dice rolling</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-Utilities.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/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>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Utilities.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="code-structure-and-utilities">
|
||||
<h1>Code structure and Utilities<a class="headerlink" href="#code-structure-and-utilities" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In this lesson we will set up the file structure for <em>EvAdventure</em>. We will make some
|
||||
utilities that will be useful later. We will also learn how to write <em>tests</em>.</p>
|
||||
<section id="folder-structure">
|
||||
<h2>Folder structure<a class="headerlink" href="#folder-structure" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Create a new folder under your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder, named <code class="docutils literal notranslate"><span class="pre">evadventure</span></code>. Inside it, create
|
||||
another folder <code class="docutils literal notranslate"><span class="pre">tests/</span></code> and make sure to put empty <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> files in both. This turns both
|
||||
folders into packages Python understands to import from.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mygame</span><span class="o">/</span>
|
||||
<span class="n">commands</span><span class="o">/</span>
|
||||
<span class="n">evadventure</span><span class="o">/</span> <span class="o"><---</span>
|
||||
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span> <span class="o"><---</span>
|
||||
<span class="n">tests</span><span class="o">/</span> <span class="o"><---</span>
|
||||
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span> <span class="o"><---</span>
|
||||
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
|
||||
<span class="n">README</span><span class="o">.</span><span class="n">md</span>
|
||||
<span class="n">server</span><span class="o">/</span>
|
||||
<span class="n">typeclasses</span><span class="o">/</span>
|
||||
<span class="n">web</span><span class="o">/</span>
|
||||
<span class="n">world</span><span class="o">/</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Importing anything from inside this folder from anywhere else under <code class="docutils literal notranslate"><span class="pre">mygame</span></code> will be done by</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from anywhere in mygame/</span>
|
||||
<span class="kn">from</span> <span class="nn">evadventure.yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is the ‘absolute path` type of import.</p>
|
||||
<p>Between two modules both in <code class="docutils literal notranslate"><span class="pre">evadventure/</span></code>, you can use a ‘relative’ import with <code class="docutils literal notranslate"><span class="pre">.</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from a module inside mygame/evadventure</span>
|
||||
<span class="kn">from</span> <span class="nn">.yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>From e.g. inside <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/</span></code> you can import from one level above using <code class="docutils literal notranslate"><span class="pre">..</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from mygame/evadventure/tests/ </span>
|
||||
<span class="kn">from</span> <span class="nn">..yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="enums">
|
||||
<h2>Enums<a class="headerlink" href="#enums" title="Permalink to this headline">¶</a></h2>
|
||||
<aside class="sidebar">
|
||||
<p>A full example of the enum module is found in
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.enums.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/enums.py</span></a>.</p>
|
||||
</aside>
|
||||
<p>Create a new file <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/enums.py</span></code>.</p>
|
||||
<p>An <a class="reference external" href="https://docs.python.org/3/library/enum.html">enum</a> (enumeration) is a way to establish constants
|
||||
in Python. Best is to show an example:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in a file mygame/evadventure/enums.py</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Ability</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||||
|
||||
<span class="n">STR</span> <span class="o">=</span> <span class="s2">"strength"</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You access an enum like this:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># from another module in mygame/evadventure</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
|
||||
|
||||
<span class="n">Ability</span><span class="o">.</span><span class="n">STR</span> <span class="c1"># the enum itself </span>
|
||||
<span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="o">.</span><span class="n">value</span> <span class="c1"># this is the string "strength"</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Having enums is recommended practice. With them set up, it means we can make sure to refer to the
|
||||
same thing every time. Having all enums in one place also means you have a good overview of the
|
||||
constants you are dealing with.</p>
|
||||
<p>The alternative would be to for example pass around a string <code class="docutils literal notranslate"><span class="pre">"constitution"</span></code>. If you mis-spell
|
||||
this (<code class="docutils literal notranslate"><span class="pre">"consitution"</span></code>), you would not necessarily know it right away - the error would happen later
|
||||
when the string is not recognized. If you make a typo getting <code class="docutils literal notranslate"><span class="pre">Ability.COM</span></code> instead of <code class="docutils literal notranslate"><span class="pre">Ability.CON</span></code>,
|
||||
Python will immediately raise an error since this enum is not recognized.</p>
|
||||
<p>With enums you can also do nice direct comparisons like <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">ability</span> <span class="pre">is</span> <span class="pre">Ability.WIS:</span> <span class="pre"><do</span> <span class="pre">stuff></span></code>.</p>
|
||||
<p>Note that the <code class="docutils literal notranslate"><span class="pre">Ability.STR</span></code> enum does not have the actual <em>value</em> of e.g. your Strength.
|
||||
It’s just a fixed label for the Strength ability.</p>
|
||||
<p>Here is the <code class="docutils literal notranslate"><span class="pre">enum.py</span></code> module needed for <em>Knave</em>. It covers the basic aspects of
|
||||
rule systems we need to track (check out the <em>Knave</em> rules. If you use another rule system you’ll
|
||||
likely gradually expand on your enums as you figure out what you’ll need).</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Ability</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> The six base ability-bonuses and other </span>
|
||||
<span class="sd"> abilities</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">STR</span> <span class="o">=</span> <span class="s2">"strength"</span>
|
||||
<span class="n">DEX</span> <span class="o">=</span> <span class="s2">"dexterity"</span>
|
||||
<span class="n">CON</span> <span class="o">=</span> <span class="s2">"constitution"</span>
|
||||
<span class="n">INT</span> <span class="o">=</span> <span class="s2">"intelligence"</span>
|
||||
<span class="n">WIS</span> <span class="o">=</span> <span class="s2">"wisdom"</span>
|
||||
<span class="n">CHA</span> <span class="o">=</span> <span class="s2">"charisma"</span>
|
||||
|
||||
<span class="n">ARMOR</span> <span class="o">=</span> <span class="s2">"armor"</span>
|
||||
|
||||
<span class="n">CRITICAL_FAILURE</span> <span class="o">=</span> <span class="s2">"critical_failure"</span>
|
||||
<span class="n">CRITICAL_SUCCESS</span> <span class="o">=</span> <span class="s2">"critical_success"</span>
|
||||
|
||||
<span class="n">ALLEGIANCE_HOSTILE</span> <span class="o">=</span> <span class="s2">"hostile"</span>
|
||||
<span class="n">ALLEGIANCE_NEUTRAL</span> <span class="o">=</span> <span class="s2">"neutral"</span>
|
||||
<span class="n">ALLEGIANCE_FRIENDLY</span> <span class="o">=</span> <span class="s2">"friendly"</span>
|
||||
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here the <code class="docutils literal notranslate"><span class="pre">Ability</span></code> class holds basic properties of a character sheet.</p>
|
||||
</section>
|
||||
<section id="utility-module">
|
||||
<h2>Utility module<a class="headerlink" href="#utility-module" title="Permalink to this headline">¶</a></h2>
|
||||
<blockquote>
|
||||
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/utils.py</span></code></p>
|
||||
</div></blockquote>
|
||||
<aside class="sidebar">
|
||||
<p>An example of the utility module is found in
|
||||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.utils.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/utils.py</span></a></p>
|
||||
</aside>
|
||||
<p>This is for general functions we may need from all over. In this case we only picture one utility,
|
||||
a function that produces a pretty display of any object we pass to it.</p>
|
||||
<p>This is an example of the string we want to see:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Chipped</span> <span class="n">Sword</span>
|
||||
<span class="n">Value</span><span class="p">:</span> <span class="o">~</span><span class="mi">10</span> <span class="n">coins</span> <span class="p">[</span><span class="n">wielded</span> <span class="ow">in</span> <span class="n">Weapon</span> <span class="n">hand</span><span class="p">]</span>
|
||||
|
||||
<span class="n">A</span> <span class="n">simple</span> <span class="n">sword</span> <span class="n">used</span> <span class="n">by</span> <span class="n">mercenaries</span> <span class="nb">all</span> <span class="n">over</span>
|
||||
<span class="n">the</span> <span class="n">world</span><span class="o">.</span>
|
||||
|
||||
<span class="n">Slots</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="n">Used</span> <span class="n">from</span><span class="p">:</span> <span class="n">weapon</span> <span class="n">hand</span>
|
||||
<span class="n">Quality</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="n">Uses</span><span class="p">:</span> <span class="kc">None</span>
|
||||
<span class="n">Attacks</span> <span class="n">using</span> <span class="n">strength</span> <span class="n">against</span> <span class="n">armor</span><span class="o">.</span>
|
||||
<span class="n">Damage</span> <span class="n">roll</span><span class="p">:</span> <span class="mi">1</span><span class="n">d6</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here’s the start of how the function could look:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/utils.py</span>
|
||||
|
||||
<span class="n">_OBJ_STATS</span> <span class="o">=</span> <span class="s2">"""</span>
|
||||
<span class="s2">|c</span><span class="si">{key}</span><span class="s2">|n</span>
|
||||
<span class="s2">Value: ~|y</span><span class="si">{value}</span><span class="s2">|n coins</span><span class="si">{carried}</span><span class="s2"></span>
|
||||
|
||||
<span class="si">{desc}</span><span class="s2"></span>
|
||||
|
||||
<span class="s2">Slots: |w</span><span class="si">{size}</span><span class="s2">|n, Used from: |w</span><span class="si">{use_slot_name}</span><span class="s2">|n</span>
|
||||
<span class="s2">Quality: |w</span><span class="si">{quality}</span><span class="s2">|n, Uses: |wuses|n</span>
|
||||
<span class="s2">Attacks using |w</span><span class="si">{attack_type_name}</span><span class="s2">|n against |w</span><span class="si">{defense_type_name}</span><span class="s2">|n</span>
|
||||
<span class="s2">Damage roll: |w</span><span class="si">{damage_roll}</span><span class="s2">|n</span>
|
||||
<span class="s2">"""</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">get_obj_stats</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">owner</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Get a string of stats about the object.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> obj (Object): The object to get stats for.</span>
|
||||
<span class="sd"> owner (Object): The one currently owning/carrying `obj`, if any. Can be </span>
|
||||
<span class="sd"> used to show e.g. where they are wielding it.</span>
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> str: A nice info string to display about the object.</span>
|
||||
<span class="sd"> </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="n">_OBJ_STATS</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
|
||||
<span class="n">key</span><span class="o">=</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
|
||||
<span class="n">value</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
|
||||
<span class="n">carried</span><span class="o">=</span><span class="s2">"[Not carried]"</span><span class="p">,</span>
|
||||
<span class="n">desc</span><span class="o">=</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span><span class="p">,</span>
|
||||
<span class="n">size</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
|
||||
<span class="n">quality</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
|
||||
<span class="n">uses</span><span class="o">=</span><span class="s2">"infinite"</span>
|
||||
<span class="n">use_slot_name</span><span class="o">=</span><span class="s2">"backpack"</span><span class="p">,</span>
|
||||
<span class="n">attack_type_name</span><span class="o">=</span><span class="s2">"strength"</span>
|
||||
<span class="n">defense_type_name</span><span class="o">=</span><span class="s2">"armor"</span>
|
||||
<span class="n">damage_roll</span><span class="o">=</span><span class="s2">"1d6"</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we set up the string template with place holders for where every piece of info should go.
|
||||
Study this string so you understand what it does. The <code class="docutils literal notranslate"><span class="pre">|c</span></code>, <code class="docutils literal notranslate"><span class="pre">|y</span></code>, <code class="docutils literal notranslate"><span class="pre">|w</span></code> and <code class="docutils literal notranslate"><span class="pre">|n</span></code> markers are
|
||||
<a class="reference internal" href="../../../Concepts/Colors.html"><span class="doc std std-doc">Evennia color markup</span></a> for making the text cyan, yellow, white and neutral-color respectively.</p>
|
||||
<p>We can guess some things, such that <code class="docutils literal notranslate"><span class="pre">obj.key</span></code> is the name of the object, and that <code class="docutils literal notranslate"><span class="pre">obj.db.desc</span></code> will
|
||||
hold its description (this is how it is in default Evennia).</p>
|
||||
<p>But so far we have not established how to get any of the other properties like <code class="docutils literal notranslate"><span class="pre">size</span></code> or <code class="docutils literal notranslate"><span class="pre">attack_type</span></code>.
|
||||
So we just set them to dummy values. We’ll need to get back to this when we have more code in place!</p>
|
||||
</section>
|
||||
<section id="testing">
|
||||
<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>It’s useful for any game dev to know how to effectively test their code. So we’ll try to include a
|
||||
<em>Testing</em> section at the end of each of the implementation lessons to follow. Writing tests for your code
|
||||
is optional but highly recommended; it can feel a little cumbersome at first, but you’ll thank yourself later.</p>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_utils.py</span></code></p>
|
||||
</div></blockquote>
|
||||
<p>How do you know if you made a typo in the code above? You could <em>manually</em> test it by reloading your
|
||||
Evennia server and do the following from in-game:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py from evadventure.utils import get_obj_stats;print(get_obj_stats(self))
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You should get back a nice string about yourself! If that works, great! But you’ll need to remember
|
||||
doing that test when you change this code later.</p>
|
||||
<aside class="sidebar">
|
||||
<p>In [evennia/contrib/tutorials/evadventure/tests/test_utils.py](evennia.contrib.tutorials.
|
||||
evadventure.tests.test_utils)
|
||||
is an example of the testing module. To dive deeper into unit testing in Evennia, see the
|
||||
<a class="reference internal" href="../../../Coding/Unit-Testing.html"><span class="doc std std-doc">Unit testing</span></a> documentation.</p>
|
||||
</aside>
|
||||
<p>A <em>unit test</em> allows you to set up automated testing of code. Once you’ve written your test you
|
||||
can run it over and over and make sure later changes to your code didn’t break things.</p>
|
||||
<p>In this particular case, we <em>expect</em> to later have to update the test when <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> becomes more
|
||||
complete and returns more reasonable data.</p>
|
||||
<p>Evennia comes with extensive functionality to help you test your code. Here’s a module for
|
||||
testing <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_utils.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">..import</span> <span class="n">utils</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">TestUtils</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
|
||||
<span class="k">def</span> <span class="nf">test_get_obj_stats</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="c1"># make a simple object to test with </span>
|
||||
<span class="n">obj</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">key</span><span class="o">=</span><span class="s2">"testobj"</span><span class="p">,</span>
|
||||
<span class="n">attributes</span><span class="o">=</span><span class="p">((</span><span class="s2">"desc"</span><span class="p">,</span> <span class="s2">"A test object"</span><span class="p">),)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="c1"># run it through the function </span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">get_obj_stats</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||||
<span class="c1"># check that the result is what we expected</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="sd">""" </span>
|
||||
<span class="sd">|ctestobj|n</span>
|
||||
<span class="sd">Value: ~|y10|n coins</span>
|
||||
|
||||
<span class="sd">A test object</span>
|
||||
|
||||
<span class="sd">Slots: |w1|n, Used from: |wbackpack|n</span>
|
||||
<span class="sd">Quality: |w3|n, Uses: |winfinite|n</span>
|
||||
<span class="sd">Attacks using |wstrength|n against |warmor|n</span>
|
||||
<span class="sd">Damage roll: |w1d6|n</span>
|
||||
<span class="sd">"""</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>What happens here is that we create a new test-class <code class="docutils literal notranslate"><span class="pre">TestUtils</span></code> that inherits from <code class="docutils literal notranslate"><span class="pre">BaseEvenniaTest</span></code>.
|
||||
This inheritance is what makes this a testing class.</p>
|
||||
<p>We can have any number of methods on this class. To have a method recognized as one containing
|
||||
code to test, its name <em>must</em> start with <code class="docutils literal notranslate"><span class="pre">test_</span></code>. We have one - <code class="docutils literal notranslate"><span class="pre">test_get_obj_stats</span></code>.</p>
|
||||
<p>In this method we create a dummy <code class="docutils literal notranslate"><span class="pre">obj</span></code> and gives it a <code class="docutils literal notranslate"><span class="pre">key</span></code> “testobj”. Note how we add the
|
||||
<code class="docutils literal notranslate"><span class="pre">desc</span></code> <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a> directly in the <code class="docutils literal notranslate"><span class="pre">create_object</span></code> call by specifying the attribute as a
|
||||
tuple <code class="docutils literal notranslate"><span class="pre">(name,</span> <span class="pre">value)</span></code>!</p>
|
||||
<p>We then get the result of passing this dummy-object through <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> we imported earlier.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">assertEqual</span></code> method is available on all testing classes and checks that the <code class="docutils literal notranslate"><span class="pre">result</span></code> is equal
|
||||
to the string we specify. If they are the same, the test <em>passes</em>, otherwise it <em>fails</em> and we
|
||||
need to investigate what went wrong.</p>
|
||||
<section id="running-your-test">
|
||||
<h3>Running your test<a class="headerlink" href="#running-your-test" title="Permalink to this headline">¶</a></h3>
|
||||
<p>To run your test you need to stand inside your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder and execute the following command:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will run all your <code class="docutils literal notranslate"><span class="pre">evadventure</span></code> tests (if you had more of them). To only run your utility tests
|
||||
you could do</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests.test_utils
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If all goes well, you should get an <code class="docutils literal notranslate"><span class="pre">OK</span></code> back. Otherwise you need to check the failure, maybe
|
||||
your return string doesn’t quite match what you expected.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="summary">
|
||||
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p>It’s very important to understand how you import code between modules in Python, so if this is still
|
||||
confusing to you, it’s worth to read up on this more.</p>
|
||||
<p>That said, many newcomers are confused with how to begin, so by creating the folder structure, some
|
||||
small modules and even making your first unit test, you are off to a great start!</p>
|
||||
</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-Rules.html" title="Rules and dice rolling"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Code structure and Utilities</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue