mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
557 lines
No EOL
44 KiB
HTML
557 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>A voice operated elevator using events — 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="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>
|
||
|
||
|
||
|
||
|
||
<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>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" >Contribs</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="Contrib-Ingame-Python.html" accesskey="U">Evennia in-game Python system</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">A voice operated elevator using events</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="#">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>
|
||
<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, it’s 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 don’t
|
||
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>Let’s 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>We’ll 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>Let’s go into limbo (<code class="docutils literal notranslate"><span class="pre">#2</span></code>) to add our elevator. We’ll 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? Isn’t 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.
|
||
You’ll see this process a bit later.</p>
|
||
<p>We have two more rooms to create: our floor 2 and 3. This time, we’ll use <code class="docutils literal notranslate"><span class="pre">dig</span></code>, because we don’t
|
||
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>Let’s 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, here’s 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 we’ll need to add a callback to this event. Don’t worry if you’re 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. Let’s
|
||
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">"You just said </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">."</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>Let’s 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>Let’s 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. Let’s 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 we’d 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 here’s the time to truly code our callback in-game. Here’s 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>It’s a good idea to try to write this callback yourself, but don’t feel bad about checking the
|
||
solution right now. Here’s 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'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">"1"</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">"2"</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">"3"</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'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">"Which floor do you want?"</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">"The elevator already is at this floor."</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># 'floor' 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">"The doors of the elevator close with a clank."</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">"The doors of the elevator open to </span><span class="si">{floor}</span><span class="s2">."</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>Let’s 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. Let’s 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 shouldn’t 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>Let’s improve our callback. One thing that’s 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 aren’t 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">"chain_X"</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>We’ll also have to make sure the elevator isn’t already moving.</p></li>
|
||
</ul>
|
||
<p>Other than that, a chained event can be connected to a callback as usual. We’ll 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">"chain_1"</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">"The doors of the elevator open to </span><span class="si">{floor}</span><span class="s2">."</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 let’s edit our callback in the “say” event. We’ll have to change it a bit:</p>
|
||
<ul class="simple">
|
||
<li><p>The callback will have to check the elevator isn’t 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">"chain_1"</span></code> event we have defined. It should call it 15 seconds later.</p></li>
|
||
</ul>
|
||
<p>Let’s 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'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">"1"</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">"2"</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">"3"</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'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">"Which floor do you want?"</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">"The elevator is between floors."</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">"The elevator already is at this floor."</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># 'floor' 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">"The doors of the elevator close with a clank."</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">"chain_1"</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 wasn’t 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>. We’ll 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 doesn’t destroy them. The exits still exist but they don’t connect anything. If you say
|
||
“2” in the elevator and look around while the elevator is moving, you won’t 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
|
||
won’t 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 don’t 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>Here’s 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, we’d 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.
|
||
Let’s 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. We’ll need to
|
||
change the “message” variable, and use custom mapping (between braces) to alter the message. We’re
|
||
given an example, let’s 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">"</span><span class="si">{character}</span><span class="s2"> walks out of the elevator."</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("beggar").move_to(self.search("south"))
|
||
</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! Let’s 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">"</span><span class="si">{character}</span><span class="s2"> walks into the elevator."</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 won’t 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">"chain_"</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">"chain_open_doors"</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. There’s 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>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" >Contribs</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="Contrib-Ingame-Python.html" >Evennia in-game Python system</a> »</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">
|
||
© Copyright 2023, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |