mirror of
https://github.com/evennia/evennia.git
synced 2026-03-30 20:47:17 +02:00
parent
51d5840b8b
commit
e34f258a92
2504 changed files with 820160 additions and 0 deletions
|
|
@ -0,0 +1,536 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>8. Adding custom commands — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="9. Parsing Command input" href="Beginner-Tutorial-More-on-Commands.html" />
|
||||
<link rel="prev" title="7. Making objects persistent" href="Beginner-Tutorial-Learning-Typeclasses.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">8. </span>Adding custom commands</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">8. Adding custom commands</a><ul>
|
||||
<li><a class="reference internal" href="#creating-a-custom-command">8.1. Creating a custom command</a><ul>
|
||||
<li><a class="reference internal" href="#making-our-cmdset-persistent">8.1.1. Making our cmdset persistent</a></li>
|
||||
<li><a class="reference internal" href="#figuring-out-who-to-hit">8.1.2. Figuring out who to hit</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#summary">8.2. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Learning-Typeclasses.html"
|
||||
title="previous chapter"><span class="section-number">7. </span>Making objects persistent</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-More-on-Commands.html"
|
||||
title="next chapter"><span class="section-number">9. </span>Parsing Command input</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Adding-Commands.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="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>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
|
||||
what is in it.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Commands are not typeclassed</p>
|
||||
<p>If you just came from the previous lesson, you might want to know that Commands and
|
||||
CommandSets are not <code class="docutils literal notranslate"><span class="pre">typeclassed</span></code>. That is, instances of them are not saved to the
|
||||
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>
|
||||
<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>
|
||||
<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">Command</span> <span class="k">as</span> <span class="n">BaseCommand</span>
|
||||
<span class="c1"># from evennia import default_cmds</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Command</span><span class="p">(</span><span class="n">BaseCommand</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="c1"># (lots of commented-out stuff)</span>
|
||||
<span class="c1"># ...</span>
|
||||
</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>
|
||||
<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></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>
|
||||
<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>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"echo"</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is the simplest form of command you can imagine. It just gives itself a name, “echo”. This is
|
||||
what you will use to call this command later.</p>
|
||||
<p>Next we need to put this in a CmdSet. It will be a one-command CmdSet for now! Change your file as such:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="kn">from</span> <span class="nn">commands.command</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">CmdSet</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CmdEcho</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"echo"</span>
|
||||
|
||||
|
||||
<span class="k">class</span> <span class="nc">MyCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdEcho</span><span class="p">)</span>
|
||||
|
||||
</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>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")
|
||||
</pre></div>
|
||||
</div>
|
||||
<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:
|
||||
...
|
||||
...
|
||||
</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>
|
||||
<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()
|
||||
caller (<class 'typeclasses.characters.Character'>): YourName
|
||||
cmdname (<class 'str'>): echo
|
||||
raw_cmdname (<class 'str'>): echo
|
||||
cmdstring (<class 'str'>): echo
|
||||
args (<class 'str'>):
|
||||
cmdset (<class 'evennia.commands.cmdset.CmdSet'>): @mail, about, access, accounts, addcom, alias, allcom, ban, batchcode, batchcommands, boot, cboot, ccreate,
|
||||
cdesc, cdestroy, cemit, channels, charcreate, chardelete, checklockstring, clientwidth, clock, cmdbare, cmdsets, color, copy, cpattr, create, cwho, delcom,
|
||||
desc, destroy, dig, dolphin, drop, echo, emit, examine, find, force, get, give, grapevine2chan, help, home, ic, inventory, irc2chan, ircstatus, link, lock,
|
||||
look, menutest, mudinfo, mvattr, name, nick, objects, ooc, open, option, page, password, perm, pose, public, py, quell, quit, reload, reset, rss2chan, say,
|
||||
script, scripts, server, service, sessions, set, setdesc, sethelp, sethome, shutdown, spawn, style, tag, tel, test2010, test2028, testrename, testtable,
|
||||
tickers, time, tunnel, typeclass, unban, unlink, up, up, userpassword, wall, whisper, who, wipe
|
||||
session (<class 'evennia.server.serversession.ServerSession'>): Griatch(#1)@1:2:7:.:0:.:0:.:1
|
||||
account (<class 'typeclasses.accounts.Account'>): Griatch(account 1)
|
||||
raw_string (<class 'str'>): echo
|
||||
|
||||
--------------------------------------------------
|
||||
echo - Command variables from evennia:
|
||||
--------------------------------------------------
|
||||
name of cmd (self.key): echo
|
||||
cmd aliases (self.aliases): []
|
||||
cmd locks (self.locks): cmd:all();
|
||||
help category (self.help_category): General
|
||||
object calling (self.caller): Griatch
|
||||
object storing cmdset (self.obj): Griatch
|
||||
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>
|
||||
<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">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>
|
||||
<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>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> A simple echo command</span>
|
||||
|
||||
<span class="sd"> Usage:</span>
|
||||
<span class="sd"> echo <something></span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"echo"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Echo: '</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
|
||||
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
||||
> echo
|
||||
Echo: ''
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Try to pass an argument:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> echo Woo Tang!
|
||||
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>
|
||||
<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>
|
||||
<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>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> A simple echo command</span>
|
||||
|
||||
<span class="sd"> Usage:</span>
|
||||
<span class="sd"> echo <something></span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"echo"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Echo: '</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
|
||||
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
||||
> echo Woo Tang!
|
||||
Echo: 'Woo Tang!'
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Don’t forget to look at the help for the echo command:</p>
|
||||
<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>
|
||||
<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
|
||||
enough to make <code class="docutils literal notranslate"><span class="pre">echo</span></code> a <em>persistent</em> change though:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.cmdset.add("commands.mycommands.MyCmdSet", persistent=True)
|
||||
</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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.cmdset.remove("commands.mycommands.MyCmdSet")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>But for now, keep it around, we’ll expand it with some more examples.</p>
|
||||
</section>
|
||||
<section id="figuring-out-who-to-hit">
|
||||
<h3><span class="section-number">8.1.2. </span>Figuring out who to hit<a class="headerlink" href="#figuring-out-who-to-hit" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Let’s try something a little more exciting than just echo. Let’s make a <code class="docutils literal notranslate"><span class="pre">hit</span></code> command, for punching
|
||||
someone in the face! This is how we want it to work:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> hit <target>
|
||||
You hit <target> with full force!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Not only that, we want the <target> 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>
|
||||
<p>Here, <code class="docutils literal notranslate"><span class="pre"><hitter></span></code> would be the one using the <code class="docutils literal notranslate"><span class="pre">hit</span></code> command and <code class="docutils literal notranslate"><span class="pre"><target></span></code> is the one doing the punching.</p>
|
||||
<p>Still in <code class="docutils literal notranslate"><span class="pre">mygame/commands/mycommands.py</span></code>, add a new class, between <code class="docutils literal notranslate"><span class="pre">CmdEcho</span></code> and <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
|
||||
<span class="normal"> 2</span>
|
||||
<span class="normal"> 3</span>
|
||||
<span class="normal"> 4</span>
|
||||
<span class="normal"> 5</span>
|
||||
<span class="normal"> 6</span>
|
||||
<span class="normal"> 7</span>
|
||||
<span class="normal"> 8</span>
|
||||
<span class="normal"> 9</span>
|
||||
<span class="normal">10</span>
|
||||
<span class="normal">11</span>
|
||||
<span class="normal">12</span>
|
||||
<span class="normal">13</span>
|
||||
<span class="normal">14</span>
|
||||
<span class="normal">15</span>
|
||||
<span class="normal">16</span>
|
||||
<span class="normal">17</span>
|
||||
<span class="normal">18</span>
|
||||
<span class="normal">19</span>
|
||||
<span class="normal">20</span>
|
||||
<span class="normal">21</span>
|
||||
<span class="normal">22</span>
|
||||
<span class="normal">23</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CmdHit</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Hit a target.</span>
|
||||
|
||||
<span class="sd"> Usage:</span>
|
||||
<span class="sd"> hit <target></span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"hit"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">args</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Who do you want to hit?"</span><span class="p">)</span>
|
||||
<span class="k">return</span>
|
||||
<span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You hit </span><span class="si">{</span><span class="n">target</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> with full force!"</span><span class="p">)</span>
|
||||
<span class="n">target</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You got hit by </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> with full force!"</span><span class="p">)</span>
|
||||
<span class="c1"># ...</span>
|
||||
</pre></div></td></tr></table></div>
|
||||
</div>
|
||||
<p>A lot of things to dissect here:</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Line 3</strong>: The normal <code class="docutils literal notranslate"><span class="pre">class</span></code> header. We inherit from <code class="docutils literal notranslate"><span class="pre">Command</span></code> which we imported at the top of this file.</p></li>
|
||||
<li><p><strong>Lines 4-10</strong>: The docstring and help-entry for the command. You could expand on this as much as you wanted.</p></li>
|
||||
<li><p><strong>Line 11</strong>: We want to write <code class="docutils literal notranslate"><span class="pre">hit</span></code> to use this command.</p></li>
|
||||
<li><p><strong>Line 14</strong>: We strip the whitespace from the argument like before. Since we don’t want to have to do
|
||||
<code class="docutils literal notranslate"><span class="pre">self.args.strip()</span></code> over and over, we store the stripped version
|
||||
in a <em>local variable</em> <code class="docutils literal notranslate"><span class="pre">args</span></code>. Note that we don’t modify <code class="docutils literal notranslate"><span class="pre">self.args</span></code> by doing this, <code class="docutils literal notranslate"><span class="pre">self.args</span></code> will still
|
||||
have the whitespace and is not the same as <code class="docutils literal notranslate"><span class="pre">args</span></code> in this example.</p></li>
|
||||
</ul>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">if-statements</p>
|
||||
<p>The full form of the if statement is</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>if condition:
|
||||
...
|
||||
elif othercondition:
|
||||
...
|
||||
else:
|
||||
...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>There can be any number of <code class="docutils literal notranslate"><span class="pre">elifs</span></code> to mark when different branches of the code should run. If
|
||||
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><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>
|
||||
<li><p>The empty string <code class="docutils literal notranslate"><span class="pre">""</span></code> or <code class="docutils literal notranslate"><span class="pre">''</span></code> or <code class="docutils literal notranslate"><span class="pre">""""""</span></code> or <code class="docutils literal notranslate"><span class="pre">''''''</span></code></p></li>
|
||||
<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>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 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>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">MyCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdEcho</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdHit</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Errors in your code</p>
|
||||
<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>
|
||||
</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
|
||||
hit
|
||||
Who do you want to hit?
|
||||
hit me
|
||||
You hit YourName with full force!
|
||||
You got hit by YourName with full force!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Lacking a target, we hit ourselves. If you have one of the dragons still around from the previous lesson
|
||||
you could try to hit it (if you dare):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>hit smaug
|
||||
You hit Smaug with full force!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You won’t see the second string. Only Smaug sees that (and is not amused).</p>
|
||||
</section>
|
||||
</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 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>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">8. </span>Adding custom commands</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>1. Using commands and building stuff — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="2. The Tutorial World" href="Beginner-Tutorial-Tutorial-World.html" />
|
||||
<link rel="prev" title="Part 1: What we have" href="Beginner-Tutorial-Part1-Intro.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Part1-Intro.html" title="Part 1: What we have"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">1. </span>Using commands and building stuff</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">1. Using commands and building stuff</a><ul>
|
||||
<li><a class="reference internal" href="#getting-help">1.1. Getting help</a></li>
|
||||
<li><a class="reference internal" href="#looking-around">1.2. Looking around</a></li>
|
||||
<li><a class="reference internal" href="#stepping-down-from-godhood">1.3. Stepping Down From Godhood</a></li>
|
||||
<li><a class="reference internal" href="#creating-an-object">1.4. Creating an Object</a></li>
|
||||
<li><a class="reference internal" href="#get-a-personality">1.5. Get a Personality</a></li>
|
||||
<li><a class="reference internal" href="#pushing-your-buttons">1.6. Pushing Your Buttons</a></li>
|
||||
<li><a class="reference internal" href="#making-yourself-a-house">1.7. Making Yourself a House</a></li>
|
||||
<li><a class="reference internal" href="#reshuffling-the-world">1.8. Reshuffling the World</a></li>
|
||||
<li><a class="reference internal" href="#adding-a-help-entry">1.9. Adding a Help Entry</a></li>
|
||||
<li><a class="reference internal" href="#adding-a-world">1.10. Adding a World</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Part1-Intro.html"
|
||||
title="previous chapter">Part 1: What we have</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Tutorial-World.html"
|
||||
title="next chapter"><span class="section-number">2. </span>The Tutorial World</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Building-Quickstart.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Building-Quickstart.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="using-commands-and-building-stuff">
|
||||
<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>
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> command[/switch/switch...] [arguments ...]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>An example would be</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> create/drop box
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A <em>/switch</em> is a special, optional flag to the command to make it behave differently. It is always
|
||||
put directly after the command name, and begins with a forward slash (<code class="docutils literal notranslate"><span class="pre">/</span></code>). The <em>arguments</em> are one
|
||||
or more inputs to the commands. It’s common to use an equal sign (<code class="docutils literal notranslate"><span class="pre">=</span></code>) when assigning something to
|
||||
an object.</p>
|
||||
<blockquote>
|
||||
<div><p>Are you used to commands starting with @, like @create? That will work too. Evennia simply ignores
|
||||
the preceeding @.</p>
|
||||
</div></blockquote>
|
||||
<section id="getting-help">
|
||||
<h2><span class="section-number">1.1. </span>Getting help<a class="headerlink" href="#getting-help" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>help
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Will give you a list of all commands available to you. Use</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>help <commandname>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>to see the in-game help for that command.</p>
|
||||
</section>
|
||||
<section id="looking-around">
|
||||
<h2><span class="section-number">1.2. </span>Looking around<a class="headerlink" href="#looking-around" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The most common comman is</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>look
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will show you the description of the current location. <code class="docutils literal notranslate"><span class="pre">l</span></code> is an alias.</p>
|
||||
<p>When targeting objects in commands you have two special labels you can use, <code class="docutils literal notranslate"><span class="pre">here</span></code> for the current
|
||||
room or <code class="docutils literal notranslate"><span class="pre">me</span></code>/<code class="docutils literal notranslate"><span class="pre">self</span></code> to point back to yourself. So</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>look me
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>will give you your own description. <code class="docutils literal notranslate"><span class="pre">look</span> <span class="pre">here</span></code> is, in this case, the same as plain <code class="docutils literal notranslate"><span class="pre">look</span></code>.</p>
|
||||
</section>
|
||||
<section id="stepping-down-from-godhood">
|
||||
<h2><span class="section-number">1.3. </span>Stepping Down From Godhood<a class="headerlink" href="#stepping-down-from-godhood" title="Permalink to this headline">¶</a></h2>
|
||||
<p>If you just installed Evennia, your very first player account is called user #1, also known as the
|
||||
<em>superuser</em> or <em>god user</em>. This user is very powerful, so powerful that it will override many game
|
||||
restrictions such as locks. This can be useful, but it also hides some functionality that you might
|
||||
want to test.</p>
|
||||
<p>To temporarily step down from your superuser position you can use the <code class="docutils literal notranslate"><span class="pre">quell</span></code> command in-game:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>quell
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will make you start using the permission of your current character’s level instead of your
|
||||
superuser level. If you didn’t change any settings your game Character should have an <em>Developer</em>
|
||||
level permission - high as can be without bypassing locks like the superuser does. This will work
|
||||
fine for the examples on this page. Use</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>unquell
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>to get superuser status again when you are done.</p>
|
||||
</section>
|
||||
<section id="creating-an-object">
|
||||
<h2><span class="section-number">1.4. </span>Creating an Object<a class="headerlink" href="#creating-an-object" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Basic objects can be anything – swords, flowers and non-player characters. They are created using
|
||||
the <code class="docutils literal notranslate"><span class="pre">create</span></code> command:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>create box
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This created a new ‘box’ (of the default object type) in your inventory. Use the command <code class="docutils literal notranslate"><span class="pre">inventory</span></code>
|
||||
(or <code class="docutils literal notranslate"><span class="pre">i</span></code>) to see it. Now, ‘box’ is a rather short name, let’s rename it and tack on a few aliases.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>name box = very large box;box;very;crate
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>MUD clients and semi-colon
|
||||
Some traditional MUD clients use the semi-colon <code class="docutils literal notranslate"><span class="pre">;</span></code> to separate client inputs. If so,
|
||||
the above line will give an error. You need to change your client to use another command-separator
|
||||
or to put it in ‘verbatim’ mode. If you still have trouble, use the Evennia web client instead.</p>
|
||||
</div>
|
||||
<p>We now renamed the box to <em>very large box</em> (and this is what we will see when looking at it), but we
|
||||
will also recognize it by any of the other names we give - like <em>crate</em> or simply <em>box</em> as before.
|
||||
We could have given these aliases directly after the name in the <code class="docutils literal notranslate"><span class="pre">create</span></code> command, this is true for
|
||||
all creation commands - you can always tag on a list of <code class="docutils literal notranslate"><span class="pre">;</span></code>-separated aliases to the name of your
|
||||
new object. If you had wanted to not change the name itself, but to only add aliases, you could have
|
||||
used the <code class="docutils literal notranslate"><span class="pre">alias</span></code> command.</p>
|
||||
<p>We are currently carrying the box. Let’s drop it (there is also a short cut to create and drop in
|
||||
one go by using the <code class="docutils literal notranslate"><span class="pre">/drop</span></code> switch, for example <code class="docutils literal notranslate"><span class="pre">create/drop</span> <span class="pre">box</span></code>).</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>drop box
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Hey presto - there it is on the ground, in all its normality.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine box
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will show some technical details about the box object. For now we will ignore what this
|
||||
information means.</p>
|
||||
<p>Try to <code class="docutils literal notranslate"><span class="pre">look</span></code> at the box to see the (default) description.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>look box
|
||||
You see nothing special.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The description you get is not very exciting. Let’s add some flavor.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>desc box = This is a large and very heavy box.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you try the <code class="docutils literal notranslate"><span class="pre">get</span></code> command we will pick up the box. So far so good, but if we really want this to
|
||||
be a large and heavy box, people should <em>not</em> be able to run off with it that easily. To prevent
|
||||
this we need to lock it down. This is done by assigning a <em>Lock</em> to it. Make sure the box was
|
||||
dropped in the room, then try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>lock box = get:false()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Locks represent a rather <a class="reference internal" href="../../../Components/Locks.html"><span class="doc std std-doc">big topic</span></a>, but for now that will do what we want. This will lock
|
||||
the box so noone can lift it. The exception is superusers, they override all locks and will pick it
|
||||
up anyway. Make sure you are quelling your superuser powers and try to get the box now:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> get box
|
||||
You can't get that.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Think thís default error message looks dull? The <code class="docutils literal notranslate"><span class="pre">get</span></code> command looks for an <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a>
|
||||
named <code class="docutils literal notranslate"><span class="pre">get_err_msg</span></code> for returning a nicer error message (we just happen to know this, you would need
|
||||
to peek into the
|
||||
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/commands/default/general.py#L235">code</a> for
|
||||
the <code class="docutils literal notranslate"><span class="pre">get</span></code> command to find out.). You set attributes using the <code class="docutils literal notranslate"><span class="pre">set</span></code> command:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set box/get_err_msg = It's way too heavy for you to lift.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Try to get it now and you should see a nicer error message echoed back to you. To see what this
|
||||
message string is in the future, you can use ‘examine.’</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine box/get_err_msg
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Examine will return the value of attributes, including color codes. <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">here/desc</span></code> would return
|
||||
the raw description of your current room (including color codes), so that you can copy-and-paste to
|
||||
set its description to something else.</p>
|
||||
<p>You create new Commands (or modify existing ones) in Python outside the game. We will get to that
|
||||
later, in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Commands tutorial</span></a>.</p>
|
||||
</section>
|
||||
<section id="get-a-personality">
|
||||
<h2><span class="section-number">1.5. </span>Get a Personality<a class="headerlink" href="#get-a-personality" title="Permalink to this headline">¶</a></h2>
|
||||
<p><a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Scripts</span></a> are powerful out-of-character objects useful for many “under the hood” things.
|
||||
One of their optional abilities is to do things on a timer. To try out a first script, let’s put one
|
||||
on ourselves. There is an example script in <code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorials/bodyfunctions/bodyfunctions.py</span></code>
|
||||
that is called <code class="docutils literal notranslate"><span class="pre">BodyFunctions</span></code>. To add this to us we will use the <code class="docutils literal notranslate"><span class="pre">script</span></code> command:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>script self = tutorials.bodyfunctions.BodyFunctions
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This string will tell Evennia to dig up the Python code at the place we indicate. It already knows
|
||||
to look in the <code class="docutils literal notranslate"><span class="pre">contrib/</span></code> folder, so we don’t have to give the full path.</p>
|
||||
<blockquote>
|
||||
<div><p>Note also how we use <code class="docutils literal notranslate"><span class="pre">.</span></code> instead of <code class="docutils literal notranslate"><span class="pre">/</span></code> (or <code class="docutils literal notranslate"><span class="pre">\</span></code> on Windows). This is a so-called “Python path”. In a Python-path,
|
||||
you separate the parts of the path with <code class="docutils literal notranslate"><span class="pre">.</span></code> and skip the <code class="docutils literal notranslate"><span class="pre">.py</span></code> file-ending. Importantly, it also allows you to point to
|
||||
Python code <em>inside</em> files, like the <code class="docutils literal notranslate"><span class="pre">BodyFunctions</span></code> class inside <code class="docutils literal notranslate"><span class="pre">bodyfunctions.py</span></code> (we’ll get to classes later).
|
||||
These “Python-paths” are used extensively throughout Evennia.</p>
|
||||
</div></blockquote>
|
||||
<p>Wait a while and you will notice yourself starting making random observations …</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>script self
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will show details about scripts on yourself (also <code class="docutils literal notranslate"><span class="pre">examine</span></code> works). You will see how long it is
|
||||
until it “fires” next. Don’t be alarmed if nothing happens when the countdown reaches zero - this
|
||||
particular script has a randomizer to determine if it will say something or not. So you will not see
|
||||
output every time it fires.</p>
|
||||
<p>When you are tired of your character’s “insights”, kill the script with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>script/stop self = tutorials.bodyfunctions.BodyFunctions
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You create your own scripts in Python, outside the game; the path you give to <code class="docutils literal notranslate"><span class="pre">script</span></code> is literally
|
||||
the Python path to your script file. The <a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Scripts</span></a> page explains more details.</p>
|
||||
</section>
|
||||
<section id="pushing-your-buttons">
|
||||
<h2><span class="section-number">1.6. </span>Pushing Your Buttons<a class="headerlink" href="#pushing-your-buttons" title="Permalink to this headline">¶</a></h2>
|
||||
<p>If we get back to the box we made, there is only so much fun you can have with it at this point. It’s
|
||||
just a dumb generic object. If you renamed it to <code class="docutils literal notranslate"><span class="pre">stone</span></code> and changed its description, noone would be
|
||||
the wiser. However, with the combined use of custom <a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a>, <a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Scripts</span></a>
|
||||
and object-based <a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc">Commands</span></a>, you could expand it and other items to be as unique, complex
|
||||
and interactive as you want.</p>
|
||||
<p>Let’s take an example. So far we have only created objects that use the default object typeclass
|
||||
named simply <code class="docutils literal notranslate"><span class="pre">Object</span></code>. Let’s create an object that is a little more interesting. Under
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples</span></code> there is a module <code class="docutils literal notranslate"><span class="pre">red_button.py</span></code>. It contains the enigmatic
|
||||
<code class="docutils literal notranslate"><span class="pre">RedButton</span></code> class.</p>
|
||||
<p>Let’s make us one of <em>those</em>!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>create/drop button:tutorials.red_button.RedButton
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The same way we did with the Script Earler, we specify a “Python-path” to the Python code we want Evennia
|
||||
to use for creating the object. There you go - one red button.</p>
|
||||
<p>The RedButton is an example object intended to show off a few of Evennia’s features. You will find
|
||||
that the <a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a> and <a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc">Commands</span></a> controlling it are
|
||||
inside <a class="reference internal" href="../../../api/evennia.contrib.tutorials.red_button.html"><span class="doc std std-doc">evennia/contrib/tutorials/red_button</span></a></p>
|
||||
<p>If you wait for a while (make sure you dropped it!) the button will blink invitingly.</p>
|
||||
<p>Why don’t you try to push it …?</p>
|
||||
<p>Surely a big red button is meant to be pushed.</p>
|
||||
<p>You know you want to.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>Don’t press the invitingly blinking red button.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="making-yourself-a-house">
|
||||
<h2><span class="section-number">1.7. </span>Making Yourself a House<a class="headerlink" href="#making-yourself-a-house" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The main command for shaping the game world is <code class="docutils literal notranslate"><span class="pre">dig</span></code>. For example, if you are standing in Limbo you
|
||||
can dig a route to your new house location like this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>dig house = large red door;door;in,to the outside;out
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will create a new room named ‘house’. Spaces at the start/end of names and aliases are ignored
|
||||
so you could put more air if you wanted. This call will directly create an exit from your current
|
||||
location named ‘large red door’ and a corresponding exit named ‘to the outside’ in the house room
|
||||
leading back to Limbo. We also define a few aliases to those exits, so people don’t have to write
|
||||
the full thing all the time.</p>
|
||||
<p>If you wanted to use normal compass directions (north, west, southwest etc), you could do that with
|
||||
<code class="docutils literal notranslate"><span class="pre">dig</span></code> too. But Evennia also has a limited version of <code class="docutils literal notranslate"><span class="pre">dig</span></code> that helps for compass directions (and
|
||||
also up/down and in/out). It’s called <code class="docutils literal notranslate"><span class="pre">tunnel</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>tunnel sw = cliff
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will create a new room “cliff” with an exit “southwest” leading there and a path “northeast”
|
||||
leading back from the cliff to your current location.</p>
|
||||
<p>You can create new exits from where you are, using the <code class="docutils literal notranslate"><span class="pre">open</span></code> command:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>open north;n = house
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This opens an exit <code class="docutils literal notranslate"><span class="pre">north</span></code> (with an alias <code class="docutils literal notranslate"><span class="pre">n</span></code>) to the previously created room <code class="docutils literal notranslate"><span class="pre">house</span></code>.</p>
|
||||
<p>If you have many rooms named <code class="docutils literal notranslate"><span class="pre">house</span></code> you will get a list of matches and have to select which one you
|
||||
want to link to.</p>
|
||||
<p>Follow the north exit to your ‘house’ or <code class="docutils literal notranslate"><span class="pre">teleport</span></code> to it:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>north
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>or:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>teleport house
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To manually open an exit back to Limbo (if you didn’t do so with the <code class="docutils literal notranslate"><span class="pre">dig</span></code> command):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>open door = limbo
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>(You can also us the #dbref of limbo, which you can find by using <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">here</span></code> when in limbo).</p>
|
||||
</section>
|
||||
<section id="reshuffling-the-world">
|
||||
<h2><span class="section-number">1.8. </span>Reshuffling the World<a class="headerlink" href="#reshuffling-the-world" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You can find things using the <code class="docutils literal notranslate"><span class="pre">find</span></code> command. Assuming you are back at <code class="docutils literal notranslate"><span class="pre">Limbo</span></code>, let’s teleport the
|
||||
<em>large box</em> to our house.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>teleport box = house
|
||||
very large box is leaving Limbo, heading for house.
|
||||
Teleported very large box -> house.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We can still find the box by using find:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>find box
|
||||
One Match(#1-#8):
|
||||
very large box(#8) - src.objects.objects.Object
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Knowing the <code class="docutils literal notranslate"><span class="pre">#dbref</span></code> of the box (#8 in this example), you can grab the box and get it back here
|
||||
without actually yourself going to <code class="docutils literal notranslate"><span class="pre">house</span></code> first:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>teleport #8 = here
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As mentioned, <code class="docutils literal notranslate"><span class="pre">here</span></code> is an alias for ‘your current location’. The box should now be back in Limbo with you.</p>
|
||||
<p>We are getting tired of the box. Let’s destroy it.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>destroy box
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It will ask you for confirmation. Once you give it, the box will be gone.</p>
|
||||
<p>You can destroy many objects in one go by giving a comma-separated list of objects (or a range
|
||||
of #dbrefs, if they are not in the same location) to the command.</p>
|
||||
</section>
|
||||
<section id="adding-a-help-entry">
|
||||
<h2><span class="section-number">1.9. </span>Adding a Help Entry<a class="headerlink" href="#adding-a-help-entry" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The Command-help is something you modify in Python code. We’ll get to that when we get to how to
|
||||
add Commands. But you can also add regular help entries, for example to explain something about
|
||||
the history of your game world:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>sethelp History = At the dawn of time ...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You will now find your new <code class="docutils literal notranslate"><span class="pre">History</span></code> entry in the <code class="docutils literal notranslate"><span class="pre">help</span></code> list and read your help-text with <code class="docutils literal notranslate"><span class="pre">help</span> <span class="pre">History</span></code>.</p>
|
||||
</section>
|
||||
<section id="adding-a-world">
|
||||
<h2><span class="section-number">1.10. </span>Adding a World<a class="headerlink" href="#adding-a-world" title="Permalink to this headline">¶</a></h2>
|
||||
<p>After this brief introduction to building and using in-game commands you may be ready to see a more fleshed-out
|
||||
example. Evennia comes with a tutorial world for you to explore. We will try that out in the next lesson.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Part1-Intro.html" title="Part 1: What we have"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">1. </span>Using commands and building stuff</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>10. Creating things — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="11. Searching for things" href="Beginner-Tutorial-Searching-Things.html" />
|
||||
<link rel="prev" title="9. Parsing Command input" href="Beginner-Tutorial-More-on-Commands.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">10. </span>Creating things</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">10. Creating things</a><ul>
|
||||
<li><a class="reference internal" href="#creating-objects">10.1. Creating Objects</a></li>
|
||||
<li><a class="reference internal" href="#creating-accounts">10.2. Creating Accounts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-More-on-Commands.html"
|
||||
title="previous chapter"><span class="section-number">9. </span>Parsing Command input</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Searching-Things.html"
|
||||
title="next chapter"><span class="section-number">11. </span>Searching for things</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Creating-Things.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Creating-Things.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="creating-things">
|
||||
<h1><span class="section-number">10. </span>Creating things<a class="headerlink" href="#creating-things" title="Permalink to this headline">¶</a></h1>
|
||||
<p>We have already created some things - dragons for example. There are many different things to create
|
||||
in Evennia though. In the last lesson we learned about typeclasses, the way to make objects persistent in the database.</p>
|
||||
<p>Given the path to a Typeclass, there are three ways to create an instance of it:</p>
|
||||
<ul>
|
||||
<li><p>Firstly, you can call the class directly, and then <code class="docutils literal notranslate"><span class="pre">.save()</span></code> it:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> obj = SomeTypeClass(db_key=...)
|
||||
obj.save()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This has the drawback of being two operations; you must also import the class and have to pass
|
||||
the actual database field names, such as <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> as keyword arguments.</p>
|
||||
</li>
|
||||
<li><p>Secondly you can use the Evennia creation helpers:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> obj = evennia.create_object(SomeTypeClass, key=...)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is the recommended way if you are trying to create things in Python. The first argument can either be
|
||||
the class <em>or</em> the python-path to the typeclass, like <code class="docutils literal notranslate"><span class="pre">"path.to.SomeTypeClass"</span></code>. It can also be <code class="docutils literal notranslate"><span class="pre">None</span></code> in which
|
||||
case the Evennia default will be used. While all the creation methods
|
||||
are available on <code class="docutils literal notranslate"><span class="pre">evennia</span></code>, they are actually implemented in <a class="reference internal" href="../../../api/evennia.utils.create.html"><span class="doc std std-doc">evennia/utils/create.py</span></a>.</p>
|
||||
</li>
|
||||
<li><p>Finally, you can create objects using an in-game command, such as</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> create/drop obj:path.to.SomeTypeClass
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As a developer you are usually best off using the two other methods, but a command is usually the only way
|
||||
to let regular players or builders without Python-access help build the game world.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<section id="creating-objects">
|
||||
<h2><span class="section-number">10.1. </span>Creating Objects<a class="headerlink" href="#creating-objects" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This is one of the most common creation-types. These are entities that inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> at any distance.
|
||||
They have an existence in the game world and includes rooms, characters, exits, weapons, flower pots and castles.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> import evennia
|
||||
> rose = evennia.create_object(key="rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Since we didn’t specify the <code class="docutils literal notranslate"><span class="pre">typeclass</span></code> as the first argument, the default given by <code class="docutils literal notranslate"><span class="pre">settings.BASE_OBJECT_TYPECLASS</span></code>
|
||||
(<code class="docutils literal notranslate"><span class="pre">typeclasses.objects.Object</span></code>) will be used.</p>
|
||||
</section>
|
||||
<section id="creating-accounts">
|
||||
<h2><span class="section-number">10.2. </span>Creating Accounts<a class="headerlink" href="#creating-accounts" title="Permalink to this headline">¶</a></h2>
|
||||
<p>An <em>Account</em> is an out-of-character (OOC) entity, with no existence in the game world.
|
||||
You can find the parent class for Accounts in <code class="docutils literal notranslate"><span class="pre">typeclasses/accounts.py</span></code>.</p>
|
||||
<p><em>TODO</em></p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">10. </span>Creating things</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,549 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>12. Advanced searching - Django Database queries — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="Part 2: What we want" href="../Part2/Beginner-Tutorial-Part2-Intro.html" />
|
||||
<link rel="prev" title="11. Searching for things" href="Beginner-Tutorial-Searching-Things.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Part2/Beginner-Tutorial-Part2-Intro.html" title="Part 2: What we want"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">12. </span>Advanced searching - Django Database queries</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">12. Advanced searching - Django Database queries</a><ul>
|
||||
<li><a class="reference internal" href="#queryset-field-lookups">12.1. Queryset field lookups</a></li>
|
||||
<li><a class="reference internal" href="#get-that-werewolf">12.2. Get that werewolf …</a></li>
|
||||
<li><a class="reference internal" href="#complex-queries">12.3. Complex queries</a></li>
|
||||
<li><a class="reference internal" href="#annotations">12.4. Annotations</a></li>
|
||||
<li><a class="reference internal" href="#f-objects">12.5. F-objects</a></li>
|
||||
<li><a class="reference internal" href="#grouping-and-returning-only-certain-properties">12.6. Grouping and returning only certain properties</a></li>
|
||||
<li><a class="reference internal" href="#conclusions">12.7. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Searching-Things.html"
|
||||
title="previous chapter"><span class="section-number">11. </span>Searching for things</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="../Part2/Beginner-Tutorial-Part2-Intro.html"
|
||||
title="next chapter">Part 2: What we want</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Django-queries.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Django-queries.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="advanced-searching-django-database-queries">
|
||||
<h1><span class="section-number">12. </span>Advanced searching - Django Database queries<a class="headerlink" href="#advanced-searching-django-database-queries" title="Permalink to this headline">¶</a></h1>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>More advanced lesson!</p>
|
||||
<p>Learning about Django’s query language is very useful once you start doing more
|
||||
advanced things in Evennia. But it’s not strictly needed out the box and can be
|
||||
a little overwhelming for a first reading. So if you are new to Python and
|
||||
Evennia, feel free to just skim this lesson and refer back to it later when
|
||||
you’ve gained more experience.</p>
|
||||
</div>
|
||||
<p>The search functions and methods we used in the previous lesson are enough for most cases.
|
||||
But sometimes you need to be more specific:</p>
|
||||
<ul class="simple">
|
||||
<li><p>You want to find all <code class="docutils literal notranslate"><span class="pre">Characters</span></code> …</p></li>
|
||||
<li><p>… who are in Rooms tagged as <code class="docutils literal notranslate"><span class="pre">moonlit</span></code> …</p></li>
|
||||
<li><p>… <em>and</em> who has the Attribute <code class="docutils literal notranslate"><span class="pre">lycantrophy</span></code> with a level higher than 2 …</p></li>
|
||||
<li><p>… because they should immediately transform to werewolves!</p></li>
|
||||
</ul>
|
||||
<p>In principle you could achieve this with the existing search functions combined with a lot of loops
|
||||
and if statements. But for something non-standard like this, querying the database directly will be
|
||||
much more efficient.</p>
|
||||
<p>Evennia uses <a class="reference external" href="https://www.djangoproject.com/">Django</a> to handle its connection to the database.
|
||||
A <a class="reference external" href="https://docs.djangoproject.com/en/3.0/ref/models/querysets/">django queryset</a> represents
|
||||
a database query. One can add querysets together to build ever-more complicated queries. Only when
|
||||
you are trying to use the results of the queryset will it actually call the database.</p>
|
||||
<p>The normal way to build a queryset is to define what class of entity you want to search by getting its
|
||||
<code class="docutils literal notranslate"><span class="pre">.objects</span></code> resource, and then call various methods on that. We’ve seen this one before:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_weapons = Weapon.objects.all()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is now a queryset representing all instances of <code class="docutils literal notranslate"><span class="pre">Weapon</span></code>. If <code class="docutils literal notranslate"><span class="pre">Weapon</span></code> had a subclass <code class="docutils literal notranslate"><span class="pre">Cannon</span></code> and we
|
||||
only wanted the cannons, we would do</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_cannons = Cannon.objects.all()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note that <code class="docutils literal notranslate"><span class="pre">Weapon</span></code> and <code class="docutils literal notranslate"><span class="pre">Cannon</span></code> are <em>different</em> typeclasses. This means that you
|
||||
won’t find any <code class="docutils literal notranslate"><span class="pre">Weapon</span></code>-typeclassed results in <code class="docutils literal notranslate"><span class="pre">all_cannons</span></code>. Vice-versa, you
|
||||
won’t find any <code class="docutils literal notranslate"><span class="pre">Cannon</span></code>-typeclassed results in <code class="docutils literal notranslate"><span class="pre">all_weapons</span></code>. This may not be
|
||||
what you expect.</p>
|
||||
<p>If you want to get all entities with typeclass <code class="docutils literal notranslate"><span class="pre">Weapon</span></code> <em>as well</em> as all the
|
||||
subclasses of <code class="docutils literal notranslate"><span class="pre">Weapon</span></code>, such as <code class="docutils literal notranslate"><span class="pre">Cannon</span></code>, you need to use the <code class="docutils literal notranslate"><span class="pre">_family</span></code> type of
|
||||
query:</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">_family</p>
|
||||
<p>The all_family, filter_family etc is an Evennia-specific
|
||||
thing. It’s not part of regular Django.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>really_all_weapons = Weapon.objects.all_family()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This result now contains both <code class="docutils literal notranslate"><span class="pre">Weapon</span></code> and <code class="docutils literal notranslate"><span class="pre">Cannon</span></code> instances (and any other
|
||||
entities whose typeclasses inherit at any distance from <code class="docutils literal notranslate"><span class="pre">Weapon</span></code>, like <code class="docutils literal notranslate"><span class="pre">Musket</span></code> or
|
||||
<code class="docutils literal notranslate"><span class="pre">Sword</span></code>).</p>
|
||||
<p>To limit your search by other criteria than the Typeclass you need to use <code class="docutils literal notranslate"><span class="pre">.filter</span></code>
|
||||
(or <code class="docutils literal notranslate"><span class="pre">.filter_family</span></code>) instead:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>roses = Flower.objects.filter(db_key="rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is a queryset representing all flowers having a <code class="docutils literal notranslate"><span class="pre">db_key</span></code> equal to <code class="docutils literal notranslate"><span class="pre">"rose"</span></code>.
|
||||
Since this is a queryset you can keep adding to it; this will act as an <code class="docutils literal notranslate"><span class="pre">AND</span></code> condition.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>local_roses = roses.filter(db_location=myroom)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We could also have written this in one statement:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>local_roses = Flower.objects.filter(db_key="rose", db_location=myroom)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We can also <code class="docutils literal notranslate"><span class="pre">.exclude</span></code> something from results</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>local_non_red_roses = local_roses.exclude(db_key="red_rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It’s important to note that we haven’t called the database yet! Not until we
|
||||
actually try to examine the result will the database be called. Here the
|
||||
database is called when we try to loop over it (because now we need to actually
|
||||
get results out of it to be able to loop):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>for rose in local_non_red_roses:
|
||||
print(rose)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>From now on, the queryset is <em>evaluated</em> and we can’t keep adding more queries to it - we’d need to
|
||||
create a new queryset if we wanted to find some other result. Other ways to evaluate the queryset is to
|
||||
print it, convert it to a list with <code class="docutils literal notranslate"><span class="pre">list()</span></code> and otherwise try to access its results.</p>
|
||||
<p>Note how we use <code class="docutils literal notranslate"><span class="pre">db_key</span></code> and <code class="docutils literal notranslate"><span class="pre">db_location</span></code>. This is the actual names of these
|
||||
database fields. By convention Evennia uses <code class="docutils literal notranslate"><span class="pre">db_</span></code> in front of every database
|
||||
field. When you use the normal Evennia search helpers and objects you can skip
|
||||
the <code class="docutils literal notranslate"><span class="pre">db_</span></code> but here we are calling the database directly and need to use the
|
||||
‘real’ names.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">database fields</p>
|
||||
<p>Each database table have only a few fields. For <code class="docutils literal notranslate"><span class="pre">Objects</span></code>, the most common ones
|
||||
are <code class="docutils literal notranslate"><span class="pre">db_key</span></code>, <code class="docutils literal notranslate"><span class="pre">db_location</span></code> and <code class="docutils literal notranslate"><span class="pre">db_destination</span></code>. When accessing them they are
|
||||
normally accessed just as <code class="docutils literal notranslate"><span class="pre">obj.key</span></code>, <code class="docutils literal notranslate"><span class="pre">obj.location</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.destination</span></code>. You
|
||||
only need to remember the <code class="docutils literal notranslate"><span class="pre">db_</span></code> when using them in database queries. The object
|
||||
description, <code class="docutils literal notranslate"><span class="pre">obj.db.desc</span></code> is not such a hard-coded field, but one of many
|
||||
arbitrary Attributes attached to the Object.</p>
|
||||
</aside>
|
||||
<p>Here are the most commonly used methods to use with the <code class="docutils literal notranslate"><span class="pre">objects</span></code> managers:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">filter</span></code> - query for a listing of objects based on search criteria. Gives empty queryset if none
|
||||
were found.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">get</span></code> - query for a single match - raises exception if none were found, or more than one was
|
||||
found.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">all</span></code> - get all instances of the particular type.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">filter_family</span></code> - like <code class="docutils literal notranslate"><span class="pre">filter</span></code>, but search all sub classes as well.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">get_family</span></code> - like <code class="docutils literal notranslate"><span class="pre">get</span></code>, but search all sub classes as well.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">all_family</span></code> - like <code class="docutils literal notranslate"><span class="pre">all</span></code>, but return entities of all subclasses as well.</p></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<div><p>All of Evennia search functions use querysets under the hood. The <code class="docutils literal notranslate"><span class="pre">evennia.search_*</span></code> functions actually
|
||||
return querysets, which means you could in principle keep adding queries to their results as well.</p>
|
||||
</div></blockquote>
|
||||
<section id="queryset-field-lookups">
|
||||
<h2><span class="section-number">12.1. </span>Queryset field lookups<a class="headerlink" href="#queryset-field-lookups" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Above we found roses with exactly the <code class="docutils literal notranslate"><span class="pre">db_key</span></code> <code class="docutils literal notranslate"><span class="pre">"rose"</span></code>. This is an <em>exact</em> match that is <em>case sensitive</em>,
|
||||
so it would not find <code class="docutils literal notranslate"><span class="pre">"Rose"</span></code>.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span># this is case-sensitive and the same as =
|
||||
roses = Flower.objects.filter(db_key__exact="rose"
|
||||
|
||||
# the i means it's case-insensitive
|
||||
roses = Flower.objects.filter(db_key__iexact="rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The Django field query language uses <code class="docutils literal notranslate"><span class="pre">__</span></code> similarly to how Python uses <code class="docutils literal notranslate"><span class="pre">.</span></code> to access resources. This
|
||||
is because <code class="docutils literal notranslate"><span class="pre">.</span></code> is not allowed in a function keyword.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>roses = Flower.objects.filter(db_key__icontains="rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will find all flowers whose name contains the string <code class="docutils literal notranslate"><span class="pre">"rose"</span></code>, like <code class="docutils literal notranslate"><span class="pre">"roses"</span></code>, <code class="docutils literal notranslate"><span class="pre">"wild</span> <span class="pre">rose"</span></code> etc. The
|
||||
<code class="docutils literal notranslate"><span class="pre">i</span></code> in the beginning makes the search case-insensitive. Other useful variations to use
|
||||
are <code class="docutils literal notranslate"><span class="pre">__istartswith</span></code> and <code class="docutils literal notranslate"><span class="pre">__iendswith</span></code>. You can also use <code class="docutils literal notranslate"><span class="pre">__gt</span></code>, <code class="docutils literal notranslate"><span class="pre">__ge</span></code> for “greater-than”/“greater-or-equal-than”
|
||||
comparisons (same for <code class="docutils literal notranslate"><span class="pre">__lt</span></code> and <code class="docutils literal notranslate"><span class="pre">__le</span></code>). There is also <code class="docutils literal notranslate"><span class="pre">__in</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>swords = Weapons.objects.filter(db_key__in=("rapier", "two-hander", "shortsword"))
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>One also uses <code class="docutils literal notranslate"><span class="pre">__</span></code> to access foreign objects like Tags. Let’s for example assume
|
||||
this is how we have identified mages:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>char.tags.add("mage", category="profession")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now, in this case we have an Evennia helper to do this search:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>mages = evennia.search_tags("mage", category="profession")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>But this will find all Objects with this tag+category. Maybe you are only looking for Vampire mages:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>sparkly_mages = Vampire.objects.filter(db_tags__db_key="mage", db_tags__db_category="profession")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This looks at the <code class="docutils literal notranslate"><span class="pre">db_tags</span></code> field on the <code class="docutils literal notranslate"><span class="pre">Vampire</span></code> and filters on the values of each tag’s
|
||||
<code class="docutils literal notranslate"><span class="pre">db_key</span></code> and <code class="docutils literal notranslate"><span class="pre">db_category</span></code> together.</p>
|
||||
<p>For more field lookups, see the
|
||||
<a class="reference external" href="https://docs.djangoproject.com/en/3.0/ref/models/querysets/#field-lookups">django docs</a> on the subject.</p>
|
||||
</section>
|
||||
<section id="get-that-werewolf">
|
||||
<h2><span class="section-number">12.2. </span>Get that werewolf …<a class="headerlink" href="#get-that-werewolf" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Let’s see if we can make a query for the werewolves in the moonlight we mentioned at the beginning
|
||||
of this lesson.</p>
|
||||
<p>Firstly, we make ourselves and our current location match the criteria, so we can test:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py here.tags.add("moonlit")
|
||||
> py me.db.lycantrophy = 3
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is an example of a more complex query. We’ll consider it an example of what is
|
||||
possible.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Line breaks</p>
|
||||
<p>Note the way of writing this code. It would have been very hard to read if we
|
||||
just wrote it in one long line. But since we wrapped it in <code class="docutils literal notranslate"><span class="pre">(...)</span></code> we can spread
|
||||
it out over multiple lines without worrying about line breaks!</p>
|
||||
</aside>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.characters</span> <span class="kn">import</span> <span class="n">Character</span>
|
||||
|
||||
<span class="n">will_transform</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">Character</span><span class="o">.</span><span class="n">objects</span>
|
||||
<span class="o">.</span><span class="n">filter</span><span class="p">(</span>
|
||||
<span class="n">db_location__db_tags__db_key__iexact</span><span class="o">=</span><span class="s2">"moonlit"</span><span class="p">,</span>
|
||||
<span class="n">db_attributes__db_key</span><span class="o">=</span><span class="s2">"lycantrophy"</span><span class="p">,</span>
|
||||
<span class="n">db_attributes__db_value__gt</span><span class="o">=</span><span class="mi">2</span>
|
||||
<span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p>We want to find <code class="docutils literal notranslate"><span class="pre">Character</span></code>s, so we access <code class="docutils literal notranslate"><span class="pre">.objects</span></code> on the <code class="docutils literal notranslate"><span class="pre">Character</span></code> typeclass.</p></li>
|
||||
<li><p>We start to filter …</p></li>
|
||||
<li><ul>
|
||||
<li><p>… by accessing the <code class="docutils literal notranslate"><span class="pre">db_location</span></code> field (usually this is a Room)</p></li>
|
||||
<li><p>… and on that location, we get the value of <code class="docutils literal notranslate"><span class="pre">db_tags</span></code> (this is a <em>many-to-many</em> database field
|
||||
that we can treat like an object for this purpose; it references all Tags on the location)</p></li>
|
||||
<li><p>… and from those <code class="docutils literal notranslate"><span class="pre">Tags</span></code>, we looking for <code class="docutils literal notranslate"><span class="pre">Tags</span></code> whose <code class="docutils literal notranslate"><span class="pre">db_key</span></code> is “monlit” (non-case sensitive).</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>… We also want only Characters with <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> whose <code class="docutils literal notranslate"><span class="pre">db_key</span></code> is exactly <code class="docutils literal notranslate"><span class="pre">"lycantrophy"</span></code></p></li>
|
||||
<li><p>… at the same time as the <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>’s <code class="docutils literal notranslate"><span class="pre">db_value</span></code> is greater-than 2.</p></li>
|
||||
</ul>
|
||||
<p>Running this query makes our newly lycantrophic Character appear in <code class="docutils literal notranslate"><span class="pre">will_transform</span></code> so we
|
||||
know to transform it. Success!</p>
|
||||
<blockquote>
|
||||
<div><p>Don’t confuse database fields with <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> you set via <code class="docutils literal notranslate"><span class="pre">obj.db.attr</span> <span class="pre">=</span> <span class="pre">'foo'</span></code> or
|
||||
<code class="docutils literal notranslate"><span class="pre">obj.attributes.add()</span></code>. Attributes are custom database entities <em>linked</em> to an object. They are not
|
||||
separate fields <em>on</em> that object like <code class="docutils literal notranslate"><span class="pre">db_key</span></code> or <code class="docutils literal notranslate"><span class="pre">db_location</span></code> are.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="complex-queries">
|
||||
<h2><span class="section-number">12.3. </span>Complex queries<a class="headerlink" href="#complex-queries" title="Permalink to this headline">¶</a></h2>
|
||||
<p>All examples so far used <code class="docutils literal notranslate"><span class="pre">AND</span></code> relations. The arguments to <code class="docutils literal notranslate"><span class="pre">.filter</span></code> are added together with <code class="docutils literal notranslate"><span class="pre">AND</span></code>
|
||||
(“we want tag room to be “monlit” <em>and</em> lycantrhopy be > 2”).</p>
|
||||
<p>For queries using <code class="docutils literal notranslate"><span class="pre">OR</span></code> and <code class="docutils literal notranslate"><span class="pre">NOT</span></code> we need Django’s
|
||||
<a class="reference external" href="https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q-objects">Q object</a>. It is
|
||||
imported from Django directly:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from django.db.models import Q
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">Q</span></code> is an object that is created with the same arguments as <code class="docutils literal notranslate"><span class="pre">.filter</span></code>, for example</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Q(db_key="foo")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can then use this <code class="docutils literal notranslate"><span class="pre">Q</span></code> instance as argument in a <code class="docutils literal notranslate"><span class="pre">filter</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>q1 = Q(db_key="foo")
|
||||
Character.objects.filter(q1)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The useful thing about <code class="docutils literal notranslate"><span class="pre">Q</span></code> is that these objects can be chained together with special symbols (bit operators):
|
||||
<code class="docutils literal notranslate"><span class="pre">|</span></code> for <code class="docutils literal notranslate"><span class="pre">OR</span></code> and <code class="docutils literal notranslate"><span class="pre">&</span></code> for <code class="docutils literal notranslate"><span class="pre">AND</span></code>. A tilde <code class="docutils literal notranslate"><span class="pre">~</span></code> in front negates the expression inside the <code class="docutils literal notranslate"><span class="pre">Q</span></code> and thus
|
||||
works like <code class="docutils literal notranslate"><span class="pre">NOT</span></code>.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>q1 = Q(db_key="Dalton")
|
||||
q2 = Q(db_location=prison)
|
||||
Character.objects.filter(q1 | ~q2)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Would get all Characters that are either named “Dalton” <em>or</em> which is <em>not</em> in prison. The result is a mix
|
||||
of Daltons and non-prisoners.</p>
|
||||
<p>Let us expand our original werewolf query. Not only do we want to find all
|
||||
Characters in a moonlit room with a certain level of <code class="docutils literal notranslate"><span class="pre">lycanthrophy</span></code>. Now we also
|
||||
want the full moon to immediately transform people who were recently bitten,
|
||||
even if their <code class="docutils literal notranslate"><span class="pre">lycantrophy</span></code> level is not yet high enough (more dramatic this
|
||||
way!). When you get bitten, you’ll get a Tag <code class="docutils literal notranslate"><span class="pre">recently_bitten</span></code> put on you to
|
||||
indicate this.</p>
|
||||
<p>This is how we’d change our query:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
|
||||
|
||||
<span class="n">will_transform</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">Character</span><span class="o">.</span><span class="n">objects</span>
|
||||
<span class="o">.</span><span class="n">filter</span><span class="p">(</span>
|
||||
<span class="n">Q</span><span class="p">(</span><span class="n">db_location__db_tags__db_key__iexact</span><span class="o">=</span><span class="s2">"moonlit"</span><span class="p">)</span>
|
||||
<span class="o">&</span> <span class="p">(</span>
|
||||
<span class="n">Q</span><span class="p">(</span><span class="n">db_attributes__db_key</span><span class="o">=</span><span class="s2">"lycantrophy"</span><span class="p">,</span>
|
||||
<span class="n">db_attributes__db_value__gt</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">db_tags__db_key__iexact</span><span class="o">=</span><span class="s2">"recently_bitten"</span><span class="p">)</span>
|
||||
<span class="p">))</span>
|
||||
<span class="o">.</span><span class="n">distinct</span><span class="p">()</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That’s quite compact. It may be easier to see what’s going on if written this way:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
|
||||
|
||||
<span class="n">q_moonlit</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">db_location__db_tags__db_key__iexact</span><span class="o">=</span><span class="s2">"moonlit"</span><span class="p">)</span>
|
||||
<span class="n">q_lycantropic</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">db_attributes__db_key</span><span class="o">=</span><span class="s2">"lycantrophy"</span><span class="p">,</span> <span class="n">db_attributes__db_value__gt</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
|
||||
<span class="n">q_recently_bitten</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">db_tags__db_key__iexact</span><span class="o">=</span><span class="s2">"recently_bitten"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">will_transform</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">Character</span><span class="o">.</span><span class="n">objects</span>
|
||||
<span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">q_moonlit</span> <span class="o">&</span> <span class="p">(</span><span class="n">q_lycantropic</span> <span class="o">|</span> <span class="n">q_recently_bitten</span><span class="p">))</span>
|
||||
<span class="o">.</span><span class="n">distinct</span><span class="p">()</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">SQL</p>
|
||||
<p>These Python structures are internally converted to SQL, the native language of
|
||||
the database. If you are familiar with SQL, these are many-to-many tables
|
||||
joined with <code class="docutils literal notranslate"><span class="pre">LEFT</span> <span class="pre">OUTER</span> <span class="pre">JOIN</span></code>, which may lead to multiple merged rows combining
|
||||
the same object with different relations.</p>
|
||||
</aside>
|
||||
<p>This reads as “Find all Characters in a moonlit room that either has the
|
||||
Attribute <code class="docutils literal notranslate"><span class="pre">lycantrophy</span></code> higher than two, <em>or</em> which has the Tag
|
||||
<code class="docutils literal notranslate"><span class="pre">recently_bitten</span></code>”. With an OR-query like this it’s possible to find the same
|
||||
Character via different paths, so we add <code class="docutils literal notranslate"><span class="pre">.distinct()</span></code> at the end. This makes
|
||||
sure that there is only one instance of each Character in the result.</p>
|
||||
</section>
|
||||
<section id="annotations">
|
||||
<h2><span class="section-number">12.4. </span>Annotations<a class="headerlink" href="#annotations" title="Permalink to this headline">¶</a></h2>
|
||||
<p>What if we wanted to filter on some condition that isn’t represented easily by a
|
||||
field on the object? Maybe we want to find rooms only containing five or more
|
||||
objects?</p>
|
||||
<p>We <em>could</em> do it like this (don’t actually do it this way!):</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
||||
|
||||
<span class="n">all_rooms</span> <span class="o">=</span> <span class="n">Rooms</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||||
|
||||
<span class="n">rooms_with_five_objects</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">for</span> <span class="n">room</span> <span class="ow">in</span> <span class="n">all_rooms</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">room</span><span class="o">.</span><span class="n">contents</span><span class="p">)</span> <span class="o">>=</span> <span class="mi">5</span><span class="p">:</span>
|
||||
<span class="n">rooms_with_five_objects</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">room</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Above we get all rooms and then use <code class="docutils literal notranslate"><span class="pre">list.append()</span></code> to keep adding the right
|
||||
rooms to an ever-growing list. This is <em>not</em> a good idea, once your database
|
||||
grows this will be unnecessarily computing-intensive. The database is much more
|
||||
suitable for this.</p>
|
||||
<p><em>Annotations</em> allow you to set a ‘variable’ inside the query that you can then
|
||||
access from other parts of the query. Let’s do the same example as before
|
||||
directly in the database:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
||||
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Count</span>
|
||||
|
||||
<span class="n">rooms</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">Room</span><span class="o">.</span><span class="n">objects</span>
|
||||
<span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
|
||||
<span class="n">num_objects</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'locations_set'</span><span class="p">))</span>
|
||||
<span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">num_objects__gte</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">Count</span></code> is a Django class for counting the number of things in the database.</p>
|
||||
<p>Here we first create an annotation <code class="docutils literal notranslate"><span class="pre">num_objects</span></code> of type <code class="docutils literal notranslate"><span class="pre">Count</span></code>. It creates an in-database function
|
||||
that will count the number of results inside the database.</p>
|
||||
<blockquote>
|
||||
<div><p>Note the use of <code class="docutils literal notranslate"><span class="pre">location_set</span></code> in that <code class="docutils literal notranslate"><span class="pre">Count</span></code>. The <code class="docutils literal notranslate"><span class="pre">*_set</span></code> is a back-reference automatically created by
|
||||
Django. In this case it allows you to find all objects that <em>has the current object as location</em>.</p>
|
||||
</div></blockquote>
|
||||
<p>Next we filter on this annotation, using the name <code class="docutils literal notranslate"><span class="pre">num_objects</span></code> as something we
|
||||
can filter for. We use <code class="docutils literal notranslate"><span class="pre">num_objects__gte=5</span></code> which means that <code class="docutils literal notranslate"><span class="pre">num_objects</span></code>
|
||||
should be greater than or equal to 5. This is a little harder to get one’s head
|
||||
around but much more efficient than lopping over all objects in Python.</p>
|
||||
</section>
|
||||
<section id="f-objects">
|
||||
<h2><span class="section-number">12.5. </span>F-objects<a class="headerlink" href="#f-objects" title="Permalink to this headline">¶</a></h2>
|
||||
<p>What if we wanted to compare two dynamic parameters against one another in a
|
||||
query? For example, what if instead of having 5 or more objects, we only wanted
|
||||
objects that had a bigger inventory than they had tags (silly example, but …)?
|
||||
This can be with Django’s <a class="reference external" href="https://docs.djangoproject.com/en/1.11/ref/models/expressions/#f-expressions">F objects</a>.
|
||||
So-called F expressions allow you to do a query that looks at a value of each
|
||||
object in the database.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Count</span><span class="p">,</span> <span class="n">F</span>
|
||||
<span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
||||
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">Room</span><span class="o">.</span><span class="n">objects</span>
|
||||
<span class="o">.</span><span class="n">annotate</span><span class="p">(</span>
|
||||
<span class="n">num_objects</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'locations_set'</span><span class="p">),</span>
|
||||
<span class="n">num_tags</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'db_tags'</span><span class="p">))</span>
|
||||
<span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">num_objects__gt</span><span class="o">=</span><span class="n">F</span><span class="p">(</span><span class="s1">'num_tags'</span><span class="p">))</span>
|
||||
<span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we used <code class="docutils literal notranslate"><span class="pre">.annotate</span></code> to create two in-query ‘variables’ <code class="docutils literal notranslate"><span class="pre">num_objects</span></code> and <code class="docutils literal notranslate"><span class="pre">num_tags</span></code>. We then
|
||||
directly use these results in the filter. Using <code class="docutils literal notranslate"><span class="pre">F()</span></code> allows for also the right-hand-side of the filter
|
||||
condition to be calculated on the fly, completely within the database.</p>
|
||||
</section>
|
||||
<section id="grouping-and-returning-only-certain-properties">
|
||||
<h2><span class="section-number">12.6. </span>Grouping and returning only certain properties<a class="headerlink" href="#grouping-and-returning-only-certain-properties" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Suppose you used tags to mark someone belonging to an organization. Now you want to make a list and
|
||||
need to get the membership count of every organization all at once.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">.annotate</span></code>, <code class="docutils literal notranslate"><span class="pre">.values_list</span></code>, and <code class="docutils literal notranslate"><span class="pre">.order_by</span></code> queryset methods are useful for this. Normally when
|
||||
you run a <code class="docutils literal notranslate"><span class="pre">.filter</span></code>, what you get back is a bunch of full typeclass instances, like roses or swords.
|
||||
Using <code class="docutils literal notranslate"><span class="pre">.values_list</span></code> you can instead choose to only get back certain properties on objects.
|
||||
The <code class="docutils literal notranslate"><span class="pre">.order_by</span></code> method finally allows for sorting the results according to some criterion:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Count</span>
|
||||
<span class="kn">from</span> <span class="nn">typeclasses.rooms</span> <span class="kn">import</span> <span class="n">Room</span>
|
||||
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">Character</span><span class="o">.</span><span class="n">objects</span>
|
||||
<span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db_tags__db_category</span><span class="o">=</span><span class="s2">"organization"</span><span class="p">)</span>
|
||||
<span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">tagcount</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s1">'id'</span><span class="p">))</span>
|
||||
<span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">'-tagcount'</span><span class="p">))</span>
|
||||
<span class="o">.</span><span class="n">values_list</span><span class="p">(</span><span class="s1">'db_tags__db_key'</span><span class="p">,</span> <span class="s2">"tagcount"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we fetch all Characters who …</p>
|
||||
<ul class="simple">
|
||||
<li><p>… has a tag of category “organization” on them</p></li>
|
||||
<li><p>… along the way we count how many different Characters (each <code class="docutils literal notranslate"><span class="pre">id</span></code> is unique) we find for each organization
|
||||
and store it in a ‘variable’ <code class="docutils literal notranslate"><span class="pre">tagcount</span></code> using <code class="docutils literal notranslate"><span class="pre">.annotate</span></code> and <code class="docutils literal notranslate"><span class="pre">Count</span></code></p></li>
|
||||
<li><p>… we use this count to sort the result in descending order of <code class="docutils literal notranslate"><span class="pre">tagcount</span></code> (descending because there is a minus sign,
|
||||
default is increasing order but we want the most popular organization to be first).</p></li>
|
||||
<li><p>… and finally we make sure to only return exactly the properties we want, namely the name of the organization tag
|
||||
and how many matches we found for that organization.</p></li>
|
||||
</ul>
|
||||
<p>The result queryset will be a list of tuples ordered in descending order by the number of matches,
|
||||
in a format like the following:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span>
|
||||
<span class="p">(</span><span class="s1">'Griatch'</span><span class="n">s</span> <span class="n">poets</span> <span class="n">society</span><span class="s1">', 3872),</span>
|
||||
<span class="p">(</span><span class="s2">"Chainsol's Ainneve Testers"</span><span class="p">,</span> <span class="mi">2076</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"Blaufeuer's Whitespace Fixers"</span><span class="p">,</span> <span class="mi">1903</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"Volund's Bikeshed Design Crew"</span><span class="p">,</span> <span class="mi">1764</span><span class="p">),</span>
|
||||
<span class="p">(</span><span class="s2">"Tehom's Glorious Misanthropes"</span><span class="p">,</span> <span class="mi">1763</span><span class="p">)</span>
|
||||
<span class="p">]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="conclusions">
|
||||
<h2><span class="section-number">12.7. </span>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We have covered a lot of ground in this lesson and covered several more complex
|
||||
topics. Knowing how to query using Django is a powerful skill to have.</p>
|
||||
<p>This concludes the first part of the Evennia starting tutorial - “What we have”.
|
||||
Now we have a good foundation to understand how to plan what our tutorial game
|
||||
will be about.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Part2/Beginner-Tutorial-Part2-Intro.html" title="Part 2: What we want"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">12. </span>Advanced searching - Django Database queries</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>6. Overview of the Evennia library — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="7. Making objects persistent" href="Beginner-Tutorial-Learning-Typeclasses.html" />
|
||||
<link rel="prev" title="5. Introduction to Python classes and objects" href="Beginner-Tutorial-Python-classes-and-objects.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">6. </span>Overview of the Evennia library</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">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>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Python-classes-and-objects.html"
|
||||
title="previous chapter"><span class="section-number">5. </span>Introduction to Python classes and objects</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Learning-Typeclasses.html"
|
||||
title="next chapter"><span class="section-number">7. </span>Making objects persistent</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Evennia-Library-Overview.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Evennia-Library-Overview.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="overview-of-the-evennia-library">
|
||||
<h1><span class="section-number">6. </span>Overview of the Evennia library<a class="headerlink" href="#overview-of-the-evennia-library" title="Permalink to this headline">¶</a></h1>
|
||||
<aside class="sidebar">
|
||||
<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>
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>import evennia
|
||||
from evennia import some_module
|
||||
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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia/
|
||||
bin/
|
||||
CHANGELOG.md
|
||||
...
|
||||
...
|
||||
docs/
|
||||
evennia/
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This outer layer is for Evennia’s installation and package distribution. That internal folder <code class="docutils literal notranslate"><span class="pre">evennia/evennia/</span></code> is
|
||||
the <em>actual</em> library, the thing covered by the API auto-docs and what you get when you do <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">evennia</span></code>.</p>
|
||||
<blockquote>
|
||||
<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>
|
||||
<ul class="simple">
|
||||
<li><p>evennia</p>
|
||||
<ul>
|
||||
<li><p><a class="reference internal" href="../../../Evennia-API.html#shortcuts"><span class="std std-doc"><code class="docutils literal notranslate"><span class="pre">__init__.py</span></code></span></a> - The “flat API” of Evennia resides here.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Setup/Settings.html#settings-file"><span class="std std-doc"><code class="docutils literal notranslate"><span class="pre">settings_default.py</span></code></span></a> - Root settings of Evennia. Copy settings
|
||||
from here to <code class="docutils literal notranslate"><span class="pre">mygame/server/settings.py</span></code> file.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">commands/</span></code></span></a> - The command parser and handler.</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">default/</span></code> - The <a class="reference internal" href="../../../Components/Default-Commands.html"><span class="doc std std-doc">default commands</span></a> and cmdsets.</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Channels.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">comms/</span></code></span></a> - Systems for communicating in-game.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">contrib/</span></code> - Optional plugins too game-specific for core Evennia.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">game_template/</span></code> - Copied to become the “game directory” when using <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">--init</span></code>.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Help-System.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">help/</span></code></span></a> - Handles the storage and creation of help entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">locale/</span></code> - Language files (<a class="reference internal" href="../../../Concepts/Internationalization.html"><span class="doc std std-doc">i18n</span></a>).</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Locks.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">locks/</span></code></span></a> - Lock system for restricting access to in-game entities.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Objects.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">objects/</span></code></span></a> - In-game entities (all types of items and Characters).</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Prototypes.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">prototypes/</span></code></span></a> - Object Prototype/spawning system and OLC menu</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Accounts.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">accounts/</span></code></span></a> - Out-of-game Session-controlled entities (accounts, bots etc)</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">scripts/</span></code></span></a> - Out-of-game entities equivalence to Objects, also with timer support.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Portal-And-Server.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">server/</span></code></span></a> - Core server code and Session handling.</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">portal/</span></code> - Portal proxy and connection protocols.</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">typeclasses/</span></code></span></a> - Abstract classes for the typeclass storage and database system.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Coding-Utils.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">utils/</span></code></span></a> - Various miscellaneous useful coding resources.</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Concepts/Web-Features.html"><span class="doc std std-doc"><code class="docutils literal notranslate"><span class="pre">web/</span></code></span></a> - Web resources and webserver. Partly copied into game directory on initialization.</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<aside class="sidebar">
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from .objects.objects import DefaultObject
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Relative and absolute imports</p>
|
||||
<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></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>
|
||||
<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>
|
||||
</ol>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">6. </span>Overview of the Evennia library</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,360 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>4. Overview of your new Game Dir — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="5. Introduction to Python classes and objects" href="Beginner-Tutorial-Python-classes-and-objects.html" />
|
||||
<link rel="prev" title="3. Intro to using Python with Evennia" href="Beginner-Tutorial-Python-basic-introduction.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">4. </span>Overview of your new Game Dir</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">4. Overview of your new Game Dir</a><ul>
|
||||
<li><a class="reference internal" href="#commands">4.1. commands/</a></li>
|
||||
<li><a class="reference internal" href="#server">4.2. server/</a><ul>
|
||||
<li><a class="reference internal" href="#server-logs">4.2.1. server/logs/</a></li>
|
||||
<li><a class="reference internal" href="#server-conf">4.2.2. server/conf/</a></li>
|
||||
<li><a class="reference internal" href="#typeclasses">4.2.3. typeclasses/</a></li>
|
||||
<li><a class="reference internal" href="#web">4.2.4. web/</a></li>
|
||||
<li><a class="reference internal" href="#world">4.2.5. world/</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Python-basic-introduction.html"
|
||||
title="previous chapter"><span class="section-number">3. </span>Intro to using Python with Evennia</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Python-classes-and-objects.html"
|
||||
title="next chapter"><span class="section-number">5. </span>Introduction to Python classes and objects</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Gamedir-Overview.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Gamedir-Overview.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="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>
|
||||
<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>
|
||||
<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>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">commands/</span></code> - This holds all your custom commands (user-input handlers). You both add your own
|
||||
and override Evennia’s defaults from here.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">server</span></code>/ - The structure of this folder should not change since Evennia expects it.</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">conf/</span></code> - All server configuration files sits here. The most important file is <code class="docutils literal notranslate"><span class="pre">settings.py</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">logs/</span></code> - Server log files are stored here. When you use <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">--log</span></code> you are actually
|
||||
tailing the files in this directory.</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">typeclasses/</span></code> - this holds empty templates describing all database-bound entities in the
|
||||
game, like Characters, Scripts, Accounts etc. Adding code here allows to customize and extend
|
||||
the defaults.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">web/</span></code> - This is where you override and extend the default templates, views and static files used
|
||||
for Evennia’s web-presence, like the website and the HTML5 webclient.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">world/</span></code> - this is a “miscellaneous” folder holding everything related to the world you are
|
||||
building, such as build scripts and rules modules that don’t fit with one of the other folders.</p></li>
|
||||
</ul>
|
||||
</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></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>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">commands/</span></code> folder holds Python modules related to creating and extending the <a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc">Commands</span></a>
|
||||
of Evennia. These manifest in game like the server understanding input like <code class="docutils literal notranslate"><span class="pre">look</span></code> or <code class="docutils literal notranslate"><span class="pre">dig</span></code>.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Classes</p>
|
||||
<p>A <code class="docutils literal notranslate"><span class="pre">class</span></code> is template for creating object-instances of a particular type in Python. We will explain classes in more detail in the next lesson.</p>
|
||||
</aside>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/commands/command.py">command.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">commands.command</span></code>) - this contain the
|
||||
base <em>classes</em> for designing new input commands, or override the defaults.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/commands/default_cmdsets.py">default_cmdsets.py</a> (Python path: <code class="docutils literal notranslate"><span class="pre">commands.default_commands</span></code>) -
|
||||
a cmdset (Command-Set) groups Commands together. Command-sets can be added and removed from objects on the fly,
|
||||
meaning a user could have a different set of commands (or versions of commands) available depending on their circumstance
|
||||
in the game. In order to add a new command to the game, it’s common to import the new command-class
|
||||
from <code class="docutils literal notranslate"><span class="pre">command.py</span></code> and add it to one of the default cmdsets in this module.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="server">
|
||||
<h2><span class="section-number">4.2. </span>server/<a class="headerlink" href="#server" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This folder contains resource necessary for running Evennia. Contrary to the other folders, the structure
|
||||
of this should be kept the way it is.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia.db3</span></code> - you will only have this file if you are using the default SQLite3 database. This file
|
||||
contains the entire database. Just copy it to make a backup. For development you could also just
|
||||
make a copy once you have set up everything you need and just copy that back to ‘reset’ the state.
|
||||
If you delete this file you can easily recreate it by running <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">migrate</span></code>.</p></li>
|
||||
</ul>
|
||||
<section id="server-logs">
|
||||
<h3><span class="section-number">4.2.1. </span>server/logs/<a class="headerlink" href="#server-logs" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This holds the server logs. When you do <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">--log</span></code>, the evennia program is in fact tailing and concatenating
|
||||
the <code class="docutils literal notranslate"><span class="pre">server.log</span></code> and <code class="docutils literal notranslate"><span class="pre">portal.log</span></code> files in this directory. The logs are rotated every week. Depending on your settings,
|
||||
other logs, like the webserver HTTP request log can also be found here.</p>
|
||||
</section>
|
||||
<section id="server-conf">
|
||||
<h3><span class="section-number">4.2.2. </span>server/conf/<a class="headerlink" href="#server-conf" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This contains all configuration files of the Evennia server. These are regular Python modules which
|
||||
means that they must be extended with valid Python. You can also add logic to them if you wanted to.</p>
|
||||
<p>Common for the settings is that you generally will never them directly via their python-path; instead Evennia
|
||||
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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> from django.conf import settings
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To get to the setting <code class="docutils literal notranslate"><span class="pre">TELNET_PORT</span></code> in the settings file you’d then do</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>
|
||||
</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
|
||||
from the players. Put such settings in here, it will override values in <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> and not be included in
|
||||
version control.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_initial_setup.py</span></code> - When Evennia starts up for the very first time, it does some basic tasks, like creating the
|
||||
superuser and Limbo room. Adding to this file allows to add more actions for it to for first-startup.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_search.py</span></code> - When searching for objects and either finding no match or more than one match, it will
|
||||
respond by giving a warning or offering the user to differentiate between the multiple matches. Modifying
|
||||
the code here will change this behavior to your liking.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_startstop.py</span></code> - This allows to inject code to execute every time the server starts, stops or reloads
|
||||
in different ways.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">connection_screens.py</span></code> - This allows for changing the connection screen you see when you first connect to your
|
||||
game.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">inlinefuncs.py</span></code> - <em>Inlinefuncs</em> are optional and limited ‘functions’ that can be embedded in any strings being
|
||||
sent to a player. They are written as <code class="docutils literal notranslate"><span class="pre">$funcname(args)</span></code> and are used to customize the output
|
||||
depending on the user receiving it. For example sending people the text <code class="docutils literal notranslate"><span class="pre">"Let's</span> <span class="pre">meet</span> <span class="pre">at</span> <span class="pre">$realtime(13:00,</span> <span class="pre">GMT)!</span></code>
|
||||
would show every player seeing that string the time given in their own time zone. The functions added to this
|
||||
module will become new inlinefuncs in the game.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">inputfucs.py</span></code> - When a command like <code class="docutils literal notranslate"><span class="pre">look</span></code> is received by the server, it is handled by an <em>inputfunc</em>
|
||||
that redirects it to the cmdhandler system. But there could be other inputs coming from the clients, like
|
||||
button-presses or the request to update a health-bar. While most common cases are already covered, this is
|
||||
where one adds new functions to process new types of input.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">lockfuncs.py</span></code> - <em>Locks</em> restrict access to things in-game. Lock funcs are used in a mini-language
|
||||
to defined more complex locks. For example you could have a lockfunc that checks if the user is carrying
|
||||
a given item, is bleeding or has a certain skill value. New functions added in this modules will
|
||||
become available for use in lock definitions.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mssp.py</span></code> - Mud Server Status Protocol is a way for online MUD archives/listings (which you usually have
|
||||
to sign up for) to track which MUDs are currently online, how many players they have etc. While Evennia handles
|
||||
the dynamic information automatically, this is were you set up the meta-info about your game, such as its
|
||||
theme, if player-killing is allowed and so on. This is a more generic form of the Evennia Game directory.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">portal_services_plugins.py</span></code> - If you want to add new external connection protocols to Evennia, this is the place
|
||||
to add them.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">server_services_plugins.py</span></code> - This allows to override internal server connection protocols.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">web_plugins.py</span></code> - This allows to add plugins to the Evennia webserver as it starts.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="typeclasses">
|
||||
<h3><span class="section-number">4.2.3. </span>typeclasses/<a class="headerlink" href="#typeclasses" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a> of Evennia are Evennia-specific Python classes whose instances save themselves
|
||||
to the database. This allows a Character to remain in the same place and your updated strength stat to still
|
||||
be the same after a server reboot.</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/accounts.py">accounts.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.accounts</span></code>) - An
|
||||
<a class="reference internal" href="../../../Components/Accounts.html"><span class="doc std std-doc">Account</span></a> represents the player connecting to the game. It holds information like email,
|
||||
password and other out-of-character details.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/channels.py">channels.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.channels</span></code>) -
|
||||
<a class="reference internal" href="../../../Components/Channels.html"><span class="doc std std-doc">Channels</span></a> are used to manage in-game communication between players.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/objects.py">objects.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.objects</span></code>) -
|
||||
<a class="reference internal" href="../../../Components/Objects.html"><span class="doc std std-doc">Objects</span></a> represent all things having a location within the game world.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/characters.py">characters.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.characters</span></code>) -
|
||||
The <a class="reference internal" href="../../../Components/Objects.html#characters"><span class="std std-doc">Character</span></a> is a subclass of Objects, controlled by Accounts - they are the player’s
|
||||
avatars in the game world.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/rooms.py">rooms.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.rooms</span></code>) - A
|
||||
<a class="reference internal" href="../../../Components/Objects.html#rooms"><span class="std std-doc">Room</span></a> is also a subclass of Object; describing discrete locations. While the traditional
|
||||
term is ‘room’, such a location can be anything and on any scale that fits your game, from a forest glade,
|
||||
an entire planet or an actual dungeon room.</p></li>
|
||||
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/typeclasses/exits.py">exits.py</a> (Python-path: <code class="docutils literal notranslate"><span class="pre">typeclasses.exits</span></code>) -
|
||||
<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>
|
||||
</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>
|
||||
<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
|
||||
should consider re-pointing Evennia to use some external service to serve your media instead.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">static_overrides/</span></code> - ‘static’ files include fonts, CSS and JS. Within this folder you’ll find sub-folders for
|
||||
overriding the static files for the <code class="docutils literal notranslate"><span class="pre">admin</span></code> (this is the Django web-admin), the <code class="docutils literal notranslate"><span class="pre">webclient</span></code> (this is thet
|
||||
HTML5 webclient) and the <code class="docutils literal notranslate"><span class="pre">website</span></code>. Adding files to this folder will replace same-named files in the
|
||||
default web presence.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">template_overrides/</span></code> - these are HTML files, for the <code class="docutils literal notranslate"><span class="pre">webclient</span></code> and the <code class="docutils literal notranslate"><span class="pre">website</span></code>. HTML files are written
|
||||
using <a class="reference external" href="https://jinja.palletsprojects.com/en/2.11.x/">Jinja</a> templating, which means that one can override
|
||||
only particular parts of a default template without touching others.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">static/</span></code> - this is a work-directory for the web system and should <em>not</em> be manually modified. Basically,
|
||||
Evennia will copy static data from <code class="docutils literal notranslate"><span class="pre">static_overrides</span></code> here when the server starts.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">urls.py</span></code> - this module links up the Python code to the URLs you go to in the browser.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="world">
|
||||
<h3><span class="section-number">4.2.5. </span>world/<a class="headerlink" href="#world" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This folder only contains some example files. It’s meant to hold ‘the rest’ of your game implementation. Many
|
||||
people change and re-structure this in various ways to better fit their ideas.</p>
|
||||
<ul class="simple">
|
||||
<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>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">4. </span>Overview of your new Game Dir</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,744 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>7. Making objects persistent — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="8. Adding custom commands" href="Beginner-Tutorial-Adding-Commands.html" />
|
||||
<link rel="prev" title="6. Overview of the Evennia library" href="Beginner-Tutorial-Evennia-Library-Overview.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">7. </span>Making objects persistent</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">7. Making objects persistent</a><ul>
|
||||
<li><a class="reference internal" href="#our-first-persistent-object">7.1. Our first persistent object</a><ul>
|
||||
<li><a class="reference internal" href="#making-a-new-object-by-calling-the-class">7.1.1. Making a new object by calling the class</a></li>
|
||||
<li><a class="reference internal" href="#creating-using-create-object">7.1.2. Creating using create_object</a></li>
|
||||
<li><a class="reference internal" href="#creating-using-create-command">7.1.3. Creating using create-command</a></li>
|
||||
</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>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#modifying-ourselves">7.3. Modifying ourselves</a><ul>
|
||||
<li><a class="reference internal" href="#a-method-on-ourselves">7.3.1. A method on ourselves</a></li>
|
||||
<li><a class="reference internal" href="#attributes">7.3.2. Attributes</a></li>
|
||||
<li><a class="reference internal" href="#setting-things-on-new-characters">7.3.3. Setting things on new Characters</a></li>
|
||||
<li><a class="reference internal" href="#updating-all-characters-in-a-loop">7.3.4. Updating all Characters in a loop</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#extra-credits">7.4. Extra Credits</a></li>
|
||||
<li><a class="reference internal" href="#conclusions">7.5. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Evennia-Library-Overview.html"
|
||||
title="previous chapter"><span class="section-number">6. </span>Overview of the Evennia library</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Adding-Commands.html"
|
||||
title="next chapter"><span class="section-number">8. </span>Adding custom commands</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Learning-Typeclasses.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Learning-Typeclasses.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="making-objects-persistent">
|
||||
<h1><span class="section-number">7. </span>Making objects persistent<a class="headerlink" href="#making-objects-persistent" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Now that we have learned a little about how to find things in the Evennia library, let’s use it.</p>
|
||||
<p>In the <a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html"><span class="doc std std-doc">Python classes and objects</span></a> lesson we created the dragons Fluffy, Cuddly
|
||||
and Smaug and made them fly and breathe fire. So far our dragons are short-lived - whenever we <code class="docutils literal notranslate"><span class="pre">restart</span></code>
|
||||
the server or <code class="docutils literal notranslate"><span class="pre">quit()</span></code> out of python mode they are gone.</p>
|
||||
<p>This is what you should have in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/monsters.py</span></code> so far:</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>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> This is a base class for Monsters.</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</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>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is moving!"</span><span class="p">)</span>
|
||||
|
||||
|
||||
<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"> """</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>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">move_around</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"The world trembles."</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">firebreath</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Let our dragon breathe fire.</span>
|
||||
<span class="sd"> """</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="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> breathes fire!"</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="our-first-persistent-object">
|
||||
<h2><span class="section-number">7.1. </span>Our first persistent object<a class="headerlink" href="#our-first-persistent-object" title="Permalink to this headline">¶</a></h2>
|
||||
<p>At this point we should know enough to understand what is happening in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code>. Let’s
|
||||
open it:</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>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>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>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Monster</span><span class="p">(</span><span class="n">Object</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> This is a base class for Monsters.</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>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is moving!"</span><span class="p">)</span>
|
||||
|
||||
|
||||
<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"> """</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>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">move_around</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"The world trembles."</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">firebreath</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> Let our dragon breathe fire.</span>
|
||||
<span class="sd"> """</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="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> breathes fire!"</span><span class="p">)</span>
|
||||
|
||||
</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>
|
||||
<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>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Dragon
|
||||
> smaug = Dragon(db_key="Smaug", db_location=here)
|
||||
> smaug.save()
|
||||
> smaug.move_around()
|
||||
Smaug is moving!
|
||||
The world trembles.
|
||||
</pre></div>
|
||||
</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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quit()
|
||||
Python Console is closing.
|
||||
> look
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You should now see that Smaug <em>is in the room with you</em>. Woah!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> 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>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()
|
||||
Smaug breathes fire!
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="creating-using-create-object">
|
||||
<h3><span class="section-number">7.1.2. </span>Creating using create_object<a class="headerlink" href="#creating-using-create-object" title="Permalink to this headline">¶</a></h3>
|
||||
<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)
|
||||
> 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!
|
||||
</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></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
|
||||
</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)
|
||||
</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>
|
||||
</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 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>
|
||||
<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.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>or</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py evennia.create_object("typeclasses.monsters.Monster", key="Giantess", location=here)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You are specifying exactly which typeclass you want to use to build the Giantess. Let’s examine the result:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> examine giantess
|
||||
-------------------------------------------------------------------------------
|
||||
Name/key: Giantess (#14)
|
||||
Typeclass: Monster (typeclasses.monsters.Monster)
|
||||
Location: Limbo (#2)
|
||||
Home: Limbo (#2)
|
||||
Permissions: <None>
|
||||
Locks: call:true(); control:id(1) or perm(Admin); delete:id(1) or perm(Admin);
|
||||
drop:holds(); edit:perm(Admin); examine:perm(Builder); get:all();
|
||||
puppet:pperm(Developer); tell:perm(Admin); view:all()
|
||||
Persistent attributes:
|
||||
desc = You see nothing special.
|
||||
-------------------------------------------------------------------------------
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We used the <code class="docutils literal notranslate"><span class="pre">examine</span></code> command briefly in the <a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">lesson about building in-game</span></a>. Now these lines
|
||||
may be more useful to us:</p>
|
||||
<ul class="simple">
|
||||
<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>
|
||||
</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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create/drop box
|
||||
You create a new Object: box.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>or</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py create.create_object(None, key="box", location=here)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now check it out:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> examine box
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You will find that the <strong>Typeclass</strong> line now reads</p>
|
||||
<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>
|
||||
<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>
|
||||
</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>
|
||||
</section>
|
||||
</section>
|
||||
<section id="modifying-ourselves">
|
||||
<h2><span class="section-number">7.3. </span>Modifying ourselves<a class="headerlink" href="#modifying-ourselves" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Let’s try to modify ourselves a little. Open up <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>.</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">DefaultCharacter</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</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>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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> examine me
|
||||
------------------------------------------------------------------------------
|
||||
Name/key: YourName (#1)
|
||||
Session id(s): #1
|
||||
Account: YourName
|
||||
Account Perms: <Superuser> (quelled)
|
||||
Typeclass: Character (typeclasses.characters.Character)
|
||||
Location: Limbo (#2)
|
||||
Home: Limbo (#2)
|
||||
Permissions: developer, player
|
||||
Locks: boot:false(); call:false(); control:perm(Developer); delete:false();
|
||||
drop:holds(); edit:false(); examine:perm(Developer); get:false();
|
||||
msg:all(); puppet:false(); tell:perm(Admin); view:all()
|
||||
Stored Cmdset(s):
|
||||
commands.default_cmdsets.CharacterCmdSet [DefaultCharacter] (Union, prio 0)
|
||||
Merged Cmdset(s):
|
||||
...
|
||||
Commands available to YourName (result of Merged CmdSets):
|
||||
...
|
||||
Persistent attributes:
|
||||
desc = This is User #1.
|
||||
prelogout_location = Limbo
|
||||
Non-Persistent attributes:
|
||||
last_cmd = None
|
||||
------------------------------------------------------------------------------
|
||||
</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>
|
||||
<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
|
||||
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>
|
||||
<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>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<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="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>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.get_stats()
|
||||
(10, 12, 15)
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Tuples and lists</p>
|
||||
<ul class="simple">
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre">list</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">d,</span> <span class="pre">...]</span></code>. It can be modified after creation.</p></li>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
</section>
|
||||
<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
|
||||
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
|
||||
12
|
||||
> py self.get_stats()
|
||||
(12, 12, 15)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This looks correct! Try to change the values for dex and int too; it works fine. However:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.get_stats()
|
||||
(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>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>
|
||||
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> (class docstring)</span>
|
||||
<span class="sd"> """</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>
|
||||
</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>
|
||||
</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>
|
||||
<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
|
||||
(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()
|
||||
(10, 12, 15)
|
||||
> reload
|
||||
> py self.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
|
||||
> py self.get_stats()
|
||||
(12, 12, 15)
|
||||
> reload
|
||||
> py self.get_stats()
|
||||
(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>
|
||||
</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>
|
||||
<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>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> (class docstring)</span>
|
||||
<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="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>
|
||||
</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
|
||||
set a random value from 3 to 18 to each stat. Simple, but for some classical RPGs this is all you need!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py self.get_stats()
|
||||
(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>
|
||||
<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()
|
||||
(5, 4, 8)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Lady luck didn’t smile on us for this example; maybe you’ll fare better. Evennia has a helper command
|
||||
<code class="docutils literal notranslate"><span class="pre">update</span></code> that re-runs the creation hook and also cleans up any other Attributes not re-created by <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> update self
|
||||
> py self.get_stats()
|
||||
(8, 16, 14)
|
||||
</pre></div>
|
||||
</div>
|
||||
</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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> 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>
|
||||
<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()
|
||||
</pre></div>
|
||||
</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>
|
||||
</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
|
||||
of all of them that we then immediately loop over. Boom, we just updated all Characters, including ourselves:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quit()
|
||||
Closing the Python console.
|
||||
> self.get_stats()
|
||||
(3, 18, 10)
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</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.
|
||||
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>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">7. </span>Making objects persistent</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,621 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>9. Parsing Command input — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="10. Creating things" href="Beginner-Tutorial-Creating-Things.html" />
|
||||
<link rel="prev" title="8. Adding custom commands" href="Beginner-Tutorial-Adding-Commands.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">9. </span>Parsing Command input</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">9. Parsing Command input</a><ul>
|
||||
<li><a class="reference internal" href="#more-advanced-parsing">9.1. More advanced parsing</a></li>
|
||||
<li><a class="reference internal" href="#adding-a-command-to-an-object">9.2. Adding a Command to an object</a><ul>
|
||||
<li><a class="reference internal" href="#you-need-to-hold-the-sword">9.2.1. You need to hold the sword!</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#adding-the-command-to-a-default-cmdset">9.3. Adding the Command to a default Cmdset</a><ul>
|
||||
<li><a class="reference internal" href="#removing-commands">9.3.1. Removing Commands</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#replace-a-default-command">9.4. Replace a default command</a></li>
|
||||
<li><a class="reference internal" href="#summary">9.5. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Adding-Commands.html"
|
||||
title="previous chapter"><span class="section-number">8. </span>Adding custom commands</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Creating-Things.html"
|
||||
title="next chapter"><span class="section-number">10. </span>Creating things</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-More-on-Commands.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-More-on-Commands.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="parsing-command-input">
|
||||
<h1><span class="section-number">9. </span>Parsing Command input<a class="headerlink" href="#parsing-command-input" title="Permalink to this headline">¶</a></h1>
|
||||
<p>In this lesson we learn some basics about parsing the input of Commands. We will
|
||||
also learn how to add, modify and extend Evennia’s default commands.</p>
|
||||
<section id="more-advanced-parsing">
|
||||
<h2><span class="section-number">9.1. </span>More advanced parsing<a class="headerlink" href="#more-advanced-parsing" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In the last lesson we made a <code class="docutils literal notranslate"><span class="pre">hit</span></code> Command and hit a dragon with it. You should have the code
|
||||
from that still around.</p>
|
||||
<p>Let’s expand our simple <code class="docutils literal notranslate"><span class="pre">hit</span></code> command to accept a little more complex input:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>hit <target> [[with] <weapon>]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That is, we want to support all of these forms</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>hit target
|
||||
hit target weapon
|
||||
hit target with weapon
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you don’t specify a weapon you’ll use your fists. It’s also nice to be able to skip “with” if
|
||||
you are in a hurry. Time to modify <code class="docutils literal notranslate"><span class="pre">mygame/commands/mycommands.py</span></code> again. Let us break out the parsing
|
||||
a little, in a new method <code class="docutils literal notranslate"><span class="pre">parse</span></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">CmdHit</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Hit a target.</span>
|
||||
|
||||
<span class="sd"> Usage:</span>
|
||||
<span class="sd"> hit <target></span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"hit"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">parse</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">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
<span class="n">target</span><span class="p">,</span> <span class="o">*</span><span class="n">weapon</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" with "</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="n">target</span><span class="p">,</span> <span class="o">*</span><span class="n">weapon</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="n">target</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">weapon</span> <span class="o">=</span> <span class="n">weapon</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">weapon</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">:</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Who do you want to hit?"</span><span class="p">)</span>
|
||||
<span class="k">return</span>
|
||||
<span class="c1"># get the target for the hit</span>
|
||||
<span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
<span class="c1"># get and handle the weapon</span>
|
||||
<span class="n">weapon</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="n">weapon</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">weapon</span><span class="p">:</span>
|
||||
<span class="n">weaponstr</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">weapon</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">weaponstr</span> <span class="o">=</span> <span class="s2">"bare fists"</span>
|
||||
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You hit </span><span class="si">{</span><span class="n">target</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> with </span><span class="si">{</span><span class="n">weaponstr</span><span class="si">}</span><span class="s2">!"</span><span class="p">)</span>
|
||||
<span class="n">target</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You got hit by </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> with </span><span class="si">{</span><span class="n">weaponstr</span><span class="si">}</span><span class="s2">!"</span><span class="p">)</span>
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">parse</span></code> method is called before <code class="docutils literal notranslate"><span class="pre">func</span></code> and has access to all the same on-command variables as in <code class="docutils literal notranslate"><span class="pre">func</span></code>. Using
|
||||
<code class="docutils literal notranslate"><span class="pre">parse</span></code> not only makes things a little easier to read, it also means you can easily let other Commands <em>inherit</em>
|
||||
your parsing - if you wanted some other Command to also understand input on the form <code class="docutils literal notranslate"><span class="pre"><arg></span> <span class="pre">with</span> <span class="pre"><arg></span></code> you’d inherit
|
||||
from this class and just implement the <code class="docutils literal notranslate"><span class="pre">func</span></code> needed for that command without implementing <code class="docutils literal notranslate"><span class="pre">parse</span></code> anew.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Tuples and Lists</p>
|
||||
<ul class="simple">
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre">list</span></code> is written as <code class="docutils literal notranslate"><span class="pre">[a,</span> <span class="pre">b,</span> <span class="pre">c,</span> <span class="pre">d,</span> <span class="pre">...]</span></code>. You can add and grow/shrink a list after it was first created.</p></li>
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre">tuple</span></code> is written as <code class="docutils literal notranslate"><span class="pre">(a,</span> <span class="pre">b,</span> <span class="pre">c,</span> <span class="pre">d,</span> <span class="pre">...)</span></code>. A tuple cannot be modified once it is created.</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<ul>
|
||||
<li><p><strong>Line 14</strong> - We do the stripping of <code class="docutils literal notranslate"><span class="pre">self.args</span></code> once and for all here. We also store the stripped version back
|
||||
into <code class="docutils literal notranslate"><span class="pre">self.args</span></code>, overwriting it. So there is no way to get back the non-stripped version from here on, which is fine
|
||||
for this command.</p></li>
|
||||
<li><p><strong>Line 15</strong> - This makes use of the <code class="docutils literal notranslate"><span class="pre">.split</span></code> method of strings. <code class="docutils literal notranslate"><span class="pre">.split</span></code> will, well, split the string by some criterion.
|
||||
<code class="docutils literal notranslate"><span class="pre">.split("</span> <span class="pre">with</span> <span class="pre">",</span> <span class="pre">1)</span></code> means “split the string once, around the substring <code class="docutils literal notranslate"><span class="pre">"</span> <span class="pre">with</span> <span class="pre">"</span></code> if it exists”. The result
|
||||
of this split is a <em>list</em>. Just how that list looks depends on the string we are trying to split:</p>
|
||||
<ol class="simple">
|
||||
<li><p>If we entered just <code class="docutils literal notranslate"><span class="pre">hit</span> <span class="pre">smaug</span></code>, we’d be splitting just <code class="docutils literal notranslate"><span class="pre">"smaug"</span></code> which would give the result <code class="docutils literal notranslate"><span class="pre">["smaug"]</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">hit</span> <span class="pre">smaug</span> <span class="pre">sword</span></code> gives <code class="docutils literal notranslate"><span class="pre">["smaug</span> <span class="pre">sword"]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">hit</span> <span class="pre">smaug</span> <span class="pre">with</span> <span class="pre">sword</span></code> gives <code class="docutils literal notranslate"><span class="pre">["smaug",</span> <span class="pre">"sword"]</span></code></p></li>
|
||||
</ol>
|
||||
<p>So we get a list of 1 or 2 elements. We assign it to two variables like this, <code class="docutils literal notranslate"><span class="pre">target,</span> <span class="pre">*weapon</span> <span class="pre">=</span> </code>. That
|
||||
asterisk in <code class="docutils literal notranslate"><span class="pre">*weapon</span></code> is a nifty trick - it will automatically become a list of <em>0 or more</em> values. It sorts of
|
||||
“soaks” up everything left over.</p>
|
||||
<ol class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> becomes <code class="docutils literal notranslate"><span class="pre">"smaug"</span></code> and <code class="docutils literal notranslate"><span class="pre">weapon</span></code> becomes <code class="docutils literal notranslate"><span class="pre">[]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> becomes <code class="docutils literal notranslate"><span class="pre">"smaug</span> <span class="pre">sword"</span></code> and <code class="docutils literal notranslate"><span class="pre">weapon</span></code> becomes <code class="docutils literal notranslate"><span class="pre">[]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> becomes <code class="docutils literal notranslate"><span class="pre">"smaug"</span></code> and <code class="docutils literal notranslate"><span class="pre">weapon</span></code> becomes <code class="docutils literal notranslate"><span class="pre">sword</span></code></p></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><p><strong>Lines 16-17</strong> - In this <code class="docutils literal notranslate"><span class="pre">if</span></code> condition we check if <code class="docutils literal notranslate"><span class="pre">weapon</span></code> is falsy (that is, the empty list). This can happen
|
||||
under two conditions (from the example above):</p>
|
||||
<ol class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> is simply <code class="docutils literal notranslate"><span class="pre">smaug</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> is <code class="docutils literal notranslate"><span class="pre">smaug</span> <span class="pre">sword</span></code></p></li>
|
||||
</ol>
|
||||
<p>To separate these cases we split <code class="docutils literal notranslate"><span class="pre">target</span></code> once again, this time by empty space <code class="docutils literal notranslate"><span class="pre">"</span> <span class="pre">"</span></code>. Again we store the
|
||||
result back with <code class="docutils literal notranslate"><span class="pre">target,</span> <span class="pre">*weapon</span> <span class="pre">=</span></code>. The result will be one of the following:</p>
|
||||
<ol class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> remains <code class="docutils literal notranslate"><span class="pre">smaug</span></code> and <code class="docutils literal notranslate"><span class="pre">weapon</span></code> remains <code class="docutils literal notranslate"><span class="pre">[]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">target</span></code> becomes <code class="docutils literal notranslate"><span class="pre">smaug</span></code> and <code class="docutils literal notranslate"><span class="pre">weapon</span></code> becomes <code class="docutils literal notranslate"><span class="pre">sword</span></code></p></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><p><strong>Lines 18-22</strong> - We now store <code class="docutils literal notranslate"><span class="pre">target</span></code> and <code class="docutils literal notranslate"><span class="pre">weapon</span></code> into <code class="docutils literal notranslate"><span class="pre">self.target</span></code> and <code class="docutils literal notranslate"><span class="pre">self.weapon</span></code>. We must do this in order
|
||||
for these local variables to made available in <code class="docutils literal notranslate"><span class="pre">func</span></code> later. Note how we need to check so <code class="docutils literal notranslate"><span class="pre">weapon</span></code> is not falsy
|
||||
before running <code class="docutils literal notranslate"><span class="pre">strip()</span></code> on it. This is because we know that if it’s falsy, it’s an empty list <code class="docutils literal notranslate"><span class="pre">[]</span></code> and lists
|
||||
don’t have the <code class="docutils literal notranslate"><span class="pre">.strip()</span></code> method on them (so if we tried to use it, we’d get an error).</p></li>
|
||||
</ul>
|
||||
<p>Now onto the <code class="docutils literal notranslate"><span class="pre">func</span></code> method. The main difference is we now have <code class="docutils literal notranslate"><span class="pre">self.target</span></code> and <code class="docutils literal notranslate"><span class="pre">self.weapon</span></code> available for
|
||||
convenient use.</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Lines 29 and 35</strong> - We make use of the previously parsed search terms for the target and weapon to find the
|
||||
respective resource.</p></li>
|
||||
<li><p><strong>Lines 34-39</strong> - Since the weapon is optional, we need to supply a default (use our fists!) if it’s not set. We
|
||||
use this to create a <code class="docutils literal notranslate"><span class="pre">weaponstr</span></code> that is different depending on if we have a weapon or not.</p></li>
|
||||
<li><p><strong>Lines 41-42</strong> - We merge the <code class="docutils literal notranslate"><span class="pre">weaponstr</span></code> with our attack text.</p></li>
|
||||
</ul>
|
||||
<p>Let’s try it out!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> hit smaug with sword
|
||||
Could not find 'sword'.
|
||||
You hit smaug with bare fists!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Oops, our <code class="docutils literal notranslate"><span class="pre">self.caller.search(self.weapon)</span></code> is telling us that it found no sword. Since we are not <code class="docutils literal notranslate"><span class="pre">return</span></code>ing
|
||||
in this situation (like we do if failing to find <code class="docutils literal notranslate"><span class="pre">target</span></code>) we still continue fighting with our bare hands.
|
||||
This won’t do. Let’s make ourselves a sword.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create sword
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Since we didn’t specify <code class="docutils literal notranslate"><span class="pre">/drop</span></code>, the sword will end up in our inventory and can seen with the <code class="docutils literal notranslate"><span class="pre">i</span></code> or
|
||||
<code class="docutils literal notranslate"><span class="pre">inventory</span></code> command. The <code class="docutils literal notranslate"><span class="pre">.search</span></code> helper will still find it there. There is no need to reload to see this
|
||||
change (no code changed, only stuff in the database).</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> hit smaug with sword
|
||||
You hit smaug with sword!
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="adding-a-command-to-an-object">
|
||||
<h2><span class="section-number">9.2. </span>Adding a Command to an object<a class="headerlink" href="#adding-a-command-to-an-object" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The commands of a cmdset attached to an object with <code class="docutils literal notranslate"><span class="pre">obj.cmdset.add()</span></code> will by default be made available to that object
|
||||
but <em>also to those in the same location as that object</em>. If you did the <a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">Building introduction</span></a>
|
||||
you’ve seen an example of this with the “Red Button” object. The <a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html"><span class="doc std std-doc">Tutorial world</span></a>
|
||||
also has many examples of objects with commands on them.</p>
|
||||
<p>To show how this could work, let’s put our ‘hit’ Command on our simple <code class="docutils literal notranslate"><span class="pre">sword</span></code> object from the previous section.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> self.search("sword").cmdset.add("commands.mycommands.MyCmdSet", persistent=True)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We find the sword (it’s still in our inventory so <code class="docutils literal notranslate"><span class="pre">self.search</span></code> should be able to find it), then
|
||||
add <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code> to it. This actually adds both <code class="docutils literal notranslate"><span class="pre">hit</span></code> and <code class="docutils literal notranslate"><span class="pre">echo</span></code> to the sword, which is fine.</p>
|
||||
<p>Let’s try to swing it!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> hit
|
||||
More than one match for 'hit' (please narrow target):
|
||||
hit-1 (sword #11)
|
||||
hit-2
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Multi-matches</p>
|
||||
<p>Some game engines will just pick the first hit when finding more than one. Evennia will always give you a choice. The reason for this is that Evennia cannot know if <code class="docutils literal notranslate"><span class="pre">hit</span></code> and <code class="docutils literal notranslate"><span class="pre">hit</span></code> are different or the same - maybe it behaves differently depending on the object it sits on? Besides, imagine if you had a red and a blue button both with the command <code class="docutils literal notranslate"><span class="pre">push</span></code> on it. Now you just write <code class="docutils literal notranslate"><span class="pre">push</span></code>. Wouldn’t you prefer to be asked <code class="docutils literal notranslate"><span class="pre">which</span></code> button you really wanted to push?</p>
|
||||
</aside>
|
||||
<p>Woah, that didn’t go as planned. Evennia actually found <em>two</em> <code class="docutils literal notranslate"><span class="pre">hit</span></code> commands to didn’t know which one to use
|
||||
(<em>we</em> know they are the same, but Evennia can’t be sure of that). As we can see, <code class="docutils literal notranslate"><span class="pre">hit-1</span></code> is the one found on
|
||||
the sword. The other one is from adding <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code> to ourself earlier. It’s easy enough to tell Evennia which
|
||||
one you meant:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> hit-1
|
||||
Who do you want to hit?
|
||||
> hit-2
|
||||
Who do you want to hit?
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In this case we don’t need both command-sets, so let’s just keep the one on the sword:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> self.cmdset.remove("commands.mycommands.MyCmdSet")
|
||||
> hit
|
||||
Who do you want to hit?
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> tunnel n = kitchen
|
||||
> n
|
||||
> drop sword
|
||||
> s
|
||||
> hit
|
||||
Command 'hit' is not available. Maybe you meant ...
|
||||
> n
|
||||
> hit
|
||||
Who do you want to hit?
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">hit</span></code> command is now only available if you hold or are in the same room as the sword.</p>
|
||||
<section id="you-need-to-hold-the-sword">
|
||||
<h3><span class="section-number">9.2.1. </span>You need to hold the sword!<a class="headerlink" href="#you-need-to-hold-the-sword" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Let’s get a little ahead of ourselves and make it so you have to <em>hold</em> the sword for the <code class="docutils literal notranslate"><span class="pre">hit</span></code> command to
|
||||
be available. This involves a <em>Lock</em>. We’ve cover locks in more detail later, just know that they are useful
|
||||
for limiting the kind of things you can do with an object, including limiting just when you can call commands on
|
||||
it.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Locks</p>
|
||||
<p>Evennia Locks are defined as a mini-language defined in <code class="docutils literal notranslate"><span class="pre">lockstrings</span></code>. The lockstring is on a form <code class="docutils literal notranslate"><span class="pre"><situation>:<lockfuncs></span></code>, where <code class="docutils literal notranslate"><span class="pre">situation</span></code> determines when this lock applies and the <code class="docutils literal notranslate"><span class="pre">lockfuncs</span></code> (there can be more than one) are run to determine if the lock-check passes or not depending on circumstance.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py self.search("sword").locks.add("call:holds()")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We added a new lock to the sword. The <em>lockstring</em> <code class="docutils literal notranslate"><span class="pre">"call:holds()"</span></code> means that you can only <em>call</em> commands on
|
||||
this object if you are <em>holding</em> the object (that is, it’s in your inventory).</p>
|
||||
<p>For locks to work, you cannot be <em>superuser</em>, since the superuser passes all locks. You need to <code class="docutils literal notranslate"><span class="pre">quell</span></code> yourself
|
||||
first:</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">quell/unquell</p>
|
||||
<p>Quelling allows you as a developer to take on the role of players with less priveleges. This is useful for testing and debugging, in particular since a superuser has a little <code class="docutils literal notranslate"><span class="pre">too</span></code> much power sometimes. Use <code class="docutils literal notranslate"><span class="pre">unquell</span></code> to get back to your normal self.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quell
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the sword lies on the ground, try</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> hit
|
||||
Command 'hit' is not available. ..
|
||||
> get sword
|
||||
> hit
|
||||
> Who do you want to hit?
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Finally, we get rid of ours sword so we have a clean slate with no more <code class="docutils literal notranslate"><span class="pre">hit</span></code> commands floating around.
|
||||
We can do that in two ways:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>delete sword
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>or</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py self.search("sword").delete()
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="adding-the-command-to-a-default-cmdset">
|
||||
<h2><span class="section-number">9.3. </span>Adding the Command to a default Cmdset<a class="headerlink" href="#adding-the-command-to-a-default-cmdset" title="Permalink to this headline">¶</a></h2>
|
||||
<p>As we have seen we can use <code class="docutils literal notranslate"><span class="pre">obj.cmdset.add()</span></code> to add a new cmdset to objects, whether that object
|
||||
is ourself (<code class="docutils literal notranslate"><span class="pre">self</span></code>) or other objects like the <code class="docutils literal notranslate"><span class="pre">sword</span></code>.</p>
|
||||
<p>This is how all commands in Evennia work, including default commands like <code class="docutils literal notranslate"><span class="pre">look</span></code>, <code class="docutils literal notranslate"><span class="pre">dig</span></code>, <code class="docutils literal notranslate"><span class="pre">inventory</span></code> and so on.
|
||||
All these commands are in just loaded on the default objects that Evennia provides out of the box.</p>
|
||||
<ul class="simple">
|
||||
<li><p>Characters (that is ‘you’ in the gameworld) has the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>.</p></li>
|
||||
<li><p>Accounts (the thing that represents your out-of-character existence on the server) has the <code class="docutils literal notranslate"><span class="pre">AccountCmdSet</span></code></p></li>
|
||||
<li><p>Sessions (representing one single client connection) has the <code class="docutils literal notranslate"><span class="pre">SessionCmdSet</span></code></p></li>
|
||||
<li><p>Before you log in (at the connection screen) you’ll have access to the <code class="docutils literal notranslate"><span class="pre">UnloggedinCmdSet</span></code>.</p></li>
|
||||
</ul>
|
||||
<p>The thing must commonly modified is the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>.</p>
|
||||
<p>The default cmdset are defined in <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code>. Open that file now:</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">default_cmds</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultCharacter"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">AccountCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">AccountCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultAccount"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">UnloggedinCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">UnloggedinCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultUnloggedin"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">SessionCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">SessionCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultSession"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">super()</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">super()</span></code> function refers to the parent of the current class and is commonly used to call same-named methods on the parent.</p>
|
||||
</aside>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">evennia.default_cmds</span></code> is a container that holds all of Evennia’s default commands and cmdsets. In this module
|
||||
we can see that this was imported and then a new child class was made for each cmdset. Each class looks familiar
|
||||
(except the <code class="docutils literal notranslate"><span class="pre">key</span></code>, that’s mainly used to easily identify the cmdset in listings). In each <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code> all
|
||||
we do is call <code class="docutils literal notranslate"><span class="pre">super().at_cmdset_creation</span></code> which means that we call `at_cmdset_creation() on the <em>parent</em> CmdSet.
|
||||
This is what adds all the default commands to each CmdSet.</p>
|
||||
<p>To add even more Commands to a default cmdset, we can just add them below the <code class="docutils literal notranslate"><span class="pre">super()</span></code> line. Usefully, if we were to
|
||||
add a Command with the same <code class="docutils literal notranslate"><span class="pre">.key</span></code> as a default command, it would completely replace that original. So if you were
|
||||
to add a command with a key <code class="docutils literal notranslate"><span class="pre">look</span></code>, the original <code class="docutils literal notranslate"><span class="pre">look</span></code> command would be replaced by your own version.</p>
|
||||
<p>For now, let’s add our own <code class="docutils literal notranslate"><span class="pre">hit</span></code> and <code class="docutils literal notranslate"><span class="pre">echo</span></code> commands to the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">mycommands</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultCharacter"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">CmdEcho</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">CmdHit</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> hit
|
||||
Who do you want to hit?
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Your new commands are now available for all player characters in the game. There is another way to add a bunch
|
||||
of commands at once, and that is to add a <em>CmdSet</em> to the other cmdset. All commands in that cmdset will then be added:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">mycommands</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultCharacter"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCmdSet</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Which way you use depends on how much control you want, but if you already have a CmdSet,
|
||||
this is practical. A Command can be a part of any number of different CmdSets.</p>
|
||||
<section id="removing-commands">
|
||||
<h3><span class="section-number">9.3.1. </span>Removing Commands<a class="headerlink" href="#removing-commands" title="Permalink to this headline">¶</a></h3>
|
||||
<p>To remove your custom commands again, you of course just delete the change you did to
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code>. But what if you want to remove a default command?</p>
|
||||
<p>We already know that we use <code class="docutils literal notranslate"><span class="pre">cmdset.remove()</span></code> to remove a cmdset. It turns out you can
|
||||
do the same in <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code>. For example, let’s remove the default <code class="docutils literal notranslate"><span class="pre">get</span></code> Command
|
||||
from Evennia. We happen to know this can be found as <code class="docutils literal notranslate"><span class="pre">default_cmds.CmdGet</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">mycommands</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultCharacter"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCmdSet</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdGet</span><span class="p">)</span>
|
||||
<span class="c1"># ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> get
|
||||
Command 'get' is not available ...
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="replace-a-default-command">
|
||||
<h2><span class="section-number">9.4. </span>Replace a default command<a class="headerlink" href="#replace-a-default-command" title="Permalink to this headline">¶</a></h2>
|
||||
<p>At this point you already have all the pieces for how to do this! We just need to add a new
|
||||
command with the same <code class="docutils literal notranslate"><span class="pre">key</span></code> in the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code> to replace the default one.</p>
|
||||
<p>Let’s combine this with what we know about classes and
|
||||
how to <em>override</em> a parent class. Open <code class="docutils literal notranslate"><span class="pre">mygame/commands/mycommands.py</span></code> and lets override
|
||||
that <code class="docutils literal notranslate"><span class="pre">CmdGet</span></code> command.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># up top, by the other imports</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
|
||||
|
||||
<span class="c1"># somewhere below</span>
|
||||
<span class="k">class</span> <span class="nc">MyCmdGet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdGet</span><span class="p">):</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">func</span><span class="p">()</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">contents</span><span class="p">))</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Line2</strong>: We import <code class="docutils literal notranslate"><span class="pre">default_cmds</span></code> so we can get the parent class.
|
||||
We made a new class and we make it <em>inherit</em> <code class="docutils literal notranslate"><span class="pre">default_cmds.CmdGet</span></code>. We don’t
|
||||
need to set <code class="docutils literal notranslate"><span class="pre">.key</span></code> or <code class="docutils literal notranslate"><span class="pre">.parse</span></code>, that’s already handled by the parent.
|
||||
In <code class="docutils literal notranslate"><span class="pre">func</span></code> we call <code class="docutils literal notranslate"><span class="pre">super().func()</span></code> to let the parent do its normal thing,</p></li>
|
||||
<li><p><strong>Line 7</strong>: By adding our own <code class="docutils literal notranslate"><span class="pre">func</span></code> we replace the one in the parent.</p></li>
|
||||
<li><p><strong>Line 8</strong>: For this simple change we still want the command to work the
|
||||
same as before, so we use <code class="docutils literal notranslate"><span class="pre">super()</span></code> to call <code class="docutils literal notranslate"><span class="pre">func</span></code> on the parent.</p></li>
|
||||
<li><p><strong>Line 9</strong>: <code class="docutils literal notranslate"><span class="pre">.location</span></code> is the place an object is at. <code class="docutils literal notranslate"><span class="pre">.contents</span></code> contains, well, the
|
||||
contents of an object. If you tried <code class="docutils literal notranslate"><span class="pre">py</span> <span class="pre">self.contents</span></code> you’d get a list that equals
|
||||
your inventory. For a room, the contents is everything in it.
|
||||
So <code class="docutils literal notranslate"><span class="pre">self.caller.location.contents</span></code> gets the contents of our current location. This is
|
||||
a <em>list</em>. In order send this to us with <code class="docutils literal notranslate"><span class="pre">.msg</span></code> we turn the list into a string. Python
|
||||
has a special function <code class="docutils literal notranslate"><span class="pre">str()</span></code> to do this.</p></li>
|
||||
</ul>
|
||||
<p>We now just have to add this so it replaces the default <code class="docutils literal notranslate"><span class="pre">get</span></code> command. Open
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code> again:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
|
||||
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">mycommands</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"DefaultCharacter"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># any commands you add below will overload the default ones</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCmdSet</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCmdGet</span><span class="p">)</span>
|
||||
<span class="c1"># ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Another way</p>
|
||||
<p>Instead of adding <code class="docutils literal notranslate"><span class="pre">MyCmdGet</span></code> explicitly in default_cmdset.py, you could also add it to <code class="docutils literal notranslate"><span class="pre">mycommands.MyCmdSet</span></code> and let it be added automatically here for you.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> get
|
||||
Get What?
|
||||
[smaug, fluffy, YourName, ...]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We just made a new <code class="docutils literal notranslate"><span class="pre">get</span></code>-command that tells us everything we could pick up (well, we can’t pick up ourselves, so
|
||||
there’s some room for improvement there).</p>
|
||||
</section>
|
||||
<section id="summary">
|
||||
<h2><span class="section-number">9.5. </span>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In this lesson we got into some more advanced string formatting - many of those tricks will help you a lot in
|
||||
the future! We also made a functional sword. Finally we got into how to add to, extend and replace a default
|
||||
command on ourselves.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">9. </span>Parsing Command input</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>Part 1: What we have — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="1. Using commands and building stuff" href="Beginner-Tutorial-Building-Quickstart.html" />
|
||||
<link rel="prev" title="Beginner Tutorial" href="../Beginner-Tutorial-Intro.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Beginner-Tutorial-Intro.html" title="Beginner Tutorial"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" accesskey="U">Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Part 1: What we have</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Part 1: What we have</a><ul>
|
||||
<li><a class="reference internal" href="#lessons">Lessons</a></li>
|
||||
<li><a class="reference internal" href="#table-of-contents">Table of Contents</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="../Beginner-Tutorial-Intro.html"
|
||||
title="previous chapter">Beginner Tutorial</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Building-Quickstart.html"
|
||||
title="next chapter"><span class="section-number">1. </span>Using commands and building stuff</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Intro.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Part1-Intro.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="part-1-what-we-have">
|
||||
<h1>Part 1: What we have<a class="headerlink" href="#part-1-what-we-have" title="Permalink to this headline">¶</a></h1>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Beginner Tutorial Parts</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../Beginner-Tutorial-Intro.html"><span class="doc std std-doc">Introduction</span></a>
|
||||
<br>Getting set up.</p></li>
|
||||
<li><p>Part 1: <strong><a class="reference internal" href="#"><span class="doc std std-doc">What we have</span></a></strong>
|
||||
<br>A tour of Evennia and how to use the tools, including an introduction to Python.</p></li>
|
||||
<li><p>Part 2: <a class="reference internal" href="../Part2/Beginner-Tutorial-Part2-Intro.html"><span class="doc std std-doc">What we want</span></a>
|
||||
<br>Planning our tutorial game and what to think about when planning your own in the future.</p></li>
|
||||
<li><p>Part 3: <a class="reference internal" href="../Part3/Beginner-Tutorial-Part3-Intro.html"><span class="doc std std-doc">How we get there</span></a>
|
||||
<br>Getting down to the meat of extending Evennia to make our game</p></li>
|
||||
<li><p>Part 4: <a class="reference internal" href="../Part4/Beginner-Tutorial-Part4-Intro.html"><span class="doc std std-doc">Using what we created</span></a>
|
||||
<br>Building a tech-demo and world content to go with our code</p></li>
|
||||
<li><p>Part 5: <a class="reference internal" href="../Part5/Beginner-Tutorial-Part5-Intro.html"><span class="doc std std-doc">Showing the world</span></a>
|
||||
<br>Taking our new game online and let players try it out</p></li>
|
||||
</ul>
|
||||
</aside>
|
||||
<p>In this first part we’ll focus on what we get out of the box in Evennia - we’ll get used to the tools,
|
||||
and how to find things we are looking for. We will also dive into some of things you’ll
|
||||
need to know to fully utilize the system, including giving you a brief rundown of Python concepts. If you are
|
||||
an experienced Python programmer, some sections may feel a bit basic, but you will at least not have seen
|
||||
these concepts in the context of Evennia before.</p>
|
||||
<section id="lessons">
|
||||
<h2>Lessons<a class="headerlink" href="#lessons" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html">1. Using commands and building stuff</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html">2. The Tutorial World</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html">3. Intro to using Python with Evennia</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html">4. Overview of your new Game Dir</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html">5. Introduction to Python classes and objects</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html">6. Overview of the Evennia library</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html">8. Adding custom commands</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html">9. Parsing Command input</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html">10. Creating things</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html">11. Searching for things</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html">12. Advanced searching - Django Database queries</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section id="table-of-contents">
|
||||
<h2>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html">1. Using commands and building stuff</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#getting-help">1.1. Getting help</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#looking-around">1.2. Looking around</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#stepping-down-from-godhood">1.3. Stepping Down From Godhood</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#creating-an-object">1.4. Creating an Object</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#get-a-personality">1.5. Get a Personality</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#pushing-your-buttons">1.6. Pushing Your Buttons</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#making-yourself-a-house">1.7. Making Yourself a House</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#reshuffling-the-world">1.8. Reshuffling the World</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#adding-a-help-entry">1.9. Adding a Help Entry</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#adding-a-world">1.10. Adding a World</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html">2. The Tutorial World</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html#gameplay">2.1. Gameplay</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html#once-you-are-done-or-had-enough">2.2. Once you are done (or had enough)</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html#uninstall-the-tutorial-world">2.3. Uninstall the tutorial world</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html">3. Intro to using Python with Evennia</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#evennia-hello-world">3.1. Evennia Hello world</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#making-some-text-graphics">3.2. Making some text ‘graphics’</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#importing-code-from-other-modules">3.3. Importing code from other modules</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#sending-text-to-others">3.4. Sending text to others</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#parsing-python-errors">3.5. Parsing Python errors</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#passing-arguments-to-functions">3.6. Passing arguments to functions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#finding-others-to-send-to">3.7. Finding others to send to</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#multi-line-py">3.8. Multi-line py</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#other-ways-to-test-python-code">3.9. Other ways to test Python code</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#ipython">3.10. ipython</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#conclusions">3.11. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html">4. Overview of your new Game Dir</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html#commands">4.1. commands/</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html#server">4.2. server/</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html">5. Introduction to Python classes and objects</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#importing-things">5.1. Importing things</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#on-classes-and-objects">5.2. On classes and objects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#summary">5.3. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<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>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#our-first-persistent-object">7.1. Our first persistent object</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#typeclasses">7.2. Typeclasses</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#modifying-ourselves">7.3. Modifying ourselves</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#extra-credits">7.4. Extra Credits</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#conclusions">7.5. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html">8. Adding custom commands</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html#creating-a-custom-command">8.1. Creating a custom command</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html#summary">8.2. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html">9. Parsing Command input</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#more-advanced-parsing">9.1. More advanced parsing</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#adding-a-command-to-an-object">9.2. Adding a Command to an object</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#adding-the-command-to-a-default-cmdset">9.3. Adding the Command to a default Cmdset</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#replace-a-default-command">9.4. Replace a default command</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#summary">9.5. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html">10. Creating things</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html#creating-objects">10.1. Creating Objects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html#creating-accounts">10.2. Creating Accounts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html">11. Searching for things</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#main-search-functions">11.1. Main search functions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#searching-using-object-search">11.2. Searching using Object.search</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#what-can-be-searched-for">11.3. What can be searched for</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#finding-objects-relative-each-other">11.4. Finding objects relative each other</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#summary">11.5. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html">12. Advanced searching - Django Database queries</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#queryset-field-lookups">12.1. Queryset field lookups</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#get-that-werewolf">12.2. Get that werewolf …</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#complex-queries">12.3. Complex queries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#annotations">12.4. Annotations</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#f-objects">12.5. F-objects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#grouping-and-returning-only-certain-properties">12.6. Grouping and returning only certain properties</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#conclusions">12.7. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Beginner-Tutorial-Intro.html" title="Beginner Tutorial"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Part 1: What we have</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,771 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>3. Intro to using Python with Evennia — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="4. Overview of your new Game Dir" href="Beginner-Tutorial-Gamedir-Overview.html" />
|
||||
<link rel="prev" title="2. The Tutorial World" href="Beginner-Tutorial-Tutorial-World.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">3. </span>Intro to using Python with Evennia</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">3. Intro to using Python with Evennia</a><ul>
|
||||
<li><a class="reference internal" href="#evennia-hello-world">3.1. Evennia Hello world</a></li>
|
||||
<li><a class="reference internal" href="#making-some-text-graphics">3.2. Making some text ‘graphics’</a><ul>
|
||||
<li><a class="reference internal" href="#format">3.2.1. .format()</a></li>
|
||||
<li><a class="reference internal" href="#f-strings">3.2.2. f-strings</a></li>
|
||||
<li><a class="reference internal" href="#colored-text">3.2.3. Colored text</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#importing-code-from-other-modules">3.3. Importing code from other modules</a><ul>
|
||||
<li><a class="reference internal" href="#our-first-own-function">3.3.1. Our first own function</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#sending-text-to-others">3.4. Sending text to others</a></li>
|
||||
<li><a class="reference internal" href="#parsing-python-errors">3.5. Parsing Python errors</a></li>
|
||||
<li><a class="reference internal" href="#passing-arguments-to-functions">3.6. Passing arguments to functions</a></li>
|
||||
<li><a class="reference internal" href="#finding-others-to-send-to">3.7. Finding others to send to</a></li>
|
||||
<li><a class="reference internal" href="#multi-line-py">3.8. Multi-line py</a></li>
|
||||
<li><a class="reference internal" href="#other-ways-to-test-python-code">3.9. Other ways to test Python code</a></li>
|
||||
<li><a class="reference internal" href="#ipython">3.10. ipython</a></li>
|
||||
<li><a class="reference internal" href="#conclusions">3.11. Conclusions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Tutorial-World.html"
|
||||
title="previous chapter"><span class="section-number">2. </span>The Tutorial World</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Gamedir-Overview.html"
|
||||
title="next chapter"><span class="section-number">4. </span>Overview of your new Game Dir</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Python-basic-introduction.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Python-basic-introduction.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="intro-to-using-python-with-evennia">
|
||||
<h1><span class="section-number">3. </span>Intro to using Python with Evennia<a class="headerlink" href="#intro-to-using-python-with-evennia" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Time to dip our toe into some coding! Evennia is written and extended in <a class="reference external" href="https://python.org">Python</a>,
|
||||
which is a mature and professional programming language that is very fast to work with.</p>
|
||||
<p>That said, even though Python is widely considered easy to learn, we can only cover the most immediately
|
||||
important aspects of Python in this series of starting tutorials. Hopefully we can get you started
|
||||
but then you’ll need to continue learning from there. See our <a class="reference internal" href="../../../Links.html"><span class="doc std std-doc">link section</span></a> for finding
|
||||
more reference material and dedicated Python tutorials.</p>
|
||||
<blockquote>
|
||||
<div><p>While this will be quite basic if you are an experienced developer, you may want to at least
|
||||
stay around for the first few sections where we cover how to run Python from inside Evennia.</p>
|
||||
</div></blockquote>
|
||||
<p>First, if you were quelling yourself to play the tutorial world, make sure to get your
|
||||
superuser powers back:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> unquell
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="evennia-hello-world">
|
||||
<h2><span class="section-number">3.1. </span>Evennia Hello world<a class="headerlink" href="#evennia-hello-world" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">py</span></code> Command (or <code class="docutils literal notranslate"><span class="pre">!</span></code>, which is an alias) allows you as a superuser to execute raw Python from in-
|
||||
game. This is useful for quick testing. From the game’s input line, enter the following:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("Hello World!")
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Command input</p>
|
||||
<p>The line with <code class="docutils literal notranslate"><span class="pre">></span></code> indicates input to enter in-game, while the lines below are the
|
||||
expected return from that input.</p>
|
||||
</aside>
|
||||
<p>You will see</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> print("Hello world!")
|
||||
Hello World!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To understand what is going on: some extra info: The <code class="docutils literal notranslate"><span class="pre">print(...)</span></code> <em>function</em> is the basic, in-built
|
||||
way to output text in Python. We are sending “Hello World” as an <em>argument</em> to this function. The quotes <code class="docutils literal notranslate"><span class="pre">"..."</span></code>
|
||||
mean that you are inputting a <em>string</em> (i.e. text). You could also have used single-quotes <code class="docutils literal notranslate"><span class="pre">'...'</span></code>,
|
||||
Python accepts both. A third variant is triple-quotes (<code class="docutils literal notranslate"><span class="pre">"""..."""</span></code> or <code class="docutils literal notranslate"><span class="pre">'''...'''</span></code>, which work across multiple
|
||||
lines and are common for larger text-blocks. The way we use the <code class="docutils literal notranslate"><span class="pre">py</span></code> command right now only supports
|
||||
single-line input however.</p>
|
||||
</section>
|
||||
<section id="making-some-text-graphics">
|
||||
<h2><span class="section-number">3.2. </span>Making some text ‘graphics’<a class="headerlink" href="#making-some-text-graphics" title="Permalink to this headline">¶</a></h2>
|
||||
<p>When making a text-game you will, unsurprisingly, be working a lot with text. Even if you have the occational
|
||||
button or even graphical element, the normal process is for the user to input commands as
|
||||
text and get text back. As we saw above, a piece of text is called a <em>string</em> in Python and is enclosed in
|
||||
either single- or double-quotes.</p>
|
||||
<p>Strings can be added together:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("This is a " + "breaking change.")
|
||||
This is a breaking change.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A string multiplied with a number will repeat that string as many times:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("|" + "-" * 40 + "|")
|
||||
|----------------------------------------|
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>or</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("A" + "a" * 5 + "rgh!")
|
||||
Aaaaaargh!
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="format">
|
||||
<h3><span class="section-number">3.2.1. </span>.format()<a class="headerlink" href="#format" title="Permalink to this headline">¶</a></h3>
|
||||
<p>While combining different strings is useful, even more powerful is the ability to modify the contents
|
||||
of the string in-place. There are several ways to do this in Python and we’ll show two of them here. The first
|
||||
is to use the <code class="docutils literal notranslate"><span class="pre">.format</span></code> <em>method</em> of the string:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("This is a {} idea!".format("good"))
|
||||
This is a good idea!
|
||||
</pre></div>
|
||||
</div>
|
||||
<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>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>
|
||||
<p>A method can be thought of as a resource “on” another object. The method knows on which object it
|
||||
sits and can thus affect it in various ways. You access it with the period <code class="docutils literal notranslate"><span class="pre">.</span></code>. In this case, the
|
||||
string has a resource <code class="docutils literal notranslate"><span class="pre">format(...)</span></code> that modifies it. More specifically, it replaced the <code class="docutils literal notranslate"><span class="pre">{}</span></code> marker
|
||||
inside the string with the value passed to the format. You can do so many times:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("This is a {} idea!".format("bad"))
|
||||
This is a bad idea!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>or</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("This is the {} and {} {} idea!".format("first", "second", "great"))
|
||||
This is the first and second great idea!
|
||||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Note the double-parenthesis at the end - the first closes the <code class="docutils literal notranslate"><span class="pre">format(...</span></code> method and the outermost
|
||||
closes the <code class="docutils literal notranslate"><span class="pre">print(...</span></code>. Not closing them will give you a scary <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code>. We will talk a
|
||||
little more about errors in the next section, for now just fix until it prints as expected.</p>
|
||||
</div></blockquote>
|
||||
<p>Here we passed three comma-separated strings as <em>arguments</em> to the string’s <code class="docutils literal notranslate"><span class="pre">format</span></code> method. These
|
||||
replaced the <code class="docutils literal notranslate"><span class="pre">{}</span></code> markers in the same order as they were given.</p>
|
||||
<p>The input does not have to be strings either:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("STR: {}, DEX: {}, INT: {}".format(12, 14, 8))
|
||||
STR: 12, DEX: 14, INT: 8
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To separate two Python instructions on the same line, you use the semi-colon, <code class="docutils literal notranslate"><span class="pre">;</span></code>. Try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py a = "awesome sauce" ; print("This is {}!".format(a))
|
||||
This is awesome sauce!
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>MUD clients and semi-colon</p>
|
||||
<p>Some MUD clients use the semi-colon <code class="docutils literal notranslate"><span class="pre">;</span></code> to split client-inputs
|
||||
into separate sends. If so, the above will give an error. Most clients allow you to
|
||||
run in ‘verbatim’ mode or to remap to use some other separator than <code class="docutils literal notranslate"><span class="pre">;</span></code>. If you still have
|
||||
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>
|
||||
<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>
|
||||
</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
|
||||
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>
|
||||
</div>
|
||||
<p>An f-string on its own is just like any other string. But let’s redo the example we did before, using an f-string:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py a = "awesome sauce" ; print(f"This is {a}!")
|
||||
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
|
||||
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
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We will be exploring more complex string concepts when we get to creating Commands and need to
|
||||
parse and understand player input.</p>
|
||||
</section>
|
||||
<section id="colored-text">
|
||||
<h3><span class="section-number">3.2.3. </span>Colored text<a class="headerlink" href="#colored-text" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Python itself knows nothing about colored text, this is an Evennia thing. Evennia supports the
|
||||
standard color schemes of traditional MUDs.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("|rThis is red text!|n This is normal color.")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Adding that <code class="docutils literal notranslate"><span class="pre">|r</span></code> at the start will turn our output bright red. <code class="docutils literal notranslate"><span class="pre">|R</span></code> will make it dark red. <code class="docutils literal notranslate"><span class="pre">|n</span></code>
|
||||
gives the normal text color. You can also use RGB (Red-Green-Blue) values from 0-5 (Xterm256 colors):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py print("|043This is a blue-green color.|[530|003 Now dark blue text on orange background.")
|
||||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<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>
|
||||
</section>
|
||||
</section>
|
||||
<section id="importing-code-from-other-modules">
|
||||
<h2><span class="section-number">3.3. </span>Importing code from other modules<a class="headerlink" href="#importing-code-from-other-modules" title="Permalink to this headline">¶</a></h2>
|
||||
<p>As we saw in the previous sections, we used <code class="docutils literal notranslate"><span class="pre">.format</span></code> to format strings and <code class="docutils literal notranslate"><span class="pre">me.msg</span></code> to access
|
||||
the <code class="docutils literal notranslate"><span class="pre">msg</span></code> method on <code class="docutils literal notranslate"><span class="pre">me</span></code>. This use of the full-stop character is used to access all sorts of resources,
|
||||
including that in other Python modules.</p>
|
||||
<p>Keep your game running, then open a text editor of your choice. If your game folder is called
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame</span></code>, create a new text file <code class="docutils literal notranslate"><span class="pre">test.py</span></code> in the subfolder <code class="docutils literal notranslate"><span class="pre">mygame/world</span></code>. This is how the file
|
||||
structure should look:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mygame</span><span class="o">/</span>
|
||||
<span class="n">world</span><span class="o">/</span>
|
||||
<span class="n">test</span><span class="o">.</span><span class="n">py</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For now, only add one line to <code class="docutils literal notranslate"><span class="pre">test.py</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="s2">"Hello World!"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Python module</p>
|
||||
<p>This is a text file with the <code class="docutils literal notranslate"><span class="pre">.py</span></code> file ending. A module
|
||||
contains Python source code and from within Python one can
|
||||
access its contents by importing it via its python-path.</p>
|
||||
</aside>
|
||||
<p>Don’t forget to <em>save</em> the file. We just created our first Python <em>module</em>!
|
||||
To use this in-game we have to <em>import</em> it. Try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test
|
||||
Hello World
|
||||
</pre></div>
|
||||
</div>
|
||||
<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>
|
||||
<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>Try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>And then</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test
|
||||
Hello World!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now we see it again. The <code class="docutils literal notranslate"><span class="pre">reload</span></code> wiped the server’s memory of what was imported, so it had to
|
||||
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></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>
|
||||
<p>We want to be able to print our hello-world message at any time, not just once after a server
|
||||
reload. Change your <code class="docutils literal notranslate"><span class="pre">mygame/world/test.py</span></code> file to look like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hello_world</span><span class="p">():</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Hello World!"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>As we are moving to multi-line Python code, there are some important things to remember:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Capitalization matters in Python. It must be <code class="docutils literal notranslate"><span class="pre">def</span></code> and not <code class="docutils literal notranslate"><span class="pre">DEF</span></code>, <code class="docutils literal notranslate"><span class="pre">who</span></code> is not the same as <code class="docutils literal notranslate"><span class="pre">Who</span></code>.</p></li>
|
||||
<li><p>Indentation matters in Python. The second line must be indented or it’s not valid code. You should
|
||||
also use a consistent indentation length. We <em>strongly</em> recommend that you, for your own sanity’s sake,
|
||||
set up your editor to always indent <em>4 spaces</em> (<strong>not</strong> a single tab-character) when you press the TAB key.</p></li>
|
||||
</ul>
|
||||
<p>So about that function. Line 1:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">def</span></code> is short for “define” and defines a <em>function</em> (or a <em>method</em>, if sitting on an object).
|
||||
This is a <a class="reference external" href="https://docs.python.org/2.5/ref/keywords.html">reserved Python keyword</a>; try not to use
|
||||
these words anywhere else.</p></li>
|
||||
<li><p>A function name can not have spaces but otherwise we could have called it almost anything. We call
|
||||
it <code class="docutils literal notranslate"><span class="pre">hello_world</span></code>. Evennia follows <a class="reference external" href="https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style-points">Python’s standard naming style</a>
|
||||
with lowercase letters and underscores. We recommend you do the same.</p></li>
|
||||
<li><p>The colon (<code class="docutils literal notranslate"><span class="pre">:</span></code>) at the end of line 1 indicates that the header of the function is complete.</p></li>
|
||||
</ul>
|
||||
<p>Line 2:</p>
|
||||
<ul class="simple">
|
||||
<li><p>The indentation marks the beginning of the actual operating code of the function (the function’s
|
||||
<em>body</em>). If we wanted more lines to belong to this function those lines would all have to
|
||||
start at least at this indentation level.</p></li>
|
||||
</ul>
|
||||
<p>Now let’s try this out. First <code class="docutils literal notranslate"><span class="pre">reload</span></code> your game to have it pick up
|
||||
our updated Python module, then import it.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> reload
|
||||
> py import world.test
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Nothing happened! That is because the function in our module won’t do anything just by importing it (this
|
||||
is what we wanted). It will only act when we <em>call</em> it. So we need to first import the module and then access the
|
||||
function within:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test ; world.test.hello_world()
|
||||
Hello world!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>There is our “Hello World”! As mentioned earlier, use use semi-colon to put multiple
|
||||
Python-statements on one line. Note also the previous warning about mud-clients using the <code class="docutils literal notranslate"><span class="pre">;</span></code> to their
|
||||
own ends.</p>
|
||||
<p>So what happened there? First we imported <code class="docutils literal notranslate"><span class="pre">world.test</span></code> as usual. But this time we continued and
|
||||
accessed the <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> function <em>inside</em> the newly imported module.</p>
|
||||
<p>By adding <code class="docutils literal notranslate"><span class="pre">()</span></code> to the <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> function we <em>call</em> it, that is we run the body of the function and
|
||||
print our text. We can now redo this as many times as we want without having to <code class="docutils literal notranslate"><span class="pre">reload</span></code> in between:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test ; world.test.hello_world()
|
||||
Hello world!
|
||||
> py import world.test ; world.test.hello_world()
|
||||
Hello world!
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="sending-text-to-others">
|
||||
<h2><span class="section-number">3.4. </span>Sending text to others<a class="headerlink" href="#sending-text-to-others" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">print</span></code> command is a standard Python structure. We can use that here in the <code class="docutils literal notranslate"><span class="pre">py</span></code> command since
|
||||
we can se the output. It’s great for debugging and quick testing. But if you need to send a text
|
||||
to an actual player, <code class="docutils literal notranslate"><span class="pre">print</span></code> won’t do, because it doesn’t know <em>who</em> to send to. Try this:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py me.msg("Hello world!")
|
||||
Hello world!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This looks the same as the <code class="docutils literal notranslate"><span class="pre">print</span></code> result, but we are now actually messaging a specific <em>object</em>,
|
||||
<code class="docutils literal notranslate"><span class="pre">me</span></code>. The <code class="docutils literal notranslate"><span class="pre">me</span></code> is a shortcut to ‘us’, the one running the <code class="docutils literal notranslate"><span class="pre">py</span></code> command. It is not some special
|
||||
Python thing, but something Evennia just makes available in the <code class="docutils literal notranslate"><span class="pre">py</span></code> command for convenience
|
||||
(<code class="docutils literal notranslate"><span class="pre">self</span></code> is an alias).</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">me</span></code> is an example of an <em>Object instance</em>. Objects are fundamental in Python and Evennia.
|
||||
The <code class="docutils literal notranslate"><span class="pre">me</span></code> object also contains a lot of useful resources for doing
|
||||
things with that object. We access those resources with ‘<code class="docutils literal notranslate"><span class="pre">.</span></code>’.</p>
|
||||
<p>One such resource is <code class="docutils literal notranslate"><span class="pre">msg</span></code>, which works like <code class="docutils literal notranslate"><span class="pre">print</span></code> except it sends the text to the object it
|
||||
is attached to. So if we, for example, had an object <code class="docutils literal notranslate"><span class="pre">you</span></code>, doing <code class="docutils literal notranslate"><span class="pre">you.msg(...)</span></code> would send a message
|
||||
to the object <code class="docutils literal notranslate"><span class="pre">you</span></code>.</p>
|
||||
<p>For now, <code class="docutils literal notranslate"><span class="pre">print</span></code> and <code class="docutils literal notranslate"><span class="pre">me.msg</span></code> behaves the same, just remember that <code class="docutils literal notranslate"><span class="pre">print</span></code> is mainly used for
|
||||
debugging and <code class="docutils literal notranslate"><span class="pre">.msg()</span></code> will be more useful for you in the future.</p>
|
||||
</section>
|
||||
<section id="parsing-python-errors">
|
||||
<h2><span class="section-number">3.5. </span>Parsing Python errors<a class="headerlink" href="#parsing-python-errors" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Let’s try this new text-sending in the function we just created. Go back to
|
||||
your <code class="docutils literal notranslate"><span class="pre">test.py</span></code> file and Replace the function with this instead:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hello_world</span><span class="p">():</span>
|
||||
<span class="n">me</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Hello World!"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Save your file and <code class="docutils literal notranslate"><span class="pre">reload</span></code> your server to tell Evennia to re-import new code,
|
||||
then run it like before:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > py import world.test ; world.test.hello_world()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>No go - this time you get an error!</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">File</span> <span class="s2">"./world/test.py"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">2</span><span class="p">,</span> <span class="ow">in</span> <span class="n">hello_world</span>
|
||||
<span class="n">me</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Hello World!"</span><span class="p">)</span>
|
||||
<span class="ne">NameError</span><span class="p">:</span> <span class="n">name</span> <span class="s1">'me'</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">defined</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Errors in the logs</p>
|
||||
<p>In regular use, tracebacks will often appear in the log rather than
|
||||
in the game. Use <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">--log</span></code> to view the log in the terminal. Make
|
||||
sure to scroll back if you expect an error and don’t see it. Use
|
||||
<code class="docutils literal notranslate"><span class="pre">Ctrl-C</span></code> (or <code class="docutils literal notranslate"><span class="pre">Cmd-C</span></code> on Mac) to exit the log-view.</p>
|
||||
</aside>
|
||||
<p>This is called a <em>traceback</em>. Python’s errors are very friendly and will most of the time tell you
|
||||
exactly what and where things go wrong. It’s important that you learn to parse tracebacks so you
|
||||
know how to fix your code.</p>
|
||||
<p>A traceback is to be read from the <em>bottom up</em>:</p>
|
||||
<ul class="simple">
|
||||
<li><p>(line 3) An error of type <code class="docutils literal notranslate"><span class="pre">NameError</span></code> is the problem …</p></li>
|
||||
<li><p>(line 3) … more specifically it is due to the variable <code class="docutils literal notranslate"><span class="pre">me</span></code> not being defined.</p></li>
|
||||
<li><p>(line 2) This happened on the line <code class="docutils literal notranslate"><span class="pre">me.msg("Hello</span> <span class="pre">world!")</span></code> …</p></li>
|
||||
<li><p>(line 1) … which is on line <code class="docutils literal notranslate"><span class="pre">2</span></code> of the file <code class="docutils literal notranslate"><span class="pre">./world/test.py</span></code>.</p></li>
|
||||
</ul>
|
||||
<p>In our case the traceback is short. There may be many more lines above it, tracking just how
|
||||
different modules called each other until the program got to the faulty line. That can
|
||||
sometimes be useful information, but reading from the bottom is always a good start.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">NameError</span></code> we see here is due to a module being its own isolated thing. It knows nothing about
|
||||
the environment into which it is imported. It knew what <code class="docutils literal notranslate"><span class="pre">print</span></code> is because that is a special
|
||||
<a class="reference external" href="https://docs.python.org/2.5/ref/keywords.html">reserved Python keyword</a>. But <code class="docutils literal notranslate"><span class="pre">me</span></code> is <em>not</em> such a
|
||||
reserved word (as mentioned, it’s just something Evennia came up with for convenience in the <code class="docutils literal notranslate"><span class="pre">py</span></code>
|
||||
command). As far as the module is concerned <code class="docutils literal notranslate"><span class="pre">me</span></code> is an unfamiliar name, appearing out of nowhere.
|
||||
Hence the <code class="docutils literal notranslate"><span class="pre">NameError</span></code>.</p>
|
||||
</section>
|
||||
<section id="passing-arguments-to-functions">
|
||||
<h2><span class="section-number">3.6. </span>Passing arguments to functions<a class="headerlink" href="#passing-arguments-to-functions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>We know that <code class="docutils literal notranslate"><span class="pre">me</span></code> exists at the point when we run the <code class="docutils literal notranslate"><span class="pre">py</span></code> command, because we can do <code class="docutils literal notranslate"><span class="pre">py</span> <span class="pre">me.msg("Hello</span> <span class="pre">World!")</span></code>
|
||||
with no problem. So let’s <em>pass</em> that me along to the function so it knows what it should be.
|
||||
Go back to your <code class="docutils literal notranslate"><span class="pre">test.py</span></code> and change it to this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hello_world</span><span class="p">(</span><span class="n">who</span><span class="p">):</span>
|
||||
<span class="n">who</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Hello World!"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We now added an <em>argument</em> to the function. We could have named it anything. Whatever <code class="docutils literal notranslate"><span class="pre">who</span></code> is,
|
||||
we will call a method <code class="docutils literal notranslate"><span class="pre">.msg()</span></code> on it.</p>
|
||||
<p>As usual, <code class="docutils literal notranslate"><span class="pre">reload</span></code> the server to make sure the new code is available.</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>
|
||||
</div>
|
||||
<p>Now it worked. We <em>passed</em> <code class="docutils literal notranslate"><span class="pre">me</span></code> to our function. It will appear inside the function renamed as <code class="docutils literal notranslate"><span class="pre">who</span></code> and
|
||||
now the function works and prints as expected. Note how the <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> function doesn’t care <em>what</em> you
|
||||
pass into it as long as it has a <code class="docutils literal notranslate"><span class="pre">.msg()</span></code> method on it. So you could reuse this function over and over for other
|
||||
suitable targets.</p>
|
||||
<blockquote>
|
||||
<div><p><strong>Extra Credit:</strong> As an exercise, try to pass something else into <code class="docutils literal notranslate"><span class="pre">hello_world</span></code>. Try for example
|
||||
to pass the number <code class="docutils literal notranslate"><span class="pre">5</span></code> or the string <code class="docutils literal notranslate"><span class="pre">"foo"</span></code>. You’ll get errors telling you that they don’t have
|
||||
the attribute <code class="docutils literal notranslate"><span class="pre">msg</span></code>. They don’t care about <code class="docutils literal notranslate"><span class="pre">me</span></code> itself not being a string or a number. If you are
|
||||
familiar with other programming languages (especially C/Java) you may be tempted to start <em>validating</em>
|
||||
<code class="docutils literal notranslate"><span class="pre">who</span></code> to make sure it’s of the right type before you send it. This is usually not recommended in Python.
|
||||
Python philosophy is to <a class="reference external" href="https://docs.python.org/2/tutorial/errors.html">handle</a> the error if it happens
|
||||
rather than to add a lot of code to prevent it from happening. See <a class="reference external" href="https://en.wikipedia.org/wiki/Duck_typing">duck typing</a>
|
||||
and the concept of <em>Leap before you Look</em>.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="finding-others-to-send-to">
|
||||
<h2><span class="section-number">3.7. </span>Finding others to send to<a class="headerlink" href="#finding-others-to-send-to" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Let’s wrap up this first Python <code class="docutils literal notranslate"><span class="pre">py</span></code> crash-course by finding someone else to send to.</p>
|
||||
<p>In Evennia’s <code class="docutils literal notranslate"><span class="pre">contrib/</span></code> folder (<code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples/mirror.py</span></code>) is a handy little
|
||||
object called the <code class="docutils literal notranslate"><span class="pre">TutorialMirror</span></code>. The mirror will echo whatever is being sent to it to
|
||||
the room it is in.</p>
|
||||
<p>On the game command-line, let’s create a mirror:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> create/drop mirror:contrib.tutorial_examples.mirror.TutorialMirror
|
||||
</pre></div>
|
||||
</div>
|
||||
<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>
|
||||
</aside>
|
||||
<p>A mirror should appear in your location.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> look mirror
|
||||
mirror shows your reflection:
|
||||
This is User #1
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>What you are seeing is actually your own avatar in the game, the same thing that is available as <code class="docutils literal notranslate"><span class="pre">me</span></code> in the <code class="docutils literal notranslate"><span class="pre">py</span></code>
|
||||
command.</p>
|
||||
<p>What we are aiming for now is the equivalent of <code class="docutils literal notranslate"><span class="pre">mirror.msg("Mirror</span> <span class="pre">Mirror</span> <span class="pre">on</span> <span class="pre">the</span> <span class="pre">wall")</span></code>. But the first thing that
|
||||
comes to mind will not work:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py mirror.msg("Mirror, Mirror on the wall ...")
|
||||
NameError: name 'mirror' is not defined.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is not surprising: Python knows nothing about “mirrors” or locations or anything. The <code class="docutils literal notranslate"><span class="pre">me</span></code> we’ve been using
|
||||
is, as mentioned, just a convenient thing the Evennia devs makes available to the <code class="docutils literal notranslate"><span class="pre">py</span></code> command. They couldn’t possibly
|
||||
predict that you wanted to talk to mirrors.</p>
|
||||
<p>Instead we will need to <em>search</em> for that <code class="docutils literal notranslate"><span class="pre">mirror</span></code> object before we can send to it.
|
||||
Make sure you are in the same location as the mirror and try:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py me.search("mirror")
|
||||
mirror
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">me.search("name")</span></code> will, by default, search and <em>return</em> an object with the given name found in <em>the same location</em>
|
||||
as the <code class="docutils literal notranslate"><span class="pre">me</span></code> object is. If it can’t find anything you’ll see an error.</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Function returns</p>
|
||||
<p>Whereas a function like <code class="docutils literal notranslate"><span class="pre">print</span></code> only prints its arguments, it’s very common
|
||||
for functions/methods to <code class="docutils literal notranslate"><span class="pre">return</span></code> a result of some kind. Think of the function
|
||||
as a machine - you put something in and out comes a result you can use. In the case
|
||||
of <code class="docutils literal notranslate"><span class="pre">me.search</span></code>, it will perform a database search and spit out the object it finds.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py me.search("dummy")
|
||||
Could not find 'dummy'.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Wanting to find things in the same location is very common, but as we continue we’ll
|
||||
find that Evennia provides ample tools for tagging, searching and finding things from all over your game.</p>
|
||||
<p>Now that we know how to find the ‘mirror’ object, we just need to use that instead of <code class="docutils literal notranslate"><span class="pre">me</span></code>!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py mirror = self.search("mirror") ; mirror.msg("Mirror, Mirror on the wall ...")
|
||||
mirror echoes back to you:
|
||||
"Mirror, Mirror on the wall ..."
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The mirror is useful for testing because its <code class="docutils literal notranslate"><span class="pre">.msg</span></code> method just echoes whatever is sent to it back to the room. More common
|
||||
would be to talk to a player character, in which case the text you sent would have appeared in their game client.</p>
|
||||
</section>
|
||||
<section id="multi-line-py">
|
||||
<h2><span class="section-number">3.8. </span>Multi-line py<a class="headerlink" href="#multi-line-py" title="Permalink to this headline">¶</a></h2>
|
||||
<p>So far we have use <code class="docutils literal notranslate"><span class="pre">py</span></code> in single-line mode, using <code class="docutils literal notranslate"><span class="pre">;</span></code> to separate multiple inputs. This is very convenient
|
||||
when you want to do some quick testing. But you can also start a full multi-line Python interactive interpreter
|
||||
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)
|
||||
[GCC 8.2.0] on Linux
|
||||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>(the details of the output will vary with your Python version and OS). You are now in python interpreter mode. It means
|
||||
that <em>everything</em> you insert from now on will become a line of Python (you can no longer look around or do other
|
||||
commands).</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> print("Hello World")
|
||||
|
||||
>>> print("Hello World")
|
||||
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>
|
||||
<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)
|
||||
[GCC 8.2.0] on Linux
|
||||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">interactive py</p>
|
||||
<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>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}."}
|
||||
This is a Test.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Let’s try to define a function:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> def hello_world(who, txt):
|
||||
...
|
||||
> who.msg(txt)
|
||||
...
|
||||
>
|
||||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Some important things above:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Definining a function with <code class="docutils literal notranslate"><span class="pre">def</span></code> means we are starting a new code block. Python works so that you mark the content
|
||||
of the block with indention. So the next line must be manually indented (4 spaces is a good standard) in order
|
||||
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>
|
||||
</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!")
|
||||
Hello world to me!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">me</span></code> is still available to us, so we pass that as the <code class="docutils literal notranslate"><span class="pre">who</span></code> argument, along with a little longer
|
||||
string. Let’s combine this with searching for the mirror.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> mirror = me.search("mirror")
|
||||
> hello_world(mirror, "Mirror, Mirror on the wall ...")
|
||||
mirror echoes back to you:
|
||||
"Mirror, Mirror on the wall ..."
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Exit the <code class="docutils literal notranslate"><span class="pre">py</span></code> mode with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quit()
|
||||
Closing the Python console.
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="other-ways-to-test-python-code">
|
||||
<h2><span class="section-number">3.9. </span>Other ways to test Python code<a class="headerlink" href="#other-ways-to-test-python-code" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">py</span></code> command is very powerful for experimenting with Python in-game. It’s great for quick testing.
|
||||
But you are still limited to working over telnet or the webclient, interfaces that doesn’t know anything
|
||||
about Python per-se.</p>
|
||||
<p>Outside the game, go to the terminal where you ran Evennia (or any terminal where the <code class="docutils literal notranslate"><span class="pre">evennia</span></code> command
|
||||
is available).</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cd</span></code> to your game dir.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">shell</span></code></p></li>
|
||||
</ul>
|
||||
<p>A Python shell opens. This works like <code class="docutils literal notranslate"><span class="pre">py</span></code> did inside the game, with the exception that you don’t have
|
||||
<code class="docutils literal notranslate"><span class="pre">me</span></code> available out of the box. If you want <code class="docutils literal notranslate"><span class="pre">me</span></code>, you need to first find yourself:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> import evennia
|
||||
> me = evennia.search_object("YourChar")[0]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here we make use of one of evennia’s search functions, available by importing <code class="docutils literal notranslate"><span class="pre">evennia</span></code> directly.
|
||||
We will cover more advanced searching later, but suffice to say, you put your own character name instead of
|
||||
“YourChar” above.</p>
|
||||
<blockquote>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">[0]</span></code> at the end is because <code class="docutils literal notranslate"><span class="pre">.search_object</span></code> returns a list of objects and we want to
|
||||
get at the first of them (counting starts from 0).</p>
|
||||
</div></blockquote>
|
||||
<p>Use <code class="docutils literal notranslate"><span class="pre">Ctrl-D</span></code> (<code class="docutils literal notranslate"><span class="pre">Cmd-D</span></code> on Mac) or <code class="docutils literal notranslate"><span class="pre">quit()</span></code> to exit the Python console.</p>
|
||||
</section>
|
||||
<section id="ipython">
|
||||
<h2><span class="section-number">3.10. </span>ipython<a class="headerlink" href="#ipython" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The default Python shell is quite limited and ugly. It’s <em>highly</em> recommended to install <code class="docutils literal notranslate"><span class="pre">ipython</span></code> instead. This
|
||||
is a much nicer, third-party Python interpreter with colors and many usability improvements.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>pip install ipython
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If <code class="docutils literal notranslate"><span class="pre">ipython</span></code> is installed, <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">shell</span></code> will use it automatically.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia shell
|
||||
...
|
||||
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help
|
||||
In [1]: You now have Tab-completion:
|
||||
|
||||
> import evennia
|
||||
> evennia.<TAB>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>That is, enter <code class="docutils literal notranslate"><span class="pre">evennia.</span></code> and then press the TAB key - you will be given a list of all the resources
|
||||
available on the <code class="docutils literal notranslate"><span class="pre">evennia</span></code> object. This is great for exploring what Evennia has to offer. For example,
|
||||
use your arrow keys to scroll to <code class="docutils literal notranslate"><span class="pre">search_object()</span></code> to fill it in.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> evennia.search_object?
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Adding a <code class="docutils literal notranslate"><span class="pre">?</span></code> and pressing return will give you the full documentation for <code class="docutils literal notranslate"><span class="pre">.search_object</span></code>. Use <code class="docutils literal notranslate"><span class="pre">??</span></code> if you
|
||||
want to see the entire source code.</p>
|
||||
<p>As for the normal python interpreter, use <code class="docutils literal notranslate"><span class="pre">Ctrl-D</span></code>/<code class="docutils literal notranslate"><span class="pre">Cmd-D</span></code> or <code class="docutils literal notranslate"><span class="pre">quit()</span></code> to exit ipython.</p>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>Persistent code</p>
|
||||
<p>Common for both <code class="docutils literal notranslate"><span class="pre">py</span></code> and <code class="docutils literal notranslate"><span class="pre">python</span></code>/<code class="docutils literal notranslate"><span class="pre">ipython</span></code> is that the code you write is not persistent - it will
|
||||
be gone after you shut down the interpreter (but ipython will remember your input history). For making long-lasting
|
||||
Python code, we need to save it in a Python module, like we did for <code class="docutils literal notranslate"><span class="pre">world/test.py</span></code>.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="conclusions">
|
||||
<h2><span class="section-number">3.11. </span>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This covers quite a lot of basic Python usage. We printed and formatted strings, defined our own
|
||||
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>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">3. </span>Intro to using Python with Evennia</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,525 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>5. Introduction to Python classes and objects — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="6. Overview of the Evennia library" href="Beginner-Tutorial-Evennia-Library-Overview.html" />
|
||||
<link rel="prev" title="4. Overview of your new Game Dir" href="Beginner-Tutorial-Gamedir-Overview.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">5. </span>Introduction to Python classes and objects</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">5. Introduction to Python classes and objects</a><ul>
|
||||
<li><a class="reference internal" href="#importing-things">5.1. Importing things</a></li>
|
||||
<li><a class="reference internal" href="#on-classes-and-objects">5.2. On classes and objects</a><ul>
|
||||
<li><a class="reference internal" href="#classes-and-instances">5.2.1. Classes and instances</a></li>
|
||||
<li><a class="reference internal" href="#whats-so-good-about-objects">5.2.2. What’s so good about objects?</a></li>
|
||||
<li><a class="reference internal" href="#classes-can-have-children">5.2.3. Classes can have children</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#summary">5.3. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Gamedir-Overview.html"
|
||||
title="previous chapter"><span class="section-number">4. </span>Overview of your new Game Dir</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Evennia-Library-Overview.html"
|
||||
title="next chapter"><span class="section-number">6. </span>Overview of the Evennia library</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Python-classes-and-objects.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Python-classes-and-objects.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="introduction-to-python-classes-and-objects">
|
||||
<h1><span class="section-number">5. </span>Introduction to Python classes and objects<a class="headerlink" href="#introduction-to-python-classes-and-objects" title="Permalink to this headline">¶</a></h1>
|
||||
<p>We have now learned how to run some simple Python code from inside (and outside) your game server.
|
||||
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>
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py import world.test ; world.test.hello_world(me)
|
||||
Hello World!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In this example, on your hard drive, the files looks like this:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mygame</span><span class="o">/</span>
|
||||
<span class="n">world</span><span class="o">/</span>
|
||||
<span class="n">test</span><span class="o">.</span><span class="n">py</span> <span class="o"><-</span> <span class="n">inside</span> <span class="n">this</span> <span class="n">file</span> <span class="ow">is</span> <span class="n">a</span> <span class="n">function</span> <span class="n">hello_world</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you followed earlier tutorial lessons, the <code class="docutils literal notranslate"><span class="pre">mygame/world/test.py</span></code> file should look like this (if
|
||||
not, make it so):</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">hello_world</span><span class="p">(</span><span class="n">who</span><span class="p">):</span>
|
||||
<span class="n">who</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Hello World!"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Whitespace matters in Python!</p>
|
||||
<ul class="simple">
|
||||
<li><p>Indentation matters in Python</p></li>
|
||||
<li><p>So does capitalization</p></li>
|
||||
<li><p>Use 4 <code class="docutils literal notranslate"><span class="pre">spaces</span></code> to indent, not tabs</p></li>
|
||||
<li><p>Empty lines are fine</p></li>
|
||||
<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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>import world.test
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">import</span></code> Python instruction loads <code class="docutils literal notranslate"><span class="pre">world.test</span></code> so you have it available. You can now go “into”
|
||||
this module to get to the function you want:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>world.test.hello_world(me)
|
||||
</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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from world.test import hello_world
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">...</span> <span class="pre">import</span> <span class="pre">...</span></code> is very, very common as long as you want to get something with a longer
|
||||
python path. It imports <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> directly, so you can use it right away!</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > py from world.test import hello_world ; hello_world(me)
|
||||
Hello World!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Let’s say your <code class="docutils literal notranslate"><span class="pre">test.py</span></code> module had a bunch of interesting functions. You could then import them
|
||||
all one by one:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from world.test import hello_world, my_func, awesome_func
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If there were <em>a lot</em> of functions, you could instead just import <code class="docutils literal notranslate"><span class="pre">test</span></code> and get the function
|
||||
from there when you need (without having to give the full <code class="docutils literal notranslate"><span class="pre">world.test</span></code> every time):</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> from world import test ; test.hello_world(me
|
||||
Hello World!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also <em>rename</em> stuff you import. Say for example that the module you import to already
|
||||
has a function <code class="docutils literal notranslate"><span class="pre">hello_world</span></code> but we also want to use the one from <code class="docutils literal notranslate"><span class="pre">world/test.py</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>from world.test import hello_world as test_hello_world
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The form <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> renames the import.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> from world.test import hello_world as hw ; hw(me)
|
||||
Hello World!
|
||||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Avoid renaming unless it’s to avoid a name-collistion like above - you want to make things as
|
||||
easy to read as possible, and renaming adds another layer of potential confusion.</p>
|
||||
</div></blockquote>
|
||||
<p>In <a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html"><span class="doc std std-doc">the basic intro to Python</span></a> we learned how to open the in-game
|
||||
multi-line interpreter.</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)
|
||||
[GCC 8.2.0] on Linux
|
||||
[py mode - quit() to exit]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You now only need to import once to use the imported function over and over.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> from world.test import hello_world
|
||||
> hello_world()
|
||||
Hello World!
|
||||
> hello_world()
|
||||
Hello World!
|
||||
> hello_world()
|
||||
Hello World!
|
||||
> quit()
|
||||
Closing the Python console.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The same goes when writing code in a module - in most Python modules you will see a bunch of
|
||||
imports at the top, resources that are then used by all code in that module.</p>
|
||||
</section>
|
||||
<section id="on-classes-and-objects">
|
||||
<h2><span class="section-number">5.2. </span>On classes and objects<a class="headerlink" href="#on-classes-and-objects" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Now that we know about imports, let look at a real Evennia module and try to understand it.</p>
|
||||
<p>Open <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code> in your text editor of choice.</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>
|
||||
<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>
|
||||
</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>
|
||||
<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>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>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"Monster"</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>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is moving!"</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Above we have defined a <code class="docutils literal notranslate"><span class="pre">Monster</span></code> class with one variable <code class="docutils literal notranslate"><span class="pre">key</span></code> (that is, the name) and one
|
||||
<em>method</em> on it. A method is like a function except it sits “on” the class. It also always has
|
||||
at least one argument (almost always written as <code class="docutils literal notranslate"><span class="pre">self</span></code> although you could in principle use
|
||||
another name), which is a reference back to itself. So when we print <code class="docutils literal notranslate"><span class="pre">self.key</span></code> we are referring
|
||||
back to the <code class="docutils literal notranslate"><span class="pre">key</span></code> on the class.</p>
|
||||
<aside class="sidebar">
|
||||
<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>
|
||||
</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
|
||||
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>
|
||||
</div>
|
||||
<p>Let’s try it in-game (we use multi-line mode, it’s easier)</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Monster
|
||||
> fluffy = Monster()
|
||||
> fluffy.move_around()
|
||||
Monster is moving!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We created an <em>instance</em> of <code class="docutils literal notranslate"><span class="pre">Monster</span></code>, which we stored in the variable <code class="docutils literal notranslate"><span class="pre">fluffy</span></code>. We then
|
||||
called the <code class="docutils literal notranslate"><span class="pre">move_around</span></code> method on fluffy to get the printout.</p>
|
||||
<blockquote>
|
||||
<div><p>Note how we <em>didn’t</em> call the method as <code class="docutils literal notranslate"><span class="pre">fluffy.move_around(self)</span></code>. While the <code class="docutils literal notranslate"><span class="pre">self</span></code> has to be
|
||||
there when defining the method, we <em>never</em> add it explicitly when we call the method (Python
|
||||
will add the correct <code class="docutils literal notranslate"><span class="pre">self</span></code> for us automatically behind the scenes).</p>
|
||||
</div></blockquote>
|
||||
<p>Let’s create the sibling of Fluffy, Cuddly:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> cuddly = Monster()
|
||||
> cuddly.move_around()
|
||||
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>
|
||||
<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>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</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>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is moving!"</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">__init__</span></code> is a special method that Python recognizes. If given, this handles extra arguments
|
||||
when you instantiate a new Monster. We have it add an argument <code class="docutils literal notranslate"><span class="pre">key</span></code> that we store on <code class="docutils literal notranslate"><span class="pre">self</span></code>.</p>
|
||||
<p>Now, for Evennia to see this code change, we need to reload the server. You can either do it this
|
||||
way:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> quit()
|
||||
Python Console is closing.
|
||||
> reload
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or you can use a separate terminal and restart from outside the game:</p>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">On reloading</p>
|
||||
<p>Reloading with the python mode gets a little annoying since you need to redo everything after every reload. Just keep in mind that during regular development you will not be working this way. The in-game python mode is practical for quick fixes and experiments like this, but actual code is normally written externally, in python modules.</p>
|
||||
</aside>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>$ evennia reload (or restart)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Either way you’ll need to go into <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
|
||||
> from typeclasses.monsters import Monster
|
||||
fluffy = Monster("Fluffy")
|
||||
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>
|
||||
</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>
|
||||
<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>
|
||||
</div>
|
||||
<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"
|
||||
> fluffy.move_around()
|
||||
Cuddly 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>
|
||||
<ul class="simple">
|
||||
<li><p>A player character with all its stats</p></li>
|
||||
<li><p>A monster with HP</p></li>
|
||||
<li><p>A chest with a number of gold coins in it</p></li>
|
||||
<li><p>A room with other objects inside it</p></li>
|
||||
<li><p>The current policy positions of a political party</p></li>
|
||||
<li><p>A rule with methods for resolving challenges or roll dice</p></li>
|
||||
<li><p>A multi-dimenstional data-point for a complex economic simulation</p></li>
|
||||
<li><p>And so much more!</p></li>
|
||||
</ul>
|
||||
</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>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>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> This is a base class for Monster.</span>
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</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>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is moving!"</span><span class="p">)</span>
|
||||
|
||||
|
||||
<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"> """</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>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> flies through the air high above!"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">firebreath</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> Let our dragon breathe fire.</span>
|
||||
<span class="sd"> """</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="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> breathes fire!"</span><span class="p">)</span>
|
||||
|
||||
</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 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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Dragon
|
||||
> smaug = Dragon("Smaug")
|
||||
> smaug.move_around()
|
||||
Smaug flies through the air high above!
|
||||
> smaug.firebreath()
|
||||
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>
|
||||
<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>
|
||||
|
||||
<span class="k">def</span> <span class="nf">move_around</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">move_around</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"The world trembles."</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
</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></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>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> py
|
||||
> from typeclasses.monsters import Dragon
|
||||
> smaug = Dragon("Smaug")
|
||||
> smaug.move_around()
|
||||
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>
|
||||
</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>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">5. </span>Introduction to Python classes and objects</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>11. Searching for things — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="12. Advanced searching - Django Database queries" href="Beginner-Tutorial-Django-queries.html" />
|
||||
<link rel="prev" title="10. Creating things" href="Beginner-Tutorial-Creating-Things.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Django-queries.html" title="12. Advanced searching - Django Database queries"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">11. </span>Searching for things</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">11. Searching for things</a><ul>
|
||||
<li><a class="reference internal" href="#main-search-functions">11.1. Main search functions</a></li>
|
||||
<li><a class="reference internal" href="#searching-using-object-search">11.2. Searching using Object.search</a></li>
|
||||
<li><a class="reference internal" href="#what-can-be-searched-for">11.3. What can be searched for</a><ul>
|
||||
<li><a class="reference internal" href="#search-by-key">11.3.1. Search by key</a></li>
|
||||
<li><a class="reference internal" href="#search-by-aliases">11.3.2. Search by aliases</a></li>
|
||||
<li><a class="reference internal" href="#search-by-location">11.3.3. Search by location</a></li>
|
||||
<li><a class="reference internal" href="#search-by-tags">11.3.4. Search by Tags</a></li>
|
||||
<li><a class="reference internal" href="#search-by-attribute">11.3.5. Search by Attribute</a></li>
|
||||
<li><a class="reference internal" href="#search-by-typeclass">11.3.6. Search by Typeclass</a></li>
|
||||
<li><a class="reference internal" href="#search-by-dbref">11.3.7. Search by dbref</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#finding-objects-relative-each-other">11.4. Finding objects relative each other</a></li>
|
||||
<li><a class="reference internal" href="#summary">11.5. Summary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Creating-Things.html"
|
||||
title="previous chapter"><span class="section-number">10. </span>Creating things</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Django-queries.html"
|
||||
title="next chapter"><span class="section-number">12. </span>Advanced searching - Django Database queries</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Searching-Things.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Searching-Things.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="searching-for-things">
|
||||
<h1><span class="section-number">11. </span>Searching for things<a class="headerlink" href="#searching-for-things" title="Permalink to this headline">¶</a></h1>
|
||||
<p>We have gone through how to create the various entities in Evennia. But creating something is of little use
|
||||
if we cannot find and use it afterwards.</p>
|
||||
<section id="main-search-functions">
|
||||
<h2><span class="section-number">11.1. </span>Main search functions<a class="headerlink" href="#main-search-functions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The base tools are the <code class="docutils literal notranslate"><span class="pre">evennia.search_*</span></code> functions, such as <code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code>.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> rose = evennia.search_object(key="rose")
|
||||
acct = evennia.search_account(key="MyAccountName", email="foo@bar.com")
|
||||
</pre></div>
|
||||
</div>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Querysets</p>
|
||||
<p>What is returned from the main search functions is actually a <code class="docutils literal notranslate"><span class="pre">queryset</span></code>. They can be treated like lists except that they can’t modified in-place. We’ll discuss querysets in the <code class="docutils literal notranslate"><span class="pre">next</span> <span class="pre">lesson</span></code> <Django-queries>`_.</p>
|
||||
</aside>
|
||||
<p>Strings are always case-insensitive, so searching for <code class="docutils literal notranslate"><span class="pre">"rose"</span></code>, <code class="docutils literal notranslate"><span class="pre">"Rose"</span></code> or <code class="docutils literal notranslate"><span class="pre">"rOsE"</span></code> give the same results.
|
||||
It’s important to remember that what is returned from these search methods is a <em>listing</em> of 0, one or more
|
||||
elements - all the matches to your search. To get the first match:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose = rose[0]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Often you really want all matches to the search parameters you specify. In other situations, having zero or
|
||||
more than one match is a sign of a problem and you need to handle this case yourself.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>the_one_ring = evennia.search_object(key="The one Ring")
|
||||
if not the_one_ring:
|
||||
# handle not finding the ring at all
|
||||
elif len(the_one_ring) > 1:
|
||||
# handle finding more than one ring
|
||||
else:
|
||||
# ok - exactly one ring found
|
||||
the_one_ring = the_one_ring[0]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>There are equivalent search functions for all the main resources. You can find a listing of them
|
||||
<a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">in the Search functions section</span></a> of the API frontpage.</p>
|
||||
</section>
|
||||
<section id="searching-using-object-search">
|
||||
<h2><span class="section-number">11.2. </span>Searching using Object.search<a class="headerlink" href="#searching-using-object-search" title="Permalink to this headline">¶</a></h2>
|
||||
<p>On the <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is a <code class="docutils literal notranslate"><span class="pre">.search</span></code> method which we have already tried out when we made Commands. For
|
||||
this to be used you must already have an object available:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose = obj.search("rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">.search</span></code> method wraps <code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code> and handles its output in various ways.</p>
|
||||
<ul class="simple">
|
||||
<li><p>By default it will always search for objects among those in <code class="docutils literal notranslate"><span class="pre">obj.location.contents</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.contents</span></code> (that is,
|
||||
things in obj’s inventory or in the same room).</p></li>
|
||||
<li><p>It will always return exactly one match. If it found zero or more than one match, the return is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
|
||||
<li><p>On a no-match or multimatch, <code class="docutils literal notranslate"><span class="pre">.search</span></code> will automatically send an error message to <code class="docutils literal notranslate"><span class="pre">obj</span></code>.</p></li>
|
||||
</ul>
|
||||
<p>So this method handles error messaging for you. A very common way to use it is in commands:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">MyCommand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"findfoo"</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="n">foo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s2">"foo"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">foo</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Remember, <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> is the one calling the command. This is usually a Character, which
|
||||
inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>! This (rather stupid) Command searches for an object named “foo” in
|
||||
the same location. If it can’t find it, <code class="docutils literal notranslate"><span class="pre">foo</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code>. The error has already been reported
|
||||
to <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> so we just abort with <code class="docutils literal notranslate"><span class="pre">return</span></code>.</p>
|
||||
<p>You can use <code class="docutils literal notranslate"><span class="pre">.search</span></code> to find anything, not just stuff in the same room:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>volcano = self.caller.search("Volcano", global=True)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you only want to search for a specific list of things, you can do so too:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>stone = self.caller.search("MyStone", candidates=[obj1, obj2, obj3, obj4])
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will only return a match if MyStone is one of the four provided candidate objects. This is quite powerful,
|
||||
here’s how you’d find something only in your inventory:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>potion = self.caller.search("Healing potion", candidates=self.caller.contents)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also turn off the automatic error handling:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>swords = self.caller.search("Sword", quiet=True)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>With <code class="docutils literal notranslate"><span class="pre">quiet=True</span></code> the user will not be notified on zero or multi-match errors. Instead you are expected to handle this
|
||||
yourself and what you get back is now a list of zero, one or more matches!</p>
|
||||
</section>
|
||||
<section id="what-can-be-searched-for">
|
||||
<h2><span class="section-number">11.3. </span>What can be searched for<a class="headerlink" href="#what-can-be-searched-for" title="Permalink to this headline">¶</a></h2>
|
||||
<p>These are the main database entities one can search for:</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../../../Components/Objects.html"><span class="doc std std-doc">Objects</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Accounts.html"><span class="doc std std-doc">Accounts</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Scripts</span></a>,</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Channels.html"><span class="doc std std-doc">Channels</span></a>,</p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Msg.html"><span class="doc std std-doc">Messages</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../../../Components/Help-System.html"><span class="doc std std-doc">Help Entries</span></a>.</p></li>
|
||||
</ul>
|
||||
<p>Most of the time you’ll likely spend your time searching for Objects and the occasional Accounts.</p>
|
||||
<p>So to find an entity, what can be searched for?</p>
|
||||
<section id="search-by-key">
|
||||
<h3><span class="section-number">11.3.1. </span>Search by key<a class="headerlink" href="#search-by-key" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">key</span></code> is the name of the entity. Searching for this is always case-insensitive.</p>
|
||||
</section>
|
||||
<section id="search-by-aliases">
|
||||
<h3><span class="section-number">11.3.2. </span>Search by aliases<a class="headerlink" href="#search-by-aliases" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Objects and Accounts can have any number of aliases. When searching for <code class="docutils literal notranslate"><span class="pre">key</span></code> these will searched too,
|
||||
you can’t easily search only for aliases.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose.aliases.add("flower")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the above <code class="docutils literal notranslate"><span class="pre">rose</span></code> has a <code class="docutils literal notranslate"><span class="pre">key</span></code> <code class="docutils literal notranslate"><span class="pre">"Rose"</span></code>, it can now also be found by searching for <code class="docutils literal notranslate"><span class="pre">flower</span></code>. In-game
|
||||
you can assign new aliases to things with the <code class="docutils literal notranslate"><span class="pre">alias</span></code> command.</p>
|
||||
</section>
|
||||
<section id="search-by-location">
|
||||
<h3><span class="section-number">11.3.3. </span>Search by location<a class="headerlink" href="#search-by-location" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Only Objects (things inheriting from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultObject</span></code>) has a location. This is usually a room.
|
||||
The <code class="docutils literal notranslate"><span class="pre">Object.search</span></code> method will automatically limit it search by location, but it also works for the
|
||||
general search function. If we assume <code class="docutils literal notranslate"><span class="pre">room</span></code> is a particular Room instance,</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>chest = evennia.search_object("Treasure chest", location=room)
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="search-by-tags">
|
||||
<h3><span class="section-number">11.3.4. </span>Search by Tags<a class="headerlink" href="#search-by-tags" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Think of a <a class="reference internal" href="../../../Components/Tags.html"><span class="doc std std-doc">Tag</span></a> as the label the airport puts on your luggage when flying.
|
||||
Everyone going on the same plane gets a tag grouping them together so the airport can know what should
|
||||
go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached
|
||||
to each object.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose.tags.add("flowers")
|
||||
daffodil.tags.add("flowers")
|
||||
tulip.tags.add("flowers")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can now find all flowers using the <code class="docutils literal notranslate"><span class="pre">search_tag</span></code> function:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_flowers = evennia.search_tag("flowers")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Tags can also have categories. By default this category is <code class="docutils literal notranslate"><span class="pre">None</span></code> which is also considered a category.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>silmarillion.tags.add("fantasy", category="books")
|
||||
ice_and_fire.tags.add("fantasy", category="books")
|
||||
mona_lisa_overdrive.tags.add("cyberpunk", category="books")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note that if you specify the tag you <em>must</em> also include its category, otherwise that category
|
||||
will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and find no matches.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_fantasy_books = evennia.search_tag("fantasy") # no matches!
|
||||
all_fantasy_books = evennia.search_tag("fantasy", category="books")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Only the second line above returns the two fantasy books. If we specify a category however,
|
||||
we can get all tagged entities within that category:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_books = evennia.search_tag(category="books")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This gets all three books.</p>
|
||||
</section>
|
||||
<section id="search-by-attribute">
|
||||
<h3><span class="section-number">11.3.5. </span>Search by Attribute<a class="headerlink" href="#search-by-attribute" title="Permalink to this headline">¶</a></h3>
|
||||
<p>We can also search by the <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> associated with entities.</p>
|
||||
<p>For example, let’s give our rose thorns:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose.db.has_thorns = True
|
||||
wines.db.has_thorns = True
|
||||
daffodil.db.has_thorns = False
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now we can find things attribute and the value we want it to have:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>is_ouch = evennia.search_object_attribute("has_thorns", True)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This returns the rose and the wines.</p>
|
||||
<blockquote>
|
||||
<div><p>Searching by Attribute can be very practical. But if you plan to do a search very often, searching
|
||||
by-tag is generally faster.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="search-by-typeclass">
|
||||
<h3><span class="section-number">11.3.6. </span>Search by Typeclass<a class="headerlink" href="#search-by-typeclass" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Sometimes it’s useful to find all objects of a specific Typeclass. All of Evennia’s search tools support this.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_roses = evennia.search_object(typeclass="typeclasses.flowers.Rose")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you have the <code class="docutils literal notranslate"><span class="pre">Rose</span></code> class already imported you can also pass it directly:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_roses = evennia.search_object(typeclass=Rose)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also search using the typeclass itself:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_roses = Rose.objects.all()
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This last way of searching is a simple form of a Django <em>query</em>. This is a way to express SQL queries using
|
||||
Python.</p>
|
||||
</section>
|
||||
<section id="search-by-dbref">
|
||||
<h3><span class="section-number">11.3.7. </span>Search by dbref<a class="headerlink" href="#search-by-dbref" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The database id or <code class="docutils literal notranslate"><span class="pre">#dbref</span></code> is unique and never-reused within each database table. In search methods you can
|
||||
replace the search for <code class="docutils literal notranslate"><span class="pre">key</span></code> with the dbref to search for. This must be written as a string <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>the_answer = self.caller.search("#42")
|
||||
eightball = evennia.search_object("#8")
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Since <code class="docutils literal notranslate"><span class="pre">#dbref</span></code> is always unique, this search is always global.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>Relying on #dbrefs</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You may be used to using #dbrefs a lot from other codebases. It is however considered
|
||||
`bad practice` in Evennia to rely on hard-coded #dbrefs. It makes your code hard to maintain
|
||||
and tied to the exact layout of the database. In 99% of cases you should pass the actual objects
|
||||
around and search by key/tags/attribute instead.
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="finding-objects-relative-each-other">
|
||||
<h2><span class="section-number">11.4. </span>Finding objects relative each other<a class="headerlink" href="#finding-objects-relative-each-other" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Let’s consider a <code class="docutils literal notranslate"><span class="pre">chest</span></code> with a <code class="docutils literal notranslate"><span class="pre">coin</span></code> inside it. The chests stand in a room <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>. In the dungeon is also
|
||||
a <code class="docutils literal notranslate"><span class="pre">door</span></code>. This is an exit leading outside.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">coin.location</span></code> is <code class="docutils literal notranslate"><span class="pre">chest</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">chest.location</span></code> is <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">door.location</span></code> is <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">room.location</span></code> is <code class="docutils literal notranslate"><span class="pre">None</span></code> since it’s not inside something else.</p></li>
|
||||
</ul>
|
||||
<p>One can use this to find what is inside what. For example, <code class="docutils literal notranslate"><span class="pre">coin.location.location</span></code> is the <code class="docutils literal notranslate"><span class="pre">room</span></code>.
|
||||
We can also find what is inside each object. This is a list of things.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">room.contents</span></code> is <code class="docutils literal notranslate"><span class="pre">[chest,</span> <span class="pre">door]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">chest.contents</span></code> is <code class="docutils literal notranslate"><span class="pre">[coin]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">coin.contents</span></code> is <code class="docutils literal notranslate"><span class="pre">[]</span></code>, the empty list since there’s nothing ‘inside’ the coin.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">door.contents</span></code> is <code class="docutils literal notranslate"><span class="pre">[]</span></code> too.</p></li>
|
||||
</ul>
|
||||
<p>A convenient helper is <code class="docutils literal notranslate"><span class="pre">.contents_get</span></code> - this allows to restrict what is returned:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">room.contents_get(exclude=chest)</span></code> - this returns everything in the room except the chest (maybe it’s hidden?)</p></li>
|
||||
</ul>
|
||||
<p>There is a special property for finding exits:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">room.exits</span></code> is <code class="docutils literal notranslate"><span class="pre">[door]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">coin.exits</span></code> is <code class="docutils literal notranslate"><span class="pre">[]</span></code> (same for all the other objects)</p></li>
|
||||
</ul>
|
||||
<p>There is a property <code class="docutils literal notranslate"><span class="pre">.destination</span></code> which is only used by exits:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">door.destination</span></code> is <code class="docutils literal notranslate"><span class="pre">outside</span></code> (or wherever the door leads)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">room.destination</span></code> is <code class="docutils literal notranslate"><span class="pre">None</span></code> (same for all the other non-exit objects)</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="summary">
|
||||
<h2><span class="section-number">11.5. </span>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Knowing how to find things is important and the tools from this section will serve you well. For most of your needs
|
||||
these tools will be all you need …</p>
|
||||
<p>… but not always. In the next lesson we will dive further into more complex searching when we look at
|
||||
Django queries and querysets in earnest.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Django-queries.html" title="12. Advanced searching - Django Database queries"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">11. </span>Searching for things</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>2. The Tutorial World — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
|
||||
<script src="../../../_static/jquery.js"></script>
|
||||
<script src="../../../_static/underscore.js"></script>
|
||||
<script src="../../../_static/doctools.js"></script>
|
||||
<script src="../../../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../../../genindex.html" />
|
||||
<link rel="search" title="Search" href="../../../search.html" />
|
||||
<link rel="next" title="3. Intro to using Python with Evennia" href="Beginner-Tutorial-Python-basic-introduction.html" />
|
||||
<link rel="prev" title="1. Using commands and building stuff" href="Beginner-Tutorial-Building-Quickstart.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" accesskey="U">Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">2. </span>The Tutorial World</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../../../index.html">
|
||||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../../../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../../../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">2. The Tutorial World</a><ul>
|
||||
<li><a class="reference internal" href="#gameplay">2.1. Gameplay</a><ul>
|
||||
<li><a class="reference internal" href="#gameplay-hints">2.1.1. Gameplay hints</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#once-you-are-done-or-had-enough">2.2. Once you are done (or had enough)</a></li>
|
||||
<li><a class="reference internal" href="#uninstall-the-tutorial-world">2.3. Uninstall the tutorial world</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Building-Quickstart.html"
|
||||
title="previous chapter"><span class="section-number">1. </span>Using commands and building stuff</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Beginner-Tutorial-Python-basic-introduction.html"
|
||||
title="next chapter"><span class="section-number">3. </span>Intro to using Python with Evennia</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Tutorial-World.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Beginner-Tutorial-Tutorial-World.html">1.0-dev (develop branch)</a></li>
|
||||
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="the-tutorial-world">
|
||||
<h1><span class="section-number">2. </span>The Tutorial World<a class="headerlink" href="#the-tutorial-world" title="Permalink to this headline">¶</a></h1>
|
||||
<p>The <em>Tutorial World</em> is a small and functioning MUD-style game world shipped with Evennia.
|
||||
It’s a small showcase of what is possible. It can also be useful for those who have an easier
|
||||
time learning by deconstructing existing code.</p>
|
||||
<p>Stand in the Limbo room and install it with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>batchcommand tutorial_world.build
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>What this does is to run the build script
|
||||
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/contrib/tutorial_world/build.ev">evennia/contrib/tutorial_world/build.ev</a>.
|
||||
This is pretty much just a list of build-commands executed in sequence by the <code class="docutils literal notranslate"><span class="pre">batchcommand</span></code> command.
|
||||
Wait for the building to complete and don’t run it twice.</p>
|
||||
<blockquote>
|
||||
<div><p>After having run the batchcommand, the <code class="docutils literal notranslate"><span class="pre">intro</span></code> command also becomes available in Limbo. Try it out to
|
||||
for in-game help and to get an example of <a class="reference internal" href="../../../Components/EvMenu.html"><span class="doc std std-doc">EvMenu</span></a>, Evennia’s in-built
|
||||
menu generation system!</p>
|
||||
</div></blockquote>
|
||||
<p>The game consists of a single-player quest and has some 20 rooms that you can explore as you seek
|
||||
to discover the whereabouts of a mythical weapon.</p>
|
||||
<p>A new exit should have appeared named <em>Tutorial</em>. Enter by writing <code class="docutils literal notranslate"><span class="pre">tutorial</span></code>.</p>
|
||||
<p>You will automatically <code class="docutils literal notranslate"><span class="pre">quell</span></code> when you enter (and <code class="docutils literal notranslate"><span class="pre">unquell</span></code> when you leave), so you can play the way it was intended.
|
||||
Both if you are triumphant or if you use the <code class="docutils literal notranslate"><span class="pre">give</span> <span class="pre">up</span></code> command you will eventually end up back in Limbo.</p>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>Only LOSERS and QUITTERS use the <code class="docutils literal notranslate"><span class="pre">give</span> <span class="pre">up</span></code> command.</p>
|
||||
</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><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
|
||||
this is a chance to adventure that you cannot turn down!</em></p>
|
||||
<p><em>You reach the ocean in the midst of a raging thunderstorm. With wind and rain screaming in your
|
||||
face you stand where the moor meets the sea along a high, rocky coast …</em></p>
|
||||
<hr class="docutils" />
|
||||
<section id="gameplay-hints">
|
||||
<h3><span class="section-number">2.1.1. </span>Gameplay hints<a class="headerlink" href="#gameplay-hints" title="Permalink to this headline">¶</a></h3>
|
||||
<ul class="simple">
|
||||
<li><p>Use the command <code class="docutils literal notranslate"><span class="pre">tutorial</span></code> to get code insight behind the scenes of every room.</p></li>
|
||||
<li><p>Look at everything. While a demo, the Tutorial World is not necessarily trivial to solve - it depends
|
||||
on your experience with text-based adventure games. Just remember that everything can be solved or bypassed.</p></li>
|
||||
<li><p>Some objects are interactive in more than one way. Use the normal <code class="docutils literal notranslate"><span class="pre">help</span></code> command to get a feel for
|
||||
which commands are available at any given time.</p></li>
|
||||
<li><p>In order to fight, you need to first find some type of weapon.</p>
|
||||
<ul>
|
||||
<li><p><em>slash</em> is a normal attack</p></li>
|
||||
<li><p><em>stab</em> launches an attack that makes more damage but has a lower chance to hit.</p></li>
|
||||
<li><p><em>defend</em> will lower the chance to taking damage on your enemy’s next attack.</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>Some things <em>cannot</em> be hurt by mundane weapons. In that case it’s OK to run away. Expect
|
||||
to be chased though.</p></li>
|
||||
<li><p>Being defeated is a part of the experience. You can’t actually die, but getting knocked out
|
||||
means being left in the dark …</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
<section id="once-you-are-done-or-had-enough">
|
||||
<h2><span class="section-number">2.2. </span>Once you are done (or had enough)<a class="headerlink" href="#once-you-are-done-or-had-enough" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Afterwards you’ll either have conquered the old ruin and returned in glory and triumph … or
|
||||
you returned limping and whimpering from the challenge by using the <code class="docutils literal notranslate"><span class="pre">give</span> <span class="pre">up</span></code> command.
|
||||
Either way you should now be back in Limbo, able to reflect on the experience.</p>
|
||||
<p>Some features exemplified by the tutorial world:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Rooms with custom ability to show details (like looking at the wall in the dark room)</p></li>
|
||||
<li><p>Hidden or impassable exits until you fulfilled some criterion</p></li>
|
||||
<li><p>Objects with multiple custom interactions (like swords, the well, the obelisk …)</p></li>
|
||||
<li><p>Large-area rooms (that bridge is actually only one room!)</p></li>
|
||||
<li><p>Outdoor weather rooms with weather (the rain pummeling you)</p></li>
|
||||
<li><p>Dark room, needing light source to reveal itself (the burning splinter even burns out after a while)</p></li>
|
||||
<li><p>Puzzle object (the wines in the dark cell; hope you didn’t get stuck!)</p></li>
|
||||
<li><p>Multi-room puzzle (the obelisk and the crypt)</p></li>
|
||||
<li><p>Aggressive mobile with roam, pursue and battle state-engine AI (quite deadly until you find the right weapon)</p></li>
|
||||
<li><p>Weapons, also used by mobs (most are admittedly not that useful against the big baddie)</p></li>
|
||||
<li><p>Simple combat system with attack/defend commands (teleporting on-defeat)</p></li>
|
||||
<li><p>Object spawning (the weapons in the barrel and the final weapoon is actually randomized)</p></li>
|
||||
<li><p>Teleporter trap rooms (if you fail the obelisk puzzle)</p></li>
|
||||
</ul>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">Extra Credit</p>
|
||||
<p>If you have previous programming experience (or after you have gone
|
||||
through this Starter tutorial) it may be instructive to dig a little deeper into the Tutorial-world
|
||||
code to learn how it achieves what it does. The code is heavily documented.
|
||||
You can find all the code in <a class="reference internal" href="../../../api/evennia.contrib.tutorials.tutorial_world.html"><span class="doc std std-doc">evennia/contrib/tutorials/tutorial_world</span></a>.
|
||||
The build-script is <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/contrib/tutorials/tutorial_world/build.ev">here</a>.</p>
|
||||
<p>When reading the code, remember that the Tutorial World was designed to install easily and to not permanently modify
|
||||
the rest of the game. It therefore makes sure to only use temporary solutions and to clean up after itself. This is
|
||||
not something you will often need to worry about when making your own game.</p>
|
||||
</aside>
|
||||
<p>Quite a lot of stuff crammed in such a small area!</p>
|
||||
</section>
|
||||
<section id="uninstall-the-tutorial-world">
|
||||
<h2><span class="section-number">2.3. </span>Uninstall the tutorial world<a class="headerlink" href="#uninstall-the-tutorial-world" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Once are done playing with the tutorial world, let’s uninstall it.
|
||||
Uninstalling the tutorial world basically means deleting all the rooms and objects it consists of.
|
||||
Make sure you are back in Limbo, then</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> find tut#01
|
||||
find tut#16
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This should locate the first and last rooms created by <code class="docutils literal notranslate"><span class="pre">build.ev</span></code> - <em>Intro</em> and <em>Outro</em>. If you
|
||||
installed normally, everything created between these two numbers should be part of the tutorial.
|
||||
Note their #dbref numbers, for example 5 and 80. Next we just delete all objects in that range:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> del 5-80
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You will see some errors since some objects are auto-deleted and so cannot be found when the delete
|
||||
mechanism gets to them. That’s fine. You should have removed the tutorial completely once the
|
||||
command finishes.</p>
|
||||
<p>Even if the game-style of the Tutorial-world was not similar to the one you are interested in, it
|
||||
should hopefully have given you a little taste of some of the possibilities of Evennia. Now we’ll
|
||||
move on with how to access this power through code.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../../../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> »</li>
|
||||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part1-Intro.html" >Part 1: What we have</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">2. </span>The Tutorial World</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2020, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue