mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
501 lines
No EOL
44 KiB
HTML
501 lines
No EOL
44 KiB
HTML
|
||
<!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>Building a train that moves — Evennia latest 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="Making a Persistent object Handler" href="Tutorial-Persistent-Handler.html" />
|
||
<link rel="prev" title="Building a giant mech" href="Tutorial-Building-a-Mech.html" />
|
||
</head><body>
|
||
|
||
|
||
|
||
|
||
<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="Tutorial-Persistent-Handler.html" title="Making a Persistent object Handler"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Tutorial-Building-a-Mech.html" title="Building a giant mech"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" accesskey="U">Tutorials and How-To’s</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Building a train that moves</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="#">Building a train that moves</a><ul>
|
||
<li><a class="reference internal" href="#creating-our-train-object">Creating our train object</a></li>
|
||
<li><a class="reference internal" href="#entering-and-leaving-the-train">Entering and leaving the train</a></li>
|
||
<li><a class="reference internal" href="#locking-down-the-commands">Locking down the commands</a></li>
|
||
<li><a class="reference internal" href="#making-our-train-move">Making our train move</a></li>
|
||
<li><a class="reference internal" href="#adding-in-scripts">Adding in scripts</a></li>
|
||
<li><a class="reference internal" href="#expanding">Expanding</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Tutorial-Building-a-Mech.html"
|
||
title="previous chapter">Building a giant mech</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Tutorial-Persistent-Handler.html"
|
||
title="next chapter">Making a Persistent object Handler</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Howtos/Tutorial-Building-a-Train.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>
|
||
<h3>Doc Versions</h3>
|
||
<ul>
|
||
|
||
<li><a href="Tutorial-Building-a-Train.html">latest (main branch)</a></li>
|
||
|
||
<li><a href="../../3.x/index.html">v3.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../../2.x/index.html">v2.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../../1.x/index.html">v1.0.0 branch (outdated)</a></li>
|
||
|
||
<li><a href="../../0.x/index.html">v0.9.5 branch (outdated)</a></li>
|
||
|
||
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="building-a-train-that-moves">
|
||
<h1>Building a train that moves<a class="headerlink" href="#building-a-train-that-moves" title="Permalink to this headline">¶</a></h1>
|
||
<blockquote>
|
||
<div><p>TODO: This should be updated for latest Evennia use.</p>
|
||
</div></blockquote>
|
||
<p>Vehicles are things that you can enter and then move around in your game world. Here we’ll explain how to create a train, but this can be equally applied to create other kind of vehicles
|
||
(cars, planes, boats, spaceships, submarines, …).</p>
|
||
<p>Objects in Evennia have an interesting property: you can put any object inside another object. This is most obvious in rooms: a room in Evennia is just like any other game object (except rooms tend to not themselves be inside anything else).</p>
|
||
<p>Our train will be similar: it will be an object that other objects can get inside. We then simply
|
||
move the Train, which brings along everyone inside it.</p>
|
||
<section id="creating-our-train-object">
|
||
<h2>Creating our train object<a class="headerlink" href="#creating-our-train-object" title="Permalink to this headline">¶</a></h2>
|
||
<p>The first step we need to do is create our train object, including a new typeclass. To do this,
|
||
create a new file, for instance in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/train.py</span></code> with the following content:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/train.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TrainObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># We'll add in code here later.</span>
|
||
<span class="k">pass</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Now we can create our train in our game:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">create</span><span class="o">/</span><span class="n">drop</span> <span class="n">train</span><span class="p">:</span><span class="n">train</span><span class="o">.</span><span class="n">TrainObject</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Now this is just an object that doesn’t do much yet… but we can already force our way inside it
|
||
and back (assuming we created it in limbo).</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">tel</span> <span class="n">train</span>
|
||
<span class="n">tel</span> <span class="n">limbo</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="entering-and-leaving-the-train">
|
||
<h2>Entering and leaving the train<a class="headerlink" href="#entering-and-leaving-the-train" title="Permalink to this headline">¶</a></h2>
|
||
<p>Using the <code class="docutils literal notranslate"><span class="pre">tel</span></code>command like shown above is obviously not what we want. <code class="docutils literal notranslate"><span class="pre">@tel</span></code> is an admin command and normal players will thus never be able to enter the train!</p>
|
||
<p>It is also not really a good idea to use <span class="xref myst">Exits</span> to get in and out of the train - Exits are (at least by default) objects too. They point to a specific destination. If we put an Exit in this room leading inside the train it would stay here when the train moved away (still leading into the train like a magic portal!). In the same way, if we put an Exit object inside the train, it would always point back to this room, regardless of where the Train has moved.</p>
|
||
<p>Now, one <em>could</em> define custom Exit types that move with the train or change their destination in the right way - but this seems to be a pretty cumbersome solution.</p>
|
||
<p>What we will do instead is to create some new <a class="reference internal" href="../Components/Commands.html"><span class="doc std std-doc">commands</span></a>: one for entering the train and
|
||
another for leaving it again. These will be stored <em>on the train object</em> and will thus be made
|
||
available to whomever is either inside it or in the same room as the train.</p>
|
||
<p>Let’s create a new command module as <code class="docutils literal notranslate"><span class="pre">mygame/commands/train.py</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/commands/train.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span><span class="p">,</span> <span class="n">CmdSet</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CmdEnterTrain</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> entering the train</span>
|
||
<span class="sd"> </span>
|
||
<span class="sd"> Usage:</span>
|
||
<span class="sd"> enter train</span>
|
||
|
||
<span class="sd"> This will be available to players in the same location</span>
|
||
<span class="sd"> as the train and allows them to embark. </span>
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"enter train"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">train</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"You board the train."</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">move_to</span><span class="p">(</span><span class="n">train</span><span class="p">,</span> <span class="n">move_type</span><span class="o">=</span><span class="s2">"board"</span><span class="p">)</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">CmdLeaveTrain</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> leaving the train </span>
|
||
<span class="sd"> </span>
|
||
<span class="sd"> Usage:</span>
|
||
<span class="sd"> leave train</span>
|
||
|
||
<span class="sd"> This will be available to everyone inside the </span>
|
||
<span class="sd"> train. It allows them to exit to the train's</span>
|
||
<span class="sd"> current location. </span>
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"leave train"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">train</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span>
|
||
<span class="n">parent</span> <span class="o">=</span> <span class="n">train</span><span class="o">.</span><span class="n">location</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">move_to</span><span class="p">(</span><span class="n">parent</span><span class="p">,</span> <span class="n">move_type</span><span class="o">=</span><span class="s2">"disembark"</span><span class="p">)</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">CmdSetTrain</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdEnterTrain</span><span class="p">())</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdLeaveTrain</span><span class="p">())</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that while this seems like a lot of text, the majority of lines here are taken up by
|
||
documentation.</p>
|
||
<p>These commands are work in a pretty straightforward way: <code class="docutils literal notranslate"><span class="pre">CmdEnterTrain</span></code> moves the location of the player to inside the train and <code class="docutils literal notranslate"><span class="pre">CmdLeaveTrain</span></code> does the opposite: it moves the player back to the
|
||
current location of the train (back outside to its current location). We stacked them in a <a class="reference internal" href="../Components/Command-Sets.html"><span class="doc std std-doc">cmdset</span></a> <code class="docutils literal notranslate"><span class="pre">CmdSetTrain</span></code> so they can be used.</p>
|
||
<p>To make the commands work we need to add this cmdset to our train typeclass:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/typeclasses/train.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">commands.train</span> <span class="kn">import</span> <span class="n">CmdSetTrain</span>
|
||
<span class="kn">from</span> <span class="nn">typeclasses.objects</span> <span class="kn">import</span> <span class="n">Object</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TrainObject</span><span class="p">(</span><span class="n">Object</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add_default</span><span class="p">(</span><span class="n">CmdSetTrain</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>If we now <code class="docutils literal notranslate"><span class="pre">reload</span></code> our game and reset our train, those commands should work and we can now enter and leave the train:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">reload</span>
|
||
<span class="n">typeclass</span><span class="o">/</span><span class="n">force</span><span class="o">/</span><span class="n">reset</span> <span class="n">train</span> <span class="o">=</span> <span class="n">train</span><span class="o">.</span><span class="n">TrainObject</span>
|
||
<span class="n">enter</span> <span class="n">train</span>
|
||
<span class="n">leave</span> <span class="n">train</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note the switches used with the <code class="docutils literal notranslate"><span class="pre">typeclass</span></code> command: The <code class="docutils literal notranslate"><span class="pre">/force</span></code> switch is necessary to assign our object the same typeclass we already have. The <code class="docutils literal notranslate"><span class="pre">/reset</span></code> re-triggers the typeclass’ <code class="docutils literal notranslate"><span class="pre">at_object_creation()</span></code> hook (which is otherwise only called the very first an instance is created).
|
||
As seen above, when this hook is called on our train, our new cmdset will be loaded.</p>
|
||
</section>
|
||
<section id="locking-down-the-commands">
|
||
<h2>Locking down the commands<a class="headerlink" href="#locking-down-the-commands" title="Permalink to this headline">¶</a></h2>
|
||
<p>If you have played around a bit, you’ve probably figured out that you can use <code class="docutils literal notranslate"><span class="pre">leave</span> <span class="pre">train</span></code> when
|
||
outside the train and <code class="docutils literal notranslate"><span class="pre">enter</span> <span class="pre">train</span></code> when inside. This doesn’t make any sense … so let’s go ahead
|
||
and fix that. We need to tell Evennia that you can not enter the train when you’re already inside
|
||
or leave the train when you’re outside. One solution to this is <a class="reference internal" href="../Components/Locks.html"><span class="doc std std-doc">locks</span></a>: we will lock down the commands so that they can only be called if the player is at the correct location.</p>
|
||
<p>Since we didn’t set a <code class="docutils literal notranslate"><span class="pre">lock</span></code> property on the Command, it defaults to <code class="docutils literal notranslate"><span class="pre">cmd:all()</span></code>. This means that everyone can use the command as long as they are in the same room <em>or inside the train</em>.</p>
|
||
<p>First of all we need to create a new lock function. Evennia comes with many lock functions built-in
|
||
already, but none that we can use for locking a command in this particular case. Create a new entry in <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/lockfuncs.py</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="c1"># file mygame/server/conf/lockfuncs.py</span>
|
||
|
||
<span class="k">def</span> <span class="nf">cmdinside</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Usage: cmdinside() </span>
|
||
<span class="sd"> Used to lock commands and only allows access if the command</span>
|
||
<span class="sd"> is defined on an object which accessing_obj is inside of. </span>
|
||
<span class="sd"> """</span>
|
||
<span class="k">return</span> <span class="n">accessed_obj</span><span class="o">.</span><span class="n">obj</span> <span class="o">==</span> <span class="n">accessing_obj</span><span class="o">.</span><span class="n">location</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>If you didn’t know, Evennia is by default set up to use all functions in this module as lock
|
||
functions (there is a setting variable that points to it).</p>
|
||
<p>Our new lock function, <code class="docutils literal notranslate"><span class="pre">cmdinside</span></code>, is to be used by Commands. The <code class="docutils literal notranslate"><span class="pre">accessed_obj</span></code> is the Command object (in our case this will be <code class="docutils literal notranslate"><span class="pre">CmdEnterTrain</span></code> and <code class="docutils literal notranslate"><span class="pre">CmdLeaveTrain</span></code>) — Every command has an <code class="docutils literal notranslate"><span class="pre">obj</span></code> property: this is the the object on which the command “sits”. Since we added those commands to our train object, the <code class="docutils literal notranslate"><span class="pre">.obj</span></code> property will be set to the train object. Conversely, <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> is the object that called the command: in our case it’s the Character trying to enter or leave the train.</p>
|
||
<p>What this function does is to check that the player’s location is the same as the train object. If
|
||
it is, it means the player is inside the train. Otherwise it means the player is somewhere else and
|
||
the check will fail.</p>
|
||
<p>The next step is to actually use this new lock function to create a lock of type <code class="docutils literal notranslate"><span class="pre">cmd</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file commands/train.py</span>
|
||
<span class="o">...</span>
|
||
<span class="k">class</span> <span class="nc">CmdEnterTrain</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"enter train"</span>
|
||
<span class="n">locks</span> <span class="o">=</span> <span class="s2">"cmd:not cmdinside()"</span>
|
||
<span class="c1"># ...</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CmdLeaveTrain</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"leave train"</span>
|
||
<span class="n">locks</span> <span class="o">=</span> <span class="s2">"cmd:cmdinside()"</span>
|
||
<span class="c1"># ...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Notice how we use the <code class="docutils literal notranslate"><span class="pre">not</span></code> here so that we can use the same <code class="docutils literal notranslate"><span class="pre">cmdinside</span></code> to check if we are inside
|
||
and outside, without having to create two separate lock functions. After a <code class="docutils literal notranslate"><span class="pre">@reload</span></code> our commands
|
||
should be locked down appropriately and you should only be able to use them at the right places.</p>
|
||
<blockquote>
|
||
<div><p>Note: If you’re logged in as the super user (user <code class="docutils literal notranslate"><span class="pre">#1</span></code>) then this lock will not work: the super
|
||
user ignores lock functions. In order to use this functionality you need to <code class="docutils literal notranslate"><span class="pre">@quell</span></code> first.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="making-our-train-move">
|
||
<h2>Making our train move<a class="headerlink" href="#making-our-train-move" title="Permalink to this headline">¶</a></h2>
|
||
<p>Now that we can enter and leave the train correctly, it’s time to make it move. There are different
|
||
things we need to consider for this:</p>
|
||
<ul class="simple">
|
||
<li><p>Who can control your vehicle? The first player to enter it, only players that have a certain “drive” skill, automatically?</p></li>
|
||
<li><p>Where should it go? Can the player steer the vehicle to go somewhere else or will it always follow the same route?</p></li>
|
||
</ul>
|
||
<p>For our example train we’re going to go with automatic movement through a predefined route (its track). The train will stop for a bit at the start and end of the route to allow players to enter and leave it.</p>
|
||
<p>Go ahead and create some rooms for our train. Make a list of the room ids along the route (using the <code class="docutils literal notranslate"><span class="pre">xe</span></code> command).</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">></span> <span class="n">dig</span><span class="o">/</span><span class="n">tel</span> <span class="n">South</span> <span class="n">station</span>
|
||
<span class="o">></span> <span class="n">ex</span> <span class="c1"># note the id of the station</span>
|
||
<span class="o">></span> <span class="n">tunnel</span><span class="o">/</span><span class="n">tel</span> <span class="n">n</span> <span class="o">=</span> <span class="n">Following</span> <span class="n">a</span> <span class="n">railroad</span>
|
||
<span class="o">></span> <span class="n">ex</span> <span class="c1"># note the id of the track</span>
|
||
<span class="o">></span> <span class="n">tunnel</span><span class="o">/</span><span class="n">tel</span> <span class="n">n</span> <span class="o">=</span> <span class="n">Following</span> <span class="n">a</span> <span class="n">railroad</span>
|
||
<span class="o">></span> <span class="o">...</span>
|
||
<span class="o">></span> <span class="n">tunnel</span><span class="o">/</span><span class="n">tel</span> <span class="n">n</span> <span class="o">=</span> <span class="n">North</span> <span class="n">Station</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Put the train onto the tracks:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">tel</span> <span class="n">south</span> <span class="n">station</span>
|
||
<span class="n">tel</span> <span class="n">train</span> <span class="o">=</span> <span class="n">here</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Next we will tell the train how to move and which route to take.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file typeclasses/train.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span><span class="p">,</span> <span class="n">search_object</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">commands.train</span> <span class="kn">import</span> <span class="n">CmdSetTrain</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TrainObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add_default</span><span class="p">(</span><span class="n">CmdSetTrain</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">driving</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="c1"># The direction our train is driving (1 for forward, -1 for backwards)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">direction</span> <span class="o">=</span> <span class="mi">1</span>
|
||
<span class="c1"># The rooms our train will pass through (change to fit your game)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">rooms</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"#2"</span><span class="p">,</span> <span class="s2">"#47"</span><span class="p">,</span> <span class="s2">"#50"</span><span class="p">,</span> <span class="s2">"#53"</span><span class="p">,</span> <span class="s2">"#56"</span><span class="p">,</span> <span class="s2">"#59"</span><span class="p">]</span>
|
||
|
||
<span class="k">def</span> <span class="nf">start_driving</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">driving</span> <span class="o">=</span> <span class="kc">True</span>
|
||
|
||
<span class="k">def</span> <span class="nf">stop_driving</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">driving</span> <span class="o">=</span> <span class="kc">False</span>
|
||
|
||
<span class="k">def</span> <span class="nf">goto_next_room</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">currentroom</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">dbref</span>
|
||
<span class="n">idx</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">rooms</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="n">currentroom</span><span class="p">)</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">direction</span>
|
||
|
||
<span class="k">if</span> <span class="n">idx</span> <span class="o"><</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">idx</span> <span class="o">>=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">rooms</span><span class="p">):</span>
|
||
<span class="c1"># We reached the end of our path</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">stop_driving</span><span class="p">()</span>
|
||
<span class="c1"># Reverse the direction of the train</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">direction</span> <span class="o">*=</span> <span class="o">-</span><span class="mi">1</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">roomref</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">rooms</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
|
||
<span class="n">room</span> <span class="o">=</span> <span class="n">search_object</span><span class="p">(</span><span class="n">roomref</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">move_to</span><span class="p">(</span><span class="n">room</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="sa">f</span><span class="s2">"The train is moving forward to </span><span class="si">{</span><span class="n">room</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>We added a lot of code here. Since we changed the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> to add in variables we will have to reset our train object like earlier (using the <code class="docutils literal notranslate"><span class="pre">@typeclass/force/reset</span></code> command).</p>
|
||
<p>We are keeping track of a few different things now: whether the train is moving or standing still,
|
||
which direction the train is heading to and what rooms the train will pass through.</p>
|
||
<p>We also added some methods: one to start moving the train, another to stop and a third that actually moves the train to the next room in the list. Or makes it stop driving if it reaches the last stop.</p>
|
||
<p>Let’s try it out, using <code class="docutils literal notranslate"><span class="pre">py</span></code> to call the new train functionality:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">></span> <span class="n">reload</span>
|
||
<span class="o">></span> <span class="n">typeclass</span><span class="o">/</span><span class="n">force</span><span class="o">/</span><span class="n">reset</span> <span class="n">train</span> <span class="o">=</span> <span class="n">train</span><span class="o">.</span><span class="n">TrainObject</span>
|
||
<span class="o">></span> <span class="n">enter</span> <span class="n">train</span>
|
||
<span class="o">></span> <span class="n">py</span> <span class="n">here</span><span class="o">.</span><span class="n">goto_next_room</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>You should see the train moving forward one step along the rail road.</p>
|
||
</section>
|
||
<section id="adding-in-scripts">
|
||
<h2>Adding in scripts<a class="headerlink" href="#adding-in-scripts" title="Permalink to this headline">¶</a></h2>
|
||
<p>If we wanted full control of the train we could now just add a command to step it along the track when desired. We want the train to move on its own though, without us having to force it by manually calling the <code class="docutils literal notranslate"><span class="pre">goto_next_room</span></code> method.</p>
|
||
<p>To do this we will create two <a class="reference internal" href="../Components/Scripts.html"><span class="doc std std-doc">scripts</span></a>: one script that runs when the train has stopped at
|
||
a station and is responsible for starting the train again after a while. The other script will take
|
||
care of the driving.</p>
|
||
<p>Let’s make a new file in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/trainscript.py</span></code></p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file mygame/typeclasses/trainscript.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TrainStoppedScript</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">"trainstopped"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">30</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">persistent</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">repeats</span> <span class="o">=</span> <span class="mi">1</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">start_delay</span> <span class="o">=</span> <span class="kc">True</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">start_driving</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_stop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">TrainDrivingScript</span><span class="p">)</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">TrainDrivingScript</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">"traindriving"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">1</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">persistent</span> <span class="o">=</span> <span class="kc">True</span>
|
||
|
||
<span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">driving</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">driving</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">goto_next_room</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_stop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">TrainStoppedScript</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Those scripts work as a state system: when the train is stopped, it waits for 30 seconds and then
|
||
starts again. When the train is driving, it moves to the next room every second. The train is always
|
||
in one of those two states - both scripts take care of adding the other one once they are done.</p>
|
||
<p>As a last step we need to link the stopped-state script to our train, reload the game and reset our
|
||
train again., and we’re ready to ride it around!</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># file typeclasses/train.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">typeclasses.trainscript</span> <span class="kn">import</span> <span class="n">TrainStoppedScript</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TrainObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># ...</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">TrainStoppedScript</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">></span> <span class="n">reload</span>
|
||
<span class="o">></span> <span class="n">typeclass</span><span class="o">/</span><span class="n">force</span><span class="o">/</span><span class="n">reset</span> <span class="n">train</span> <span class="o">=</span> <span class="n">train</span><span class="o">.</span><span class="n">TrainObject</span>
|
||
<span class="o">></span> <span class="n">enter</span> <span class="n">train</span>
|
||
|
||
<span class="c1"># output:</span>
|
||
<span class="o"><</span> <span class="n">The</span> <span class="n">train</span> <span class="ow">is</span> <span class="n">moving</span> <span class="n">forward</span> <span class="n">to</span> <span class="n">Following</span> <span class="n">a</span> <span class="n">railroad</span><span class="o">.</span>
|
||
<span class="o"><</span> <span class="n">The</span> <span class="n">train</span> <span class="ow">is</span> <span class="n">moving</span> <span class="n">forward</span> <span class="n">to</span> <span class="n">Following</span> <span class="n">a</span> <span class="n">railroad</span><span class="o">.</span>
|
||
<span class="o"><</span> <span class="n">The</span> <span class="n">train</span> <span class="ow">is</span> <span class="n">moving</span> <span class="n">forward</span> <span class="n">to</span> <span class="n">Following</span> <span class="n">a</span> <span class="n">railroad</span><span class="o">.</span>
|
||
<span class="o">...</span>
|
||
<span class="o"><</span> <span class="n">The</span> <span class="n">train</span> <span class="ow">is</span> <span class="n">moving</span> <span class="n">forward</span> <span class="n">to</span> <span class="n">Following</span> <span class="n">a</span> <span class="n">railroad</span><span class="o">.</span>
|
||
<span class="o"><</span> <span class="n">The</span> <span class="n">train</span> <span class="ow">is</span> <span class="n">moving</span> <span class="n">forward</span> <span class="n">to</span> <span class="n">North</span> <span class="n">station</span><span class="o">.</span>
|
||
|
||
<span class="n">leave</span> <span class="n">train</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Our train will stop 30 seconds at each end station and then turn around to go back to the other end.</p>
|
||
</section>
|
||
<section id="expanding">
|
||
<h2>Expanding<a class="headerlink" href="#expanding" title="Permalink to this headline">¶</a></h2>
|
||
<p>This train is very basic and still has some flaws. Some more things to do:</p>
|
||
<ul class="simple">
|
||
<li><p>Make it look like a train.</p></li>
|
||
<li><p>Make it impossible to exit and enter the train mid-ride. This could be made by having the enter/exit commands check so the train is not moving before allowing the caller to proceed.</p></li>
|
||
<li><p>Have train conductor commands that can override the automatic start/stop.</p></li>
|
||
<li><p>Allow for in-between stops between the start- and end station</p></li>
|
||
<li><p>Have a rail road track instead of hard-coding the rooms in the train object. This could for example be a custom <span class="xref myst">Exit</span> only traversable by trains. The train will follow the track. Some track segments can split to lead to two different rooms and a player can switch the direction to which room it goes.</p></li>
|
||
<li><p>Create another kind of vehicle!</p></li>
|
||
</ul>
|
||
</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="Tutorial-Persistent-Handler.html" title="Making a Persistent object Handler"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Tutorial-Building-a-Mech.html" title="Building a giant mech"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" >Tutorials and How-To’s</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Building a train that moves</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2023, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |