<h1><spanclass="section-number">7. </span>In-game Rooms<aclass="headerlink"href="#in-game-rooms"title="Permalink to this headline">¶</a></h1>
<p>A <em>room</em> describes a specific location in the game world. Being an abstract concept, it can represent any area of game content that is convenient to group together. In this lesson we will also create a small in-game automap.</p>
<p>In EvAdventure, we will have two main types of rooms:</p>
<ulclass="simple">
<li><p>Normal, above-ground rooms. Based on a fixed map, these will be created once and then don’t change. We’ll cover them in this lesson.</p></li>
<li><p>Dungeon rooms - these will be examples of <em>procedurally generated</em> rooms, created on the fly as the players explore the underworld. Being subclasses of the normal room, we’ll get to them in the <aclass="reference internal"href="Beginner-Tutorial-Dungeon.html"><spanclass="doc std std-doc">Dungeon generation lesson</span></a>.</p></li>
</ul>
<sectionid="the-base-room">
<h2><spanclass="section-number">7.1. </span>The base room<aclass="headerlink"href="#the-base-room"title="Permalink to this headline">¶</a></h2>
<blockquote>
<div><p>Create a new module <codeclass="docutils literal notranslate"><spanclass="pre">evadventure/rooms.py</span></code>.</p>
</div></blockquote>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/rooms.py</span>
<p>Our <codeclass="docutils literal notranslate"><spanclass="pre">EvadventureRoom</span></code> is very simple. We use Evennia’s <codeclass="docutils literal notranslate"><spanclass="pre">DefaultRoom</span></code> as a base and just add three additional Attributes that defines</p>
<ulclass="simple">
<li><p>If combat is allowed to start in the room at all.</p></li>
<li><p>If combat is allowed, if PvP (player vs player) combat is allowed.</p></li>
<li><p>If combat is allowed, if any side is allowed to die from it.</p></li>
</ul>
<p>Later on we must make sure our combat systems honors these values.</p>
</section>
<sectionid="pvp-room">
<h2><spanclass="section-number">7.2. </span>PvP room<aclass="headerlink"href="#pvp-room"title="Permalink to this headline">¶</a></h2>
<p>Here’s a room that allows non-lethal PvP (sparring):</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/rooms.py</span>
<spanclass="sd"> Customize footer of description.</span>
<spanclass="sd">"""</span>
<spanclass="k">return</span><spanclass="s2">"|yNon-lethal PvP combat is allowed here!|n"</span>
</pre></div>
</div>
<p>The return of <codeclass="docutils literal notranslate"><spanclass="pre">get_display_footer</span></code> will show after the <aclass="reference internal"href="../../../Components/Objects.html#changing-an-objects-appearance"><spanclass="std std-doc">main room description</span></a>, showing that the room is a sparring room. This means that when a player drops to 0 HP, they will lose the combat, but don’t stand any risk of dying (weapons wear out normally during sparring though).</p>
</section>
<sectionid="adding-a-room-map">
<h2><spanclass="section-number">7.3. </span>Adding a room map<aclass="headerlink"href="#adding-a-room-map"title="Permalink to this headline">¶</a></h2>
<p>We want a dynamic map that visualizes the exits you can use at any moment. Here’s how our room will display:</p>
<p>The string returned from <codeclass="docutils literal notranslate"><spanclass="pre">get_display_header</span></code> will end up at the top of the <spanclass="xref myst">room description</span>, a good place to have the map appear!</p>
<ulclass="simple">
<li><p><strong>Line 12</strong>: The map itself consists of the 2D matrix <codeclass="docutils literal notranslate"><spanclass="pre">_MAP_GRID</span></code>. This is a 2D area described by a list of Python lists. To find a given place in the list, you first first need to find which of the nested lists to use, and then which element to use in that list. Indices start from 0 in Python. So to draw the <codeclass="docutils literal notranslate"><spanclass="pre">o</span></code> symbol for the southermost room, you’d need to do so at <codeclass="docutils literal notranslate"><spanclass="pre">_MAP_GRID[4][2]</span></code>.</p></li>
<li><p><strong>Line 19</strong>: The <codeclass="docutils literal notranslate"><spanclass="pre">_EXIT_GRID_SHIFT</span></code> indicates the direction to go for each cardinal exit, along with the map symbol to draw at that point. So <codeclass="docutils literal notranslate"><spanclass="pre">"east":</span><spanclass="pre">(1,</span><spanclass="pre">0,</span><spanclass="pre">"-")</span></code> means the east exit will be drawn one step in the positive x direction (to the right), using the “-” symbol. For symbols like <codeclass="docutils literal notranslate"><spanclass="pre">|</span></code> and “\” we need to escape with a double-symbol since these would otherwise be interpreted as part of other formatting.</p></li>
<li><p><strong>Line 51</strong>: We start by making a <codeclass="docutils literal notranslate"><spanclass="pre">deepcopy</span></code> of the <codeclass="docutils literal notranslate"><spanclass="pre">_MAP_GRID</span></code>. This is so that we don’t modify the original but always have an empty template to work from.</p></li>
<li><p><strong>Line 52</strong>: We use <codeclass="docutils literal notranslate"><spanclass="pre">@</span></code> to indicate the location of the player (at coordinate <codeclass="docutils literal notranslate"><spanclass="pre">(2,</span><spanclass="pre">2)</span></code>). We then take the actual exits from the room use their names to figure out what symbols to draw out from the center.</p></li>
<li><p><strong>Line 58</strong>: We want to be able to get on/off the grid if so needed. So if a room has a non-cardinal exit in it (like ‘back’ or up/down), we’ll indicate this by showing the <codeclass="docutils literal notranslate"><spanclass="pre">></span></code> symbol instead of the <codeclass="docutils literal notranslate"><spanclass="pre">@</span></code> in your current room.</p></li>
<li><p><strong>Line 67</strong>: Once we have placed all the exit- and room-symbols in the grid, we merge it all together into a single string. At the end we use Python’s standard <aclass="reference external"href="https://www.w3schools.com/python/ref_string_join.asp">join</a> to convert the grid into a single string. In doing so we must flip the grid upside down (reverse the outermost list). Why is this? If you think about how a MUD game displays its data - by printing at the bottom and then scrolling upwards - you’ll realize that Evennia has to send out the top of your map <em>first</em> and the bottom of it <em>last</em> for it to show correctly to the user.</p></li>
</ul>
</section>
<sectionid="adding-life-to-a-room">
<h2><spanclass="section-number">7.4. </span>Adding life to a room<aclass="headerlink"href="#adding-life-to-a-room"title="Permalink to this headline">¶</a></h2>
<p>Normally the room is static until you do something in it. But let’s say you are in a room described to be a bustling market. Would it not be nice to occasionally get some random messages like</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>"You hear a merchant calling out his wares."
"The sound of music drifts over the square from an open tavern door."
"The sound of commerse rises and fall in a steady rythm."
</pre></div>
</div>
<p>Here’s an example of how to accomplish this:</p>
<p>The <aclass="reference internal"href="../../../Components/TickerHandler.html"><spanclass="doc std std-doc">TickerHandler</span></a>. This is acts as a ‘please tick me - subscription service’. In <strong>Line 22</strong> we tell add our <codeclass="docutils literal notranslate"><spanclass="pre">.send_echo</span></code> method to the handler and tell the TickerHandler to call that method every <codeclass="docutils literal notranslate"><spanclass="pre">.echo_rate</span></code> seconds.</p>
<p>When the <codeclass="docutils literal notranslate"><spanclass="pre">.send_echo</span></code> method is called, it will use <codeclass="docutils literal notranslate"><spanclass="pre">random.random()</span></code> to check if we should <em>actually</em> do anything. In our example we only show a message 10% of the time. In that case we use Python’s <codeclass="docutils literal notranslate"><spanclass="pre">random.choice()</span></code> to grab a random text string from the <codeclass="docutils literal notranslate"><spanclass="pre">.echoes</span></code> list to send to everyone inside this room.</p>
> set here/echoes = ["You hear a merchant shouting", "You hear the clatter of coins"]
> py here.start_echo()
</pre></div>
</div>
<p>If you wait a while you’ll eventually see one of the two echoes show up. Use <codeclass="docutils literal notranslate"><spanclass="pre">py</span><spanclass="pre">here.stop_echo()</span></code> if you want.</p>
<p>It’s a good idea to be able to turn on/off the echoes at will, if nothing else because you’d be surprised how annoying they can be if they show too often.</p>
<p>In this example we had to resort to <codeclass="docutils literal notranslate"><spanclass="pre">py</span></code> to activate/deactivate the echoes, but you could very easily make little utility <aclass="reference internal"href="../Part1/Beginner-Tutorial-Adding-Commands.html"><spanclass="doc std std-doc">Commands</span></a><codeclass="docutils literal notranslate"><spanclass="pre">startecho</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">stopecho</span></code> to do it for you. This we leave as a bonus exercise.</p>
</section>
<sectionid="testing">
<h2><spanclass="section-number">7.5. </span>Testing<aclass="headerlink"href="#testing"title="Permalink to this headline">¶</a></h2>
<blockquote>
<div><p>Create a new module <codeclass="docutils literal notranslate"><spanclass="pre">evadventure/tests/test_rooms.py</span></code>.</p>
</div></blockquote>
<asideclass="sidebar">
<p>You can find a ready testing module <aclass="reference internal"href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_rooms.html#evennia-contrib-tutorials-evadventure-tests-test-rooms"><spanclass="std std-ref">here in the tutorial folder</span></a>.</p>
</aside>
<p>The main thing to test with our new rooms is the map. Here’s the basic principle for how to do this testing:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in evadventure/tests/test_rooms.py</span>
<spanclass="c1"># compare the desc we got with the expected description here</span>
</pre></div>
</div>
<p>So we create a bunch of rooms, link them to one centr room and then make sure the map in that room looks like we’d expect.</p>
</section>
<sectionid="conclusion">
<h2><spanclass="section-number">7.6. </span>Conclusion<aclass="headerlink"href="#conclusion"title="Permalink to this headline">¶</a></h2>
<p>In this lesson we manipulated strings and made a map. Changing the description of an object is a big part of changing the ‘graphics’ of a text-based game, so checking out the <spanclass="xref myst">parts making up an object description</span> is good extra reading.</p>