evennia/docs/2.x/Howtos/Evennia-for-roleplaying-sessions.html
Evennia docbuilder action e535f5782a Updated HTML docs.
2023-10-19 20:22:27 +00:00

821 lines
No EOL
85 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>Evennia for roleplaying sessions &#8212; Evennia 2.x 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="Evennia for Diku Users" href="Evennia-for-Diku-Users.html" />
<link rel="prev" title="Understanding Color Tags" href="Tutorial-Understanding-Color-Tags.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="Evennia-for-Diku-Users.html" title="Evennia for Diku Users"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Tutorial-Understanding-Color-Tags.html" title="Understanding Color Tags"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" accesskey="U">Tutorials and How-Tos</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Evennia for roleplaying sessions</a></li>
</ul>
</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="#">Evennia for roleplaying sessions</a><ul>
<li><a class="reference internal" href="#starting-out">Starting out</a></li>
<li><a class="reference internal" href="#the-game-master-role">The Game Master role</a><ul>
<li><a class="reference internal" href="#the-permission-hierarchy">The permission hierarchy</a></li>
<li><a class="reference internal" href="#how-to-grant-permissions">How to grant permissions</a></li>
<li><a class="reference internal" href="#optional-making-a-gm-granting-command">Optional: Making a GM-granting command</a><ul>
<li><a class="reference internal" href="#character-modification">Character modification</a></li>
<li><a class="reference internal" href="#new-gm-ungm-command">New &#64;gm/&#64;ungm command</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#character-sheet">Character sheet</a><ul>
<li><a class="reference internal" href="#building-a-character-sheet">Building a Character sheet</a><ul>
<li><a class="reference internal" href="#making-a-sheet-with-evtable">Making a sheet with EvTable</a></li>
<li><a class="reference internal" href="#making-a-sheet-with-evform">Making a sheet with EvForm</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tie-a-character-sheet-to-a-character">Tie a Character sheet to a Character</a></li>
<li><a class="reference internal" href="#command-for-account-to-change-character-sheet">Command for Account to change Character sheet</a></li>
<li><a class="reference internal" href="#commands-for-gm-to-change-character-sheet">Commands for GM to change Character sheet</a></li>
</ul>
</li>
<li><a class="reference internal" href="#dice-roller">Dice roller</a></li>
<li><a class="reference internal" href="#rooms">Rooms</a></li>
<li><a class="reference internal" href="#channels">Channels</a></li>
<li><a class="reference internal" href="#pms">PMs</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Tutorial-Understanding-Color-Tags.html"
title="previous chapter">Understanding Color Tags</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Evennia-for-Diku-Users.html"
title="next chapter">Evennia for Diku Users</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Howtos/Evennia-for-roleplaying-sessions.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/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>Doc Versions</h3>
<ul>
<li><a href="Evennia-for-roleplaying-sessions.html">2.x (main branch)</a></li>
<ul>
<li><a href="../1.3.0/index.html">1.3.0 (v1.3.0 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="evennia-for-roleplaying-sessions">
<h1>Evennia for roleplaying sessions<a class="headerlink" href="#evennia-for-roleplaying-sessions" title="Permalink to this headline"></a></h1>
<p>This tutorial will explain how to set up a realtime or play-by-post tabletop style game using a
fresh Evennia server.</p>
<p>The scenario is thus: You and a bunch of friends want to play a tabletop role playing game online.
One of you will be the game master and you are all okay with playing using written text. You want
both the ability to role play in real-time (when people happen to be online at the same time) as
well as the ability for people to post when they can and catch up on what happened since they were
last online.</p>
<p>This is the functionality we will be needing and using:</p>
<ul class="simple">
<li><p>The ability to make one of you the <em>GM</em> (game master), with special abilities.</p></li>
<li><p>A <em>Character sheet</em> that players can create, view and fill in. It can also be locked so only the
GM can modify it.</p></li>
<li><p>A <em>dice roller</em> mechanism, for whatever type of dice the RPG rules require.</p></li>
<li><p><em>Rooms</em>, to give a sense of location and to compartmentalize play going on- This means both
Character movements from location to location and GM explicitly moving them around.</p></li>
<li><p><em>Channels</em>, for easily sending text to all subscribing accounts, regardless of location.</p></li>
<li><p>Account-to-Account <em>messaging</em> capability, including sending to multiple recipients
simultaneously, regardless of location.</p></li>
</ul>
<p>We will find most of these things are already part of vanilla Evennia, but that we can expand on the
defaults for our particular use-case. Below we will flesh out these components from start to finish.</p>
<section id="starting-out">
<h2>Starting out<a class="headerlink" href="#starting-out" title="Permalink to this headline"></a></h2>
<p>We will assume you start from scratch. You need Evennia installed, as per the <a class="reference internal" href="../Setup/Installation.html"><span class="doc std std-doc">Setup Quickstart</span></a>
instructions. Initialize a new game directory with <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">init</span> <span class="pre">&lt;gamedirname&gt;</span></code>. In this tutorial we assume your game dir is simply named <code class="docutils literal notranslate"><span class="pre">mygame</span></code>. You can use the default database and keep all other settings to default for now. Familiarize yourself with the
<code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder before continuing. You might want to browse the <a class="reference internal" href="Beginner-Tutorial/Part1/Beginner-Tutorial-Part1-Overview.html"><span class="doc std std-doc">Beginner Tutorial</span></a> tutorial, just to see roughly where things are modified.</p>
</section>
<section id="the-game-master-role">
<h2>The Game Master role<a class="headerlink" href="#the-game-master-role" title="Permalink to this headline"></a></h2>
<p>In brief:</p>
<ul class="simple">
<li><p>Simplest way: Being an admin, just give one account <code class="docutils literal notranslate"><span class="pre">Admins</span></code> permission using the standard <code class="docutils literal notranslate"><span class="pre">perm</span></code> command.</p></li>
<li><p>Better but more work: Make a custom command to set/unset the above, while tweaking the Character to show your renewed GM status to the other accounts.</p></li>
</ul>
<section id="the-permission-hierarchy">
<h3>The permission hierarchy<a class="headerlink" href="#the-permission-hierarchy" title="Permalink to this headline"></a></h3>
<p>Evennia has the following <a class="reference internal" href="../Components/Permissions.html"><span class="doc std std-doc">permission hierarchy</span></a> out of the box: <em>Players, Helpers, Builders, Admins</em> and finally <em>Developers</em>. We could change these but then wed need to update our Default commands to use the changes. We want to keep this simple, so instead we map our different roles on top of this permission ladder.</p>
<ol class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">Players</span></code> is the permission set on normal players. This is the default for anyone creating a new
account on the server.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Helpers</span></code> are like <code class="docutils literal notranslate"><span class="pre">Players</span></code> except they also have the ability to create/edit new help entries.
This could be granted to players who are willing to help with writing lore or custom logs for
everyone.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Builders</span></code> is not used in our case since the GM should be the only world-builder.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Admins</span></code> is the permission level the GM should have. Admins can do everything builders can
(create/describe rooms etc) but also kick accounts, rename them and things like that.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Developers</span></code>-level permission are the server administrators, the ones with the ability to
restart/shutdown the server as well as changing the permission levels.</p></li>
</ol>
<blockquote>
<div><p>The <em>superuser</em> is not part of the hierarchy and actually completely bypasses it. Well assume server admin(s) will “just” be Developers.</p>
</div></blockquote>
</section>
<section id="how-to-grant-permissions">
<h3>How to grant permissions<a class="headerlink" href="#how-to-grant-permissions" title="Permalink to this headline"></a></h3>
<p>Only <code class="docutils literal notranslate"><span class="pre">Developers</span></code> can (by default) change permission level. Only they have access to the <code class="docutils literal notranslate"><span class="pre">&#64;perm</span></code>
command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">perm</span> <span class="n">Yvonne</span>
<span class="n">Permissions</span> <span class="n">on</span> <span class="n">Yvonne</span><span class="p">:</span> <span class="n">accounts</span>
<span class="o">&gt;</span> <span class="n">perm</span> <span class="n">Yvonne</span> <span class="o">=</span> <span class="n">Admins</span>
<span class="o">&gt;</span> <span class="n">perm</span> <span class="n">Yvonne</span>
<span class="n">Permissions</span> <span class="n">on</span> <span class="n">Yvonne</span><span class="p">:</span> <span class="n">accounts</span><span class="p">,</span> <span class="n">admins</span>
<span class="o">&gt;</span> <span class="n">perm</span><span class="o">/</span><span class="k">del</span> <span class="n">Yvonne</span> <span class="o">=</span> <span class="n">Admins</span>
<span class="o">&gt;</span> <span class="n">perm</span> <span class="n">Yvonne</span>
<span class="n">Permissions</span> <span class="n">on</span> <span class="n">Yvonne</span><span class="p">:</span> <span class="n">accounts</span>
</pre></div>
</div>
<p>There is no need to remove the basic <code class="docutils literal notranslate"><span class="pre">Players</span></code> permission when adding the higher permission: the
highest will be used. Permission level names are <em>not</em> case sensitive. You can also use both plural
and singular, so “Admins” gives the same powers as “Admin”.</p>
</section>
<section id="optional-making-a-gm-granting-command">
<h3>Optional: Making a GM-granting command<a class="headerlink" href="#optional-making-a-gm-granting-command" title="Permalink to this headline"></a></h3>
<p>Use of <code class="docutils literal notranslate"><span class="pre">perm</span></code> works out of the box, but its really the bare minimum. Would it not be nice if other
accounts could tell at a glance who the GM is? Also, we shouldnt really need to remember that the
permission level is called “Admins”. It would be easier if we could just do <code class="docutils literal notranslate"><span class="pre">&#64;gm</span> <span class="pre">&lt;account&gt;</span></code> and
<code class="docutils literal notranslate"><span class="pre">&#64;notgm</span> <span class="pre">&lt;account&gt;</span></code> and at the same time change something make the new GM status apparent.</p>
<p>So lets make this possible. This is what well do:</p>
<ol class="simple">
<li><p>Well customize the default Character class. If an object of this class has a particular flag,
its name will have the string<code class="docutils literal notranslate"><span class="pre">(GM)</span></code> added to the end.</p></li>
<li><p>Well add a new command, for the server admin to assign the GM-flag properly.</p></li>
</ol>
<section id="character-modification">
<h4>Character modification<a class="headerlink" href="#character-modification" title="Permalink to this headline"></a></h4>
<p>Lets first start by customizing the Character. We recommend you browse the beginning of the
<a class="reference internal" href="../Components/Accounts.html"><span class="doc std std-doc">Account</span></a> page to make sure you know how Evennia differentiates between the OOC “Account
objects” (not to be confused with the <code class="docutils literal notranslate"><span class="pre">Accounts</span></code> permission, which is just a string specifying your
access) and the IC “Character objects”.</p>
<p>Open <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> and modify the default <code class="docutils literal notranslate"><span class="pre">Character</span></code> class:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/characters.py</span>
<span class="c1"># [...]</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="c1"># [...]</span>
<span class="k">def</span> <span class="nf">get_display_name</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looker</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This method customizes how character names are displayed. We assume</span>
<span class="sd"> only permissions of types &quot;Developers&quot; and &quot;Admins&quot; require</span>
<span class="sd"> special attention.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">key</span>
<span class="n">selfaccount</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">account</span> <span class="c1"># will be None if we are not puppeted</span>
<span class="n">lookaccount</span> <span class="o">=</span> <span class="n">looker</span><span class="o">.</span><span class="n">account</span> <span class="c1"># - &quot; -</span>
<span class="k">if</span> <span class="n">selfaccount</span> <span class="ow">and</span> <span class="n">selfaccount</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_gm</span><span class="p">:</span>
<span class="c1"># A GM. Show name as name(GM)</span>
<span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">(GM)&quot;</span>
<span class="k">if</span> <span class="n">lookaccount</span> <span class="ow">and</span> \
<span class="p">(</span><span class="n">lookaccount</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Developers&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">lookaccount</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_gm</span><span class="p">):</span>
<span class="c1"># Developers/GMs see name(#dbref) or name(GM)(#dbref)</span>
<span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">(#</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="k">return</span> <span class="n">name</span>
</pre></div>
</div>
<p>Above, we change how the Characters name is displayed: If the account controlling this Character is
a GM, we attach the string <code class="docutils literal notranslate"><span class="pre">(GM)</span></code> to the Characters name so everyone can tell whos the boss. If we
ourselves are Developers or GMs we will see database ids attached to Characters names, which can
help if doing database searches against Characters of exactly the same name. We base the “gm-
ingness” on having an flag (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">is_gm</span></code>. Well make sure new GMs
actually get this flag below.</p>
<blockquote>
<div><p><strong>Extra exercise:</strong> This will only show the <code class="docutils literal notranslate"><span class="pre">(GM)</span></code> text on <em>Characters</em> puppeted by a GM account,
that is, it will show only to those in the same location. If we wanted it to also pop up in, say,
<code class="docutils literal notranslate"><span class="pre">who</span></code> listings and channels, wed need to make a similar change to the <code class="docutils literal notranslate"><span class="pre">Account</span></code> typeclass in
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/accounts.py</span></code>. We leave this as an exercise to the reader.</p>
</div></blockquote>
</section>
<section id="new-gm-ungm-command">
<h4>New &#64;gm/&#64;ungm command<a class="headerlink" href="#new-gm-ungm-command" title="Permalink to this headline"></a></h4>
<p>We will describe in some detail how to create and add an Evennia <a class="reference internal" href="../Components/Commands.html"><span class="doc std std-doc">command</span></a> here with the
hope that we dont need to be as detailed when adding commands in the future. We will build on
Evennias default “mux-like” commands here.</p>
<p>Open <code class="docutils literal notranslate"><span class="pre">mygame/commands/command.py</span></code> and add a new Command class at the bottom:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/commands/command.py</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"># [...]</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="k">class</span> <span class="nc">CmdMakeGM</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">MuxCommand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Change an account&#39;s GM status</span>
<span class="sd"> Usage:</span>
<span class="sd"> @gm &lt;account&gt;</span>
<span class="sd"> @ungm &lt;account&gt;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># note using the key without @ means both @gm !gm etc will work</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;gm&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="s2">&quot;ungm&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:perm(Developers)&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;RP&quot;</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="s2">&quot;Implement the command&quot;</span>
<span class="n">caller</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</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="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Usage: @gm account or @ungm account&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">accountlist</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_account</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span> <span class="c1"># returns a list</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">accountlist</span><span class="p">:</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">&quot;Could not find account &#39;</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">&#39;&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">accountlist</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</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">&quot;Multiple matches for &#39;</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">&#39;: </span><span class="si">{</span><span class="n">accountlist</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">account</span> <span class="o">=</span> <span class="n">accountlist</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmdstring</span> <span class="o">==</span> <span class="s2">&quot;gm&quot;</span><span class="p">:</span>
<span class="c1"># turn someone into a GM</span>
<span class="k">if</span> <span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Admins&quot;</span><span class="p">):</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">&quot;Account </span><span class="si">{</span><span class="n">account</span><span class="si">}</span><span class="s2"> is already a GM.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Admins&quot;</span><span class="p">)</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">&quot;Account </span><span class="si">{</span><span class="n">account</span><span class="si">}</span><span class="s2"> is now a GM.&quot;</span><span class="p">)</span>
<span class="n">account</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You are now a GM (changed by </span><span class="si">{</span><span class="n">caller</span><span class="si">}</span><span class="s2">).&quot;</span><span class="p">)</span>
<span class="n">account</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_gm</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># @ungm was entered - revoke GM status from someone</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Admins&quot;</span><span class="p">):</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">&quot;Account </span><span class="si">{</span><span class="n">account</span><span class="si">}</span><span class="s2"> is not a GM.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&quot;Admins&quot;</span><span class="p">)</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">&quot;Account </span><span class="si">{</span><span class="n">account</span><span class="si">}</span><span class="s2"> is no longer a GM.&quot;</span><span class="p">)</span>
<span class="n">account</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You are no longer a GM (changed by </span><span class="si">{</span><span class="n">caller</span><span class="si">}</span><span class="s2">).&quot;</span><span class="p">)</span>
<span class="k">del</span> <span class="n">account</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_gm</span>
</pre></div>
</div>
<p>All the command does is to locate the account target and assign it the <code class="docutils literal notranslate"><span class="pre">Admins</span></code> permission if we
used <code class="docutils literal notranslate"><span class="pre">gm</span></code> or revoke it if using the <code class="docutils literal notranslate"><span class="pre">ungm</span></code> alias. We also set/unset the <code class="docutils literal notranslate"><span class="pre">is_gm</span></code> Attribute that is
expected by our new <code class="docutils literal notranslate"><span class="pre">Character.get_display_name</span></code> method from earlier.</p>
<blockquote>
<div><p>We could have made this into two separate commands or opted for a syntax like <code class="docutils literal notranslate"><span class="pre">gm/revoke</span> <span class="pre">&lt;accountname&gt;</span></code>. Instead we examine how this command was called (stored in <code class="docutils literal notranslate"><span class="pre">self.cmdstring</span></code>) in order to act accordingly. Either way works, practicality and coding style decides which to go with.</p>
</div></blockquote>
<p>To actually make this command available (only to Developers, due to the lock on it), we add it to the default Account command set. Open the file <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code> and find the <code class="docutils literal notranslate"><span class="pre">AccountCmdSet</span></code> class:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/commands/default_cmdsets.py</span>
<span class="c1"># [...]</span>
<span class="kn">from</span> <span class="nn">commands.command</span> <span class="kn">import</span> <span class="n">CmdMakeGM</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="c1"># [...]</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="c1"># [...]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdMakeGM</span><span class="p">())</span>
</pre></div>
</div>
<p>Finally, issue the <code class="docutils literal notranslate"><span class="pre">reload</span></code> command to update the server to your changes. Developer-level players
(or the superuser) should now have the <code class="docutils literal notranslate"><span class="pre">gm/ungm</span></code> command available.</p>
</section>
</section>
</section>
<section id="character-sheet">
<h2>Character sheet<a class="headerlink" href="#character-sheet" title="Permalink to this headline"></a></h2>
<p>In brief:</p>
<ul class="simple">
<li><p>Use Evennias EvTable/EvForm to build a Character sheet</p></li>
<li><p>Tie individual sheets to a given Character.</p></li>
<li><p>Add new commands to modify the Character sheet, both by Accounts and GMs.</p></li>
<li><p>Make the Character sheet lockable by a GM, so the Player can no longer modify it.</p></li>
</ul>
<section id="building-a-character-sheet">
<h3>Building a Character sheet<a class="headerlink" href="#building-a-character-sheet" title="Permalink to this headline"></a></h3>
<p>There are many ways to build a Character sheet in text, from manually pasting strings together to more automated ways. Exactly what is the best/easiest way depends on the sheet one tries to create. We will here show two examples using the <em>EvTable</em> and <em>EvForm</em> utilities.Later we will create Commands to edit and display the output from those utilities.</p>
<blockquote>
<div><p>Note that these docs dont show the color. see <a class="reference internal" href="../Concepts/Tags-Parsed-By-Evennia.html"><span class="doc std std-doc">the text tag documentation</span></a> for how to add color to the tables and forms.</p>
</div></blockquote>
<section id="making-a-sheet-with-evtable">
<h4>Making a sheet with EvTable<a class="headerlink" href="#making-a-sheet-with-evtable" title="Permalink to this headline"></a></h4>
<p><a class="reference internal" href="../Components/EvTable.html"><span class="doc std std-doc">EvTable</span></a> is a text-table generator. It helps with displaying text in ordered rows and columns. This is an example of using it in code:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># this can be tried out in a Python shell like iPython</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">evtable</span>
<span class="c1"># we hardcode these for now, we&#39;ll get them as input later</span>
<span class="n">STR</span><span class="p">,</span> <span class="n">CON</span><span class="p">,</span> <span class="n">DEX</span><span class="p">,</span> <span class="n">INT</span><span class="p">,</span> <span class="n">WIS</span><span class="p">,</span> <span class="n">CHA</span> <span class="o">=</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">13</span>
<span class="n">table</span> <span class="o">=</span> <span class="n">evtable</span><span class="o">.</span><span class="n">EvTable</span><span class="p">(</span><span class="s2">&quot;Attr&quot;</span><span class="p">,</span> <span class="s2">&quot;Value&quot;</span><span class="p">,</span>
<span class="n">table</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">[</span><span class="s2">&quot;STR&quot;</span><span class="p">,</span> <span class="s2">&quot;CON&quot;</span><span class="p">,</span> <span class="s2">&quot;DEX&quot;</span><span class="p">,</span> <span class="s2">&quot;INT&quot;</span><span class="p">,</span> <span class="s2">&quot;WIS&quot;</span><span class="p">,</span> <span class="s2">&quot;CHA&quot;</span><span class="p">],</span>
<span class="p">[</span><span class="n">STR</span><span class="p">,</span> <span class="n">CON</span><span class="p">,</span> <span class="n">DEX</span><span class="p">,</span> <span class="n">INT</span><span class="p">,</span> <span class="n">WIS</span><span class="p">,</span> <span class="n">CHA</span><span class="p">]</span>
<span class="p">],</span> <span class="n">align</span><span class="o">=</span><span class="s1">&#39;r&#39;</span><span class="p">,</span> <span class="n">border</span><span class="o">=</span><span class="s2">&quot;incols&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Above, we create a two-column table by supplying the two columns directly. We also tell the table to be right-aligned and to use the “incols” border type (borders drawns only in between columns). The <code class="docutils literal notranslate"><span class="pre">EvTable</span></code> class takes a lot of arguments for customizing its look, you can see <a class="reference external" href="https://github.com/evennia/evennia/blob/main/evennia.utils.evtable#evtable__init__">some of the possible keyword arguments here</a>. Once you have the <code class="docutils literal notranslate"><span class="pre">table</span></code> you could also retroactively add new columns and rows to it with <code class="docutils literal notranslate"><span class="pre">table.add_row()</span></code> and <code class="docutils literal notranslate"><span class="pre">table.add_column()</span></code>: if necessary the table will expand with empty rows/columns to always remain rectangular.</p>
<p>The result from printing the above table will be</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">table_string</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">table</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">table_string</span><span class="p">)</span>
<span class="n">Attr</span> <span class="o">|</span> <span class="n">Value</span>
<span class="o">~~~~~~+~~~~~~~</span>
<span class="n">STR</span> <span class="o">|</span> <span class="mi">12</span>
<span class="n">CON</span> <span class="o">|</span> <span class="mi">13</span>
<span class="n">DEX</span> <span class="o">|</span> <span class="mi">8</span>
<span class="n">INT</span> <span class="o">|</span> <span class="mi">10</span>
<span class="n">WIS</span> <span class="o">|</span> <span class="mi">9</span>
<span class="n">CHA</span> <span class="o">|</span> <span class="mi">13</span>
</pre></div>
</div>
<p>This is a minimalistic but effective Character sheet. By combining the <code class="docutils literal notranslate"><span class="pre">table_string</span></code> with other
strings one could build up a reasonably full graphical representation of a Character. For more
advanced layouts well look into EvForm next.</p>
</section>
<section id="making-a-sheet-with-evform">
<h4>Making a sheet with EvForm<a class="headerlink" href="#making-a-sheet-with-evform" title="Permalink to this headline"></a></h4>
<p><a class="reference internal" href="../Components/EvForm.html"><span class="doc std std-doc">EvForm</span></a> allows the creation of a two-dimensional “graphic” made by text characters. On this surface, one marks and tags rectangular regions (“cells”) to be filled with content. This content can be either normal strings or <code class="docutils literal notranslate"><span class="pre">EvTable</span></code> instances (see the previous section, one such instance would be the <code class="docutils literal notranslate"><span class="pre">table</span></code> variable in that example).</p>
<p>In the case of a Character sheet, these cells would be comparable to a line or box where you could
enter the name of your character or their strength score. EvMenu also easily allows to update the
content of those fields in code (it use EvTables so you rebuild the table first before re-sending it
to EvForm).</p>
<p>The drawback of EvForm is that its shape is static; if you try to put more text in a region than it
was sized for, the text will be cropped. Similarly, if you try to put an EvTable instance in a field
too small for it, the EvTable will do its best to try to resize to fit, but will eventually resort
to cropping its data or even give an error if too small to fit any data.</p>
<p>An EvForm is defined in a Python module. Create a new file <code class="docutils literal notranslate"><span class="pre">mygame/world/charsheetform.py</span></code> and
modify it thus:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1">#coding=utf-8</span>
<span class="c1"># in mygame/world/charsheetform.py</span>
<span class="n">FORMCHAR</span> <span class="o">=</span> <span class="s2">&quot;x&quot;</span>
<span class="n">TABLECHAR</span> <span class="o">=</span> <span class="s2">&quot;c&quot;</span>
<span class="n">FORM</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">.--------------------------------------.</span>
<span class="s2">| |</span>
<span class="s2">| Name: xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx |</span>
<span class="s2">| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |</span>
<span class="s2">| |</span>
<span class="s2"> &gt;------------------------------------&lt;</span>
<span class="s2">| |</span>
<span class="s2">| ccccccccccc Advantages: |</span>
<span class="s2">| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx |</span>
<span class="s2">| ccccccccccc xxxxxxxxxx3xxxxxxxxxxx |</span>
<span class="s2">| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx |</span>
<span class="s2">| ccccc2ccccc Disadvantages: |</span>
<span class="s2">| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx |</span>
<span class="s2">| ccccccccccc xxxxxxxxxx4xxxxxxxxxxx |</span>
<span class="s2">| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx |</span>
<span class="s2">| |</span>
<span class="s2">+--------------------------------------+</span>
<span class="s2">&quot;&quot;&quot;</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">#coding</span></code> statement (which must be put on the very first line to work) tells Python to use the
utf-8 encoding for the file. Using the <code class="docutils literal notranslate"><span class="pre">FORMCHAR</span></code> and <code class="docutils literal notranslate"><span class="pre">TABLECHAR</span></code> we define what single-character we
want to use to “mark” the regions of the character sheet holding cells and tables respectively.
Within each block (which must be separated from one another by at least one non-marking character) we embed identifiers 1-4 to identify each block. The identifier could be any single character except for the <code class="docutils literal notranslate"><span class="pre">FORMCHAR</span></code> and <code class="docutils literal notranslate"><span class="pre">TABLECHAR</span></code></p>
<blockquote>
<div><p>You can still use <code class="docutils literal notranslate"><span class="pre">FORMCHAR</span></code> and <code class="docutils literal notranslate"><span class="pre">TABLECHAR</span></code> elsewhere in your sheet, but not in a way that it would identify a cell/table. The smallest identifiable cell/table area is 3 characters wide including the identifier (for example <code class="docutils literal notranslate"><span class="pre">x2x</span></code>).</p>
</div></blockquote>
<p>Now we will map content to this form.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># again, this can be tested in a Python shell</span>
<span class="c1"># hard-code this info here, later we&#39;ll ask the</span>
<span class="c1"># account for this info. We will re-use the &#39;table&#39;</span>
<span class="c1"># variable from the EvTable example.</span>
<span class="n">NAME</span> <span class="o">=</span> <span class="s2">&quot;John, the wise old admin with a chip on his shoulder&quot;</span>
<span class="n">ADVANTAGES</span> <span class="o">=</span> <span class="s2">&quot;Language-wiz, Intimidation, Firebreathing&quot;</span>
<span class="n">DISADVANTAGES</span> <span class="o">=</span> <span class="s2">&quot;Bad body odor, Poor eyesight, Troubled history&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">evform</span>
<span class="c1"># load the form from the module</span>
<span class="n">form</span> <span class="o">=</span> <span class="n">evform</span><span class="o">.</span><span class="n">EvForm</span><span class="p">(</span><span class="s2">&quot;world/charsheetform.py&quot;</span><span class="p">)</span>
<span class="c1"># map the data to the form</span>
<span class="n">form</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">cells</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;1&quot;</span><span class="p">:</span><span class="n">NAME</span><span class="p">,</span> <span class="s2">&quot;3&quot;</span><span class="p">:</span> <span class="n">ADVANTAGES</span><span class="p">,</span> <span class="s2">&quot;4&quot;</span><span class="p">:</span> <span class="n">DISADVANTAGES</span><span class="p">},</span>
<span class="n">tables</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;2&quot;</span><span class="p">:</span><span class="n">table</span><span class="p">})</span>
</pre></div>
</div>
<p>We create some RP-sounding input and re-use the <code class="docutils literal notranslate"><span class="pre">table</span></code> variable from the previous <code class="docutils literal notranslate"><span class="pre">EvTable</span></code>
example.</p>
<blockquote>
<div><p>Note, that if you didnt want to create the form in a separate module you <em>could</em> also load it directly into the <code class="docutils literal notranslate"><span class="pre">EvForm</span></code> call like this: <code class="docutils literal notranslate"><span class="pre">EvForm(form={&quot;FORMCHAR&quot;:&quot;x&quot;,</span> <span class="pre">&quot;TABLECHAR&quot;:&quot;c&quot;,</span> <span class="pre">&quot;FORM&quot;:</span> <span class="pre">formstring})</span></code> where <code class="docutils literal notranslate"><span class="pre">FORM</span></code> specifies the form as a string in the same way as listed in the module above. Note however that the very first line of the <code class="docutils literal notranslate"><span class="pre">FORM</span></code> string is ignored, so start with a <code class="docutils literal notranslate"><span class="pre">\n</span></code>.</p>
</div></blockquote>
<p>We then map those to the cells of the form:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">.--------------------------------------.</span>
<span class="o">|</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">Name</span><span class="p">:</span> <span class="n">John</span><span class="p">,</span> <span class="n">the</span> <span class="n">wise</span> <span class="n">old</span> <span class="n">admin</span> <span class="k">with</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">a</span> <span class="n">chip</span> <span class="n">on</span> <span class="n">his</span> <span class="n">shoulder</span> <span class="o">|</span>
<span class="o">|</span> <span class="o">|</span>
<span class="o">&gt;------------------------------------&lt;</span>
<span class="o">|</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">Attr</span><span class="o">|</span><span class="n">Value</span> <span class="n">Advantages</span><span class="p">:</span> <span class="o">|</span>
<span class="o">|</span> <span class="o">~~~~~+~~~~~</span> <span class="n">Language</span><span class="o">-</span><span class="n">wiz</span><span class="p">,</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">STR</span><span class="o">|</span> <span class="mi">12</span> <span class="n">Intimidation</span><span class="p">,</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">CON</span><span class="o">|</span> <span class="mi">13</span> <span class="n">Firebreathing</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">DEX</span><span class="o">|</span> <span class="mi">8</span> <span class="n">Disadvantages</span><span class="p">:</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">INT</span><span class="o">|</span> <span class="mi">10</span> <span class="n">Bad</span> <span class="n">body</span> <span class="n">odor</span><span class="p">,</span> <span class="n">Poor</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">WIS</span><span class="o">|</span> <span class="mi">9</span> <span class="n">eyesight</span><span class="p">,</span> <span class="n">Troubled</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">CHA</span><span class="o">|</span> <span class="mi">13</span> <span class="n">history</span> <span class="o">|</span>
<span class="o">|</span> <span class="o">|</span>
<span class="o">+--------------------------------------+</span>
</pre></div>
</div>
<p>As seen, the texts and tables have been slotted into the text areas and line breaks have been added where needed. We chose to just enter the Advantages/Disadvantages as plain strings here, meaning long names ended up split between rows. If we wanted more control over the display we could have inserted <code class="docutils literal notranslate"><span class="pre">\n</span></code> line breaks after each line or used a borderless <code class="docutils literal notranslate"><span class="pre">EvTable</span></code> to display those as well.</p>
</section>
</section>
<section id="tie-a-character-sheet-to-a-character">
<h3>Tie a Character sheet to a Character<a class="headerlink" href="#tie-a-character-sheet-to-a-character" title="Permalink to this headline"></a></h3>
<p>We will assume we go with the <code class="docutils literal notranslate"><span class="pre">EvForm</span></code> example above. We now need to attach this to a Character so it can be modified. For this we will modify our <code class="docutils literal notranslate"><span class="pre">Character</span></code> class a little more:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/typeclasses/character.py</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">evform</span><span class="p">,</span> <span class="n">evtable</span>
<span class="p">[</span><span class="o">...</span><span class="p">]</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="p">[</span><span class="o">...</span><span class="p">]</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="s2">&quot;called only once, when object is first created&quot;</span>
<span class="c1"># we will use this to stop account from changing sheet</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sheet_locked</span> <span class="o">=</span> <span class="kc">False</span>
<span class="c1"># we store these so we can build these on demand</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">chardata</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;str&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;con&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;dex&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;int&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;wis&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;cha&quot;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
<span class="s2">&quot;advantages&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
<span class="s2">&quot;disadvantages&quot;</span><span class="p">:</span> <span class="s2">&quot;&quot;</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">charsheet</span> <span class="o">=</span> <span class="n">evform</span><span class="o">.</span><span class="n">EvForm</span><span class="p">(</span><span class="s2">&quot;world/charsheetform.py&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">update_charsheet</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">update_charsheet</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Call this to update the sheet after any of the ingoing data</span>
<span class="sd"> has changed.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">chardata</span>
<span class="n">table</span> <span class="o">=</span> <span class="n">evtable</span><span class="o">.</span><span class="n">EvTable</span><span class="p">(</span><span class="s2">&quot;Attr&quot;</span><span class="p">,</span> <span class="s2">&quot;Value&quot;</span><span class="p">,</span>
<span class="n">table</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">[</span><span class="s2">&quot;STR&quot;</span><span class="p">,</span> <span class="s2">&quot;CON&quot;</span><span class="p">,</span> <span class="s2">&quot;DEX&quot;</span><span class="p">,</span> <span class="s2">&quot;INT&quot;</span><span class="p">,</span> <span class="s2">&quot;WIS&quot;</span><span class="p">,</span> <span class="s2">&quot;CHA&quot;</span><span class="p">],</span>
<span class="p">[</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;str&quot;</span><span class="p">],</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;con&quot;</span><span class="p">],</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;dex&quot;</span><span class="p">],</span>
<span class="n">data</span><span class="p">[</span><span class="s2">&quot;int&quot;</span><span class="p">],</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;wis&quot;</span><span class="p">],</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;cha&quot;</span><span class="p">]]],</span>
<span class="n">align</span><span class="o">=</span><span class="s1">&#39;r&#39;</span><span class="p">,</span> <span class="n">border</span><span class="o">=</span><span class="s2">&quot;incols&quot;</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">charsheet</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="n">tables</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;2&quot;</span><span class="p">:</span> <span class="n">table</span><span class="p">},</span>
<span class="n">cells</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;1&quot;</span><span class="p">:</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
<span class="s2">&quot;3&quot;</span><span class="p">:</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;advantages&quot;</span><span class="p">],</span>
<span class="s2">&quot;4&quot;</span><span class="p">:</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;disadvantages&quot;</span><span class="p">]})</span>
</pre></div>
</div>
<p>Use <code class="docutils literal notranslate"><span class="pre">reload</span></code> to make this change available to all <em>newly created</em> Characters. <em>Already existing</em>
Characters will <em>not</em> have the charsheet defined, since <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> is only called once.
The easiest to force an existing Character to re-fire its <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> is to use the
<code class="docutils literal notranslate"><span class="pre">typeclass</span></code> command in-game:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typeclass</span><span class="o">/</span><span class="n">force</span> <span class="o">&lt;</span><span class="n">Character</span> <span class="n">Name</span><span class="o">&gt;</span>
</pre></div>
</div>
</section>
<section id="command-for-account-to-change-character-sheet">
<h3>Command for Account to change Character sheet<a class="headerlink" href="#command-for-account-to-change-character-sheet" title="Permalink to this headline"></a></h3>
<p>We will add a command to edit the sections of our Character sheet. 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="c1"># at the end of mygame/commands/command.py</span>
<span class="n">ALLOWED_ATTRS</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;str&quot;</span><span class="p">,</span> <span class="s2">&quot;con&quot;</span><span class="p">,</span> <span class="s2">&quot;dex&quot;</span><span class="p">,</span> <span class="s2">&quot;int&quot;</span><span class="p">,</span> <span class="s2">&quot;wis&quot;</span><span class="p">,</span> <span class="s2">&quot;cha&quot;</span><span class="p">)</span>
<span class="n">ALLOWED_FIELDNAMES</span> <span class="o">=</span> <span class="n">ALLOWED_ATTRS</span> <span class="o">+</span> \
<span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;advantages&quot;</span><span class="p">,</span> <span class="s2">&quot;disadvantages&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_validate_fieldname</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">fieldname</span><span class="p">):</span>
<span class="s2">&quot;Helper function to validate field names.&quot;</span>
<span class="k">if</span> <span class="n">fieldname</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">ALLOWED_FIELDNAMES</span><span class="p">:</span>
<span class="n">list_of_fieldnames</span> <span class="o">=</span> <span class="s2">&quot;, &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">ALLOWED_FIELDNAMES</span><span class="p">)</span>
<span class="n">err</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;Allowed field names: </span><span class="si">{</span><span class="n">list_of_fieldnames</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">if</span> <span class="n">fieldname</span> <span class="ow">in</span> <span class="n">ALLOWED_ATTRS</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">value</span><span class="o">.</span><span class="n">isdigit</span><span class="p">():</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">&quot;</span><span class="si">{</span><span class="n">fieldname</span><span class="si">}</span><span class="s2"> must receive a number.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">class</span> <span class="nc">CmdSheet</span><span class="p">(</span><span class="n">MuxCommand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Edit a field on the character sheet</span>
<span class="sd"> Usage:</span>
<span class="sd"> @sheet field value</span>
<span class="sd"> Examples:</span>
<span class="sd"> @sheet name Ulrik the Warrior</span>
<span class="sd"> @sheet dex 12</span>
<span class="sd"> @sheet advantages Super strength, Night vision</span>
<span class="sd"> If given without arguments, will view the current character sheet.</span>
<span class="sd"> Allowed field names are:</span>
<span class="sd"> name,</span>
<span class="sd"> str, con, dex, int, wis, cha,</span>
<span class="sd"> advantages, disadvantages</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;sheet&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="s2">&quot;editsheet&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd: perm(Players)&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;RP&quot;</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">caller</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</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="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
<span class="c1"># not enough arguments. Display the sheet</span>
<span class="k">if</span> <span class="n">sheet</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">caller</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">charsheet</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You have no character sheet.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="c1"># if caller.db.sheet_locked:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Your character sheet is locked.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="c1"># split input by whitespace, once</span>
<span class="n">fieldname</span><span class="p">,</span> <span class="n">value</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="kc">None</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">fieldname</span> <span class="o">=</span> <span class="n">fieldname</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="c1"># ignore case</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_validate_fieldnames</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">fieldname</span><span class="p">):</span>
<span class="k">return</span>
<span class="k">if</span> <span class="n">fieldname</span> <span class="o">==</span> <span class="s2">&quot;name&quot;</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">value</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">chardata</span><span class="p">[</span><span class="n">fieldname</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="n">caller</span><span class="o">.</span><span class="n">update_charsheet</span><span class="p">()</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">&quot;</span><span class="si">{</span><span class="n">fieldname</span><span class="si">}</span><span class="s2"> was set to </span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Most of this command is error-checking to make sure the right type of data was input. Note how the <code class="docutils literal notranslate"><span class="pre">sheet_locked</span></code> Attribute is checked and will return if not set.</p>
<p>This command you import into <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code> and add to the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>, in the same way the <code class="docutils literal notranslate"><span class="pre">&#64;gm</span></code> command was added to the <code class="docutils literal notranslate"><span class="pre">AccountCmdSet</span></code> earlier.</p>
</section>
<section id="commands-for-gm-to-change-character-sheet">
<h3>Commands for GM to change Character sheet<a class="headerlink" href="#commands-for-gm-to-change-character-sheet" title="Permalink to this headline"></a></h3>
<p>Game masters use basically the same input as Players do to edit a character sheet, except they can do it on other players than themselves. They are also not stopped by any <code class="docutils literal notranslate"><span class="pre">sheet_locked</span></code> flags.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># continuing in mygame/commands/command.py</span>
<span class="k">class</span> <span class="nc">CmdGMsheet</span><span class="p">(</span><span class="n">MuxCommand</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> GM-modification of char sheets</span>
<span class="sd"> Usage:</span>
<span class="sd"> @gmsheet character [= fieldname value]</span>
<span class="sd"> Switches:</span>
<span class="sd"> lock - lock the character sheet so the account</span>
<span class="sd"> can no longer edit it (GM&#39;s still can)</span>
<span class="sd"> unlock - unlock character sheet for Account</span>
<span class="sd"> editing.</span>
<span class="sd"> Examples:</span>
<span class="sd"> @gmsheet Tom</span>
<span class="sd"> @gmsheet Anna = str 12</span>
<span class="sd"> @gmsheet/lock Tom</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;gmsheet&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd: perm(Admins)&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;RP&quot;</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">caller</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</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="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Usage: @gmsheet character [= fieldname value]&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="p">:</span>
<span class="c1"># rhs (right-hand-side) is set only if a &#39;=&#39;</span>
<span class="c1"># was given.</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You must specify both a fieldname and value.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">fieldname</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">fieldname</span> <span class="o">=</span> <span class="n">fieldname</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_validate_fieldname</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">fieldname</span><span class="p">):</span>
<span class="k">return</span>
<span class="n">charname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">lhs</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># no &#39;=&#39;, so we must be aiming to look at a charsheet</span>
<span class="n">fieldname</span><span class="p">,</span> <span class="n">value</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
<span class="n">charname</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">character</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">charname</span><span class="p">,</span> <span class="n">global_search</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">character</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">if</span> <span class="s2">&quot;lock&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span><span class="p">:</span>
<span class="k">if</span> <span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sheet_locked</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The character sheet is already locked.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sheet_locked</span> <span class="o">=</span> <span class="kc">True</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">&quot;</span><span class="si">{</span><span class="n">character</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> can no longer edit their character sheet.&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="s2">&quot;unlock&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span><span class="p">:</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sheet_locked</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The character sheet is already unlocked.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sheet_locked</span> <span class="o">=</span> <span class="kc">False</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">&quot;</span><span class="si">{</span><span class="n">character</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> can now edit their character sheet.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">fieldname</span><span class="p">:</span>
<span class="k">if</span> <span class="n">fieldname</span> <span class="o">==</span> <span class="s2">&quot;name&quot;</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">chardata</span><span class="p">[</span><span class="n">fieldname</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="n">character</span><span class="o">.</span><span class="n">update_charsheet</span><span class="p">()</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">&quot;You set </span><span class="si">{</span><span class="n">character</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&#39;s </span><span class="si">{</span><span class="n">fieldname</span><span class="si">}</span><span class="s2"> to </span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># just display</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">charsheet</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">gmsheet</span></code> command takes an additional argument to specify which Characters character sheet to edit. It also takes <code class="docutils literal notranslate"><span class="pre">/lock</span></code> and <code class="docutils literal notranslate"><span class="pre">/unlock</span></code> switches to block the Player from tweaking their sheet.</p>
<p>Before this can be used, it should be added to the default <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code> in the same way as the normal <code class="docutils literal notranslate"><span class="pre">sheet</span></code>. Due to the lock set on it, this command will only be available to <code class="docutils literal notranslate"><span class="pre">Admins</span></code> (i.e. GMs) or higher permission levels.</p>
</section>
</section>
<section id="dice-roller">
<h2>Dice roller<a class="headerlink" href="#dice-roller" title="Permalink to this headline"></a></h2>
<p>Evennias <em>contrib</em> folder already comes with a full dice roller. To add it to the game, simply import <code class="docutils literal notranslate"><span class="pre">contrib.dice.CmdDice</span></code> into <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code> and add <code class="docutils literal notranslate"><span class="pre">CmdDice</span></code> to the <code class="docutils literal notranslate"><span class="pre">CharacterCmdset</span></code> as done with other commands in this tutorial. After a <code class="docutils literal notranslate"><span class="pre">&#64;reload</span></code> you will be able
to roll dice using normal RPG-style format:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">roll</span> <span class="mi">2</span><span class="n">d6</span> <span class="o">+</span> <span class="mi">3</span>
<span class="mi">7</span>
</pre></div>
</div>
<p>Use <code class="docutils literal notranslate"><span class="pre">help</span> <span class="pre">dice</span></code> to see what syntax is supported or look at <code class="docutils literal notranslate"><span class="pre">evennia/contrib/dice.py</span></code> to see how its implemented.</p>
</section>
<section id="rooms">
<h2>Rooms<a class="headerlink" href="#rooms" title="Permalink to this headline"></a></h2>
<p>Evennia comes with rooms out of the box, so no extra work needed. A GM will automatically have all needed building commands available. A fuller go-through is found in the <a class="reference internal" href="Beginner-Tutorial/Part1/Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">Building tutorial</span></a>.
Here are some useful highlights:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">dig</span> <span class="pre">roomname;alias</span> <span class="pre">=</span> <span class="pre">exit_there;alias,</span> <span class="pre">exit_back;alias</span></code> - this is the basic command for digging a new room. You can specify any exit-names and just enter the name of that exit to go there.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">tunnel</span> <span class="pre">direction</span> <span class="pre">=</span> <span class="pre">roomname</span></code> - this is a specialized command that only accepts directions in the cardinal directions (n,ne,e,se,s,sw,w,nw) as well as in/out and up/down. It also automatically builds “matching” exits back in the opposite direction.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">create/drop</span> <span class="pre">objectname</span></code> - this creates and drops a new simple object in the current location.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">desc</span> <span class="pre">obj</span></code> - change the look-description of the object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">tel</span> <span class="pre">object</span> <span class="pre">=</span> <span class="pre">location</span></code> - teleport an object to a named location.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">search</span> <span class="pre">objectname</span></code> - locate an object in the database.</p></li>
</ul>
<blockquote>
<div><p>TODO: Describe how to add a logging room, that logs says and poses to a log file that people can access after the fact.</p>
</div></blockquote>
</section>
<section id="channels">
<h2>Channels<a class="headerlink" href="#channels" title="Permalink to this headline"></a></h2>
<p>Evennia comes with <a class="reference internal" href="../Components/Channels.html"><span class="doc std std-doc">Channels</span></a> in-built and they are described fully in the documentation. For brevity, here are the relevant commands for normal use:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">channel/create</span> <span class="pre">=</span> <span class="pre">new_channel;alias;alias</span> <span class="pre">=</span> <span class="pre">short</span> <span class="pre">description</span></code> - Creates a new channel.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel/sub</span> <span class="pre">channel</span></code> - subscribe to a channel.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel/unsub</span> <span class="pre">channel</span></code> - unsubscribel from a channel.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channels</span></code> lists all available channels, including your subscriptions and any aliases you have set up for them.</p></li>
</ul>
<p>You can read channel history: if you for example are chatting on the <code class="docutils literal notranslate"><span class="pre">public</span></code> channel you can do
<code class="docutils literal notranslate"><span class="pre">public/history</span></code> to see the 20 last posts to that channel or <code class="docutils literal notranslate"><span class="pre">public/history</span> <span class="pre">32</span></code> to view twenty
posts backwards, starting with the 32nd from the end.</p>
</section>
<section id="pms">
<h2>PMs<a class="headerlink" href="#pms" title="Permalink to this headline"></a></h2>
<p>To send PMs to one another, players can use the <code class="docutils literal notranslate"><span class="pre">page</span></code> (or <code class="docutils literal notranslate"><span class="pre">tell</span></code>) command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">page</span> <span class="n">recipient</span> <span class="o">=</span> <span class="n">message</span>
<span class="n">page</span> <span class="n">recipient</span><span class="p">,</span> <span class="n">recipient</span><span class="p">,</span> <span class="o">...</span> <span class="o">=</span> <span class="n">message</span>
</pre></div>
</div>
<p>Players can use <code class="docutils literal notranslate"><span class="pre">page</span></code> alone to see the latest messages. This also works if they were not online
when the message was sent.</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="Evennia-for-Diku-Users.html" title="Evennia for Diku Users"
>next</a> |</li>
<li class="right" >
<a href="Tutorial-Understanding-Color-Tags.html" title="Understanding Color Tags"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" >Tutorials and How-Tos</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Evennia for roleplaying sessions</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>