evennia/docs/3.x/Howtos/Tutorial-Displaying-Room-Map.html
2023-12-21 00:12:31 +01:00

567 lines
No EOL
66 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>Show a dynamic map of rooms &#8212; Evennia 3.x 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="Changing the Game Website" href="Web-Changing-Webpage.html" />
<link rel="prev" title="Adding room coordinates to your game" href="Tutorial-Coordinates.html" />
</head><body>
<div class="admonition important">
<p class="first admonition-title">Note</p>
<p class="last">You are reading an old version of the Evennia documentation. <a href="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
</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"
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="Web-Changing-Webpage.html" title="Changing the Game Website"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Tutorial-Coordinates.html" title="Adding room coordinates to your game"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 3.x</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" accesskey="U">Tutorials and How-Tos</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Show a dynamic map of rooms</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="#">Show a dynamic map of rooms</a><ul>
<li><a class="reference internal" href="#the-grid-of-rooms">The Grid of Rooms</a></li>
<li><a class="reference internal" href="#concept">Concept</a></li>
<li><a class="reference internal" href="#setting-up-the-map-display">Setting up the Map Display</a></li>
<li><a class="reference internal" href="#building-the-mapper">Building the Mapper</a></li>
<li><a class="reference internal" href="#using-the-map">Using the Map</a></li>
<li><a class="reference internal" href="#final-comments">Final Comments</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Tutorial-Coordinates.html"
title="previous chapter">Adding room coordinates to your game</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Web-Changing-Webpage.html"
title="next chapter">Changing the Game Website</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Howtos/Tutorial-Displaying-Room-Map.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>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="show-a-dynamic-map-of-rooms">
<h1>Show a dynamic map of rooms<a class="headerlink" href="#show-a-dynamic-map-of-rooms" title="Permalink to this headline"></a></h1>
<aside class="sidebar">
<p>See also the <a class="reference internal" href="../Contribs/Contrib-Mapbuilder.html"><span class="doc std std-doc">Mapbuilder</span></a> and <a class="reference internal" href="../Contribs/Contrib-XYZGrid.html"><span class="doc std std-doc">XYZGrid</span></a> contribs, which offer alternative ways of both creating and displaying room maps. The <a class="reference external" href="https://www.evennia.com/docs/latest/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Rooms.html#adding-a-room-map">Beginner Tutorial lesson implementing Evadventure rooms</a> also explains how to add a (simpler) auto-map.</p>
</aside>
<p>An often desired feature in a MUD is to show an in-game map to help navigation.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Forest</span> <span class="n">path</span>
<span class="p">[</span><span class="o">.</span><span class="p">]</span> <span class="p">[</span><span class="o">.</span><span class="p">]</span>
<span class="p">[</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">@</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">]</span>
<span class="p">[</span><span class="o">.</span><span class="p">]</span> <span class="p">[</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">]</span>
<span class="n">The</span> <span class="n">trees</span> <span class="n">are</span> <span class="n">looming</span> <span class="n">over</span> <span class="n">the</span> <span class="n">narrow</span> <span class="n">forest</span> <span class="n">path</span><span class="o">.</span>
<span class="n">Exits</span><span class="p">:</span> <span class="n">East</span><span class="p">,</span> <span class="n">West</span>
</pre></div>
</div>
<section id="the-grid-of-rooms">
<h2>The Grid of Rooms<a class="headerlink" href="#the-grid-of-rooms" title="Permalink to this headline"></a></h2>
<p>There are at least two requirements needed for this tutorial to work.</p>
<ol class="simple">
<li><p>The structure of your mud has to follow a logical layout. Evennia supports the layout of your world to be logically impossible with rooms looping to themselves or exits leading to the other side of the map. Exits can also be named anything, from “jumping out the window” to “into the fifth dimension”. This tutorial assumes you can only move in the cardinal directions (N, E, S and W).</p></li>
<li><p>Rooms must be connected and linked together for the map to be generated correctly. Vanilla Evennia comes with a admin command <a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdTunnel" title="evennia.commands.default.building.CmdTunnel"><span class="xref myst py py-class">tunnel</span></a> that allows a user to create rooms in the cardinal directions, but additional work is needed to assure that rooms are connected. For example, if you <code class="docutils literal notranslate"><span class="pre">tunnel</span> <span class="pre">east</span></code> and then immediately do <code class="docutils literal notranslate"><span class="pre">tunnel</span> <span class="pre">west</span></code> youll find that you have created two completely stand-alone rooms. So care is needed if you want to create a “logical” layout. In this tutorial we assume you have such a grid of rooms that we can generate the map from.</p></li>
</ol>
</section>
<section id="concept">
<h2>Concept<a class="headerlink" href="#concept" title="Permalink to this headline"></a></h2>
<p>Before getting into the code, it is beneficial to understand and conceptualize how this is going to work. The idea is analogous to a worm that starts at your current position. It chooses a direction and walks outward from it, mapping its route as it goes. Once it has traveled a pre-set distance it stops and starts over in another direction. An important note is that we want a system which is easily callable and not too complicated. Therefore we will wrap this entire code into a custom Python class (not a typeclass as this doesnt use any core objects from evennia itself). We are going to create something that displays like this when you type look:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Hallway</span>
<span class="p">[</span><span class="o">.</span><span class="p">]</span> <span class="p">[</span><span class="o">.</span><span class="p">]</span>
<span class="p">[</span><span class="o">@</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">]</span>
<span class="p">[</span><span class="o">.</span><span class="p">]</span> <span class="p">[</span><span class="o">.</span><span class="p">]</span> <span class="p">[</span><span class="o">.</span><span class="p">]</span>
<span class="n">The</span> <span class="n">distant</span> <span class="n">echoes</span> <span class="n">of</span> <span class="n">the</span> <span class="n">forgotten</span>
<span class="n">wail</span> <span class="n">throughout</span> <span class="n">the</span> <span class="n">empty</span> <span class="n">halls</span><span class="o">.</span>
<span class="n">Exits</span><span class="p">:</span> <span class="n">North</span><span class="p">,</span> <span class="n">East</span><span class="p">,</span> <span class="n">South</span>
</pre></div>
</div>
<p>Your current location is defined by <code class="docutils literal notranslate"><span class="pre">[&#64;]</span></code> while the <code class="docutils literal notranslate"><span class="pre">[.]</span></code>s are other rooms that the “worm” has seen
since departing from your location.</p>
</section>
<section id="setting-up-the-map-display">
<h2>Setting up the Map Display<a class="headerlink" href="#setting-up-the-map-display" title="Permalink to this headline"></a></h2>
<p>First we must define the components for displaying the map. For the “worm” to know what symbol to draw on the map we will have it check an Attribute on the room it visits called <code class="docutils literal notranslate"><span class="pre">sector_type</span></code>. For this tutorial we understand two symbols - a normal room and the room with us in it. We also define a fallback symbol for rooms without said Attribute - that way the map will still work even if we didnt prepare the room correctly. Assuming your game folder is named <code class="docutils literal notranslate"><span class="pre">mygame</span></code>, we create this code in <code class="docutils literal notranslate"><span class="pre">mygame/world/map.py.</span></code></p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/world/map.py</span>
<span class="c1"># the symbol is identified with a key &quot;sector_type&quot; on the</span>
<span class="c1"># Room. Keys None and &quot;you&quot; must always exist.</span>
<span class="n">SYMBOLS</span> <span class="o">=</span> <span class="p">{</span> <span class="kc">None</span> <span class="p">:</span> <span class="s1">&#39; . &#39;</span><span class="p">,</span> <span class="c1"># for rooms without sector_type Attribute</span>
<span class="s1">&#39;you&#39;</span> <span class="p">:</span> <span class="s1">&#39;[@]&#39;</span><span class="p">,</span>
<span class="s1">&#39;SECT_INSIDE&#39;</span><span class="p">:</span> <span class="s1">&#39;[.]&#39;</span> <span class="p">}</span>
</pre></div>
</div>
<p>Since trying to access an unset Attribute returns <code class="docutils literal notranslate"><span class="pre">None</span></code>, this means rooms without the <code class="docutils literal notranslate"><span class="pre">sector_type</span></code>
Atttribute will show as <code class="docutils literal notranslate"><span class="pre">.</span></code>. Next we start building the custom class <code class="docutils literal notranslate"><span class="pre">Map</span></code>. It will hold all
methods we need.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/world/map.py</span>
<span class="k">class</span> <span class="nc">Map</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">max_width</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">9</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span> <span class="o">=</span> <span class="n">caller</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_width</span> <span class="o">=</span> <span class="n">max_width</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_length</span> <span class="o">=</span> <span class="n">max_length</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> <span class="kc">None</span>
</pre></div>
</div>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">self.caller</span></code> is normally your Character object, the one using the map.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.max_width/length</span></code> determine the max width and length of the map that will be generated. Note that its important that these variables are set to <em>odd</em> numbers to make sure the display area has a center point.</p></li>
<li><p><code class="docutils literal notranslate"> <span class="pre">self.worm_has_mapped</span></code> is building off the worm analogy above. This dictionary will store all rooms the “worm” has mapped as well as its relative position within the grid. This is the most important variable as it acts as a checker and address book that is able to tell us where the worm has been and what it has mapped so far.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.curX/Y</span></code> are coordinates representing the worms current location on the grid.</p></li>
</ul>
<p>Before any sort of mapping can actually be done we need to create an empty display area and do some sanity checks on it by using the following methods.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/world/map.py</span>
<span class="k">class</span> <span class="nc">Map</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="c1"># [... continued]</span>
<span class="k">def</span> <span class="nf">create_grid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># This method simply creates an empty grid/display area</span>
<span class="c1"># with the specified variables from __init__(self):</span>
<span class="n">board</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_width</span><span class="p">):</span>
<span class="n">board</span><span class="o">.</span><span class="n">append</span><span class="p">([])</span>
<span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_length</span><span class="p">):</span>
<span class="n">board</span><span class="p">[</span><span class="n">row</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">board</span>
<span class="k">def</span> <span class="nf">check_grid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># this method simply checks the grid to make sure</span>
<span class="c1"># that both max_l and max_w are odd numbers.</span>
<span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_length</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_width</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span>\
<span class="k">else</span> <span class="kc">False</span>
</pre></div>
</div>
<p>Before we can set our worm on its way, we need to know some of the computer science behind all this called Graph Traversing. In Pseudo code what we are trying to accomplish is this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># pseudo code</span>
<span class="k">def</span> <span class="nf">draw_room_on_map</span><span class="p">(</span><span class="n">room</span><span class="p">,</span> <span class="n">max_distance</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">room</span><span class="p">)</span>
<span class="k">if</span> <span class="n">max_distance</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_drawn</span><span class="p">(</span><span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">):</span>
<span class="c1"># skip drawing if we already visited the destination</span>
<span class="k">continue</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># first time here!</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw_room_on_map</span><span class="p">(</span><span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">max_distance</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>The beauty of Python is that our actual code of doing this doesnt differ much if at all from this
Pseudo code example.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">max_distance</span></code> is a variable indicating to our Worm how many rooms AWAY from your current location will it map. Obviously the larger the number the more time it will take if your current location has many many rooms around you.</p></li>
</ul>
<p>The first hurdle here is what value to use for max_distance. There is no reason for the worm to travel further than what is actually displayed to you. For example, if your current location is placed in the center of a display area of size <code class="docutils literal notranslate"><span class="pre">max_length</span> <span class="pre">=</span> <span class="pre">max_width</span> <span class="pre">=</span> <span class="pre">9</span></code>, then the worm need only
go <code class="docutils literal notranslate"><span class="pre">4</span></code> spaces in either direction:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">@</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">][</span><span class="o">.</span><span class="p">]</span>
<span class="mi">4</span> <span class="mi">3</span> <span class="mi">2</span> <span class="mi">1</span> <span class="mi">0</span> <span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">max_distance</span></code> can be set dynamically based on the size of the display area. As your width/length changes it becomes a simple algebraic linear relationship which is simply <code class="docutils literal notranslate"><span class="pre">max_distance</span> <span class="pre">=</span> <span class="pre">(min(max_width,</span> <span class="pre">max_length)</span> <span class="pre">-1)</span> <span class="pre">/</span> <span class="pre">2</span></code>.</p>
</section>
<section id="building-the-mapper">
<h2>Building the Mapper<a class="headerlink" href="#building-the-mapper" title="Permalink to this headline"></a></h2>
<p>Now we can start to fill our Map object with some methods. We are still missing a few methods that are very important:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">self.draw(self,</span> <span class="pre">room)</span></code> - responsible for actually drawing room to grid.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.has_drawn(self,</span> <span class="pre">room)</span></code> - checks to see if the room has been mapped and worm has already been here.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.median(self,</span> <span class="pre">number)</span></code> - a simple utility method that finds the median (middle point) from <code class="docutils literal notranslate"><span class="pre">0,</span> <span class="pre">n</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.update_pos(self,</span> <span class="pre">room,</span> <span class="pre">exit_name)</span></code> - updates the worms physical position by reassigning <code class="docutils literal notranslate"><span class="pre">self.curX/Y</span></code> accordingly.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.start_loc_on_grid(self)</span></code> - the very first initial draw on the grid representing your location in the middle of the grid.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.show_map</span></code> - after everything is done convert the map into a readable string</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.draw_room_on_map(self,</span> <span class="pre">room,</span> <span class="pre">max_distance)</span></code> - the main method that ties it all together.</p></li>
</ul>
<p>Now that we know which methods we need, lets refine our initial <code class="docutils literal notranslate"><span class="pre">__init__(self)</span></code> to pass some
conditional statements and set it up to start building the display.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1">#mygame/world/map.py</span>
<span class="k">class</span> <span class="nc">Map</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">max_width</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">9</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span> <span class="o">=</span> <span class="n">caller</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_width</span> <span class="o">=</span> <span class="n">max_width</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_length</span> <span class="o">=</span> <span class="n">max_length</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_grid</span><span class="p">():</span>
<span class="c1"># we have to store the grid into a variable</span>
<span class="bp">self</span><span class="o">.</span><span class="n">grid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_grid</span><span class="p">()</span>
<span class="c1"># we use the algebraic relationship</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw_room_on_map</span><span class="p">(</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="p">,</span>
<span class="p">((</span><span class="nb">min</span><span class="p">(</span><span class="n">max_width</span><span class="p">,</span> <span class="n">max_length</span><span class="p">)</span> <span class="o">-</span><span class="mi">1</span> <span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span>
</pre></div>
</div>
<p>Here we check to see if the parameters for the grid are okay, then we create an empty canvas and map our initial location as the first room!</p>
<p>As mentioned above, the code for the <code class="docutils literal notranslate"><span class="pre">self.draw_room_on_map()</span></code> is not much different than the Pseudo code. The method is shown below:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/world/map.py, in the Map class</span>
<span class="k">def</span> <span class="nf">draw_room_on_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">max_distance</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">room</span><span class="p">)</span>
<span class="k">if</span> <span class="n">max_distance</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;north&quot;</span><span class="p">,</span> <span class="s2">&quot;east&quot;</span><span class="p">,</span> <span class="s2">&quot;west&quot;</span><span class="p">,</span> <span class="s2">&quot;south&quot;</span><span class="p">):</span>
<span class="c1"># we only map in the cardinal directions. Mapping up/down would be</span>
<span class="c1"># an interesting learning project for someone who wanted to try it.</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_drawn</span><span class="p">(</span><span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">):</span>
<span class="c1"># we&#39;ve been to the destination already, skip ahead.</span>
<span class="k">continue</span>
<span class="bp">self</span><span class="o">.</span><span class="n">update_pos</span><span class="p">(</span><span class="n">room</span><span class="p">,</span> <span class="n">exit</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw_room_on_map</span><span class="p">(</span><span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">max_distance</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>The first thing the “worm” does is to draw your current location in <code class="docutils literal notranslate"><span class="pre">self.draw</span></code>. Lets define that…</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1">#in mygame/word/map.py, in the Map class</span>
<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="c1"># draw initial ch location on map first!</span>
<span class="k">if</span> <span class="n">room</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_loc_on_grid</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># map all other rooms</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span><span class="p">]</span>
<span class="c1"># this will use the sector_type Attribute or None if not set.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">grid</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">][</span><span class="bp">self</span><span class="o">.</span><span class="n">curY</span><span class="p">]</span> <span class="o">=</span> <span class="n">SYMBOLS</span><span class="p">[</span><span class="n">room</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sector_type</span><span class="p">]</span>
</pre></div>
</div>
<p>In <code class="docutils literal notranslate"><span class="pre">self.start_loc_on_grid()</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">median</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">num</span><span class="p">):</span>
<span class="n">lst</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">num</span><span class="p">))</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">n</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">return</span> <span class="p">(</span><span class="n">lst</span><span class="p">[</span><span class="n">n</span><span class="o">//</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">lst</span><span class="p">[</span><span class="n">m</span><span class="o">//</span><span class="mi">2</span><span class="p">])</span> <span class="o">/</span> <span class="mf">2.0</span>
<span class="k">def</span> <span class="nf">start_loc_on_grid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">median</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_width</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">median</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_length</span><span class="p">)</span>
<span class="c1"># x and y are floats by default, can&#39;t index lists with float types</span>
<span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">grid</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">SYMBOLS</span><span class="p">[</span><span class="s1">&#39;you&#39;</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="c1"># updating worms current location</span>
</pre></div>
</div>
<p>After the system has drawn the current map it checks to see if the <code class="docutils literal notranslate"><span class="pre">max_distance</span></code> is <code class="docutils literal notranslate"><span class="pre">0</span></code> (since this
is the inital start phase it is not). Now we handle the iteration once we have each individual exit
in the room. The first thing it does is check if the room the Worm is in has been mapped already…
lets define that…</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">has_drawn</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">room</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span> <span class="k">else</span> <span class="kc">False</span>
</pre></div>
</div>
<p>If <code class="docutils literal notranslate"><span class="pre">has_drawn</span></code> returns <code class="docutils literal notranslate"><span class="pre">False</span></code> that means the worm has found a room that hasnt been mapped yet. It
will then move there. The self.curX/Y sort of lags behind, so we have to make sure to track the
position of the worm; we do this in <code class="docutils literal notranslate"><span class="pre">self.update_pos()</span></code> below.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">update_pos</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">exit_name</span><span class="p">):</span>
<span class="c1"># this ensures the coordinates stays up to date</span>
<span class="c1"># to where the worm is currently at.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> \
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="c1"># now we have to actually move the pointer</span>
<span class="c1"># variables depending on which &#39;exit&#39; it found</span>
<span class="k">if</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;east&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;west&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;north&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;south&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">+=</span> <span class="mi">1</span>
</pre></div>
</div>
<p>Once the system updates the position of the worm it feeds the new room back into the original
<code class="docutils literal notranslate"><span class="pre">draw_room_on_map()</span></code> and starts the process all over again…</p>
<p>That is essentially the entire thing. The final method is to bring it all together and make a nice
presentational string out of it using the <code class="docutils literal notranslate"><span class="pre">self.show_map()</span></code> method.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">show_map</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">map_string</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">grid</span><span class="p">:</span>
<span class="n">map_string</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
<span class="n">map_string</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="k">return</span> <span class="n">map_string</span>
</pre></div>
</div>
</section>
<section id="using-the-map">
<h2>Using the Map<a class="headerlink" href="#using-the-map" title="Permalink to this headline"></a></h2>
<p>In order for the map to get triggered we store it on the Room typeclass. If we put it in
<code class="docutils literal notranslate"><span class="pre">return_appearance</span></code> we will get the map back every time we look at the room.</p>
<blockquote>
<div><p><code class="docutils literal notranslate"><span class="pre">return_appearance</span></code> is a default Evennia hook available on all objects; it is called e.g. by the
<code class="docutils literal notranslate"><span class="pre">look</span></code> command to get the description of something (the room in this case).</p>
</div></blockquote>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/rooms.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultRoom</span>
<span class="kn">from</span> <span class="nn">world.map</span> <span class="kn">import</span> <span class="n">Map</span>
<span class="k">class</span> <span class="nc">Room</span><span class="p">(</span><span class="n">DefaultRoom</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">return_appearance</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looker</span><span class="p">):</span>
<span class="c1"># [...]</span>
<span class="n">string</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">Map</span><span class="p">(</span><span class="n">looker</span><span class="p">)</span><span class="o">.</span><span class="n">show_map</span><span class="p">()</span><span class="si">}</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="c1"># Add all the normal stuff like room description,</span>
<span class="c1"># contents, exits etc.</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">return_appearance</span><span class="p">(</span><span class="n">looker</span><span class="p">)</span>
<span class="k">return</span> <span class="n">string</span>
</pre></div>
</div>
<p>Obviously this method of generating maps doesnt take into account of any doors or exits that are hidden… etc… but hopefully it serves as a good base to start with. Like previously mentioned, it is very important to have a solid foundation on rooms before implementing this. You can try this on vanilla evennia by using &#64;tunnel and essentially you can just create a long straight/edgy non- looping rooms that will show on your in-game map.</p>
<p>The above example will display the map above the room description. You could also use an <a class="reference external" href="https://github.com/evennia/evennia/blob/main/evennia.utils.evtable">EvTable</a> to place description and map next to each other. Some other things you can do is to have a <a class="reference internal" href="../Components/Commands.html"><span class="doc std std-doc">Command</span></a> that displays with a larger radius, maybe with a legend and other features.</p>
<p>Below is the whole <code class="docutils literal notranslate"><span class="pre">map.py</span></code> for your reference. You need to update your <code class="docutils literal notranslate"><span class="pre">Room</span></code> typeclass (see above) to actually call it. Remember that to see different symbols for a location you also need to set the <code class="docutils literal notranslate"><span class="pre">sector_type</span></code> Attribute on the room to one of the keys in the <code class="docutils literal notranslate"><span class="pre">SYMBOLS</span></code> dictionary. So in this example, to make a room be mapped as <code class="docutils literal notranslate"><span class="pre">[.]</span></code> you would set the rooms <code class="docutils literal notranslate"><span class="pre">sector_type</span></code> to <code class="docutils literal notranslate"><span class="pre">&quot;SECT_INSIDE&quot;</span></code>. Try it out with <code class="docutils literal notranslate"><span class="pre">&#64;set</span> <span class="pre">here/sector_type</span> <span class="pre">=</span> <span class="pre">&quot;SECT_INSIDE&quot;</span></code>. If you wanted all new rooms to have a given sector symbol, you could change the default in the <code class="docutils literal notranslate"><span class="pre">SYMBOLS</span></code> dictionary below, or you could add the Attribute in the Rooms <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> method.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/world/map.py</span>
<span class="c1"># These are keys set with the Attribute sector_type on the room.</span>
<span class="c1"># The keys None and &quot;you&quot; must always exist.</span>
<span class="n">SYMBOLS</span> <span class="o">=</span> <span class="p">{</span> <span class="kc">None</span> <span class="p">:</span> <span class="s1">&#39; . &#39;</span><span class="p">,</span> <span class="c1"># for rooms without a sector_type attr</span>
<span class="s1">&#39;you&#39;</span> <span class="p">:</span> <span class="s1">&#39;[@]&#39;</span><span class="p">,</span>
<span class="s1">&#39;SECT_INSIDE&#39;</span><span class="p">:</span> <span class="s1">&#39;[.]&#39;</span> <span class="p">}</span>
<span class="k">class</span> <span class="nc">Map</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">max_width</span><span class="o">=</span><span class="mi">9</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">9</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span> <span class="o">=</span> <span class="n">caller</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_width</span> <span class="o">=</span> <span class="n">max_width</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_length</span> <span class="o">=</span> <span class="n">max_length</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span> <span class="o">=</span> <span class="p">{}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">check_grid</span><span class="p">():</span>
<span class="c1"># we actually have to store the grid into a variable</span>
<span class="bp">self</span><span class="o">.</span><span class="n">grid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_grid</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw_room_on_map</span><span class="p">(</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="p">,</span>
<span class="p">((</span><span class="nb">min</span><span class="p">(</span><span class="n">max_width</span><span class="p">,</span> <span class="n">max_length</span><span class="p">)</span> <span class="o">-</span><span class="mi">1</span> <span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">update_pos</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">exit_name</span><span class="p">):</span>
<span class="c1"># this ensures the pointer variables always</span>
<span class="c1"># stays up to date to where the worm is currently at.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> \
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="c1"># now we have to actually move the pointer</span>
<span class="c1"># variables depending on which &#39;exit&#39; it found</span>
<span class="k">if</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;east&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;west&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;north&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">elif</span> <span class="n">exit_name</span> <span class="o">==</span> <span class="s1">&#39;south&#39;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">draw_room_on_map</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">,</span> <span class="n">max_distance</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">room</span><span class="p">)</span>
<span class="k">if</span> <span class="n">max_distance</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">exit</span> <span class="ow">in</span> <span class="n">room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="k">if</span> <span class="n">exit</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;north&quot;</span><span class="p">,</span> <span class="s2">&quot;east&quot;</span><span class="p">,</span> <span class="s2">&quot;west&quot;</span><span class="p">,</span> <span class="s2">&quot;south&quot;</span><span class="p">):</span>
<span class="c1"># we only map in the cardinal directions. Mapping up/down would be</span>
<span class="c1"># an interesting learning project for someone who wanted to try it.</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_drawn</span><span class="p">(</span><span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">):</span>
<span class="c1"># we&#39;ve been to the destination already, skip ahead.</span>
<span class="k">continue</span>
<span class="bp">self</span><span class="o">.</span><span class="n">update_pos</span><span class="p">(</span><span class="n">room</span><span class="p">,</span> <span class="n">exit</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">draw_room_on_map</span><span class="p">(</span><span class="n">exit</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">max_distance</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">draw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="c1"># draw initial caller location on map first!</span>
<span class="k">if</span> <span class="n">room</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_loc_on_grid</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># map all other rooms</span>
<span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="p">[</span><span class="n">room</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span><span class="p">]</span>
<span class="c1"># this will use the sector_type Attribute or None if not set.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">grid</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">][</span><span class="bp">self</span><span class="o">.</span><span class="n">curY</span><span class="p">]</span> <span class="o">=</span> <span class="n">SYMBOLS</span><span class="p">[</span><span class="n">room</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sector_type</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">median</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">num</span><span class="p">):</span>
<span class="n">lst</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">num</span><span class="p">))</span>
<span class="n">n</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">lst</span><span class="p">)</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">n</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">return</span> <span class="p">(</span><span class="n">lst</span><span class="p">[</span><span class="n">n</span><span class="o">//</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">lst</span><span class="p">[</span><span class="n">m</span><span class="o">//</span><span class="mi">2</span><span class="p">])</span> <span class="o">/</span> <span class="mf">2.0</span>
<span class="k">def</span> <span class="nf">start_loc_on_grid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">x</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">median</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_width</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">median</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_length</span><span class="p">)</span>
<span class="c1"># x and y are floats by default, can&#39;t index lists with float types</span>
<span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">grid</span><span class="p">[</span><span class="n">x</span><span class="p">][</span><span class="n">y</span><span class="p">]</span> <span class="o">=</span> <span class="n">SYMBOLS</span><span class="p">[</span><span class="s1">&#39;you&#39;</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">curX</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">curY</span> <span class="o">=</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="c1"># updating worms current location</span>
<span class="k">def</span> <span class="nf">has_drawn</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">room</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="n">room</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">worm_has_mapped</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span> <span class="k">else</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">create_grid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># This method simply creates an empty grid</span>
<span class="c1"># with the specified variables from __init__(self):</span>
<span class="n">board</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_width</span><span class="p">):</span>
<span class="n">board</span><span class="o">.</span><span class="n">append</span><span class="p">([])</span>
<span class="k">for</span> <span class="n">column</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">max_length</span><span class="p">):</span>
<span class="n">board</span><span class="p">[</span><span class="n">row</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">board</span>
<span class="k">def</span> <span class="nf">check_grid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># this method simply checks the grid to make sure</span>
<span class="c1"># both max_l and max_w are odd numbers</span>
<span class="k">return</span> <span class="kc">True</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_length</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span> <span class="ow">or</span> \
<span class="bp">self</span><span class="o">.</span><span class="n">max_width</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">!=</span> <span class="mi">0</span> <span class="k">else</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">show_map</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">map_string</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">grid</span><span class="p">:</span>
<span class="n">map_string</span> <span class="o">+=</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
<span class="n">map_string</span> <span class="o">+=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span>
<span class="k">return</span> <span class="n">map_string</span>
</pre></div>
</div>
</section>
<section id="final-comments">
<h2>Final Comments<a class="headerlink" href="#final-comments" title="Permalink to this headline"></a></h2>
<p>The Dynamic map could be expanded with further capabilities. For example, it could mark exits or
allow NE, SE etc directions as well. It could have colors for different terrain types. One could
also look into up/down directions and figure out how to display that in a good way.</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="Web-Changing-Webpage.html" title="Changing the Game Website"
>next</a> |</li>
<li class="right" >
<a href="Tutorial-Coordinates.html" title="Adding room coordinates to your game"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 3.x</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" >Tutorials and How-Tos</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Show a dynamic map of rooms</a></li>
</ul>
</div>
<div class="admonition important">
<p class="first admonition-title">Note</p>
<p class="last">You are reading an old version of the Evennia documentation. <a href="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>