mirror of
https://github.com/evennia/evennia.git
synced 2026-03-19 22:36:31 +01:00
535 lines
No EOL
39 KiB
HTML
535 lines
No EOL
39 KiB
HTML
|
||
<!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="More-on-Commands.html" />
|
||
<link rel="prev" title="7. Making objects persistent" href="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="More-on-Commands.html" title="9. Parsing Command input"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="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="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="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>
|
||
<p>if condition:
|
||
…
|
||
elif othercondition:
|
||
…
|
||
else:
|
||
…</p>
|
||
<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 class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="../../../index.html">
|
||
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="../../../search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">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="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="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/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="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="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../../../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../../../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="More-on-Commands.html" title="9. Parsing Command input"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="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> |