mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
438 lines
No EOL
35 KiB
HTML
438 lines
No EOL
35 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||
|
||
<title>1. Code structure and Utilities — Evennia latest documentation</title>
|
||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||
<script src="../../../_static/jquery.js"></script>
|
||
<script src="../../../_static/underscore.js"></script>
|
||
<script src="../../../_static/doctools.js"></script>
|
||
<script src="../../../_static/language_data.js"></script>
|
||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||
<link rel="search" title="Search" href="../../../search.html" />
|
||
<link rel="next" title="2. Rules and dice rolling" href="Beginner-Tutorial-Rules.html" />
|
||
<link rel="prev" title="Part 3: How We Get There (Example Game)" href="Beginner-Tutorial-Part3-Overview.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="2. Rules and dice rolling"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Beginner-Tutorial-Part3-Overview.html" title="Part 3: How We Get There (Example Game)"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and How-To’s</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Overview.html" >Beginner Tutorial</a> »</li>
|
||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Overview.html" accesskey="U">Part 3: How We Get There (Example Game)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">1. </span>Code structure and Utilities</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
|
||
<div class="documentwrapper">
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="../../../index.html">
|
||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="../../../search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">1. Code structure and Utilities</a><ul>
|
||
<li><a class="reference internal" href="#folder-structure">1.1. Folder structure</a></li>
|
||
<li><a class="reference internal" href="#enums">1.2. Enums</a></li>
|
||
<li><a class="reference internal" href="#utility-module">1.3. Utility module</a></li>
|
||
<li><a class="reference internal" href="#testing">1.4. Testing</a><ul>
|
||
<li><a class="reference internal" href="#running-your-test">1.4.1. Running your test</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#summary">1.5. Summary</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Beginner-Tutorial-Part3-Overview.html"
|
||
title="previous chapter">Part 3: How We Get There (Example Game)</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
|
||
title="next chapter"><span class="section-number">2. </span>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/docs/latest/index.html">Documentation Top</a> </li>
|
||
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li>
|
||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||
</li>
|
||
</ul>
|
||
<h3>Doc Versions</h3>
|
||
<ul>
|
||
|
||
<li><a href="Beginner-Tutorial-Utilities.html">latest (main branch)</a></li>
|
||
|
||
<li><a href="../../2.x/index.html">2.x (v2.0.0 branch)</a></li>
|
||
|
||
<li><a href="../../1.x/index.html">1.x (v1.0.0 branch)</a></li>
|
||
|
||
<li><a href="../../0.x/index.html">0.x (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><span class="section-number">1. </span>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><span class="section-number">1.1. </span>Folder structure<a class="headerlink" href="#folder-structure" title="Permalink to this headline">¶</a></h2>
|
||
<aside class="sidebar">
|
||
<p class="sidebar-title">This layout is for the tutorial!</p>
|
||
<p>We make the <code class="docutils literal notranslate"><span class="pre">evadventure</span></code> folder stand-alone for the sake of the tutorial only. Leaving the code isolated makes it clear what we changed - and for you to grab what you want later. It also makes it easier to refer to matching code in <code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorials/evadventure</span></code>.</p>
|
||
<p>For your own game you are encouraged to modify your game dir in-place instead (such as add to <code class="docutils literal notranslate"><span class="pre">commands/commands.py</span></code> and to modify the <code class="docutils literal notranslate"><span class="pre">typeclasses/</span></code> modules directly). Except for the <code class="docutils literal notranslate"><span class="pre">server/</span></code> folder, you are infact free to structure your game dir code pretty much as you like.</p>
|
||
</aside>
|
||
<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><span class="section-number">1.2. </span>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="w"> </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>
|
||
|
||
|
||
<span class="n">ABILITY_REVERSE_MAP</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s2">"str"</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="s2">"dex"</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="s2">"con"</span><span class="p">:</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="p">,</span>
|
||
<span class="s2">"int"</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="s2">"wis"</span><span class="p">:</span> <span class="n">Ability</span><span class="o">.</span><span class="n">WIS</span><span class="p">,</span>
|
||
<span class="s2">"cha"</span><span class="p">:</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CHA</span>
|
||
<span class="p">}</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>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">ABILITY_REVERSE_MAP</span></code> is a convenient map to go the other way - if you in some command were to enter the string ‘cha’, we could use this mapping to directly convert your input to the correct <code class="docutils literal notranslate"><span class="pre">Ability</span></code>:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>ability = ABILITY_REVERSE_MAP.get(your_input)
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="utility-module">
|
||
<h2><span class="section-number">1.3. </span>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="si">{desc}</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: |w</span><span class="si">{uses}</span><span class="s2">|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="w"> </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="p">,</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="p">,</span>
|
||
<span class="n">defense_type_name</span><span class="o">=</span><span class="s2">"armor"</span><span class="p">,</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><span class="section-number">1.4. </span>Testing<a class="headerlink" href="#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_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 <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_utils.html#evennia-contrib-tutorials-evadventure-tests-test-utils"><span class="std std-ref">evennia/contrib/tutorials/evadventure/tests/test_utils.py</span></a>
|
||
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">EvenniaTest</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">EvenniaTest</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="w"> </span><span class="sd">""" </span>
|
||
<span class="sd">|ctestobj|n</span>
|
||
<span class="sd">Value: ~|y10|n coins[not carried]</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">EvenniaTest</span></code>. This inheritance is what makes this a testing class.</p>
|
||
<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 or time-consuming at first … but you’ll thank yourself later.</p>
|
||
</div>
|
||
<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><span class="section-number">1.4.1. </span>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>
|
||
<blockquote>
|
||
<div><p>Hint: The example unit test code above contains a deliberate error in capitalization. See if you can interpret the error and fix it!</p>
|
||
</div></blockquote>
|
||
</section>
|
||
</section>
|
||
<section id="summary">
|
||
<h2><span class="section-number">1.5. </span>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="2. Rules and dice rolling"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Beginner-Tutorial-Part3-Overview.html" title="Part 3: How We Get There (Example Game)"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and How-To’s</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Overview.html" >Beginner Tutorial</a> »</li>
|
||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Overview.html" >Part 3: How We Get There (Example Game)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">1. </span>Code structure and Utilities</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2023, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |