evennia/docs/2.x/Contribs/Contrib-Ingame-Python-Tutorial-Elevator.html

556 lines
44 KiB
HTML
Raw Normal View History

<!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/" />
2023-10-19 20:22:27 +00:00
<title>A voice operated elevator using events &#8212; Evennia 2.x documentation</title>
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
<script src="../_static/jquery.js"></script>
<script src="../_static/underscore.js"></script>
<script src="../_static/doctools.js"></script>
<script src="../_static/language_data.js"></script>
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="Menu-based login system" href="Contrib-Menu-Login.html" />
<link rel="prev" title="Dialogues in events" href="Contrib-Ingame-Python-Tutorial-Dialogue.html" />
</head><body>
2023-10-19 20:22:27 +00:00
<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="Contrib-Menu-Login.html" title="Menu-based login system"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Contrib-Ingame-Python-Tutorial-Dialogue.html" title="Dialogues in events"
accesskey="P">previous</a> |</li>
2023-10-19 20:22:27 +00:00
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" >Contribs</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="Contrib-Ingame-Python.html" accesskey="U">Evennia in-game Python system</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">A voice operated elevator using events</a></li>
</ul>
2023-12-20 18:20:52 +01:00
</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="#">A voice operated elevator using events</a><ul>
<li><a class="reference internal" href="#our-study-case">Our study case</a></li>
<li><a class="reference internal" href="#creating-the-rooms-and-exits-we-need">Creating the rooms and exits we need</a></li>
<li><a class="reference internal" href="#our-first-callback-in-the-elevator">Our first callback in the elevator</a></li>
<li><a class="reference internal" href="#our-entire-callback-in-the-elevator">Our entire callback in the elevator</a></li>
<li><a class="reference internal" href="#adding-a-pause-in-our-callback">Adding a pause in our callback</a></li>
<li><a class="reference internal" href="#changing-exit-messages">Changing exit messages</a></li>
<li><a class="reference internal" href="#tutorial-f-a-q">Tutorial F.A.Q.</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Contrib-Ingame-Python-Tutorial-Dialogue.html"
title="previous chapter">Dialogues in events</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Contrib-Menu-Login.html"
title="next chapter">Menu-based login system</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Contribs/Contrib-Ingame-Python-Tutorial-Elevator.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
2023-10-19 20:22:27 +00:00
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="a-voice-operated-elevator-using-events">
<h1>A voice operated elevator using events<a class="headerlink" href="#a-voice-operated-elevator-using-events" title="Permalink to this headline"></a></h1>
<p>This tutorial will walk you through the steps to create a voice-operated elevator, using the <a class="reference internal" href="Contrib-Ingame-Python.html"><span class="doc std std-doc">in-
game Python system</span></a>. This tutorial assumes the in-game Python
system is installed per the instructions in that doc. <strong>You do not need to read</strong> the entire
documentation, its a good reference, but not the easiest way to learn about it. Hence these
tutorials.</p>
<p>The in-game Python system allows to run code on individual objects in some situations. You dont
have to modify the source code to add these features, past the installation. The entire system
makes it easy to add specific features to some objects, but not all.</p>
<blockquote>
<div><p>What will we try to do?</p>
</div></blockquote>
<p>In this tutorial, we are going to create a simple voice-operated elevator. In terms of features, we
will:</p>
<ul class="simple">
<li><p>Explore events with parameters.</p></li>
<li><p>Work on more interesting callbacks.</p></li>
<li><p>Learn about chained events.</p></li>
<li><p>Play with variable modification in callbacks.</p></li>
</ul>
<section id="our-study-case">
<h2>Our study case<a class="headerlink" href="#our-study-case" title="Permalink to this headline"></a></h2>
<p>Lets summarize what we want to achieve first. We would like to create a room that will represent
the inside of our elevator. In this room, a character could just say “1”, “2” or “3”, and the
elevator will start moving. The doors will close and open on the new floor (the exits leading in
and out of the elevator will be modified).</p>
<p>We will work on basic features first, and then will adjust some, showing you how easy and powerfully
independent actions can be configured through the in-game Python system.</p>
</section>
<section id="creating-the-rooms-and-exits-we-need">
<h2>Creating the rooms and exits we need<a class="headerlink" href="#creating-the-rooms-and-exits-we-need" title="Permalink to this headline"></a></h2>
<p>Well create an elevator right in our room (generally called “Limbo”, of ID 2). You could easily
adapt the following instructions if you already have some rooms and exits, of course, just remember
to check the IDs.</p>
<blockquote>
<div><p>Note: the in-game Python system uses IDs for a lot of things. While it is not mandatory, it is
good practice to know the IDs you have for your callbacks, because it will make manipulation much
quicker. There are other ways to identify objects, but as they depend on many factors, IDs are
usually the safest path in our callbacks.</p>
</div></blockquote>
<p>Lets go into limbo (<code class="docutils literal notranslate"><span class="pre">#2</span></code>) to add our elevator. Well add it to the north. To create this room,
in-game you could type:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>tunnel n = Inside of an elevator
</pre></div>
</div>
<p>The game should respond by telling you:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Created room Inside of an elevator(#3) of type typeclasses.rooms.Room.
Created Exit from Limbo to Inside of an elevator: north(#4) (n).
Created Exit back from Inside of an elevator to Limbo: south(#5) (s).
</pre></div>
</div>
<p>Note the given IDs:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">#2</span></code> is limbo, the first room the system created.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">#3</span></code> is our room inside of an elevator.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">#4</span></code> is the north exit from Limbo to our elevator.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">#5</span></code> is the south exit from an elevator to Limbo.</p></li>
</ul>
<p>Keep these IDs somewhere for the demonstration. You will shortly see why they are important.</p>
<blockquote>
<div><p>Why have we created exits to our elevator and back to Limbo? Isnt the elevator supposed to move?</p>
</div></blockquote>
<p>It is. But we need to have exits that will represent the way inside the elevator and out. What we
will do, at every floor, will be to change these exits so they become connected to the right room.
Youll see this process a bit later.</p>
<p>We have two more rooms to create: our floor 2 and 3. This time, well use <code class="docutils literal notranslate"><span class="pre">dig</span></code>, because we dont
need exits leading there, not yet anyway.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>dig The second floor
dig The third floor
</pre></div>
</div>
<p>Evennia should answer with:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Created room The second floor(#6) of type typeclasses.rooms.Room.
Created room The third floor(#7) of type typeclasses.rooms.Room.
</pre></div>
</div>
<p>Add these IDs to your list, we will use them too.</p>
</section>
<section id="our-first-callback-in-the-elevator">
<h2>Our first callback in the elevator<a class="headerlink" href="#our-first-callback-in-the-elevator" title="Permalink to this headline"></a></h2>
<p>Lets go to the elevator (you could use <code class="docutils literal notranslate"><span class="pre">tel</span> <span class="pre">#3</span></code> if you have the same IDs I have).</p>
<p>This is our elevator room. It looks a bit empty, feel free to add a prettier description or other
things to decorate it a bit.</p>
<p>But what we want now is to be able to say “1”, “2” or “3” and have the elevator move in that
direction.</p>
<p>If you have read
<a class="reference internal" href="Contrib-Ingame-Python-Tutorial-Dialogue.html"><span class="doc std std-doc">the other in-game Python tutorial about adding dialogues in events</span></a>, you
may remember what we need to do. If not, heres a summary: we need to run some code when somebody
speaks in the room. So we need to create a callback (the callback will contain our lines of code).
We just need to know on which event this should be set. You can enter <code class="docutils literal notranslate"><span class="pre">call</span> <span class="pre">here</span></code> to see the
possible events in this room.</p>
<p>In the table, you should see the “say” event, which is called when somebody says something in the
room. So well need to add a callback to this event. Dont worry if youre a bit lost, just follow
the following steps, the way they connect together will become more obvious.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = say 1, 2, 3
</pre></div>
</div>
<ol class="simple">
<li><p>We need to add a callback. A callback contains the code that will be executed at a given time.
So we use the <code class="docutils literal notranslate"><span class="pre">call/add</span></code> command and switch.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">here</span></code> is our object, the room in which we are.</p></li>
<li><p>An equal sign.</p></li>
<li><p>The name of the event to which the callback should be connected. Here, the event is “say”.
Meaning this callback will be executed every time somebody says something in the room.</p></li>
<li><p>But we add an event parameter to indicate the keywords said in the room that should execute our
callback. Otherwise, our callback would be called every time somebody speaks, no matter what. Here
we limit, indicating our callback should be executed only if the spoken message contains “1”, “2” or
“3”.</p></li>
</ol>
<p>An editor should open, inviting you to enter the Python code that should be executed. The first
thing to remember is to read the text provided (it can contain important information) and, most of
all, the list of variables that are available in this callback:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Variables</span> <span class="n">you</span> <span class="n">can</span> <span class="n">use</span> <span class="ow">in</span> <span class="n">this</span> <span class="n">event</span><span class="p">:</span>
<span class="n">character</span><span class="p">:</span> <span class="n">the</span> <span class="n">character</span> <span class="n">having</span> <span class="n">spoken</span> <span class="ow">in</span> <span class="n">this</span> <span class="n">room</span><span class="o">.</span>
<span class="n">room</span><span class="p">:</span> <span class="n">the</span> <span class="n">room</span> <span class="n">connected</span> <span class="n">to</span> <span class="n">this</span> <span class="n">event</span><span class="o">.</span>
<span class="n">message</span><span class="p">:</span> <span class="n">the</span> <span class="n">text</span> <span class="n">having</span> <span class="n">been</span> <span class="n">spoken</span> <span class="n">by</span> <span class="n">the</span> <span class="n">character</span><span class="o">.</span>
<span class="o">----------</span><span class="n">Line</span> <span class="n">Editor</span> <span class="p">[</span><span class="n">Callback</span> <span class="n">say</span> <span class="n">of</span> <span class="n">Inside</span> <span class="n">of</span> <span class="n">an</span> <span class="n">elevator</span><span class="p">]</span><span class="o">---------------------</span>
<span class="mi">01</span><span class="o">|</span>
<span class="o">----------</span><span class="p">[</span><span class="n">l</span><span class="p">:</span><span class="mi">01</span> <span class="n">w</span><span class="p">:</span><span class="mi">000</span> <span class="n">c</span><span class="p">:</span><span class="mi">0000</span><span class="p">]</span><span class="o">------------</span><span class="p">(:</span><span class="n">h</span> <span class="k">for</span> <span class="n">help</span><span class="p">)</span><span class="o">----------------------------</span>
</pre></div>
</div>
<p>This is important, in order to know what variables we can use in our callback out-of-the-box. Lets
write a single line to be sure our callback is called when we expect it to:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You just said </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>You can paste this line in-game, then type the <code class="docutils literal notranslate"><span class="pre">:wq</span></code> command to exit the editor and save your
modifications.</p>
<p>Lets check. Try to say “hello” in the room. You should see the standard message, but nothing
more. Now try to say “1”. Below the standard message, you should see:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You just said 1.
</pre></div>
</div>
<p>You can try it. Our callback is only called when we say “1”, “2” or “3”. Which is just what we
want.</p>
<p>Lets go back in our code editor and add something more useful.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/edit here = say
</pre></div>
</div>
<blockquote>
<div><p>Notice that we used the “edit” switch this time, since the callback exists, we just want to edit
it.</p>
</div></blockquote>
<p>The editor opens again. Lets empty it first:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>:DD
</pre></div>
</div>
<p>And turn off automatic indentation, which will help us:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>:=
</pre></div>
</div>
<blockquote>
<div><p>Auto-indentation is an interesting feature of the code editor, but wed better not use it at this
point, it will make copy/pasting more complicated.</p>
</div></blockquote>
</section>
<section id="our-entire-callback-in-the-elevator">
<h2>Our entire callback in the elevator<a class="headerlink" href="#our-entire-callback-in-the-elevator" title="Permalink to this headline"></a></h2>
<p>So heres the time to truly code our callback in-game. Heres a little reminder:</p>
<ol class="simple">
<li><p>We have all the IDs of our three rooms and two exits.</p></li>
<li><p>When we say “1”, “2” or “3”, the elevator should move to the right room, that is change the
exits. Remember, we already have the exits, we just need to change their location and destination.</p></li>
</ol>
<p>Its a good idea to try to write this callback yourself, but dont feel bad about checking the
solution right now. Heres a possible code that you could paste in the code editor:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># First let&#39;s have some constants</span>
<span class="n">ELEVATOR</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
<span class="n">FLOORS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;1&quot;</span><span class="p">:</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">),</span>
<span class="s2">&quot;2&quot;</span><span class="p">:</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">6</span><span class="p">),</span>
<span class="s2">&quot;3&quot;</span><span class="p">:</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">7</span><span class="p">),</span>
<span class="p">}</span>
<span class="n">TO_EXIT</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
<span class="n">BACK_EXIT</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="c1"># Now we check that the elevator isn&#39;t already at this floor</span>
<span class="n">floor</span> <span class="o">=</span> <span class="n">FLOORS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">if</span> <span class="n">floor</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Which floor do you want?&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">TO_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="ow">is</span> <span class="n">floor</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The elevator already is at this floor.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># &#39;floor&#39; contains the new room where the elevator should be</span>
<span class="n">room</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">&quot;The doors of the elevator close with a clank.&quot;</span><span class="p">)</span>
<span class="n">TO_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="n">floor</span>
<span class="n">BACK_EXIT</span><span class="o">.</span><span class="n">destination</span> <span class="o">=</span> <span class="n">floor</span>
<span class="n">room</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">&quot;The doors of the elevator open to </span><span class="si">{floor}</span><span class="s2">.&quot;</span><span class="p">,</span>
<span class="n">mapping</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">floor</span><span class="o">=</span><span class="n">floor</span><span class="p">))</span>
</pre></div>
</div>
<p>Lets review this longer callback:</p>
<ol class="simple">
<li><p>We first obtain the objects of both exits and our three floors. We use the <code class="docutils literal notranslate"><span class="pre">get()</span></code> eventfunc,
which is a shortcut to obtaining objects. We usually use it to retrieve specific objects with an
ID. We put the floors in a dictionary. The keys of the dictionary are the floor number (as str),
the values are room objects.</p></li>
<li><p>Remember, the <code class="docutils literal notranslate"><span class="pre">message</span></code> variable contains the message spoken in the room. So either “1”, “2”, or
“3”. We still need to check it, however, because if the character says something like “1 2” in the
room, our callback will be executed. Lets be sure what she says is a floor number.</p></li>
<li><p>We then check if the elevator is already at this floor. Notice that we use <code class="docutils literal notranslate"><span class="pre">TO_EXIT.location</span></code>.
<code class="docutils literal notranslate"><span class="pre">TO_EXIT</span></code> contains our “north” exit, leading inside of our elevator. Therefore, its <code class="docutils literal notranslate"><span class="pre">location</span></code> will
be the room where the elevator currently is.</p></li>
<li><p>If the floor is a different one, have the elevator “move”, changing just the location and
destination of both exits.</p>
<ul class="simple">
<li><p>The <code class="docutils literal notranslate"><span class="pre">BACK_EXIT</span></code> (that is “north”) should change its location. The elevator shouldnt be
accessible through our old floor.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">TO_EXIT</span></code> (that is “south”, the exit leading out of the elevator) should have a different
destination. When we go out of the elevator, we should find ourselves in the new floor, not the old
one.</p></li>
</ul>
</li>
</ol>
<p>Feel free to expand on this example, changing messages, making further checks. Usage and practice
are keys.</p>
<p>You can quit the editor as usual with <code class="docutils literal notranslate"><span class="pre">:wq</span></code> and test it out.</p>
</section>
<section id="adding-a-pause-in-our-callback">
<h2>Adding a pause in our callback<a class="headerlink" href="#adding-a-pause-in-our-callback" title="Permalink to this headline"></a></h2>
<p>Lets improve our callback. One thing thats worth adding would be a pause: for the time being,
when we say the floor number in the elevator, the doors close and open right away. It would be
better to have a pause of several seconds. More logical.</p>
<p>This is a great opportunity to learn about chained events. Chained events are very useful to create
pauses. Contrary to the events we have seen so far, chained events arent called automatically.
They must be called by you, and can be called after some time.</p>
<ul class="simple">
<li><p>Chained events always have the name <code class="docutils literal notranslate"><span class="pre">&quot;chain_X&quot;</span></code>. Usually, X is a number, but you can give the
chained event a more explicit name.</p></li>
<li><p>In our original callback, we will call our chained events in, say, 15 seconds.</p></li>
<li><p>Well also have to make sure the elevator isnt already moving.</p></li>
</ul>
<p>Other than that, a chained event can be connected to a callback as usual. Well create a chained
event in our elevator, that will only contain the code necessary to open the doors to the new floor.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = chain_1
</pre></div>
</div>
<p>The callback is added to the <code class="docutils literal notranslate"><span class="pre">&quot;chain_1&quot;</span></code> event, an event that will not be automatically called by the
system when something happens. Inside this event, you can paste the code to open the doors at the
new floor. You can notice a few differences:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">TO_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="n">floor</span>
<span class="n">TO_EXIT</span><span class="o">.</span><span class="n">destination</span> <span class="o">=</span> <span class="n">ELEVATOR</span>
<span class="n">BACK_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="n">ELEVATOR</span>
<span class="n">BACK_EXIT</span><span class="o">.</span><span class="n">destination</span> <span class="o">=</span> <span class="n">floor</span>
<span class="n">room</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">&quot;The doors of the elevator open to </span><span class="si">{floor}</span><span class="s2">.&quot;</span><span class="p">,</span>
<span class="n">mapping</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">floor</span><span class="o">=</span><span class="n">floor</span><span class="p">))</span>
</pre></div>
</div>
<p>Paste this code into the editor, then use <code class="docutils literal notranslate"><span class="pre">:wq</span></code> to save and quit the editor.</p>
<p>Now lets edit our callback in the “say” event. Well have to change it a bit:</p>
<ul class="simple">
<li><p>The callback will have to check the elevator isnt already moving.</p></li>
<li><p>It must change the exits when the elevator move.</p></li>
<li><p>It has to call the <code class="docutils literal notranslate"><span class="pre">&quot;chain_1&quot;</span></code> event we have defined. It should call it 15 seconds later.</p></li>
</ul>
<p>Lets see the code in our callback.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/edit here = say
</pre></div>
</div>
<p>Remove the current code and disable auto-indentation again:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>:DD
:=
</pre></div>
</div>
<p>And you can paste instead the following code. Notice the differences with our first attempt:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># First let&#39;s have some constants</span>
<span class="n">ELEVATOR</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
<span class="n">FLOORS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;1&quot;</span><span class="p">:</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">2</span><span class="p">),</span>
<span class="s2">&quot;2&quot;</span><span class="p">:</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">6</span><span class="p">),</span>
<span class="s2">&quot;3&quot;</span><span class="p">:</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">7</span><span class="p">),</span>
<span class="p">}</span>
<span class="n">TO_EXIT</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
<span class="n">BACK_EXIT</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="c1"># Now we check that the elevator isn&#39;t already at this floor</span>
<span class="n">floor</span> <span class="o">=</span> <span class="n">FLOORS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">if</span> <span class="n">floor</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Which floor do you want?&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">BACK_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The elevator is between floors.&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">TO_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="ow">is</span> <span class="n">floor</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The elevator already is at this floor.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># &#39;floor&#39; contains the new room where the elevator should be</span>
<span class="n">room</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">&quot;The doors of the elevator close with a clank.&quot;</span><span class="p">)</span>
<span class="n">TO_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">BACK_EXIT</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">call_event</span><span class="p">(</span><span class="n">room</span><span class="p">,</span> <span class="s2">&quot;chain_1&quot;</span><span class="p">,</span> <span class="mi">15</span><span class="p">)</span>
</pre></div>
</div>
<p>What changed?</p>
<ol class="simple">
<li><p>We added a little test to make sure the elevator wasnt already moving. If it is, the
<code class="docutils literal notranslate"><span class="pre">BACK_EXIT.location</span></code> (the “south” exit leading out of the elevator) should be <code class="docutils literal notranslate"><span class="pre">None</span></code>. Well remove
the exit while the elevator is moving.</p></li>
<li><p>When the doors close, we set both exits <code class="docutils literal notranslate"><span class="pre">location</span></code> to <code class="docutils literal notranslate"><span class="pre">None</span></code>. Which “removes” them from their
room but doesnt destroy them. The exits still exist but they dont connect anything. If you say
“2” in the elevator and look around while the elevator is moving, you wont see any exits.</p></li>
<li><p>Instead of opening the doors immediately, we call <code class="docutils literal notranslate"><span class="pre">call_event</span></code>. We give it the object containing
the event to be called (here, our elevator), the name of the event to be called (here, “chain_1”)
and the number of seconds from now when the event should be called (here, <code class="docutils literal notranslate"><span class="pre">15</span></code>).</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">chain_1</span></code> callback we have created contains the code to “re-open” the elevator doors. That
is, besides displaying a message, it reset the exits <code class="docutils literal notranslate"><span class="pre">location</span></code> and <code class="docutils literal notranslate"><span class="pre">destination</span></code>.</p></li>
</ol>
<p>If you try to say “3” in the elevator, you should see the doors closing. Look around you and you
wont see any exit. Then, 15 seconds later, the doors should open, and you can leave the elevator
to go to the third floor. While the elevator is moving, the exit leading to it will be
inaccessible.</p>
<blockquote>
<div><p>Note: we dont define the variables again in our chained event, we just call them. When we
execute <code class="docutils literal notranslate"><span class="pre">call_event</span></code>, a copy of our current variables is placed in the database. These variables
will be restored and accessible again when the chained event is called.</p>
</div></blockquote>
<p>You can use the <code class="docutils literal notranslate"><span class="pre">call/tasks</span></code> command to see the tasks waiting to be executed. For instance, say “2”
in the room, notice the doors closing, and then type the <code class="docutils literal notranslate"><span class="pre">call/tasks</span></code> command. You will see a task
in the elevator, waiting to call the <code class="docutils literal notranslate"><span class="pre">chain_1</span></code> event.</p>
</section>
<section id="changing-exit-messages">
<h2>Changing exit messages<a class="headerlink" href="#changing-exit-messages" title="Permalink to this headline"></a></h2>
<p>Heres another nice little feature of events: you can modify the message of a single exit without
altering the others. In this case, when someone goes north into our elevator, wed like to see
something like: “someone walks into the elevator.” Something similar for the back exit would be
great too.</p>
<p>Inside of the elevator, you can look at the available events on the exit leading outside (south).</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call south
</pre></div>
</div>
<p>You should see two interesting rows in this table:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">|</span> <span class="n">msg_arrive</span> <span class="o">|</span> <span class="mi">0</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">|</span> <span class="n">Customize</span> <span class="n">the</span> <span class="n">message</span> <span class="n">when</span> <span class="n">a</span> <span class="n">character</span> <span class="o">|</span>
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">arrives</span> <span class="n">through</span> <span class="n">this</span> <span class="n">exit</span><span class="o">.</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">msg_leave</span> <span class="o">|</span> <span class="mi">0</span> <span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">|</span> <span class="n">Customize</span> <span class="n">the</span> <span class="n">message</span> <span class="n">when</span> <span class="n">a</span> <span class="n">character</span> <span class="n">leaves</span> <span class="o">|</span>
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">through</span> <span class="n">this</span> <span class="n">exit</span><span class="o">.</span> <span class="o">|</span>
</pre></div>
</div>
<p>So we can change the message others see when a character leaves, by editing the “msg_leave” event.
Lets do that:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add south = msg_leave
</pre></div>
</div>
<p>Take the time to read the help. It gives you all the information you should need. Well need to
change the “message” variable, and use custom mapping (between braces) to alter the message. Were
given an example, lets use it. In the code editor, you can paste the following line:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">{character}</span><span class="s2"> walks out of the elevator.&quot;</span>
</pre></div>
</div>
<p>Again, save and quit the editor by entering <code class="docutils literal notranslate"><span class="pre">:wq</span></code>. You can create a new character to see it leave.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>charcreate A beggar
tel #8 = here
</pre></div>
</div>
<p>(Obviously, adapt the ID if necessary.)</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py self.search(&quot;beggar&quot;).move_to(self.search(&quot;south&quot;))
</pre></div>
</div>
<p>This is a crude way to force our beggar out of the elevator, but it allows us to test. You should
see:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>A beggar(#8) walks out of the elevator.
</pre></div>
</div>
<p>Great! Lets do the same thing for the exit leading inside of the elevator. Follow the beggar,
then edit “msg_leave” of “north”:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add north = msg_leave
</pre></div>
</div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">{character}</span><span class="s2"> walks into the elevator.&quot;</span>
</pre></div>
</div>
<p>Again, you can force our beggar to move and see the message we have just set. This modification
applies to these two exits, obviously: the custom message wont be used for other exits. Since we
use the same exits for every floor, this will be available no matter at what floor the elevator is,
which is pretty neat!</p>
</section>
<section id="tutorial-f-a-q">
<h2>Tutorial F.A.Q.<a class="headerlink" href="#tutorial-f-a-q" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p><strong>Q:</strong> what happens if the game reloads or shuts down while a task is waiting to happen?</p></li>
<li><p><strong>A:</strong> if your game reloads while a task is in pause (like our elevator between floors), when the
game is accessible again, the task will be called (if necessary, with a new time difference to take
into account the reload). If the server shuts down, obviously, the task will not be called, but
will be stored and executed when the server is up again.</p></li>
<li><p><strong>Q:</strong> can I use all kinds of variables in my callback? Whether chained or not?</p></li>
<li><p><strong>A:</strong> you can use every variable type you like in your original callback. However, if you
execute <code class="docutils literal notranslate"><span class="pre">call_event</span></code>, since your variables are stored in the database, they will need to respect the
constraints on persistent attributes. A callback will not be stored in this way, for instance.
This variable will not be available in your chained event.</p></li>
<li><p><strong>Q:</strong> when you say I can call my chained events something else than “chain_1”, “chain_2” and
such, what is the naming convention?</p></li>
<li><p><strong>A:</strong> chained events have names beginning by <code class="docutils literal notranslate"><span class="pre">&quot;chain_&quot;</span></code>. This is useful for you and for the
system. But after the underscore, you can give a more useful name, like <code class="docutils literal notranslate"><span class="pre">&quot;chain_open_doors&quot;</span></code> in our
case.</p></li>
<li><p><strong>Q:</strong> do I have to pause several seconds to call a chained event?</p></li>
<li><p><strong>A:</strong> no, you can call it right away. Just leave the third parameter of <code class="docutils literal notranslate"><span class="pre">call_event</span></code> out (it
will default to 0, meaning the chained event will be called right away). This will not create a
task.</p></li>
<li><p><strong>Q:</strong> can I have chained events calling themselves?</p></li>
<li><p><strong>A:</strong> you can. Theres no limitation. Just be careful, a callback that calls itself,
particularly without delay, might be a good recipe for an infinite loop. However, in some cases, it
is useful to have chained events calling themselves, to do the same repeated action every X seconds
for instance.</p></li>
<li><p><strong>Q:</strong> what if I need several elevators, do I need to copy/paste these callbacks each time?</p></li>
<li><p><strong>A:</strong> not advisable. There are definitely better ways to handle this situation. One of them is
to consider adding the code in the source itself. Another possibility is to call chained events
with the expected behavior, which makes porting code very easy. This side of chained events will be
shown in the next tutorial.</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="Contrib-Menu-Login.html" title="Menu-based login system"
>next</a> |</li>
<li class="right" >
<a href="Contrib-Ingame-Python-Tutorial-Dialogue.html" title="Dialogues in events"
>previous</a> |</li>
2023-10-19 20:22:27 +00:00
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" >Contribs</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="Contrib-Ingame-Python.html" >Evennia in-game Python system</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">A voice operated elevator using events</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
2023-10-19 20:22:27 +00:00
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>