<p>This will install all optional requirements of Evennia.</p>
</li>
<li><p>Import and <aclass="reference internal"href="../Components/Command-Sets.html"><spanclass="doc std std-doc">add</span></a> the <codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.grid.xyzgrid.commands.XYZGridCmdSet</span></code> to the
<codeclass="docutils literal notranslate"><spanclass="pre">CharacterCmdset</span></code> cmdset in <codeclass="docutils literal notranslate"><spanclass="pre">mygame/commands.default_cmds.py</span></code>. Reload
the server. This makes the <codeclass="docutils literal notranslate"><spanclass="pre">map</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">goto/path</span></code> and the modified <codeclass="docutils literal notranslate"><spanclass="pre">teleport</span></code> and
<codeclass="docutils literal notranslate"><spanclass="pre">open</span></code> commands available in-game.</p></li>
</ol>
<ol>
<li><p>Edit <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf/settings.py</span></code> and add</p>
<p>This will add the new ability to enter <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre"><option></span></code> on the
command line. It will also make the <codeclass="docutils literal notranslate"><spanclass="pre">xyz_room</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">xyz_exit</span></code> prototypes
available for use as prototype-parents when spawning the grid.</p>
</li>
<li><p>Run <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">help</span></code> for available options.</p></li>
<li><p>(Optional): By default, the xyzgrid will only spawn module-based
<aclass="reference internal"href="../Components/Prototypes.html"><spanclass="doc std std-doc">prototypes</span></a>. This is an optimization and usually makes sense
since the grid is entirely defined outside the game anyway. If you want to
also make use of in-game (db-) created prototypes, add
<codeclass="docutils literal notranslate"><spanclass="pre">XYZGRID_USE_DB_PROTOTYPES</span><spanclass="pre">=</span><spanclass="pre">True</span></code> to settings.</p></li>
</ol>
</section>
<sectionid="overview">
<h2>Overview<aclass="headerlink"href="#overview"title="Permalink to this headline">¶</a></h2>
<p>The grid contrib consists of multiple components.</p>
<olclass="simple">
<li><p>The <codeclass="docutils literal notranslate"><spanclass="pre">XYMap</span></code> - This class parses modules with special <em>Map strings</em>
and <em>Map legends</em> into one Python object. It has helpers for pathfinding and
visual-range handling.</p></li>
<li><p>The <codeclass="docutils literal notranslate"><spanclass="pre">XYZGrid</span></code> - This is a singleton <aclass="reference internal"href="../Components/Scripts.html"><spanclass="doc std std-doc">Script</span></a> that
stores all <codeclass="docutils literal notranslate"><spanclass="pre">XYMaps</span></code> in the game. It is the central point for managing the ‘grid’
of the game.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">XYZExit</span></code>are custom typeclasses that use
to know which X,Y,Z coordinate they are located at. The <codeclass="docutils literal notranslate"><spanclass="pre">XYZGrid</span></code> is
abstract until it is used to <em>spawn</em> these database entities into
something you can actually interract with in the game. The <codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code>
typeclass is using its <codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code> hook to display the in-game map.</p></li>
<li><p>Custom <em>Commands</em> have been added for interacting with XYZ-aware locations.</p></li>
<li><p>A new custom <em>Launcher command</em>, <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre"><options></span></code> is used to
manage the grid from the terminal (no game login is needed).</p></li>
</ol>
<p>We’ll start exploring these components with an example.</p>
</section>
<sectionid="first-example-usage">
<h2>First example usage<aclass="headerlink"href="#first-example-usage"title="Permalink to this headline">¶</a></h2>
<p>After installation, do the following from your command line (where the
<codeclass="docutils literal notranslate"><spanclass="pre">evennia</span></code> command is available):</p>
<p>use <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">help</span></code> to see all options)
This will create a new <codeclass="docutils literal notranslate"><spanclass="pre">XYZGrid</span></code><aclass="reference internal"href="../Components/Scripts.html"><spanclass="doc std std-doc">Script</span></a> if one didn’t already exist.
The <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span></code> is a custom launch option added only for this contrib.</p>
<p>The xyzgrid-contrib comes with a full grid example. Let’s add it:</p>
<p>(or <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">start</span></code> if server was not running). This is important to do after
every spawning operation, since the <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span></code> operates outside of the
regular evennia process. Reloading makes sure all caches are refreshed.</p>
<p>Now you can log into the server. Some new commands should be available to you.</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>teleport (3,0,the large tree)
</pre></div>
</div>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">teleport</span></code> command now accepts an optional (X, Y, Z) coordinate. Teleporting
to a room-name or <codeclass="docutils literal notranslate"><spanclass="pre">#dbref</span></code> still works the same. This will teleport you onto the
grid. You should see a map-display. Try walking around.</p>
<p>Once you are in a grid-room, you can teleport to another grid room <em>on the same
map</em> without specifying the Z coordinate/map name.</p>
<p>You can use <codeclass="docutils literal notranslate"><spanclass="pre">open</span></code> to make an exit back to the ‘non-grid’, but remember that you
mustn’t use a cardinal direction to do so - if you do, the <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code>
will likely remove it next time you run it.</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>open To limbo;limbo = #2
limbo
</pre></div>
</div>
<p>You are back in Limbo (which doesn’t know anything about XYZ coordinates). You
can however make a permanent link back into the gridmap:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>open To grid;grid = (3,0,the large tree)
grid
</pre></div>
</div>
<p>This is how you link non-grid and grid locations together. You could for example
embed a house ‘inside’ the grid this way.</p>
<p>the <codeclass="docutils literal notranslate"><spanclass="pre">(3,0,the</span><spanclass="pre">large</span><spanclass="pre">tree)</span></code> is a ‘Dungeon entrance’. If you walk east you’ll
<em>transition</em> into “the small cave” map. This is a small underground dungeon
with limited visibility. Go back outside again (back on “the large tree” map).</p>
<p>You will be asked to confirm the deletion of the grid and unloading of the
XYZGrid script. Reload the server afterwards. If you were on a map that was
deleted you will have been moved back to your home location.</p>
</section>
<sectionid="defining-an-xymap">
<h2>Defining an XYMap<aclass="headerlink"href="#defining-an-xymap"title="Permalink to this headline">¶</a></h2>
<p>For a module to be suitable to pass to <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">add</span><spanclass="pre"><module></span></code>, the
module must contain one of the following variables:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code> - a dict containing data that fully defines the XYMap</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA_LIST</span></code> - a list of <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code> dicts. If this exists, it will take
precedence. This allows for storing multiple maps in one module.</p></li>
</ul>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code> dict has the following form:</p>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"zcoord"</span></code> (str): The Z-coordinate/map name of the map.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"map"</span></code> (str): A <em>Map string</em> describing the topology of the map.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"legend"</span></code> (dict, optional): Maps each symbol on the map to Python code. This
dict can be left out or only partially filled - any symbol not specified will
instead use the default legend from the contrib.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"prototypes"</span></code> (dict, optional): This is a dict that maps map-coordinates
to custom prototype overrides. This is used when spawning the map into
actual rooms/exits.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">"options"</span></code> (dict, optional): These are passed into the <codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code>
hook of the room and allows for customizing how a map should be displayed,
how pathfinding should work etc.</p></li>
</ul>
<p>Here’s a minimal example of the whole setup:</p>
<divclass="highlight-default notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># In, say, a module gamedir/world/mymap.py</span>
<spanclass="s2">"desc"</span><spanclass="p">:</span><spanclass="s2">"Sun shines through the branches above."</span><spanclass="p">,</span>
<spanclass="s2">"desc"</span><spanclass="p">:</span><spanclass="s2">"A quiet path through the foilage"</span><spanclass="p">,</span>
<spanclass="s2">"desc"</span><spanclass="p">:</span><spanclass="s2">"The path leads further into the forest."</span><spanclass="p">,</span>
<p>Each XYMap on the grid has a Z-coordinate which usually can be treated just as
the name of the map. The Z-coordinate can be either a string or an integer, and must
be unique across the entire grid. It is added as the key ‘zcoord’ to <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code>.</p>
“Z-coordinate” things like <codeclass="docutils literal notranslate"><spanclass="pre">Dungeon</span><spanclass="pre">of</span><spanclass="pre">Doom</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">The</span><spanclass="pre">ice</span><spanclass="pre">queen's</span><spanclass="pre">palace</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">City</span><spanclass="pre">of</span><spanclass="pre">Blackhaven</span></code>. But you could also name it -1, 0, 1, 2, 3 if you wanted.</p>
<p>Pathfinding happens only within each XYMap (up/down is normally ‘faked’ by moving
sideways to a new area of the XY plane).</p>
<sectionid="a-true-3d-map">
<h4>A true 3D map<aclass="headerlink"href="#a-true-3d-map"title="Permalink to this headline">¶</a></h4>
<p>Even for the most hardcore of sci-fi space game, consider sticking to 2D
movement. It’s hard enough for players to visualize a 3D volume with graphics.
In text it’s even harder.</p>
<p>That said, if you want to set up a true X, Y, Z 3D coordinate system (where
you can move up/down from every point), you can do that too.</p>
<p>This contrib provides an example command <codeclass="docutils literal notranslate"><spanclass="pre">commands.CmdFlyAndDive</span></code> that provides the player
with the ability to use <codeclass="docutils literal notranslate"><spanclass="pre">fly</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">dive</span></code> to move straight up/down between Z
coordinates. Just add it (or its cmdset <codeclass="docutils literal notranslate"><spanclass="pre">commands.XYZGridFlyDiveCmdSet</span></code>) to your
Character cmdset and reload to try it out.</p>
<p>For the fly/dive to work you need to build your grid as a ‘stack’ of XY-grid maps
and name them by their Z-coordinate as an integer. The fly/dive actions will
only work if there is actually a matching room directly above/below.</p>
<blockquote>
<div><p>Note that since pathfinding only works within each XYmap, the player will not
be able to include fly/dive in their autowalking - this is always a manual
action.</p>
</div></blockquote>
<p>As an example, let’s assume coordinate <codeclass="docutils literal notranslate"><spanclass="pre">(1,</span><spanclass="pre">1,</span><spanclass="pre">-3)</span></code>
is the bottom of a deep well leading up to the surface (at level 0)</p>
<p>In this example, if we arrive to the bottom of the well at <codeclass="docutils literal notranslate"><spanclass="pre">(1,</span><spanclass="pre">1,</span><spanclass="pre">-3)</span></code> we
<codeclass="docutils literal notranslate"><spanclass="pre">fly</span></code> straight up three levels until we arrive at <codeclass="docutils literal notranslate"><spanclass="pre">(1,</span><spanclass="pre">1,</span><spanclass="pre">0)</span></code>, at the corner
of some sort of open field.</p>
<p>We can dive down from <codeclass="docutils literal notranslate"><spanclass="pre">(1,</span><spanclass="pre">1,</span><spanclass="pre">0)</span></code>. In the default implementation you must <codeclass="docutils literal notranslate"><spanclass="pre">dive</span></code> 3 times
to get to the bottom. If you wanted you could tweak the command so you
automatically fall to the bottom and take damage etc.</p>
<p>We can’t fly/dive up/down from any other XY positions because there are no open rooms at the
<div><p>Even though it’s optional, it’s highly recommended that you add numbers to
your axes - if only for your own sanity.</p>
</div></blockquote>
<p>The coordinate area starts <em>two spaces to the right</em> and <em>two spaces
below/above</em> the mandatory <codeclass="docutils literal notranslate"><spanclass="pre">+</span></code> signs (which marks the corners of the map area).
Origo <codeclass="docutils literal notranslate"><spanclass="pre">(0,0)</span></code> is in the bottom left (so X-coordinate increases to the right and
Y-coordinate increases towards the top). There is no limit to how high/wide the
map can be, but splitting a large world into multiple maps can make it easier
to organize.</p>
<p>Position is important on the grid. Full coordinates are placed on every <em>second</em>
space along all axes. Between these ‘full’ coordinates are <codeclass="docutils literal notranslate"><spanclass="pre">.5</span></code> coordinates.
Note that there are <em>no</em><codeclass="docutils literal notranslate"><spanclass="pre">.5</span></code> coordinates spawned in-game; they are only used
in the map string to have space to describe how rooms/nodes link to one another.</p>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">A</span></code> is at origo, <codeclass="docutils literal notranslate"><spanclass="pre">(0,</span><spanclass="pre">0)</span></code> (a ‘full’ coordinate)</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">B</span></code> is at <codeclass="docutils literal notranslate"><spanclass="pre">(0.5,</span><spanclass="pre">3.5)</span></code></p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">C</span></code> is at <codeclass="docutils literal notranslate"><spanclass="pre">(1.5,</span><spanclass="pre">1)</span></code></p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">D</span></code> is at <codeclass="docutils literal notranslate"><spanclass="pre">(4,</span><spanclass="pre">2)</span></code> (a ‘full’ coordinate).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">E</span></code> is the top-right corner of the map, at <codeclass="docutils literal notranslate"><spanclass="pre">(5,</span><spanclass="pre">4)</span></code> (a ‘full’ coordinate)</p></li>
</ul>
<p>The map string consists of two main classes of entities - <em>nodes</em> and <em>links</em>.</p>
<ulclass="simple">
<li><p>A <em>node</em> usually represents a <em>room</em> in-game (but not always). Nodes must
<em>always</em> be placed on a ‘full’ coordinate.</p></li>
<li><p>A <em>link</em> describes a connection between two nodes. In-game, links are usuallyj
represented by <em>exits</em>. A link can be placed
anywhere in the coordinate space (both on full and 0.5 coordinates). Multiple
links are often <em>chained</em> together, but the chain must always end in nodes
on both sides.</p></li>
</ul>
<blockquote>
<div><p>Even though a link-chain may consist of several steps, like <codeclass="docutils literal notranslate"><spanclass="pre">#-----#</span></code>,
in-game it will still only represent one ‘step’ (e.g. you go ‘east’ only once
to move from leftmost to the rightmost node/room).</p>
</div></blockquote>
</section>
<sectionid="map-legend">
<h3>Map legend<aclass="headerlink"href="#map-legend"title="Permalink to this headline">¶</a></h3>
<p>There can be many different types of <em>nodes</em> and <em>links</em>. Whereas the map
string describes where they are located, the <em>Map Legend</em> connects each symbol
<spanclass="c1"># added to XYMAP_DATA dict as 'legend': LEGEND below</span>
</pre></div>
</div>
<p>The legend is optional, and any symbol not explicitly given in your legend will
fall back to its value in the default legend <aclass="reference internal"href="#default-legend"><spanclass="std std-doc">outlined below</span></a>.</p>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">symbol</span></code> (str) - The character to parse from the map into this node. By default this
is <codeclass="docutils literal notranslate"><spanclass="pre">'#'</span></code> and <em>must</em> be a single character (with the exception of <codeclass="docutils literal notranslate"><spanclass="pre">\\</span></code> that must
be escaped to be used). Whatever this value defaults to, it is replaced at
run-time by the symbol used in the legend-dict.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">display_symbol</span></code> (str or <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code>) - This is what is used to visualize this node
in-game. This symbol must still only have a visual size of 1, but you could e.g.
use some fancy unicode character (be aware of encodings to different clients
though) or, commonly, add color tags around it. The <codeclass="docutils literal notranslate"><spanclass="pre">.get_display_symbol</span></code>
of this class can be customized to generate this dynamically; by default it
just returns <codeclass="docutils literal notranslate"><spanclass="pre">.display_symbol</span></code>. If set to <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> (default), the <codeclass="docutils literal notranslate"><spanclass="pre">symbol</span></code> is
used.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">interrupt_path</span></code> (bool): If this is set, the shortest-path algorithm will
include this node normally, but the auto-stepper will stop when reaching it,
even if not having reached its target yet. This is useful for marking ‘points of
interest’ along a route, or places where you are not expected to be able to
continue without some
further in-game action not covered by the map (such as a guard or locked gate
etc).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">prototype</span></code> (dict) - The default <codeclass="docutils literal notranslate"><spanclass="pre">prototype</span></code> dict to use for reproducing this
map component on the game grid. This is used if not overridden specifically
for this coordinate in the “prototype” dict of <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code>… If this is not
given, nothing will be spawned for this coordinate (a ‘virtual’ node can be
useful for various reasons, mostly map-transitions).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">symbol</span></code> (str) - The character to parse from the map into this node. This must
be a single character, with the exception of <codeclass="docutils literal notranslate"><spanclass="pre">\\</span></code>. This will be replaced
at run-time by the symbol used in the legend-dict.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">display_symbol</span></code> (str or None) - This is what is used to visualize this node
later. This symbol must still only have a visual size of 1, but you could e.g.
use some fancy unicode character (be aware of encodings to different clients
though) or, commonly, add color tags around it. For further customization, the
<codeclass="docutils literal notranslate"><spanclass="pre">.get_display_symbol</span></code> can be used.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">default_weight</span></code> (int) - Each link direction covered by this link can have its
separate weight (used for pathfinding). This is used if none specific weight
is specified in a particular link direction. This value must be >= 1, and can
be higher than 1 if a link should be less favored.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">directions</span></code> (dict) - this specifies which from which link edge to which other
link-edge this link is connected; A link connecting the link’s sw edge to its
easted edge would be written as <codeclass="docutils literal notranslate"><spanclass="pre">{'sw':</span><spanclass="pre">'e'}</span></code> and read ‘connects from southwest
to east’ This ONLY takes cardinal directions (not up/down). Note that if you
want the link to go both ways, also the inverse (east to southwest) must be
added.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">weights</span><spanclass="pre">(dict)</span></code> This maps a link’s start direction to a weight. So for the
<codeclass="docutils literal notranslate"><spanclass="pre">{'sw':</span><spanclass="pre">'e'}</span></code> link, a weight would be given as <codeclass="docutils literal notranslate"><spanclass="pre">{'sw':</span><spanclass="pre">2}</span></code>. If not given, a
link will use the <codeclass="docutils literal notranslate"><spanclass="pre">default_weight</span></code>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">average_long_link_weights</span></code> (bool): This applies to the <em>first</em> link out of a
node only. When tracing links to another node, multiple links could be
involved, each with a weight. So for a link chain with default weights, <codeclass="docutils literal notranslate"><spanclass="pre">#---#</span></code>
would give a total weight of 3. With this setting (default), the weight will
be (1+1+1) / 3 = 1. That is, for evenly weighted links, the length of the
link-chain doesn’t matter (this is usually what makes most sense).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">direction_aliases</span></code> (dict): When displaying a direction during pathfinding,
one may want to display a different ‘direction’ than the cardinal on-map one.
For example ‘up’ may be visualized on the map as a ‘n’ movement, but the found
path over this link should show as ‘u’. In that case, the alias would be
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">multilink</span></code> (bool): If set, this link accepts links from all directions. It
will usually use a custom <codeclass="docutils literal notranslate"><spanclass="pre">.get_direction</span></code> method to determine what these are
based on surrounding topology. This setting is necessary to avoid infinite
loops when such multilinks are next to each other.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">interrupt_path</span></code> (bool): If set, a shortest-path solution will include this
link as normal, but auto-stepper will stop short of actually moving past this
link.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">prototype</span></code> (dict) - The default <codeclass="docutils literal notranslate"><spanclass="pre">prototype</span></code> dict to use for reproducing this
map component on the game grid. This is only relevant for the <em>first</em> link out
of a Node (the continuation of the link is only used to determine its
destination). This can be overridden on a per-direction basis.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">spawn_aliases</span></code> (dict): A mapping <codeclass="docutils literal notranslate"><spanclass="pre">{direction:</span><spanclass="pre">(key,</span><spanclass="pre">alias,</span><spanclass="pre">alias,</span><spanclass="pre">...),}</span></code>to
use when spawning actual exits from this link. If not given, a sane set of
defaults (<codeclass="docutils literal notranslate"><spanclass="pre">n=(north,</span><spanclass="pre">n)</span></code> etc) will be used. This is required if you use any
custom directions outside of the cardinal directions + up/down. The exit’s key
(useful for auto-walk) is usually retrieved by calling
<h4>Default Legend<aclass="headerlink"href="#default-legend"title="Permalink to this headline">¶</a></h4>
<p>Below is the default map legend. The <codeclass="docutils literal notranslate"><spanclass="pre">symbol</span></code> is what should be put in the Map
string. It must always be a single character. The <codeclass="docutils literal notranslate"><spanclass="pre">display-symbol</span></code> is what is
actually visualized when displaying the map to players in-game. This could have
colors etc. All classes are found in <codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.grid.xyzgrid.xymap_legend</span></code> and
their names are included to make it easy to know what to override.</p>
<h4>Map Nodes<aclass="headerlink"href="#map-nodes"title="Permalink to this headline">¶</a></h4>
<p>The basic map node (<codeclass="docutils literal notranslate"><spanclass="pre">#</span></code>) usually represents a ‘room’ in the game world. Links
can connect to the node from any of the 8 cardinal directions, but since nodes
must <em>only</em> exist on full coordinates, they can never appear directly next to
<h4>One-way links<aclass="headerlink"href="#one-way-links"title="Permalink to this headline">¶</a></h4>
<p><codeclass="docutils literal notranslate"><spanclass="pre">></span></code>,<codeclass="docutils literal notranslate"><spanclass="pre"><</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">v</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">^</span></code> are used to indicate one-way links. These indicators should
either be <em>first</em> or <em>last</em> in a link chain (think of them as arrows):</p>
<p>These two are equivalent, but the first one is arguably easier to read. It is also
faster to parse since the parser on the rightmost node immediately sees that the
link in that direction is impassable from that direction.</p>
<blockquote>
<div><p>Note that there are no one-way equivalents to the <codeclass="docutils literal notranslate"><spanclass="pre">\</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">/</span></code> directions. This
is not because it can’t be done but because there are no obvious ASCII
characters to represent diagonal arrows. If you want them, it’s easy enough to
subclass the existing one-way map-legend to add one-way versions of diagonal
movement as well.</p>
</div></blockquote>
</section>
<sectionid="up-and-down-links">
<h4>Up- and Down-links<aclass="headerlink"href="#up-and-down-links"title="Permalink to this headline">¶</a></h4>
<p>Links like <codeclass="docutils literal notranslate"><spanclass="pre">u</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">d</span></code> don’t have a clear indicator which directions they
connect (unlike e.g. <codeclass="docutils literal notranslate"><spanclass="pre">|</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">-</span></code>).</p>
<p>So placing them (and many similar types of map elements) requires that the
directions are visually clear. For example, multiple links cannot connect to the
up-down links (it’d be unclear which leads where) and if adjacent to a node, the
link will prioritize connecting to the node. Here are some examples:</p>
u - moving up in BOTH directions will bring you to the other node (two-way)
#
#
| - one-way up from the lower node to the upper, south to go back
u
#
#
^ - true one-way up movement, combined with a one-way 'n' link
u
#
#
d - one-way up, one-way down again (standard up/down behavior)
u
#
#u#
u - invalid since top-left node has two 'up' directions to go to
#
# |
u# or u- - invalid since the direction of u is unclear
# |
</pre></div>
</div>
</section>
<sectionid="interrupt-nodes">
<h4>Interrupt-nodes<aclass="headerlink"href="#interrupt-nodes"title="Permalink to this headline">¶</a></h4>
<p>An interrupt-node (<codeclass="docutils literal notranslate"><spanclass="pre">I</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">InterruptMapNode</span></code>) is a node that acts like any other
node except it is considered a ‘point of interest’ and the auto-walk of the
<codeclass="docutils literal notranslate"><spanclass="pre">goto</span></code> command will always stop auto-stepping at this location.</p>
<p>So if auto-walking from left to right, the auto-walk will correctly map a path
to the end room, but will always stop at the <codeclass="docutils literal notranslate"><spanclass="pre">I</span></code> node. If the user <em>starts</em> from
the <codeclass="docutils literal notranslate"><spanclass="pre">I</span></code> room, they will move away from it without interruption (so you can
manually run the <codeclass="docutils literal notranslate"><spanclass="pre">goto</span></code> again to resume the auto-step).</p>
<p>The use of this room is to anticipate blocks not covered by the map. For example
there could be a guard standing in this room that will arrest you unless you
show them the right paperwork - trying to auto-walk past them would be bad!</p>
<p>By default, this node looks just like a normal <codeclass="docutils literal notranslate"><spanclass="pre">#</span></code> to the player.</p>
</section>
<sectionid="interrupt-links">
<h4>Interrupt-links<aclass="headerlink"href="#interrupt-links"title="Permalink to this headline">¶</a></h4>
<p>The interrupt-link (<codeclass="docutils literal notranslate"><spanclass="pre">i</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">InterruptMapLink</span></code>) is equivalent to the
<codeclass="docutils literal notranslate"><spanclass="pre">InterruptMapNode</span></code> except it applies to a link. While the pathfinder will
correctly trace a path to the other side, the auto-stepper will never cross an
interrupting link - you have to do so ‘manually’. Similarly to up/down links,
the InterruptMapLink must be placed so that its direction is un-ambiguous (with
<p>When pathfinding from left to right, the pathfinder will find the end room just
fine, but when auto-stepping, it will always stop at the node just to the left
of the <codeclass="docutils literal notranslate"><spanclass="pre">i</span></code> link. Rerunning <codeclass="docutils literal notranslate"><spanclass="pre">goto</span></code> will not matter.</p>
<p>This is useful for automatically handle in-game blocks not part of the map.
An example would be a locked door - rather than having the auto-stepper trying
to walk accross the door exit (and failing), it should stop and let the user
cross the threshold manually before they can continue.</p>
<p>Same as for interrupt-nodes, the interrupt-link looks like the expected link to the user
(so in the above example, it would show as <codeclass="docutils literal notranslate"><spanclass="pre">-</span></code>).</p>
</section>
<sectionid="blocked-links">
<h4>Blocked links<aclass="headerlink"href="#blocked-links"title="Permalink to this headline">¶</a></h4>
<p>Blockers (<codeclass="docutils literal notranslate"><spanclass="pre">b</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">BlockedMapLink</span></code>) indicates a route that the pathfinder should not use. The
pathfinder will treat it as impassable even though it will be spawned as a
<p>There is no way to auto-step from left to right because the pathfinder will
treat the <codeclass="docutils literal notranslate"><spanclass="pre">b</span></code> (block) as if there was no link there (technically it sets the
link’s <codeclass="docutils literal notranslate"><spanclass="pre">weight</span></code> to a very high number). The player will need to auto-walk to the
room just to the left of the block, manually step over the block and then
continue from there.</p>
<p>This is useful both for actual blocks (maybe the room is full of rubble?) and in
order to avoid players auto-walking into hidden areas or finding the way out of
a labyrinth etc. Just hide the labyrinth’s exit behind a block and <codeclass="docutils literal notranslate"><spanclass="pre">goto</span><spanclass="pre">exit</span></code>
will not work (admittedly one may want to turn off pathfinding altogether on
such maps).</p>
</section>
<sectionid="router-links">
<h4>Router-links<aclass="headerlink"href="#router-links"title="Permalink to this headline">¶</a></h4>
<p>Routers (<codeclass="docutils literal notranslate"><spanclass="pre">o</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">RouterMapLink</span></code>) allow for connecting nodes with links at an
-o- - equivalent to '+': one n-s and one w-e link crossing
|
\|/
-o- - all links are passing straight through
/|\
-o- - w-e link pass straight through, other link is sw-s
/|
-o - invalid; impossible to know which input goes to which output
/|
</pre></div>
</div>
</section>
<sectionid="teleporter-links">
<h4>Teleporter Links<aclass="headerlink"href="#teleporter-links"title="Permalink to this headline">¶</a></h4>
<p>Teleporters (<codeclass="docutils literal notranslate"><spanclass="pre">TeleportMapLink</span></code>) always come in pairs using the same map symbol
(<codeclass="docutils literal notranslate"><spanclass="pre">'t'</span></code> by default). When moving into one link, movement continues out the
matching teleport link. The pair must both be on the same XYMap and both sides
must connect/chain to a node (like all links). Only a single link (or node) may
connect to the teleport link.</p>
<p>Pathfinding will also work correctly across the teleport.</p>
<p>Moving east from the leftmost node will have you appear at the rightmost node
and vice versa (think of the two <codeclass="docutils literal notranslate"><spanclass="pre">t</span></code> as thinking they are in the same location).</p>
<p>Teleportation movement is always two-way, but you can use one-way links to
<h4>Map-Transition Nodes<aclass="headerlink"href="#map-transition-nodes"title="Permalink to this headline">¶</a></h4>
<p>The map transition (<codeclass="docutils literal notranslate"><spanclass="pre">MapTransitionNode</span></code>) teleports between XYMaps (a
Z-coordinate transition, if you will), like walking from the “Dungeon” map to
the “Castle” map. Unlike other nodes, the MapTransitionNode is never spawned
into an actual room (it has no prototype). It just holds an XYZ
coordinate pointing to somewhere on the other map. The link leading <em>to</em> the
node will use those coordinates to make an exit pointing there. Only one single
link may lead to this type of node.</p>
<p>Unlike for <codeclass="docutils literal notranslate"><spanclass="pre">TeleporterMapLink</span></code>, there need <em>not</em> be a matching
<codeclass="docutils literal notranslate"><spanclass="pre">MapTransitionNode</span></code> on the other map - the transition can choose to send the
player to <em>any</em> valid coordinate on the other map.</p>
<p>Each MapTransitionNode has a property <codeclass="docutils literal notranslate"><spanclass="pre">target_map_xyz</span></code> that holds the XYZ
coordinate the player should end up in when going towards this node. This
must be customized in a child class for every transition.</p>
<p>If there are more than one transition, separate transition classes should be
added, with different map-legend symbols:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in your map definition module (let's say this is mapB)</span>
<p>Moving west from <codeclass="docutils literal notranslate"><spanclass="pre">(1,0)</span></code> will bring you to <codeclass="docutils literal notranslate"><spanclass="pre">(1,4)</span></code> of MapA, and moving east from
<codeclass="docutils literal notranslate"><spanclass="pre">(1,2)</span></code> will bring you to <codeclass="docutils literal notranslate"><spanclass="pre">(12,14)</span></code> on MapC (assuming those maps exist).</p>
<p>A map transition is always one-way, and can lead to the coordinates of <em>any</em>
<p>A player moving east towards <codeclass="docutils literal notranslate"><spanclass="pre">T</span></code> could for example end up at the 4th <codeclass="docutils literal notranslate"><spanclass="pre">#</span></code> from
the left on map2 if so desired (even though it doesn’t make sense visually).
There is no way to get back to map1 from there.</p>
<p>To create the effect of a two-way transition, one can set up a mirrored
<p>The transition-node of each map above has <codeclass="docutils literal notranslate"><spanclass="pre">target_map_xyz</span></code> pointing to the
coordinate of the <codeclass="docutils literal notranslate"><spanclass="pre">#</span></code> node of the other map (<em>not</em> to the other <codeclass="docutils literal notranslate"><spanclass="pre">T</span></code>, that is not
spawned and would lead to the exit finding no destination!). The result is that
one can go east into the dungeon and then immediately go back west to the city
across the map boundary.</p>
</section>
</section>
<sectionid="prototypes">
<h3>Prototypes<aclass="headerlink"href="#prototypes"title="Permalink to this headline">¶</a></h3>
<p><aclass="reference internal"href="../Components/Prototypes.html"><spanclass="doc std std-doc">Prototypes</span></a> are dicts that describe how to <em>spawn</em> a new instance
of an object. Each of the <em>nodes</em> and <em>links</em> above have a default prototype
that allows the <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code> command to convert them to
a <aclass="reference internal"href="../api/evennia.contrib.grid.xyzgrid.xyzroom.html#evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom"title="evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom"><spanclass="xref myst py py-class">XYZRoom</span></a>
or an <aclass="reference internal"href="../api/evennia.contrib.grid.xyzgrid.xyzroom.html#evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom"title="evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom"><spanclass="xref myst py py-class">XYZExit</span></a> respectively.</p>
<p>The default prototypes are found in <codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.grid.xyzgrid.prototypes</span></code> (added
during installation of this contrib), with <codeclass="docutils literal notranslate"><spanclass="pre">prototype_key</span></code>s <codeclass="docutils literal notranslate"><spanclass="pre">"xyz_room"</span></code> and
<codeclass="docutils literal notranslate"><spanclass="pre">"xyz_exit"</span></code> - use these as <codeclass="docutils literal notranslate"><spanclass="pre">prototype_parent</span></code> to add your own custom prototypes.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">"prototypes"</span></code> key of the XYMap-data dict allows you to customize which
prototype is used for each coordinate in your XYMap. The coordinate is given as
<codeclass="docutils literal notranslate"><spanclass="pre">(X,</span><spanclass="pre">Y)</span></code> for nodes/rooms and <codeclass="docutils literal notranslate"><spanclass="pre">(X,</span><spanclass="pre">Y,</span><spanclass="pre">direction)</span></code> for links/exits, where the
direction is one of “n”, “ne”, “e”, “se”, “s”, “sw”, “w”, “nw”, “u” or “d”. For
exits, it’s recommended to <em>not</em> set a <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code> since this is generated
automatically by the grid spawner to be as expected (“north” with alias “n”, for
example).</p>
<p>A special coordinate is <codeclass="docutils literal notranslate"><spanclass="pre">*</span></code>. This acts as a wild card for that coordinate and
allows you to add ‘default’ prototypes to be used for rooms.</p>
<spanclass="s2">"key"</span><spanclass="p">:</span><spanclass="s2">"End of a the tunnel"</span><spanclass="p">,</span>
<spanclass="s2">"desc"</span><spanclass="p">:</span><spanclass="s2">"This is is the end of the dark tunnel. It smells of sewage."</span>
<p>When spawning the above map, the room at the bottom-left and top-right of the
map will get custom descriptions and names, while the others will have default
values. One exit (the east exit out of the room in the bottom-left will have a
custom description.</p>
<blockquote>
<div><p>If you are used to using prototypes, you may notice that we didn’t add a
<codeclass="docutils literal notranslate"><spanclass="pre">prototype_key</span></code> for the above prototypes. This is normally required for every
prototype. This is for convenience - if
you don’t add a <codeclass="docutils literal notranslate"><spanclass="pre">prototype_key</span></code>, the grid will automatically generate one for
you - a hash based on the current XYZ (+ direction) of the node/link to spawn.</p>
</div></blockquote>
<p>If you find yourself changing your prototypes after already spawning the
grid/map, you can rerun <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code> again; The changes will be
picked up and applied to the existing objects.</p>
<sectionid="extending-the-base-prototypes">
<h4>Extending the base prototypes<aclass="headerlink"href="#extending-the-base-prototypes"title="Permalink to this headline">¶</a></h4>
<p>The default prototypes are found in <codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.grid.xyzgrid.prototypes</span></code> and
should be included as <codeclass="docutils literal notranslate"><spanclass="pre">prototype_parents</span></code> for prototypes on the map. Would it
not be nice to be able to change these and have the change apply to all of the
grid? You can, by adding the following to your <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf/settings.py</span></code>:</p>
<div><p>If you override the typeclass in your prototypes, the typeclass used <strong>MUST</strong>
inherit from <codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code> and/or <codeclass="docutils literal notranslate"><spanclass="pre">XYZExit</span></code>. The <codeclass="docutils literal notranslate"><spanclass="pre">BASE_ROOM_TYPECLASS</span></code> and
<codeclass="docutils literal notranslate"><spanclass="pre">BASE_EXIT_TYPECLASS</span></code> settings will not help - these are still useful for
non-xyzgrid rooms/exits though.</p>
</div></blockquote>
<p>Only add what you want to change - these dicts will <em>extend</em> the default parent
prototypes rather than replace them. As long as you define your map’s prototypes
to use a <codeclass="docutils literal notranslate"><spanclass="pre">prototype_parent</span></code> of <codeclass="docutils literal notranslate"><spanclass="pre">"xyz_room"</span></code> and/or <codeclass="docutils literal notranslate"><spanclass="pre">"xyz_exit"</span></code>, your changes
will now be applied. You may need to respawn your grid and reload the server
after a change like this.</p>
</section>
</section>
<sectionid="options">
<h3>Options<aclass="headerlink"href="#options"title="Permalink to this headline">¶</a></h3>
<p>The last element of the <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code> dict is the <codeclass="docutils literal notranslate"><spanclass="pre">"options"</span></code>, for example</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">options</span></code> dict is passed as <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code> to <codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom.return_appearance</span></code>
when visualizing the map in-game. It allows for making different maps display
differently from one another (note that while these options are convenient one
could of course also override <codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code> entirely by inheriting from
<codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code> and then pointing to it in your prototypes).</p>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_display</span></code> (bool): This turns off the display entirely for this map.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_character_symbol</span></code> (str): The symbol used to show ‘you’ on the map. It can
have colors but should only take up one character space. By default this is a
green <codeclass="docutils literal notranslate"><spanclass="pre">@</span></code>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_visual_range</span></code> (int): This how far away from your current location you can
see.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_mode</span></code> (str): This is either “node” or “scan” and affects how the visual
range is calculated.
In “node” mode, the range shows how many <em>nodes</em> away from that you can see. In “scan”
mode you can instead see that many <em>on-screen characters</em> away from your character.
To visualize, assume this is the full map (where ‘@’ is the character location):</p>
<p>This is what the player will see in ‘nodes’ mode with <codeclass="docutils literal notranslate"><spanclass="pre">map_visual_range=2</span></code>:</p>
<p>The ‘nodes’ mode has the advantage of showing only connected links and is
great for navigation but depending on the map it can include nodes quite
visually far away from you. The ‘scan’ mode can accidentally reveal unconnected
parts of the map (see example above), but limiting the range can be used as a
way to hide information.</p>
<p>This is what the player will see in ‘nodes’ mode with <codeclass="docutils literal notranslate"><spanclass="pre">map_visual_range=1</span></code>:</p>
<p>One could for example use ‘nodes’ for outdoor/town maps and ‘scan’ for
exploring dungeons.</p>
</li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_align</span></code> (str): One of ‘r’, ‘c’ or ‘l’. This shifts the map relative to
the room text. By default it’s centered.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_target_path_style</span></code>: How to visualize the path to a target. This is a
string that takes the <codeclass="docutils literal notranslate"><spanclass="pre">{display_symbol}</span></code> formatting tag. This will be replaced
with the <codeclass="docutils literal notranslate"><spanclass="pre">display_symbol</span></code> of each map element in the path. By default this is
<codeclass="docutils literal notranslate"><spanclass="pre">"|y{display_symbol}|n"</span></code>, that is, the path is colored yellow.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_fill_all</span></code> (bool): If the map area should fill the entire client width
(default) or change to always only be as wide as the room description. Note
that in the latter case, the map can end up ‘dancing around’ in the client window
if descriptions vary a lot in width.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">map_separator_char</span></code> (str): The char to use for the separator-lines between the map
and the room description. Defaults to <codeclass="docutils literal notranslate"><spanclass="pre">"|x~|n"</span></code> - wavy, dark-grey lines.</p></li>
</ul>
<p>Changing the options of an already spawned map does not require re-spawning the
map, but you <em>do</em> need to reload the server!</p>
</section>
<sectionid="about-the-pathfinder">
<h3>About the Pathfinder<aclass="headerlink"href="#about-the-pathfinder"title="Permalink to this headline">¶</a></h3>
<p>The new <codeclass="docutils literal notranslate"><spanclass="pre">goto</span></code> command exemplifies the use of the <em>Pathfinder</em>. This
is an algorithm that calculates the shortest route between nodes (rooms) on an
XY-map of arbitrary size and complexity. It allows players to quickly move to
a location if they know that location’s name. Here are some details about</p>
<ulclass="simple">
<li><p>The pathfinder parses the nodes and links to build a matrix of distances
of moving from each node to <em>all</em> other nodes on one XYMap. The path
<li><p>The pathfinder’s matrices can take a long time to build for very large maps.
Therefore they are are cached as pickled binary files in
<codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/.cache/</span></code> and only rebuilt if the map changes. They are safe to
delete (you can also use <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">initpath</span></code> to force-create/rebuild the cache files).</p></li>
<li><p>Once cached, the pathfinder is fast (Finding a 500-step shortest-path over
20 000 nodes/rooms takes below 0.1s).</p></li>
<li><p>It’s important to remember that the pathfinder only works within <em>one</em> XYMap.
It will not find paths across map transitions. If this is a concern, one can consider
making all regions of the game as one XYMap. This probably works fine, but makes it
harder to add/remove new maps to/from the grid.</p></li>
<li><p>The pathfinder will actually sum up the ‘weight’ of each link to determine which is
the ‘cheapest’ (shortest) route. By default every link except blocking links have
a cost of 1 (so cost is equal to the number of steps to move between nodes).
Individual links can however change this to a higher/lower weight (must be >=1).
A higher weight means the pathfinder will be less likely to use that route
compared to others (this can also be vidually confusing for the user, so use with care).</p></li>
<li><p>The pathfinder will <em>average</em> the weight of long link-chains. Since all links
default to having the same weight (=1), this means that
<codeclass="docutils literal notranslate"><spanclass="pre">#-#</span></code> has the same movement cost as <codeclass="docutils literal notranslate"><spanclass="pre">#----#</span></code> even though it is visually ‘shorter’.
This behavior can be changed per-link by using links with
<h2>XYZGrid<aclass="headerlink"href="#id1"title="Permalink to this headline">¶</a></h2>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">XYZGrid</span></code> is a <aclass="reference internal"href="../Components/Scripts.html"><spanclass="doc std std-doc">Global Script</span></a> that holds all <codeclass="docutils literal notranslate"><spanclass="pre">XYMap</span></code> objects on
the grid. There should be only one XYZGrid created at any time.</p>
<p>To access the grid in-code, there are several ways:</p>
<ul>
<li><p>You can search for the grid like any other Script. It’s named “XYZGrid”.</p>
<p>grid = evennia.search_script(“XYZGrid”)[0]</p>
<p>(<codeclass="docutils literal notranslate"><spanclass="pre">search_script</span></code> always returns a list)</p>
</li>
<li><p>You can get it with <codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.grid.xyzgrid.xyzgrid.get_xyzgrid</span></code></p>
<p>This will <em>always</em> return a grid, creating an empty grid if one didn’t
previously exist. So this is also the recommended way of creating a fresh grid
in-code.</p>
</li>
<li><p>You can get it from an existing XYZRoom/Exit by accessing their <codeclass="docutils literal notranslate"><spanclass="pre">.xyzgrid</span></code>
property</p>
<p>grid = self.caller.location.xyzgrid # if currently in grid room</p>
</li>
</ul>
<p>Most tools on the grid class have to do with loading/adding and deleting maps,
something you are expected to use the <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span></code> commands for. But there
are also several methods that are generally useful:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.get_room(xyz)</span></code> - Get a room at a specific coordinate <codeclass="docutils literal notranslate"><spanclass="pre">(X,</span><spanclass="pre">Y,</span><spanclass="pre">Z)</span></code>. This will
only work if the map has been actually spawned first. For example
<codeclass="docutils literal notranslate"><spanclass="pre">.get_room((0,4,"the</span><spanclass="pre">dark</span><spanclass="pre">castle))</span></code>. Use <codeclass="docutils literal notranslate"><spanclass="pre">'*'</span></code> as a wild card, so
<codeclass="docutils literal notranslate"><spanclass="pre">.get_room(('*','*',"the</span><spanclass="pre">dark</span><spanclass="pre">castle))</span></code> will get you all rooms spawned on the dark
castle map.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.get_exit(xyz,</span><spanclass="pre">name)</span></code> - get a particular exit, e.g.
<codeclass="docutils literal notranslate"><spanclass="pre">.get_exit((0,4,"the</span><spanclass="pre">dark</span><spanclass="pre">castle",</span><spanclass="pre">"north")</span></code>. You can also use <codeclass="docutils literal notranslate"><spanclass="pre">'*'</span></code> as
wildcards.</p></li>
</ul>
<p>One can also access particular parsed <codeclass="docutils literal notranslate"><spanclass="pre">XYMap</span></code> objects on the <codeclass="docutils literal notranslate"><spanclass="pre">XYZGrid</span></code> directly:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.grid</span></code> - this is the actual (cached) store of all XYMaps, as <codeclass="docutils literal notranslate"><spanclass="pre">{zcoord:</span><spanclass="pre">XYMap,</span><spanclass="pre">...}</span></code></p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.get_map(zcoord)</span></code> - get a specific XYMap.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.all_maps()</span></code> - get a list of all XYMaps.</p></li>
</ul>
<p>Unless you want to heavily change how the map works (or learn what it does), you
will probably never need to modify the <codeclass="docutils literal notranslate"><spanclass="pre">XYZMap</span></code> object itself. You may want to
<p>See the <aclass="reference internal"href="../api/evennia.contrib.grid.xyzgrid.commands.html#evennia.contrib.grid.xyzgrid.commands.PathData.xymap"title="evennia.contrib.grid.xyzgrid.commands.PathData.xymap"><spanclass="xref myst py py-attr">XYMap</span></a> documentation for
details.</p>
</section>
<sectionid="xyzroom-and-xyzexit">
<h2>XYZRoom and XYZExit<aclass="headerlink"href="#xyzroom-and-xyzexit"title="Permalink to this headline">¶</a></h2>
<p>These are new custom <aclass="reference internal"href="../Components/Typeclasses.html"><spanclass="doc std std-doc">Typeclasses</span></a> located in
<codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.xyzgrid.xyzroom</span></code>. They extend the base <codeclass="docutils literal notranslate"><spanclass="pre">DefaultRoom</span></code> and
<codeclass="docutils literal notranslate"><spanclass="pre">DefaultExit</span></code> to be aware of their <codeclass="docutils literal notranslate"><spanclass="pre">X</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">Y</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">Z</span></code> coordinates.</p>
<divclass="admonition warning">
<pclass="admonition-title">Warning</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>You should usually **not** create XYZRooms/Exits manually. They are intended
to be created/deleted based on the layout of the grid. So to add a new room, add
a new node to your map. To delete it, you remove it. Then rerun
**evennia xyzgrid spawn**. Having manually created XYZRooms/exits in the mix
can lead to them getting deleted or the system getting confused.
If you **still** want to create XYZRoom/Exits manually (don't say we didn't
warn you!), you should do it with their `XYZRoom.create()` and
`XYZExit.create()` methods. This makes sure the XYZ they use are unique.
</pre></div>
</div>
</div>
<p>Useful (extra) properties on <codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">XYZExit</span></code>:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">xyz</span></code> The <codeclass="docutils literal notranslate"><spanclass="pre">(X,</span><spanclass="pre">Y,</span><spanclass="pre">Z)</span></code> coordinate of the entity, for example <codeclass="docutils literal notranslate"><spanclass="pre">(23,</span><spanclass="pre">1,</span><spanclass="pre">"greenforest")</span></code></p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">xyzmap</span></code> The <codeclass="docutils literal notranslate"><spanclass="pre">XYMap</span></code> this belongs to.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_display_name(looker)</span></code> - this has been modified to show the coordinates of
the entity as well as the <codeclass="docutils literal notranslate"><spanclass="pre">#dbref</span></code> if you have Builder or higher privileges.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">return_appearance(looker,</span><spanclass="pre">**kwargs)</span></code> - this has been extensively modified for
<codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code>, to display the map. The <codeclass="docutils literal notranslate"><spanclass="pre">options</span></code> given in <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code> will appear
as <codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code> to this method and if you override this you can customize the
map display in depth.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">xyz_destination</span></code> (only for <codeclass="docutils literal notranslate"><spanclass="pre">XYZExits</span></code>) - this gives the xyz-coordinate of
the exit’s destination.</p></li>
</ul>
<p>The coordinates are stored as <aclass="reference internal"href="../Components/Tags.html"><spanclass="doc std std-doc">Tags</span></a> where both rooms and exits tag
<p>You can customize the XYZRoom/Exit by having the grid spawn your own subclasses
of them. To do this you need to override the prototype used to spawn rooms on
the grid. Easiest is to modify the base prototype-parents in settings (see the
<aclass="reference internal"href="#xyzroom-and-xyzexit"><spanclass="std std-doc">XYZRoom and XYZExit</span></a> section above).</p>
</section>
<sectionid="working-with-the-grid">
<h2>Working with the grid<aclass="headerlink"href="#working-with-the-grid"title="Permalink to this headline">¶</a></h2>
<p>The work flow of working with the grid is usually as follows:</p>
<olclass="simple">
<li><p>Prepare a module with a <em>Map String</em>, <em>Map Legend</em>, <em>Prototypes</em> and
<em>Options</em> packaged into a dict <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code>. Include multiple maps per module
by adding several <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA</span></code> to a variable <codeclass="docutils literal notranslate"><spanclass="pre">XYMAP_DATA_LIST</span></code> instead.</p></li>
<li><p>If your map contains <codeclass="docutils literal notranslate"><spanclass="pre">TransitionMapNodes</span></code>, the target map must either also be
added or already exist in the grid. If not, you should skip that node for
now (otherwise you’ll face errors when spawning because the exit-destination
does not exist).</p></li>
<li><p>Run <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">add</span><spanclass="pre"><module></span></code> to register the maps with the grid. If no
grid existed, it will be created by this. Fix any errors reported by the
parser.</p></li>
<li><p>Inspect the parsed map(s) with <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">show</span><spanclass="pre"><zcoord></span></code> and make sure
they look okay.</p></li>
<li><p>Run <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code> to spawn/update maps into actual <codeclass="docutils literal notranslate"><spanclass="pre">XYZRoom</span></code>s and
<li><p>If you want you can now tweak your grid manually by usual building commands.
Anything you do <em>not</em> specify in your grid prototypes you can
modify locally in your game - as long as the whole room/exit is not deleted,
those will be untouched by <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code>. You can also dig/open
exits to other rooms ‘embedded’ in your grid. These exits must <em>not</em> be named
one of the grid directions (north, northeast, etc, nor up/down) or the grid
will delete it next <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code> runs (since it’s not on the map).</p></li>
<li><p>If you want to add new grid-rooms/exits you should <em>always</em> do so by
modifying the <em>Map String</em> and then rerunning <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">spawn</span></code> to
apply the changes.</p></li>
</ol>
</section>
<sectionid="details">
<h2>Details<aclass="headerlink"href="#details"title="Permalink to this headline">¶</a></h2>
<p>The default Evennia’s rooms are non-euclidian - they can connect
to each other with any types of exits without necessarily having a clear
position relative to each other. This gives maximum flexibility, but many games
want to use cardinal movements (north, east etc) and also features like finding
the shortest-path between two points.</p>
<p>This contrib forces each room to exist on a 3-dimensional XYZ grid and also
implements very efficient pathfinding along with tools for displaying
your current visual-range and a lot of related features.</p>
<p>The rooms of the grid are entirely controlled from outside the game, using
python modules with strings and dicts defining the map(s) of the game. It’s
possible to combine grid- with non-grid rooms, and you can decorate
grid rooms as much as you like in-game, but you cannot spawn new grid
rooms without editing the map files outside of the game.</p>
</section>
<sectionid="id2">
<h2>Installation<aclass="headerlink"href="#id2"title="Permalink to this headline">¶</a></h2>
<ol>
<li><p>If you haven’t before, install the extra contrib requirements.
You can do so by doing <codeclass="docutils literal notranslate"><spanclass="pre">pip</span><spanclass="pre">install</span><spanclass="pre">evennia[extra]</span></code>, or if you used <codeclass="docutils literal notranslate"><spanclass="pre">git</span></code> to
install, do <codeclass="docutils literal notranslate"><spanclass="pre">pip</span><spanclass="pre">install</span><spanclass="pre">--upgrade</span><spanclass="pre">-e</span><spanclass="pre">.[extra]</span></code> from the <codeclass="docutils literal notranslate"><spanclass="pre">evennia/</span></code> repo
<li><p>Import and add the <codeclass="docutils literal notranslate"><spanclass="pre">evennia.contrib.grid.xyzgrid.commands.XYZGridCmdSet</span></code> to the
<codeclass="docutils literal notranslate"><spanclass="pre">CharacterCmdset</span></code> cmdset in <codeclass="docutils literal notranslate"><spanclass="pre">mygame/commands.default_cmds.py</span></code>. Reload
the server. This makes the <codeclass="docutils literal notranslate"><spanclass="pre">map</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">goto/path</span></code> and modified <codeclass="docutils literal notranslate"><spanclass="pre">teleport</span></code> and
<codeclass="docutils literal notranslate"><spanclass="pre">open</span></code> commands available in-game.</p></li>
<li><p>Edit <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf/settings.py</span></code> and set</p>
<li><p>Run the new <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">xyzgrid</span><spanclass="pre">help</span></code> for instructions on how to spawn the grid.</p></li>
</ol>
</section>
<sectionid="example-usage">
<h2>Example usage<aclass="headerlink"href="#example-usage"title="Permalink to this headline">¶</a></h2>
<p>After installation, do the following (from your command line, where the
<codeclass="docutils literal notranslate"><spanclass="pre">evennia</span></code> command is available) to install an example grid:</p>
<p>(remember to reload the server after spawn operations).</p>
<p>Now you can log into the
server and do <codeclass="docutils literal notranslate"><spanclass="pre">teleport</span><spanclass="pre">(3,0,the</span><spanclass="pre">large</span><spanclass="pre">tree)</span></code> to teleport into the map.</p>
<p>You can use <codeclass="docutils literal notranslate"><spanclass="pre">open</span><spanclass="pre">togrid</span><spanclass="pre">=</span><spanclass="pre">(3,</span><spanclass="pre">0,</span><spanclass="pre">the</span><spanclass="pre">large</span><spanclass="pre">tree)</span></code> to open a permanent (one-way)
exit from your current location into the grid. To make a way back to a non-grid
location just stand in a grid room and open a new exit out of it:
<p>Try <codeclass="docutils literal notranslate"><spanclass="pre">goto</span><spanclass="pre">view</span></code> to go to the top of the tree and <codeclass="docutils literal notranslate"><spanclass="pre">goto</span><spanclass="pre">dungeon</span></code> to go down to
the dungeon entrance at the bottom of the tree.</p>
<hrclass="docutils"/>
<p><small>This document page is generated from <codeclass="docutils literal notranslate"><spanclass="pre">evennia/contrib/grid/xyzgrid/README.md</span></code>. Changes to this
file will be overwritten, so edit that file rather than this one.</small></p>