evennia/docs/1.0-dev/Components/Scripts.html
2020-11-14 12:27:06 +01:00

539 lines
No EOL
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Scripts &#8212; Evennia 1.0-dev 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="scripts">
<h1>Scripts<a class="headerlink" href="#scripts" title="Permalink to this headline"></a></h1>
<p><em>Scripts</em> are the out-of-character siblings to the in-character
<a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>. Scripts are so flexible that the “Script” is a bit limiting</p>
<ul class="simple">
<li><p>we had to pick something to name them after all. Other possible names
(depending on what youd use them for) would be <code class="docutils literal notranslate"><span class="pre">OOBObjects</span></code>,
<code class="docutils literal notranslate"><span class="pre">StorageContainers</span></code> or <code class="docutils literal notranslate"><span class="pre">TimerObjects</span></code>.</p></li>
</ul>
<p>Scripts can be used for many different things in Evennia:</p>
<ul class="simple">
<li><p>They can attach to Objects to influence them in various ways - or exist
independently of any one in-game entity (so-called <em>Global Scripts</em>).</p></li>
<li><p>They can work as timers and tickers - anything that may change with Time. But
they can also have no time dependence at all. Note though that if all you want
is just to have an object method called repeatedly, you should consider using
the <a class="reference internal" href="TickerHandler.html"><span class="doc">TickerHandler</span></a> which is more limited but is specialized on
just this task.</p></li>
<li><p>They can describe State changes. A Script is an excellent platform for
hosting a persistent, but unique system handler. For example, a Script could be
used as the base to track the state of a turn-based combat system. Since
Scripts can also operate on a timer they can also update themselves regularly
to perform various actions.</p></li>
<li><p>They can act as data stores for storing game data persistently in the database
(thanks to its ability to have <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a>).</p></li>
<li><p>They can be used as OOC stores for sharing data between groups of objects, for
example for tracking the turns in a turn-based combat system or barter exchange.</p></li>
</ul>
<p>Scripts are <a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> entities and are manipulated in a similar
way to how it works for other such Evennia entities:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># create a new script </span>
<span class="n">new_script</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;myscript&quot;</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=...</span><span class="p">)</span>
<span class="c1"># search (this is always a list, also if there is only one match)</span>
<span class="n">list_of_myscript</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_script</span><span class="p">(</span><span class="s2">&quot;myscript&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<div class="section" id="defining-new-scripts">
<h2>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline"></a></h2>
<p>A Script is defined as a class and is created in the same way as other
<a class="reference internal" href="Typeclasses.html"><span class="doc">typeclassed</span></a> entities. The class has several properties
to control the timer-component of the scripts. These are all <em>optional</em> -
leaving them out will just create a Script with no timer components (useful to act as
a database store or to hold a persistent game system, for example).</p>
<p>This you can do for example in the module
<code class="docutils literal notranslate"><span class="pre">evennia/typeclasses/scripts.py</span></code>. Below is an example Script
Typeclass.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
<span class="k">class</span> <span class="nc">MyScript</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;myscript&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="c1"># 1 min repeat</span>
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># do stuff every minute </span>
</pre></div>
</td></tr></table></div>
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> is the <code class="docutils literal notranslate"><span class="pre">Script</span></code> class which inherits from <code class="docutils literal notranslate"><span class="pre">DefaultScript</span></code>
already. This is provided as your own base class to do with what you like: You can tweak <code class="docutils literal notranslate"><span class="pre">Script</span></code> if
you want to change the default behavior and it is usually convenient to inherit from this instead.
Heres an example:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># for example in mygame/typeclasses/scripts.py </span>
<span class="c1"># Script class is defined at the top of this module</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A timer script that displays weather info. Meant to </span>
<span class="sd"> be attached to a room. </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;weather_script&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">&quot;Gives random weather messages.&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">5</span> <span class="c1"># every 5 minutes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">persistent</span> <span class="o">=</span> <span class="bp">True</span> <span class="c1"># will survive reload</span>
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;called every self.interval seconds.&quot;</span>
<span class="n">rand</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span>
<span class="k">if</span> <span class="n">rand</span> <span class="o">&lt;</span> <span class="mf">0.5</span><span class="p">:</span>
<span class="n">weather</span> <span class="o">=</span> <span class="s2">&quot;A faint breeze is felt.&quot;</span>
<span class="k">elif</span> <span class="n">rand</span> <span class="o">&lt;</span> <span class="mf">0.7</span><span class="p">:</span>
<span class="n">weather</span> <span class="o">=</span> <span class="s2">&quot;Clouds sweep across the sky.&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">weather</span> <span class="o">=</span> <span class="s2">&quot;There is a light drizzle of rain.&quot;</span>
<span class="c1"># send this message to everyone inside the object this</span>
<span class="c1"># script is attached to (likely a room)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="n">weather</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>If we put this script on a room, it will randomly report some weather
to everyone in the room every 5 minutes.</p>
<p>To activate it, just add it to the script handler (<code class="docutils literal notranslate"><span class="pre">scripts</span></code>) on an
<a class="reference internal" href="Objects.html"><span class="doc">Room</span></a>. That object becomes <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> in the example above. Here we
put it on a room called <code class="docutils literal notranslate"><span class="pre">myroom</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">myroom</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">scripts</span><span class="o">.</span><span class="n">Weather</span><span class="p">)</span>
</pre></div>
</div>
<blockquote>
<div><p>Note that <code class="docutils literal notranslate"><span class="pre">typeclasses</span></code> in your game dir is added to the setting <code class="docutils literal notranslate"><span class="pre">TYPECLASS_PATHS</span></code>.
Therefore we dont need to give the full path (<code class="docutils literal notranslate"><span class="pre">typeclasses.scripts.Weather</span></code>
but only <code class="docutils literal notranslate"><span class="pre">scripts.Weather</span></code> above.</p>
</div></blockquote>
<p>You can also create scripts using the <code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code> function:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_script</span>
<span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.weather.Weather&#39;</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">myroom</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Note that if you were to give a keyword argument to <code class="docutils literal notranslate"><span class="pre">create_script</span></code>, that would
override the default value in your Typeclass. So for example, here is an instance
of the weather script that runs every 10 minutes instead (and also not survive
a server reload):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.weather.Weather&#39;</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">myroom</span><span class="p">,</span>
<span class="n">persistent</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">10</span><span class="o">*</span><span class="mi">60</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>From in-game you can use the <code class="docutils literal notranslate"><span class="pre">&#64;script</span></code> command to launch the Script on things:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nd">@script</span> <span class="n">here</span> <span class="o">=</span> <span class="n">typeclasses</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">Weather</span>
</pre></div>
</div>
<p>You can conveniently view and kill running Scripts by using the <code class="docutils literal notranslate"><span class="pre">&#64;scripts</span></code>
command in-game.</p>
</div>
<div class="section" id="properties-and-functions-defined-on-scripts">
<h2>Properties and functions defined on Scripts<a class="headerlink" href="#properties-and-functions-defined-on-scripts" title="Permalink to this headline"></a></h2>
<p>A Script has all the properties of a typeclassed object, such as <code class="docutils literal notranslate"><span class="pre">db</span></code> and <code class="docutils literal notranslate"><span class="pre">ndb</span></code>(see
<a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclasses</span></a>). Setting <code class="docutils literal notranslate"><span class="pre">key</span></code> is useful in order to manage scripts (delete them by name
etc). These are usually set up in the Scripts typeclass, but can also be assigned on the fly as
keyword arguments to <code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">desc</span></code> - an optional description of the scripts function. Seen in script listings.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">interval</span></code> - how often the script should run. If <code class="docutils literal notranslate"><span class="pre">interval</span> <span class="pre">==</span> <span class="pre">0</span></code> (default), this script has no
timing component, will not repeat and will exist forever. This is useful for Scripts used for
storage or acting as bases for various non-time dependent game systems.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">start_delay</span></code> - (bool), if we should wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds before firing for the first time or
not.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">repeats</span></code> - How many times we should repeat, assuming <code class="docutils literal notranslate"><span class="pre">interval</span> <span class="pre">&gt;</span> <span class="pre">0</span></code>. If repeats is set to <code class="docutils literal notranslate"><span class="pre">&lt;=</span> <span class="pre">0</span></code>,
the script will repeat indefinitely. Note that <em>each</em> firing of the script (including the first one)
counts towards this value. So a <code class="docutils literal notranslate"><span class="pre">Script</span></code> with <code class="docutils literal notranslate"><span class="pre">start_delay=False</span></code> and <code class="docutils literal notranslate"><span class="pre">repeats=1</span></code> will start,
immediately fire and shut down right away.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code>- if this script should survive a server <em>reset</em> or server <em>shutdown</em>. (You dont need
to set this for it to survive a normal reload - the script will be paused and seamlessly restart
after the reload is complete).</p></li>
</ul>
<p>There is one special property:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code> - the <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> this script is attached to (if any). You should not need to set
this manually. If you add the script to the Object with <code class="docutils literal notranslate"><span class="pre">myobj.scripts.add(myscriptpath)</span></code> or give
<code class="docutils literal notranslate"><span class="pre">myobj</span></code> as an argument to the <code class="docutils literal notranslate"><span class="pre">utils.create.create_script</span></code> function, the <code class="docutils literal notranslate"><span class="pre">obj</span></code> property will be set
to <code class="docutils literal notranslate"><span class="pre">myobj</span></code> for you.</p></li>
</ul>
<p>Its also imperative to know the hook functions. Normally, overriding
these are all the customization youll need to do in Scripts. You can
find longer descriptions of these in <code class="docutils literal notranslate"><span class="pre">src/scripts/scripts.py</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">at_script_creation()</span></code> - this is usually where the script class sets things like <code class="docutils literal notranslate"><span class="pre">interval</span></code> and
<code class="docutils literal notranslate"><span class="pre">repeats</span></code>; things that control how the script runs. It is only called once - when the script is
first created.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">is_valid()</span></code> - determines if the script should still be running or not. This is called when
running <code class="docutils literal notranslate"><span class="pre">obj.scripts.validate()</span></code>, which you can run manually, but which is also called by Evennia
during certain situations such as reloads. This is also useful for using scripts as state managers.
If the method returns <code class="docutils literal notranslate"><span class="pre">False</span></code>, the script is stopped and cleanly removed.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_start()</span></code> - this is called when the script starts or is unpaused. For persistent scripts this
is at least once ever server startup. Note that this will <em>always</em> be called right away, also if
<code class="docutils literal notranslate"><span class="pre">start_delay</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code> - this is called every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds, or not at all. It is called right away at
startup, unless <code class="docutils literal notranslate"><span class="pre">start_delay</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code>, in which case the system will wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds
before calling.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_stop()</span></code> - this is called when the script stops for whatever reason. Its a good place to do
custom cleanup.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_reload()</span></code> - this is called whenever the server is warm-rebooted (e.g. with the
<code class="docutils literal notranslate"><span class="pre">&#64;reload</span></code> command). Its a good place to save non-persistent data you might want to survive a
reload.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_shutdown()</span></code> - this is called when a system reset or systems shutdown is invoked.</p></li>
</ul>
<p>Running methods (usually called automatically by the engine, but possible to also invoke manually)</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">start()</span></code> - this will start the script. This is called automatically whenever you add a new script
to a handler. <code class="docutils literal notranslate"><span class="pre">at_start()</span></code> will be called.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">stop()</span></code> - this will stop the script and delete it. Removing a script from a handler will stop it
automatically. <code class="docutils literal notranslate"><span class="pre">at_stop()</span></code> will be called.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pause()</span></code> - this pauses a running script, rendering it inactive, but not deleting it. All
properties are saved and timers can be resumed. This is called automatically when the server reloads
and will <em>not</em> lead to the <em>at_stop()</em> hook being called. This is a suspension of the script, not a
change of state.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">unpause()</span></code> - resumes a previously paused script. The <code class="docutils literal notranslate"><span class="pre">at_start()</span></code> hook <em>will</em> be called to allow
it to reclaim its internal state. Timers etc are restored to what they were before pause. The server
automatically unpauses all paused scripts after a server reload.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">force_repeat()</span></code> - this will forcibly step the script, regardless of when it would otherwise have
fired. The timer will reset and the <code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code> hook is called as normal. This also counts towards
the total number of repeats, if limited.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">time_until_next_repeat()</span></code> - for timed scripts, this returns the time in seconds until it next
fires. Returns <code class="docutils literal notranslate"><span class="pre">None</span></code> if <code class="docutils literal notranslate"><span class="pre">interval==0</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">remaining_repeats()</span></code> - if the Script should run a limited amount of times, this tells us how many
are currently left.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">reset_callcount(value=0)</span></code> - this allows you to reset the number of times the Script has fired. It
only makes sense if <code class="docutils literal notranslate"><span class="pre">repeats</span> <span class="pre">&gt;</span> <span class="pre">0</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">restart(interval=None,</span> <span class="pre">repeats=None,</span> <span class="pre">start_delay=None)</span></code> - this method allows you to restart the
Script in-place with different run settings. If you do, the <code class="docutils literal notranslate"><span class="pre">at_stop</span></code> hook will be called and the
Script brought to a halt, then the <code class="docutils literal notranslate"><span class="pre">at_start</span></code> hook will be called as the Script starts up with your
(possibly changed) settings. Any keyword left at <code class="docutils literal notranslate"><span class="pre">None</span></code> means to not change the original setting.</p></li>
</ul>
</div>
<div class="section" id="global-scripts">
<h2>Global Scripts<a class="headerlink" href="#global-scripts" title="Permalink to this headline"></a></h2>
<p>A script does not have to be connected to an in-game object. If not it is
called a <em>Global script</em>. You can create global scripts by simply not supplying an object to store
it on:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># adding a global script</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_script</span>
<span class="n">create_script</span><span class="p">(</span><span class="s2">&quot;typeclasses.globals.MyGlobalEconomy&quot;</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="s2">&quot;economy&quot;</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Henceforth you can then get it back by searching for its key or other identifier with
<code class="docutils literal notranslate"><span class="pre">evennia.search_script</span></code>. In-game, the <code class="docutils literal notranslate"><span class="pre">scripts</span></code> command will show all scripts.</p>
<p>Evennia supplies a convenient “container” called <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> that can offer an easy
way to access global scripts. If you know the name (key) of the script you can get it like so:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
<span class="n">my_script</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">my_script</span>
<span class="c1"># needed if there are spaces in name or name determined on the fly</span>
<span class="n">another_script</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;another script&quot;</span><span class="p">)</span>
<span class="c1"># get all global scripts (this returns a Queryset)</span>
<span class="n">all_scripts</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="c1"># you can operate directly on the script</span>
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">weather</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">current_weather</span> <span class="o">=</span> <span class="s2">&quot;Cloudy&quot;</span>
</pre></div>
</td></tr></table></div>
<blockquote>
<div><p>Note that global scripts appear as properties on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> based on their <code class="docutils literal notranslate"><span class="pre">key</span></code>.
If you were to create two global scripts with the same <code class="docutils literal notranslate"><span class="pre">key</span></code> (even with different typeclasses),
the <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> container will only return one of them (which one depends on order in
the database). Best is to organize your scripts so that this does not happen. Otherwise, use
<code class="docutils literal notranslate"><span class="pre">evennia.search_script</span></code> to get exactly the script you want.</p>
</div></blockquote>
<p>There are two ways to make a script appear as a property on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>. The first is
to manually create a new global script with <code class="docutils literal notranslate"><span class="pre">create_script</span></code> as mentioned above. Often you want this
to happen automatically when the server starts though. For this you can use the setting
<code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">GLOBAL_SCRIPTS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;my_script&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;typeclass&quot;</span><span class="p">:</span> <span class="s2">&quot;scripts.Weather&quot;</span><span class="p">,</span>
<span class="s2">&quot;repeats&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
<span class="s2">&quot;interval&quot;</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span>
<span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Weather script&quot;</span>
<span class="s2">&quot;persistent&quot;</span><span class="p">:</span> <span class="bp">True</span>
<span class="p">},</span>
<span class="s2">&quot;storagescript&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;typeclass&quot;</span><span class="p">:</span> <span class="s2">&quot;scripts.Storage&quot;</span><span class="p">,</span>
<span class="s2">&quot;persistent&quot;</span><span class="p">:</span> <span class="bp">True</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>Here the key (<code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code> above) is required, all other fields are optional. If
<code class="docutils literal notranslate"><span class="pre">typeclass</span></code> is not given, a script of type <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> is assumed. The keys
related to timing and intervals are only needed if the script is timed.</p>
<p>Evennia will use the information in <code class="docutils literal notranslate"><span class="pre">settings.GLOBAL_SCRIPTS</span></code> to automatically create and start
these
scripts when the server starts (unless they already exist, based on their <code class="docutils literal notranslate"><span class="pre">key</span></code>). You need to reload
the server before the setting is read and new scripts become available. You can then find the <code class="docutils literal notranslate"><span class="pre">key</span></code>
you gave as properties on <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS</span></code>
(such as <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS.storagescript</span></code>).</p>
<blockquote>
<div><p>Note: Make sure that your Script typeclass does not have any critical errors. If so, youll see
errors in your log and your Script will temporarily fall back to being a <code class="docutils literal notranslate"><span class="pre">DefaultScript</span></code> type.</p>
</div></blockquote>
<p>Moreover, a script defined this way is <em>guaranteed</em> to exist when you try to access it:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
<span class="c1"># first stop the script </span>
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">storagescript</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
<span class="c1"># running the `scripts` command now will show no storagescript</span>
<span class="c1"># but below now it&#39;s recreated again! </span>
<span class="n">storage</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">storagescript</span>
</pre></div>
</td></tr></table></div>
<p>That is, if the script is deleted, next time you get it from <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>, it will use the
information
in settings to recreate it for you.</p>
<blockquote>
<div><p>Note that if your goal with the Script is to store persistent data, you should set it as
<code class="docutils literal notranslate"><span class="pre">persistent=True</span></code>, either in <code class="docutils literal notranslate"><span class="pre">settings.GLOBAL_SCRIPTS</span></code> or in the Scripts typeclass. Otherwise any
data you wanted to store on it will be gone (since a new script of the same name is restarted
instead).</p>
</div></blockquote>
</div>
<div class="section" id="dealing-with-errors">
<h2>Dealing with Errors<a class="headerlink" href="#dealing-with-errors" title="Permalink to this headline"></a></h2>
<p>Errors inside an timed, executing script can sometimes be rather terse or point to
parts of the execution mechanism that is hard to interpret. One way to make it
easier to debug scripts is to import Evennias native logger and wrap your
functions in a try/catch block. Evennias logger can show you where the
traceback occurred in your script.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></div></td><td class="code"><div class="highlight"><pre><span></span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
<span class="c1"># [...]</span>
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># [...] code as above</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="c1"># logs the error </span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="example-of-a-timed-script">
<h2>Example of a timed script<a class="headerlink" href="#example-of-a-timed-script" title="Permalink to this headline"></a></h2>
<p>In-game you can try out scripts using the <code class="docutils literal notranslate"><span class="pre">&#64;script</span></code> command. In the
<code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples/bodyfunctions.py</span></code> is a little example script
that makes you do little sounds at random intervals. Try the following to apply an
example time-based script to your character.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@script</span> <span class="bp">self</span> <span class="o">=</span> <span class="n">bodyfunctions</span><span class="o">.</span><span class="n">BodyFunctions</span>
</pre></div>
</div>
<blockquote>
<div><p>Note: Since <code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples</span></code> is in the default setting
<code class="docutils literal notranslate"><span class="pre">TYPECLASS_PATHS</span></code>, we only need to specify the final part of the path,
that is, <code class="docutils literal notranslate"><span class="pre">bodyfunctions.BodyFunctions</span></code>.</p>
</div></blockquote>
<p>If you want to inflict your flatulence script on another person, place or
thing, try something like the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@py</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s1">&#39;matt&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">&#39;bodyfunctions.BodyFunctions&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Heres how you stop it on yourself.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@script</span><span class="o">/</span><span class="n">stop</span> <span class="bp">self</span> <span class="o">=</span> <span class="n">bodyfunctions</span><span class="o">.</span><span class="n">BodyFunctions</span>
</pre></div>
</div>
<p>This will kill the script again. You can use the <code class="docutils literal notranslate"><span class="pre">&#64;scripts</span></code> command to list all
active scripts in the game, if any (there are none by default).</p>
<p>For another example of a Script in use, check out the <a class="reference external" href="https://github.com/evennia/evennia/wiki/Turn%20based%20Combat%20System">Turn Based Combat System
tutorial</a>.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Scripts</a><ul>
<li><a class="reference internal" href="#defining-new-scripts">Defining new Scripts</a></li>
<li><a class="reference internal" href="#properties-and-functions-defined-on-scripts">Properties and functions defined on Scripts</a></li>
<li><a class="reference internal" href="#global-scripts">Global Scripts</a></li>
<li><a class="reference internal" href="#dealing-with-errors">Dealing with Errors</a></li>
<li><a class="reference internal" href="#example-of-a-timed-script">Example of a timed script</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Scripts.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Scripts.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>