<p>This tutorial lets you code a small but complete and functioning MUSH-like game in Evennia. A
<aclass="reference external"href="http://en.wikipedia.org/wiki/MUSH">MUSH</a> is, for our purposes, a class of roleplay-centric games
focused on free form storytelling. Even if you are not interested in MUSH:es, this is still a good
first game-type to try since it’s not so code heavy. You will be able to use the same principles for
building other types of games.</p>
<p>The tutorial starts from scratch. If you did the <aclass="reference internal"href="First-Steps-Coding.html"><spanclass="doc">First Steps Coding</span></a> tutorial
already you should have some ideas about how to do some of the steps already.</p>
<p>The following are the (very simplistic and cut-down) features we will implement (this was taken from
a feature request from a MUSH user new to Evennia). A Character in this system should:</p>
<li><p>Have a “Power” score from 1 to 10 that measures how strong they are (stand-in for the stat
system).</p></li>
<li><p>Have a command (e.g. <codeclass="docutils literal notranslate"><spanclass="pre">+setpower</span><spanclass="pre">4</span></code>) that sets their power (stand-in for character generation
code).</p></li>
<li><p>Have a command (e.g. <codeclass="docutils literal notranslate"><spanclass="pre">+attack</span></code>) that lets them roll their power and produce a “Combat Score”
between <codeclass="docutils literal notranslate"><spanclass="pre">1</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">10*Power</span></code>, displaying the result and editing their object to record this number
(stand-in for <codeclass="docutils literal notranslate"><spanclass="pre">+actions</span></code> in the command code).</p></li>
<li><p>Have a command that displays everyone in the room and what their most recent “Combat Score” roll
<li><p>Have a command (e.g. <codeclass="docutils literal notranslate"><spanclass="pre">+createNPC</span><spanclass="pre">Jenkins</span></code>) that creates an NPC with full abilities.</p></li>
<li><p>Have a command to control NPCs, such as <codeclass="docutils literal notranslate"><spanclass="pre">+npc/cmd</span><spanclass="pre">(name)=(command)</span></code> (stand-in for the NPC
<p>To emulate a MUSH, the default <codeclass="docutils literal notranslate"><spanclass="pre">MULTISESSION_MODE=0</span></code> is enough (one unique session per
account/character). This is the default so you don’t need to change anything. You will still be able
to puppet/unpuppet objects you have permission to, but there is no character selection out of the
box in this mode.</p>
<p>We will assume our game folder is called <codeclass="docutils literal notranslate"><spanclass="pre">mygame</span></code> henceforth. You should be fine with the default
<p>We defined two new <aclass="reference internal"href="Attributes.html"><spanclass="doc">Attributes</span></a><codeclass="docutils literal notranslate"><spanclass="pre">power</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">combat_score</span></code> and set them to default
values. Make sure to <codeclass="docutils literal notranslate"><spanclass="pre">@reload</span></code> the server if you had it already running (you need to reload every
time you update your python code, don’t worry, no accounts will be disconnected by the reload).</p>
<p>Note that only <em>new</em> characters will see your new Attributes (since the <codeclass="docutils literal notranslate"><spanclass="pre">at_object_creation</span></code> hook is
called when the object is first created, existing Characters won’t have it). To update yourself,
<p>This resets your own typeclass (the <codeclass="docutils literal notranslate"><spanclass="pre">/force</span></code> switch is a safety measure to not do this
accidentally), this means that <codeclass="docutils literal notranslate"><spanclass="pre">at_object_creation</span></code> is re-run.</p>
<p>Under the “Persistent attributes” heading you should now find the new Attributes <codeclass="docutils literal notranslate"><spanclass="pre">power</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">score</span></code>
set on yourself by <codeclass="docutils literal notranslate"><spanclass="pre">at_object_creation</span></code>. If you don’t, first make sure you <codeclass="docutils literal notranslate"><spanclass="pre">@reload</span></code>ed into the new
code, next look at your server log (in the terminal/console) to see if there were any syntax errors
in your code that may have stopped your new code from loading correctly.</p>
<p>We assume in this example that Accounts first connect into a “character generation area”. Evennia
also supports full OOC menu-driven character generation, but for this example, a simple start room
is enough. When in this room (or rooms) we allow character generation commands. In fact, character
generation commands will <em>only</em> be available in such rooms.</p>
<p>Note that this again is made so as to be easy to expand to a full-fledged game. With our simple
example, we could simply set an <codeclass="docutils literal notranslate"><spanclass="pre">is_in_chargen</span></code> flag on the account and have the <codeclass="docutils literal notranslate"><spanclass="pre">+setpower</span></code> command
check it. Using this method however will make it easy to add more functionality later.</p>
<li><p>One character generation <aclass="reference internal"href="Commands.html"><spanclass="doc">Command</span></a> to set the “Power” on the <codeclass="docutils literal notranslate"><spanclass="pre">Character</span></code>.</p></li>
<li><p>A chargen <aclass="reference internal"href="Command-Sets.html"><spanclass="doc">CmdSet</span></a> to hold this command. Lets call it <codeclass="docutils literal notranslate"><spanclass="pre">ChargenCmdset</span></code>.</p></li>
<li><p>A custom <codeclass="docutils literal notranslate"><spanclass="pre">ChargenRoom</span></code> type that makes this set of commands available to players in such rooms.</p></li>
<li><p>One such room to test things in.</p></li>
</ul>
<divclass="section"id="the-setpower-command">
<h3>The +setpower command<aclass="headerlink"href="#the-setpower-command"title="Permalink to this headline">¶</a></h3>
<p>For this tutorial we will add all our new commands to <codeclass="docutils literal notranslate"><spanclass="pre">mygame/commands/command.py</span></code> but you could
split your commands into multiple module if you prefered.</p>
<p>For this tutorial character generation will only consist of one <aclass="reference internal"href="Commands.html"><spanclass="doc">Command</span></a> to set the
Character s “power” stat. It will be called on the following MUSH-like form:</p>
<p>Open <codeclass="docutils literal notranslate"><spanclass="pre">command.py</span></code> file. It contains documented empty templates for the base command and the
“MuxCommand” type used by default in Evennia. We will use the plain <codeclass="docutils literal notranslate"><spanclass="pre">Command</span></code> type here, the
<codeclass="docutils literal notranslate"><spanclass="pre">MuxCommand</span></code> class offers some extra features like stripping whitespace that may be useful - if so,
34</pre></div></td><tdclass="code"><divclass="highlight"><pre><span></span><spanclass="c1"># end of command.py</span>
<spanclass="kn">from</span><spanclass="nn">evennia</span><spanclass="kn">import</span><spanclass="n">Command</span><spanclass="c1"># just for clarity; already imported above</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"Your Power was set to </span><spanclass="si">%i</span><spanclass="s2">."</span><spanclass="o">%</span><spanclass="n">power</span><spanclass="p">)</span>
<p>This is a pretty straightforward command. We do some error checking, then set the power on ourself.
We use a <codeclass="docutils literal notranslate"><spanclass="pre">help_category</span></code> of “mush” for all our commands, just so they are easy to find and separate
in the help list.</p>
<p>Save the file. We will now add it to a new <aclass="reference internal"href="Command-Sets.html"><spanclass="doc">CmdSet</span></a> so it can be accessed (in a full
chargen system you would of course have more than one command here).</p>
<p>Open <codeclass="docutils literal notranslate"><spanclass="pre">mygame/commands/default_cmdsets.py</span></code> and import your <codeclass="docutils literal notranslate"><spanclass="pre">command.py</span></code> module at the top. We also
import the default <codeclass="docutils literal notranslate"><spanclass="pre">CmdSet</span></code> class for the next step:</p>
<p>Next scroll down and define a new command set (based on the base <codeclass="docutils literal notranslate"><spanclass="pre">CmdSet</span></code> class we just imported at
the end of this file, to hold only our chargen-specific command(s):</p>
<p>Note how new rooms created with this typeclass will always start with <codeclass="docutils literal notranslate"><spanclass="pre">ChargenCmdset</span></code> on themselves.
Don’t forget the <codeclass="docutils literal notranslate"><spanclass="pre">permanent=True</span></code> keyword or you will lose the cmdset after a server reload. For
more information about <aclass="reference internal"href="Command-Sets.html"><spanclass="doc">Command Sets</span></a> and <aclass="reference internal"href="Commands.html"><spanclass="doc">Commands</span></a>, see the respective
<p>First, make sure you have <codeclass="docutils literal notranslate"><spanclass="pre">@reload</span></code>ed the server (or use <codeclass="docutils literal notranslate"><spanclass="pre">evennia</span><spanclass="pre">reload</span></code> from the terminal) to have
your new python code added to the game. Check your terminal and fix any errors you see - the error
traceback lists exactly where the error is found - look line numbers in files you have changed.</p>
<p>We can’t test things unless we have some chargen areas to test. Log into the game (you should at
this point be using the new, custom Character class). Let’s dig a chargen area to test.</p>
<p>If you read the help for <codeclass="docutils literal notranslate"><spanclass="pre">@dig</span></code> you will find that this will create a new room named <codeclass="docutils literal notranslate"><spanclass="pre">chargen</span></code>. The
part after the <codeclass="docutils literal notranslate"><spanclass="pre">:</span></code> is the python-path to the Typeclass you want to use. Since Evennia will
automatically try the <codeclass="docutils literal notranslate"><spanclass="pre">typeclasses</span></code> folder of our game directory, we just specify
<codeclass="docutils literal notranslate"><spanclass="pre">rooms.ChargenRoom</span></code>, meaning it will look inside the module <codeclass="docutils literal notranslate"><spanclass="pre">rooms.py</span></code> for a class named
<codeclass="docutils literal notranslate"><spanclass="pre">ChargenRoom</span></code> (which is what we created above). The names given after <codeclass="docutils literal notranslate"><spanclass="pre">=</span></code> are the names of exits to
and from the room from your current location. You could also append aliases to each one name, such
as <codeclass="docutils literal notranslate"><spanclass="pre">chargen;character</span><spanclass="pre">generation</span></code>.</p>
<p>So in summary, this will create a new room of type ChargenRoom and open an exit <codeclass="docutils literal notranslate"><spanclass="pre">chargen</span></code> to it and
an exit back here named <codeclass="docutils literal notranslate"><spanclass="pre">finish</span></code>. If you see errors at this stage, you must fix them in your code.
<p>This should bring you to the chargen room. Being in there you should now have the <codeclass="docutils literal notranslate"><spanclass="pre">+setpower</span></code>
command available, so test it out. When you leave (via the <codeclass="docutils literal notranslate"><spanclass="pre">finish</span></code> exit), the command will go away
and trying <codeclass="docutils literal notranslate"><spanclass="pre">+setpower</span></code> should now give you a command-not-found error. Use <codeclass="docutils literal notranslate"><spanclass="pre">ex</span><spanclass="pre">me</span></code> (as a privileged
user) to check so the <codeclass="docutils literal notranslate"><spanclass="pre">Power</span></code><aclass="reference internal"href="Attributes.html"><spanclass="doc">Attribute</span></a> has been set correctly.</p>
<p>If things are not working, make sure your typeclasses and commands are free of bugs and that you
have entered the paths to the various command sets and commands correctly. Check the logs or command
<p>We will add our combat command to the default command set, meaning it will be available to everyone
at all times. The combat system consists of a <codeclass="docutils literal notranslate"><spanclass="pre">+attack</span></code> command to get how successful our attack is.
We also change the default <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> command to display the current combat score.</p>
<p>Attacking in this simple system means rolling a random “combat score” influenced by the <codeclass="docutils literal notranslate"><spanclass="pre">power</span></code> stat
<p>Go back to <codeclass="docutils literal notranslate"><spanclass="pre">mygame/commands/command.py</span></code> and add the command to the end like this:</p>
<spanclass="n">message</span><spanclass="o">=</span><spanclass="s2">"</span><spanclass="si">%s</span><spanclass="s2"> +attack</span><spanclass="si">%s</span><spanclass="s2"> with a combat score of </span><spanclass="si">%s</span><spanclass="s2">!"</span>
<p>What we do here is simply to generate a “combat score” using Python’s inbuilt <codeclass="docutils literal notranslate"><spanclass="pre">random.randint()</span></code>
function. We then store that and echo the result to everyone involved.</p>
<p>To make the <codeclass="docutils literal notranslate"><spanclass="pre">+attack</span></code> command available to you in game, go back to
<codeclass="docutils literal notranslate"><spanclass="pre">mygame/commands/default_cmdsets.py</span></code> and scroll down to the <codeclass="docutils literal notranslate"><spanclass="pre">CharacterCmdSet</span></code> class. At the correct
<p><codeclass="docutils literal notranslate"><spanclass="pre">@reload</span></code> Evennia and the <codeclass="docutils literal notranslate"><spanclass="pre">+attack</span></code> command should be available to you. Run it and use e.g. <codeclass="docutils literal notranslate"><spanclass="pre">@ex</span></code> to
make sure the <codeclass="docutils literal notranslate"><spanclass="pre">combat_score</span></code> attribute is saved correctly.</p>
<p>Players should be able to view all current combat scores in the room. We could do this by simply
adding a second command named something like <codeclass="docutils literal notranslate"><spanclass="pre">+combatscores</span></code>, but we will instead let the default
<codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> command do the heavy lifting for us and display our scores as part of its normal output, like
<p>We don’t actually have to modify the <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> command itself however. To understand why, take a look
at how the default <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> is actually defined. It sits in <codeclass="docutils literal notranslate"><spanclass="pre">evennia/commands/default/general.py</span></code> (or
You will find that the actual return text is done by the <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> command calling a <em>hook method</em>
named <codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code> on the object looked at. All the <codeclass="docutils literal notranslate"><spanclass="pre">look</span></code> does is to echo whatever this hook
returns. So what we need to do is to edit our custom Character typeclass and overload its
<codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code> to return what we want (this is where the advantage of having a custom typeclass
comes into play for real).</p>
<p>Go back to your custom Character typeclass in <codeclass="docutils literal notranslate"><spanclass="pre">mygame/typeclasses/characters.py</span></code>. The default
implementation of <codeclass="docutils literal notranslate"><spanclass="pre">return</span><spanclass="pre">appearance</span></code> is found in <codeclass="docutils literal notranslate"><spanclass="pre">evennia.DefaultCharacter</span></code> (or online
<aclass="reference external"href="https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1438">here</a>). If you
want to make bigger changes you could copy & paste the whole default thing into our overloading
method. In our case the change is small though:</p>
<p>What we do is to simply let the default <codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code> do its thing (<codeclass="docutils literal notranslate"><spanclass="pre">super</span></code> will call the
parent’s version of the same method). We then split out the first line of this text, append our
<codeclass="docutils literal notranslate"><spanclass="pre">combat_score</span></code> and put it back together again.</p>
<p><codeclass="docutils literal notranslate"><spanclass="pre">@reload</span></code> the server and you should be able to look at other Characters and see their current combat
<div><p>Note: A potentially more useful way to do this would be to overload the entire <codeclass="docutils literal notranslate"><spanclass="pre">return_appearance</span></code>
of the <codeclass="docutils literal notranslate"><spanclass="pre">Room</span></code>s of your mush and change how they list their contents; in that way one could see all
combat scores of all present Characters at the same time as looking at the room. We leave this as an
<spanclass="c1"># may not create npc when OOC</span>
<spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You must have a location to create an npc."</span><spanclass="p">)</span>
<spanclass="k">return</span>
<spanclass="c1"># make name always start with capital letter</span>
<spanclass="n">locks</span><spanclass="o">=</span><spanclass="s2">"edit:id(</span><spanclass="si">%i</span><spanclass="s2">) and perm(Builders);call:false()"</span><spanclass="o">%</span><spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">id</span><spanclass="p">)</span>
<spanclass="n">message</span><spanclass="o">=</span><spanclass="s2">"</span><spanclass="si">%s</span><spanclass="s2"> created the NPC '</span><spanclass="si">%s</span><spanclass="s2">'."</span>
<p>Here we define a <codeclass="docutils literal notranslate"><spanclass="pre">+createnpc</span></code> (<codeclass="docutils literal notranslate"><spanclass="pre">+createNPC</span></code> works too) that is callable by everyone <em>not</em> having the
<codeclass="docutils literal notranslate"><spanclass="pre">nonpcs</span></code> “<aclass="reference external"href="Locks.html#Permissions">permission</a>” (in Evennia, a “permission” can just as well be used to
block access, it depends on the lock we define). We create the NPC object in the caller’s current
location, using our custom <codeclass="docutils literal notranslate"><spanclass="pre">Character</span></code> typeclass to do so.</p>
<p>We set an extra lock condition on the NPC, which we will use to check who may edit the NPC later –
we allow the creator to do so, and anyone with the Builders permission (or higher). See
<aclass="reference internal"href="Locks.html"><spanclass="doc">Locks</span></a> for more information about the lock system.</p>
<p>Note that we just give the object default permissions (by not specifying the <codeclass="docutils literal notranslate"><spanclass="pre">permissions</span></code> keyword
to the <codeclass="docutils literal notranslate"><spanclass="pre">create_object()</span></code> call). In some games one might want to give the NPC the same permissions
as the Character creating them, this might be a security risk though.</p>
<p>Add this command to your default cmdset the same way you did the <codeclass="docutils literal notranslate"><spanclass="pre">+attack</span></code> command earlier.
<codeclass="docutils literal notranslate"><spanclass="pre">@reload</span></code> and it will be available to test.</p>
<p>Since we re-used our custom character typeclass, our new NPC already has a <em>Power</em> value - it
defaults to 1. How do we change this?</p>
<p>There are a few ways we can do this. The easiest is to remember that the <codeclass="docutils literal notranslate"><spanclass="pre">power</span></code> attribute is just a
simple <aclass="reference internal"href="Attributes.html"><spanclass="doc">Attribute</span></a> stored on the NPC object. So as a Builder or Admin we could set this
right away with the default <codeclass="docutils literal notranslate"><spanclass="pre">@set</span></code> command:</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">@set</span></code> command is too generally powerful though, and thus only available to staff. We will add a
custom command that only changes the things we want players to be allowed to change. We could in
principle re-work our old <codeclass="docutils literal notranslate"><spanclass="pre">+setpower</span></code> command, but let’s try something more useful. Let’s make a
<spanclass="n">Set</span><spanclass="n">Anna</span><spanclass="s1">'s property '</span><spanclass="n">power</span><spanclass="s1">' to 10.</span>
<p>This is a slightly more complex command. It goes at the end of your <codeclass="docutils literal notranslate"><spanclass="pre">command.py</span></code> file as before.</p>
<spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You cannot change this NPC."</span><spanclass="p">)</span>
<spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="n">f</span><spanclass="s2">"You may only change {', '.join(allowed_propnames)}."</span><spanclass="p">)</span>
<p><em>Note: If you wanted a player to use this command to change an on-object property like the NPC’s
name (the <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code> property), you’d need to modify the command since “key” is not an Attribute (it is
not retrievable via <codeclass="docutils literal notranslate"><spanclass="pre">npc.attributes.get</span></code> but directly via <codeclass="docutils literal notranslate"><spanclass="pre">npc.key</span></code>). We leave this as an optional
<h3>Making the NPC do stuff - the +npc command<aclass="headerlink"href="#making-the-npc-do-stuff-the-npc-command"title="Permalink to this headline">¶</a></h3>
<spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="s2">"You may not order this NPC to do anything."</span><spanclass="p">)</span>
<spanclass="n">caller</span><spanclass="o">.</span><spanclass="n">msg</span><spanclass="p">(</span><spanclass="n">f</span><spanclass="s2">"You told {npc.key} to do '{self.cmdname}'."</span><spanclass="p">)</span>
<p>Another thing to remember is however that this is a very simplistic way to control NPCs. Evennia
supports full puppeting very easily. An Account (assuming the “puppet” permission was set correctly)
could simply do <codeclass="docutils literal notranslate"><spanclass="pre">@ic</span><spanclass="pre">mynpc</span></code> and be able to play the game “as” that NPC. This is in fact just what
happens when an Account takes control of their normal Character as well.</p>
<p>This ends the tutorial. It looks like a lot of text but the amount of code you have to write is
actually relatively short. At this point you should have a basic skeleton of a game and a feel for
what is involved in coding your game.</p>
<p>From here on you could build a few more ChargenRooms and link that to a bigger grid. The <codeclass="docutils literal notranslate"><spanclass="pre">+setpower</span></code>
command can either be built upon or accompanied by many more to get a more elaborate character
generation.</p>
<p>The simple “Power” game mechanic should be easily expandable to something more full-fledged and
useful, same is true for the combat score principle. The <codeclass="docutils literal notranslate"><spanclass="pre">+attack</span></code> could be made to target a
specific player (or npc) and automatically compare their relevant attributes to determine a result.</p>
<p>To continue from here, you can take a look at the <aclass="reference internal"href="Tutorial-World-Introduction.html"><spanclass="doc">Tutorial World</span></a>. For
more specific ideas, see the <aclass="reference internal"href="Tutorials.html"><spanclass="doc">other tutorials and hints</span></a> as well