evennia/docs/0.x/Manually-Configuring-Color.html

276 lines
23 KiB
HTML
Raw Normal View History

<!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>Manually Configuring Color &#8212; Evennia 0.9.5 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>
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"processClass": "tex2jax_process|mathjax_process|math|output_area"}})</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" />
</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="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Manually Configuring Color</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="manually-configuring-color">
<h1>Manually Configuring Color<a class="headerlink" href="#manually-configuring-color" title="Permalink to this headline"></a></h1>
<p>This is a small tutorial for customizing your character objects, using the example of letting users
turn on and off ANSI color parsing as an example. <code class="docutils literal notranslate"><span class="pre">&#64;options</span> <span class="pre">NOCOLOR=True</span></code> will now do what this
tutorial shows, but the tutorial subject can be applied to other toggles you may want, as well.</p>
<p>In the Building guides <a class="reference internal" href="TextTags.html#coloured-text"><span class="std std-doc">Colors</span></a> page you can learn how to add color to your
game by using special markup. Colors enhance the gaming experience, but not all users want color.
Examples would be users working from clients that dont support color, or people with various seeing
disabilities that rely on screen readers to play your game. Also, whereas Evennia normally
automatically detects if a client supports color, it may get it wrong. Being able to turn it on
manually if you know it <strong>should</strong> work could be a nice feature.</p>
<p>So heres how to allow those users to remove color. It basically means you implementing a simple
configuration system for your characters. This is the basic sequence:</p>
<ol class="simple">
<li><p>Define your own default character typeclass, inheriting from Evennias default.</p></li>
<li><p>Set an attribute on the character to control markup on/off.</p></li>
<li><p>Set your custom character class to be the default for new accounts.</p></li>
<li><p>Overload the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> method on the typeclass and change how it uses markup.</p></li>
<li><p>Create a custom command to allow users to change their setting.</p></li>
</ol>
<section id="setting-up-a-custom-typeclass">
<h2>Setting up a custom Typeclass<a class="headerlink" href="#setting-up-a-custom-typeclass" title="Permalink to this headline"></a></h2>
<p>Create a new module in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses</span></code> named, for example, <code class="docutils literal notranslate"><span class="pre">mycharacter.py</span></code>. Alternatively you
can simply add a new class to mygamegame/typeclasses/characters.py.</p>
<p>In your new module(or <a class="reference external" href="http://characters.py">characters.py</a>), create a new <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a> inheriting from
<code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code>. We will also import <code class="docutils literal notranslate"><span class="pre">evennia.utils.ansi</span></code>, which we will use later.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Character</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">ansi</span>
<span class="k">class</span> <span class="nc">ColorableCharacter</span><span class="p">(</span><span class="n">Character</span><span class="p">):</span>
<span class="n">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># set a color config value</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_color</span> <span class="o">=</span> <span class="kc">True</span>
</pre></div>
</div>
<p>Above we set a simple config value as an <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attribute</span></a>.</p>
<p>Lets make sure that new characters are created of this type. Edit your
<code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> file and add/change <code class="docutils literal notranslate"><span class="pre">BASE_CHARACTER_TYPECLASS</span></code> to point to your new
character class. Observe that this will only affect <em>new</em> characters, not those already created. You
have to convert already created characters to the new typeclass by using the <code class="docutils literal notranslate"><span class="pre">&#64;typeclass</span></code> command
(try on a secondary character first though, to test that everything works - you dont want to render
your root user unusable!).</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> @typeclass/reset/force Bob = mycharacter.ColorableCharacter
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">&#64;typeclass</span></code> changes Bobs typeclass and runs all its creation hooks all over again. The <code class="docutils literal notranslate"><span class="pre">/reset</span></code>
switch clears all attributes and properties back to the default for the new typeclass - this is
useful in this case to avoid ending up with an object having a “mixture” of properties from the old
typeclass and the new one. <code class="docutils literal notranslate"><span class="pre">/force</span></code> might be needed if you edit the typeclass and want to update the
object despite the actual typeclass name not having changed.</p>
</section>
<section id="overload-the-msg-method">
<h2>Overload the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> method<a class="headerlink" href="#overload-the-msg-method" title="Permalink to this headline"></a></h2>
<p>Next we need to overload the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> method. What we want is to check the configuration value before
calling the main function. The original <code class="docutils literal notranslate"><span class="pre">msg</span></code> method call is seen in <code class="docutils literal notranslate"><span class="pre">evennia/objects/objects.py</span></code>
and is called like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">msg</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">from_obj</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</pre></div>
</div>
<p>As long as we define a method on our custom object with the same name and keep the same number of
arguments/keywords we will overload the original. Heres how it could look:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">class</span> <span class="nc">ColorableCharacter</span><span class="p">(</span><span class="n">Character</span><span class="p">):</span>
<span class="c1"># [...]</span>
<span class="n">msg</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">from_obj</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="s2">&quot;our custom msg()&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_color</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># this would mean it was not set</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_color</span><span class="p">:</span>
<span class="c1"># remove the ANSI from the text</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">ansi</span><span class="o">.</span><span class="n">strip_ansi</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">text</span><span class="p">,</span> <span class="n">from_obj</span><span class="o">=</span><span class="n">from_obj</span><span class="p">,</span>
<span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>Above we create a custom version of the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> method. If the configuration Attribute is set, it
strips the ANSI from the text it is about to send, and then calls the parent <code class="docutils literal notranslate"><span class="pre">msg()</span></code> as usual. You
need to <code class="docutils literal notranslate"><span class="pre">&#64;reload</span></code> before your changes become visible.</p>
<p>There we go! Just flip the attribute <code class="docutils literal notranslate"><span class="pre">config_color</span></code> to False and your users will not see any color.
As superuser (assuming you use the Typeclass <code class="docutils literal notranslate"><span class="pre">ColorableCharacter</span></code>) you can test this with the <code class="docutils literal notranslate"><span class="pre">&#64;py</span></code>
command:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> @py self.db.config_color = False
</pre></div>
</div>
</section>
<section id="custom-color-config-command">
<h2>Custom color config command<a class="headerlink" href="#custom-color-config-command" title="Permalink to this headline"></a></h2>
<p>For completeness, lets add a custom command so users can turn off their color display themselves if
they want.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/commands</span></code>, create a new file, call it for example <code class="docutils literal notranslate"><span class="pre">configcmds.py</span></code> (its likely that
youll want to add other commands for configuration down the line). You can also copy/rename the
command template.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
<span class="k">class</span> <span class="nc">CmdConfigColor</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Configures your color</span>
<span class="sd"> Usage:</span>
<span class="sd"> @togglecolor on|off</span>
<span class="sd"> This turns ANSI-colors on/off.</span>
<span class="sd"> Default is on.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;@togglecolor&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;@setcolor&quot;</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;implements the command&quot;</span>
<span class="c1"># first we must remove whitespace from the argument</span>
<span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="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="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;on&quot;</span><span class="p">,</span> <span class="s2">&quot;off&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Usage: @setcolor on|off&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">==</span> <span class="s2">&quot;on&quot;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_color</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># send a message with a tiny bit of formatting, just for fun</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Color was turned |won|W.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_color</span> <span class="o">=</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Color was turned off.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Lastly, we make this command available to the user by adding it to the default <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code> in
<code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code> and reloading the server. Make sure you also import the
command:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mygame.commands</span> <span class="kn">import</span> <span class="n">configcmds</span>
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
<span class="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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Populates the cmdset</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_cmdset_creation</span><span class="p">()</span>
<span class="c1">#</span>
<span class="c1"># any commands you add below will overload the default ones.</span>
<span class="c1">#</span>
<span class="c1"># here is the only line that we edit</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">configcmds</span><span class="o">.</span><span class="n">CmdConfigColor</span><span class="p">())</span>
</pre></div>
</div>
</section>
<section id="more-colors">
<h2>More colors<a class="headerlink" href="#more-colors" title="Permalink to this headline"></a></h2>
<p>Apart from ANSI colors, Evennia also supports <strong>Xterm256</strong> colors (See [Colors](./TextTags.md#colored-
text)). The <code class="docutils literal notranslate"><span class="pre">msg()</span></code> method supports the <code class="docutils literal notranslate"><span class="pre">xterm256</span></code> keyword for manually activating/deactiving
xterm256. It should be easy to expand the above example to allow players to customize xterm256
regardless of if Evennia thinks their client supports it or not.</p>
<p>To get a better understanding of how <code class="docutils literal notranslate"><span class="pre">msg()</span></code> works with keywords, you can try this as superuser:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@py self.msg(&quot;|123Dark blue with xterm256, bright blue with ANSI&quot;, xterm256=True)
@py self.msg(&quot;|gThis should be uncolored&quot;, nomarkup=True)
</pre></div>
</div>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="index.html">
<img class="logo" src="_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Manually Configuring Color</a><ul>
<li><a class="reference internal" href="#setting-up-a-custom-typeclass">Setting up a custom Typeclass</a></li>
<li><a class="reference internal" href="#overload-the-msg-method">Overload the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> method</a></li>
<li><a class="reference internal" href="#custom-color-config-command">Custom color config command</a></li>
<li><a class="reference internal" href="#more-colors">More colors</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="_sources/Manually-Configuring-Color.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
<a href="https://discord.gg/NecFePw">Discord</a> -
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
</li>
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="../1.0-dev/index.html">1.0-dev (develop branch)</a></li>
<li><a href="Manually-Configuring-Color.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Manually Configuring Color</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>