mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
1061 lines
No EOL
87 KiB
HTML
1061 lines
No EOL
87 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>Evennia in-game Python system — 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="Dialogues in events" href="Contrib-Ingame-Python-Tutorial-Dialogue.html" />
|
||
<link rel="prev" title="Godot Websocket" href="Contrib-Godotwebsocket.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-Ingame-Python-Tutorial-Dialogue.html" title="Dialogues in events"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Contrib-Godotwebsocket.html" title="Godot Websocket"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" accesskey="U">Contribs</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Evennia in-game Python system</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="#">Evennia in-game Python system</a><ul>
|
||
<li><a class="reference internal" href="#a-warning-regarding-security">A WARNING REGARDING SECURITY</a></li>
|
||
<li><a class="reference internal" href="#extra-tutorials">Extra tutorials</a></li>
|
||
<li><a class="reference internal" href="#basic-structure-and-vocabulary">Basic structure and vocabulary</a></li>
|
||
<li><a class="reference internal" href="#installation">Installation</a><ul>
|
||
<li><a class="reference internal" href="#starting-the-event-script">Starting the event script</a></li>
|
||
<li><a class="reference internal" href="#editing-permissions">Editing permissions</a></li>
|
||
<li><a class="reference internal" href="#adding-the-call-command">Adding the <code class="docutils literal notranslate"><span class="pre">call</span></code> command</a></li>
|
||
<li><a class="reference internal" href="#changing-parent-classes-of-typeclasses">Changing parent classes of typeclasses</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#using-the-call-command">Using the <code class="docutils literal notranslate"><span class="pre">call</span></code> command</a><ul>
|
||
<li><a class="reference internal" href="#examining-callbacks-and-events">Examining callbacks and events</a></li>
|
||
<li><a class="reference internal" href="#creating-a-new-callback">Creating a new callback</a></li>
|
||
<li><a class="reference internal" href="#editing-and-removing-a-callback">Editing and removing a callback</a></li>
|
||
<li><a class="reference internal" href="#the-code-editor">The code editor</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#using-events">Using events</a><ul>
|
||
<li><a class="reference internal" href="#the-eventfuncs">The eventfuncs</a><ul>
|
||
<li><a class="reference internal" href="#deny">deny</a></li>
|
||
<li><a class="reference internal" href="#get">get</a></li>
|
||
<li><a class="reference internal" href="#call-event">call_event</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#variables-in-callbacks">Variables in callbacks</a></li>
|
||
<li><a class="reference internal" href="#callbacks-with-parameters">Callbacks with parameters</a></li>
|
||
<li><a class="reference internal" href="#time-related-events">Time-related events</a></li>
|
||
<li><a class="reference internal" href="#chained-events">Chained events</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#using-events-in-code">Using events in code</a><ul>
|
||
<li><a class="reference internal" href="#adding-new-events">Adding new events</a></li>
|
||
<li><a class="reference internal" href="#calling-an-event-in-code">Calling an event in code</a></li>
|
||
<li><a class="reference internal" href="#see-it-all-work">See it all work</a></li>
|
||
<li><a class="reference internal" href="#adding-new-eventfuncs">Adding new eventfuncs</a></li>
|
||
<li><a class="reference internal" href="#creating-events-with-parameters">Creating events with parameters</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#disabling-all-events-at-once">Disabling all events at once</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Contrib-Godotwebsocket.html"
|
||
title="previous chapter">Godot Websocket</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Contrib-Ingame-Python-Tutorial-Dialogue.html"
|
||
title="next chapter">Dialogues in events</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.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="Contrib-Ingame-Python.html">2.x (main branch)</a></li>
|
||
<ul>
|
||
<li><a href="../../1.3.0/index.html">1.3.0 (v1.3.0 branch)</a></li>
|
||
|
||
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||
|
||
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="evennia-in-game-python-system">
|
||
<h1>Evennia in-game Python system<a class="headerlink" href="#evennia-in-game-python-system" title="Permalink to this headline">¶</a></h1>
|
||
<p>Contrib by Vincent Le Goff 2017</p>
|
||
<p>This contrib adds the ability to script with Python in-game. It allows trusted
|
||
staff/builders to dynamically add features and triggers to individual objects
|
||
without needing to do it in external Python modules. Using custom Python in-game,
|
||
specific rooms, exits, characters, objects etc can be made to behave differently from
|
||
its “cousins”. This is similar to how softcode works for MU or MudProgs for DIKU.
|
||
Keep in mind, however, that allowing Python in-game comes with <em>severe</em>
|
||
security concerns (you must trust your builders deeply), so read the warnings in
|
||
this module carefully before continuing.</p>
|
||
<section id="a-warning-regarding-security">
|
||
<h2>A WARNING REGARDING SECURITY<a class="headerlink" href="#a-warning-regarding-security" title="Permalink to this headline">¶</a></h2>
|
||
<p>Evennia’s in-game Python system will run arbitrary Python code without much
|
||
restriction. Such a system is as powerful as potentially dangerous, and you
|
||
will have to keep in mind these points before deciding to install it:</p>
|
||
<ol class="simple">
|
||
<li><p>Untrusted people can run Python code on your game server with this system.
|
||
Be careful about who can use this system (see the permissions below).</p></li>
|
||
<li><p>You can do all of this in Python outside the game. The in-game Python system
|
||
is not to replace all your game feature.</p></li>
|
||
</ol>
|
||
</section>
|
||
<section id="extra-tutorials">
|
||
<h2>Extra tutorials<a class="headerlink" href="#extra-tutorials" title="Permalink to this headline">¶</a></h2>
|
||
<p>These tutorials cover examples of using ingame python. Once you have the system
|
||
installed (see below) they may be an easier way to learn than reading the full
|
||
documentation from beginning to end.</p>
|
||
<ul class="simple">
|
||
<li><p><a class="reference internal" href="Contrib-Ingame-Python-Tutorial-Dialogue.html"><span class="doc std std-doc">Dialogue events</span></a>, where
|
||
NPCs react to things said.</p></li>
|
||
<li><p><a class="reference internal" href="Contrib-Ingame-Python-Tutorial-Elevator.html"><span class="doc std std-doc">A voice operated elevator</span></a>
|
||
using ingame-python events.</p></li>
|
||
</ul>
|
||
</section>
|
||
<section id="basic-structure-and-vocabulary">
|
||
<h2>Basic structure and vocabulary<a class="headerlink" href="#basic-structure-and-vocabulary" title="Permalink to this headline">¶</a></h2>
|
||
<ul class="simple">
|
||
<li><p>At the basis of the in-game Python system are <strong>events</strong>. An <strong>event</strong>
|
||
defines the context in which we would like to call some arbitrary code. For
|
||
instance, one event is defined on exits and will fire every time a character
|
||
traverses through this exit. Events are described on a <a class="reference internal" href="../Components/Typeclasses.html"><span class="doc std std-doc">typeclass</span></a>
|
||
(<a class="reference internal" href="../Components/Exits.html"><span class="doc std std-doc">exits</span></a> in our example). All objects inheriting from this
|
||
typeclass will have access to this event.</p></li>
|
||
<li><p><strong>Callbacks</strong> can be set on individual objects, on events defined in code.
|
||
These <strong>callbacks</strong> can contain arbitrary code and describe a specific
|
||
behavior for an object. When the event fires, all callbacks connected to this
|
||
object’s event are executed.</p></li>
|
||
</ul>
|
||
<p>To see the system in context, when an object is picked up (using the default
|
||
<code class="docutils literal notranslate"><span class="pre">get</span></code> command), a specific event is fired:</p>
|
||
<ol class="simple">
|
||
<li><p>The event “get” is set on objects (on the <code class="docutils literal notranslate"><span class="pre">Object</span></code> typeclass).</p></li>
|
||
<li><p>When using the “get” command to pick up an object, this object’s <code class="docutils literal notranslate"><span class="pre">at_get</span></code>
|
||
hook is called.</p></li>
|
||
<li><p>A modified hook of DefaultObject is set by the event system. This hook will
|
||
execute (or call) the “get” event on this object.</p></li>
|
||
<li><p>All callbacks tied to this object’s “get” event will be executed in order.
|
||
These callbacks act as functions containing Python code that you can write
|
||
in-game, using specific variables that will be listed when you edit the callback
|
||
itself.</p></li>
|
||
<li><p>In individual callbacks, you can add multiple lines of Python code that will
|
||
be fired at this point. In this example, the <code class="docutils literal notranslate"><span class="pre">character</span></code> variable will
|
||
contain the character who has picked up the object, while <code class="docutils literal notranslate"><span class="pre">obj</span></code> will contain the
|
||
object that was picked up.</p></li>
|
||
</ol>
|
||
<p>Following this example, if you create a callback “get” on the object “a sword”,
|
||
and put in it:</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="s2">"You have picked up </span><span class="si">{}</span><span class="s2"> and have completed this quest!"</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="n">character</span><span class="p">)))</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>When you pick up this object you should see something like:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You pick up a sword.
|
||
You have picked up a sword and have completed this quest!
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="installation">
|
||
<h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2>
|
||
<p>Being in a separate contrib, the in-game Python system isn’t installed by
|
||
default. You need to do it manually, following these steps:</p>
|
||
<p>This is the quick summary. Scroll down for more detailed help on each step.</p>
|
||
<ol>
|
||
<li><p>Launch the main script (important!):</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> py evennia.create_script("evennia.contrib.base_systems.ingame_python.scripts.EventHandler")
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li><p>Set the permissions (optional):</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_WITH_VALIDATION</span></code>: a group that can edit callbacks, but will need approval (default to
|
||
<code class="docutils literal notranslate"><span class="pre">None</span></code>).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_WITHOUT_VALIDATION</span></code>: a group with permission to edit callbacks without need of
|
||
validation (default to <code class="docutils literal notranslate"><span class="pre">"immortals"</span></code>).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_VALIDATING</span></code>: a group that can validate callbacks (default to <code class="docutils literal notranslate"><span class="pre">"immortals"</span></code>).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_CALENDAR</span></code>: type of the calendar to be used (either <code class="docutils literal notranslate"><span class="pre">None</span></code>, <code class="docutils literal notranslate"><span class="pre">"standard"</span></code> or <code class="docutils literal notranslate"><span class="pre">"custom"</span></code>,
|
||
default to <code class="docutils literal notranslate"><span class="pre">None</span></code>).</p></li>
|
||
</ul>
|
||
</li>
|
||
<li><p>Add the <code class="docutils literal notranslate"><span class="pre">call</span></code> command.</p></li>
|
||
<li><p>Inherit from the custom typeclasses of the in-game Python system.</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.contrib.base_systems.ingame_python.typeclasses.EventCharacter</span></code>: to replace <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.contrib.base_systems.ingame_python.typeclasses.EventExit</span></code>: to replace <code class="docutils literal notranslate"><span class="pre">DefaultExit</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.contrib.base_systems.ingame_python.typeclasses.EventObject</span></code>: to replace <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.contrib.base_systems.ingame_python.typeclasses.EventRoom</span></code>: to replace <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code>.</p></li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<p>The following sections describe in details each step of the installation.</p>
|
||
<blockquote>
|
||
<div><p>Note: If you were to start the game without having started the main script (such as when
|
||
resetting your database) you will most likely face a traceback when logging in, telling you
|
||
that a ‘callback’ property is not defined. After performing step <code class="docutils literal notranslate"><span class="pre">1</span></code> the error will go away.</p>
|
||
</div></blockquote>
|
||
<section id="starting-the-event-script">
|
||
<h3>Starting the event script<a class="headerlink" href="#starting-the-event-script" title="Permalink to this headline">¶</a></h3>
|
||
<p>To start the event script, you only need a single command, using <code class="docutils literal notranslate"><span class="pre">@py</span></code>.</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py evennia.create_script("evennia.contrib.base_systems.ingame_python.scripts.EventHandler")
|
||
</pre></div>
|
||
</div>
|
||
<p>This command will create a global script (that is, a script independent from any object). This
|
||
script will hold basic configuration, individual callbacks and so on. You may access it directly,
|
||
but you will probably use the callback handler. Creating this script will also create a <code class="docutils literal notranslate"><span class="pre">callback</span></code>
|
||
handler on all objects (see below for details).</p>
|
||
</section>
|
||
<section id="editing-permissions">
|
||
<h3>Editing permissions<a class="headerlink" href="#editing-permissions" title="Permalink to this headline">¶</a></h3>
|
||
<p>This contrib comes with its own set of permissions. They define who can edit callbacks without
|
||
validation, and who can edit callbacks but needs validation. Validation is a process in which an
|
||
administrator (or somebody trusted as such) will check the callbacks produced by others and will
|
||
accept or reject them. If accepted, the callbacks are connected, otherwise they are never run.</p>
|
||
<p>By default, callbacks can only be created by immortals: no one except the immortals can edit
|
||
callbacks, and immortals don’t need validation. It can easily be changed, either through settings
|
||
or dynamically by changing permissions of users.</p>
|
||
<p>The ingame-python contrib adds three <a class="reference internal" href="../Components/Permissions.html"><span class="doc std std-doc">permissions</span></a>) in the settings. You can
|
||
override them by changing the settings into your <code class="docutils literal notranslate"><span class="pre">server/conf/settings.py</span></code> file (see below for an
|
||
example). The settings defined in the events contrib are:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_WITH_VALIDATION</span></code>: this defines a permission that can edit callbacks, but will need
|
||
approval. If you set this to <code class="docutils literal notranslate"><span class="pre">"wizards"</span></code>, for instance, users with the permission <code class="docutils literal notranslate"><span class="pre">"wizards"</span></code>
|
||
will be able to edit callbacks. These callbacks will not be connected, though, and will need to be
|
||
checked and approved by an administrator. This setting can contain <code class="docutils literal notranslate"><span class="pre">None</span></code>, meaning that no user is
|
||
allowed to edit callbacks with validation.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_WITHOUT_VALIDATION</span></code>: this setting defines a permission allowing editing of callbacks
|
||
without needing validation. By default, this setting is set to <code class="docutils literal notranslate"><span class="pre">"immortals"</span></code>. It means that
|
||
immortals can edit callbacks, and they will be connected when they leave the editor, without needing
|
||
approval.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EVENTS_VALIDATING</span></code>: this last setting defines who can validate callbacks. By default, this is
|
||
set to <code class="docutils literal notranslate"><span class="pre">"immortals"</span></code>, meaning only immortals can see callbacks needing validation, accept or
|
||
reject them.</p></li>
|
||
</ul>
|
||
<p>You can override all these settings in your <code class="docutils literal notranslate"><span class="pre">server/conf/settings.py</span></code> file. For instance:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ... other settings ...</span>
|
||
|
||
<span class="c1"># Event settings</span>
|
||
<span class="n">EVENTS_WITH_VALIDATION</span> <span class="o">=</span> <span class="s2">"wizards"</span>
|
||
<span class="n">EVENTS_WITHOUT_VALIDATION</span> <span class="o">=</span> <span class="s2">"immortals"</span>
|
||
<span class="n">EVENTS_VALIDATING</span> <span class="o">=</span> <span class="s2">"immortals"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>In addition, there is another setting that must be set if you plan on using the time-related events
|
||
(events that are scheduled at specific, in-game times). You would need to specify the type of
|
||
calendar you are using. By default, time-related events are disabled. You can change the
|
||
<code class="docutils literal notranslate"><span class="pre">EVENTS_CALENDAR</span></code> to set it to:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">"standard"</span></code>: the standard calendar, with standard days, months, years and so on.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">"custom"</span></code>: a custom calendar that will use the <code class="docutils literal notranslate"><span class="pre">custom_gametime</span></code> contrib to schedule events.</p></li>
|
||
</ul>
|
||
<p>This contrib defines two additional permissions that can be set on individual users:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">events_without_validation</span></code>: this would give this user the rights to edit callbacks but not
|
||
require validation before they are connected.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">events_validating</span></code>: this permission allows this user to run validation checks on callbacks
|
||
needing to be validated.</p></li>
|
||
</ul>
|
||
<p>For instance, to give the right to edit callbacks without needing approval to the player ‘kaldara’,
|
||
you might do something like:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>perm *kaldara = events_without_validation
|
||
</pre></div>
|
||
</div>
|
||
<p>To remove this same permission, just use the <code class="docutils literal notranslate"><span class="pre">/del</span></code> switch:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>perm/del *kaldara = events_without_validation
|
||
</pre></div>
|
||
</div>
|
||
<p>The rights to use the <code class="docutils literal notranslate"><span class="pre">call</span></code> command are directly related to these permissions: by default, only
|
||
users who have the <code class="docutils literal notranslate"><span class="pre">events_without_validation</span></code> permission or are in (or above) the group defined in
|
||
the <code class="docutils literal notranslate"><span class="pre">EVENTS_WITH_VALIDATION</span></code> setting will be able to call the command (with different switches).</p>
|
||
</section>
|
||
<section id="adding-the-call-command">
|
||
<h3>Adding the <code class="docutils literal notranslate"><span class="pre">call</span></code> command<a class="headerlink" href="#adding-the-call-command" title="Permalink to this headline">¶</a></h3>
|
||
<p>You also have to add the <code class="docutils literal notranslate"><span class="pre">@call</span></code> command to your Character CmdSet. This command allows your users
|
||
to add, edit and delete callbacks in-game. In your <code class="docutils literal notranslate"><span class="pre">commands/default_cmdsets</span></code>, it might look like
|
||
this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
|
||
<span class="kn">from</span> <span class="nn">evennia.contrib.base_systems.ingame_python.commands</span> <span class="kn">import</span> <span class="n">CmdCallback</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> The `CharacterCmdSet` contains general in-game commands like `look`,</span>
|
||
<span class="sd"> `get`, etc available on in-game Character objects. It is merged with</span>
|
||
<span class="sd"> the `PlayerCmdSet` when a Player puppets a Character.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultCharacter"</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="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Populates the cmdset</span>
|
||
<span class="sd"> """</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</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">CmdCallback</span><span class="p">())</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="changing-parent-classes-of-typeclasses">
|
||
<h3>Changing parent classes of typeclasses<a class="headerlink" href="#changing-parent-classes-of-typeclasses" title="Permalink to this headline">¶</a></h3>
|
||
<p>Finally, to use the in-game Python system, you need to have your typeclasses inherit from the modified event
|
||
classes. For instance, in your <code class="docutils literal notranslate"><span class="pre">typeclasses/characters.py</span></code> module, you should change inheritance
|
||
like this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.contrib.base_systems.ingame_python.typeclasses</span> <span class="kn">import</span> <span class="n">EventCharacter</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">EventCharacter</span><span class="p">):</span>
|
||
|
||
<span class="c1"># ...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>You should do the same thing for your rooms, exits and objects. Note that the
|
||
in-game Python system works by overriding some hooks. Some of these features
|
||
might not be accessible in your game if you don’t call the parent methods when
|
||
overriding hooks.</p>
|
||
</section>
|
||
</section>
|
||
<section id="using-the-call-command">
|
||
<h2>Using the <code class="docutils literal notranslate"><span class="pre">call</span></code> command<a class="headerlink" href="#using-the-call-command" title="Permalink to this headline">¶</a></h2>
|
||
<p>The in-game Python system relies, to a great extent, on its <code class="docutils literal notranslate"><span class="pre">call</span></code> command.
|
||
Who can execute this command, and who can do what with it, will depend on your
|
||
set of permissions.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">call</span></code> command allows to add, edit and delete callbacks on specific objects’ events. The event
|
||
system can be used on most Evennia objects, mostly typeclassed objects (excluding players). The
|
||
first argument of the <code class="docutils literal notranslate"><span class="pre">call</span></code> command is the name of the object you want to edit. It can also be
|
||
used to know what events are available for this specific object.</p>
|
||
<section id="examining-callbacks-and-events">
|
||
<h3>Examining callbacks and events<a class="headerlink" href="#examining-callbacks-and-events" title="Permalink to this headline">¶</a></h3>
|
||
<p>To see the events connected to an object, use the <code class="docutils literal notranslate"><span class="pre">call</span></code> command and give the name or ID of the
|
||
object to examine. For instance, <code class="docutils literal notranslate"><span class="pre">call</span> <span class="pre">here</span></code> to examine the events on your current location. Or
|
||
<code class="docutils literal notranslate"><span class="pre">call</span> <span class="pre">self</span></code> to see the events on yourself.</p>
|
||
<p>This command will display a table, containing:</p>
|
||
<ul class="simple">
|
||
<li><p>The name of each event in the first column.</p></li>
|
||
<li><p>The number of callbacks of this name, and the number of total lines of these callbacks in the
|
||
second column.</p></li>
|
||
<li><p>A short help to tell you when the event is triggered in the third column.</p></li>
|
||
</ul>
|
||
<p>If you execute <code class="docutils literal notranslate"><span class="pre">call</span> <span class="pre">#1</span></code> for instance, you might see a table like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>+------------------+---------+-----------------------------------------------+
|
||
| Event name | Number | Description |
|
||
+~~~~~~~~~~~~~~~~~~+~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
|
||
| can_delete | 0 (0) | Can the character be deleted? |
|
||
| can_move | 0 (0) | Can the character move? |
|
||
| can_part | 0 (0) | Can the departing character leave this room? |
|
||
| delete | 0 (0) | Before deleting the character. |
|
||
| greet | 0 (0) | A new character arrives in the location of |
|
||
| | | this character. |
|
||
| move | 0 (0) | After the character has moved into its new |
|
||
| | | room. |
|
||
| puppeted | 0 (0) | When the character has been puppeted by a |
|
||
| | | player. |
|
||
| time | 0 (0) | A repeated event to be called regularly. |
|
||
| unpuppeted | 0 (0) | When the character is about to be un- |
|
||
| | | puppeted. |
|
||
+------------------+---------+-----------------------------------------------+
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="creating-a-new-callback">
|
||
<h3>Creating a new callback<a class="headerlink" href="#creating-a-new-callback" title="Permalink to this headline">¶</a></h3>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">/add</span></code> switch should be used to add a callback. It takes two arguments beyond the object’s
|
||
name/DBREF:</p>
|
||
<ol class="simple">
|
||
<li><p>After an = sign, the name of the event to be edited (if not supplied, will display the list of
|
||
possible events, like above).</p></li>
|
||
<li><p>The parameters (optional).</p></li>
|
||
</ol>
|
||
<p>We’ll see callbacks with parameters later. For the time being, let’s try to prevent a character
|
||
from going through the “north” exit of this room:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>call north
|
||
+------------------+---------+-----------------------------------------------+
|
||
| Event name | Number | Description |
|
||
+~~~~~~~~~~~~~~~~~~+~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
|
||
| can_traverse | 0 (0) | Can the character traverse through this exit? |
|
||
| msg_arrive | 0 (0) | Customize the message when a character |
|
||
| | | arrives through this exit. |
|
||
| msg_leave | 0 (0) | Customize the message when a character leaves |
|
||
| | | through this exit. |
|
||
| time | 0 (0) | A repeated event to be called regularly. |
|
||
| traverse | 0 (0) | After the character has traversed through |
|
||
| | | this exit. |
|
||
+------------------+---------+-----------------------------------------------+
|
||
</pre></div>
|
||
</div>
|
||
<p>If we want to prevent a character from traversing through this exit, the best event for us would be
|
||
“can_traverse”.</p>
|
||
<blockquote>
|
||
<div><p>Why not “traverse”? If you read the description of both events, you will see “traverse” is called
|
||
<strong>after</strong> the character has traversed through this exit. It would be too late to prevent it. On
|
||
the other hand, “can_traverse” is obviously checked before the character traverses.</p>
|
||
</div></blockquote>
|
||
<p>When we edit the event, we have some more information:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add north = can_traverse
|
||
</pre></div>
|
||
</div>
|
||
<p>Can the character traverse through this exit?
|
||
This event is called when a character is about to traverse this
|
||
exit. You can use the deny() eventfunc to deny the character from
|
||
exiting for this time.</p>
|
||
<p>Variables you can use in this event:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>- character: the character that wants to traverse this exit.
|
||
- exit: the exit to be traversed.
|
||
- room: the room in which stands the character before moving.
|
||
</pre></div>
|
||
</div>
|
||
<p>The section dedicated to <a class="reference internal" href="#the-eventfuncs"><span class="std std-doc">eventfuncs</span></a> will elaborate on the <code class="docutils literal notranslate"><span class="pre">deny()</span></code> function and
|
||
other eventfuncs. Let us say, for the time being, that it can prevent an action (in this case, it
|
||
can prevent the character from traversing through this exit). In the editor that opened when you
|
||
used <code class="docutils literal notranslate"><span class="pre">call/add</span></code>, you can type something like:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">character</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</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">"You're the superuser, 'course I'll let you pass."</span><span class="p">)</span>
|
||
<span class="k">else</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">"Hold on, what do you think you're doing?"</span><span class="p">)</span>
|
||
<span class="n">deny</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>You can now enter <code class="docutils literal notranslate"><span class="pre">:wq</span></code> to leave the editor by saving the callback.</p>
|
||
<p>If you enter <code class="docutils literal notranslate"><span class="pre">call</span> <span class="pre">north</span></code>, you should see that “can_traverse” now has an active callback. You can
|
||
use <code class="docutils literal notranslate"><span class="pre">call</span> <span class="pre">north</span> <span class="pre">=</span> <span class="pre">can_traverse</span></code> to see more details on the connected callbacks:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">call</span> <span class="n">north</span> <span class="o">=</span> <span class="n">can_traverse</span>
|
||
<span class="o">+--------------+--------------+----------------+--------------+--------------+</span>
|
||
<span class="o">|</span> <span class="n">Number</span> <span class="o">|</span> <span class="n">Author</span> <span class="o">|</span> <span class="n">Updated</span> <span class="o">|</span> <span class="n">Param</span> <span class="o">|</span> <span class="n">Valid</span> <span class="o">|</span>
|
||
<span class="o">+~~~~~~~~~~~~~~+~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~+~~~~~~~~~~~~~~+</span>
|
||
<span class="o">|</span> <span class="mi">1</span> <span class="o">|</span> <span class="n">XXXXX</span> <span class="o">|</span> <span class="mi">5</span> <span class="n">seconds</span> <span class="n">ago</span> <span class="o">|</span> <span class="o">|</span> <span class="n">Yes</span> <span class="o">|</span>
|
||
<span class="o">+--------------+--------------+----------------+--------------+--------------+</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The left column contains callback numbers. You can use them to have even more information on a
|
||
specific event. Here, for instance:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">call</span> <span class="n">north</span> <span class="o">=</span> <span class="n">can_traverse</span> <span class="mi">1</span>
|
||
<span class="n">Callback</span> <span class="n">can_traverse</span> <span class="mi">1</span> <span class="n">of</span> <span class="n">north</span><span class="p">:</span>
|
||
<span class="n">Created</span> <span class="n">by</span> <span class="n">XXXXX</span> <span class="n">on</span> <span class="mi">2017</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">02</span> <span class="mi">17</span><span class="p">:</span><span class="mi">58</span><span class="p">:</span><span class="mf">05.</span>
|
||
<span class="n">Updated</span> <span class="n">by</span> <span class="n">XXXXX</span> <span class="n">on</span> <span class="mi">2017</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">02</span> <span class="mi">18</span><span class="p">:</span><span class="mi">02</span><span class="p">:</span><span class="mi">50</span>
|
||
<span class="n">This</span> <span class="n">callback</span> <span class="ow">is</span> <span class="n">connected</span> <span class="ow">and</span> <span class="n">active</span><span class="o">.</span>
|
||
<span class="n">Callback</span> <span class="n">code</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="n">character</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</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">"You're the superuser, 'course I'll let you pass."</span><span class="p">)</span>
|
||
<span class="k">else</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">"Hold on, what do you think you're doing?"</span><span class="p">)</span>
|
||
<span class="n">deny</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Then try to walk through this exit. Do it with another character if possible, too, to see the
|
||
difference.</p>
|
||
</section>
|
||
<section id="editing-and-removing-a-callback">
|
||
<h3>Editing and removing a callback<a class="headerlink" href="#editing-and-removing-a-callback" title="Permalink to this headline">¶</a></h3>
|
||
<p>You can use the <code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch to the <code class="docutils literal notranslate"><span class="pre">@call</span></code> command to edit a callback. You should provide, after
|
||
the name of the object to edit and the equal sign:</p>
|
||
<ol class="simple">
|
||
<li><p>The name of the event (as seen above).</p></li>
|
||
<li><p>A number, if several callbacks are connected at this location.</p></li>
|
||
</ol>
|
||
<p>You can type <code class="docutils literal notranslate"><span class="pre">call/edit</span> <span class="pre"><object></span> <span class="pre">=</span> <span class="pre"><event</span> <span class="pre">name></span></code> to see the callbacks that are linked at this
|
||
location. If there is only one callback, it will be opened in the editor; if more are defined, you
|
||
will be asked for a number to provide (for instance, <code class="docutils literal notranslate"><span class="pre">call/edit</span> <span class="pre">north</span> <span class="pre">=</span> <span class="pre">can_traverse</span> <span class="pre">2</span></code>).</p>
|
||
<p>The command <code class="docutils literal notranslate"><span class="pre">call</span></code> also provides a <code class="docutils literal notranslate"><span class="pre">/del</span></code> switch to remove a callback. It takes the same arguments
|
||
as the <code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch.</p>
|
||
<p>When removed, callbacks are logged, so an administrator can retrieve its content, assuming the
|
||
<code class="docutils literal notranslate"><span class="pre">/del</span></code> was an error.</p>
|
||
</section>
|
||
<section id="the-code-editor">
|
||
<h3>The code editor<a class="headerlink" href="#the-code-editor" title="Permalink to this headline">¶</a></h3>
|
||
<p>When adding or editing a callback, the event editor should open in code mode. The additional
|
||
options supported by the editor in this mode are describe in <a class="reference external" href="https://github.com/evennia/evennia/wiki/EvEditor#the-eveditor-to-edit-code">a dedicated section of the EvEditor’s
|
||
documentation</a>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="using-events">
|
||
<h2>Using events<a class="headerlink" href="#using-events" title="Permalink to this headline">¶</a></h2>
|
||
<p>The following sections describe how to use events for various tasks, from the most simple to the
|
||
most complex.</p>
|
||
<section id="the-eventfuncs">
|
||
<h3>The eventfuncs<a class="headerlink" href="#the-eventfuncs" title="Permalink to this headline">¶</a></h3>
|
||
<p>In order to make development a little easier, the in-game Python system provides eventfuncs to be used in
|
||
callbacks themselves. You don’t have to use them, they are just shortcuts. An eventfunc is just a
|
||
simple function that can be used inside of your callback code.</p>
|
||
<table class="colwidths-auto docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head"><p>Function</p></th>
|
||
<th class="head"><p>Argument</p></th>
|
||
<th class="head"><p>Description</p></th>
|
||
<th class="head"><p>Example</p></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td><p>deny</p></td>
|
||
<td><p><code class="docutils literal notranslate"><span class="pre">()</span></code></p></td>
|
||
<td><p>Prevent an action from happening.</p></td>
|
||
<td><p><code class="docutils literal notranslate"><span class="pre">deny()</span></code></p></td>
|
||
</tr>
|
||
<tr class="row-odd"><td><p>get</p></td>
|
||
<td><p><code class="docutils literal notranslate"><span class="pre">(**kwargs)</span></code></p></td>
|
||
<td><p>Get a single object.</p></td>
|
||
<td><p><code class="docutils literal notranslate"><span class="pre">char</span> <span class="pre">=</span> <span class="pre">get(id=1)</span></code></p></td>
|
||
</tr>
|
||
<tr class="row-even"><td><p>call_event</p></td>
|
||
<td><p><code class="docutils literal notranslate"><span class="pre">(obj,</span> <span class="pre">name,</span> <span class="pre">seconds=0)</span></code></p></td>
|
||
<td><p>Call another event.</p></td>
|
||
<td><p><code class="docutils literal notranslate"><span class="pre">call_event(char,</span> <span class="pre">"chain_1",</span> <span class="pre">20)</span></code></p></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<section id="deny">
|
||
<h4>deny<a class="headerlink" href="#deny" title="Permalink to this headline">¶</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">deny()</span></code> function allows to interrupt the callback and the action that called it. In the
|
||
<code class="docutils literal notranslate"><span class="pre">can_*</span></code> events, it can be used to prevent the action from happening. For instance, in <code class="docutils literal notranslate"><span class="pre">can_say</span></code> on
|
||
rooms, it can prevent the character from saying something in the room. One could have a <code class="docutils literal notranslate"><span class="pre">can_eat</span></code>
|
||
event set on food that would prevent this character from eating this food.</p>
|
||
<p>Behind the scenes, the <code class="docutils literal notranslate"><span class="pre">deny()</span></code> function raises an exception that is being intercepted by the
|
||
handler of events. The handler will then report that the action was cancelled.</p>
|
||
</section>
|
||
<section id="get">
|
||
<h4>get<a class="headerlink" href="#get" title="Permalink to this headline">¶</a></h4>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">get</span></code> eventfunc is a shortcut to get a single object with a specific identity. It’s often used
|
||
to retrieve an object with a given ID. In the section dedicated to <a class="reference internal" href="#chained-events"><span class="std std-doc">chained
|
||
events</span></a>, you will see a concrete example of this function in action.</p>
|
||
</section>
|
||
<section id="call-event">
|
||
<h4>call_event<a class="headerlink" href="#call-event" title="Permalink to this headline">¶</a></h4>
|
||
<p>Some callbacks will call other events. It is particularly useful for <a class="reference internal" href="#chained-events"><span class="std std-doc">chained
|
||
events</span></a> that are described in a dedicated section. This eventfunc is used to call
|
||
another event, immediately or in a defined time.</p>
|
||
<p>You need to specify as first parameter the object containing the event. The second parameter is the
|
||
name of the event to call. The third parameter is the number of seconds before calling this event.
|
||
By default, this parameter is set to 0 (the event is called immediately).</p>
|
||
</section>
|
||
</section>
|
||
<section id="variables-in-callbacks">
|
||
<h3>Variables in callbacks<a class="headerlink" href="#variables-in-callbacks" title="Permalink to this headline">¶</a></h3>
|
||
<p>In the Python code you will enter in individual callbacks, you will have access to variables in your
|
||
locals. These variables will depend on the event, and will be clearly listed when you add or edit a
|
||
callback. As you’ve seen in the previous example, when we manipulate characters or character
|
||
actions, we often have a <code class="docutils literal notranslate"><span class="pre">character</span></code> variable that holds the character doing the action.</p>
|
||
<p>In most cases, when an event is fired, all callbacks from this event are called. Variables are
|
||
created for each event. Sometimes, however, the callback will execute and then ask for a variable
|
||
in your locals: in other words, some callbacks can alter the actions being performed by changing
|
||
values of variables. This is always clearly specified in the help of the event.</p>
|
||
<p>One example that will illustrate this system is the “msg_leave” event that can be set on exits.
|
||
This event can alter the message that will be sent to other characters when someone leaves through
|
||
this exit.</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add down = msg_leave
|
||
</pre></div>
|
||
</div>
|
||
<p>Which should display:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="n">through</span> <span class="n">this</span> <span class="n">exit</span><span class="o">.</span>
|
||
<span class="n">This</span> <span class="n">event</span> <span class="ow">is</span> <span class="n">called</span> <span class="n">when</span> <span class="n">a</span> <span class="n">character</span> <span class="n">leaves</span> <span class="n">through</span> <span class="n">this</span> <span class="n">exit</span><span class="o">.</span>
|
||
<span class="n">To</span> <span class="n">customize</span> <span class="n">the</span> <span class="n">message</span> <span class="n">that</span> <span class="n">will</span> <span class="n">be</span> <span class="n">sent</span> <span class="n">to</span> <span class="n">the</span> <span class="n">room</span> <span class="n">where</span> <span class="n">the</span>
|
||
<span class="n">character</span> <span class="n">came</span> <span class="n">from</span><span class="p">,</span> <span class="n">change</span> <span class="n">the</span> <span class="n">value</span> <span class="n">of</span> <span class="n">the</span> <span class="n">variable</span> <span class="s2">"message"</span>
|
||
<span class="n">to</span> <span class="n">give</span> <span class="n">it</span> <span class="n">your</span> <span class="n">custom</span> <span class="n">message</span><span class="o">.</span> <span class="n">The</span> <span class="n">character</span> <span class="n">itself</span> <span class="n">will</span> <span class="ow">not</span> <span class="n">be</span>
|
||
<span class="n">notified</span><span class="o">.</span> <span class="n">You</span> <span class="n">can</span> <span class="n">use</span> <span class="n">mapping</span> <span class="n">between</span> <span class="n">braces</span><span class="p">,</span> <span class="n">like</span> <span class="n">this</span><span class="p">:</span>
|
||
<span class="n">message</span> <span class="o">=</span> <span class="s2">"</span><span class="si">{character}</span><span class="s2"> falls into a hole!"</span>
|
||
<span class="n">In</span> <span class="n">your</span> <span class="n">mapping</span><span class="p">,</span> <span class="n">you</span> <span class="n">can</span> <span class="n">use</span> <span class="p">{</span><span class="n">character</span><span class="p">}</span> <span class="p">(</span><span class="n">the</span> <span class="n">character</span> <span class="n">who</span> <span class="ow">is</span>
|
||
<span class="n">about</span> <span class="n">to</span> <span class="n">leave</span><span class="p">),</span> <span class="p">{</span><span class="n">exit</span><span class="p">}</span> <span class="p">(</span><span class="n">the</span> <span class="n">exit</span><span class="p">),</span> <span class="p">{</span><span class="n">origin</span><span class="p">}</span> <span class="p">(</span><span class="n">the</span> <span class="n">room</span> <span class="ow">in</span> <span class="n">which</span>
|
||
<span class="n">the</span> <span class="n">character</span> <span class="ow">is</span><span class="p">),</span> <span class="ow">and</span> <span class="p">{</span><span class="n">destination</span><span class="p">}</span> <span class="p">(</span><span class="n">the</span> <span class="n">room</span> <span class="ow">in</span> <span class="n">which</span> <span class="n">the</span> <span class="n">character</span>
|
||
<span class="ow">is</span> <span class="n">heading</span> <span class="k">for</span><span class="p">)</span><span class="o">.</span> <span class="n">If</span> <span class="n">you</span> <span class="n">need</span> <span class="n">to</span> <span class="n">customize</span> <span class="n">the</span> <span class="n">message</span> <span class="k">with</span> <span class="n">other</span>
|
||
<span class="n">information</span><span class="p">,</span> <span class="n">you</span> <span class="n">can</span> <span class="n">also</span> <span class="nb">set</span> <span class="s2">"message"</span> <span class="n">to</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">send</span> <span class="n">something</span>
|
||
<span class="k">else</span> <span class="n">instead</span><span class="o">.</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">who</span> <span class="ow">is</span> <span class="n">leaving</span> <span class="n">through</span> <span class="n">this</span> <span class="n">exit</span><span class="o">.</span>
|
||
<span class="n">exit</span><span class="p">:</span> <span class="n">the</span> <span class="n">exit</span> <span class="n">being</span> <span class="n">traversed</span><span class="o">.</span>
|
||
<span class="n">origin</span><span class="p">:</span> <span class="n">the</span> <span class="n">location</span> <span class="n">of</span> <span class="n">the</span> <span class="n">character</span><span class="o">.</span>
|
||
<span class="n">destination</span><span class="p">:</span> <span class="n">the</span> <span class="n">destination</span> <span class="n">of</span> <span class="n">the</span> <span class="n">character</span><span class="o">.</span>
|
||
<span class="n">message</span><span class="p">:</span> <span class="n">the</span> <span class="n">message</span> <span class="n">to</span> <span class="n">be</span> <span class="n">displayed</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">location</span><span class="o">.</span>
|
||
<span class="n">mapping</span><span class="p">:</span> <span class="n">a</span> <span class="n">dictionary</span> <span class="n">containing</span> <span class="n">additional</span> <span class="n">mapping</span><span class="o">.</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you write something like this in your event:</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"> falls into a hole in the ground!"</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>And if the character Wilfred takes this exit, others in the room will see:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Wildred falls into a hole in the ground!
|
||
</pre></div>
|
||
</div>
|
||
<p>In this case, the in-game Python system placed the variable “message” in the callback locals, but will read
|
||
from it when the event has been executed.</p>
|
||
</section>
|
||
<section id="callbacks-with-parameters">
|
||
<h3>Callbacks with parameters<a class="headerlink" href="#callbacks-with-parameters" title="Permalink to this headline">¶</a></h3>
|
||
<p>Some callbacks are called without parameter. It has been the case for all examples we have seen
|
||
before. In some cases, you can create callbacks that are triggered under only some conditions. A
|
||
typical example is the room’s “say” event. This event is triggered when somebody says something in
|
||
the room. Individual callbacks set on this event can be configured to fire only when some words are
|
||
used in the sentence.</p>
|
||
<p>For instance, let’s say we want to create a cool voice-operated elevator. You enter into the
|
||
elevator and say the floor number… and the elevator moves in the right direction. In this case,
|
||
we could create an callback with the parameter “one”:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = say one
|
||
</pre></div>
|
||
</div>
|
||
<p>This callback will only fire when the user says a sentence that contains “one”.</p>
|
||
<p>But what if we want to have a callback that would fire if the user says 1 or one? We can provide
|
||
several parameters, separated by a comma.</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = say 1, one
|
||
</pre></div>
|
||
</div>
|
||
<p>Or, still more keywords:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = say 1, one, ground
|
||
</pre></div>
|
||
</div>
|
||
<p>This time, the user could say something like “take me to the ground floor” (“ground” is one of our
|
||
keywords defined in the above callback).</p>
|
||
<p>Not all events can take parameters, and these who do have different ways of handling them. There
|
||
isn’t a single meaning to parameters that could apply to all events. Refer to the event
|
||
documentation for details.</p>
|
||
<blockquote>
|
||
<div><p>If you get confused between callback variables and parameters, think of parameters as checks
|
||
performed before the callback is run. Event with parameters will only fire some specific
|
||
callbacks, not all of them.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="time-related-events">
|
||
<h3>Time-related events<a class="headerlink" href="#time-related-events" title="Permalink to this headline">¶</a></h3>
|
||
<p>Events are usually linked to commands, as we saw before. However, this is not always the case.
|
||
Events can be triggered by other actions and, as we’ll see later, could even be called from inside
|
||
other events!</p>
|
||
<p>There is a specific event, on all objects, that can trigger at a specific time. It’s an event with
|
||
a mandatory parameter, which is the time you expect this event to fire.</p>
|
||
<p>For instance, let’s add an event on this room that should trigger every day, at precisely 12:00 PM
|
||
(the time is given as game time, not real time):</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call here = time 12:00
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># This will be called every MUD day at 12:00 PM</span>
|
||
<span class="n">room</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">"It's noon, time to have lunch!"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Now, at noon every MUD day, this event will fire and this callback will be executed. You can use
|
||
this event on every kind of typeclassed object, to have a specific action done every MUD day at the
|
||
same time.</p>
|
||
<p>Time-related events can be much more complex than this. They can trigger every in-game hour or more
|
||
often (it might not be a good idea to have events trigger that often on a lot of objects). You can
|
||
have events that run every in-game week or month or year. It will greatly vary depending on the
|
||
type of calendar used in your game. The number of time units is described in the game
|
||
configuration.</p>
|
||
<p>With a standard calendar, for instance, you have the following units: minutes, hours, days, months
|
||
and years. You will specify them as numbers separated by either a colon (:), a space ( ), or a dash
|
||
(-). Pick whatever feels more appropriate (usually, we separate hours and minutes with a colon, the
|
||
other units with a dash).</p>
|
||
<p>Some examples of syntax:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">18:30</span></code>: every day at 6:30 PM.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">01</span> <span class="pre">12:00</span></code>: every month, the first day, at 12 PM.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">06-15</span> <span class="pre">09:58</span></code>: every year, on the 15th of June (month comes before day), at 9:58 AM.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">2025-01-01</span> <span class="pre">00:00</span></code>: January 1st, 2025 at midnight (obviously, this will trigger only once).</p></li>
|
||
</ul>
|
||
<p>Notice that we specify units in the reverse order (year, month, day, hour and minute) and separate
|
||
them with logical separators. The smallest unit that is not defined is going to set how often the
|
||
event should fire. That’s why, if you use <code class="docutils literal notranslate"><span class="pre">12:00</span></code>, the smallest unit that is not defined is “day”:
|
||
the event will fire every day at the specified time.</p>
|
||
<blockquote>
|
||
<div><p>You can use chained events (see below) in conjunction with time-related events to create more
|
||
random or frequent actions in events.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="chained-events">
|
||
<h3>Chained events<a class="headerlink" href="#chained-events" title="Permalink to this headline">¶</a></h3>
|
||
<p>Callbacks can call other events, either now or a bit later. It is potentially very powerful.</p>
|
||
<p>To use chained events, just use the <code class="docutils literal notranslate"><span class="pre">call_event</span></code> eventfunc. It takes 2-3 arguments:</p>
|
||
<ul class="simple">
|
||
<li><p>The object containing the event.</p></li>
|
||
<li><p>The name of the event to call.</p></li>
|
||
<li><p>Optionally, the number of seconds to wait before calling this event.</p></li>
|
||
</ul>
|
||
<p>All objects have events that are not triggered by commands or game-related operations. They are
|
||
called “chain_X”, like “chain_1”, “chain_2”, “chain_3” and so on. You can give them more specific
|
||
names, as long as it begins by “chain_”, like “chain_flood_room”.</p>
|
||
<p>Rather than a long explanation, let’s look at an example: a subway that will go from one place to
|
||
the next at regular times. Connecting exits (opening its doors), waiting a bit, closing them,
|
||
rolling around and stopping at a different station. That’s quite a complex set of callbacks, as it
|
||
is, but let’s only look at the part that opens and closes the doors:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = time 10:00
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># At 10:00 AM, the subway arrives in the room of ID 22.</span>
|
||
<span class="c1"># Notice that exit #23 and #24 are respectively the exit leading</span>
|
||
<span class="c1"># on the platform and back in the subway.</span>
|
||
<span class="n">station</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">22</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">23</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">24</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Open the door</span>
|
||
<span class="n">to_exit</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s2">"platform"</span>
|
||
<span class="n">to_exit</span><span class="o">.</span><span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"p"</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">room</span>
|
||
<span class="n">to_exit</span><span class="o">.</span><span class="n">destination</span> <span class="o">=</span> <span class="n">station</span>
|
||
<span class="n">back_exit</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="s2">"subway"</span>
|
||
<span class="n">back_exit</span><span class="o">.</span><span class="n">location</span> <span class="o">=</span> <span class="n">station</span>
|
||
<span class="n">back_exit</span><span class="o">.</span><span class="n">destination</span> <span class="o">=</span> <span class="n">room</span>
|
||
|
||
<span class="c1"># Display some messages</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 open and wind gushes in the subway"</span><span class="p">)</span>
|
||
<span class="n">station</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">"The doors of the subway open with a dull clank."</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Set the doors to close in 20 seconds</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">20</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This callback will:</p>
|
||
<ol class="simple">
|
||
<li><p>Be called at 10:00 AM (specify 22:00 to set it to 10:00 PM).</p></li>
|
||
<li><p>Set an exit between the subway and the station. Notice that the exits already exist (you will
|
||
not have to create them), but they don’t need to have specific location and destination.</p></li>
|
||
<li><p>Display a message both in the subway and on the platform.</p></li>
|
||
<li><p>Call the event “chain_1” to execute in 20 seconds.</p></li>
|
||
</ol>
|
||
<p>And now, what should we have in “chain_1”?</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>call/add here = chain_1
|
||
</pre></div>
|
||
</div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Close the doors</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">to_exit</span><span class="o">.</span><span class="n">destination</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">back_exit</span><span class="o">.</span><span class="n">destination</span> <span class="o">=</span> <span class="kc">None</span>
|
||
<span class="n">room</span><span class="o">.</span><span class="n">msg_content</span><span class="p">(</span><span class="s2">"After a short warning signal, the doors close and the subway begins moving."</span><span class="p">)</span>
|
||
<span class="n">station</span><span class="o">.</span><span class="n">msg_content</span><span class="p">(</span><span class="s2">"After a short warning signal, the doors close and the subway begins moving."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Behind the scenes, the <code class="docutils literal notranslate"><span class="pre">call_event</span></code> function freezes all variables (“room”, “station”, “to_exit”,
|
||
“back_exit” in our example), so you don’t need to define them again.</p>
|
||
<p>A word of caution on callbacks that call chained events: it isn’t impossible for a callback to call
|
||
itself at some recursion level. If <code class="docutils literal notranslate"><span class="pre">chain_1</span></code> calls <code class="docutils literal notranslate"><span class="pre">chain_2</span></code> that calls <code class="docutils literal notranslate"><span class="pre">chain_3</span></code> that calls
|
||
<code class="docutils literal notranslate"><span class="pre">chain_</span></code>, particularly if there’s no pause between them, you might run into an infinite loop.</p>
|
||
<p>Be also careful when it comes to handling characters or objects that may very well move during your
|
||
pause between event calls. When you use <code class="docutils literal notranslate"><span class="pre">call_event()</span></code>, the MUD doesn’t pause and commands can be
|
||
entered by players, fortunately. It also means that, a character could start an event that pauses
|
||
for awhile, but be gone when the chained event is called. You need to check that, even lock the
|
||
character into place while you are pausing (some actions should require locking) or at least,
|
||
checking that the character is still in the room, for it might create illogical situations if you
|
||
don’t.</p>
|
||
<blockquote>
|
||
<div><p>Chained events are a special case: contrary to standard events, they are created in-game, not
|
||
through code. They usually contain only one callback, although nothing prevents you from creating
|
||
several chained events in the same object.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
</section>
|
||
<section id="using-events-in-code">
|
||
<h2>Using events in code<a class="headerlink" href="#using-events-in-code" title="Permalink to this headline">¶</a></h2>
|
||
<p>This section describes callbacks and events from code, how to create new events, how to call them in
|
||
a command, and how to handle specific cases like parameters.</p>
|
||
<p>Along this section, we will see how to implement the following example: we would like to create a
|
||
“push” command that could be used to push objects. Objects could react to this command and have
|
||
specific events fired.</p>
|
||
<section id="adding-new-events">
|
||
<h3>Adding new events<a class="headerlink" href="#adding-new-events" title="Permalink to this headline">¶</a></h3>
|
||
<p>Adding new events should be done in your typeclasses. Events are contained in the <code class="docutils literal notranslate"><span class="pre">_events</span></code> class
|
||
variable, a dictionary of event names as keys, and tuples to describe these events as values. You
|
||
also need to register this class, to tell the in-game Python system that it contains events to be added to
|
||
this typeclass.</p>
|
||
<p>Here, we want to add a “push” event on objects. In your <code class="docutils literal notranslate"><span class="pre">typeclasses/objects.py</span></code> file, you should
|
||
write something like:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.contrib.base_systems.ingame_python.utils</span> <span class="kn">import</span> <span class="n">register_events</span>
|
||
<span class="kn">from</span> <span class="nn">evennia.contrib.base_systems.ingame_python.typeclasses</span> <span class="kn">import</span> <span class="n">EventObject</span>
|
||
|
||
<span class="n">EVENT_PUSH</span> <span class="o">=</span> <span class="s2">"""</span>
|
||
<span class="s2">A character push the object.</span>
|
||
<span class="s2">This event is called when a character uses the "push" command on</span>
|
||
<span class="s2">an object in the same room.</span>
|
||
|
||
<span class="s2">Variables you can use in this event:</span>
|
||
<span class="s2"> character: the character that pushes this object.</span>
|
||
<span class="s2"> obj: the object connected to this event.</span>
|
||
<span class="s2">"""</span>
|
||
|
||
<span class="nd">@register_events</span>
|
||
<span class="k">class</span> <span class="nc">Object</span><span class="p">(</span><span class="n">EventObject</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> Class representing objects.</span>
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="n">_events</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s2">"push"</span><span class="p">:</span> <span class="p">([</span><span class="s2">"character"</span><span class="p">,</span> <span class="s2">"obj"</span><span class="p">],</span> <span class="n">EVENT_PUSH</span><span class="p">),</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><p>Line 1-2: we import several things we will need from the in-game Python system. Note that we use
|
||
<code class="docutils literal notranslate"><span class="pre">EventObject</span></code> as a parent instead of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, as explained in the installation.</p></li>
|
||
<li><p>Line 4-12: we usually define the help of the event in a separate variable, this is more readable,
|
||
though there’s no rule against doing it another way. Usually, the help should contain a short
|
||
explanation on a single line, a longer explanation on several lines, and then the list of variables
|
||
with explanations.</p></li>
|
||
<li><p>Line 14: we call a decorator on the class to indicate it contains events. If you’re not familiar
|
||
with decorators, you don’t really have to worry about it, just remember to put this line just
|
||
above the class definition if your class contains events.</p></li>
|
||
<li><p>Line 15: we create the class inheriting from <code class="docutils literal notranslate"><span class="pre">EventObject</span></code>.</p></li>
|
||
<li><p>Line 20-22: we define the events of our objects in an <code class="docutils literal notranslate"><span class="pre">_events</span></code> class variable. It is a
|
||
dictionary. Keys are event names. Values are a tuple containing:</p>
|
||
<ul>
|
||
<li><p>The list of variable names (list of str). This will determine what variables are needed when
|
||
the event triggers. These variables will be used in callbacks (as we’ll see below).</p></li>
|
||
<li><p>The event help (a str, the one we have defined above).</p></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>If you add this code and reload your game, create an object and examine its events with <code class="docutils literal notranslate"><span class="pre">@call</span></code>, you
|
||
should see the “push” event with its help. Of course, right now, the event exists, but it’s not
|
||
fired.</p>
|
||
</section>
|
||
<section id="calling-an-event-in-code">
|
||
<h3>Calling an event in code<a class="headerlink" href="#calling-an-event-in-code" title="Permalink to this headline">¶</a></h3>
|
||
<p>The in-game Python system is accessible through a handler on all objects. This handler is named <code class="docutils literal notranslate"><span class="pre">callbacks</span></code>
|
||
and can be accessed from any typeclassed object (your character, a room, an exit…). This handler
|
||
offers several methods to examine and call an event or callback on this object.</p>
|
||
<p>To call an event, use the <code class="docutils literal notranslate"><span class="pre">callbacks.call</span></code> method in an object. It takes as argument:</p>
|
||
<ul class="simple">
|
||
<li><p>The name of the event to call.</p></li>
|
||
<li><p>All variables that will be accessible in the event as positional arguments. They should be
|
||
specified in the order chosen when <a class="reference internal" href="#adding-new-events"><span class="std std-doc">creating new events</span></a>.</p></li>
|
||
</ul>
|
||
<p>Following the same example, so far, we have created an event on all objects, called “push”. This
|
||
event is never fired for the time being. We could add a “push” command, taking as argument the name
|
||
of an object. If this object is valid, it will call its “push” event.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">commands.command</span> <span class="kn">import</span> <span class="n">Command</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CmdPush</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"> Push something.</span>
|
||
|
||
<span class="sd"> Usage:</span>
|
||
<span class="sd"> push <something></span>
|
||
|
||
<span class="sd"> Push something where you are, like an elevator button.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"push"</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="w"> </span><span class="sd">"""Called when pushing something."""</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Usage: push <something>"</span><span class="p">)</span>
|
||
<span class="k">return</span>
|
||
|
||
<span class="c1"># Search for this object</span>
|
||
<span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="p">:</span>
|
||
<span class="k">return</span>
|
||
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"You push </span><span class="si">{}</span><span class="s2">."</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">get_display_name</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)))</span>
|
||
|
||
<span class="c1"># Call the "push" event of this object</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">callbacks</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="s2">"push"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Here we use <code class="docutils literal notranslate"><span class="pre">callbacks.call</span></code> with the following arguments:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">"push"</span></code>: the name of the event to be called.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">self.caller</span></code>: the one who pushed the button (this is our first variable, <code class="docutils literal notranslate"><span class="pre">character</span></code>).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code>: the object being pushed (our second variable, <code class="docutils literal notranslate"><span class="pre">obj</span></code>).</p></li>
|
||
</ul>
|
||
<p>In the “push” callbacks of our objects, we then can use the “character” variable (containing the one
|
||
who pushed the object), and the “obj” variable (containing the object that was pushed).</p>
|
||
</section>
|
||
<section id="see-it-all-work">
|
||
<h3>See it all work<a class="headerlink" href="#see-it-all-work" title="Permalink to this headline">¶</a></h3>
|
||
<p>To see the effect of the two modifications above (the added event and the “push” command), let us
|
||
create a simple object:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@create/drop rock
|
||
@desc rock = It's a single rock, apparently pretty heavy. Perhaps you can try to push it though.
|
||
@call/add rock = push
|
||
</pre></div>
|
||
</div>
|
||
<p>In the callback you could write:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span>
|
||
<span class="n">number</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">6</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">"You push a rock... is... it... going... to... move?"</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="n">number</span> <span class="o">==</span> <span class="mi">6</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 rock topples over to reveal a beautiful ant-hill!"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>You can now try to “push rock”. You’ll try to push the rock, and once out of six times, you will
|
||
see a message about a “beautiful ant-hill”.</p>
|
||
</section>
|
||
<section id="adding-new-eventfuncs">
|
||
<h3>Adding new eventfuncs<a class="headerlink" href="#adding-new-eventfuncs" title="Permalink to this headline">¶</a></h3>
|
||
<p>Eventfuncs, like <code class="docutils literal notranslate"><span class="pre">deny()</span></code>, are defined in
|
||
<code class="docutils literal notranslate"><span class="pre">contrib/base_systesm/ingame_python/eventfuncs.py</span></code>. You can add your own
|
||
eventfuncs by creating a file named <code class="docutils literal notranslate"><span class="pre">eventfuncs.py</span></code> in your <code class="docutils literal notranslate"><span class="pre">world</span></code> directory.
|
||
The functions defined in this file will be added as helpers.</p>
|
||
<p>You can also decide to create your eventfuncs in another location, or even in
|
||
several locations. To do so, edit the <code class="docutils literal notranslate"><span class="pre">EVENTFUNCS_LOCATION</span></code> setting in your
|
||
<code class="docutils literal notranslate"><span class="pre">server/conf/settings.py</span></code> file, specifying either a python path or a list of
|
||
Python paths in which your helper functions are defined. For instance:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">EVENTFUNCS_LOCATIONS</span> <span class="o">=</span> <span class="p">[</span>
|
||
<span class="s2">"world.events.functions"</span><span class="p">,</span>
|
||
<span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="creating-events-with-parameters">
|
||
<h3>Creating events with parameters<a class="headerlink" href="#creating-events-with-parameters" title="Permalink to this headline">¶</a></h3>
|
||
<p>If you want to create events with parameters (if you create a “whisper” or “ask” command, for
|
||
instance, and need to have some characters automatically react to words), you can set an additional
|
||
argument in the tuple of events in your typeclass’ <code class="docutils literal notranslate"><span class="pre">_events</span></code> class variable. This third argument
|
||
must contain a callback that will be called to filter through the list of callbacks when the event
|
||
fires. Two types of parameters are commonly used (but you can define more parameter types, although
|
||
this is out of the scope of this documentation).</p>
|
||
<ul class="simple">
|
||
<li><p>Keyword parameters: callbacks of this event will be filtered based on specific keywords. This is
|
||
useful if you want the user to specify a word and compare this word to a list.</p></li>
|
||
<li><p>Phrase parameters: callbacks will be filtered using an entire phrase and checking all its words.
|
||
The “say” command uses phrase parameters (you can set a “say” callback to fires if a phrase
|
||
contains one specific word).</p></li>
|
||
</ul>
|
||
<p>In both cases, you need to import a function from
|
||
<code class="docutils literal notranslate"><span class="pre">evennia.contrib.base_systems.ingame_python.utils</span></code> and use it as third parameter in your
|
||
event definition.</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">keyword_event</span></code> should be used for keyword parameters.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">phrase_event</span></code> should be used for phrase parameters.</p></li>
|
||
</ul>
|
||
<p>For example, here is the definition of the “say” event:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.contrib.base_systems.ingame_python.utils</span> <span class="kn">import</span> <span class="n">register_events</span><span class="p">,</span> <span class="n">phrase_event</span>
|
||
<span class="c1"># ...</span>
|
||
<span class="nd">@register_events</span>
|
||
<span class="k">class</span> <span class="nc">SomeTypeclass</span><span class="p">:</span>
|
||
<span class="n">_events</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s2">"say"</span><span class="p">:</span> <span class="p">([</span><span class="s2">"speaker"</span><span class="p">,</span> <span class="s2">"character"</span><span class="p">,</span> <span class="s2">"message"</span><span class="p">],</span> <span class="n">CHARACTER_SAY</span><span class="p">,</span> <span class="n">phrase_event</span><span class="p">),</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When you call an event using the <code class="docutils literal notranslate"><span class="pre">obj.callbacks.call</span></code> method, you should also provide the parameter,
|
||
using the <code class="docutils literal notranslate"><span class="pre">parameters</span></code> keyword:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj</span><span class="o">.</span><span class="n">callbacks</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="o">...</span><span class="p">,</span> <span class="n">parameters</span><span class="o">=</span><span class="s2">"<put parameters here>"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>It is necessary to specifically call the event with parameters, otherwise the system will not be
|
||
able to know how to filter down the list of callbacks.</p>
|
||
</section>
|
||
</section>
|
||
<section id="disabling-all-events-at-once">
|
||
<h2>Disabling all events at once<a class="headerlink" href="#disabling-all-events-at-once" title="Permalink to this headline">¶</a></h2>
|
||
<p>When callbacks are running in an infinite loop, for instance, or sending unwanted information to
|
||
players or other sources, you, as the game administrator, have the power to restart without events.
|
||
The best way to do this is to use a custom setting, in your setting file
|
||
(<code class="docutils literal notranslate"><span class="pre">server/conf/settings.py</span></code>):</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Disable all events</span>
|
||
<span class="n">EVENTS_DISABLED</span> <span class="o">=</span> <span class="kc">True</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The in-game Python system will still be accessible (you will have access to the <code class="docutils literal notranslate"><span class="pre">call</span></code> command, to debug),
|
||
but no event will be called automatically.</p>
|
||
<div class="toctree-wrapper compound">
|
||
</div>
|
||
<hr class="docutils" />
|
||
<p><small>This document page is generated from <code class="docutils literal notranslate"><span class="pre">evennia/contrib/base_systems/ingame_python/README.md</span></code>. Changes to this
|
||
file will be overwritten, so edit that file rather than this one.</small></p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Contrib-Ingame-Python-Tutorial-Dialogue.html" title="Dialogues in events"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Contrib-Godotwebsocket.html" title="Godot Websocket"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Contribs-Overview.html" >Contribs</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Evennia in-game Python system</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> |