mirror of
https://github.com/evennia/evennia.git
synced 2026-03-27 02:06:32 +01:00
Updated HTML docs.
This commit is contained in:
parent
c758f0d402
commit
57f411a6fa
95 changed files with 1370 additions and 2035 deletions
|
|
@ -295,6 +295,7 @@ Click here to expand a list of all Beginner-Tutorial sections (all parts).
|
|||
<li class="toctree-l3"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html">6. Overview of the Evennia library</a><ul>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html#where-is-it">6.1. Where is it?</a></li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html#an-example-of-exploring-the-library">6.2. An example of exploring the library</a></li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html#conclusions">6.3. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a><ul>
|
||||
|
|
@ -305,7 +306,8 @@ Click here to expand a list of all Beginner-Tutorial sections (all parts).
|
|||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#typeclasses">7.2. Typeclasses</a><ul>
|
||||
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#examining-and-defaults">7.2.1. Examining and defaults</a></li>
|
||||
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#examining-objects">7.2.1. Examining objects</a></li>
|
||||
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#default-typeclasses">7.2.2. Default typeclasses</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#modifying-ourselves">7.3. Modifying ourselves</a><ul>
|
||||
|
|
@ -447,6 +449,7 @@ Click here to expand a list of all Beginner-Tutorial sections (all parts).
|
|||
<li class="toctree-l3"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html">6. Overview of the Evennia library</a><ul>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html#where-is-it">6.1. Where is it?</a></li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html#an-example-of-exploring-the-library">6.2. An example of exploring the library</a></li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Evennia-Library-Overview.html#conclusions">6.3. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a><ul>
|
||||
|
|
@ -457,7 +460,8 @@ Click here to expand a list of all Beginner-Tutorial sections (all parts).
|
|||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#typeclasses">7.2. Typeclasses</a><ul>
|
||||
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#examining-and-defaults">7.2.1. Examining and defaults</a></li>
|
||||
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#examining-objects">7.2.1. Examining objects</a></li>
|
||||
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#default-typeclasses">7.2.2. Default typeclasses</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Learning-Typeclasses.html#modifying-ourselves">7.3. Modifying ourselves</a><ul>
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="adding-custom-commands">
|
||||
<h1><span class="section-number">8. </span>Adding custom commands<a class="headerlink" href="#adding-custom-commands" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In this lesson we’ll learn how to create our own Evennia <em>Commands</em>. If you are new to Python you’ll also learn some more basics about how to manipulate strings and get information out of Evennia.</p>
|
||||
<p>In this lesson we’ll learn how to create our own Evennia <a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc">Commands</span></a> If you are new to Python you’ll also learn some more basics about how to manipulate strings and get information out of Evennia.</p>
|
||||
<p>A Command is something that handles the input from a user and causes a result to happen.
|
||||
An example is <code class="docutils literal notranslate"><span class="pre">look</span></code>, which examines your current location and tells how it looks like and
|
||||
An example is <code class="docutils literal notranslate"><span class="pre">look</span></code>, which examines your current location and tells you what it looks like and
|
||||
what is in it.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Commands are not typeclassed</p>
|
||||
|
|
@ -124,19 +124,9 @@ CommandSets are not <code class="docutils literal notranslate"><span class="pre"
|
|||
database. They are “just” normal Python classes.</p>
|
||||
</aside>
|
||||
<p>In Evennia, a Command is a Python <em>class</em>. If you are unsure about what a class is, review the
|
||||
previous lessons! A Command inherits from <code class="docutils literal notranslate"><span class="pre">evennia.Command</span></code> or from one of the alternative command-
|
||||
classes, such as <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> which is what most default commands use.</p>
|
||||
<p>All Commands are in turn grouped in another class called a <em>Command Set</em>. Think of a Command Set
|
||||
as a bag holding many different commands. One CmdSet could for example hold all commands for
|
||||
combat, another for building etc. By default, Evennia groups all character-commands into one
|
||||
big cmdset.</p>
|
||||
<p>Command-Sets are then associated with objects, for example with your Character. Doing so makes the
|
||||
commands in that cmdset available to the object. So, to summarize:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Commands are classes</p></li>
|
||||
<li><p>A group of Commands is stored in a CmdSet</p></li>
|
||||
<li><p>CmdSets are stored on objects - this defines which commands are available to that object.</p></li>
|
||||
</ul>
|
||||
<a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html"><span class="doc std std-doc">previous lesson about it</span></a>! A Command inherits from <code class="docutils literal notranslate"><span class="pre">evennia.Command</span></code> or from one of the alternative command- classes, such as <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> which is what most default commands use.</p>
|
||||
<p>All Commands are grouped in another class called a <em>Command Set</em>. Think of a Command Set as a bag holding many different commands. One CmdSet could for example hold all commands for combat, another for building etc.</p>
|
||||
<p>Command-Sets are then associated with objects, for example with your Character. Doing so makes the commands in that cmdset available to the object. By default, Evennia groups all character-commands into one big cmdset called the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>. It sits on <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code> (and thus, through inheritance, on <code class="docutils literal notranslate"><span class="pre">typeclasses.characters.Character</span></code>).</p>
|
||||
<section id="creating-a-custom-command">
|
||||
<h2><span class="section-number">8.1. </span>Creating a custom command<a class="headerlink" href="#creating-a-custom-command" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Open <code class="docutils literal notranslate"><span class="pre">mygame/commands/command.py</span></code>:</p>
|
||||
|
|
@ -158,17 +148,13 @@ commands in that cmdset available to the object. So, to summarize:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>Ignoring the docstrings (which you can read if you want), this is the only really active code in the module.</p>
|
||||
<p>We can see that we import <code class="docutils literal notranslate"><span class="pre">Command</span></code> from <code class="docutils literal notranslate"><span class="pre">evennia</span></code> and use the <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">...</span> <span class="pre">import</span> <span class="pre">...</span> <span class="pre">as</span> <span class="pre">...</span></code> form to rename it
|
||||
to <code class="docutils literal notranslate"><span class="pre">BaseCommand</span></code>. This is so we can let our child class also be named <code class="docutils literal notranslate"><span class="pre">Command</span></code> for reference. The class
|
||||
itself doesn’t do anything, it just has <code class="docutils literal notranslate"><span class="pre">pass</span></code>. So in the same way as <code class="docutils literal notranslate"><span class="pre">Object</span></code> in the previous lesson, this
|
||||
class is identical to its parent.</p>
|
||||
<p>We can see that we import <code class="docutils literal notranslate"><span class="pre">Command</span></code> from <code class="docutils literal notranslate"><span class="pre">evennia</span></code> and use the <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">...</span> <span class="pre">import</span> <span class="pre">...</span> <span class="pre">as</span> <span class="pre">...</span></code> form to rename it to <code class="docutils literal notranslate"><span class="pre">BaseCommand</span></code>. This is so we can let our child class also be named <code class="docutils literal notranslate"><span class="pre">Command</span></code> to make it easier to reference. The class itself doesn’t do anything, it just has <code class="docutils literal notranslate"><span class="pre">pass</span></code>. So in the same way as <code class="docutils literal notranslate"><span class="pre">Object</span></code> and <code class="docutils literal notranslate"><span class="pre">Character</span></code> in the previous lessons, this class is identical to its parent.</p>
|
||||
<blockquote>
|
||||
<div><p>The commented out <code class="docutils literal notranslate"><span class="pre">default_cmds</span></code> gives us access to Evennia’s default commands for easy overriding. We’ll try
|
||||
that a little later.</p>
|
||||
<div><p>The commented out <code class="docutils literal notranslate"><span class="pre">default_cmds</span></code> gives us access to Evennia’s default commands for easy overriding. We’ll try that a little later.</p>
|
||||
</div></blockquote>
|
||||
<p>We could modify this module directly, but to train imports we’ll work in a separate module. Open a new file
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/commands/mycommands.py</span></code> and add the following code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<p>We could modify this module directly, but let’s work in a separate module just for the heck of it. Open a new file <code class="docutils literal notranslate"><span class="pre">mygame/commands/mycommands.py</span></code> and add the following code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/commands/mycommands.py</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">commands.command</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CmdEcho</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
|
|
@ -194,15 +180,12 @@ what you will use to call this command later.</p>
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Our <code class="docutils literal notranslate"><span class="pre">EchoCmdSet</span></code> class must have an <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code> method, named exactly
|
||||
like this - this is what Evennia will be looking for when setting up the cmdset later, so
|
||||
if you didn’t set it up, it will use the parent’s version, which is empty. Inside we add the
|
||||
command class to the cmdset by <code class="docutils literal notranslate"><span class="pre">self.add()</span></code>. If you wanted to add more commands to this CmdSet you
|
||||
could just add more lines of <code class="docutils literal notranslate"><span class="pre">self.add</span></code> after this.</p>
|
||||
<p>Our <code class="docutils literal notranslate"><span class="pre">EchoCmdSet</span></code> class must have an <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code> method, named exactly like this - this is what Evennia will be looking for when setting up the cmdset later, so if you didn’t set it up, it will use the parent’s version, which is empty. Inside we add the command class to the cmdset by <code class="docutils literal notranslate"><span class="pre">self.add()</span></code>. If you wanted to add more commands to this CmdSet you could just add more lines of <code class="docutils literal notranslate"><span class="pre">self.add</span></code> after this.</p>
|
||||
<p>Finally, let’s add this command to ourselves so we can try it out. In-game you can experiment with <code class="docutils literal notranslate"><span class="pre">py</span></code> again:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py me.cmdset.add("commands.mycommands.MyCmdSet")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">me.cmdset</span></code> is the store of all cmdsets stored on us. By giving the path to our CmdSet class, it will be added.</p>
|
||||
<p>Now try</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> echo
|
||||
Command echo has no defined `func()` - showing on-command variables:
|
||||
|
|
@ -210,9 +193,7 @@ Command echo has no defined `func()` - showing on-command variables:
|
|||
...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You should be getting a long list of outputs. The reason for this is that your <code class="docutils literal notranslate"><span class="pre">echo</span></code> function is not really
|
||||
“doing” anything yet and the default function is then to show all useful resources available to you when you
|
||||
use your Command. Let’s look at some of those listed:</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">echo</span></code> works! You should be getting a long list of outputs. The reason for this is that your <code class="docutils literal notranslate"><span class="pre">echo</span></code> function is not really “doing” anything yet and the default function is then to show all useful resources available to you when you use your Command. Let’s look at some of those listed:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Command echo has no defined `func()` - showing on-command variables:
|
||||
obj (<class 'typeclasses.characters.Character'>): YourName
|
||||
lockhandler (<class 'evennia.locks.lockhandler.LockHandler'>): cmd:all()
|
||||
|
|
@ -244,17 +225,13 @@ command string given (self.cmdstring): echo
|
|||
current cmdset (self.cmdset): ChannelCmdSet
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>These are all properties you can access with <code class="docutils literal notranslate"><span class="pre">.</span></code> on the Command instance, such as <code class="docutils literal notranslate"><span class="pre">.key</span></code>, <code class="docutils literal notranslate"><span class="pre">.args</span></code> and so on.
|
||||
Evennia makes these available to you and they will be different every time a command is run. The most
|
||||
important ones we will make use of now are:</p>
|
||||
<p>These are all properties you can access with <code class="docutils literal notranslate"><span class="pre">.</span></code> on the Command instance, such as <code class="docutils literal notranslate"><span class="pre">.key</span></code>, <code class="docutils literal notranslate"><span class="pre">.args</span></code> and so on. Evennia makes these available to you and they will be different every time a command is run. The most important ones we will make use of now are:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> - this is ‘you’, the person calling the command.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">args</span></code> - this is all arguments to the command. Now it’s empty, but if you tried <code class="docutils literal notranslate"><span class="pre">echo</span> <span class="pre">foo</span> <span class="pre">bar</span></code> you’d find
|
||||
that this would be <code class="docutils literal notranslate"><span class="pre">"</span> <span class="pre">foo</span> <span class="pre">bar"</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">args</span></code> - this is all arguments to the command. Now it’s empty, but if you tried <code class="docutils literal notranslate"><span class="pre">echo</span> <span class="pre">foo</span> <span class="pre">bar</span></code> you’d find that this would be <code class="docutils literal notranslate"><span class="pre">"</span> <span class="pre">foo</span> <span class="pre">bar"</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code> - this is object on which this Command (and CmdSet) “sits”. So you, in this case.</p></li>
|
||||
</ul>
|
||||
<p>The reason our command doesn’t do anything yet is because it’s missing a <code class="docutils literal notranslate"><span class="pre">func</span></code> method. This is what Evennia
|
||||
looks for to figure out what a Command actually does. Modify your <code class="docutils literal notranslate"><span class="pre">CmdEcho</span></code> class:</p>
|
||||
<p>The reason our command doesn’t do anything yet is because it’s missing a <code class="docutils literal notranslate"><span class="pre">func</span></code> method. This is what Evennia looks for to figure out what a Command actually does. Modify your <code class="docutils literal notranslate"><span class="pre">CmdEcho</span></code> class:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CmdEcho</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
|
|
@ -273,14 +250,13 @@ looks for to figure out what a Command actually does. Modify your <code class="d
|
|||
<span class="c1"># ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>First we added a docstring. This is always a good thing to do in general, but for a Command class, it will also
|
||||
automatically become the in-game help entry! Next we add the <code class="docutils literal notranslate"><span class="pre">func</span></code> method. It has one active line where it
|
||||
makes use of some of those variables we found the Command offers to us. If you did the
|
||||
<a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html"><span class="doc std std-doc">basic Python tutorial</span></a>, you will recognize <code class="docutils literal notranslate"><span class="pre">.msg</span></code> - this will send a message
|
||||
to the object it is attached to us - in this case <code class="docutils literal notranslate"><span class="pre">self.caller</span></code>, that is, us. We grab <code class="docutils literal notranslate"><span class="pre">self.args</span></code> and includes
|
||||
that in the message.</p>
|
||||
<p>Since we haven’t changed <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code>, that will work as before. Reload and re-add this command to ourselves to
|
||||
try out the new version:</p>
|
||||
<p>First we added a docstring. This is always a good thing to do in general, but for a Command class, it will also automatically become the in-game help entry!</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Use Command.msg </p>
|
||||
<p>In a Command class, the <code class="docutils literal notranslate"><span class="pre">self.msg()</span></code> acts as a convenient shortcut for <code class="docutils literal notranslate"><span class="pre">self.caller.msg()</span></code>. Not only is it shorter, it also has some advantages because the command can include more metadata with the message. So using <code class="docutils literal notranslate"><span class="pre">self.msg()</span></code> is usually better. For this tutorial though, <code class="docutils literal notranslate"><span class="pre">self.caller.msg()</span></code> is more explicit in showing what is going on.</p>
|
||||
</aside>
|
||||
<p>Next we add the <code class="docutils literal notranslate"><span class="pre">func</span></code> method. It has one active line where it makes use of some of those variables the Command class offers to us. If you did the <a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html"><span class="doc std std-doc">basic Python tutorial</span></a>, you will recognize <code class="docutils literal notranslate"><span class="pre">.msg</span></code> - this will send a message to the object it is attached to us - in this case <code class="docutils literal notranslate"><span class="pre">self.caller</span></code>, that is, us. We grab <code class="docutils literal notranslate"><span class="pre">self.args</span></code> and includes that in the message.</p>
|
||||
<p>Since we haven’t changed <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code>, that will work as before. Reload and re-add this command to ourselves to try out the new version:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
||||
> echo
|
||||
|
|
@ -292,14 +268,12 @@ Echo: ''
|
|||
Echo: ' Woo Tang!'
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note that there is an extra space before <code class="docutils literal notranslate"><span class="pre">Woo!</span></code>. That is because self.args contains the <em>everything</em> after
|
||||
the command name, including spaces. Evennia will happily understand if you skip that space too:</p>
|
||||
<p>Note that there is an extra space before <code class="docutils literal notranslate"><span class="pre">Woo!</span></code>. That is because self.args contains <em>everything</em> after the command name, including spaces. Evennia will happily understand if you skip that space too:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> echoWoo Tang!
|
||||
Echo: 'Woo Tang!'
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>There are ways to force Evennia to <em>require</em> an initial space, but right now we want to just ignore it since
|
||||
it looks a bit weird for our echo example. Tweak the code:</p>
|
||||
<p>There are ways to force Evennia to <em>require</em> an initial space, but right now we want to just ignore it since it looks a bit weird for our echo example. Tweak the code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CmdEcho</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
|
|
@ -318,9 +292,7 @@ it looks a bit weird for our echo example. Tweak the code:</p>
|
|||
<span class="c1"># ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The only difference is that we called <code class="docutils literal notranslate"><span class="pre">.strip()</span></code> on <code class="docutils literal notranslate"><span class="pre">self.args</span></code>. This is a helper method available on all
|
||||
strings - it strips out all whitespace before and after the string. Now the Command-argument will no longer
|
||||
have any space in front of it.</p>
|
||||
<p>The only difference is that we called <code class="docutils literal notranslate"><span class="pre">.strip()</span></code> on <code class="docutils literal notranslate"><span class="pre">self.args</span></code>. This is a helper method available on all strings - it strips out all whitespace before and after the string. Now the Command-argument will no longer have any space in front of it.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
||||
> echo Woo Tang!
|
||||
|
|
@ -331,7 +303,7 @@ Echo: 'Woo Tang!'
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> help echo
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You will get the docstring you put in your Command-class.</p>
|
||||
<p>You will get the docstring you put in your Command-class!</p>
|
||||
<section id="making-our-cmdset-persistent">
|
||||
<h3><span class="section-number">8.1.1. </span>Making our cmdset persistent<a class="headerlink" href="#making-our-cmdset-persistent" title="Permalink to this headline">¶</a></h3>
|
||||
<p>It’s getting a little annoying to have to re-add our cmdset every time we reload, right? It’s simple
|
||||
|
|
@ -340,7 +312,7 @@ enough to make <code class="docutils literal notranslate"><span class="pre">echo
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>Now you can <code class="docutils literal notranslate"><span class="pre">reload</span></code> as much as you want and your code changes will be available directly without
|
||||
needing to re-add the MyCmdSet again. To remove the cmdset again, do</p>
|
||||
needing to re-add the MyCmdSet again. To remove the cmdset again, you’d do</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.cmdset.remove("commands.mycommands.MyCmdSet")
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -354,7 +326,7 @@ someone in the face! This is how we want it to work:</p>
|
|||
You hit <target> with full force!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Not only that, we want the <target> to see</p>
|
||||
<p>Not only that, we want the <code class="docutils literal notranslate"><span class="pre"><target></span></code> to see</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You got hit by <hitter> with full force!
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -432,11 +404,9 @@ else:
|
|||
the <code class="docutils literal notranslate"><span class="pre">else</span></code> condition is given, it will run if none of the other conditions was truthy. In Python
|
||||
the <code class="docutils literal notranslate"><span class="pre">if..elif..else</span></code> structure also serves the same function as <code class="docutils literal notranslate"><span class="pre">case</span></code> in some other languages.</p>
|
||||
</aside>
|
||||
<ul>
|
||||
<li><p><strong>Line 15</strong> has our first <em>conditional</em>, an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement. This is written on the form <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre"><condition>:</span></code> and only
|
||||
if that condition is ‘truthy’ will the indented code block under the <code class="docutils literal notranslate"><span class="pre">if</span></code> statement run. To learn what is truthy in
|
||||
Python it’s usually easier to learn what is “falsy”:</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Line 15</strong> has our first <em>conditional</em>, an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement. This is written on the form <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre"><condition>:</span></code> and only if that condition is ‘truthy’ will the indented code block under the <code class="docutils literal notranslate"><span class="pre">if</span></code> statement run. To learn what is truthy in Python it’s usually easier to learn what is “falsy”:</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">False</span></code> - this is a reserved boolean word in Python. The opposite is <code class="docutils literal notranslate"><span class="pre">True</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">None</span></code> - another reserved word. This represents nothing, a null-result or value.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">0</span></code> or <code class="docutils literal notranslate"><span class="pre">0.0</span></code></p></li>
|
||||
|
|
@ -444,14 +414,12 @@ Python it’s usually easier to learn what is “falsy”:</p>
|
|||
<li><p>Empty <em>iterables</em> we haven’t seen yet, like empty lists <code class="docutils literal notranslate"><span class="pre">[]</span></code>, empty tuples <code class="docutils literal notranslate"><span class="pre">()</span></code> and empty dicts <code class="docutils literal notranslate"><span class="pre">{}</span></code>.</p></li>
|
||||
<li><p>Everything else is “truthy”.</p></li>
|
||||
</ul>
|
||||
<p>Line 16’s condition is <code class="docutils literal notranslate"><span class="pre">not</span> <span class="pre">args</span></code>. The <code class="docutils literal notranslate"><span class="pre">not</span></code> <em>inverses</em> the result, so if <code class="docutils literal notranslate"><span class="pre">args</span></code> is the empty string (falsy), the
|
||||
whole conditional becomes truthy. Let’s continue in the code:</p>
|
||||
</li>
|
||||
<li><p><strong>Line 16</strong>’s condition is <code class="docutils literal notranslate"><span class="pre">not</span> <span class="pre">args</span></code>. The <code class="docutils literal notranslate"><span class="pre">not</span></code> <em>inverses</em> the result, so if <code class="docutils literal notranslate"><span class="pre">args</span></code> is the empty string (falsy), the whole conditional becomes truthy. Let’s continue in the code:</p></li>
|
||||
<li><p><strong>Lines 16-17</strong>: This code will only run if the <code class="docutils literal notranslate"><span class="pre">if</span></code> statement is truthy, in this case if <code class="docutils literal notranslate"><span class="pre">args</span></code> is the empty string.</p></li>
|
||||
<li><p><strong>Line 17</strong>: <code class="docutils literal notranslate"><span class="pre">return</span></code> is a reserved Python word that exits <code class="docutils literal notranslate"><span class="pre">func</span></code> immediately.</p></li>
|
||||
<li><p><strong>Line 18</strong>: We use <code class="docutils literal notranslate"><span class="pre">self.caller.search</span></code> to look for the target in the current location.</p></li>
|
||||
<li><p><strong>Lines 19-20</strong>: A feature of <code class="docutils literal notranslate"><span class="pre">.search</span></code> is that it will already inform <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> if it couldn’t find the target.
|
||||
In that case, <code class="docutils literal notranslate"><span class="pre">target</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and we should just directly <code class="docutils literal notranslate"><span class="pre">return</span></code>.</p></li>
|
||||
<li><p><strong>Lines 19-20</strong>: A feature of <code class="docutils literal notranslate"><span class="pre">.search</span></code> is that it will already inform <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> if it couldn’t find the target. In that case, <code class="docutils literal notranslate"><span class="pre">target</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and we should just directly <code class="docutils literal notranslate"><span class="pre">return</span></code>.</p></li>
|
||||
<li><p><strong>Lines 21-22</strong>: At this point we have a suitable target and can send our punching strings to each.</p></li>
|
||||
</ul>
|
||||
<p>Finally we must also add this to a CmdSet. Let’s add it to <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code> which we made persistent earlier.</p>
|
||||
|
|
@ -470,9 +438,7 @@ In that case, <code class="docutils literal notranslate"><span class="pre">targe
|
|||
<p>With longer code snippets to try, it gets more and more likely you’ll
|
||||
make an error and get a <code class="docutils literal notranslate"><span class="pre">traceback</span></code> when you reload. This will either appear
|
||||
directly in-game or in your log (view it with <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">-l</span></code> in a terminal).
|
||||
Don’t panic; tracebacks are your friends - they are to be read bottom-up and usually describe
|
||||
exactly where your problem is. Refer to <code class="docutils literal notranslate"><span class="pre">The</span> <span class="pre">Python</span> <span class="pre">intro</span> <span class="pre"><Python-basic-introduction.html></span></code>_ for
|
||||
more hints. If you get stuck, reach out to the Evennia community for help.</p>
|
||||
Don’t panic; tracebacks are your friends - they are to be read bottom-up and usually describe exactly where your problem is. Refer to <a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html"><span class="doc std std-doc">The Python introduction lesson</span></a> for more hints. If you get stuck, reach out to the Evennia community for help.</p>
|
||||
</aside>
|
||||
<p>Next we reload to let Evennia know of these code changes and try it out:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
|
|
@ -494,8 +460,7 @@ You hit Smaug with full force!
|
|||
</section>
|
||||
<section id="summary">
|
||||
<h2><span class="section-number">8.2. </span>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In this lesson we learned how to create our own Command, add it to a CmdSet and then to ourselves.
|
||||
We also upset a dragon.</p>
|
||||
<p>In this lesson we learned how to create our own Command, add it to a CmdSet and then to ourselves. We also upset a dragon.</p>
|
||||
<p>In the next lesson we’ll learn how to hit Smaug with different weapons. We’ll also
|
||||
get into how we replace and extend Evennia’s default Commands.</p>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@
|
|||
<h1><span class="section-number">1. </span>Using commands and building stuff<a class="headerlink" href="#using-commands-and-building-stuff" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In this lesson we will test out what we can do in-game out-of-the-box. Evennia ships with
|
||||
<a class="reference internal" href="../../../Components/Default-Commands.html"><span class="doc std std-doc">around 90 default commands</span></a>, and while you can override those as you please,
|
||||
they can be quite useful.</p>
|
||||
the defaults can be quite useful.</p>
|
||||
<p>Connect and log into your new game and you will end up in the “Limbo” location. This
|
||||
is the only room in the game at this point. Let’s explore the commands a little.</p>
|
||||
<p>The default commands has syntax <a class="reference internal" href="../../../Concepts/Using-MUX-as-a-Standard.html"><span class="doc std std-doc">similar to MUX</span></a>:</p>
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
<li><a class="reference internal" href="#">6. Overview of the Evennia library</a><ul>
|
||||
<li><a class="reference internal" href="#where-is-it">6.1. Where is it?</a></li>
|
||||
<li><a class="reference internal" href="#an-example-of-exploring-the-library">6.2. An example of exploring the library</a></li>
|
||||
<li><a class="reference internal" href="#conclusions">6.3. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -113,16 +114,13 @@
|
|||
<p class="sidebar-title">API</p>
|
||||
<p>API stands for <code class="docutils literal notranslate"><span class="pre">Application</span> <span class="pre">Programming</span> <span class="pre">Interface</span></code>, a description for how to access the resources of a program or library.</p>
|
||||
</aside>
|
||||
<p>A good place to start exploring Evennia is the <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">Evenia-API frontpage</span></a>.
|
||||
This page sums up the main components of Evennia with a short description of each. Try clicking through
|
||||
to a few entries - once you get deep enough you’ll see full descriptions
|
||||
of each component along with their documentation. You can also click <code class="docutils literal notranslate"><span class="pre">[source]</span></code> to see the full Python source
|
||||
for each thing.</p>
|
||||
<p>You can also browse <a class="reference external" href="https://github.com/evennia/evennia">the evennia repository on github</a>. This is exactly
|
||||
what you can download from us. The github repo is also searchable.</p>
|
||||
<p>Finally, you can clone the evennia repo to your own computer and read the sources locally. This is necessary
|
||||
if you want to help with Evennia’s development itself. See the
|
||||
<a class="reference internal" href="../../../Setup/Installation-Git.html"><span class="doc std std-doc">extended install instructions</span></a> if you want to do this.</p>
|
||||
<p>There are several good ways to explore the Evennia library.</p>
|
||||
<ul class="simple">
|
||||
<li><p>This documentation contains the <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">Evennia-API docs</span></a>, generated automatically from sources. Try clicking through to a few entries - once you get deep enough you’ll see full descriptions of each component along with their documentation. You can also click <code class="docutils literal notranslate"><span class="pre">[source]</span></code> to see the full Python source code for each thing.</p></li>
|
||||
<li><p>There are <a class="reference internal" href="../../../Components/Components-Overview.html"><span class="doc std std-doc">separate doc pages for each component</span></a> if you want more detailed explanations.</p></li>
|
||||
<li><p>You can browse <a class="reference external" href="https://github.com/evennia/evennia">the evennia repository on github</a>. This is exactly what you can download from us.</p></li>
|
||||
<li><p>Finally, you can clone the evennia repo to your own computer and read the sources. This is necessary if you want to <em>really</em> understand what’s going on, or help with Evennia’s development. See the <a class="reference internal" href="../../../Setup/Installation-Git.html"><span class="doc std std-doc">extended install instructions</span></a> if you want to do this.</p></li>
|
||||
</ul>
|
||||
<section id="where-is-it">
|
||||
<h2><span class="section-number">6.1. </span>Where is it?<a class="headerlink" href="#where-is-it" title="Permalink to this headline">¶</a></h2>
|
||||
<p>If Evennia is installed, you can import from it simply with</p>
|
||||
|
|
@ -132,9 +130,8 @@ from evennia.some_module.other_module import SomeClass
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>and so on.</p>
|
||||
<p>If you installed Evennia with <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span></code>, the library folder will be installed deep inside your Python
|
||||
installation. If you cloned the repo there will be a folder <code class="docutils literal notranslate"><span class="pre">evennia</span></code> on your hard drive there.</p>
|
||||
<p>If you cloned the repo or read the code on <code class="docutils literal notranslate"><span class="pre">github</span></code> you’ll find this being the outermost structure:</p>
|
||||
<p>If you installed Evennia with <code class="docutils literal notranslate"><span class="pre">pip</span> <span class="pre">install</span></code>, the library folder will be installed deep inside your Python installation; you are better off <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia">looking at it on github</a>. If you cloned it, you should have an <code class="docutils literal notranslate"><span class="pre">evennia</span></code> folder to look into.</p>
|
||||
<p>You’ll find this being the outermost structure:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia/
|
||||
bin/
|
||||
CHANGELOG.md
|
||||
|
|
@ -150,7 +147,7 @@ the <em>actual</em> library, the thing covered by the API auto-docs and what you
|
|||
<div><p>The <code class="docutils literal notranslate"><span class="pre">evennia/docs/</span></code> folder contains the sources for this documentation. See
|
||||
<a class="reference internal" href="../../../Contributing-Docs.html"><span class="doc std std-doc">contributing to the docs</span></a> if you want to learn more about how this works.</p>
|
||||
</div></blockquote>
|
||||
<p>This the the structure of the Evennia library:</p>
|
||||
<p>This is the structure of the Evennia library:</p>
|
||||
<ul class="simple">
|
||||
<li><p>evennia</p>
|
||||
<ul>
|
||||
|
|
@ -187,21 +184,29 @@ from here to <code class="docutils literal notranslate"><span class="pre">mygame
|
|||
<p class="sidebar-title"><strong>init</strong>.py</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> file is a special Python filename used to represent a Python ‘package’. When you import <code class="docutils literal notranslate"><span class="pre">evennia</span></code> on its own, you import this file. When you do <code class="docutils literal notranslate"><span class="pre">evennia.foo</span></code> Python will first look for a property <code class="docutils literal notranslate"><span class="pre">.foo</span></code> in <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> and then for a module or folder of that name in the same location.</p>
|
||||
</aside>
|
||||
<p>While all the actual Evennia code is found in the various folders, the <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> represents the entire
|
||||
package <code class="docutils literal notranslate"><span class="pre">evennia</span></code>. It contains “shortcuts” to code that is actually located elsewhere. Most of these shortcuts
|
||||
are listed if you <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">scroll down a bit</span></a> on the Evennia-API page.</p>
|
||||
<p>While all the actual Evennia code is found in the various folders, the <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> represents the entire package <code class="docutils literal notranslate"><span class="pre">evennia</span></code>. It contains “shortcuts” to code that is actually located elsewhere. Most of these shortcuts are listed if you <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">scroll down a bit</span></a> on the Evennia-API page.</p>
|
||||
</section>
|
||||
<section id="an-example-of-exploring-the-library">
|
||||
<h2><span class="section-number">6.2. </span>An example of exploring the library<a class="headerlink" href="#an-example-of-exploring-the-library" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In the previous lesson we took a brief look at <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects</span></code> as an example of a Python module. Let’s
|
||||
open it again. Inside is the <code class="docutils literal notranslate"><span class="pre">Object</span></code> class, which inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>.
|
||||
Near the top of the module is this line:</p>
|
||||
<p>In the <a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#on-classes-and-objects"><span class="std std-doc">previous lesson</span></a> we took a brief look at <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects</span></code> as an example of a Python module. Let’s open it again.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="sd">"""</span>
|
||||
<span class="sd">module docstring</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Object</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> class docstring</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">pass</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We have the <code class="docutils literal notranslate"><span class="pre">Object</span></code> class, which inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. Near the top of the module is this line:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from evennia import DefaultObject
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We want to figure out just what this DefaultObject offers. Since this is imported directly from <code class="docutils literal notranslate"><span class="pre">evennia</span></code>, we
|
||||
are actually importing from <code class="docutils literal notranslate"><span class="pre">evennia/__init__.py</span></code>.</p>
|
||||
<p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/__init__.py#159">Look at Line 159</a> of <code class="docutils literal notranslate"><span class="pre">evennia/__init__.py</span></code> and you’ll find this line:</p>
|
||||
<p>We want to figure out just what this DefaultObject offers. Since this is imported directly from <code class="docutils literal notranslate"><span class="pre">evennia</span></code>, we are actually importing from <code class="docutils literal notranslate"><span class="pre">evennia/__init__.py</span></code>.</p>
|
||||
<p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/__init__.py#L160">Look at Line 160</a> of <code class="docutils literal notranslate"><span class="pre">evennia/__init__.py</span></code> and you’ll find this line:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from .objects.objects import DefaultObject
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -210,21 +215,22 @@ are actually importing from <code class="docutils literal notranslate"><span cla
|
|||
<p>The first full-stop in <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">.objects.objects</span> <span class="pre">...</span></code> means that we are importing from the current location. This is called a <code class="docutils literal notranslate"><span class="pre">relative</span> <span class="pre">import</span></code>. By comparison, <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">evennia.objects.objects</span></code> is an <code class="docutils literal notranslate"><span class="pre">absolute</span> <span class="pre">import</span></code>. In this particular case, the two would give the same result.</p>
|
||||
</aside>
|
||||
<blockquote>
|
||||
<div><p>You can also look at <a class="reference internal" href="../../../Evennia-API.html#typeclasses"><span class="std std-doc">the right section of the API frontpage</span></a> and click through
|
||||
to the code that way.</p>
|
||||
<div><p>You can also look at <a class="reference internal" href="../../../Evennia-API.html#typeclasses"><span class="std std-doc">the right section of the API frontpage</span></a> and click through to the code that way.</p>
|
||||
</div></blockquote>
|
||||
<p>The fact that <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is imported into <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> here is what makes it possible to also import
|
||||
it as <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">evennia</span> <span class="pre">import</span> <span class="pre">DefaultObject</span></code> even though the code for the class is not actually here.</p>
|
||||
<p>So to find the code for <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> we need to look in <code class="docutils literal notranslate"><span class="pre">evennia/objects/objects.py</span></code>. Here’s how
|
||||
to look it up in the docs:</p>
|
||||
<p>The fact that <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is imported into <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> here is what makes it possible to also import it as <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">evennia</span> <span class="pre">import</span> <span class="pre">DefaultObject</span></code> even though the code for the class is not actually here.</p>
|
||||
<p>So to find the code for <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> we need to look in <code class="docutils literal notranslate"><span class="pre">evennia/objects/objects.py</span></code>. Here’s how to look it up in the docs:</p>
|
||||
<ol class="simple">
|
||||
<li><p>Open the <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">API frontpage</span></a></p></li>
|
||||
<li><p>Locate the link to <a class="reference internal" href="../../../api/evennia.objects.objects.html"><span class="doc std std-doc">evennia.objects.objects</span></a> and click on it.
|
||||
3 You are now in the python module. Scroll down (or search in your web browser) to find the <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> class.
|
||||
4 You can now read what this does and what methods are on it. If you want to see the full source, click the
|
||||
[source] link next to it.</p></li>
|
||||
<li><p>Locate the link to <a class="reference internal" href="../../../api/evennia.objects.objects.html"><span class="doc std std-doc">evennia.objects.objects</span></a> and click on it.</p></li>
|
||||
<li><p>You are now in the python module. Scroll down (or search in your web browser) to find the <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> class.</p></li>
|
||||
<li><p>You can now read what this does and what methods are on it. If you want to see the full source, click the [source] link next to it.</p></li>
|
||||
</ol>
|
||||
</section>
|
||||
<section id="conclusions">
|
||||
<h2><span class="section-number">6.3. </span>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This is an important lesson. It teaches you how to find information for yourself. Knowing how to follow the class inheritance tree and navigate to things you need is a big part in learning a new library like Evennia.</p>
|
||||
<p>Next we’ll start to make use of what we have learned so far and combine it with the building blocks provided by Evennia.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -116,30 +116,24 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="overview-of-your-new-game-dir">
|
||||
<h1><span class="section-number">4. </span>Overview of your new Game Dir<a class="headerlink" href="#overview-of-your-new-game-dir" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Next we will take a little detour to look at the <em>Tutorial World</em>. This is a little solo adventure
|
||||
that comes with Evennia, a showcase for some of the things that are possible.</p>
|
||||
<p>Now we have ‘run the game’ a bit and started with our forays into Python from inside Evennia.
|
||||
It is time to start to look at how things look ‘outside of the game’. Let’s do a tour of your game-dir
|
||||
Like everywhere in the docs we’ll assume it’s called <code class="docutils literal notranslate"><span class="pre">mygame</span></code>.</p>
|
||||
<p>Until now we have ‘run the game’ a bit and started playing with Python inside Evennia.
|
||||
It is time to start to look at how things look ‘outside of the game’.</p>
|
||||
<p>Let’s do a tour of your game-dir (we assume it’s called <code class="docutils literal notranslate"><span class="pre">mygame</span></code>).</p>
|
||||
<blockquote>
|
||||
<div><p>When looking through files, ignore files ending with <code class="docutils literal notranslate"><span class="pre">.pyc</span></code> and the
|
||||
<code class="docutils literal notranslate"><span class="pre">__pycache__</span></code> folder if it exists. This is internal Python compilation files that you should never
|
||||
need to touch. Files <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> is also often empty and can be ignored (they have to do with
|
||||
Python package management).</p>
|
||||
</div></blockquote>
|
||||
<p>You may have noticed when we were building things in-game that we would often refer to code through
|
||||
“python paths”, such as</p>
|
||||
<p>You may have noticed when we were building things in-game that we would often refer to code through “python paths”, such as</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>create/drop button:tutorial_examples.red_button.RedButton
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is a fundamental aspect of coding Evennia - <em>you create code and then you tell Evennia where that code is and when it should be used</em>. Above we told it to create a red button by pulling from specific code in the <code class="docutils literal notranslate"><span class="pre">contrib/</span></code> folder. The same principle is true everywhere. So it’s important to know where code is and how you point to it correctly.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Python-paths</p>
|
||||
<p>A ‘python path’ uses ‘.’ instead of ‘/’ or ‘<code class="docutils literal notranslate"><span class="pre">\\</span></code>’ and skips the <code class="docutils literal notranslate"><span class="pre">.py</span></code> ending of files. It can also point to the code contents of python files. Since Evennia is already looking for code in your game dir, your python paths can start from there. So a path <code class="docutils literal notranslate"><span class="pre">/home/foo/devel/mygame/commands/command.py</span></code> would translate to a Python-path <code class="docutils literal notranslate"><span class="pre">commands.command</span></code>.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>create/drop button:tutorial_examples.red_button.RedButton
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is a fundamental aspect of coding Evennia - <em>you create code and then you tell Evennia where that
|
||||
code is and when it should be used</em>. Above we told it to create a red button by pulling from specific code
|
||||
in the <code class="docutils literal notranslate"><span class="pre">contribs/</span></code> folder but the same principle is true everywhere. So it’s important to know where code is
|
||||
and how you point to it correctly.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/</span></code></p>
|
||||
<ul>
|
||||
|
|
@ -163,11 +157,8 @@ building, such as build scripts and rules modules that don’t fit with one of t
|
|||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">server/</span></code> subfolder should remain the way it is - Evennia expects this. But you could in
|
||||
principle change the structure of the rest of your game dir as best fits your preference.
|
||||
Maybe you don’t need a world/ folder but prefer many folders with different aspects of your world?
|
||||
Or a new folder ‘rules’ for your RPG rules? This is fine. If you move things around you just need
|
||||
to update Evennia’s default settings to point to the right places in the new structure.</p>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">server/</span></code> subfolder should remain the way it is - Evennia expects this. But you can change the structure of the rest of your game dir as best fits your preferences.
|
||||
Maybe you don’t want a single world/ folder but prefer many folders with different aspects of your world? A new folder ‘rules’ for your RPG rules? Group your commands with your objects instead of having them separate? This is fine. If you move things around you just need to update Evennia’s default settings to point to the right places in the new structure.</p>
|
||||
</div></blockquote>
|
||||
<section id="commands">
|
||||
<h2><span class="section-number">4.1. </span>commands/<a class="headerlink" href="#commands" title="Permalink to this headline">¶</a></h2>
|
||||
|
|
@ -211,9 +202,8 @@ means that they must be extended with valid Python. You can also add logic to th
|
|||
knows where they are and will read them to configure itself at startup.</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">settings.py</span></code> - this is by far the most important file. It’s nearly empty by default, rather you
|
||||
are expected to copy&paste the changes you need from <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/default_settings.py">evennia/default_settings.py</a>.
|
||||
The default settings file is extensively documented. Importing/accessing the values in the settings
|
||||
file is done in a special way, like this:</p>
|
||||
are expected to copy&paste the changes you need from <a class="reference internal" href="../../../Setup/Settings-Default.html"><span class="doc std std-doc">evennia/default_settings.py</span></a>.
|
||||
The default settings file is extensively documented. Importing/accessing the values in the settings file is done in a special way, like this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> from django.conf import settings
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -221,8 +211,7 @@ file is done in a special way, like this:</p>
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> telnet_port = settings.TELNET_PORT
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You cannot assign to the settings file dynamically; you must change the <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> file directly to
|
||||
change a setting.</p>
|
||||
<p>You cannot assign to the settings file dynamically; you must change the <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> file directly to change a setting. See <a class="reference internal" href="../../../Setup/Settings.html"><span class="doc std std-doc">Settings</span></a> documentation for more details.</p>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">secret_settings.py</span></code> - If you are making your code effort public, you may not want to share all settings online.
|
||||
There may be server-specific secrets or just fine-tuning for your game systems that you prefer be kept secret
|
||||
|
|
@ -284,14 +273,12 @@ an entire planet or an actual dungeon room.</p></li>
|
|||
<a class="reference internal" href="../../../Components/Objects.html#exits"><span class="std std-doc">Exits</span></a> is another subclass of Object. Exits link one Room to another.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/scripts.py">scripts.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.scripts</span></code>) -
|
||||
<a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Scripts</span></a> are ‘out-of-character’ objects. They have no location in-game and can serve as basis for
|
||||
anything that needs database persistence, such as combat, weather, or economic systems. They also
|
||||
have the ability to execute code repeatedly, on a timer.</p></li>
|
||||
anything that needs database persistence, such as combat, weather, or economic systems. They also have the ability to execute code repeatedly, on a timer.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="web">
|
||||
<h3><span class="section-number">4.2.4. </span>web/<a class="headerlink" href="#web" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This folder contains folders for overriding the default web-presence of Evennia with your own designs.
|
||||
Most of these folders are empty except for a README file or a subset of other empty folders.</p>
|
||||
<p>This folder contains folders for overriding the default web-presence of Evennia with your own designs. Most of these folders are empty except for a README file or a subset of other empty folders. See <a class="reference internal" href="../../../Components/Components-Overview.html#web-components"><span class="std std-doc">the Web overview</span></a> for more details (we’ll also get back to the web later in this beginner tutorial).</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">media/</span></code> - this empty folder is where you can place your own images or other media files you want the
|
||||
web server to serve. If you are releasing your game with a lot of media (especially if you want videos) you
|
||||
|
|
@ -316,10 +303,7 @@ people change and re-structure this in various ways to better fit their ideas.</
|
|||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/world/batch_cmds.ev">batch_cmds.ev</a> - This is an <code class="docutils literal notranslate"><span class="pre">.ev</span></code> file, which is essentially
|
||||
just a list of Evennia commands to execute in sequence. This one is empty and ready to expand on. The
|
||||
<a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html"><span class="doc std std-doc">Tutorial World</span></a> was built with such a batch-file.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/world/prototypes.py">prototypes.py</a> - A <a class="reference internal" href="../../../Components/Prototypes.html"><span class="doc std std-doc">prototype</span></a> is a way
|
||||
to easily vary objects without changing their base typeclass. For example, one could use prototypes to
|
||||
tell that Two goblins, while both of the class ‘Goblin’ (so they follow the same code logic), should have different
|
||||
equipment, stats and looks.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/world/prototypes.py">prototypes.py</a> - A <a class="reference internal" href="../../../Components/Prototypes.html"><span class="doc std std-doc">prototype</span></a> is a way to easily vary objects without changing their base typeclass. For example, one could use prototypes to tell that Two goblins, while both of the class ‘Goblin’ (so they follow the same code logic), should have different equipment, stats and looks.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#typeclasses">7.2. Typeclasses</a><ul>
|
||||
<li><a class="reference internal" href="#examining-and-defaults">7.2.1. Examining and defaults</a></li>
|
||||
<li><a class="reference internal" href="#examining-objects">7.2.1. Examining objects</a></li>
|
||||
<li><a class="reference internal" href="#default-typeclasses">7.2.2. Default typeclasses</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#modifying-ourselves">7.3. Modifying ourselves</a><ul>
|
||||
|
|
@ -170,25 +171,23 @@ open it:</p>
|
|||
<span class="sd">"""</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Object</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="k">class</span> <span class="nc">ObjectParent</span><span class="p">:</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> class docstring </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Object</span><span class="p">(</span><span class="n">ObjectParent</span><span class="p">,</span> <span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> class docstring</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">pass</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So we have a class <code class="docutils literal notranslate"><span class="pre">Object</span></code> that <em>inherits</em> from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, which we have imported from Evennia.
|
||||
The class itself doesn’t do anything (it just <code class="docutils literal notranslate"><span class="pre">pass</span></code>es) but that doesn’t mean it’s useless. As we’ve seen,
|
||||
it inherits all the functionality of its parent. It’s in fact an <em>exact replica</em> of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> right now.
|
||||
If we knew what kind of methods and resources were available on <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> we could add our own and
|
||||
change the way it works!</p>
|
||||
<blockquote>
|
||||
<div><p>Hint: We will get back to this, but to learn what resources an Evennia parent like <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> offers,
|
||||
easiest is to peek at its <a class="reference internal" href="../../../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject" title="evennia.objects.objects.DefaultObject"><span class="xref myst py py-class">API documentation</span></a>. The docstring for
|
||||
the <code class="docutils literal notranslate"><span class="pre">Object</span></code> class can also help.</p>
|
||||
</div></blockquote>
|
||||
<p>One thing that Evennia classes offers and which you don’t get with vanilla Python classes is <em>persistence</em>. As
|
||||
you’ve found, Fluffy, Cuddly and Smaug are gone once we reload the server. Let’s see if we can fix this.</p>
|
||||
<p>So we have a class <code class="docutils literal notranslate"><span class="pre">Object</span></code> that <em>inherits</em> from <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> (which is empty) and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, which we have imported from Evennia. The <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> acts as a place to put code you want all
|
||||
of your <code class="docutils literal notranslate"><span class="pre">Objects</span></code> to have. We’ll focus on <code class="docutils literal notranslate"><span class="pre">Object</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> for now.</p>
|
||||
<p>The class itself doesn’t do anything (it just <code class="docutils literal notranslate"><span class="pre">pass</span></code>es) but that doesn’t mean it’s useless. As we’ve seen, it inherits all the functionality of its parent. It’s in fact an <em>exact replica</em> of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> right now. Once we know what kind of methods and resources are available on <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> we could add our own and change the way it works!</p>
|
||||
<p>One thing that Evennia classes offers and which you don’t get with vanilla Python classes is <em>persistence</em> - they survive a server reload since they are stored in the database.</p>
|
||||
<p>Go back to <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/monsters.py</span></code>. Change it as follows:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="kn">from</span> <span class="nn">typeclasses.objects</span> <span class="kn">import</span> <span class="n">Object</span>
|
||||
|
|
@ -218,15 +217,13 @@ you’ve found, Fluffy, Cuddly and Smaug are gone once we reload the server. Let
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Don’t forget to save. We removed <code class="docutils literal notranslate"><span class="pre">Monster.__init__</span></code> and made <code class="docutils literal notranslate"><span class="pre">Monster</span></code> inherit from Evennia’s <code class="docutils literal notranslate"><span class="pre">Object</span></code> (which in turn
|
||||
inherits from Evennia’s <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, as we saw). By extension, this means that <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> also inherits
|
||||
from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, just from further away!</p>
|
||||
<p>Don’t forget to save. We removed <code class="docutils literal notranslate"><span class="pre">Monster.__init__</span></code> and made <code class="docutils literal notranslate"><span class="pre">Monster</span></code> inherit from Evennia’s <code class="docutils literal notranslate"><span class="pre">Object</span></code> (which in turn inherits from Evennia’s <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, as we saw). By extension, this means that <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> also inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, just from further away!</p>
|
||||
<section id="making-a-new-object-by-calling-the-class">
|
||||
<h3><span class="section-number">7.1.1. </span>Making a new object by calling the class<a class="headerlink" href="#making-a-new-object-by-calling-the-class" title="Permalink to this headline">¶</a></h3>
|
||||
<p>First reload the server as usual. We will need to create the dragon a little differently this time:</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Keyword arguments</p>
|
||||
<p>Keyword arguments (like <code class="docutils literal notranslate"><span class="pre">db_key="Smaug"</span></code>) is a way to name the input arguments to a function or method. They make things easier to read but also allows for conveniently setting defaults for values not given explicitly.</p>
|
||||
<p><em>Keyword arguments</em> (like <code class="docutils literal notranslate"><span class="pre">db_key="Smaug"</span></code>) is a way to name the input arguments to a function or method. They make things easier to read but also allows for conveniently setting defaults for values not given explicitly. We saw them previously in use for <code class="docutils literal notranslate"><span class="pre">.format()</span></code>.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Dragon
|
||||
|
|
@ -239,6 +236,10 @@ The world trembles.
|
|||
</div>
|
||||
<p>Smaug works the same as before, but we created him differently: first we used
|
||||
<code class="docutils literal notranslate"><span class="pre">Dragon(db_key="Smaug",</span> <span class="pre">db_location=here)</span></code> to create the object, and then we used <code class="docutils literal notranslate"><span class="pre">smaug.save()</span></code> afterwards.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">here</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">here</span></code> used in <code class="docutils literal notranslate"><span class="pre">db_location=here</span></code> is a shortcut for your current location. This <code class="docutils literal notranslate"><span class="pre">here</span></code> (similar to <code class="docutils literal notranslate"><span class="pre">me</span></code>) is <em>only</em> available to use in the <code class="docutils literal notranslate"><span class="pre">py</span></code> command; you can’t use it in other Python code you write unless you define it yourself.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quit()
|
||||
Python Console is closing.
|
||||
> look
|
||||
|
|
@ -249,9 +250,7 @@ Python Console is closing.
|
|||
> look
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><em>He’s still there</em>… What we just did was to create a new entry in the database for Smaug. We gave the object
|
||||
its name (key) and set its location to our current location (remember that <code class="docutils literal notranslate"><span class="pre">here</span></code> is just something available
|
||||
in the <code class="docutils literal notranslate"><span class="pre">py</span></code> command, you can’t use it elsewhere).</p>
|
||||
<p><em>He’s still there</em>… What we just did was to create a new entry in the database for Smaug. We gave the object its name (key) and set its location to our current location.</p>
|
||||
<p>To make use of Smaug in code we must first find him in the database. For an object in the current
|
||||
location we can easily do this in <code class="docutils literal notranslate"><span class="pre">py</span></code> by using <code class="docutils literal notranslate"><span class="pre">me.search()</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py smaug = me.search("Smaug") ; smaug.firebreath()
|
||||
|
|
@ -264,83 +263,103 @@ Smaug breathes fire!
|
|||
<p>Creating Smaug like we did above is nice because it’s similar to how we created non-database
|
||||
bound Python instances before. But you need to use <code class="docutils literal notranslate"><span class="pre">db_key</span></code> instead of <code class="docutils literal notranslate"><span class="pre">key</span></code> and you also have to
|
||||
remember to call <code class="docutils literal notranslate"><span class="pre">.save()</span></code> afterwards. Evennia has a helper function that is more common to use,
|
||||
called <code class="docutils literal notranslate"><span class="pre">create_object</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py fluffy = evennia.create_object('typeclases.monster.Monster', key="Fluffy", location=here)
|
||||
called <code class="docutils literal notranslate"><span class="pre">create_object</span></code>. Let’s recreate Cuddly this time:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py evennia.create_object('typeclasses.monster.Monster', key="Cuddly", location=here)
|
||||
> look
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Boom, Fluffy should now be in the room with you, a little less scary than Smaug. You specify the
|
||||
python-path to the code you want and then set the key and location. Evennia sets things up and saves for you.</p>
|
||||
<p>If you want to find Fluffy from anywhere, you can use Evennia’s <code class="docutils literal notranslate"><span class="pre">search_object</span></code> helper:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> fluffy = evennia.search_object("Fluffy")[0] ; fluffy.move_around()
|
||||
Fluffy is moving!
|
||||
<p>Boom, Cuddly should now be in the room with you, a little less scary than Smaug. You specify the
|
||||
python-path to the code you want and then set the key and location (if you had the <code class="docutils literal notranslate"><span class="pre">Monster</span></code> class already imported, you could have passed that too). Evennia sets things up and saves for you.</p>
|
||||
<p>If you want to find Smaug from anywhere (not just in the same room), you can use Evennia’s <code class="docutils literal notranslate"><span class="pre">search_object</span></code> function:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> cuddly = evennia.search_object("Cuddly")[0] ; cuddly.move_around()
|
||||
Cuddly is moving!
|
||||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">[0]</span></code> is because <code class="docutils literal notranslate"><span class="pre">search_object</span></code> always returns a <em>list</em> of zero, one or more found objects. The <code class="docutils literal notranslate"><span class="pre">[0]</span></code>
|
||||
means that we want the first element of this list (counting in Python always starts from 0). If there were
|
||||
multiple Fluffies we could get the second one with <code class="docutils literal notranslate"><span class="pre">[1]</span></code>.</p>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">[0]</span></code> is because <code class="docutils literal notranslate"><span class="pre">search_object</span></code> always returns a <em>list</em> of zero, one or more found objects. The <code class="docutils literal notranslate"><span class="pre">[0]</span></code> means that we want the first element of this list (counting in Python always starts from 0). If there were multiple Cuddlies we could get the second one with <code class="docutils literal notranslate"><span class="pre">[1]</span></code>.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="creating-using-create-command">
|
||||
<h3><span class="section-number">7.1.3. </span>Creating using create-command<a class="headerlink" href="#creating-using-create-command" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Finally, you can also create a new Dragon using the familiar builder-commands we explored a few lessons ago:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create/drop Cuddly:typeclasses.monsters.Monster
|
||||
<p>Finally, you can also create a new dragon using the familiar builder-commands we explored a few lessons ago:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create/drop Fluffy:typeclasses.monsters.Dragon
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Cuddly is now in the room. After learning about how objects are created you’ll realize that all this command really
|
||||
does is to parse your input, figure out that <code class="docutils literal notranslate"><span class="pre">/drop</span></code> means to “give the object the same location as the caller”,
|
||||
and then do a call akin to</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia.create_object("typeclasses.monsters.Monster", key="Cuddly", location=here)
|
||||
<p>Fluffy is now in the room. After learning about how objects are created you’ll realize that all this command really does is to parse your input, figure out that <code class="docutils literal notranslate"><span class="pre">/drop</span></code> means to “give the object the same location as the caller”, and then do a call very similar to</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia.create_object("typeclasses.monsters.Dragon", key="Cuddly", location=here)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That’s pretty much all there is to the mighty <code class="docutils literal notranslate"><span class="pre">create</span></code> command! The rest is just parsing for the command
|
||||
to understand just what the user wants to create.</p>
|
||||
<p>That’s pretty much all there is to the mighty <code class="docutils literal notranslate"><span class="pre">create</span></code> command! The rest is just parsing for the command to understand just what the user wants to create.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="typeclasses">
|
||||
<h2><span class="section-number">7.2. </span>Typeclasses<a class="headerlink" href="#typeclasses" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">Object</span></code> (and <code class="docutils literal notranslate"><span class="pre">DefafultObject</span></code> class we inherited from above is what we refer to as a <em>Typeclass</em>. This
|
||||
is an Evennia thing. The instance of a typeclass saves itself to the database when it is created, and after
|
||||
that you can just search for it to get it back. We use the term <em>typeclass</em> or <em>typeclassed</em> to differentiate
|
||||
these types of classes and objects from the normal Python classes, whose instances go away on a reload.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">Object</span></code> (and <code class="docutils literal notranslate"><span class="pre">DefafultObject</span></code> class we inherited from above is what we refer to as a <em>Typeclass</em>. This is an Evennia thing. The instance of a typeclass saves itself to the database when it is created, and after that you can just search for it to get it back.</p>
|
||||
<p>We use the term <em>typeclass</em> or <em>typeclassed</em> to differentiate these types of classes and objects from the normal Python classes, whose instances go away on a reload.</p>
|
||||
<p>The number of typeclasses in Evennia are so few they can be learned by heart:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultObject</span></code>: This is the parent of all in-game entities - everything with a location. Evennia makes
|
||||
a few very useful child classes of this class:</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code>: The default entity represening a player avatar in-game.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultRoom</span></code>: A location in the game world.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultExit</span></code>: A link between locations.</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultAccount</span></code>: The OOC representation of a player, holds password and account info.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultChannel</span></code>: In-game channels. These could be used for all sorts of in-game communication.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultScript</span></code>: Out-of-game objects, with no presence in the game world. Anything you want to create that
|
||||
needs to be persistent can be stored with these entities, such as combat state, economic systems or what have you.</p></li>
|
||||
</ul>
|
||||
<p>If you take a look in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> you’ll find modules for each of these. Each contains an empty child
|
||||
class ready that already inherits from the right parent, ready for you to modify or build from:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Object(DefaultObject)</span></code>, a class directly inheriting the basic in-game entity, this
|
||||
works as a base for any object.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Character(DefaultCharacter)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/rooms.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Room(DefaultRoom)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/exits.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Exit(DefaultExit)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/accounts.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Account(DefaultAccount)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/channels.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Channel(DefaultChannel)</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> has <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Script(DefaultScript)</span></code></p></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<div><p>Notice that the classes in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> are <em>not inheriting from each other</em>. For example,
|
||||
<code class="docutils literal notranslate"><span class="pre">Character</span></code> is inheriting from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code> and not from <code class="docutils literal notranslate"><span class="pre">typeclasses.objects.Object</span></code>.
|
||||
So if you change <code class="docutils literal notranslate"><span class="pre">Object</span></code> you will not cause any change in the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class. If you want that you
|
||||
can easily just change the child classes to inherit in that way instead; Evennia doesn’t care.</p>
|
||||
</div></blockquote>
|
||||
<p>As seen with our <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> example, you don’t <em>have</em> to modify these modules directly. You can just make your
|
||||
own modules and import the base class.</p>
|
||||
<section id="examining-and-defaults">
|
||||
<h3><span class="section-number">7.2.1. </span>Examining and defaults<a class="headerlink" href="#examining-and-defaults" title="Permalink to this headline">¶</a></h3>
|
||||
<table class="colwidths-auto docutils align-default">
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>Evennia base typeclass</p></th>
|
||||
<th class="head"><p>mygame.typeclasses child</p></th>
|
||||
<th class="head"><p>description</p></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultObject</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.objects.Object</span></code></p></td>
|
||||
<td><p>Everything with a location</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code> (child of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>)</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.characters.Character</span></code></p></td>
|
||||
<td><p>Player avatars</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultRoom</span></code> (child of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>)</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.rooms.Room</span></code></p></td>
|
||||
<td><p>In-game locations</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultExit</span></code> (chld of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>)</p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.exits.Exit</span></code></p></td>
|
||||
<td><p>Links between rooms</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultAccount</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.accounts.Account</span></code></p></td>
|
||||
<td><p>A player account</p></td>
|
||||
</tr>
|
||||
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultChannel</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.channels.Channel</span></code></p></td>
|
||||
<td><p>In-game comms</p></td>
|
||||
</tr>
|
||||
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">evennia.DefaultScript</span></code></p></td>
|
||||
<td><p><code class="docutils literal notranslate"><span class="pre">typeclasses.scripts.Script</span></code></p></td>
|
||||
<td><p>Entities with no location</p></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The child classes under <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> are meant for you to conveniently modify and
|
||||
work with. Every class inheriting (at any distance) from a Evennia base typeclass is also considered a typeclass.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">somewhere</span> <span class="kn">import</span> <span class="n">Something</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">MyOwnClass</span><span class="p">(</span><span class="n">Something</span><span class="p">):</span>
|
||||
<span class="c1"># not inheriting from an Evennia core typeclass, so this </span>
|
||||
<span class="c1"># is just a 'normal' Python class inheriting from somewhere</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">MyOwnClass2</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
|
||||
<span class="c1"># inherits from one of the core Evennia typeclasses, so </span>
|
||||
<span class="c1"># this is also considered a 'typeclass'.</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Why invent the name ‘typeclass’?</p>
|
||||
<p>We separate ‘regular classes’ from ‘typeclasses’ because while typeclasses act <em>almost</em> like normal Python classes, <a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc">there are some differences</span></a>. We will gloss over those differences for now, but they are worth to read up on when you want to do more advanced things later.</p>
|
||||
</aside>
|
||||
<p>Notice that the classes in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> are <em>not inheriting from each other</em>. For example, <code class="docutils literal notranslate"><span class="pre">Character</span></code> is inheriting from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code> and not from <code class="docutils literal notranslate"><span class="pre">typeclasses.objects.Object</span></code>. So if you change <code class="docutils literal notranslate"><span class="pre">Object</span></code> you will not cause any change in the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class. If you want that you can easily just change the child classes to inherit in that way instead; Evennia doesn’t care.</p>
|
||||
<p>As seen with our <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> example, you don’t <em>have</em> to modify these modules directly. You can just make your own modules and import the base class.</p>
|
||||
<section id="examining-objects">
|
||||
<h3><span class="section-number">7.2.1. </span>Examining objects<a class="headerlink" href="#examining-objects" title="Permalink to this headline">¶</a></h3>
|
||||
<p>When you do</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create/drop giantess:typeclasses.monsters.Monster
|
||||
You create a new Monster: giantess.
|
||||
|
|
@ -372,19 +391,17 @@ may be more useful to us:</p>
|
|||
<li><p><strong>Name/key</strong> - The name of this thing. The value <code class="docutils literal notranslate"><span class="pre">(#14)</span></code> is probably different for you. This is the
|
||||
unique ‘primary key’ or <em>dbref</em> for this entity in the database.</p></li>
|
||||
<li><p><strong>Typeclass</strong>: This show the typeclass we specified, and the path to it.</p></li>
|
||||
<li><p><strong>Location</strong>: We are in Limbo. If you moved elsewhere you’ll see that instead. Also the <code class="docutils literal notranslate"><span class="pre">#dbref</span></code> is shown.</p></li>
|
||||
<li><p><strong>Permissions</strong>: <em>Permissions</em> are like the inverse to <em>Locks</em> - they are like keys to unlock access to other things.
|
||||
The giantess have no such keys (maybe fortunately).</p></li>
|
||||
<li><p><strong>Locks</strong>: Locks are the inverse of <em>Permissions</em> - specify what criterion <em>other</em> objects must fulfill in order to
|
||||
access the <code class="docutils literal notranslate"><span class="pre">giantess</span></code> object. This uses a very flexible mini-language. For examine, the line <code class="docutils literal notranslate"><span class="pre">examine:perm(Builders)</span></code>
|
||||
is read as “Only those with permission <em>Builder</em> or higher can <em>examine</em> this object”. Since we are the superuser
|
||||
we pass (even bypass) such locks with ease.</p></li>
|
||||
<li><p><strong>Persistent attributes</strong>: This allows for storing arbitrary, persistent data on the typeclassed entity. We’ll get
|
||||
to those in the next section.</p></li>
|
||||
<li><p><strong>Location</strong>: We are in Limbo. If you moved elsewhere you’ll see that instead. Also the <code class="docutils literal notranslate"><span class="pre">#dbref</span></code> of Limbo is shown.</p></li>
|
||||
<li><p><strong>Home</strong>: All objects with a location (inheriting from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>) must have a home location. This is a backup to move the object to if its current location is deleted.</p></li>
|
||||
<li><p><strong>Permissions</strong>: <em>Permissions</em> are like the inverse to <em>Locks</em> - they are like keys to unlock access to other things. The giantess have no such keys (maybe fortunately). The <a class="reference internal" href="../../../Components/Permissions.html"><span class="doc std std-doc">Permissions</span></a> has more info.</p></li>
|
||||
<li><p><strong>Locks</strong>: Locks are the inverse of <em>Permissions</em> - specify what criterion <em>other</em> objects must fulfill in order to access the <code class="docutils literal notranslate"><span class="pre">giantess</span></code> object. This uses a very flexible mini-language. For examine, the line <code class="docutils literal notranslate"><span class="pre">examine:perm(Builders)</span></code> is read as “Only those with permission <em>Builder</em> or higher can <em>examine</em> this object”. Since we are the superuser we pass (even bypass) such locks with ease. See the <a class="reference internal" href="../../../Components/Locks.html"><span class="doc std std-doc">Locks</span></a> documentation for more info.</p></li>
|
||||
<li><p><strong>Persistent attributes</strong>: This allows for storing arbitrary, persistent data on the typeclassed entity. We’ll get to those in the next section.</p></li>
|
||||
</ul>
|
||||
<p>Note how the <strong>Typeclass</strong> line describes exactly where to find the code of this object? This is very useful for
|
||||
understanding how any object in Evennia works.</p>
|
||||
<p>What happens if we <em>don’t</em> specify the typeclass though?</p>
|
||||
<p>Note how the <strong>Typeclass</strong> line describes exactly where to find the code of this object? This is very useful for understanding how any object in Evennia works.</p>
|
||||
</section>
|
||||
<section id="default-typeclasses">
|
||||
<h3><span class="section-number">7.2.2. </span>Default typeclasses<a class="headerlink" href="#default-typeclasses" title="Permalink to this headline">¶</a></h3>
|
||||
<p>What happens if we create an object and <em>don’t</em> specify its typeclass though?</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create/drop box
|
||||
You create a new Object: box.
|
||||
</pre></div>
|
||||
|
|
@ -401,20 +418,14 @@ You create a new Object: box.
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Typeclass: Object (typeclasses.objects.Object)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So when you didn’t specify a typeclass, Evennia used a default, more specifically the (so far) empty <code class="docutils literal notranslate"><span class="pre">Object</span></code> class in
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code>. This is usually what you want, especially since you can tweak that class as much
|
||||
as you like.</p>
|
||||
<p>But the reason Evennia knows to fall back to this class is not hard-coded - it’s a setting. The default is
|
||||
in <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/settings_default.py#L465">evennia/settings_default.py</a>,
|
||||
with the name <code class="docutils literal notranslate"><span class="pre">BASE_OBJECT_TYPECLASS</span></code>, which is set to <code class="docutils literal notranslate"><span class="pre">typeclasses.objects.Object</span></code>.</p>
|
||||
<p>So when you didn’t specify a typeclass, Evennia used a default, more specifically the (so far) empty <code class="docutils literal notranslate"><span class="pre">Object</span></code> class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code>. This is usually what you want, especially since you can tweak that class as much as you like.</p>
|
||||
<p>But the reason Evennia knows to fall back to this class is not hard-coded - it’s a setting. The default is in <a class="reference internal" href="../../../Setup/Settings-Default.html"><span class="doc std std-doc">evennia/settings_default.py</span></a>, with the name <code class="docutils literal notranslate"><span class="pre">BASE_OBJECT_TYPECLASS</span></code>, which is set to <code class="docutils literal notranslate"><span class="pre">typeclasses.objects.Object</span></code>.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Changing things</p>
|
||||
<p>While it’s tempting to change folders around to your liking, this can make it harder to follow tutorials and may confuse if you are asking others for help. So don’t overdo it unless you really know what you are doing.</p>
|
||||
<p>While it’s tempting to change folders around to your liking, this can make it harder to follow tutorials and may confuse if you are asking others for help. So don’t overdo it unless you really know what you are doing.</p>
|
||||
</aside>
|
||||
<p>So if you wanted the creation commands and methods to default to some other class you could
|
||||
add your own <code class="docutils literal notranslate"><span class="pre">BASE_OBJECT_TYPECLASS</span></code> line to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>. The same is true for all the other
|
||||
typeclasseses, like characters, rooms and accounts. This way you can change the
|
||||
layout of your game dir considerably if you wanted. You just need to tell Evennia where everything is.</p>
|
||||
add your own <code class="docutils literal notranslate"><span class="pre">BASE_OBJECT_TYPECLASS</span></code> line to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>. The same is true for all the other typeclasseses, like characters, rooms and accounts. This way you can change the layout of your game dir considerably if you wanted. You just need to tell Evennia where everything is.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="modifying-ourselves">
|
||||
|
|
@ -432,8 +443,7 @@ layout of your game dir considerably if you wanted. You just need to tell Evenni
|
|||
<span class="k">pass</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This looks quite familiar now - an empty class inheriting from the Evennia base typeclass. As you would expect,
|
||||
this is also the default typeclass used for creating Characters if you don’t specify it. You can verify it:</p>
|
||||
<p>This looks quite familiar now - an empty class inheriting from the Evennia base typeclass (it’s even easier than <code class="docutils literal notranslate"><span class="pre">Object</span></code> since there is no equvalent <code class="docutils literal notranslate"><span class="pre">ParentObject</span></code> mixin class here). As you would expect, this is also the default typeclass used for creating Characters if you don’t specify it. You can verify it:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> examine me
|
||||
------------------------------------------------------------------------------
|
||||
Name/key: YourName (#1)
|
||||
|
|
@ -461,17 +471,15 @@ Non-Persistent attributes:
|
|||
------------------------------------------------------------------------------
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You got a lot longer output this time. You have a lot more going on than a simple Object. Here are some new fields of note:</p>
|
||||
<p>Yes, the <code class="docutils literal notranslate"><span class="pre">examine</span></code> command understands <code class="docutils literal notranslate"><span class="pre">me</span></code>. You got a lot longer output this time. You have a lot more going on than a simple Object. Here are some new fields of note:</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Session id(s)</strong>: This identifies the <em>Session</em> (that is, the individual connection to a player’s game client).</p></li>
|
||||
<li><p><strong>Account</strong> shows, well the <code class="docutils literal notranslate"><span class="pre">Account</span></code> object associated with this Character and Session.</p></li>
|
||||
<li><p><strong>Stored/Merged Cmdsets</strong> and <strong>Commands available</strong> is related to which <em>Commands</em> are stored on you. We will
|
||||
get to them in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">next lesson</span></a>. For now it’s enough to know these consitute all the
|
||||
<li><p><strong>Stored/Merged Cmdsets</strong> and <strong>Commands available</strong> is related to which <em>Commands</em> are stored on you. We will get to them in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">next lesson</span></a>. For now it’s enough to know these consitute all the
|
||||
commands available to you at a given moment.</p></li>
|
||||
<li><p><strong>Non-Persistent attributes</strong> are Attributes that are only stored temporarily and will go away on next reload.</p></li>
|
||||
</ul>
|
||||
<p>Look at the <strong>Typeclass</strong> field and you’ll find that it points to <code class="docutils literal notranslate"><span class="pre">typeclasses.character.Character</span></code> as expected.
|
||||
So if we modify this class we’ll also modify ourselves.</p>
|
||||
<p>Look at the <strong>Typeclass</strong> field and you’ll find that it points to <code class="docutils literal notranslate"><span class="pre">typeclasses.character.Character</span></code> as expected. So if we modify this class we’ll also modify ourselves.</p>
|
||||
<section id="a-method-on-ourselves">
|
||||
<h3><span class="section-number">7.3.1. </span>A method on ourselves<a class="headerlink" href="#a-method-on-ourselves" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Let’s try something simple first. Back in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>:</p>
|
||||
|
|
@ -481,15 +489,15 @@ So if we modify this class we’ll also modify ourselves.</p>
|
|||
<span class="sd"> (class docstring)</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="nb">str</span> <span class="o">=</span> <span class="mi">10</span>
|
||||
<span class="n">dex</span> <span class="o">=</span> <span class="mi">12</span>
|
||||
<span class="nb">int</span> <span class="o">=</span> <span class="mi">15</span>
|
||||
<span class="n">strength</span> <span class="o">=</span> <span class="mi">10</span>
|
||||
<span class="n">dexterity</span> <span class="o">=</span> <span class="mi">12</span>
|
||||
<span class="n">intelligence</span> <span class="o">=</span> <span class="mi">15</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">get_stats</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Get the main stats of this character</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">str</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">dex</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">int</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">strength</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -505,9 +513,7 @@ So if we modify this class we’ll also modify ourselves.</p>
|
|||
<li><p>A <code class="docutils literal notranslate"><span class="pre">tuple</span></code> is written <code class="docutils literal notranslate"><span class="pre">(a,</span> <span class="pre">b,</span> <span class="pre">c,</span> <span class="pre">...)</span></code>. It cannot be modified once created.</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p>We made a new method, gave it a docstring and had it <code class="docutils literal notranslate"><span class="pre">return</span></code> the RP-esque values we set. It comes back as a
|
||||
<em>tuple</em> <code class="docutils literal notranslate"><span class="pre">(10,</span> <span class="pre">12,</span> <span class="pre">15)</span></code>. To get a specific value you could specify the <em>index</em> of the value you want,
|
||||
starting from zero:</p>
|
||||
<p>We made a new method, gave it a docstring and had it <code class="docutils literal notranslate"><span class="pre">return</span></code> the RP-esque values we set. It comes back as a <em>tuple</em> <code class="docutils literal notranslate"><span class="pre">(10,</span> <span class="pre">12,</span> <span class="pre">15)</span></code>. To get a specific value you could specify the <em>index</em> of the value you want, starting from zero:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py stats = self.get_stats() ; print(f"Strength is {stats[0]}.")
|
||||
Strength is 10.
|
||||
</pre></div>
|
||||
|
|
@ -516,15 +522,14 @@ Strength is 10.
|
|||
<section id="attributes">
|
||||
<h3><span class="section-number">7.3.2. </span>Attributes<a class="headerlink" href="#attributes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>So what happens when we increase our strength? This would be one way:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.str = self.str + 1
|
||||
> py self.str
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.strength = self.str + 1
|
||||
> py self.strength
|
||||
11
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we set the strength equal to its previous value + 1. A shorter way to write this is to use Python’s <code class="docutils literal notranslate"><span class="pre">+=</span></code>
|
||||
operator:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.str += 1
|
||||
> py self.str
|
||||
<p>Here we set the strength equal to its previous value + 1. A shorter way to write this is to use Python’s <code class="docutils literal notranslate"><span class="pre">+=</span></code> operator:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.strength += 1
|
||||
> py self.strength
|
||||
12
|
||||
> py self.get_stats()
|
||||
(12, 12, 15)
|
||||
|
|
@ -536,12 +541,8 @@ operator:</p>
|
|||
(10, 12, 15)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>After a reload all our changes were forgotten. When we change properties like this, it only changes in memory,
|
||||
not in the database (nor do we modify the python module’s code). So when we reloaded, the ‘fresh’ <code class="docutils literal notranslate"><span class="pre">Character</span></code>
|
||||
class was loaded, and it still has the original stats we wrote to it.</p>
|
||||
<p>In principle we could change the python code. But we don’t want to do that manually every time. And more importantly
|
||||
since we have the stats hardcoded in the class, <em>every</em> character instance in the game will have exactly the
|
||||
same <code class="docutils literal notranslate"><span class="pre">str</span></code>, <code class="docutils literal notranslate"><span class="pre">dex</span></code> and <code class="docutils literal notranslate"><span class="pre">int</span></code> now! This is clearly not what we want.</p>
|
||||
<p>After a reload all our changes were forgotten. When we change properties like this, it only changes in memory, not in the database (nor do we modify the python module’s code). So when we reloaded, the ‘fresh’ <code class="docutils literal notranslate"><span class="pre">Character</span></code> class was loaded, and it still has the original stats we wrote in it.</p>
|
||||
<p>In principle we could change the python code. But we don’t want to do that manually every time. And more importantly since we have the stats hardcoded in the class, <em>every</em> character instance in the game will have exactly the same <code class="docutils literal notranslate"><span class="pre">str</span></code>, <code class="docutils literal notranslate"><span class="pre">dex</span></code> and <code class="docutils literal notranslate"><span class="pre">int</span></code> now! This is clearly not what we want.</p>
|
||||
<p>Evennia offers a special, persistent type of property for this, called an <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>. Rework your
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
|
|
@ -554,42 +555,38 @@ same <code class="docutils literal notranslate"><span class="pre">str</span></co
|
|||
<span class="sd">"""</span>
|
||||
<span class="sd"> Get the main stats of this character</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">str</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dex</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">int</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">strength</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dexterity</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">intelligence</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Spaces in Attribute name?</p>
|
||||
<p>What if you want spaces in your Attribute name? Or you want to assign the name of the Attribute on-the fly? Then you can use <code class="docutils literal notranslate"><span class="pre">.attributes.add(name,</span> <span class="pre">value)</span></code> instead, for example <code class="docutils literal notranslate"><span class="pre">self.attributes.add("str",</span> <span class="pre">10)</span></code>.</p>
|
||||
<p>What if you want spaces in your Attribute name? Or you want to assign the name of the Attribute on-the fly? Then you can use <code class="docutils literal notranslate"><span class="pre">.attributes.add(name,</span> <span class="pre">value)</span></code> instead, for example <code class="docutils literal notranslate"><span class="pre">self.attributes.add("emotional</span> <span class="pre">intelligence",</span> <span class="pre">10)</span></code>. You read it out again with <code class="docutils literal notranslate"><span class="pre">self.attributes.get("emotional</span> <span class="pre">intelligence"</span></code>.</p>
|
||||
</aside>
|
||||
<p>We removed the hard-coded stats and added added <code class="docutils literal notranslate"><span class="pre">.db</span></code> for every stat. The <code class="docutils literal notranslate"><span class="pre">.db</span></code> handler makes the stat
|
||||
into an an Evennia <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>.</p>
|
||||
<p>We removed the hard-coded stats and added added <code class="docutils literal notranslate"><span class="pre">.db</span></code> for every stat. The <code class="docutils literal notranslate"><span class="pre">.db</span></code> handler makes the stat into an an Evennia <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a>.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.get_stats()
|
||||
(None, None, None)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Since we removed the hard-coded values, Evennia don’t know what they should be (yet). So all we get back
|
||||
is <code class="docutils literal notranslate"><span class="pre">None</span></code>, which is a Python reserved word to represent nothing, a no-value. This is different from a normal python
|
||||
property:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.str
|
||||
AttributeError: 'Character' object has no attribute 'str'
|
||||
> py self.db.str
|
||||
<p>Since we removed the hard-coded values, Evennia don’t know what they should be (yet). So all we get back is <code class="docutils literal notranslate"><span class="pre">None</span></code>, which is a Python reserved word to represent nothing, a no-value. This is different from a normal python property:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py me.strength
|
||||
AttributeError: 'Character' object has no attribute 'strength'
|
||||
> py me.db.strength
|
||||
(nothing will be displayed, because it's None)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Trying to get an unknown normal Python property will give an error. Getting an unknown Evennia <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> will
|
||||
never give an error, but only result in <code class="docutils literal notranslate"><span class="pre">None</span></code> being returned. This is often very practical.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.db.str, self.db.dex, self.db.int = 10, 12, 15
|
||||
> py self.get_stats()
|
||||
<p>Trying to get an unknown normal Python property will give an error. Getting an unknown Evennia <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> will never give an error, but only result in <code class="docutils literal notranslate"><span class="pre">None</span></code> being returned. This is often very practical.</p>
|
||||
<p>Next, let us test out assigning those Attributes</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py me.db.strength, me.db.dexterity, me.db.intelligence = 10, 12, 15
|
||||
> py me.get_stats()
|
||||
(10, 12, 15)
|
||||
> reload
|
||||
> py self.get_stats()
|
||||
> py me.get_stats()
|
||||
(10, 12, 15)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now we set the Attributes to the right values. We can see that things work the same as before, also after a
|
||||
server reload. Let’s modify the strength:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.db.str += 2
|
||||
<p>Now we set the Attributes to the right values, and they survive a server reload! Let’s modify the strength:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.db.strength += 2
|
||||
> py self.get_stats()
|
||||
(12, 12, 15)
|
||||
> reload
|
||||
|
|
@ -597,19 +594,12 @@ server reload. Let’s modify the strength:</p>
|
|||
(12, 12, 15)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Our change now survives a reload since Evennia automatically saves the Attribute to the database for us.</p>
|
||||
<p>Also our change now survives a reload since Evennia automatically saves the Attribute to the database for us.</p>
|
||||
</section>
|
||||
<section id="setting-things-on-new-characters">
|
||||
<h3><span class="section-number">7.3.3. </span>Setting things on new Characters<a class="headerlink" href="#setting-things-on-new-characters" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Things a looking better, but one thing remains strange - the stats start out with a value <code class="docutils literal notranslate"><span class="pre">None</span></code> and we
|
||||
have to manually set them to something reasonable. In a later lesson we will investigate character-creation
|
||||
in more detail. For now, let’s give every new character some random stats to start with.</p>
|
||||
<p>We want those stats to be set only once, when the object is first created. For the Character, this method
|
||||
is called <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title"><strong>init</strong> vs at_object_creation</p>
|
||||
<p>For the <code class="docutils literal notranslate"><span class="pre">Monster</span></code> class we used <code class="docutils literal notranslate"><span class="pre">__init__</span></code> to set up the class. We can’t use this for a typeclass because it will be called more than once, at the very least after every reload and maybe more depending on caching. Even if you are familiar with Python, avoid touching <code class="docutils literal notranslate"><span class="pre">__init__</span></code> for typeclasses, the results will not be what you expect.</p>
|
||||
</aside>
|
||||
<p>Things are looking better, but one thing remains strange - the stats start out with a value <code class="docutils literal notranslate"><span class="pre">None</span></code> and we have to manually set them to something reasonable. In a later lesson we will investigate character-creation in more detail. For now, let’s give every new character some random stats to start with.</p>
|
||||
<p>We want those stats to be set only once, when the object is first created. For the Character, this method is called <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># up by the other imports</span>
|
||||
<span class="kn">import</span> <span class="nn">random</span>
|
||||
|
||||
|
|
@ -619,15 +609,15 @@ is called <code class="docutils literal notranslate"><span class="pre">at_object
|
|||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_object_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">db</span><span class="o">.</span><span class="n">str</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">18</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dex</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">18</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">int</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">18</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">strength</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">18</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dexterity</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">18</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">intelligence</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">18</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">get_stats</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Get the main stats of this character</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">str</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dex</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">int</span>
|
||||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">strength</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dexterity</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">intelligence</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We imported a new module, <code class="docutils literal notranslate"><span class="pre">random</span></code>. This is part of Python’s standard library. We used <code class="docutils literal notranslate"><span class="pre">random.randint</span></code> to
|
||||
|
|
@ -637,9 +627,11 @@ set a random value from 3 to 18 to each stat. Simple, but for some classical RPG
|
|||
(12, 12, 15)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Hm, this is the same values we set before. They are not random. The reason for this is of course that, as said,
|
||||
<code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> only runs <em>once</em>, the very first time a character is created. Our character object was already
|
||||
created long before, so it will not be called again.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title"><strong>init</strong> vs at_object_creation</p>
|
||||
<p>For the <code class="docutils literal notranslate"><span class="pre">Monster</span></code> class we used <code class="docutils literal notranslate"><span class="pre">__init__</span></code> to set up the class. We can’t use this for a typeclass because it will be called more than once, at the very least after every reload and maybe more depending on caching. Even if you are familiar with Python, avoid touching <code class="docutils literal notranslate"><span class="pre">__init__</span></code> for typeclasses, the results will not be what you expect.</p>
|
||||
</aside>
|
||||
<p>Hm, this is the same values we set before. They are not random. The reason for this is of course that, as said, <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> only runs <em>once</em>, the very first time a character is created. Our character object was already created long before, so it will not be called again.</p>
|
||||
<p>It’s simple enough to run it manually though:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> self.at_object_creation()
|
||||
> py self.get_stats()
|
||||
|
|
@ -656,21 +648,22 @@ created long before, so it will not be called again.</p>
|
|||
</section>
|
||||
<section id="updating-all-characters-in-a-loop">
|
||||
<h3><span class="section-number">7.3.4. </span>Updating all Characters in a loop<a class="headerlink" href="#updating-all-characters-in-a-loop" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Needless to say, for your game you are wise to have a feel for what you want to go into the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook
|
||||
before you create a lot of objects (characters in this case). But should it come to that you don’t want to have to
|
||||
go around and re-run the method on everyone manually. For the Python beginner, doing this will also give a chance to
|
||||
try out Python <em>loops</em>. We try them out in multi-line Python mode:</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">AttributeProperties</p>
|
||||
<p>There is another way to define Attributes on a class, known as <a class="reference internal" href="../../../Components/Attributes.html#using-attributeproperty"><span class="std std-doc">AttributeProperties</span></a>. They can make it easier to maintain static default Attribute values on a typeclass. We will show them off when we make our game later in this tutorial series.</p>
|
||||
</aside>
|
||||
<p>Needless to say, you are wise to have a feel for what you want to go into the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook <em>before</em> you create a lot of objects (characters in this case).</p>
|
||||
<p>Luckily you only need to update objects once, and you don’t have to go around and re-run the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> method on everyone manually. For this we’ll try out a Python <em>loop</em>. Let’s go into multi-line Python mode:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> for a in [1, 2, "foo"]: > print(a)
|
||||
> for a in [1, 2, "foo"]:
|
||||
> print(a)
|
||||
1
|
||||
2
|
||||
foo
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A python <em>for-loop</em> allows us to loop over something. Above, we made a <em>list</em> of two numbers and a string. In
|
||||
every iteration of the loop, the variable <code class="docutils literal notranslate"><span class="pre">a</span></code> becomes one element in turn, and we print that.</p>
|
||||
<p>For our list, we want to loop over all Characters, and want to call <code class="docutils literal notranslate"><span class="pre">.at_object_creation</span></code> on each. This is how
|
||||
this is done (still in python multi-line mode):</p>
|
||||
<p>A python <em>for-loop</em> allows us to loop over something. Above, we made a <em>list</em> of two numbers and a string. In every iteration of the loop, the variable <code class="docutils literal notranslate"><span class="pre">a</span></code> becomes one element in turn, and we print that.</p>
|
||||
<p>For our list, we want to loop over all Characters, and want to call <code class="docutils literal notranslate"><span class="pre">.at_object_creation</span></code> on each. This is how this is done (still in python multi-line mode):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> from typeclasses.characters import Character
|
||||
> for char in Character.objects.all()
|
||||
> char.at_object_creation()
|
||||
|
|
@ -678,7 +671,7 @@ this is done (still in python multi-line mode):</p>
|
|||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Database queries</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">Character.objects.all()</span></code> is an example of a database query expressed in Python. This will be converted into a database query under the hood. This syntax is part of <a class="reference external" href="https://docs.djangoproject.com/en/4.1/topics/db/queries/">Django’s query language</a>. You don’t need to know Django to use Evennia, but if you ever need more specific database queries, this is always available when you need it.</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">Character.objects.all()</span></code> is an example of a database query expressed in Python. This will be converted into a database query under the hood. This syntax is part of <a class="reference external" href="https://docs.djangoproject.com/en/4.1/topics/db/queries/">Django’s query language</a>. You don’t need to know Django to use Evennia, but if you ever need more specific database queries, this is always available when you need it. We’ll get back to database queries in a later lesson.</p>
|
||||
</aside>
|
||||
<p>We import the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class and then we use <code class="docutils literal notranslate"><span class="pre">.objects.all()</span></code> to get all <code class="docutils literal notranslate"><span class="pre">Character</span></code> instances. Simplified,
|
||||
<code class="docutils literal notranslate"><span class="pre">.objects</span></code> is a resource from which one can <em>query</em> for all <code class="docutils literal notranslate"><span class="pre">Characters</span></code>. Using <code class="docutils literal notranslate"><span class="pre">.all()</span></code> gets us a listing
|
||||
|
|
@ -693,19 +686,13 @@ Closing the Python console.
|
|||
</section>
|
||||
<section id="extra-credits">
|
||||
<h2><span class="section-number">7.4. </span>Extra Credits<a class="headerlink" href="#extra-credits" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This principle is the same for other typeclasses. So using the tools explored in this lesson, try to expand
|
||||
the default room with an <code class="docutils literal notranslate"><span class="pre">is_dark</span></code> flag. It can be either <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>.
|
||||
Have all new rooms start with <code class="docutils literal notranslate"><span class="pre">is_dark</span> <span class="pre">=</span> <span class="pre">False</span></code> and make it so that once you change it, it survives a reload.
|
||||
<p>This principle is the same for other typeclasses. So using the tools explored in this lesson, try to expand the default room with an <code class="docutils literal notranslate"><span class="pre">is_dark</span></code> flag. It can be either <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>. Have all new rooms start with <code class="docutils literal notranslate"><span class="pre">is_dark</span> <span class="pre">=</span> <span class="pre">False</span></code> and make it so that once you change it, it survives a reload.
|
||||
Oh, and if you created any other rooms before, make sure they get the new flag too!</p>
|
||||
</section>
|
||||
<section id="conclusions">
|
||||
<h2><span class="section-number">7.5. </span>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In this lesson we created database-persistent dragons by having their classes inherit from one <code class="docutils literal notranslate"><span class="pre">Object</span></code>, one
|
||||
of Evennia’s <em>typeclasses</em>. We explored where Evennia looks for typeclasses if we don’t specify the path
|
||||
explicitly. We then modified ourselves - via the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class - to give us some simple RPG stats. This
|
||||
led to the need to use Evennia’s <em>Attributes</em>, settable via <code class="docutils literal notranslate"><span class="pre">.db</span></code> and to use a for-loop to update ourselves.</p>
|
||||
<p>Typeclasses are a fundamental part of Evennia and we will see a lot of more uses of them in the course of
|
||||
this tutorial. But that’s enough of them for now. It’s time to take some action. Let’s learn about <em>Commands</em>.</p>
|
||||
<p>In this lesson we created database-persistent dragons by having their classes inherit from one <code class="docutils literal notranslate"><span class="pre">Object</span></code>, one of Evennia’s <em>typeclasses</em>. We explored where Evennia looks for typeclasses if we don’t specify the path explicitly. We then modified ourselves - via the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class - to give us some simple RPG stats. This led to the need to use Evennia’s <em>Attributes</em>, settable via <code class="docutils literal notranslate"><span class="pre">.db</span></code> and to use a for-loop to update ourselves.</p>
|
||||
<p>Typeclasses are a fundamental part of Evennia and we will see a lot of more uses of them in the course of this tutorial. But that’s enough of them for now. It’s time to take some action. Let’s learn about <em>Commands</em>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ these concepts in the context of Evennia before.</p>
|
|||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html">6. Overview of the Evennia library</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html#where-is-it">6.1. Where is it?</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html#an-example-of-exploring-the-library">6.2. An example of exploring the library</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html#conclusions">6.3. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a><ul>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ This is a good idea!
|
|||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Functions and Methods</p>
|
||||
<ul class="simple">
|
||||
<li><p>Function: Something that performs and action when you <code class="docutils literal notranslate"><span class="pre">call</span></code> it with zero or more <code class="docutils literal notranslate"><span class="pre">arguments</span></code>. A function is stand-alone in a python module, like <code class="docutils literal notranslate"><span class="pre">print()</span></code></p></li>
|
||||
<li><p>Function: Something that performs and action when you call it with zero or more <code class="docutils literal notranslate"><span class="pre">arguments</span></code>. A function is stand-alone in a python module, like <code class="docutils literal notranslate"><span class="pre">print()</span></code></p></li>
|
||||
<li><p>Method: A function that sits “on” an object, like <code class="docutils literal notranslate"><span class="pre">obj.msg()</span></code>.</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
|
|
@ -242,21 +242,24 @@ trouble, use the Evennia web client.</p>
|
|||
</div>
|
||||
<p>What happened here was that we <em>assigned</em> the string <code class="docutils literal notranslate"><span class="pre">"awesome</span> <span class="pre">sauce"</span></code> to a <em>variable</em> we chose
|
||||
to name <code class="docutils literal notranslate"><span class="pre">a</span></code>. In the next statement, Python remembered what <code class="docutils literal notranslate"><span class="pre">a</span></code> was and we passed that into <code class="docutils literal notranslate"><span class="pre">format()</span></code>
|
||||
to get the output. If you replaced the value of <code class="docutils literal notranslate"><span class="pre">a</span></code> with something else in between, <em>that</em> would be printed
|
||||
instead.</p>
|
||||
to get the output. If you replaced the value of <code class="docutils literal notranslate"><span class="pre">a</span></code> with something else in between, <em>that</em> would be printed instead.</p>
|
||||
<p>Here’s the stat-example again, moving the stats to variables (here we just set them, but in a real
|
||||
game they may be changed over time, or modified by circumstance):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py stren, dext, intel = 13, 14, 8 ; print("STR: {}, DEX: {}, INT: {}".format(stren, dext, intel))
|
||||
STR: 13, DEX: 14, INT: 8
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The point is that even if the values of the stats change, the print() statement would not change - it just keeps
|
||||
pretty-printing whatever is given to it.</p>
|
||||
<p>The point is that even if the values of the stats change, the print() statement would not change - it just keeps pretty-printing whatever is given to it.</p>
|
||||
<p>You can also use named markers, like this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > py print("STR: {stren}, INT: {intel}, STR again: {stren}".format(dext=10, intel=18, stren=9))
|
||||
STR: 9, INT: 18, Str again: 9
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>the <code class="docutils literal notranslate"><span class="pre">key=value</span></code> pairs we add are called <em>keyword arguments</em> for the <code class="docutils literal notranslate"><span class="pre">format()</span></code> method. Each named argument will go to the matching <code class="docutils literal notranslate"><span class="pre">{key}</span></code> in the string. When using keywords, the order we add them doesn’t matter. We have no <code class="docutils literal notranslate"><span class="pre">{dext}</span></code> and two <code class="docutils literal notranslate"><span class="pre">{stren}</span></code> in the string, and that works fine.</p>
|
||||
</section>
|
||||
<section id="f-strings">
|
||||
<h3><span class="section-number">3.2.2. </span>f-strings<a class="headerlink" href="#f-strings" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">.format()</span></code> is convenient (and there is a <a class="reference external" href="https://www.w3schools.com/python/ref_string_format.asp">lot more</a>
|
||||
you can do with it). But the <em>f-string</em> can be even more convenient. An
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">.format()</span></code> is convenient (and there is a <a class="reference external" href="https://www.w3schools.com/python/ref_string_format.asp">lot more</a> you can do with it). But the <em>f-string</em> can be even more convenient. An
|
||||
f-string looks like a normal string … except there is an <code class="docutils literal notranslate"><span class="pre">f</span></code> front of it, like this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>f"this is now an f-string."
|
||||
</pre></div>
|
||||
|
|
@ -266,7 +269,7 @@ f-string looks like a normal string … except there is an <code class="docutils
|
|||
This is awesome sauce!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We could just insert that <code class="docutils literal notranslate"><span class="pre">a</span></code> variable directly into the f-string using <code class="docutils literal notranslate"><span class="pre">{a}</span></code>. Fewer parentheses to
|
||||
<p>We insert that <code class="docutils literal notranslate"><span class="pre">a</span></code> variable directly into the f-string using <code class="docutils literal notranslate"><span class="pre">{a}</span></code>. Fewer parentheses to
|
||||
remember and arguable easier to read as well.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py stren, dext, intel = 13, 14, 8 ; print(f"STR: {stren}, DEX: {dext}, INT: {intel}")
|
||||
STR: 13, DEX: 14, INT: 8
|
||||
|
|
@ -291,7 +294,7 @@ gives the normal text color. You can also use RGB (Red-Green-Blue) values from 0
|
|||
<div><p>If you don’t see the expected color, your client or terminal may not support Xterm256 (or
|
||||
color at all). Use the Evennia webclient.</p>
|
||||
</div></blockquote>
|
||||
<p>Use the commands <code class="docutils literal notranslate"><span class="pre">color</span> <span class="pre">ansi</span></code> or <code class="docutils literal notranslate"><span class="pre">color</span> <span class="pre">xterm</span></code> to see which colors are available. Experiment!</p>
|
||||
<p>Use the commands <code class="docutils literal notranslate"><span class="pre">color</span> <span class="pre">ansi</span></code> or <code class="docutils literal notranslate"><span class="pre">color</span> <span class="pre">xterm</span></code> to see which colors are available. Experiment! You can also read a lot more in the <a class="reference internal" href="../../../Concepts/Colors.html"><span class="doc std std-doc">Colors</span></a> documentation.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="importing-code-from-other-modules">
|
||||
|
|
@ -326,21 +329,15 @@ Hello World
|
|||
<p>If you make some error (we’ll cover how to handle errors below), fix the error in the module and
|
||||
run the <code class="docutils literal notranslate"><span class="pre">reload</span></code> command in-game for your changes to take effect.</p>
|
||||
<p>So importing <code class="docutils literal notranslate"><span class="pre">world.test</span></code> actually means importing <code class="docutils literal notranslate"><span class="pre">world/test.py</span></code>. Think of the period <code class="docutils literal notranslate"><span class="pre">.</span></code> as
|
||||
replacing <code class="docutils literal notranslate"><span class="pre">/</span></code> (or <code class="docutils literal notranslate"><span class="pre">\</span></code> for Windows) in your path. The <code class="docutils literal notranslate"><span class="pre">.py</span></code> ending of <code class="docutils literal notranslate"><span class="pre">test.py</span></code> is also never
|
||||
included in this “Python-path”, but <em>only</em> files with that ending can be imported this way.
|
||||
Where is <code class="docutils literal notranslate"><span class="pre">mygame</span></code> in that Python-path? The answer is that Evennia has already told Python that
|
||||
your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder is a good place to look for imports. So we don’t include <code class="docutils literal notranslate"><span class="pre">mygame</span></code> in the
|
||||
path - Evennia handles this for us.</p>
|
||||
replacing <code class="docutils literal notranslate"><span class="pre">/</span></code> (or <code class="docutils literal notranslate"><span class="pre">\</span></code> for Windows) in your path.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">.py</span></code> ending of <code class="docutils literal notranslate"><span class="pre">test.py</span></code> is never included in this “Python-path”, but <em>only</em> files with that ending can be imported this way. Where is <code class="docutils literal notranslate"><span class="pre">mygame</span></code> in that Python-path? The answer is that Evennia has already told Python that your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder is a good place to look for imports. So we should not include <code class="docutils literal notranslate"><span class="pre">mygame</span></code> in the path - Evennia handles this for us.</p>
|
||||
<p>When you import the module, the top “level” of it will execute. In this case, it will immediately
|
||||
print “Hello World”.</p>
|
||||
<p>Now try to run this a second time:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You will <em>not</em> see any output this second time or any subsequent times! This is not a bug. Rather
|
||||
it is because of how Python importing works - it stores all imported modules and will
|
||||
avoid importing them more than once. So your <code class="docutils literal notranslate"><span class="pre">print</span></code> will only run the first time, when the module
|
||||
is first imported.</p>
|
||||
<p>You will <em>not</em> see any output this or any subsequent times! This is not a bug. Rather it is because of how Python importing works - it stores all imported modules and will avoid importing them more than once. So your <code class="docutils literal notranslate"><span class="pre">print</span></code> will only run the first time, when the module is first imported.</p>
|
||||
<p>Try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
</pre></div>
|
||||
|
|
@ -354,8 +351,7 @@ Hello World!
|
|||
import it anew. You’d have to do this every time you wanted the print to show though, which is
|
||||
not very useful.</p>
|
||||
<blockquote>
|
||||
<div><p>We’ll get back to more advanced ways to import code in later tutorial sections - this is an
|
||||
important topic. But for now, let’s press on and resolve this particular problem.</p>
|
||||
<div><p>We’ll get back to more advanced ways to import code in <a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#importing-things"><span class="std std-doc">a later lesson</span></a> - this is an important topic. But for now, let’s press on and resolve this particular problem.</p>
|
||||
</div></blockquote>
|
||||
<section id="our-first-own-function">
|
||||
<h3><span class="section-number">3.3.1. </span>Our first own function<a class="headerlink" href="#our-first-own-function" title="Permalink to this headline">¶</a></h3>
|
||||
|
|
@ -528,8 +524,8 @@ the room it is in.</p>
|
|||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Creating objects</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">create</span></code> command was first used to create boxes in the
|
||||
<code class="docutils literal notranslate"><span class="pre">Building</span> <span class="pre">Stuff</span> <span class="pre"><Building-Quickstart></span></code>_ tutorial. Note how it
|
||||
uses a “python-path” to describe where to load the mirror’s code from.</p>
|
||||
<a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">Building Stuff</span></a> tutorial. You should now recognize
|
||||
that it uses a “python-path” to tell Evennia where to load the mirror’s code from.</p>
|
||||
</aside>
|
||||
<p>A mirror should appear in your location.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> look mirror
|
||||
|
|
@ -585,7 +581,7 @@ when you want to do some quick testing. But you can also start a full multi-line
|
|||
inside Evennia.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
Evennia Interactive Python mode
|
||||
Python 3.7.1 (default, Oct 22 2018, 11:21:55)
|
||||
Python 3.11.0 (default, Nov 22 2022, 11:21:55)
|
||||
[GCC 8.2.0] on Linux
|
||||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
|
|
@ -600,14 +596,12 @@ Hello World
|
|||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note that we didn’t need to put <code class="docutils literal notranslate"><span class="pre">py</span></code> in front now. The system will also echo your input (that’s the bit after
|
||||
the <code class="docutils literal notranslate"><span class="pre">>>></span></code>). For brevity in this tutorual we’ll turn the echo off. First exit <code class="docutils literal notranslate"><span class="pre">py</span></code> and then start again with the
|
||||
<code class="docutils literal notranslate"><span class="pre">/noecho</span></code> flag.</p>
|
||||
<p>Note that we didn’t need to put <code class="docutils literal notranslate"><span class="pre">py</span></code> in front now. The system will also echo your input (that’s the bit after the <code class="docutils literal notranslate"><span class="pre">>>></span></code>). For brevity in this tutorual we’ll turn the echo off. First exit <code class="docutils literal notranslate"><span class="pre">py</span></code> and then start again with the <code class="docutils literal notranslate"><span class="pre">/noecho</span></code> flag.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quit()
|
||||
Closing the Python console.
|
||||
> py/noecho
|
||||
Evennia Interactive Python mode (no echoing of prompts)
|
||||
Python 3.7.1 (default, Oct 22 2018, 11:21:55)
|
||||
Python 3.11.0 (default, Nov 22 2022, 11:21:56)
|
||||
[GCC 8.2.0] on Linux
|
||||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
|
|
@ -617,13 +611,13 @@ Python 3.7.1 (default, Oct 22 2018, 11:21:55)
|
|||
<ul class="simple">
|
||||
<li><p>Start with <code class="docutils literal notranslate"><span class="pre">py</span></code>.</p></li>
|
||||
<li><p>Use <code class="docutils literal notranslate"><span class="pre">py/noecho</span></code> if you don’t want your input to be echoed for every line.</p></li>
|
||||
<li><p>All your inputs will now be interpreted as Python code.</p></li>
|
||||
<li><p><em>All</em> your inputs will now be interpreted as Python code.</p></li>
|
||||
<li><p>Exit with <code class="docutils literal notranslate"><span class="pre">quit()</span></code>.</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p>We can now enter multi-line Python code:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> a = "Test"
|
||||
> print(f"This is a {a}."}
|
||||
> print(f"This is a {a}.")
|
||||
This is a Test.
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -643,8 +637,7 @@ of the block with indention. So the next line must be manually indented (4 space
|
|||
for Python to know it’s part of the function body.</p></li>
|
||||
<li><p>We expand the <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> function with another argument <code class="docutils literal notranslate"><span class="pre">txt</span></code>. This allows us to send any text, not just
|
||||
“Hello World” over and over.</p></li>
|
||||
<li><p>To tell <code class="docutils literal notranslate"><span class="pre">py</span></code> that no more lines will be added to the function body, we end with an empty input. When
|
||||
the normal prompt on how to exit returns, we know we are done.</p></li>
|
||||
<li><p>To tell <code class="docutils literal notranslate"><span class="pre">py</span></code> that no more lines will be added to the function body, we end with an empty input. When the normal prompt returns, we know we are done.</p></li>
|
||||
</ul>
|
||||
<p>Now we have defined a new function. Let’s try it out:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> hello_world(me, "Hello world to me!")
|
||||
|
|
@ -731,8 +724,7 @@ Python code, we need to save it in a Python module, like we did for <code class=
|
|||
first function, fixed an error and even searched and talked to a mirror! Being able to access
|
||||
python inside and outside of the game is an important skill for testing and debugging, but in
|
||||
practice you will be writing most your code in Python modules.</p>
|
||||
<p>To that end we also created a first new Python module in the <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> game dir, then imported and used it.
|
||||
Now let’s look at the rest of the stuff you’ve got going on inside that <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> folder …</p>
|
||||
<p>To that end we also created a first new Python module in the <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> game dir, then imported and used it. Now let’s look at the rest of the stuff you’ve got going on inside that <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> folder …</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -119,16 +119,14 @@
|
|||
We have also taken a look at what our game dir looks and what is where. Now we’ll start to use it.</p>
|
||||
<section id="importing-things">
|
||||
<h2><span class="section-number">5.1. </span>Importing things<a class="headerlink" href="#importing-things" title="Permalink to this headline">¶</a></h2>
|
||||
<p>No one writes something as big as an online game in one single huge file. Instead one breaks up the
|
||||
code into separate files (modules). Each module is dedicated to different purposes. Not only does
|
||||
it make things cleaner, organized and easier to understand. It also makes it easier to re-use code -
|
||||
you just import the resources you need and know you only get just what you requested. This makes
|
||||
it much easier to find errors and to know what code is good and which has issues.</p>
|
||||
<p>In a <a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#importing-code-from-other-modules"><span class="std std-doc">previous lesson</span></a> we already learned how to import resources into our code. Now we’ll dive a little deeper.</p>
|
||||
<p>No one writes something as big as an online game in one single huge file. Instead one breaks up the code into separate files (modules). Each module is dedicated to different purposes. Not only does it make things cleaner, organized and easier to understand.</p>
|
||||
<p>Splitting code also makes it easier to re-use - you just import the resources you need and know you only get just what you requested. This makes it easier to spot errors and to know what code is good and which has issues.</p>
|
||||
<blockquote>
|
||||
<div><p>Evennia itself uses your code in the same way - you just tell it where a particular type of code is,
|
||||
and it will import and use it (often instead of its defaults).</p>
|
||||
</div></blockquote>
|
||||
<p>We have already successfully imported things, for example:</p>
|
||||
<p>Here’s a familiar example:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test ; world.test.hello_world(me)
|
||||
Hello World!
|
||||
</pre></div>
|
||||
|
|
@ -156,10 +154,7 @@ not, make it so):</p>
|
|||
<li><p>Anything on a line after a <code class="docutils literal notranslate"><span class="pre">#</span></code> is a <code class="docutils literal notranslate"><span class="pre">comment</span></code>, ignored by Python</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p>The <em>python_path</em> describes the relation between Python resources, both between and inside
|
||||
Python <em>modules</em> (that is, files ending with .py). A python-path separates each part of the
|
||||
path <code class="docutils literal notranslate"><span class="pre">.</span></code> and always skips the <code class="docutils literal notranslate"><span class="pre">.py</span></code> file endings. Also, Evennia already knows to start looking
|
||||
for python resources inside <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> so this should never be specified. Hence</p>
|
||||
<p>To reiterate, the <em>python_path</em> describes the relation between Python resources, both between and inside Python <em>modules</em> (that is, files ending with .py). Paths use <code class="docutils literal notranslate"><span class="pre">.</span></code> and always skips the <code class="docutils literal notranslate"><span class="pre">.py</span></code> file endings. Also, Evennia already knows to start looking for python resources inside <code class="docutils literal notranslate"><span class="pre">mygame/</span></code> so this should never be included.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>import world.test
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -169,7 +164,7 @@ this module to get to the function you want:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">import</span></code> like this means that you have to specify the full <code class="docutils literal notranslate"><span class="pre">world.test</span></code> every time you want
|
||||
to get to your function. Here’s a more powerful form of import:</p>
|
||||
to get to your function. Here’s an alternative:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from world.test import hello_world
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -237,6 +232,12 @@ imports at the top, resources that are then used by all code in that module.</p>
|
|||
<span class="sd">"""</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">ObjectParent</span><span class="p">:</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> class docstring </span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">pass</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Object</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> class docstring</span>
|
||||
|
|
@ -246,28 +247,24 @@ imports at the top, resources that are then used by all code in that module.</p>
|
|||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Docstrings vs Comments</p>
|
||||
<p>A docstring is not the same as a comment (created by <code class="docutils literal notranslate"><span class="pre">#</span></code>). A docstring is not ignored by Python but is an integral part of the thing it is documenting (the module and the class in this case).</p>
|
||||
<p>A docstring is not the same as a comment (created by <code class="docutils literal notranslate"><span class="pre">#</span></code>). A docstring is not ignored by Python but is an integral part of the thing it is documenting (the module and the class in this case). For example, we read docstrings to help text for <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">API documentation</span></a>; we could not do that with comments.</p>
|
||||
</aside>
|
||||
<p>The real file is much longer but we can ignore the multi-line strings (<code class="docutils literal notranslate"><span class="pre">"""</span> <span class="pre">...</span> <span class="pre">"""</span></code>). These serve
|
||||
as documentation-strings, or <em>docstrings</em> for the module (at the top) and the <code class="docutils literal notranslate"><span class="pre">class</span></code> below.</p>
|
||||
<p>Below the module doc string we have the import. In this case we are importing a resource
|
||||
from the core <code class="docutils literal notranslate"><span class="pre">evennia</span></code> library itself. We will dive into this later, for now we just treat this
|
||||
as a black box.</p>
|
||||
<p>Next we have a <code class="docutils literal notranslate"><span class="pre">class</span></code> named <code class="docutils literal notranslate"><span class="pre">Object</span></code>, which <em>inherits</em> from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. This class doesn’t
|
||||
actually do anything on its own, its only code (except the docstring) is <code class="docutils literal notranslate"><span class="pre">pass</span></code> which means,
|
||||
well, to pass and don’t do anything.</p>
|
||||
<p>We will get back to this module in the <a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html"><span class="doc std std-doc">next lesson</span></a>. First we need to do a
|
||||
little detour to understand what a ‘class’, an ‘object’ or ‘instance’ is. These are fundamental
|
||||
things to understand before you can use Evennia efficiently.</p>
|
||||
<p>Next we have an empty <code class="docutils literal notranslate"><span class="pre">class</span></code> named <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code>. It doesn’t do anything, its only code (except the docstring) is <code class="docutils literal notranslate"><span class="pre">pass</span></code> which means, well, to pass and don’t do anything. Since it also doesn’t <em>inherit</em> from anything, it’s just an empty container. We will not concern ourselves with it for this tutorial.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">class</span></code> named <code class="docutils literal notranslate"><span class="pre">Object</span></code>_ inherits_ from <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. Since we see that <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> is empty, what is interesting is <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. Again, the <code class="docutils literal notranslate"><span class="pre">Object</span></code> class doesn’t
|
||||
actually do anything on its own right now, but because of it being a child of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, it’s actually providing a lot of functionality! If this is confusing, read on.</p>
|
||||
<p>We will get back to this module in the <a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html"><span class="doc std std-doc">next lesson</span></a>. First we need to do a little detour to understand what a ‘class’, an ‘object’ or ‘instance’ is. These are fundamental things to understand before you can use Evennia efficiently.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">OOP</p>
|
||||
<p>Classes, objects, instances and inheritance are fundamental to Python. This and some other concepts are often clumped together under the term Object-Oriented-Programming (OOP).</p>
|
||||
</aside>
|
||||
<section id="classes-and-instances">
|
||||
<h3><span class="section-number">5.2.1. </span>Classes and instances<a class="headerlink" href="#classes-and-instances" title="Permalink to this headline">¶</a></h3>
|
||||
<p>A ‘class’ can be seen as a ‘template’ for a ‘type’ of object. The class describes the basic functionality
|
||||
of everyone of that class. For example, we could have a class <code class="docutils literal notranslate"><span class="pre">Monster</span></code> which has resources for moving itself
|
||||
from room to room.</p>
|
||||
<p>A ‘class’ can be seen as a ‘template’ for a ‘type’ of object. The class describes the basic functionality of everyone of that class. For example, we could have a class <code class="docutils literal notranslate"><span class="pre">Monster</span></code> which has resources for moving itself from room to room.</p>
|
||||
<p>Open a new file <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/monsters.py</span></code>. Add the following simple class:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="k">class</span> <span class="nc">Monster</span><span class="p">:</span>
|
||||
|
|
@ -288,11 +285,11 @@ back to the <code class="docutils literal notranslate"><span class="pre">key</sp
|
|||
<p class="sidebar-title">Terms</p>
|
||||
<ul class="simple">
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre">class</span></code> is a code template describing a ‘type’ of something</p></li>
|
||||
<li><p>An <code class="docutils literal notranslate"><span class="pre">object</span></code> is an <code class="docutils literal notranslate"><span class="pre">instance</span></code> of a <code class="docutils literal notranslate"><span class="pre">class</span></code>. Like using a mold to cast in soldiers, one class can be <code class="docutils literal notranslate"><span class="pre">instantiated</span></code> into any number of object-instances.</p></li>
|
||||
<li><p>An <code class="docutils literal notranslate"><span class="pre">object</span></code> is an <code class="docutils literal notranslate"><span class="pre">instance</span></code> of a <code class="docutils literal notranslate"><span class="pre">class</span></code>. Like using a mold to cast tin soldiers, one class can be <code class="docutils literal notranslate"><span class="pre">instantiated</span></code> into any number of object-instances. Each instance does not need to be identical (much like each tin soldier can be painted differently).</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p>A class is just a template. Before it can be used, we must create an <em>instance</em> of the class. If
|
||||
<code class="docutils literal notranslate"><span class="pre">Monster</span></code> is a class, then an instance is Fluffy, the individual red dragon. You instantiate
|
||||
<code class="docutils literal notranslate"><span class="pre">Monster</span></code> is a class, then an instance is <code class="docutils literal notranslate"><span class="pre">Fluffy</span></code>, a specific dragon individual. You instantiate
|
||||
by <em>calling</em> the class, much like you would a function:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>fluffy = Monster()
|
||||
</pre></div>
|
||||
|
|
@ -319,8 +316,7 @@ Monster is moving!
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>We now have two dragons and they’ll hang around until with call <code class="docutils literal notranslate"><span class="pre">quit()</span></code> to exit this Python
|
||||
instance. We can have them move as many times as we want. But no matter how many dragons we
|
||||
create, they will all show the same printout since <code class="docutils literal notranslate"><span class="pre">key</span></code> is always fixed as “Monster”.</p>
|
||||
instance. We can have them move as many times as we want. But no matter how many dragons we create, they will all show the same printout since <code class="docutils literal notranslate"><span class="pre">key</span></code> is always fixed as “Monster”.</p>
|
||||
<p>Let’s make the class a little more flexible:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="k">class</span> <span class="nc">Monster</span><span class="p">:</span>
|
||||
|
|
@ -358,13 +354,11 @@ fluffy.move_around()
|
|||
Fluffy is moving!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now we passed <code class="docutils literal notranslate"><span class="pre">"Fluffy"</span></code> as an argument to the class. This went into <code class="docutils literal notranslate"><span class="pre">__init__</span></code> and set <code class="docutils literal notranslate"><span class="pre">self.key</span></code>, which we
|
||||
later used to print with the right name! Again, note that we didn’t include <code class="docutils literal notranslate"><span class="pre">self</span></code> when calling.</p>
|
||||
<p>Now we passed <code class="docutils literal notranslate"><span class="pre">"Fluffy"</span></code> as an argument to the class. This went into <code class="docutils literal notranslate"><span class="pre">__init__</span></code> and set <code class="docutils literal notranslate"><span class="pre">self.key</span></code>, which we later used to print with the right name!</p>
|
||||
</section>
|
||||
<section id="whats-so-good-about-objects">
|
||||
<h3><span class="section-number">5.2.2. </span>What’s so good about objects?<a class="headerlink" href="#whats-so-good-about-objects" title="Permalink to this headline">¶</a></h3>
|
||||
<p>So far all we’ve seen a class do is to behave our first <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> function but more complex. We
|
||||
could just have made a function:</p>
|
||||
<p>So far all we’ve seen a class do is to behave like our first <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> function but being more complex. We could just have made a function:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">monster_move_around</span><span class="p">(</span><span class="n">key</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s2"> is moving!"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
|
|
@ -372,14 +366,13 @@ could just have made a function:</p>
|
|||
<p>The difference between the function and an instance of a class (the object), is that the
|
||||
object retains <em>state</em>. Once you called the function it forgets everything about what you called
|
||||
it with last time. The object, on the other hand, remembers changes:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> fluffy.key = "Cuddly"
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> fluffy.key = "Fluffy, the red dragon"
|
||||
> fluffy.move_around()
|
||||
Cuddly is moving!
|
||||
Fluffy, the red dragon is moving!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">fluffy</span></code> object’s <code class="docutils literal notranslate"><span class="pre">key</span></code> was changed to “Cuddly” for as long as it’s around. This makes objects
|
||||
extremely useful for representing and remembering collections of data - some of which can be other
|
||||
objects in turn:</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">fluffy</span></code> object’s <code class="docutils literal notranslate"><span class="pre">key</span></code> was changed for as long as it’s around. This makes objects extremely useful for representing and remembering collections of data - some of which can be other
|
||||
objects in turn. Some examples:</p>
|
||||
<ul class="simple">
|
||||
<li><p>A player character with all its stats</p></li>
|
||||
<li><p>A monster with HP</p></li>
|
||||
|
|
@ -393,8 +386,7 @@ objects in turn:</p>
|
|||
</section>
|
||||
<section id="classes-can-have-children">
|
||||
<h3><span class="section-number">5.2.3. </span>Classes can have children<a class="headerlink" href="#classes-can-have-children" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Classes can <em>inherit</em> from each other. A “child” class will inherit everything from its “parent” class. But if
|
||||
the child adds something with the same name as its parent, it will <em>override</em> whatever it got from its parent.</p>
|
||||
<p>Classes can <em>inherit</em> from each other. A “child” class will inherit everything from its “parent” class. But if the child adds something with the same name as its parent, it will <em>override</em> whatever it got from its parent.</p>
|
||||
<p>Let’s expand <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/monsters.py</span></code> with another class:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="k">class</span> <span class="nc">Monster</span><span class="p">:</span>
|
||||
|
|
@ -411,7 +403,7 @@ the child adds something with the same name as its parent, it will <em>override<
|
|||
|
||||
<span class="k">class</span> <span class="nc">Dragon</span><span class="p">(</span><span class="n">Monster</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> This is a dragon-specific monster.</span>
|
||||
<span class="sd"> This is a dragon monster.</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">move_around</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
|
@ -425,15 +417,14 @@ the child adds something with the same name as its parent, it will <em>override<
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We added some docstrings for clarity. It’s always a good idea to add doc strings; you can do so also for methods,
|
||||
as exemplified for the new <code class="docutils literal notranslate"><span class="pre">firebreath</span></code> method.</p>
|
||||
<p>We added some docstrings for clarity. It’s always a good idea to add doc strings; you can do so also for methods, as exemplified for the new <code class="docutils literal notranslate"><span class="pre">firebreath</span></code> method.</p>
|
||||
<p>We created the new class <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> but we also specified that <code class="docutils literal notranslate"><span class="pre">Monster</span></code> is the <em>parent</em> of <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> but adding
|
||||
the parent in parenthesis. <code class="docutils literal notranslate"><span class="pre">class</span> <span class="pre">Classname(Parent)</span></code> is the way to do this.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Multi-inheritance</p>
|
||||
<p>It’s possible to add more comma-separated parents to a class. You should usually avoid this until you <code class="docutils literal notranslate"><span class="pre">really</span></code> know what you are doing. A single parent will be enough for almost every case you’ll need.</p>
|
||||
</aside>
|
||||
<p>Let’s try out our new class. First <code class="docutils literal notranslate"><span class="pre">reload</span></code> the server and the do</p>
|
||||
<p>Let’s try out our new class. First <code class="docutils literal notranslate"><span class="pre">reload</span></code> the server and then:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Dragon
|
||||
> smaug = Dragon("Smaug")
|
||||
|
|
@ -443,12 +434,8 @@ Smaug flies through the air high above!
|
|||
Smaug breathes fire!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Because we didn’t implement <code class="docutils literal notranslate"><span class="pre">__init__</span></code> in <code class="docutils literal notranslate"><span class="pre">Dragon</span></code>, we got the one from <code class="docutils literal notranslate"><span class="pre">Monster</span></code> instead. But since we
|
||||
implemented our own <code class="docutils literal notranslate"><span class="pre">move_around</span></code> in <code class="docutils literal notranslate"><span class="pre">Dragon</span></code>, it <em>overrides</em> the one in <code class="docutils literal notranslate"><span class="pre">Monster</span></code>. And <code class="docutils literal notranslate"><span class="pre">firebreath</span></code> is only
|
||||
available for <code class="docutils literal notranslate"><span class="pre">Dragon</span></code>s of course. Having that on <code class="docutils literal notranslate"><span class="pre">Monster</span></code> would not have made much sense, since not every monster
|
||||
can breathe fire.</p>
|
||||
<p>One can also force a class to use resources from the parent even if you are overriding some of it. This is done
|
||||
with the <code class="docutils literal notranslate"><span class="pre">super()</span></code> method. Modify your <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> class as follows:</p>
|
||||
<p>Because we didn’t (re)implement <code class="docutils literal notranslate"><span class="pre">__init__</span></code> in <code class="docutils literal notranslate"><span class="pre">Dragon</span></code>, we got the one from <code class="docutils literal notranslate"><span class="pre">Monster</span></code>. We did implement our own <code class="docutils literal notranslate"><span class="pre">move_around</span></code> in <code class="docutils literal notranslate"><span class="pre">Dragon</span></code>, so it <em>overrides</em> the one in <code class="docutils literal notranslate"><span class="pre">Monster</span></code>. And <code class="docutils literal notranslate"><span class="pre">firebreath</span></code> is only available for <code class="docutils literal notranslate"><span class="pre">Dragon</span></code>s. Having that on <code class="docutils literal notranslate"><span class="pre">Monster</span></code> would not have made much sense, since not every monster can breathe fire.</p>
|
||||
<p>One can also force a class to use resources from the parent even if you are overriding some of it. This is done with the <code class="docutils literal notranslate"><span class="pre">super()</span></code> method. Modify your <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> class as follows:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Dragon</span><span class="p">(</span><span class="n">Monster</span><span class="p">):</span>
|
||||
|
|
@ -461,11 +448,10 @@ with the <code class="docutils literal notranslate"><span class="pre">super()</s
|
|||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Keep <code class="docutils literal notranslate"><span class="pre">Monster</span></code> and the <code class="docutils literal notranslate"><span class="pre">firebreath</span></code> method, <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">...</span></code> indicates the rest of the code is untouched.</p>
|
||||
<div><p>Keep <code class="docutils literal notranslate"><span class="pre">Monster</span></code> and the <code class="docutils literal notranslate"><span class="pre">firebreath</span></code> method. The <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">...</span></code> above indicates the rest of the code is unchanged.</p>
|
||||
</div></blockquote>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">super().move_around()</span></code> line means that we are calling <code class="docutils literal notranslate"><span class="pre">move_around()</span></code> on the parent of the class. So in this
|
||||
case, we will call <code class="docutils literal notranslate"><span class="pre">Monster.move_around</span></code> first, before doing our own thing.</p>
|
||||
<p>Now <code class="docutils literal notranslate"><span class="pre">reload</span></code> the server and then:</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">super().move_around()</span></code> line means that we are calling <code class="docutils literal notranslate"><span class="pre">move_around()</span></code> on the parent of the class. So in this case, we will call <code class="docutils literal notranslate"><span class="pre">Monster.move_around</span></code> first, before doing our own thing.</p>
|
||||
<p>To see, <code class="docutils literal notranslate"><span class="pre">reload</span></code> the server and then:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Dragon
|
||||
> smaug = Dragon("Smaug")
|
||||
|
|
@ -474,19 +460,14 @@ Smaug is moving!
|
|||
The world trembles.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We can see that <code class="docutils literal notranslate"><span class="pre">Monster.move_around()</span></code> is calls first and prints “Smaug is moving!”, followed by the extra bit
|
||||
about the trembling world we added in the <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> class.</p>
|
||||
<p>Inheritance is very powerful because it allows you to organize and re-use code while only adding the special things
|
||||
you want to change. Evennia uses this concept a lot.</p>
|
||||
<p>We can see that <code class="docutils literal notranslate"><span class="pre">Monster.move_around()</span></code> is called first and prints “Smaug is moving!”, followed by the extra bit about the trembling world from the <code class="docutils literal notranslate"><span class="pre">Dragon</span></code> class.</p>
|
||||
<p>Inheritance is a powerful concept. It allows you to organize and re-use code while only adding the special things you want to change. Evennia uses this a lot.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="summary">
|
||||
<h2><span class="section-number">5.3. </span>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We have created our first dragons from classes. We have learned a little about how you <em>instantiate</em> a class
|
||||
into an <em>object</em>. We have seen some examples of <em>inheritance</em> and we tested to <em>override</em> a method in the parent
|
||||
with one in the child class. We also used <code class="docutils literal notranslate"><span class="pre">super()</span></code> to good effect.</p>
|
||||
<p>We have used pretty much raw Python so far. In the coming lessons we’ll start to look at the extra bits that Evennia
|
||||
provides. But first we need to learn just where to find everything.</p>
|
||||
<p>We have created our first dragons from classes. We have learned a little about how you <em>instantiate</em> a class into an <em>object</em>. We have seen some examples of <em>inheritance</em> and we tested to <em>override</em> a method in the parent with one in the child class. We also used <code class="docutils literal notranslate"><span class="pre">super()</span></code> to good effect.</p>
|
||||
<p>We have used pretty much raw Python so far. In the coming lessons we’ll start to look at the extra bits that Evennia provides. But first we need to learn just where to find everything.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,8 @@ Both if you are triumphant or if you use the <code class="docutils literal notra
|
|||
</div>
|
||||
<section id="gameplay">
|
||||
<h2><span class="section-number">2.1. </span>Gameplay<a class="headerlink" href="#gameplay" title="Permalink to this headline">¶</a></h2>
|
||||
<p><img alt="the castle off the moor" src="https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/22916c25-6299-453d-a221-446ec839f567/da2pmzu-46d63c6d-9cdc-41dd-87d6-1106db5a5e1a.jpg/v1/fill/w_600,h_849,q_75,strp/the_castle_off_the_moor_by_griatch_art_da2pmzu-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD04NDkiLCJwYXRoIjoiXC9mXC8yMjkxNmMyNS02Mjk5LTQ1M2QtYTIyMS00NDZlYzgzOWY1NjdcL2RhMnBtenUtNDZkNjNjNmQtOWNkYy00MWRkLTg3ZDYtMTEwNmRiNWE1ZTFhLmpwZyIsIndpZHRoIjoiPD02MDAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.omuS3D1RmFiZCy9OSXiIita-HxVGrBok3_7asq0rflw" /></p>
|
||||
<p><img alt="the castle off the moor" src="https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/22916c25-6299-453d-a221-446ec839f567/da2pmzu-46d63c6d-9cdc-41dd-87d6-1106db5a5e1a.jpg/v1/fill/w_600,h_849,q_75,strp/the_castle_off_the_moor_by_griatch_art_da2pmzu-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD04NDkiLCJwYXRoIjoiXC9mXC8yMjkxNmMyNS02Mjk5LTQ1M2QtYTIyMS00NDZlYzgzOWY1NjdcL2RhMnBtenUtNDZkNjNjNmQtOWNkYy00MWRkLTg3ZDYtMTEwNmRiNWE1ZTFhLmpwZyIsIndpZHRoIjoiPD02MDAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.omuS3D1RmFiZCy9OSXiIita-HxVGrBok3_7asq0rflw" />
|
||||
(image by Griatch)</p>
|
||||
<p><em>To get into the mood of this miniature quest, imagine you are an adventurer out to find fame and
|
||||
fortune. You have heard rumours of an old castle ruin by the coast. In its depth a warrior princess
|
||||
was buried together with her powerful magical weapon - a valuable prize, if it’s true. Of course
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue