<h1><spanclass="section-number">4. </span>In-game Objects and items<aclass="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>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">size</span></code> - this is how many ‘slots’ the item uses in the character’s inventory.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">value</span></code> - a base value if we want to sell or buy the item.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="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><codeclass="docutils literal notranslate"><spanclass="pre">obj_type</span></code> - Which ‘type’ of item this is.</p></li>
</ul>
<sectionid="new-enums">
<h2><spanclass="section-number">4.1. </span>New Enums<aclass="headerlink"href="#new-enums"title="Permalink to this headline">¶</a></h2>
<p>We added a few enumberations for Abilities back in the <aclass="reference internal"href="Beginner-Tutorial-Utilities.html"><spanclass="doc std std-doc">Utilities tutorial</span></a>.
Before we continue, let’s expand with enums for use-slots and object types.</p>
<p>Once we have these enums, we will use them for referencing things.</p>
</section>
<sectionid="the-base-object">
<h2><spanclass="section-number">4.2. </span>The base object<aclass="headerlink"href="#the-base-object"title="Permalink to this headline">¶</a></h2>
<blockquote>
<div><p>Create a new module <codeclass="docutils literal notranslate"><spanclass="pre">mygame/evadventure/objects.py</span></code></p>
</div></blockquote>
<asideclass="sidebar">
<p><aclass="reference internal"href="../../../api/evennia.contrib.tutorials.evadventure.objects.html"><spanclass="doc std std-doc">evennia/contrib/tutorials/evadventure/objects.py</span></a> has
a full set of objects implemented.</p>
</aside>
<divstyle="clear: right;"></div>
<p>We will make a base <codeclass="docutils literal notranslate"><spanclass="pre">EvAdventureObject</span></code> class off Evennia’s standard <codeclass="docutils literal notranslate"><spanclass="pre">DefaultObject</span></code>. We will then add child classes to represent the relevant types:</p>
<spanclass="w"></span><spanclass="sd">"""Get any help text for this item"""</span>
<spanclass="k">return</span><spanclass="s2">"No help for this item"</span>
</pre></div>
</div>
<sectionid="using-attributes-or-not">
<h3><spanclass="section-number">4.2.1. </span>Using Attributes or not<aclass="headerlink"href="#using-attributes-or-not"title="Permalink to this headline">¶</a></h3>
<p>In theory, <codeclass="docutils literal notranslate"><spanclass="pre">size</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">value</span></code> does not change and <em>could</em> also be just set as a regular Python
<p>The problem with this is that if we want to make a new object of <codeclass="docutils literal notranslate"><spanclass="pre">size</span><spanclass="pre">3</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">value</span><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">AttributeProperties</span></code>, we can set <codeclass="docutils literal notranslate"><spanclass="pre">size</span></code> and <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">autocreate=False</span></code>. Normally when you create a new object with defined <codeclass="docutils literal notranslate"><spanclass="pre">AttributeProperties</span></code>, a matching <codeclass="docutils literal notranslate"><spanclass="pre">Attribute</span></code> is immediately created at the same time. So normally, the object would be created along with two Attributes <codeclass="docutils literal notranslate"><spanclass="pre">size</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">value</span></code>. With <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">size=1</span></code> no database <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">obj.db.size</span></code> or <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">size=1</span></code>, since most objects would not yet have an in-database
<codeclass="docutils literal notranslate"><spanclass="pre">size</span></code> Attribute to search for.</p>
<p>In our case, we’ll only refer to these properties as <codeclass="docutils literal notranslate"><spanclass="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>
<sectionid="creating-tags-in-at-object-creation">
<h3><spanclass="section-number">4.2.2. </span>Creating tags in <codeclass="docutils literal notranslate"><spanclass="pre">at_object_creation</span></code><aclass="headerlink"href="#creating-tags-in-at-object-creation"title="Permalink to this headline">¶</a></h3>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">at_object_creation</span></code> is a method Evennia calls on every child of <codeclass="docutils literal notranslate"><spanclass="pre">DefaultObject</span></code> whenever it is first created.</p>
<p>We do a tricky thing here, converting our <codeclass="docutils literal notranslate"><spanclass="pre">.obj_type</span></code> to one or more <aclass="reference internal"href="../../../Components/Tags.html"><spanclass="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
<p>We allow <codeclass="docutils literal notranslate"><spanclass="pre">.obj_type</span></code> to be given as a single value or a list of values. We use <codeclass="docutils literal notranslate"><spanclass="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>
<sectionid="other-object-types">
<h2><spanclass="section-number">4.3. </span>Other object types<aclass="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>
<h2><spanclass="section-number">4.4. </span>Consumables<aclass="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>
<spanclass="n">user</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You are not close enough to the target!"</span><spanclass="p">)</span>
<spanclass="n">user</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"|w</span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2"> is used up.|n"</span><spanclass="p">)</span>
<spanclass="n">user</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2"> was used up."</span><spanclass="p">)</span>
<p>In <codeclass="docutils literal notranslate"><spanclass="pre">at_pre_use</span></code> we check if we have specified a target (heal someone else or throw a fire bomb at an enemy?), making sure we are in the same location. We also make sure we have <codeclass="docutils literal notranslate"><spanclass="pre">usages</span></code> left. In <codeclass="docutils literal notranslate"><spanclass="pre">at_post_use</span></code> we make sure to tick off usages.</p>
<p>What exactly each consumable does will vary - we will need to implement children of this class later, overriding <codeclass="docutils literal notranslate"><spanclass="pre">at_use</span></code> with different effects.</p>
</section>
<sectionid="weapons">
<h2><spanclass="section-number">4.5. </span>Weapons<aclass="headerlink"href="#weapons"title="Permalink to this headline">¶</a></h2>
<p>All weapons need properties that describe how efficient they are in battle. To ‘use’ a weapon means to attack with it, so we can let the weapon itself handle all logic around performing an attack. Having the attack code on the weapon also means that if we in the future wanted a weapon doing something special on-attack (for example, a vampiric sword that heals the attacker when hurting the enemy), we could easily add that on the weapon subclass in question without modifying other code.</p>
<spanclass="c1"># we assume weapons can only be used in the same location</span>
<spanclass="n">user</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You are not close enough to the target!"</span><spanclass="p">)</span>
<spanclass="n">user</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"</span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">(</span><spanclass="n">user</span><spanclass="p">)</span><spanclass="si">}</span><spanclass="s2"> is broken and can't be used!"</span><spanclass="p">)</span>
<spanclass="n">user</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="sa">f</span><spanclass="s2">"|r</span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">get_display_name</span><spanclass="p">(</span><spanclass="n">user</span><spanclass="p">)</span><spanclass="si">}</span><spanclass="s2"> breaks and can no longer be used!"</span><spanclass="p">)</span>
</pre></div>
</div>
<p>In EvAdventure, we will assume all weapons (including bows etc) are used in the same location as the target. Weapons also have a <codeclass="docutils literal notranslate"><spanclass="pre">quality</span></code> attribute that gets worn down if the user rolls a critical failure. Once quality is down to 0, the weapon is broken and needs to be repaired.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="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. We assume that a <codeclass="docutils literal notranslate"><spanclass="pre">quality</span></code> of <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> means that quality doesn’t apply (that is, the item is unbreakable), so we must consider that when checking.</p>
<p>The attack/defend type tracks how we resolve attacks with the weapon, like <codeclass="docutils literal notranslate"><spanclass="pre">roll</span><spanclass="pre">+</span><spanclass="pre">STR</span><spanclass="pre">vs</span><spanclass="pre">ARMOR</span><spanclass="pre">+</span><spanclass="pre">10</span></code>.</p>
<p>In the <codeclass="docutils literal notranslate"><spanclass="pre">use</span></code> method we make use of the <codeclass="docutils literal notranslate"><spanclass="pre">rules</span></code> module we <aclass="reference internal"href="Beginner-Tutorial-Rules.html"><spanclass="doc std std-doc">created earlier</span></a> to perform all the dice rolls needed to resolve the attack.</p>
<p>This code requires some additional explanation:</p>
<p><codeclass="docutils literal notranslate"><spanclass="pre">location.msg_contents</span></code> sends a message to everyone in <codeclass="docutils literal notranslate"><spanclass="pre">location</span></code>. Since people will usually notice if you swing a sword at somone, this makes sense to tell people about. This message should however look <em>different</em> depending on who sees it.</p>
<p>I should see:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>You attack Grendel with sword: <dice roll results>
</pre></div>
</div>
<p>Others should see</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>Beowulf attacks Grendel with sword: <dice roll results>
</pre></div>
</div>
<p>And Grendel should see</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>Beowulf attacks you with sword: <dice roll results>
</pre></div>
</div>
<p>We provide the following string to <codeclass="docutils literal notranslate"><spanclass="pre">msg_contents</span></code>:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="sa">f</span><spanclass="s2">"$You() $conj(attack) $You(</span><spanclass="si">{</span><spanclass="n">target</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2">) with </span><spanclass="si">{</span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">key</span><spanclass="si">}</span><spanclass="s2">: </span><spanclass="si">{</span><spanclass="n">txt</span><spanclass="si">}</span><spanclass="s2">"</span>
</pre></div>
</div>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">{...}</span></code> are normal f-string formatting markers like those we have used before. The <codeclass="docutils literal notranslate"><spanclass="pre">$func(...)</span></code> bits are <aclass="reference internal"href="../../../Components/FuncParser.html"><spanclass="doc std std-doc">Evennnia FuncParser</span></a> function calls. FuncParser calls are executed as functions and the result replaces their position in the string. As this string is parsed by Evennia, this is what happens:</p>
<p>First the f-string markers are replaced, so that we get this:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="s2">"$You() $cobj(attack) $you(Grendel) with sword: </span><spanclass="se">\n</span><spanclass="s2"> rolled 8 on d20 ..."</span>
</pre></div>
</div>
<p>Next the funcparser functions are run:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">$You()</span></code> becomes the name or <codeclass="docutils literal notranslate"><spanclass="pre">You</span></code> depending on if the string is to be sent to that object or not. It uses the <codeclass="docutils literal notranslate"><spanclass="pre">from_obj=</span></code> kwarg to the <codeclass="docutils literal notranslate"><spanclass="pre">msg_contents</span></code> method to know this. Since <codeclass="docutils literal notranslate"><spanclass="pre">msg_contents=attacker</span></code> , this becomes <codeclass="docutils literal notranslate"><spanclass="pre">You</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">Beowulf</span></code> in this example.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">$you(Grendel)</span></code> looks for the <codeclass="docutils literal notranslate"><spanclass="pre">mapping=</span></code> kwarg to <codeclass="docutils literal notranslate"><spanclass="pre">msg_contents</span></code> to determine who should be addressed here. If will replace this with the display name or the lowercase <codeclass="docutils literal notranslate"><spanclass="pre">you</span></code>. We have added <codeclass="docutils literal notranslate"><spanclass="pre">mapping={target.key:</span><spanclass="pre">target}</span></code> - that is <codeclass="docutils literal notranslate"><spanclass="pre">{"Grendel":</span><spanclass="pre"><grendel_obj>}</span></code>. So this will become <codeclass="docutils literal notranslate"><spanclass="pre">you</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">Grendel</span></code> depending on who sees the string.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">$conj(attack)</span></code><em>conjugates</em> the verb depending on who sees it. The result will be <codeclass="docutils literal notranslate"><spanclass="pre">You</span><spanclass="pre">attack</span><spanclass="pre">...</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">Beowulf</span><spanclass="pre">attacks</span></code> (note the extra <codeclass="docutils literal notranslate"><spanclass="pre">s</span></code>).</p></li>
</ul>
<p>A few funcparser calls compacts all these points of view into one string!</p>
</section>
<sectionid="magic">
<h2><spanclass="section-number">4.6. </span>Magic<aclass="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>
<spanclass="n">inventory_use_slot</span><spanclass="o">=</span><spanclass="n">WieldLocation</span><spanclass="o">.</span><spanclass="n">TWO_HANDS</span><spanclass="c1"># always two hands for magic</span>
<p>We make the rune stone a mix of weapon and consumable. Note that we don’t have to add <codeclass="docutils literal notranslate"><spanclass="pre">.uses</span></code> again, it’s inherited from <codeclass="docutils literal notranslate"><spanclass="pre">EvAdventureConsumable</span></code> parent. The <codeclass="docutils literal notranslate"><spanclass="pre">at_pre_use</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">use</span></code> methods are also inherited; we only override <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="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>
<sectionid="armor">
<h2><spanclass="section-number">4.7. </span>Armor<aclass="headerlink"href="#armor"title="Permalink to this headline">¶</a></h2>
<p>Armor, shields and helmets increase the <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">bonus</span><spanclass="pre">+</span><spanclass="pre">10</span></code>, so the result will be the same - this means we can use <codeclass="docutils literal notranslate"><spanclass="pre">Ability.ARMOR</span></code> as any other defensive ability without worrying about a special case.</p>
<h2><spanclass="section-number">4.8. </span>Your Bare hands<aclass="headerlink"href="#your-bare-hands"title="Permalink to this headline">¶</a></h2>
<p>When we don’t have any weapons, we’ll be using our bare fists to fight.</p>
<p>We will use this in the upcoming <aclass="reference internal"href="Beginner-Tutorial-Equipment.html"><spanclass="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>
<p>Creating a single instance of something that is used everywhere is called to create a <em>Singleton</em>.</p>
</aside>
<p>Since everyone’s empty hands are the same (in our game), we create <em>one</em><codeclass="docutils literal notranslate"><spanclass="pre">Bare</span><spanclass="pre">hands</span></code> weapon object that everyone shares. We do this by searching for the object with <codeclass="docutils literal notranslate"><spanclass="pre">search_object</span></code> (the <codeclass="docutils literal notranslate"><spanclass="pre">.first()</span></code> means we grab the first one even if we should by accident have created multiple hands, see <aclass="reference internal"href="../Part1/Beginner-Tutorial-Django-queries.html"><spanclass="doc std std-doc">The Django querying tutorial</span></a> for more info). If we find none, we create it.</p>
<p>By use of the <codeclass="docutils literal notranslate"><spanclass="pre">global</span></code> Python keyword, we cache the bare hands object get/create in a module level property <codeclass="docutils literal notranslate"><spanclass="pre">_BARE_HANDS</span></code>. So this acts as a cache to not have to search the database more than necessary.</p>
<p>From now on, other modules can just import and run this function to get the bare hands.</p>
</section>
<sectionid="testing-and-extra-credits">
<h2><spanclass="section-number">4.9. </span>Testing and Extra credits<aclass="headerlink"href="#testing-and-extra-credits"title="Permalink to this headline">¶</a></h2>
<p>Remember the <codeclass="docutils literal notranslate"><spanclass="pre">get_obj_stats</span></code> function from the <aclass="reference internal"href="Beginner-Tutorial-Utilities.html"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="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 <codeclass="docutils literal notranslate"><spanclass="pre">get_obj_stats</span></code>.</p>
<p>Try it out yourself. If you need help, a finished utility example is found in <aclass="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"><spanclass="xref myst py py-func">evennia/contrib/tutorials/evadventure/utils.py</span></a>.</p>