Updated HTML docs

This commit is contained in:
Griatch 2021-03-07 17:53:48 +01:00
parent 95b1772cdb
commit 9e40124c44
86 changed files with 2873 additions and 3808 deletions

View file

@ -39,55 +39,66 @@
<div class="section" id="scripts">
<h1>Scripts<a class="headerlink" href="#scripts" title="Permalink to this headline"></a></h1>
<p><a class="reference external" href="../api/evennia.scripts.scripts.html">Script API reference</a></p>
<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>
<a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>. Scripts are so flexible that the name “Script” is a bit limiting
in itself - but we had to pick <em>something</em> to name them. 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>
<p>If you ever consider creating an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> with a <code class="docutils literal notranslate"><span class="pre">None</span></code>-location just to store some game data,
you should really be using a Script instead.</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>
<li><p>Scripts are full <a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> entities - they have <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a> and
can be modified in the same way. But they have <em>no in-game existence</em>, so no
location or command-execution like <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a> and no connection to a particular
player/session like <a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a>. This means they are perfectly suitable for acting
as database-storage backends for game <em>systems</em>: Storing the current state of the economy,
who is involved in the current fight, tracking an ongoing barter and so on. They are great as
persistent system handlers.</p></li>
<li><p>Scripts have an optional <em>timer component</em>. This means that you can set up the script
to tick the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook on the Script at a certain interval. The timer can be controlled
independently of the rest of the script as needed. This component is optional
and complementary to other timing functions in Evennia, like
<a class="reference external" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay">evennia.utils.delay</a> and
<a class="reference external" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat">evennia.utils.repeat</a>.</p></li>
<li><p>Scripts can <em>attach</em> to Objects and Accounts via e.g. <code class="docutils literal notranslate"><span class="pre">obj.scripts.add/remove</span></code>. In the
script you can then access the object/account as <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">self.account</span></code>. This can be used to
dynamically extend other typeclasses but also to use the timer component to affect the parent object
in various ways. For historical reasons, a Script <em>not</em> attached to an object is referred to as a
<em>Global</em> Script.</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>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>In previus Evennia versions, stopping the Scripts timer also meant deleting the Script object.
Starting with this version, the timer can be start/stopped separately and <cite>.delete()</cite> must be called
on the Script explicitly to delete it.</p>
</div>
<div class="section" id="in-game-command-examples">
<h2>In-game command examples<a class="headerlink" href="#in-game-command-examples" title="Permalink to this headline"></a></h2>
<p>There are two main commands controlling scripts in the default cmdset:</p>
<p>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command is used for attaching scripts to existing objects:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">addscript</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">bodyfunctions</span><span class="o">.</span><span class="n">BodyFunctions</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">scripts</span></code> command is used to view all scripts and perform operations on them:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">scripts</span>
<span class="o">&gt;</span> <span class="n">scripts</span><span class="o">/</span><span class="n">stop</span> <span class="n">bodyfunctions</span><span class="o">.</span><span class="n">BodyFunctions</span>
<span class="o">&gt;</span> <span class="n">scripts</span><span class="o">/</span><span class="n">start</span> <span class="c1">#244</span>
<span class="o">&gt;</span> <span class="n">scripts</span><span class="o">/</span><span class="n">pause</span> <span class="c1">#11</span>
<span class="o">&gt;</span> <span class="n">scripts</span><span class="o">/</span><span class="n">delete</span> <span class="c1">#566</span>
</pre></div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>The <cite>addscript</cite> command used to be only <cite>script</cite> which was easy to confuse with <cite>scripts</cite>.</p>
</div>
</div>
<div class="section" id="code-examples">
<h2>Code examples<a class="headerlink" href="#code-examples" title="Permalink to this headline"></a></h2>
<p>Here are some examples of working with Scripts in-code (more details to follow in later
sections).</p>
<p>Create a new script:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></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>
</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>
<p>Create script with timer component:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
@ -97,22 +108,210 @@ Typeclass.</p>
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>
10
11</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># (note that this will call `timed_script.at_repeat` which is empty by default)</span>
<span class="n">timed_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;Timed script&quot;</span><span class="p">,</span>
<span class="n">interval</span><span class="o">=</span><span class="mi">34</span><span class="p">,</span> <span class="c1"># seconds &lt;=0 means off</span>
<span class="n">start_delay</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># wait interval before first call</span>
<span class="n">autostart</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># start timer (else needing .start() )</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="c1"># manipulate the script&#39;s timer</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">pause</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">unpause</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
<p>Attach script to another object:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">myobj</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">new_script</span><span class="p">)</span>
<span class="n">myobj</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">evennia</span><span class="o">.</span><span class="n">DefaultScript</span><span class="p">)</span>
<span class="n">all_scripts_on_obj</span> <span class="o">=</span> <span class="n">myobj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
<p>Search/find scripts in various ways:</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="c1"># regular search (this is always a list, also if there is only one match)</span>
<span class="n">list_of_myscripts</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>
<span class="c1"># search through Evennia&#39;s GLOBAL_SCRIPTS container (based on </span>
<span class="c1"># script&#39;s key only)</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">myscript</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">myscript</span>
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Timed script&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span> <span class="o">=</span> <span class="s2">&quot;bar&quot;</span>
</pre></div>
</td></tr></table></div>
<p>Delete the Script (this will also stop its timer):</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">new_script</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
</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 parent class is <code class="docutils literal notranslate"><span class="pre">evennia.DefaultScript</span></code>.</p>
<div class="section" id="simple-storage-script">
<h3>Simple storage script<a class="headerlink" href="#simple-storage-script" title="Permalink to this headline"></a></h3>
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Script</span></code> class already set up. You
can use this as a base for your own scripts.</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</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
<span class="k">class</span> <span class="nc">Script</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
<span class="c1"># stuff common for all your scripts goes here</span>
<span class="k">class</span> <span class="nc">MyScript</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="n">selfself</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called once, when script is first created&quot;&quot;&quot;</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">db</span><span class="o">.</span><span class="n">foo</span> <span class="o">=</span> <span class="s2">&quot;bar&quot;</span>
</pre></div>
</td></tr></table></div>
<p>Once created, this simple Script could act as a global storage:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.scripts.MyScript&#39;</span><span class="p">)</span>
<span class="c1"># from somewhere else </span>
<span class="n">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>
<span class="n">bar</span> <span class="o">=</span> <span class="n">myscript</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span>
<span class="n">myscript</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">something_else</span> <span class="o">=</span> <span class="mi">1000</span>
</pre></div>
</td></tr></table></div>
<p>Note that if you give keyword arguments to <code class="docutils literal notranslate"><span class="pre">create_script</span></code> you can override the values
you set in your <code class="docutils literal notranslate"><span class="pre">at_script_creation</span></code>:</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="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.scripts.MyScript&#39;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;another name&quot;</span><span class="p">,</span>
<span class="n">attributes</span><span class="o">=</span><span class="p">[(</span><span class="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="s2">&quot;bar-alternative&quot;</span><span class="p">)])</span>
</pre></div>
</td></tr></table></div>
<p>See the <a class="reference external" href="../api/evennia.utils.create.html#evennia.utils.create.create_script">create_script</a> and
<a class="reference external" href="../api/evennia.utils.search.html#evennia.utils.search.search_script">search_script</a> API documentation for more options
on creating and finding Scripts.</p>
</div>
<div class="section" id="timed-scripts">
<h3>Timed Scripts<a class="headerlink" href="#timed-scripts" title="Permalink to this headline"></a></h3>
<p>There are several properties one can set on the Script to control its timer component.</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</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
<span class="k">class</span> <span class="nc">TimerScript</span><span class="p">(</span><span class="n">Script</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">desc</span> <span class="o">=</span> <span class="s2">&quot;An example script&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>
<p>This example will call <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> every minute. The <code class="docutils literal notranslate"><span class="pre">create_script</span></code> function has an <code class="docutils literal notranslate"><span class="pre">autostart=True</span></code> keyword
set by default - this means the scripts timer component will be started automatically. Otherwise
<code class="docutils literal notranslate"><span class="pre">.start()</span></code> must be called separately.</p>
<p>Supported properties are:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (str): The name of the script. This makes it easier to search for it later. If its a script
attached to another object one can also get all scripts off that object and get the script that way.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">desc</span></code> (str): Note - not <code class="docutils literal notranslate"><span class="pre">.db.desc</span></code>! This is a database field on the Script shown in script listings
to help identifying what does what.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">interval</span></code> (int): The amount of time (in seconds) between every tick of the timer. Note that
its generally bad practice to use sub-second timers for anything in a text-game - the player will
not be able to appreciate the precision (and if you print it, it will just spam the screen). For
calculations you can pretty much always do them on-demand, or at a much slower interval without the
player being the wiser.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">start_delay</span></code> (bool): If timer should start right away or wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds first.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">repeats</span></code> (int): If &gt;0, the timer will only run this many times before stopping. Otherwise the
number of repeats are infinite. If set to 1, the Script mimics a <code class="docutils literal notranslate"><span class="pre">delay</span></code> action.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (bool): This defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code> and means the timer will survive a server reload/reboot.
If not, a reload will have the timer come back in a stopped state. Setting this to <code class="docutils literal notranslate"><span class="pre">False</span></code> will <em>not</em>
delete the Script object itself (use <code class="docutils literal notranslate"><span class="pre">.delete()</span></code> for this).</p></li>
</ul>
<p>The timer component is controlled with methods on the Script class:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">.at_repeat()</span></code> - this method is called every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds while the timer is
active.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.is_valid()</span></code> - this method is called by the timer just before <code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code>. If it returns <code class="docutils literal notranslate"><span class="pre">False</span></code>
the timer is immediately stopped.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.start()</span></code> - start/update the timer. If keyword arguments are given, they can be used to
change <code class="docutils literal notranslate"><span class="pre">interval</span></code>, <code class="docutils literal notranslate"><span class="pre">start_delay</span></code> etc on the fly. This calls the <code class="docutils literal notranslate"><span class="pre">.at_start()</span></code> hook.
This is also called after a server reload assuming the timer was not previously stopped.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.update()</span></code> - legacy alias for <code class="docutils literal notranslate"><span class="pre">.start</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.stop()</span></code> - stops and resets the timer. This calls the <code class="docutils literal notranslate"><span class="pre">.at_stop()</span></code> hook.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.pause()</span></code> - pauses the timer where it is, storing its current position. This calls
the <code class="docutils literal notranslate"><span class="pre">.at_pause(manual_pause=True)</span></code> hook. This is also called on a server reload/reboot,
at which time the <code class="docutils literal notranslate"><span class="pre">manual_pause</span></code> will be <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.unpause()</span></code> - unpause a previously paused script. This will call the <code class="docutils literal notranslate"><span class="pre">at_start</span></code> hook.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.time_until_next_repeat()</span></code> - get the time until next time the timer fires.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.remaining_repeats()</span></code> - get the number of repeats remaining, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if repeats are infinite.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.reset_callcount()</span></code> - this resets the repeat counter to start over from 0. Only useful if <code class="docutils literal notranslate"><span class="pre">repeats&gt;0</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.force_repeat()</span></code> - this prematurely forces <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> to be called right away. Doing so will reset the
countdown so that next call will again happen after <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds.</p></li>
</ul>
<div class="section" id="script-timers-vs-delay-repeat">
<h4>Script timers vs delay/repeat<a class="headerlink" href="#script-timers-vs-delay-repeat" title="Permalink to this headline"></a></h4>
<p>If the <em>only</em> goal is to get a repeat/delay effect, the
<a class="reference external" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay">evennia.utils.delay</a> and
<a class="reference external" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat">evennia.utils.repeat</a> functions
should generally be considered first. A Script is a lot heavier to create/delete on the fly.
In fact, for making a single delayed call (<code class="docutils literal notranslate"><span class="pre">script.repeats==1</span></code>), the <code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> call is
probably always the better choice.</p>
<p>For repeating tasks, the <code class="docutils literal notranslate"><span class="pre">utils.repeat</span></code> is optimized for quick repeating of a large number of objects. It
uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to
start/stop the repeating action for an object. The side effect is however that all objects set to tick
at a given interval will <em>all do so at the same time</em>. This may or may not look strange in-game depending
on the situation. By contrast the Script uses its own ticker that will operate independently from the
tickers of all other Scripts.</p>
<p>Its also worth noting that once the script object has <em>already been created</em>,
starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update
methods of the script also offers a bit more fine-control than using <code class="docutils literal notranslate"><span class="pre">utils.delays/repeat</span></code>.</p>
</div>
</div>
<div class="section" id="script-attached-to-another-object">
<h3>Script attached to another object<a class="headerlink" href="#script-attached-to-another-object" title="Permalink to this headline"></a></h3>
<p>Scripts can be attached to an <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a> or (more commonly) an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a>.
If so, the parent object will be available to the script as either <code class="docutils literal notranslate"><span class="pre">.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">.account</span></code>.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
@ -140,8 +339,7 @@ Heres an example:</p>
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>
28</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># 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>
@ -156,7 +354,6 @@ Heres an example:</p>
<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="kc">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>
@ -172,169 +369,91 @@ Heres an example:</p>
<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
<p>If attached to a room, this Script 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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><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>
</td></tr></table></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>
<p>You can also attach the script as part of creating it:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</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>
</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="kc">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>
<div class="section" id="other-script-methods">
<h2>Other Script methods<a class="headerlink" href="#other-script-methods" 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_script_creation()</span></code> - this is only called once - when the script is first created.</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
<code class="docutils literal notranslate"><span class="pre">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>
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_start()</span></code> - this is called when the server comes back (from reload/shutdown/reboot). It
can be usuful for initializations and caching of non-persistent data when starting up a scripts
functionality.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_start()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_pause()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_stop()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete()</span></code> - same as for other typeclassed entities, this will delete the Script. Of note is that
it will also stop the timer (if it runs), leading to the <code class="docutils literal notranslate"><span class="pre">at_stop</span></code> hook being called.</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>
<p>In addition, Scripts support <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc">Tags</span></a> and <a class="reference internal" href="Locks.html"><span class="doc">Locks</span></a> etc like other
Typeclassed entities.</p>
<p>See also the methods involved in controlling a <a class="reference external" href="#Timed_Scripts">Timed Script</a> above.</p>
</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="kc">True</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="kc">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>
<div class="section" id="the-global-scripts-container">
<h2>The GLOBAL_SCRIPTS container<a class="headerlink" href="#the-global-scripts-container" title="Permalink to this headline"></a></h2>
<p>A Script not attached to another entity is commonly referred to as a <em>Global</em> script since itt available
to access from anywhere. This means they need to be searched for in order to be used.</p>
<p>Evennia supplies a convenient “container” <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS</span></code> to help organize your global
scripts. All you need is the Scripts <code class="docutils literal notranslate"><span class="pre">key</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</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"># access as a property on the container, named the same as the key</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="c1"># get all global scripts (this returns a Django 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
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Note that global scripts appear as properties on <cite>GLOBAL_SCRIPTS</cite> based on their <cite>key</cite>.
If you were to create two global scripts with the same <cite>key</cite> (even with different typeclasses),
the <cite>GLOBAL_SCRIPTS</cite> 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>
<cite>evennia.search_scripts</cite> to get exactly the script you want.</p>
</div>
<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>:</p>
<ol class="simple">
<li><p>Manually create a new global script with a <code class="docutils literal notranslate"><span class="pre">key</span></code> using <code class="docutils literal notranslate"><span class="pre">create_script</span></code>.</p></li>
<li><p>Define the scripts properties in the <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> settings variable. This tells Evennia
that it should check if a script with that <code class="docutils literal notranslate"><span class="pre">key</span></code> exists and if not, create it for you.
This is very useful for scripts that must always exist and/or should be auto-created with your server.</p></li>
</ol>
<p>Heres how to tell Evennia to manage the script in settings:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
@ -345,36 +464,30 @@ to happen automatically when the server starts though. For this you can use the
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>
11</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/server/conf/settings.py</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="kc">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="kc">True</span>
<span class="p">}</span>
<span class="s2">&quot;storagescript&quot;</span><span class="p">:</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>Above we add two scripts with keys <code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code>respectively. The following dict
can be empty - the <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> will then be used. Under the hood, the provided
dict (along with the <code class="docutils literal notranslate"><span class="pre">key</span></code>) will be passed into <code class="docutils literal notranslate"><span class="pre">create_script</span></code> automatically, so
all the <a class="reference external" href="../api/evennia.utils.create.create_script.html">same keyword arguments as for create_script</a> are
supported here.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Before setting up Evennia to manage your script like this, make sure that your Script typeclass
does not have any critical errors (test it separately). If there are, youll see errors in your log
and your Script will temporarily fall back to being a <cite>DefaultScript</cite> type.</p>
</div>
<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
@ -382,26 +495,19 @@ errors in your log and your Script will temporarily fall back to being a <code c
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"># Delete 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">delete</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="c1"># but below it&#39;s automatically 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>
<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>, Evennia will use the
information in settings to recreate it for you on the fly.</p>
</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
<div class="section" id="hints-dealing-with-script-errors">
<h2>Hints: Dealing with Script Errors<a class="headerlink" href="#hints-dealing-with-script-errors" title="Permalink to this headline"></a></h2>
<p>Errors inside a 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
@ -418,54 +524,22 @@ traceback occurred in your script.</p>
10
11
12
13
14
15</pre></div></td><td class="code"><div class="highlight"><pre><span></span>
13</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="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</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="c1"># [...]</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>
@ -491,11 +565,20 @@ tutorial</a>.</p>
<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>
<li><a class="reference internal" href="#in-game-command-examples">In-game command examples</a></li>
<li><a class="reference internal" href="#code-examples">Code examples</a></li>
<li><a class="reference internal" href="#defining-new-scripts">Defining new Scripts</a><ul>
<li><a class="reference internal" href="#simple-storage-script">Simple storage script</a></li>
<li><a class="reference internal" href="#timed-scripts">Timed Scripts</a><ul>
<li><a class="reference internal" href="#script-timers-vs-delay-repeat">Script timers vs delay/repeat</a></li>
</ul>
</li>
<li><a class="reference internal" href="#script-attached-to-another-object">Script attached to another object</a></li>
</ul>
</li>
<li><a class="reference internal" href="#other-script-methods">Other Script methods</a></li>
<li><a class="reference internal" href="#the-global-scripts-container">The GLOBAL_SCRIPTS container</a></li>
<li><a class="reference internal" href="#hints-dealing-with-script-errors">Hints: Dealing with Script Errors</a></li>
</ul>
</li>
</ul>