<h1><spanclass="section-number">9. </span>Combat base framework<aclass="headerlink"href="#combat-base-framework"title="Permalink to this headline">¶</a></h1>
<p>Combat is core to many games. Exactly how it works is very game-dependent. In this lesson we will build a framework to implement two common flavors:</p>
<ulclass="simple">
<li><p>“Twitch-based” combat (<aclass="reference internal"href="Beginner-Tutorial-Combat-Twitch.html"><spanclass="doc std std-doc">specific lesson here</span></a>) means that you perform a combat action by entering a command, and after some delay (which may depend on your skills etc), the action happens. It’s called ‘twitch’ because actions often happen fast enough that changing your strategy may involve some element of quick thinking and a ‘twitchy trigger finger’.</p></li>
<li><p>“Turn-based” combat (<aclass="reference internal"href="Beginner-Tutorial-Combat-Turnbased.html"><spanclass="doc std std-doc">specific lesson here</span></a>) means that players input actions in clear turns. Timeout for entering/queuing your actions is often much longer than twitch-based style. Once everyone made their choice (or the timeout is reached), everyone’s action happens all at once, after which the next turn starts. This style of combat requires less player reflexes.</p></li>
</ul>
<p>We will design a base combat system that supports both styles.</p>
<ulclass="simple">
<li><p>We need a <codeclass="docutils literal notranslate"><spanclass="pre">CombatHandler</span></code> to track the progress of combat. This will be a <aclass="reference internal"href="../../../Components/Scripts.html"><spanclass="doc std std-doc">Script</span></a>. Exactly how this works (and where it is stored) will be a bit different between Twitch- and Turnbased combat. We will create its common framework in this lesson.</p></li>
<li><p>Combat are divided into <em>actions</em>. We want to be able to easily extend our combat with more possible actions. An action needs Python code to show what actually happens when the action is performed. We will define such code in <codeclass="docutils literal notranslate"><spanclass="pre">Action</span></code> classes.</p></li>
<li><p>We also need a way to describe a <em>specific instance</em> of a given action. That is, when we do an “attack” action, we need at the minimum to know who is being attacked. For this will we use Python <codeclass="docutils literal notranslate"><spanclass="pre">dicts</span></code> that we will refer to as <codeclass="docutils literal notranslate"><spanclass="pre">action_dicts</span></code>.</p></li>
</ul>
<sectionid="combathandler">
<h2><spanclass="section-number">9.1. </span>CombatHandler<aclass="headerlink"href="#combathandler"title="Permalink to this headline">¶</a></h2>
<blockquote>
<div><p>Create a new module <codeclass="docutils literal notranslate"><spanclass="pre">evadventure/combat_base.py</span></code></p>
</div></blockquote>
<asideclass="sidebar">
<p>In <aclass="reference internal"href="../../../api/evennia.contrib.tutorials.evadventure.combat_base.html#evennia-contrib-tutorials-evadventure-combat-base"><spanclass="std std-ref">evennia/contrib/tutorials/evadventure/combat_base.py</span></a> you’ll find a complete implementation of the base combat module.</p>
</aside>
<p>Our “Combat Handler” will handle the administration around combat. It needs to be <em>persistent</em> (even is we reload the server your combat should keep going).</p>
<p>Creating the CombatHandler is a little of a catch-22 - how it works depends on how Actions and Action-dicts look. But without having the CombatHandler, it’s hard to know how to design Actions and Action-dicts. So we’ll start with its general structure and fill out the details later in this lesson.</p>
<p>Below, methods with <codeclass="docutils literal notranslate"><spanclass="pre">pass</span></code> will be filled out this lesson while those raising <codeclass="docutils literal notranslate"><spanclass="pre">NotImplementedError</span></code> will be different for Twitch/Turnbased combat and will be implemented in their respective lessons following this one.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<p>The Combat Handler is a <aclass="reference internal"href="../../../Components/Scripts.html"><spanclass="doc std std-doc">Script</span></a>. Scripts are typeclassed entities, which means that they are persistently stored in the database. Scripts can optionally be stored “on” other objects (such as on Characters or Rooms) or be ‘global’ without any such connection. While Scripts has an optional timer component, it is not active by default and Scripts are commonly used just as plain storage. Since Scripts don’t have an in-game existence, they are great for storing data on ‘systems’ of all kinds, including our combat.</p>
<p>Let’s implement the generic methods we need.</p>
<h3><spanclass="section-number">9.1.1. </span>CombatHandler.get_or_create_combathandler<aclass="headerlink"href="#combathandler-get-or-create-combathandler"title="Permalink to this headline">¶</a></h3>
<p>A helper method for quickly getting the combathandler for an ongoing combat and combatant.</p>
<p>We expect to create the script “on” an object (which one we don’t know yet, but we expect it to be a typeclassed entity).</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py</span>
<spanclass="k">raise</span><spanclass="n">CombatFailure</span><spanclass="p">(</span><spanclass="s2">"Cannot start combat without a place to do it!"</span><spanclass="p">)</span>
<p>This helper method uses <codeclass="docutils literal notranslate"><spanclass="pre">obj.scripts.get()</span></code> to find if the combat script already exists ‘on’ the provided <codeclass="docutils literal notranslate"><spanclass="pre">obj</span></code>. If not, it will create it using Evennia’s <aclass="reference internal"href="../../../api/evennia.utils.create.html#evennia.utils.create.create_script"title="evennia.utils.create.create_script"><spanclass="xref myst py py-func">create_script</span></a> function. For some extra speed we cache the handler as <codeclass="docutils literal notranslate"><spanclass="pre">obj.ndb.combathandler</span></code> The <codeclass="docutils literal notranslate"><spanclass="pre">.ndb.</span></code> (non-db) means that handler is cached only in memory.</p>
<asideclass="sidebar">
<pclass="sidebar-title">Checking .id (or .pk)</p>
<p>When getting it from cache, we make sure to also check if the combathandler we got has a database <codeclass="docutils literal notranslate"><spanclass="pre">.id</span></code> that is not <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> (we could also check <codeclass="docutils literal notranslate"><spanclass="pre">.pk</span></code>, stands for “primary key”) . If it’s <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code>, this means the database entity was deleted and we just got its cached python representation from memory - we need to recreate it.</p>
</aside>
<p><codeclass="docutils literal notranslate"><spanclass="pre">get_or_create_combathandler</span></code> is decorated to be a <aclass="reference external"href="https://docs.python.org/3/library/functions.html#classmethod">classmethod</a>, meaning it should be used on the handler class directly (rather than on an <em>instance</em> of said class). This makes sense because this method actually should return the new instance.</p>
<p>As a class method we’ll need to call this directly on the class, like this:</p>
<p>The result will be a new handler <em>or</em> one that was already defined.</p>
</section>
<sectionid="combathandler-msg">
<h3><spanclass="section-number">9.1.2. </span>CombatHandler.msg<aclass="headerlink"href="#combathandler-msg"title="Permalink to this headline">¶</a></h3>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">self.obj</span></code> property of a Script is the entity on which the Script ‘sits’. If set on a Character, <codeclass="docutils literal notranslate"><spanclass="pre">self.obj</span></code> will be that Character. If on a room, it’d be that room. For a global script, <codeclass="docutils literal notranslate"><spanclass="pre">self.obj</span></code> is <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code>.</p>
</aside>
<p>We saw the <codeclass="docutils literal notranslate"><spanclass="pre">location.msg_contents()</span></code> method before in the <aclass="reference internal"href="Beginner-Tutorial-Objects.html#weapons"><spanclass="std std-doc">Weapon class of the Objects lesson</span></a>. Its purpose is to take a string on the form <codeclass="docutils literal notranslate"><spanclass="pre">"$You()</span><spanclass="pre">do</span><spanclass="pre">stuff</span><spanclass="pre">against</span><spanclass="pre">$you(key)"</span></code> and make sure all sides see a string suitable just to them. Our <codeclass="docutils literal notranslate"><spanclass="pre">msg()</span></code> method will by default broadcast the message to everyone in the room.</p>
<spanclass="sa">f</span><spanclass="s2">"$You() $conj(throw) </span><spanclass="si">{</span><spanclass="n">item</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2"> at $you(</span><spanclass="si">{</span><spanclass="n">target</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2">)."</span><spanclass="p">,</span>
<p>If combatant is <codeclass="docutils literal notranslate"><spanclass="pre">Trickster</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">item.key</span></code> is “a colorful ball” and <codeclass="docutils literal notranslate"><spanclass="pre">target.key</span></code> is “Goblin”, then</p>
<p>The combatant would see:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>You throw a colorful ball at Goblin.
</pre></div>
</div>
<p>The Goblin sees</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>Trickster throws a colorful ball at you.
</pre></div>
</div>
<p>Everyone else in the room sees</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>Trickster throws a colorful ball at Goblin.
</pre></div>
</div>
</section>
<sectionid="combathandler-get-combat-summary">
<h3><spanclass="section-number">9.1.3. </span>Combathandler.get_combat_summary<aclass="headerlink"href="#combathandler-get-combat-summary"title="Permalink to this headline">¶</a></h3>
<p>We want to be able to show a nice summary of the current combat:</p>
<p>This may look complex, but the complexity is only in figuring out how to organize three columns, especially how to to adjust to the two sides on each side of the <codeclass="docutils literal notranslate"><spanclass="pre">vs</span></code> are roughly vertically aligned.</p>
<ulclass="simple">
<li><p><strong>Line 15</strong> : We make use of the <codeclass="docutils literal notranslate"><spanclass="pre">self.get_sides(combatant)</span></code> method which we haven’t actually implemented yet. This is because turn-based and twitch-based combat will need different ways to find out what the sides are. The <codeclass="docutils literal notranslate"><spanclass="pre">allies</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">enemies</span></code> are lists.</p></li>
<li><p><strong>Line 17</strong>: The <codeclass="docutils literal notranslate"><spanclass="pre">combatant</span></code> is not a part of the <codeclass="docutils literal notranslate"><spanclass="pre">allies</span></code> list (this is how we defined <codeclass="docutils literal notranslate"><spanclass="pre">get_sides</span></code> to work), so we insert it at the top of the list (so they show first on the left-hand side).</p></li>
<li><p><strong>Lines 21, 22</strong>: We make use of the <codeclass="docutils literal notranslate"><spanclass="pre">.hurt_level</span></code> values of all living things (see the <aclass="reference internal"href="Beginner-Tutorial-Characters.html"><spanclass="doc std std-doc">LivingMixin of the Character lesson</span></a>).</p></li>
<li><p><strong>Lines 28-39</strong>: We determine how to vertically center the two sides by adding empty lines above and below the content.</p></li>
<li><p><strong>Line 41</strong>: The <aclass="reference internal"href="../../../Components/EvTable.html"><spanclass="doc std std-doc">Evtable</span></a> is an Evennia utility for making, well, text tables. Once we are happy with the columns, we feed them to the table and let Evennia do the rest. It’s worth to explore <codeclass="docutils literal notranslate"><spanclass="pre">EvTable</span></code> since it can help you create all sorts of nice layouts.</p></li>
</ul>
</section>
</section>
<sectionid="actions">
<h2><spanclass="section-number">9.2. </span>Actions<aclass="headerlink"href="#actions"title="Permalink to this headline">¶</a></h2>
<p>In EvAdventure we will only support a few common combat actions, mapping to the equivalent rolls and checks used in <em>Knave</em>. We will design our combat framework so that it’s easy to expand with other actions later.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">hold</span></code> - The simplest action. You just lean back and do nothing.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">attack</span></code> - You attack a given <codeclass="docutils literal notranslate"><spanclass="pre">target</span></code> using your currently equipped weapon. This will become a roll of STR or WIS against the targets’ ARMOR.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">stunt</span></code> - You make a ‘stunt’, which in roleplaying terms would mean you tripping your opponent, taunting or otherwise trying to gain the upper hand without hurting them. You can do this to give yourself (or an ally) <em>advantage</em> against a <codeclass="docutils literal notranslate"><spanclass="pre">target</span></code> on the next action. You can also give a <codeclass="docutils literal notranslate"><spanclass="pre">target</span></code><em>disadvantage</em> against you or an ally for their next action.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">use</span><spanclass="pre">item</span></code> - You make use of a <codeclass="docutils literal notranslate"><spanclass="pre">Consumable</span></code> in your inventory. When used on yourself, it’d normally be something like a healing potion. If used on an enemy it could be a firebomb or a bottle of acid.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">wield</span></code> - You wield an item. Depending on what is being wielded, it will be wielded in different ways: A helmet will be placed on the head, a piece of armor on the chest. A sword will be wielded in one hand, a shield in another. A two-handed axe will use up two hands. Doing so will move whatever was there previously to the backpack.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">flee</span></code> - You run away/disengage. This action is only applicable in turn-based combat (in twitch-based combat you just move to another room to flee). We will thus wait to define this action until the <aclass="reference internal"href="Beginner-Tutorial-Combat-Turnbased.html"><spanclass="doc std std-doc">Turnbased combat lesson</span></a>.</p></li>
</ul>
</section>
<sectionid="action-dicts">
<h2><spanclass="section-number">9.3. </span>Action dicts<aclass="headerlink"href="#action-dicts"title="Permalink to this headline">¶</a></h2>
<p>To pass around the details of an attack (the second point above), we will use a <codeclass="docutils literal notranslate"><spanclass="pre">dict</span></code>. A <codeclass="docutils literal notranslate"><spanclass="pre">dict</span></code> is simple and also easy to save in an <codeclass="docutils literal notranslate"><spanclass="pre">Attribute</span></code>. We’ll call this the <codeclass="docutils literal notranslate"><spanclass="pre">action_dict</span></code> and here’s what we need for each action.</p>
<blockquote>
<div><p>You don’t need to type these out anywhere, it’s listed here for reference. We will use these dicts when calling <codeclass="docutils literal notranslate"><spanclass="pre">combathandler.queue_action(combatant,</span><spanclass="pre">action_dict)</span></code>.</p>
<spanclass="s2">"recipient"</span><spanclass="p">:</span><spanclass="o"><</span><spanclass="n">Character</span><spanclass="o">/</span><spanclass="n">NPC</span><spanclass="o">></span><spanclass="p">,</span><spanclass="c1"># who gains advantage/disadvantage</span>
<spanclass="s2">"target"</span><spanclass="p">:</span><spanclass="o"><</span><spanclass="n">Character</span><spanclass="o">/</span><spanclass="n">NPC</span><spanclass="o">></span><spanclass="p">,</span><spanclass="c1"># who the recipient gainst adv/dis against</span>
<spanclass="s2">"advantage"</span><spanclass="p">:</span><spanclass="nb">bool</span><spanclass="p">,</span><spanclass="c1"># grant advantage or disadvantage?</span>
<spanclass="s2">"stunt_type"</span><spanclass="p">:</span><spanclass="n">Ability</span><spanclass="p">,</span><spanclass="c1"># Ability to use for the challenge</span>
<spanclass="s2">"defense_type"</span><spanclass="p">:</span><spanclass="n">Ability</span><spanclass="p">,</span><spanclass="c1"># what Ability for recipient to defend with if we</span>
<spanclass="c1"># are trying to give disadvantage </span>
<spanclass="s2">"target"</span><spanclass="p">:</span><spanclass="o"><</span><spanclass="n">Character</span><spanclass="o">/</span><spanclass="n">NPC</span><spanclass="o">/</span><spanclass="kc">None</span><spanclass="o">></span><spanclass="c1"># if using item against someone else </span>
<p>Apart from the <codeclass="docutils literal notranslate"><spanclass="pre">stunt</span></code> action, these dicts are all pretty simple. The <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code> identifes the action to perform and the other fields identifies the minimum things you need to know in order to resolve each action.</p>
<p>We have not yet written the code to set these dicts, but we will assume that we know who is performing each of these actions. So if <codeclass="docutils literal notranslate"><spanclass="pre">Beowulf</span></code> attacks <codeclass="docutils literal notranslate"><spanclass="pre">Grendel</span></code>, Beowulf is not himself included in the attack dict:</p>
<p>Let’s explain the longest action dict, the <codeclass="docutils literal notranslate"><spanclass="pre">Stunt</span></code> action dict in more detail as well. In this example, The <codeclass="docutils literal notranslate"><spanclass="pre">Trickster</span></code> is performing a <em>Stunt</em> in order to help his friend <codeclass="docutils literal notranslate"><spanclass="pre">Paladin</span></code> to gain an INT- <em>advantage</em> against the <codeclass="docutils literal notranslate"><spanclass="pre">Goblin</span></code> (maybe the paladin is preparing to cast a spell of something). Since <codeclass="docutils literal notranslate"><spanclass="pre">Trickster</span></code> is doing the action, he’s not showing up in the dict:</p>
<p>In EvAdventure, we’ll always set <codeclass="docutils literal notranslate"><spanclass="pre">stunt_type</span><spanclass="pre">==</span><spanclass="pre">defense_type</span></code> for simplicity. But you could also consider mixing things up so you could use DEX to confuse someone and give them INT disadvantage, for example.</p>
</aside>
<p>This should result in an INT vs INT based check between the <codeclass="docutils literal notranslate"><spanclass="pre">Trickster</span></code> and the <codeclass="docutils literal notranslate"><spanclass="pre">Goblin</span></code> (maybe the trickster is trying to confuse the goblin with some clever word play). If the <codeclass="docutils literal notranslate"><spanclass="pre">Trickster</span></code> wins, the <codeclass="docutils literal notranslate"><spanclass="pre">Paladin</span></code> gains advantage against the Goblin on the <codeclass="docutils literal notranslate"><spanclass="pre">Paladin</span></code>’s next action .</p>
</section>
<sectionid="action-classes">
<h2><spanclass="section-number">9.4. </span>Action classes<aclass="headerlink"href="#action-classes"title="Permalink to this headline">¶</a></h2>
<p>Once our <codeclass="docutils literal notranslate"><spanclass="pre">action_dict</span></code> identifies the particular action we should use, we need something that reads those keys/values and actually <em>performs</em> the action.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<p>We will create a new instance of this class <em>every time an action is happening</em>. So we store some key things every action will need - we will need a reference to the common <codeclass="docutils literal notranslate"><spanclass="pre">combathandler</span></code> (which we will design in the next section), and to the <codeclass="docutils literal notranslate"><spanclass="pre">combatant</span></code> (the one performing this action). The <codeclass="docutils literal notranslate"><spanclass="pre">action_dict</span></code> is a dict matching the action we want to perform.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">setattr</span></code> Python standard function assigns the keys/values of the <codeclass="docutils literal notranslate"><spanclass="pre">action_dict</span></code> to be properties “on” this action. This is very convenient to use in other methods. So for the <codeclass="docutils literal notranslate"><spanclass="pre">stunt</span></code> action, other methods could just access <codeclass="docutils literal notranslate"><spanclass="pre">self.key</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">self.recipient</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">self.target</span></code> and so on directly.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<spanclass="w"></span><spanclass="sd">"""Called after `execute`"""</span>
<spanclass="k">pass</span>
</pre></div>
</div>
<p>It’s <em>very</em> common to want to send messages to everyone in combat - you need to tell people they are getting attacked, if they get hurt and so on. So having a <codeclass="docutils literal notranslate"><spanclass="pre">msg</span></code> helper method on the action is convenient. We offload all the complexity to the combathandler.msg() method.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">can_use</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">execute</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">post_execute</span></code> should all be called in a chain and we should make sure the <codeclass="docutils literal notranslate"><spanclass="pre">combathandler</span></code> calls them like this:</p>
<p>Holding does nothing but it’s cleaner to nevertheless have a separate class for it. We use the docstring to specify how its action-dict should look.</p>
</section>
<sectionid="attack-action">
<h3><spanclass="section-number">9.4.2. </span>Attack Action<aclass="headerlink"href="#attack-action"title="Permalink to this headline">¶</a></h3>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py</span>
<p>Refer to how we <aclass="reference internal"href="Beginner-Tutorial-Objects.html#weapons"><spanclass="std std-doc">designed Evadventure weapons</span></a> to understand what happens here - most of the work is performed by the weapon class - we just plug in the relevant arguments.</p>
</section>
<sectionid="stunt-action">
<h3><spanclass="section-number">9.4.3. </span>Stunt Action<aclass="headerlink"href="#stunt-action"title="Permalink to this headline">¶</a></h3>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<spanclass="n">recipient</span><spanclass="o">=</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">recipient</span><spanclass="c1"># the one to receive the effect of the stunt</span>
<spanclass="n">target</span><spanclass="o">=</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">target</span><spanclass="c1"># the affected by the stunt (can be the same as recipient/combatant)</span>
<spanclass="sa">f</span><spanclass="s2">"to gain </span><spanclass="si">{</span><spanclass="s1">'advantage'</span><spanclass="w"></span><spanclass="k">if</span><spanclass="w"></span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">advantage</span><spanclass="w"></span><spanclass="k">else</span><spanclass="w"></span><spanclass="s1">'disadvantage'</span><spanclass="si">}</span><spanclass="s2">"</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"$You(</span><spanclass="si">{</span><spanclass="n">defender</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2">) $conj(resist)! $You() $conj(fail) the stunt."</span><spanclass="p">)</span>
</pre></div>
</div>
<p>The main action here is the call to the <codeclass="docutils literal notranslate"><spanclass="pre">rules.dice.opposed_saving_throw</span></code> to determine if the stunt succeeds. After that, most lines is about figuring out who should be given advantage/disadvantage and to communicate the result to the affected parties.</p>
<p>Note that we make heavy use of the helper methods on the <codeclass="docutils literal notranslate"><spanclass="pre">combathandler</span></code> here, even those that are not yet implemented. As long as we pass the <codeclass="docutils literal notranslate"><spanclass="pre">action_dict</span></code> into the <codeclass="docutils literal notranslate"><spanclass="pre">combathandler</span></code>, the action doesn’t actually care what happens next.</p>
<p>After we have performed a successful stunt, we queue the <codeclass="docutils literal notranslate"><spanclass="pre">combathandler.fallback_action_dict</span></code>. This is because stunts are meant to be one-off things are if we are repeating actions, it would not make sense to repeat the stunt over and over.</p>
</section>
<sectionid="use-item-action">
<h3><spanclass="section-number">9.4.4. </span>Use Item Action<aclass="headerlink"href="#use-item-action"title="Permalink to this headline">¶</a></h3>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<spanclass="sd"> Use an item in combat. This is meant for one-off or limited-use items (so things like scrolls and potions, not swords and shields). If this is some sort of weapon or spell rune, we refer to the item to determine what to use for attack/defense rolls.</span>
<p>See the <aclass="reference internal"href="Beginner-Tutorial-Objects.html"><spanclass="doc std std-doc">Consumable items in the Object lesson</span></a> to see how consumables work. Like with weapons, we offload all the logic to the item we use.</p>
</section>
<sectionid="wield-action">
<h3><spanclass="section-number">9.4.5. </span>Wield Action<aclass="headerlink"href="#wield-action"title="Permalink to this headline">¶</a></h3>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/combat_base.py </span>
<p>We rely on the <aclass="reference internal"href="Beginner-Tutorial-Equipment.html"><spanclass="doc std std-doc">Equipment handler</span></a> we created to handle the swapping of items for us. Since it doesn’t make sense to keep swapping over and over, we queue the fallback action after this one.</p>
</section>
</section>
<sectionid="testing">
<h2><spanclass="section-number">9.5. </span>Testing<aclass="headerlink"href="#testing"title="Permalink to this headline">¶</a></h2>
<blockquote>
<div><p>Create a module <codeclass="docutils literal notranslate"><spanclass="pre">evadventure/tests/test_combat.py</span></code>.</p>
</div></blockquote>
<asideclass="sidebar">
<p>See <aclass="reference internal"href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_combat.html#evennia-contrib-tutorials-evadventure-tests-test-combat"><spanclass="std std-ref">evennia/contrib/tutorials/evadventure/tests/test_combat.py</span></a> for ready-made combat unit tests.</p>
</aside>
<p>Unit testing the combat base classes can seem impossible because we have not yet implemented most of it. We can however get very far by the use of <aclass="reference external"href="https://docs.python.org/3/library/unittest.mock.html">Mocks</a>. The idea of a Mock is that you <em>replace</em> a piece of code with a dummy object (a ‘mock’) that can be called to return some specific value.</p>
<p>For example, consider this following test of the <codeclass="docutils literal notranslate"><spanclass="pre">CombatHandler.get_combat_summary</span></code>. We can’t just call this because it internally calls <codeclass="docutils literal notranslate"><spanclass="pre">.get_sides</span></code> which would raise a <codeclass="docutils literal notranslate"><spanclass="pre">NotImplementedError</span></code>.</p>
<spanclass="s2">" testmonster (Perfect) vs testchar (Perfect)"</span>
<spanclass="p">)</span>
</pre></div></td></tr></table></div>
</div>
<p>The interesting places are where we apply the mocks:</p>
<ulclass="simple">
<li><p><strong>Line 25</strong> and <strong>Line 32</strong>: While <codeclass="docutils literal notranslate"><spanclass="pre">get_sides</span></code> is not implemented yet, we know what it is <em>supposed</em> to return - a tuple of lists. So for the sake of the test, we <em>replace</em> the <codeclass="docutils literal notranslate"><spanclass="pre">get_sides</span></code> method with a mock that when called will return something useful.</p></li>
</ul>
<p>With this kind of approach it’s possible to fully test a system also when it’s not ‘complete’ yet.</p>
</section>
<sectionid="conclusions">
<h2><spanclass="section-number">9.6. </span>Conclusions<aclass="headerlink"href="#conclusions"title="Permalink to this headline">¶</a></h2>
<p>We have the core functionality we need for our combat system! In the following two lessons we will make use of these building blocks to create two styles of combat.</p>