mirror of
https://github.com/evennia/evennia.git
synced 2026-03-19 06:16:31 +01:00
210 lines
No EOL
14 KiB
HTML
210 lines
No EOL
14 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<title>Tutorial Aggressive NPCs — Evennia 1.0-dev documentation</title>
|
||
<link rel="stylesheet" href="_static/alabaster.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="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
|
||
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
|
||
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=0.9, maximum-scale=0.9" />
|
||
|
||
</head><body>
|
||
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
|
||
|
||
<div class="body" role="main">
|
||
|
||
<div class="section" id="tutorial-aggressive-npcs">
|
||
<h1>Tutorial Aggressive NPCs<a class="headerlink" href="#tutorial-aggressive-npcs" title="Permalink to this headline">¶</a></h1>
|
||
<p>This tutorial shows the implementation of an NPC object that responds to characters entering their location. In this example the NPC has the option to respond aggressively or not, but any actions could be triggered this way.</p>
|
||
<p>One could imagine using a <a class="reference internal" href="Scripts.html"><span class="doc">Script</span></a> that is constantly checking for newcomers. This would be highly inefficient (most of the time its check would fail). Instead we handle this on-demand by using a couple of existing object hooks to inform the NPC that a Character has entered.</p>
|
||
<p>It is assumed that you already know how to create custom room and character typeclasses, please see the <a class="reference internal" href="Tutorial-for-basic-MUSH-like-game.html"><span class="doc">Basic Game tutorial</span></a> if you haven’t already done this.</p>
|
||
<p>What we will need is the following:</p>
|
||
<ul class="simple">
|
||
<li><p>An NPC typeclass that can react when someone enters.</p></li>
|
||
<li><p>A custom <a class="reference external" href="/Objects.html#rooms">Room</a> typeclass that can tell the NPC that someone entered.</p></li>
|
||
<li><p>We will also tweak our default <code class="docutils literal notranslate"><span class="pre">Character</span></code> typeclass a little.</p></li>
|
||
</ul>
|
||
<p>To begin with, we need to create an NPC typeclass. Create a new file inside of your typeclasses folder and name it <code class="docutils literal notranslate"><span class="pre">npcs.py</span></code> and then add the following 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
|
||
14
|
||
15</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.characters</span> <span class="kn">import</span> <span class="n">Character</span>
|
||
|
||
<span class="k">class</span> <span class="nc">NPC</span><span class="p">(</span><span class="n">Character</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> A NPC typeclass which extends the character class.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="k">def</span> <span class="nf">at_char_entered</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> A simple is_aggressive check. </span>
|
||
<span class="sd"> Can be expanded upon later.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_aggressive</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">execute_cmd</span><span class="p">(</span><span class="n">f</span><span class="s2">"say Graaah, die {character}!"</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">execute_cmd</span><span class="p">(</span><span class="n">f</span><span class="s2">"say Greetings, {character}!"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>We will define our custom <code class="docutils literal notranslate"><span class="pre">Character</span></code> typeclass below. As for the new <code class="docutils literal notranslate"><span class="pre">at_char_entered</span></code> method we’ve just defined, we’ll ensure that it will be called by the room where the NPC is located, when a player enters that room. You’ll notice that right now, the NPC merely speaks. You can expand this part as you like and trigger all sorts of effects here (like combat code, fleeing, bartering or quest-giving) as your game design dictates.</p>
|
||
<p>Now your <code class="docutils literal notranslate"><span class="pre">typeclasses.rooms</span></code> module needs to have the following added:</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="c1"># Add this import to the top of your file.</span>
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span>
|
||
|
||
<span class="c1"># Add this hook in any empty area within your Room class.</span>
|
||
<span class="k">def</span> <span class="nf">at_object_receive</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">source_location</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="n">utils</span><span class="o">.</span><span class="n">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'typeclasses.npcs.NPC'</span><span class="p">):</span> <span class="c1"># An NPC has entered</span>
|
||
<span class="k">return</span>
|
||
<span class="k">elif</span> <span class="n">utils</span><span class="o">.</span><span class="n">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s1">'typeclasses.characters.Character'</span><span class="p">):</span>
|
||
<span class="c1"># A PC has entered.</span>
|
||
<span class="c1"># Cause the player's character to look around.</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">execute_cmd</span><span class="p">(</span><span class="s1">'look'</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">contents</span><span class="p">:</span>
|
||
<span class="k">if</span> <span class="n">utils</span><span class="o">.</span><span class="n">inherits_from</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">'typeclasses.npcs.NPC'</span><span class="p">):</span>
|
||
<span class="c1"># An NPC is in the room</span>
|
||
<span class="n">item</span><span class="o">.</span><span class="n">at_char_entered</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">inherits_from</span></code> must be given the full path of the class. If the object inherited a class from your <code class="docutils literal notranslate"><span class="pre">world.races</span></code> module, then you would check inheritance with <code class="docutils literal notranslate"><span class="pre">world.races.Human</span></code>, for example. There is no need to import these prior, as we are passing in the full path. As a matter of a fact, <code class="docutils literal notranslate"><span class="pre">inherits_from</span></code> does not properly work if you import the class and only pass in the name of the class.</p>
|
||
<blockquote>
|
||
<div><p>Note: <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1529">at_object_receive</a> is a default hook of the <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> typeclass (and its children). Here we are overriding this hook in our customized room typeclass to suit our needs.</p>
|
||
</div></blockquote>
|
||
<p>This room checks the typeclass of objects entering it (using <code class="docutils literal notranslate"><span class="pre">utils.inherits_from</span></code> and responds to <code class="docutils literal notranslate"><span class="pre">Characters</span></code>, ignoring other NPCs or objects. When triggered the room will look through its contents and inform any <code class="docutils literal notranslate"><span class="pre">NPCs</span> <span class="pre">inside</span> <span class="pre">by</span> <span class="pre">calling</span> <span class="pre">their</span> </code>at_char_entered` method.</p>
|
||
<p>You’ll also see that we have added a ‘look’ into this code. This is because, by default, the <code class="docutils literal notranslate"><span class="pre">at_object_receive</span></code> is carried out <em>before</em> the character’s <code class="docutils literal notranslate"><span class="pre">at_after_move</span></code> which, we will now overload. This means that a character entering would see the NPC perform its actions before the ‘look’ command. Deactivate the look command in the default <code class="docutils literal notranslate"><span class="pre">Character</span></code> class within the <code class="docutils literal notranslate"><span class="pre">typeclasses.characters</span></code> module:</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</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># Add this hook in any blank area within your Character class.</span>
|
||
<span class="k">def</span> <span class="nf">at_after_move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">source_location</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> Default is to look around after a move </span>
|
||
<span class="sd"> Note: This has been moved to Room.at_object_receive</span>
|
||
<span class="sd"> """</span>
|
||
<span class="c1">#self.execute_cmd('look')</span>
|
||
<span class="k">pass</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>Now let’s create an NPC and make it aggressive. Type the following commands into your MUD client:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">reload</span>
|
||
<span class="n">create</span><span class="o">/</span><span class="n">drop</span> <span class="n">Orc</span><span class="p">:</span><span class="n">npcs</span><span class="o">.</span><span class="n">NPC</span>
|
||
</pre></div>
|
||
</div>
|
||
<blockquote>
|
||
<div><p>Note: You could also give the path as <code class="docutils literal notranslate"><span class="pre">typeclasses.npcs.NPC</span></code>, but Evennia will look into the <code class="docutils literal notranslate"><span class="pre">typeclasses</span></code> folder automatically, so this is a little shorter.</p>
|
||
</div></blockquote>
|
||
<p>When you enter the aggressive NPC’s location, it will default to using its peaceful action (say your name is Anna):</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Orc</span> <span class="n">says</span><span class="p">,</span> <span class="s2">"Greetings, Anna!"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Now we turn on the aggressive mode (we do it manually but it could also be triggered by some sort of AI code).</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">set</span> <span class="n">orc</span><span class="o">/</span><span class="n">is_aggressive</span> <span class="o">=</span> <span class="kc">True</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Now it will perform its aggressive action whenever a character enters.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Orc</span> <span class="n">says</span><span class="p">,</span> <span class="s2">"Graaah, die, Anna!"</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<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><div class="relations">
|
||
<h3>Related Topics</h3>
|
||
<ul>
|
||
<li><a href="index.html">Documentation overview</a><ul>
|
||
</ul></li>
|
||
</ul>
|
||
</div>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="_sources/Tutorial-Aggressive-NPCs.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div>
|
||
<h3>Versions</h3>
|
||
<ul>
|
||
<li><a href="Tutorial-Aggressive-NPCs.html">1.0-dev (develop branch)</a></li>
|
||
<li><a href="../../versions/0.9.1/index.html">0.9.1 (master branch)</a></li>
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="footer">
|
||
©2020, The Evennia developer community.
|
||
|
||
|
|
||
Powered by <a href="http://sphinx-doc.org/">Sphinx 2.4.4</a>
|
||
& <a href="https://github.com/bitprophet/alabaster">Alabaster 0.7.12</a>
|
||
|
||
|
|
||
<a href="_sources/Tutorial-Aggressive-NPCs.md.txt"
|
||
rel="nofollow">Page source</a>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
</body>
|
||
</html> |