Updated HTML docs

This commit is contained in:
Evennia docbuilder action 2022-09-17 23:44:19 +00:00
parent 937794ad0b
commit dcc4cbe66f
316 changed files with 34330 additions and 3279 deletions

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="9. Parsing Command input" href="More-on-Commands.html" />
<link rel="prev" title="7. Making objects persistent" href="Learning-Typeclasses.html" />
<link rel="next" title="9. Parsing Command input" href="Beginner-Tutorial-More-on-Commands.html" />
<link rel="prev" title="7. Making objects persistent" href="Beginner-Tutorial-Learning-Typeclasses.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="More-on-Commands.html" title="9. Parsing Command input"
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Learning-Typeclasses.html" title="7. Making objects persistent"
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -215,7 +215,7 @@ looks for to figure out what a Command actually does. Modify your <code class="d
<p>First we added a docstring. This is always a good thing to do in general, but for a Command class, it will also
automatically become the in-game help entry! Next we add the <code class="docutils literal notranslate"><span class="pre">func</span></code> method. It has one active line where it
makes use of some of those variables we found the Command offers to us. If you did the
<a class="reference internal" href="Python-basic-introduction.html"><span class="doc std std-doc">basic Python tutorial</span></a>, you will recognize <code class="docutils literal notranslate"><span class="pre">.msg</span></code> - this will send a message
<a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html"><span class="doc std std-doc">basic Python tutorial</span></a>, you will recognize <code class="docutils literal notranslate"><span class="pre">.msg</span></code> - this will send a message
to the object it is attached to us - in this case <code class="docutils literal notranslate"><span class="pre">self.caller</span></code>, that is, us. We grab <code class="docutils literal notranslate"><span class="pre">self.args</span></code> and includes
that in the message.</p>
<p>Since we havent changed <code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code>, that will work as before. Reload and re-add this command to ourselves to
@ -472,15 +472,15 @@ get into how we replace and extend Evennias default Commands.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Learning-Typeclasses.html"
<p class="topless"><a href="Beginner-Tutorial-Learning-Typeclasses.html"
title="previous chapter"><span class="section-number">7. </span>Making objects persistent</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="More-on-Commands.html"
<p class="topless"><a href="Beginner-Tutorial-More-on-Commands.html"
title="next chapter"><span class="section-number">9. </span>Parsing Command input</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Adding-Commands.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -496,7 +496,7 @@ get into how we replace and extend Evennias default Commands.</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Adding-Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Adding-Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -514,10 +514,10 @@ get into how we replace and extend Evennias default Commands.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="More-on-Commands.html" title="9. Parsing Command input"
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
>next</a> |</li>
<li class="right" >
<a href="Learning-Typeclasses.html" title="7. Making objects persistent"
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,7 +17,7 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="2. The Tutorial World" href="Tutorial-World.html" />
<link rel="next" title="2. The Tutorial World" href="Beginner-Tutorial-Tutorial-World.html" />
<link rel="prev" title="Part 1: What we have" href="Beginner-Tutorial-Part1-Intro.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
@ -30,7 +30,7 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Tutorial-World.html" title="2. The Tutorial World"
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part1-Intro.html" title="Part 1: What we have"
@ -192,7 +192,7 @@ message string is in the future, you can use examine.</p>
the raw description of your current room (including color codes), so that you can copy-and-paste to
set its description to something else.</p>
<p>You create new Commands (or modify existing ones) in Python outside the game. We will get to that
later, in the <a class="reference internal" href="Adding-Commands.html"><span class="doc std std-doc">Commands tutorial</span></a>.</p>
later, in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Commands tutorial</span></a>.</p>
</section>
<section id="get-a-personality">
<h2><span class="section-number">1.5. </span>Get a Personality<a class="headerlink" href="#get-a-personality" title="Permalink to this headline"></a></h2>
@ -383,12 +383,12 @@ example. Evennia comes with a tutorial world for you to explore. We will try tha
<p class="topless"><a href="Beginner-Tutorial-Part1-Intro.html"
title="previous chapter">Part 1: What we have</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Tutorial-World.html"
<p class="topless"><a href="Beginner-Tutorial-Tutorial-World.html"
title="next chapter"><span class="section-number">2. </span>The Tutorial World</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Building-Quickstart.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Building-Quickstart.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -404,7 +404,7 @@ example. Evennia comes with a tutorial world for you to explore. We will try tha
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Building-Quickstart.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Building-Quickstart.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -422,7 +422,7 @@ example. Evennia comes with a tutorial world for you to explore. We will try tha
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Tutorial-World.html" title="2. The Tutorial World"
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part1-Intro.html" title="Part 1: What we have"

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="11. Searching for things" href="Searching-Things.html" />
<link rel="prev" title="9. Parsing Command input" href="More-on-Commands.html" />
<link rel="next" title="11. Searching for things" href="Beginner-Tutorial-Searching-Things.html" />
<link rel="prev" title="9. Parsing Command input" href="Beginner-Tutorial-More-on-Commands.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Searching-Things.html" title="11. Searching for things"
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="More-on-Commands.html" title="9. Parsing Command input"
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -130,15 +130,15 @@ You can find the parent class for Accounts in <code class="docutils literal notr
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="More-on-Commands.html"
<p class="topless"><a href="Beginner-Tutorial-More-on-Commands.html"
title="previous chapter"><span class="section-number">9. </span>Parsing Command input</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Searching-Things.html"
<p class="topless"><a href="Beginner-Tutorial-Searching-Things.html"
title="next chapter"><span class="section-number">11. </span>Searching for things</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Creating-Things.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Creating-Things.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -154,7 +154,7 @@ You can find the parent class for Accounts in <code class="docutils literal notr
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Creating-Things.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Creating-Things.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -172,10 +172,10 @@ You can find the parent class for Accounts in <code class="docutils literal notr
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Searching-Things.html" title="11. Searching for things"
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
>next</a> |</li>
<li class="right" >
<a href="More-on-Commands.html" title="9. Parsing Command input"
<a href="Beginner-Tutorial-More-on-Commands.html" title="9. Parsing Command input"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -18,7 +18,7 @@
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Part 2: What we want" href="../Part2/Beginner-Tutorial-Part2-Intro.html" />
<link rel="prev" title="11. Searching for things" href="Searching-Things.html" />
<link rel="prev" title="11. Searching for things" href="Beginner-Tutorial-Searching-Things.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -33,7 +33,7 @@
<a href="../Part2/Beginner-Tutorial-Part2-Intro.html" title="Part 2: What we want"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Searching-Things.html" title="11. Searching for things"
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -486,7 +486,7 @@ will be about.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Searching-Things.html"
<p class="topless"><a href="Beginner-Tutorial-Searching-Things.html"
title="previous chapter"><span class="section-number">11. </span>Searching for things</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="../Part2/Beginner-Tutorial-Part2-Intro.html"
@ -494,7 +494,7 @@ will be about.</p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Django-queries.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Django-queries.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -510,7 +510,7 @@ will be about.</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Django-queries.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Django-queries.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -531,7 +531,7 @@ will be about.</p>
<a href="../Part2/Beginner-Tutorial-Part2-Intro.html" title="Part 2: What we want"
>next</a> |</li>
<li class="right" >
<a href="Searching-Things.html" title="11. Searching for things"
<a href="Beginner-Tutorial-Searching-Things.html" title="11. Searching for things"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="7. Making objects persistent" href="Learning-Typeclasses.html" />
<link rel="prev" title="5. Introduction to Python classes and objects" href="Python-classes-and-objects.html" />
<link rel="next" title="7. Making objects persistent" href="Beginner-Tutorial-Learning-Typeclasses.html" />
<link rel="prev" title="5. Introduction to Python classes and objects" href="Beginner-Tutorial-Python-classes-and-objects.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Learning-Typeclasses.html" title="7. Making objects persistent"
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -212,15 +212,15 @@ to look it up in the docs:</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Python-classes-and-objects.html"
<p class="topless"><a href="Beginner-Tutorial-Python-classes-and-objects.html"
title="previous chapter"><span class="section-number">5. </span>Introduction to Python classes and objects</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Learning-Typeclasses.html"
<p class="topless"><a href="Beginner-Tutorial-Learning-Typeclasses.html"
title="next chapter"><span class="section-number">7. </span>Making objects persistent</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Evennia-Library-Overview.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Evennia-Library-Overview.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -236,7 +236,7 @@ to look it up in the docs:</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Evennia-Library-Overview.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Evennia-Library-Overview.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -254,10 +254,10 @@ to look it up in the docs:</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Learning-Typeclasses.html" title="7. Making objects persistent"
<a href="Beginner-Tutorial-Learning-Typeclasses.html" title="7. Making objects persistent"
>next</a> |</li>
<li class="right" >
<a href="Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="5. Introduction to Python classes and objects" href="Python-classes-and-objects.html" />
<link rel="prev" title="3. Intro to using Python with Evennia" href="Python-basic-introduction.html" />
<link rel="next" title="5. Introduction to Python classes and objects" href="Beginner-Tutorial-Python-classes-and-objects.html" />
<link rel="prev" title="3. Intro to using Python with Evennia" href="Beginner-Tutorial-Python-basic-introduction.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -263,7 +263,7 @@ people change and re-structure this in various ways to better fit their ideas.</
<ul class="simple">
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/world/batch_cmds.ev">batch_cmds.ev</a> - This is an <code class="docutils literal notranslate"><span class="pre">.ev</span></code> file, which is essentially
just a list of Evennia commands to execute in sequence. This one is empty and ready to expand on. The
<a class="reference internal" href="Tutorial-World.html"><span class="doc std std-doc">Tutorial World</span></a> was built with such a batch-file.</p></li>
<a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html"><span class="doc std std-doc">Tutorial World</span></a> was built with such a batch-file.</p></li>
<li><p><a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/game_template/world/prototypes.py">prototypes.py</a> - A <a class="reference internal" href="../../../Components/Prototypes.html"><span class="doc std std-doc">prototype</span></a> is a way
to easily vary objects without changing their base typeclass. For example, one could use prototypes to
tell that Two goblins, while both of the class Goblin (so they follow the same code logic), should have different
@ -310,15 +310,15 @@ equipment, stats and looks.</p></li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Python-basic-introduction.html"
<p class="topless"><a href="Beginner-Tutorial-Python-basic-introduction.html"
title="previous chapter"><span class="section-number">3. </span>Intro to using Python with Evennia</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Python-classes-and-objects.html"
<p class="topless"><a href="Beginner-Tutorial-Python-classes-and-objects.html"
title="next chapter"><span class="section-number">5. </span>Introduction to Python classes and objects</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Gamedir-Overview.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Gamedir-Overview.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -334,7 +334,7 @@ equipment, stats and looks.</p></li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Gamedir-Overview.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Gamedir-Overview.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -352,10 +352,10 @@ equipment, stats and looks.</p></li>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
<a href="Beginner-Tutorial-Python-classes-and-objects.html" title="5. Introduction to Python classes and objects"
>next</a> |</li>
<li class="right" >
<a href="Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="8. Adding custom commands" href="Adding-Commands.html" />
<link rel="prev" title="6. Overview of the Evennia library" href="Evennia-Library-Overview.html" />
<link rel="next" title="8. Adding custom commands" href="Beginner-Tutorial-Adding-Commands.html" />
<link rel="prev" title="6. Overview of the Evennia library" href="Beginner-Tutorial-Evennia-Library-Overview.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Adding-Commands.html" title="8. Adding custom commands"
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -52,7 +52,7 @@
<section class="tex2jax_ignore mathjax_ignore" id="making-objects-persistent">
<h1><span class="section-number">7. </span>Making objects persistent<a class="headerlink" href="#making-objects-persistent" title="Permalink to this headline"></a></h1>
<p>Now that we have learned a little about how to find things in the Evennia library, lets use it.</p>
<p>In the <a class="reference internal" href="Python-classes-and-objects.html"><span class="doc std std-doc">Python classes and objects</span></a> lesson we created the dragons Fluffy, Cuddly
<p>In the <a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html"><span class="doc std std-doc">Python classes and objects</span></a> lesson we created the dragons Fluffy, Cuddly
and Smaug and made them fly and breathe fire. So far our dragons are short-lived - whenever we <code class="docutils literal notranslate"><span class="pre">restart</span></code>
the server or <code class="docutils literal notranslate"><span class="pre">quit()</span></code> out of python mode they are gone.</p>
<p>This is what you should have in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/monsters.py</span></code> so far:</p>
@ -296,7 +296,7 @@ Persistent attributes:
-------------------------------------------------------------------------------
</pre></div>
</div>
<p>We used the <code class="docutils literal notranslate"><span class="pre">examine</span></code> command briefly in the <a class="reference internal" href="Building-Quickstart.html"><span class="doc std std-doc">lesson about building in-game</span></a>. Now these lines
<p>We used the <code class="docutils literal notranslate"><span class="pre">examine</span></code> command briefly in the <a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">lesson about building in-game</span></a>. Now these lines
may be more useful to us:</p>
<ul class="simple">
<li><p><strong>Name/key</strong> - The name of this thing. The value <code class="docutils literal notranslate"><span class="pre">(#14)</span></code> is probably different for you. This is the
@ -401,7 +401,7 @@ Non-Persistent attributes:
<li><p><strong>Session id(s)</strong>: This identifies the <em>Session</em> (that is, the individual connection to a players game client).</p></li>
<li><p><strong>Account</strong> shows, well the <code class="docutils literal notranslate"><span class="pre">Account</span></code> object associated with this Character and Session.</p></li>
<li><p><strong>Stored/Merged Cmdsets</strong> and <strong>Commands available</strong> is related to which <em>Commands</em> are stored on you. We will
get to them in the <a class="reference internal" href="Adding-Commands.html"><span class="doc std std-doc">next lesson</span></a>. For now its enough to know these consitute all the
get to them in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">next lesson</span></a>. For now its enough to know these consitute all the
commands available to you at a given moment.</p></li>
<li><p><strong>Non-Persistent attributes</strong> are Attributes that are only stored temporarily and will go away on next reload.</p></li>
</ul>
@ -706,15 +706,15 @@ this tutorial. But thats enough of them for now. Its time to take some act
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Evennia-Library-Overview.html"
<p class="topless"><a href="Beginner-Tutorial-Evennia-Library-Overview.html"
title="previous chapter"><span class="section-number">6. </span>Overview of the Evennia library</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Adding-Commands.html"
<p class="topless"><a href="Beginner-Tutorial-Adding-Commands.html"
title="next chapter"><span class="section-number">8. </span>Adding custom commands</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Learning-Typeclasses.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Learning-Typeclasses.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -730,7 +730,7 @@ this tutorial. But thats enough of them for now. Its time to take some act
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Learning-Typeclasses.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Learning-Typeclasses.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -748,10 +748,10 @@ this tutorial. But thats enough of them for now. Its time to take some act
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Adding-Commands.html" title="8. Adding custom commands"
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
>next</a> |</li>
<li class="right" >
<a href="Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="10. Creating things" href="Creating-Things.html" />
<link rel="prev" title="8. Adding custom commands" href="Adding-Commands.html" />
<link rel="next" title="10. Creating things" href="Beginner-Tutorial-Creating-Things.html" />
<link rel="prev" title="8. Adding custom commands" href="Beginner-Tutorial-Adding-Commands.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Creating-Things.html" title="10. Creating things"
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Adding-Commands.html" title="8. Adding custom commands"
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -199,8 +199,8 @@ You hit smaug with sword!
<section id="adding-a-command-to-an-object">
<h2><span class="section-number">9.2. </span>Adding a Command to an object<a class="headerlink" href="#adding-a-command-to-an-object" title="Permalink to this headline"></a></h2>
<p>The commands of a cmdset attached to an object with <code class="docutils literal notranslate"><span class="pre">obj.cmdset.add()</span></code> will by default be made available to that object
but <em>also to those in the same location as that object</em>. If you did the <a class="reference internal" href="Building-Quickstart.html"><span class="doc std std-doc">Building introduction</span></a>
youve seen an example of this with the “Red Button” object. The <a class="reference internal" href="Tutorial-World.html"><span class="doc std std-doc">Tutorial world</span></a>
but <em>also to those in the same location as that object</em>. If you did the <a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">Building introduction</span></a>
youve seen an example of this with the “Red Button” object. The <a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html"><span class="doc std std-doc">Tutorial world</span></a>
also has many examples of objects with commands on them.</p>
<p>To show how this could work, lets put our hit Command on our simple <code class="docutils literal notranslate"><span class="pre">sword</span></code> object from the previous section.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; self.search(&quot;sword&quot;).cmdset.add(&quot;commands.mycommands.MyCmdSet&quot;, persistent=True)
@ -582,15 +582,15 @@ command on ourselves.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Adding-Commands.html"
<p class="topless"><a href="Beginner-Tutorial-Adding-Commands.html"
title="previous chapter"><span class="section-number">8. </span>Adding custom commands</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Creating-Things.html"
<p class="topless"><a href="Beginner-Tutorial-Creating-Things.html"
title="next chapter"><span class="section-number">10. </span>Creating things</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/More-on-Commands.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-More-on-Commands.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -606,7 +606,7 @@ command on ourselves.</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="More-on-Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-More-on-Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -624,10 +624,10 @@ command on ourselves.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Creating-Things.html" title="10. Creating things"
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
>next</a> |</li>
<li class="right" >
<a href="Adding-Commands.html" title="8. Adding custom commands"
<a href="Beginner-Tutorial-Adding-Commands.html" title="8. Adding custom commands"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,7 +17,7 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="1. Using commands and building stuff" href="Building-Quickstart.html" />
<link rel="next" title="1. Using commands and building stuff" href="Beginner-Tutorial-Building-Quickstart.html" />
<link rel="prev" title="Beginner Tutorial" href="../Beginner-Tutorial-Intro.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
@ -30,7 +30,7 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Building-Quickstart.html" title="1. Using commands and building stuff"
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="../Beginner-Tutorial-Intro.html" title="Beginner Tutorial"
@ -76,18 +76,18 @@ these concepts in the context of Evennia before.</p>
<h2>Lessons<a class="headerlink" href="#lessons" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Building-Quickstart.html">1. Using commands and building stuff</a></li>
<li class="toctree-l1"><a class="reference internal" href="Tutorial-World.html">2. The Tutorial World</a></li>
<li class="toctree-l1"><a class="reference internal" href="Python-basic-introduction.html">3. Intro to using Python with Evennia</a></li>
<li class="toctree-l1"><a class="reference internal" href="Gamedir-Overview.html">4. Overview of your new Game Dir</a></li>
<li class="toctree-l1"><a class="reference internal" href="Python-classes-and-objects.html">5. Introduction to Python classes and objects</a></li>
<li class="toctree-l1"><a class="reference internal" href="Evennia-Library-Overview.html">6. Overview of the Evennia library</a></li>
<li class="toctree-l1"><a class="reference internal" href="Learning-Typeclasses.html">7. Making objects persistent</a></li>
<li class="toctree-l1"><a class="reference internal" href="Adding-Commands.html">8. Adding custom commands</a></li>
<li class="toctree-l1"><a class="reference internal" href="More-on-Commands.html">9. Parsing Command input</a></li>
<li class="toctree-l1"><a class="reference internal" href="Creating-Things.html">10. Creating things</a></li>
<li class="toctree-l1"><a class="reference internal" href="Searching-Things.html">11. Searching for things</a></li>
<li class="toctree-l1"><a class="reference internal" href="Django-queries.html">12. Advanced searching - Django Database queries</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html">1. Using commands and building stuff</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html">2. The Tutorial World</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html">3. Intro to using Python with Evennia</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html">4. Overview of your new Game Dir</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html">5. Introduction to Python classes and objects</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html">6. Overview of the Evennia library</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html">8. Adding custom commands</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html">9. Parsing Command input</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html">10. Creating things</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html">11. Searching for things</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html">12. Advanced searching - Django Database queries</a></li>
</ul>
</div>
</section>
@ -95,97 +95,97 @@ these concepts in the context of Evennia before.</p>
<h2>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Building-Quickstart.html">1. Using commands and building stuff</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#getting-help">1.1. Getting help</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#looking-around">1.2. Looking around</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#stepping-down-from-godhood">1.3. Stepping Down From Godhood</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#creating-an-object">1.4. Creating an Object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#get-a-personality">1.5. Get a Personality</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#pushing-your-buttons">1.6. Pushing Your Buttons</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#making-yourself-a-house">1.7. Making Yourself a House</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#reshuffling-the-world">1.8. Reshuffling the World</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#adding-a-help-entry">1.9. Adding a Help Entry</a></li>
<li class="toctree-l2"><a class="reference internal" href="Building-Quickstart.html#adding-a-world">1.10. Adding a World</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html">1. Using commands and building stuff</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#getting-help">1.1. Getting help</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#looking-around">1.2. Looking around</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#stepping-down-from-godhood">1.3. Stepping Down From Godhood</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#creating-an-object">1.4. Creating an Object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#get-a-personality">1.5. Get a Personality</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#pushing-your-buttons">1.6. Pushing Your Buttons</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#making-yourself-a-house">1.7. Making Yourself a House</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#reshuffling-the-world">1.8. Reshuffling the World</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#adding-a-help-entry">1.9. Adding a Help Entry</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html#adding-a-world">1.10. Adding a World</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Tutorial-World.html">2. The Tutorial World</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Tutorial-World.html#gameplay">2.1. Gameplay</a></li>
<li class="toctree-l2"><a class="reference internal" href="Tutorial-World.html#once-you-are-done-or-had-enough">2.2. Once you are done (or had enough)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Tutorial-World.html#uninstall-the-tutorial-world">2.3. Uninstall the tutorial world</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html">2. The Tutorial World</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html#gameplay">2.1. Gameplay</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html#once-you-are-done-or-had-enough">2.2. Once you are done (or had enough)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Tutorial-World.html#uninstall-the-tutorial-world">2.3. Uninstall the tutorial world</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Python-basic-introduction.html">3. Intro to using Python with Evennia</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#evennia-hello-world">3.1. Evennia Hello world</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#making-some-text-graphics">3.2. Making some text graphics</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#importing-code-from-other-modules">3.3. Importing code from other modules</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#sending-text-to-others">3.4. Sending text to others</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#parsing-python-errors">3.5. Parsing Python errors</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#passing-arguments-to-functions">3.6. Passing arguments to functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#finding-others-to-send-to">3.7. Finding others to send to</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#multi-line-py">3.8. Multi-line py</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#other-ways-to-test-python-code">3.9. Other ways to test Python code</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#ipython">3.10. ipython</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-basic-introduction.html#conclusions">3.11. Conclusions</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html">3. Intro to using Python with Evennia</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#evennia-hello-world">3.1. Evennia Hello world</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#making-some-text-graphics">3.2. Making some text graphics</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#importing-code-from-other-modules">3.3. Importing code from other modules</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#sending-text-to-others">3.4. Sending text to others</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#parsing-python-errors">3.5. Parsing Python errors</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#passing-arguments-to-functions">3.6. Passing arguments to functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#finding-others-to-send-to">3.7. Finding others to send to</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#multi-line-py">3.8. Multi-line py</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#other-ways-to-test-python-code">3.9. Other ways to test Python code</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#ipython">3.10. ipython</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html#conclusions">3.11. Conclusions</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Gamedir-Overview.html">4. Overview of your new Game Dir</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Gamedir-Overview.html#commands">4.1. commands/</a></li>
<li class="toctree-l2"><a class="reference internal" href="Gamedir-Overview.html#server">4.2. server/</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html">4. Overview of your new Game Dir</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html#commands">4.1. commands/</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Gamedir-Overview.html#server">4.2. server/</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Python-classes-and-objects.html">5. Introduction to Python classes and objects</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Python-classes-and-objects.html#importing-things">5.1. Importing things</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-classes-and-objects.html#on-classes-and-objects">5.2. On classes and objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Python-classes-and-objects.html#summary">5.3. Summary</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html">5. Introduction to Python classes and objects</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#importing-things">5.1. Importing things</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#on-classes-and-objects">5.2. On classes and objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html#summary">5.3. Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Evennia-Library-Overview.html">6. Overview of the Evennia library</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Evennia-Library-Overview.html#where-is-it">6.1. Where is it?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Evennia-Library-Overview.html#an-example-of-exploring-the-library">6.2. An example of exploring the library</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html">6. Overview of the Evennia library</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html#where-is-it">6.1. Where is it?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Evennia-Library-Overview.html#an-example-of-exploring-the-library">6.2. An example of exploring the library</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Learning-Typeclasses.html">7. Making objects persistent</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Learning-Typeclasses.html#our-first-persistent-object">7.1. Our first persistent object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Learning-Typeclasses.html#typeclasses">7.2. Typeclasses</a></li>
<li class="toctree-l2"><a class="reference internal" href="Learning-Typeclasses.html#modifying-ourselves">7.3. Modifying ourselves</a></li>
<li class="toctree-l2"><a class="reference internal" href="Learning-Typeclasses.html#extra-credits">7.4. Extra Credits</a></li>
<li class="toctree-l2"><a class="reference internal" href="Learning-Typeclasses.html#conclusions">7.5. Conclusions</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html">7. Making objects persistent</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#our-first-persistent-object">7.1. Our first persistent object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#typeclasses">7.2. Typeclasses</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#modifying-ourselves">7.3. Modifying ourselves</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#extra-credits">7.4. Extra Credits</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html#conclusions">7.5. Conclusions</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Adding-Commands.html">8. Adding custom commands</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Adding-Commands.html#creating-a-custom-command">8.1. Creating a custom command</a></li>
<li class="toctree-l2"><a class="reference internal" href="Adding-Commands.html#summary">8.2. Summary</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html">8. Adding custom commands</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html#creating-a-custom-command">8.1. Creating a custom command</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html#summary">8.2. Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="More-on-Commands.html">9. Parsing Command input</a><ul>
<li class="toctree-l2"><a class="reference internal" href="More-on-Commands.html#more-advanced-parsing">9.1. More advanced parsing</a></li>
<li class="toctree-l2"><a class="reference internal" href="More-on-Commands.html#adding-a-command-to-an-object">9.2. Adding a Command to an object</a></li>
<li class="toctree-l2"><a class="reference internal" href="More-on-Commands.html#adding-the-command-to-a-default-cmdset">9.3. Adding the Command to a default Cmdset</a></li>
<li class="toctree-l2"><a class="reference internal" href="More-on-Commands.html#replace-a-default-command">9.4. Replace a default command</a></li>
<li class="toctree-l2"><a class="reference internal" href="More-on-Commands.html#summary">9.5. Summary</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html">9. Parsing Command input</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#more-advanced-parsing">9.1. More advanced parsing</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#adding-a-command-to-an-object">9.2. Adding a Command to an object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#adding-the-command-to-a-default-cmdset">9.3. Adding the Command to a default Cmdset</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#replace-a-default-command">9.4. Replace a default command</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-More-on-Commands.html#summary">9.5. Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Creating-Things.html">10. Creating things</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Creating-Things.html#creating-objects">10.1. Creating Objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Creating-Things.html#creating-accounts">10.2. Creating Accounts</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html">10. Creating things</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html#creating-objects">10.1. Creating Objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Creating-Things.html#creating-accounts">10.2. Creating Accounts</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Searching-Things.html">11. Searching for things</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Searching-Things.html#main-search-functions">11.1. Main search functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Searching-Things.html#searching-using-object-search">11.2. Searching using Object.search</a></li>
<li class="toctree-l2"><a class="reference internal" href="Searching-Things.html#what-can-be-searched-for">11.3. What can be searched for</a></li>
<li class="toctree-l2"><a class="reference internal" href="Searching-Things.html#finding-objects-relative-each-other">11.4. Finding objects relative each other</a></li>
<li class="toctree-l2"><a class="reference internal" href="Searching-Things.html#summary">11.5. Summary</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html">11. Searching for things</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#main-search-functions">11.1. Main search functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#searching-using-object-search">11.2. Searching using Object.search</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#what-can-be-searched-for">11.3. What can be searched for</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#finding-objects-relative-each-other">11.4. Finding objects relative each other</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#summary">11.5. Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Django-queries.html">12. Advanced searching - Django Database queries</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#queryset-field-lookups">12.1. Queryset field lookups</a></li>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#get-that-werewolf">12.2. Get that werewolf …</a></li>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#complex-queries">12.3. Complex queries</a></li>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#annotations">12.4. Annotations</a></li>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#f-objects">12.5. F-objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#grouping-and-returning-only-certain-properties">12.6. Grouping and returning only certain properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="Django-queries.html#conclusions">12.7. Conclusions</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html">12. Advanced searching - Django Database queries</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#queryset-field-lookups">12.1. Queryset field lookups</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#get-that-werewolf">12.2. Get that werewolf …</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#complex-queries">12.3. Complex queries</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#annotations">12.4. Annotations</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#f-objects">12.5. F-objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#grouping-and-returning-only-certain-properties">12.6. Grouping and returning only certain properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Django-queries.html#conclusions">12.7. Conclusions</a></li>
</ul>
</li>
</ul>
@ -226,7 +226,7 @@ these concepts in the context of Evennia before.</p>
<p class="topless"><a href="../Beginner-Tutorial-Intro.html"
title="previous chapter">Beginner Tutorial</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Building-Quickstart.html"
<p class="topless"><a href="Beginner-Tutorial-Building-Quickstart.html"
title="next chapter"><span class="section-number">1. </span>Using commands and building stuff</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
@ -265,7 +265,7 @@ these concepts in the context of Evennia before.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Building-Quickstart.html" title="1. Using commands and building stuff"
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
>next</a> |</li>
<li class="right" >
<a href="../Beginner-Tutorial-Intro.html" title="Beginner Tutorial"

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="4. Overview of your new Game Dir" href="Gamedir-Overview.html" />
<link rel="prev" title="2. The Tutorial World" href="Tutorial-World.html" />
<link rel="next" title="4. Overview of your new Game Dir" href="Beginner-Tutorial-Gamedir-Overview.html" />
<link rel="prev" title="2. The Tutorial World" href="Beginner-Tutorial-Tutorial-World.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Gamedir-Overview.html" title="4. Overview of your new Game Dir"
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Tutorial-World.html" title="2. The Tutorial World"
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -711,15 +711,15 @@ Now lets look at the rest of the stuff youve got going on inside that <cod
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Tutorial-World.html"
<p class="topless"><a href="Beginner-Tutorial-Tutorial-World.html"
title="previous chapter"><span class="section-number">2. </span>The Tutorial World</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Gamedir-Overview.html"
<p class="topless"><a href="Beginner-Tutorial-Gamedir-Overview.html"
title="next chapter"><span class="section-number">4. </span>Overview of your new Game Dir</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Python-basic-introduction.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Python-basic-introduction.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -735,7 +735,7 @@ Now lets look at the rest of the stuff youve got going on inside that <cod
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Python-basic-introduction.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Python-basic-introduction.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -753,10 +753,10 @@ Now lets look at the rest of the stuff youve got going on inside that <cod
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Gamedir-Overview.html" title="4. Overview of your new Game Dir"
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
>next</a> |</li>
<li class="right" >
<a href="Tutorial-World.html" title="2. The Tutorial World"
<a href="Beginner-Tutorial-Tutorial-World.html" title="2. The Tutorial World"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="6. Overview of the Evennia library" href="Evennia-Library-Overview.html" />
<link rel="prev" title="4. Overview of your new Game Dir" href="Gamedir-Overview.html" />
<link rel="next" title="6. Overview of the Evennia library" href="Beginner-Tutorial-Evennia-Library-Overview.html" />
<link rel="prev" title="4. Overview of your new Game Dir" href="Beginner-Tutorial-Gamedir-Overview.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Gamedir-Overview.html" title="4. Overview of your new Game Dir"
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -140,7 +140,7 @@ Hello World!
<div><p>Avoid renaming unless its to avoid a name-collistion like above - you want to make things as
easy to read as possible, and renaming adds another layer of potential confusion.</p>
</div></blockquote>
<p>In <a class="reference internal" href="Python-basic-introduction.html"><span class="doc std std-doc">the basic intro to Python</span></a> we learned how to open the in-game
<p>In <a class="reference internal" href="Beginner-Tutorial-Python-basic-introduction.html"><span class="doc std std-doc">the basic intro to Python</span></a> we learned how to open the in-game
multi-line interpreter.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py
Evennia Interactive Python mode
@ -196,7 +196,7 @@ as a black box.</p>
<p>Next we have a <code class="docutils literal notranslate"><span class="pre">class</span></code> named <code class="docutils literal notranslate"><span class="pre">Object</span></code>, which <em>inherits</em> from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. This class doesnt
actually do anything on its own, its only code (except the docstring) is <code class="docutils literal notranslate"><span class="pre">pass</span></code> which means,
well, to pass and dont do anything.</p>
<p>We will get back to this module in the <a class="reference internal" href="Learning-Typeclasses.html"><span class="doc std std-doc">next lesson</span></a>. First we need to do a
<p>We will get back to this module in the <a class="reference internal" href="Beginner-Tutorial-Learning-Typeclasses.html"><span class="doc std std-doc">next lesson</span></a>. First we need to do a
little detour to understand what a class, an object or instance is. These are fundamental
things to understand before you can use Evennia efficiently.</p>
<aside class="sidebar">
@ -478,15 +478,15 @@ provides. But first we need to learn just where to find everything.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Gamedir-Overview.html"
<p class="topless"><a href="Beginner-Tutorial-Gamedir-Overview.html"
title="previous chapter"><span class="section-number">4. </span>Overview of your new Game Dir</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Evennia-Library-Overview.html"
<p class="topless"><a href="Beginner-Tutorial-Evennia-Library-Overview.html"
title="next chapter"><span class="section-number">6. </span>Overview of the Evennia library</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Python-classes-and-objects.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Python-classes-and-objects.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -502,7 +502,7 @@ provides. But first we need to learn just where to find everything.</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Python-classes-and-objects.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Python-classes-and-objects.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -520,10 +520,10 @@ provides. But first we need to learn just where to find everything.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
<a href="Beginner-Tutorial-Evennia-Library-Overview.html" title="6. Overview of the Evennia library"
>next</a> |</li>
<li class="right" >
<a href="Gamedir-Overview.html" title="4. Overview of your new Game Dir"
<a href="Beginner-Tutorial-Gamedir-Overview.html" title="4. Overview of your new Game Dir"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="12. Advanced searching - Django Database queries" href="Django-queries.html" />
<link rel="prev" title="10. Creating things" href="Creating-Things.html" />
<link rel="next" title="12. Advanced searching - Django Database queries" href="Beginner-Tutorial-Django-queries.html" />
<link rel="prev" title="10. Creating things" href="Beginner-Tutorial-Creating-Things.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Django-queries.html" title="12. Advanced searching - Django Database queries"
<a href="Beginner-Tutorial-Django-queries.html" title="12. Advanced searching - Django Database queries"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Creating-Things.html" title="10. Creating things"
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -352,15 +352,15 @@ Django queries and querysets in earnest.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Creating-Things.html"
<p class="topless"><a href="Beginner-Tutorial-Creating-Things.html"
title="previous chapter"><span class="section-number">10. </span>Creating things</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Django-queries.html"
<p class="topless"><a href="Beginner-Tutorial-Django-queries.html"
title="next chapter"><span class="section-number">12. </span>Advanced searching - Django Database queries</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Searching-Things.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Searching-Things.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -376,7 +376,7 @@ Django queries and querysets in earnest.</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Searching-Things.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Searching-Things.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -394,10 +394,10 @@ Django queries and querysets in earnest.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Django-queries.html" title="12. Advanced searching - Django Database queries"
<a href="Beginner-Tutorial-Django-queries.html" title="12. Advanced searching - Django Database queries"
>next</a> |</li>
<li class="right" >
<a href="Creating-Things.html" title="10. Creating things"
<a href="Beginner-Tutorial-Creating-Things.html" title="10. Creating things"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="3. Intro to using Python with Evennia" href="Python-basic-introduction.html" />
<link rel="prev" title="1. Using commands and building stuff" href="Building-Quickstart.html" />
<link rel="next" title="3. Intro to using Python with Evennia" href="Beginner-Tutorial-Python-basic-introduction.html" />
<link rel="prev" title="1. Using commands and building stuff" href="Beginner-Tutorial-Building-Quickstart.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Building-Quickstart.html" title="1. Using commands and building stuff"
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -200,15 +200,15 @@ move on with how to access this power through code.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Building-Quickstart.html"
<p class="topless"><a href="Beginner-Tutorial-Building-Quickstart.html"
title="previous chapter"><span class="section-number">1. </span>Using commands and building stuff</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Python-basic-introduction.html"
<p class="topless"><a href="Beginner-Tutorial-Python-basic-introduction.html"
title="next chapter"><span class="section-number">3. </span>Intro to using Python with Evennia</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Tutorial-World.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Tutorial-World.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -224,7 +224,7 @@ move on with how to access this power through code.</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Tutorial-World.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Tutorial-World.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -242,10 +242,10 @@ move on with how to access this power through code.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
<a href="Beginner-Tutorial-Python-basic-introduction.html" title="3. Intro to using Python with Evennia"
>next</a> |</li>
<li class="right" >
<a href="Building-Quickstart.html" title="1. Using commands and building stuff"
<a href="Beginner-Tutorial-Building-Quickstart.html" title="1. Using commands and building stuff"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<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="Planning the use of some useful contribs" href="Planning-Some-Useful-Contribs.html" />
<link rel="prev" title="Where do I begin?" href="Planning-Where-Do-I-Begin.html" />
<link rel="next" title="Planning our tutorial game" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html" />
<link rel="prev" title="Where do I begin?" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Planning-Some-Useful-Contribs.html" title="Planning the use of some useful contribs"
<a href="Beginner-Tutorial-Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Planning-Where-Do-I-Begin.html" title="Where do I begin?"
<a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html" title="Where do I begin?"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -298,15 +298,15 @@ have made their dream game a reality!</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Planning-Where-Do-I-Begin.html"
<p class="topless"><a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html"
title="previous chapter">Where do I begin?</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Planning-Some-Useful-Contribs.html"
title="next chapter">Planning the use of some useful contribs</a></p>
<p class="topless"><a href="Beginner-Tutorial-Planning-The-Tutorial-Game.html"
title="next chapter">Planning our tutorial game</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Game-Planning.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Game-Planning.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -322,7 +322,7 @@ have made their dream game a reality!</p>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Game-Planning.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Game-Planning.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -340,10 +340,10 @@ have made their dream game a reality!</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Planning-Some-Useful-Contribs.html" title="Planning the use of some useful contribs"
<a href="Beginner-Tutorial-Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
>next</a> |</li>
<li class="right" >
<a href="Planning-Where-Do-I-Begin.html" title="Where do I begin?"
<a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html" title="Where do I begin?"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,8 +17,8 @@
<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="Where do I begin?" href="Planning-Where-Do-I-Begin.html" />
<link rel="prev" title="12. Advanced searching - Django Database queries" href="../Part1/Django-queries.html" />
<link rel="next" title="Where do I begin?" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html" />
<link rel="prev" title="12. Advanced searching - Django Database queries" href="../Part1/Beginner-Tutorial-Django-queries.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Planning-Where-Do-I-Begin.html" title="Where do I begin?"
<a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html" title="Where do I begin?"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="../Part1/Django-queries.html" title="12. Advanced searching - Django Database queries"
<a href="../Part1/Beginner-Tutorial-Django-queries.html" title="12. Advanced searching - Django Database queries"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -76,10 +76,9 @@ and “what to think about” when creating a multiplayer online text game.</p>
<h2>Lessons<a class="headerlink" href="#lessons" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Planning-Where-Do-I-Begin.html">Where do I begin?</a></li>
<li class="toctree-l1"><a class="reference internal" href="Game-Planning.html">On Planning a Game</a></li>
<li class="toctree-l1"><a class="reference internal" href="Planning-Some-Useful-Contribs.html">Planning the use of some useful contribs</a></li>
<li class="toctree-l1"><a class="reference internal" href="Planning-The-Tutorial-Game.html">Planning our tutorial game</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html">Where do I begin?</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html">On Planning a Game</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html">Planning our tutorial game</a></li>
</ul>
</div>
</section>
@ -87,100 +86,89 @@ and “what to think about” when creating a multiplayer online text game.</p>
<h2>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Planning-Where-Do-I-Begin.html">Where do I begin?</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Planning-Where-Do-I-Begin.html#what-is-your-motivation-for-doing-this">What is your motivation for doing this?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Where-Do-I-Begin.html#what-are-your-skills">What are your skills?</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-Where-Do-I-Begin.html#the-game-engine">The game engine</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-Where-Do-I-Begin.html#asset-creation">Asset creation</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html">Where do I begin?</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html#what-is-your-motivation-for-doing-this">What is your motivation for doing this?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html#what-are-your-skills">What are your skills?</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html#the-game-engine">The game engine</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html#asset-creation">Asset creation</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Where-Do-I-Begin.html#so-where-do-i-begin-then">So, where do I begin, then?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Where-Do-I-Begin.html#conclusions">Conclusions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html#so-where-do-i-begin-then">So, where do I begin, then?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html#conclusions">Conclusions</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Game-Planning.html">On Planning a Game</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#the-steps">The steps</a></li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#planning">Planning</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Game-Planning.html#administration">Administration</a></li>
<li class="toctree-l3"><a class="reference internal" href="Game-Planning.html#building">Building</a></li>
<li class="toctree-l3"><a class="reference internal" href="Game-Planning.html#systems">Systems</a></li>
<li class="toctree-l3"><a class="reference internal" href="Game-Planning.html#rooms">Rooms</a></li>
<li class="toctree-l3"><a class="reference internal" href="Game-Planning.html#objects-items">Objects / items</a></li>
<li class="toctree-l3"><a class="reference internal" href="Game-Planning.html#characters">Characters</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html">On Planning a Game</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#the-steps">The steps</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#planning">Planning</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#administration">Administration</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#building">Building</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#systems">Systems</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#rooms">Rooms</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#objects-items">Objects / items</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#characters">Characters</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#coding-and-tech-demo">Coding and Tech demo</a></li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#world-building">World Building</a></li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#alpha-release">Alpha Release</a></li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#beta-release-perpetual-beta">Beta Release/Perpetual Beta</a></li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#congratulate-yourself">Congratulate yourself!</a></li>
<li class="toctree-l2"><a class="reference internal" href="Game-Planning.html#planning-our-tutorial-game">Planning our tutorial game</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#coding-and-tech-demo">Coding and Tech demo</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#world-building">World Building</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#alpha-release">Alpha Release</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#beta-release-perpetual-beta">Beta Release/Perpetual Beta</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#congratulate-yourself">Congratulate yourself!</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Game-Planning.html#planning-our-tutorial-game">Planning our tutorial game</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Planning-Some-Useful-Contribs.html">Planning the use of some useful contribs</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#barter-contrib">Barter contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#clothing-contrib">Clothing contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#dice-contrib">Dice contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#extended-room-contrib">Extended room contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#rp-system-contrib">RP-System contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#talking-npc-contrib">Talking NPC contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#traits-contrib">Traits contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#turnbattle-contrib">Turnbattle contrib</a></li>
<li class="toctree-l2"><a class="reference internal" href="Planning-Some-Useful-Contribs.html#conclusions">Conclusions</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html">Planning our tutorial game</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#game-concept">Game concept</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#administration">Administration</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#should-your-game-rules-be-enforced-by-coded-systems-by-human-game-masters">Should your game rules be enforced by coded systems by human game masters?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#what-is-the-staff-hierarchy-in-your-game-is-vanilla-evennia-roles-enough-or-do-you-need-something-else">What is the staff hierarchy in your game? Is vanilla Evennia roles enough or do you need something else?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#should-players-be-able-to-post-out-of-characters-on-channels-and-via-other-means-like-bulletin-boards">Should players be able to post out-of-characters on channels and via other means like bulletin-boards?</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Planning-The-Tutorial-Game.html">Planning our tutorial game</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#administration">Administration</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#should-your-game-rules-be-enforced-by-coded-systems-by-human-game-masters">Should your game rules be enforced by coded systems by human game masters?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#what-is-the-staff-hierarchy-in-your-game-is-vanilla-evennia-roles-enough-or-do-you-need-something-else">What is the staff hierarchy in your game? Is vanilla Evennia roles enough or do you need something else?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#should-players-be-able-to-post-out-of-characters-on-channels-and-via-other-means-like-bulletin-boards">Should players be able to post out-of-characters on channels and via other means like bulletin-boards?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#building">Building</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#how-will-the-world-be-built">How will the world be built?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#can-only-privileged-builders-create-things-or-should-regular-players-also-have-limited-build-capability">Can only privileged Builders create things or should regular players also have limited build-capability?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#building">Building</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#how-will-the-world-be-built">How will the world be built?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#can-only-privileged-builders-create-things-or-should-regular-players-also-have-limited-build-capability">Can only privileged Builders create things or should regular players also have limited build-capability?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#systems">Systems</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#do-you-base-your-game-off-an-existing-rpg-system-or-make-up-your-own">Do you base your game off an existing RPG system or make up your own?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#what-are-the-game-mechanics-how-do-you-decide-if-an-action-succeeds-or-fails">What are the game mechanics? How do you decide if an action succeeds or fails?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#does-the-flow-of-time-matter-in-your-game-does-night-and-day-change-what-about-seasons">Does the flow of time matter in your game - does night and day change? What about seasons?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#do-you-want-changing-global-weather-or-should-weather-just-be-set-manually-in-roleplay">Do you want changing, global weather or should weather just be set manually in roleplay?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#do-you-want-a-coded-world-economy-or-just-a-simple-barter-system-or-no-formal-economy-at-all">Do you want a coded world-economy or just a simple barter system? Or no formal economy at all?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#do-you-have-concepts-like-reputation-and-influence">Do you have concepts like reputation and influence?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#will-your-characters-be-known-by-their-name-or-only-by-their-physical-appearance">Will your characters be known by their name or only by their physical appearance?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#systems">Systems</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#do-you-base-your-game-off-an-existing-rpg-system-or-make-up-your-own">Do you base your game off an existing RPG system or make up your own?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#what-are-the-game-mechanics-how-do-you-decide-if-an-action-succeeds-or-fails">What are the game mechanics? How do you decide if an action succeeds or fails?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#does-the-flow-of-time-matter-in-your-game-does-night-and-day-change-what-about-seasons">Does the flow of time matter in your game - does night and day change? What about seasons?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#do-you-want-changing-global-weather-or-should-weather-just-be-set-manually-in-roleplay">Do you want changing, global weather or should weather just be set manually in roleplay?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#do-you-want-a-coded-world-economy-or-just-a-simple-barter-system-or-no-formal-economy-at-all">Do you want a coded world-economy or just a simple barter system? Or no formal economy at all?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#do-you-have-concepts-like-reputation-and-influence">Do you have concepts like reputation and influence?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#will-your-characters-be-known-by-their-name-or-only-by-their-physical-appearance">Will your characters be known by their name or only by their physical appearance?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#rooms">Rooms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#is-a-simple-room-description-enough-or-should-the-description-be-able-to-change">Is a simple room description enough or should the description be able to change?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#should-the-room-have-different-statuses">Should the room have different statuses?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#can-objects-be-hidden-in-the-room-can-a-person-hide-in-the-room">Can objects be hidden in the room? Can a person hide in the room?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#rooms">Rooms</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#is-a-simple-room-description-enough-or-should-the-description-be-able-to-change">Is a simple room description enough or should the description be able to change?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#should-the-room-have-different-statuses">Should the room have different statuses?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#can-objects-be-hidden-in-the-room-can-a-person-hide-in-the-room">Can objects be hidden in the room? Can a person hide in the room?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#objects">Objects</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#how-numerous-are-your-objects-do-you-want-large-loot-lists-or-are-objects-just-role-playing-props">How numerous are your objects? Do you want large loot-lists or are objects just role playing props?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#is-each-coin-a-separate-object-or-do-you-just-store-a-bank-account-value">Is each coin a separate object or do you just store a bank account value?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#do-multiple-similar-objects-form-stack-and-how-are-those-stacks-handled-in-that-case">Do multiple similar objects form stack and how are those stacks handled in that case?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#does-an-object-have-weight-or-volume-so-you-cannot-carry-an-infinite-amount-of-them">Does an object have weight or volume (so you cannot carry an infinite amount of them)?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#can-objects-be-broken-can-they-be-repaired">Can objects be broken? Can they be repaired?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#can-you-fight-with-a-chair-or-a-flower-or-must-you-use-a-special-weapon-kind-of-thing">Can you fight with a chair or a flower or must you use a special weapon kind of thing?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#will-characters-be-able-to-craft-new-objects">Will characters be able to craft new objects?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#should-mobs-npcs-have-some-sort-of-ai">Should mobs/NPCs have some sort of AI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#are-npcs-and-mobs-different-entities-how-do-they-differ">Are NPCs and mobs different entities? How do they differ?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#should-there-be-npcs-giving-quests-if-so-how-do-you-track-quest-status">_Should there be NPCs giving quests? If so, how do you track Quest status?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#objects">Objects</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#how-numerous-are-your-objects-do-you-want-large-loot-lists-or-are-objects-just-role-playing-props">How numerous are your objects? Do you want large loot-lists or are objects just role playing props?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#is-each-coin-a-separate-object-or-do-you-just-store-a-bank-account-value">Is each coin a separate object or do you just store a bank account value?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#do-multiple-similar-objects-form-stacks-and-how-are-those-stacks-handled-in-that-case">Do multiple similar objects form stacks and how are those stacks handled in that case?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#does-an-object-have-weight-or-volume-so-you-cannot-carry-an-infinite-amount-of-them">Does an object have weight or volume (so you cannot carry an infinite amount of them)?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#can-objects-be-broken-can-they-be-repaired">Can objects be broken? Can they be repaired?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#can-you-fight-with-a-chair-or-a-flower-or-must-you-use-a-special-weapon-kind-of-thing">Can you fight with a chair or a flower or must you use a special weapon kind of thing?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#will-characters-be-able-to-craft-new-objects">Will characters be able to craft new objects?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#should-mobs-npcs-have-some-sort-of-ai">Should mobs/NPCs have some sort of AI?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#are-npcs-and-mobs-different-entities-how-do-they-differ">Are NPCs and mobs different entities? How do they differ?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#should-there-be-npcs-giving-quests-if-so-how-do-you-track-quest-status">_Should there be NPCs giving quests? If so, how do you track Quest status?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#characters">Characters</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#can-players-have-more-than-one-character-active-at-a-time-or-are-they-allowed-to-multi-play">Can players have more than one Character active at a time or are they allowed to multi-play?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#how-does-the-character-generation-work">How does the character-generation work?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#how-do-you-implement-different-classes-or-races">How do you implement different “classes” or “races”?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#if-a-character-can-hide-in-a-room-what-skill-will-decide-if-they-are-detected">If a Character can hide in a room, what skill will decide if they are detected?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#what-does-the-skill-tree-look-like-can-a-character-gain-experience-to-improve-by-killing-enemies-solving-quests-by-roleplaying">What does the skill tree look like? Can a Character gain experience to improve? By killing enemies? Solving quests? By roleplaying?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#may-player-characters-attack-each-other-pvp">May player-characters attack each other (PvP)?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#what-are-the-penalties-of-defeat-permanent-death-quick-respawn-time-in-prison">What are the penalties of defeat? Permanent death? Quick respawn? Time in prison?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#characters">Characters</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#can-players-have-more-than-one-character-active-at-a-time-or-are-they-allowed-to-multi-play">Can players have more than one Character active at a time or are they allowed to multi-play?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#how-does-the-character-generation-work">How does the character-generation work?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#how-do-you-implement-different-classes-or-races">How do you implement different “classes” or “races”?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#if-a-character-can-hide-in-a-room-what-skill-will-decide-if-they-are-detected">If a Character can hide in a room, what skill will decide if they are detected?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#what-does-the-skill-tree-look-like-can-a-character-gain-experience-to-improve-by-killing-enemies-solving-quests-by-roleplaying">What does the skill tree look like? Can a Character gain experience to improve? By killing enemies? Solving quests? By roleplaying?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#may-player-characters-attack-each-other-pvp">May player-characters attack each other (PvP)?</a></li>
<li class="toctree-l3"><a class="reference internal" href="Planning-The-Tutorial-Game.html#what-are-the-penalties-of-defeat-permanent-death-quick-respawn-time-in-prison">What are the penalties of defeat? Permanent death? Quick respawn? Time in prison?</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Planning-The-Tutorial-Game.html#conclusions">Conclusions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Planning-The-Tutorial-Game.html#conclusions">Conclusions</a></li>
</ul>
</li>
</ul>
@ -218,10 +206,10 @@ and “what to think about” when creating a multiplayer online text game.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="../Part1/Django-queries.html"
<p class="topless"><a href="../Part1/Beginner-Tutorial-Django-queries.html"
title="previous chapter"><span class="section-number">12. </span>Advanced searching - Django Database queries</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Planning-Where-Do-I-Begin.html"
<p class="topless"><a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html"
title="next chapter">Where do I begin?</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
@ -260,10 +248,10 @@ and “what to think about” when creating a multiplayer online text game.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Planning-Where-Do-I-Begin.html" title="Where do I begin?"
<a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html" title="Where do I begin?"
>next</a> |</li>
<li class="right" >
<a href="../Part1/Django-queries.html" title="12. Advanced searching - Django Database queries"
<a href="../Part1/Beginner-Tutorial-Django-queries.html" title="12. Advanced searching - Django Database queries"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -18,7 +18,7 @@
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Part 3: How we get there" href="../Part3/Beginner-Tutorial-Part3-Intro.html" />
<link rel="prev" title="Planning the use of some useful contribs" href="Planning-Some-Useful-Contribs.html" />
<link rel="prev" title="On Planning a Game" href="Beginner-Tutorial-Game-Planning.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -33,7 +33,7 @@
<a href="../Part3/Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Planning-Some-Useful-Contribs.html" title="Planning the use of some useful contribs"
<a href="Beginner-Tutorial-Game-Planning.html" title="On Planning a Game"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -51,46 +51,45 @@
<section class="tex2jax_ignore mathjax_ignore" id="planning-our-tutorial-game">
<h1>Planning our tutorial game<a class="headerlink" href="#planning-our-tutorial-game" title="Permalink to this headline"></a></h1>
<p>Using the general plan from last lesson well now establish what kind of game we want to create for this tutorial.
Remembering that we need to keep the scope down, lets establish some parameters.
Note that for your own
game you dont <em>need</em> to agree/adopt any of these. Many game-types need more or much less than this.
But this makes for good, instructive examples.</p>
<p>Using the general plan from last lesson well now establish what kind of game we want to create for this tutorial. Well call it … <em>EvAdventure</em>.
Remembering that we need to keep the scope down, lets establish some parameters.</p>
<ul class="simple">
<li><p>To have something to refer to rather than just saying “our tutorial game” over and over, well
name it … <em>EvAdventure</em>.</p></li>
<li><p>We want EvAdventure be a small game we can play ourselves for fun, but which could in principle be expanded
to something more later.</p></li>
<li><p>We want EvAdventure be a small game we can play ourselves for fun, but which could in principle be expanded to something more later.</p></li>
<li><p>We want to have a clear game-loop, with clear goals.</p></li>
<li><p>Lets go with a fantasy theme, its well understood.</p></li>
<li><p>Well use some existing, simple RPG system.</p></li>
<li><p>We will use a small, existing tabletop RPG rule set (<a class="reference external" href="https://www.drivethrurpg.com/product/250888/Knave">Knave</a>, more info later)</p></li>
<li><p>We want to be able to create and customize a character of our own.</p></li>
<li><p>We want the tools to roleplay with other players.</p></li>
<li><p>We dont want to have to rely on a Game master to resolve things, but will rely on code for skill resolution
and combat.</p></li>
<li><p>While not roleplay-focused, it should still be possible to socialize and to collaborate.</p></li>
<li><p>We dont want to have to rely on a Game master to resolve things, but will rely on code for skill resolution and combat.</p></li>
<li><p>We want monsters to fight and NPCs we can talk to. So some sort of AI.</p></li>
<li><p>We want to be able to buy and sell stuff, both with NPCs and other players.</p></li>
<li><p>We want some sort of crafting system.</p></li>
<li><p>We want some sort of quest system.</p></li>
<li><p>We want some sort of quest system and merchants to buy stuff from.</p></li>
</ul>
<p>Lets answer the questions from the previous lesson and discuss some of the possibilities.</p>
<section id="game-concept">
<h2>Game concept<a class="headerlink" href="#game-concept" title="Permalink to this headline"></a></h2>
<p>With these points in mind, heres a quick blurb for our game:</p>
<p><em>Recently, the nearby village discovered that the old abandoned well contained a dark secret. The bottom of the well led to a previously undiscovered dungeon of ever shifting passages. No one knew why it was there or what its purpose was, but local rumors abound. The first adventurer that went down didnt come back. The second … brought back a handful of glittering riches.</em></p>
<p><em>Now the rush is on - theres a dungeon to explore and coin to earn. Knaves, cutthroats, adventurers and maybe even a hero or two are coming from all over the realm to challenge whatever lurks at the bottom of that well.</em></p>
<p><em>Local merchants and opportunists have seen a chance for profit. A camp of tents has sprung up around the old well, providing food and drink, equipment, entertainment and rumors for a price. Its a festival to enjoy before paying the entrance fee for dropping down the well to find your fate among the shadows below …</em></p>
<p>Our game will consist of two main game modes - above ground and below. The player starts above ground and is expected to do expeditions into the dark. The design goal is for them to be forced back up again when their health, equipment and luck is about to run out.</p>
<ul class="simple">
<li><p>Above, in the “dungeon festival”, the player can restock and heal up, buy things and do a small set of quests. Its the only place where the characters can sleep and fully heal. They also need to spend coin here to gain XP and levels. This is a place for players to socialize and RP. There is no combat above ground except for an optional spot for non-lethal PvP.</p></li>
<li><p>Below is the mysterious dungeon. This is a procedurally generated set of rooms. Players can collaborate if they go down the well together, they will not be able to run into each other otherwise (so this works as an instance). Each room generally presents some challenge (normally a battle). Pushing deeper is more dangerous but can grant greater rewards. While the rooms could in theory go on forever, there should be a boss encounter once a player reaches deep enough.</p></li>
</ul>
<p>Heres an overview of the topside camp for inspiration (quickly thrown together in the free version of <a class="reference external" href="https://inkarnate.com/">Inkarnate</a>). Well explore how to break this up into “rooms” (locations) when we get to creating the game world later.</p>
<p><img alt="Last Step Camp" src="../../../_images/Dungeon_Merchant_Camp.jpg" /></p>
<p>For the rest of this lesson well answer and reason around the specific questions posed in the previous <a class="reference internal" href="Beginner-Tutorial-Game-Planning.html"><span class="doc std std-doc">Game Planning</span></a> lesson.</p>
</section>
<section id="administration">
<h2>Administration<a class="headerlink" href="#administration" title="Permalink to this headline"></a></h2>
<section id="should-your-game-rules-be-enforced-by-coded-systems-by-human-game-masters">
<h3>Should your game rules be enforced by coded systems by human game masters?<a class="headerlink" href="#should-your-game-rules-be-enforced-by-coded-systems-by-human-game-masters" title="Permalink to this headline"></a></h3>
<p>Generally, the more work you expect human staffers/GMs to do, the less your code needs to work. To
support GMs youd need to design commands to support GM-specific actions and the type of game-mastering
you want them to do. You may need to expand communication channels so you can easily
talk to groups people in private and split off gaming groups from each other. RPG rules could be as simple
<p>Generally, the more work you expect human staffers/GMs to do, the less your code needs to work. To support GMs youd need to design commands to support GM-specific actions and the type of game-mastering you want them to do. You may need to expand communication channels so you can easily talk to groups people in private and split off gaming groups from each other. RPG rules could be as simple
as the GM sitting with the rule books and using a dice-roller for visibility.</p>
<p>GM:ing is work-intensive however, and even the most skilled and enthusiastic GM cant be awake all hours
of the day to serve an international player base. The computer never needs sleep, so having the ability for
players to “self-serve” their RP itch when no GMs are around is a good idea even for the most GM-heavy games.</p>
<p>On the other side of the spectrum are games with no GMs at all; all gameplay are driven either by the computer
or by the interactions between players. Such games still need an active staff, but nowhere as much active
involvement. Allowing for solo-play with the computer also allows players to have fun when the number of active
<p>GM:ing is work-intensive however, and even the most skilled and enthusiastic GM cant be awake all hours of the day to serve an international player base. The computer never needs sleep, so having the ability for players to “self-serve” their RP itch when no GMs are around is a good idea even for the most GM-heavy games.</p>
<p>On the other side of the spectrum are games with no GMs at all; all gameplay are driven either by the computer or by the interactions between players. Such games still need an active staff, but nowhere as much active involvement. Allowing for solo-play with the computer also allows players to have fun when the number of active
players is low.</p>
<p>We want EvAdventure to work entirely without depending on human GMs. That said, thered be nothing
stopping a GM from stepping in and run an adventure for some players should they want to.</p>
<p><strong>EvAdventure Answer:</strong></p>
<p>We want EvAdventure to work entirely without depending on human GMs. That said, thered be nothing stopping a GM from stepping in and run an adventure for some players should they want to.</p>
</section>
<section id="what-is-the-staff-hierarchy-in-your-game-is-vanilla-evennia-roles-enough-or-do-you-need-something-else">
<h3>What is the staff hierarchy in your game? Is vanilla Evennia roles enough or do you need something else?<a class="headerlink" href="#what-is-the-staff-hierarchy-in-your-game-is-vanilla-evennia-roles-enough-or-do-you-need-something-else" title="Permalink to this headline"></a></h3>
@ -104,30 +103,27 @@ stopping a GM from stepping in and run an adventure for some players should they
</ul>
<p>There is also the <em>superuser</em>, the “owner” of the game you create when you first set up your database. This user
goes outside the regular hierarchy and should usually only.</p>
<p>We are okay with keeping this structure for our game.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We are okay with keeping the default permission structure for our game.</p>
</section>
<section id="should-players-be-able-to-post-out-of-characters-on-channels-and-via-other-means-like-bulletin-boards">
<h3>Should players be able to post out-of-characters on channels and via other means like bulletin-boards?<a class="headerlink" href="#should-players-be-able-to-post-out-of-characters-on-channels-and-via-other-means-like-bulletin-boards" title="Permalink to this headline"></a></h3>
<p>Evennias <em>Channels</em> are by default only available between <em>Accounts</em>. That is, for players to communicate with each
other. By default, the <code class="docutils literal notranslate"><span class="pre">public</span></code> channel is created for general discourse.
Channels are logged to a file and when you are coming back to the game you can view the history of a channel
in case you missed something.</p>
Channels are logged to a file and when you are coming back to the game you can view the history of a channel in case you missed something.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; public Hello world!
[Public] MyName: Hello world!
</pre></div>
</div>
<p>But Channels can also be set up to work between Characters instead of Accounts. This would mean the channels
would have an in-game meaning:</p>
<p>But Channels can also be set up to work between Characters instead of Accounts. This would mean the channels would have an in-game meaning:</p>
<ul class="simple">
<li><p>Members of a guild could be linked telepathically.</p></li>
<li><p>Survivors of the apocalypse can communicate over walkie-talkies.</p></li>
<li><p>Radio stations you can tune into or have to discover.</p></li>
</ul>
<p><em>Bulletin boards</em> are a sort of in-game forum where posts are made publicly or privately. Contrary to a channel,
the messages are usually stored and are grouped into topics with replies. Evennia has no default bulletin-board
system.</p>
<p>In EvAdventure we will just use the default inter-account channels. We will also not be implementing any
bulletin boards.</p>
<p><em>Bulletin boards</em> are a sort of in-game forum where posts are made publicly or privately. Contrary to a channel, the messages are usually stored and are grouped into topics with replies. Evennia has no default bulletin-board system.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>In EvAdventure we will just use the default inter-account channels. We will also not be implementing any bulletin boards; instead the merchant NPCs will act as quest givers.</p>
</section>
</section>
<section id="building">
@ -136,122 +132,116 @@ bulletin boards.</p>
<h3>How will the world be built?<a class="headerlink" href="#how-will-the-world-be-built" title="Permalink to this headline"></a></h3>
<p>There are two main ways to handle this:</p>
<ul class="simple">
<li><p>Traditionally, from in-game with build-commands: This means builders creating content in their game
client. This has the advantage of not requiring Python skills nor server access. This can often be a quite
intuitive way to build since you are sort-of walking around in your creation as you build it. However, the
developer (you) must make sure to provide build-commands that are flexible enough for builders to be able to
create the content you want for your game.</p></li>
<li><p>Externally (by batchcmds): Evennias <code class="docutils literal notranslate"><span class="pre">batchcmd</span></code> takes a text file with Evennia Commands and executes them
in sequence. This allows the build process to be repeated and applied quickly to a new database during development.
It also allows builders to use proper text-editing tools rather than writing things line-by-line in their clients.
The drawback is that for their changes to go live they either need server access or they need to send their
batchcode to the game administrator so they can apply the changes. Or use version control.</p></li>
<li><p>Externally (with batchcode or custom code): This is the “professional game development” approach. This gives the
builders maximum power by creating the content in Python using Evennia primitives. The <code class="docutils literal notranslate"><span class="pre">batchcode</span></code> processor
allows Evennia to apply and re-apply build-scripts that are raw Python modules. Again, this would require the
builder to have server access or to use version control to share their work with the rest of the development team.</p></li>
<li><p>Traditionally, from in-game with build-commands: This means builders creating content in their game client. This has the advantage of not requiring Python skills nor server access. This can often be a quite intuitive way to build since you are sort-of walking around in your creation as you build it. However, the developer (you) must make sure to provide build-commands that are flexible enough for builders to be able to create the content you want for your game.</p></li>
<li><p>Externally (by batchcmds): Evennias <code class="docutils literal notranslate"><span class="pre">batchcmd</span></code> takes a text file with Evennia Commands and executes them in sequence. This allows the build process to be repeated and applied quickly to a new database during development.
It also allows builders to use proper text-editing tools rather than writing things line-by-line in their clients. The drawback is that for their changes to go live they either need server access or they need to send their batchcode to the game administrator so they can apply the changes. Or use version control.</p></li>
<li><p>Externally (with batchcode or custom code): This is the “professional game development” approach. This gives the builders maximum power by creating the content in Python using Evennia primitives. The <code class="docutils literal notranslate"><span class="pre">batchcode</span></code> processor
allows Evennia to apply and re-apply build-scripts that are raw Python modules. Again, this would require the builder to have server access or to use version control to share their work with the rest of the development team.</p></li>
</ul>
<p>In this tutorial, we will show examples of all these ways, but since we dont have a team of builders well
build the brunt of things using Evennias Batchcode system.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>For EvAdventure, we will build the above-ground part of the game world using batch-scripts. The world below-ground we will build procedurally, using raw code.</p>
</section>
<section id="can-only-privileged-builders-create-things-or-should-regular-players-also-have-limited-build-capability">
<h3>Can only privileged Builders create things or should regular players also have limited build-capability?<a class="headerlink" href="#can-only-privileged-builders-create-things-or-should-regular-players-also-have-limited-build-capability" title="Permalink to this headline"></a></h3>
<p>In some game styles, players have the ability to create objects and even script them. While giving regular users
the ability to create objects with in-built commands is easy and safe, actual code-creation (aka <em>softcode</em> ) is
not something Evennia supports natively. Regular, untrusted users should never be allowed to execute raw Python
<p>In some game styles, players have the ability to create objects and even script them. While giving regular users the ability to create objects with in-built commands is easy and safe, actual code-creation (aka <em>softcode</em> ) is not something Evennia supports natively.</p>
<p>Regular, untrusted users should never be allowed to execute raw Python
code (such as what you can do with the <code class="docutils literal notranslate"><span class="pre">py</span></code> command). You can
<a class="reference internal" href="../../../Concepts/Soft-Code.html"><span class="doc std std-doc">read more about Evennias stance on softcode here</span></a>. If you want users to do limited scripting,
its suggested that this is accomplished by adding more powerful build-commands for them to use.</p>
<p>For our tutorial-game, we will only allow privileged builders to modify the world. The exception is crafting,
which we will limit to repairing broken items by combining them with other repair-related items.</p>
<a class="reference internal" href="../../../Concepts/Soft-Code.html"><span class="doc std std-doc">read more about Evennias stance on softcode here</span></a>. If you want users to do limited scripting, its suggested that this is accomplished by adding more powerful build-commands for them to use.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>For our tutorial-game, we will only allow privileged builders and admins to modify the world.</p>
</section>
</section>
<section id="systems">
<h2>Systems<a class="headerlink" href="#systems" title="Permalink to this headline"></a></h2>
<section id="do-you-base-your-game-off-an-existing-rpg-system-or-make-up-your-own">
<h3>Do you base your game off an existing RPG system or make up your own?<a class="headerlink" href="#do-you-base-your-game-off-an-existing-rpg-system-or-make-up-your-own" title="Permalink to this headline"></a></h3>
<p>We will make use of <a class="reference external" href="http://www.geekguild.com/openadventure/">Open Adventure</a>, a simple old school RPG-system
that is available for free under the Creative Commons license. Well only use a subset of the rules from
the blue “basic” book. For the sake of keeping down the length of this tutorial we will limit what features
we will include:</p>
<ul class="simple">
<li><p>Only two archetypes (classes) - Arcanist (wizard) and Warrior, these are examples of two different play
styles.</p></li>
<li><p>Two races only (dwarves and elves), to show off how to implement races and race bonuses.</p></li>
<li><p>No extra features of the races/archetypes such as foci and special feats. While these are good for fleshing
out a character, these will work the same as other bonuses and are thus not that instructive.</p></li>
<li><p>We will add only a small number of items/weapons from the Open Adventure rulebook to show how its done.</p></li>
</ul>
<p>There is a plethora of options out there, and what you choose depends on the game you want. It can be tempting to grab a short free-form ruleset, but remember that the computer does not have any intuitiion or common sense to interpret the rules like a human GM could. Conversely, if you pick a very crunchy game system, with detailed simulation of the real world, remember that youll need to actually <em>code</em> all those exceptions and tables yourself.</p>
<p>For speediest development, what you want is a game with a <em>consolidated</em> resolution mechanic - one you can code once and then use in a lot of situations. But you still want enough rules to help telling the computer how various situations should be resolved (combat is the most common system that needs such structure).</p>
<p><strong>EvAdventure Answer</strong></p>
<p>For this tutorial, we will make use of <a class="reference external" href="https://www.drivethrurpg.com/product/250888/Knave">Knave</a>, a very light <a class="reference external" href="https://en.wikipedia.org/wiki/Old_School_Renaissance">OSR</a> ruleset by Ben Milton. Its only a few pages long but highly compatible with old-school D&amp;D games. Its consolidates all rules around a few opposed d20 rolls and includes clear rules for combat, inventory, equipment and so on. Since <em>Knave</em> is a tabletop RPG, we will have to do some minor changes here and there to fit it to the computer medium.</p>
<p><em>Knave</em> is available under a Creative Commons Attributions 4.0 License, meaning it can be used for derivative work (even commercially). The above link allows you to purchase the PDF and supporting the author. Alternatively you can find unofficial fan releases of the rules <a class="reference external" href="https://dungeonsandpossums.com/2020/04/some-great-knave-rpg-resources/">on this page</a>.</p>
</section>
<section id="what-are-the-game-mechanics-how-do-you-decide-if-an-action-succeeds-or-fails">
<h3>What are the game mechanics? How do you decide if an action succeeds or fails?<a class="headerlink" href="#what-are-the-game-mechanics-how-do-you-decide-if-an-action-succeeds-or-fails" title="Permalink to this headline"></a></h3>
<p>Open Adventures conflict resolution is based on adding a trait (such as Strength) with a random number in
order to beat a target. We will emulate this in code.</p>
<p>Having a “skill” means getting a bonus to that roll for a more narrow action.
Since the computer will need to know exactly what those skills are, we will add them more explicitly than
in the rules, but we will only add the minimum to show off the functionality we need.</p>
<p>This follows from the RPG system decided upon in the previous question.</p>
<p><strong>EvAdventure Answer</strong></p>
<p><em>Knave</em> gives every character a set of six traditional stats: Strength, Intelligence, Dexterity, Constitution, Intelligence, Wisdom and Charisma. Each has a value from +1 to +10. To find its “Defense” value, you add 10.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You have Strength +1. Your Strength-Defense is 10 + 1 = 11
</pre></div>
</div>
<p>To make a check, say an arm-wrestling challenge you roll a twenty-sided die (d20) and add your stat. You have to roll higher than the opponents defense for that stat.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>I have Strength +1, my opponent has a Strength of +2. To beat them in arm wrestling I must roll d20 + 1 and hope to get higher than 12, which is their Strength defense (10 + 2).
</pre></div>
</div>
<p>If you attack someone you do the same, except you roll against their <code class="docutils literal notranslate"><span class="pre">Armor</span></code> defense. If you rolled higher, you roll for how much damage you do (depends on your weapon).
You can have <em>advantage</em> or <em>disadvantage</em> on a roll. This means rolling 2d20 and picking highest or lowest value.</p>
<p>In Knave, combat is turn-based. In our implementation well also play turn-based, but well resolve everything <em>simultaneously</em>. This changes <em>Knave</em>s feel quite a bit, but is a case where the computer can do things not practical to do when playing around a table.</p>
<p>There are also a few tables well need to implement. For example, if you lose all health, theres a one-in-six chance youll die outright. Well keep this perma-death aspect, but make it very easy to start a new character and jump back in.</p>
<blockquote>
<div><p>In this tutorial we will not add opportunities to make use of all of the character stats, making some, like strength, intelligence and dexterity more useful than others. In a full game, one would want to expand so a user can utilize all of their characters strengths.</p>
</div></blockquote>
</section>
<section id="does-the-flow-of-time-matter-in-your-game-does-night-and-day-change-what-about-seasons">
<h3>Does the flow of time matter in your game - does night and day change? What about seasons?<a class="headerlink" href="#does-the-flow-of-time-matter-in-your-game-does-night-and-day-change-what-about-seasons" title="Permalink to this headline"></a></h3>
<p>Most commonly, game-time runs faster than real-world time. There are
a few advantages with this:</p>
<ul class="simple">
<li><p>Unlike in a single-player game, you cant fast-forward time in a multiplayer game if you are waiting for
something, like NPC shops opening.</p></li>
<li><p>Unlike in a single-player game, you cant fast-forward time in a multiplayer game if you are waiting for something, like NPC shops opening.</p></li>
<li><p>Healing and other things that we know takes time will go faster while still being reasonably realistic.</p></li>
</ul>
<p>The main drawback is for games with slower roleplay pace. While you are having a thoughtful roleplaying scene
over dinner, the game world reports that two days have passed. Having a slower game time than real-time is
a less common, but possible solution for such games.</p>
<p>It is however <em>not</em> recommended to let game-time exactly equal the speed of real time. The reason for this
is that people will join your game from all around the world, and they will often only be able to play at
particular times of their day. With a game-time drifting relative real-time, everyone will eventually be
able to experience both day and night in the game.</p>
<p>For this tutorial-game we will go with Evennias default, which is that the game-time runs two times faster
than real time.</p>
<p>The main drawback is for games with slower roleplay pace. While you are having a thoughtful roleplaying scene over dinner, the game world reports that two days have passed. Having a slower game time than real-time is a less common, but possible solution for such games.</p>
<p>It is however <em>not</em> recommended to let game-time exactly equal the speed of real time. The reason for this is that people will join your game from all around the world, and they will often only be able to play at particular times of their day. With a game-time drifting relative real-time, everyone will eventually be able to experience both day and night in the game.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>The passage of time will have no impact on our particular game example, so well go with Evennias default, which is that the game-time runs two times faster than real time.</p>
</section>
<section id="do-you-want-changing-global-weather-or-should-weather-just-be-set-manually-in-roleplay">
<h3>Do you want changing, global weather or should weather just be set manually in roleplay?<a class="headerlink" href="#do-you-want-changing-global-weather-or-should-weather-just-be-set-manually-in-roleplay" title="Permalink to this headline"></a></h3>
<p>A weather system is a good example of a game-global system that affects a subset of game entities
(outdoor rooms). We will not be doing any advanced weather simulation, but well show how to do
random weather changes happening across the game world.</p>
<p>A weather system is a good example of a game-global system that affects a subset of game entities (outdoor rooms).</p>
<p><strong>EvAdventure Answer</strong></p>
<p>Well not change the weather, but will add some random messages to echo through
the game world at random intervals just to show the principle.</p>
</section>
<section id="do-you-want-a-coded-world-economy-or-just-a-simple-barter-system-or-no-formal-economy-at-all">
<h3>Do you want a coded world-economy or just a simple barter system? Or no formal economy at all?<a class="headerlink" href="#do-you-want-a-coded-world-economy-or-just-a-simple-barter-system-or-no-formal-economy-at-all" title="Permalink to this headline"></a></h3>
<p>We will allow for money and barter/trade between NPCs/Players and Player/Player, but will not care about
inflation. A real economic simulation could do things like modify shop prices based on supply and demand.
We will not go down that rabbit hole.</p>
<p>This is a big question and depends on how deep and interconnected the virtual transactions are that are happening in the game. Shop prices could rice and drop due to supply and demand, supply chains could involve crafting and production. One also could consider adding money sinks and manipulate the in-game market to combat inflation.</p>
<p>The <a class="reference internal" href="../../../Contribs/Contrib-Barter.html"><span class="doc std std-doc">Barter</span></a> contrib provides a full interface for trading with another player in a safe way.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will not deal with any of this complexity. We will allow for players to buy from npc sellers and players will be able to trade using the normal <code class="docutils literal notranslate"><span class="pre">give</span></code> command.</p>
</section>
<section id="do-you-have-concepts-like-reputation-and-influence">
<h3>Do you have concepts like reputation and influence?<a class="headerlink" href="#do-you-have-concepts-like-reputation-and-influence" title="Permalink to this headline"></a></h3>
<p>These are useful things for a more social-interaction heavy game. We will not include them for this
tutorial however.</p>
<p>These are useful things for a more social-interaction heavy game.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will not include them for this tutorial. Adding the Barter contrib is simple though.</p>
</section>
<section id="will-your-characters-be-known-by-their-name-or-only-by-their-physical-appearance">
<h3>Will your characters be known by their name or only by their physical appearance?<a class="headerlink" href="#will-your-characters-be-known-by-their-name-or-only-by-their-physical-appearance" title="Permalink to this headline"></a></h3>
<p>This is a common thing in RP-heavy games. Others will only see you as “The tall woman” until you
introduce yourself and they recognize you with a name. Linked to this is the concept of more complex
emoting and posing.</p>
<p>Adding such a system from scratch is complex and way beyond the scope of this tutorial. However,
there is an existing Evennia contrib that adds all of this functionality and more, so we will
include that and explain briefly how it works.</p>
<p>This is a common thing in RP-heavy games. Others will only see you as “The tall woman” until you introduce yourself and they recognize you with a name. Linked to this is the concept of more complex emoting and posing.</p>
<p>Implementing such a system is not trivial, but the <a class="reference internal" href="../../../Contribs/Contrib-RPSystem.html"><span class="doc std std-doc">RPsystem</span></a> Evennia contrib offers a ready system with everything needed for free emoting, recognizing people by their appearance and more.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will not use any special RP systems for this tutorial. Adding the RPSystem contrib is a good extra expansion though!</p>
</section>
</section>
<section id="rooms">
<h2>Rooms<a class="headerlink" href="#rooms" title="Permalink to this headline"></a></h2>
<section id="is-a-simple-room-description-enough-or-should-the-description-be-able-to-change">
<h3>Is a simple room description enough or should the description be able to change?<a class="headerlink" href="#is-a-simple-room-description-enough-or-should-the-description-be-able-to-change" title="Permalink to this headline"></a></h3>
<p>Changing room descriptions for day and night, winder and summer is actually quite easy to do, but looks
very impressive. We happen to know there is also a contrib that helps with this, so well show how to
include that.</p>
<p>Changing room descriptions for day and night, winder and summer is actually quite easy to do, but looks very impressive. We happen to know there is also a contrib that helps with this, so well show how to include that.</p>
<p>There is an <a class="reference internal" href="../../../Contribs/Contrib-Extended-Room.html"><span class="doc std std-doc">Extended Room</span></a> contrib that adds a Room type that is aware of the time-of-day as well as seasonal variations.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will stick to a normal room in this tutorial and let the world be in a perpetual daylight. Making Rooms into ExtendedRooms is not hard though.</p>
</section>
<section id="should-the-room-have-different-statuses">
<h3>Should the room have different statuses?<a class="headerlink" href="#should-the-room-have-different-statuses" title="Permalink to this headline"></a></h3>
<p>We will have different weather in outdoor rooms, but this will not have any gameplay effect - bow strings
will not get wet and fireballs will not fizzle if it rains.</p>
<p>One could picture weather making outdoor rooms wet, cold or burnt. In rain, bow strings could get wet and fireballs fizz out. In a hot room, characters could require drinking more water, or even take damage if not finding shelter.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>For the above-ground we need to be able to disable combat all rooms except for the PvP location. We also need to consider how to auto-generate the rooms under ground. So we probably will need some statuses to control that.</p>
<p>Since each room under ground should present some sort of challenge, we may need a few different room types different from the above-ground Rooms.</p>
</section>
<section id="can-objects-be-hidden-in-the-room-can-a-person-hide-in-the-room">
<h3>Can objects be hidden in the room? Can a person hide in the room?<a class="headerlink" href="#can-objects-be-hidden-in-the-room-can-a-person-hide-in-the-room" title="Permalink to this headline"></a></h3>
<p>This ties into if you have hide/stealth mechanics. Maybe you could evesdrop or attack out of hiding.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will not model hiding and stealth. This will be a game of honorable face-to-face conflict.</p>
</section>
</section>
@ -259,80 +249,74 @@ will not get wet and fireballs will not fizzle if it rains.</p>
<h2>Objects<a class="headerlink" href="#objects" title="Permalink to this headline"></a></h2>
<section id="how-numerous-are-your-objects-do-you-want-large-loot-lists-or-are-objects-just-role-playing-props">
<h3>How numerous are your objects? Do you want large loot-lists or are objects just role playing props?<a class="headerlink" href="#how-numerous-are-your-objects-do-you-want-large-loot-lists-or-are-objects-just-role-playing-props" title="Permalink to this headline"></a></h3>
<p>Since we are not going for a pure freeform RPG here, we will want objects with properties, like weapons
and potions and such. Monsters should drop loot even though our list of objects will not be huge.</p>
<p>This also depends on the type of game. In a pure freeform RPG, most objects may be imaginary and just appearing in fiction. If the game is more coded, you want objects with properties that the computer can measure, track and calculate. In many roleplaying-heavy games, you find a mixture of the two, with players imagining items for roleplaying scenes, but only using real objects to resolve conflicts.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will want objects with properties, like weapons and potions and such. Monsters should drop loot even though our list of objects will not be huge in this example game.</p>
</section>
<section id="is-each-coin-a-separate-object-or-do-you-just-store-a-bank-account-value">
<h3>Is each coin a separate object or do you just store a bank account value?<a class="headerlink" href="#is-each-coin-a-separate-object-or-do-you-just-store-a-bank-account-value" title="Permalink to this headline"></a></h3>
<p>Since we will use bartering, placing coin objects on one side of the barter makes for a simple way to
handle payments. So we will use coins as-objects.</p>
<p>The advantage of having multiple items is that it can be more immersive. The drawback is that its also very fiddly to deal with individual coins, especially if you have to deal with different currencies.</p>
<p><strong>EvAdventure Answer</strong></p>
<p><em>Knave</em> uses the “copper” as the base coin and so will we. Knave considers the weight of coin and one inventory “slot” can hold 100 coins. So well implement a “coin item” to represent many coins.</p>
</section>
<section id="do-multiple-similar-objects-form-stacks-and-how-are-those-stacks-handled-in-that-case">
<h3>Do multiple similar objects form stacks and how are those stacks handled in that case?<a class="headerlink" href="#do-multiple-similar-objects-form-stacks-and-how-are-those-stacks-handled-in-that-case" title="Permalink to this headline"></a></h3>
<p>Since well use coins, its practical to have them and other items stack together. While Evennia does not
do this natively, we will make use of a contrib for this.</p>
<section id="do-multiple-similar-objects-form-stack-and-how-are-those-stacks-handled-in-that-case">
<h3>Do multiple similar objects form stack and how are those stacks handled in that case?<a class="headerlink" href="#do-multiple-similar-objects-form-stack-and-how-are-those-stacks-handled-in-that-case" title="Permalink to this headline"></a></h3>
<p>If you drop two identical apples on the ground, Evennia will default to show this in the room as “two apples”, but this is just a visual effect - there are still two apple-objects in the room. One could picture instead merging the two into a single object “X nr of apples” when you drop the apples.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will keep Evennias default.</p>
</section>
<section id="does-an-object-have-weight-or-volume-so-you-cannot-carry-an-infinite-amount-of-them">
<h3>Does an object have weight or volume (so you cannot carry an infinite amount of them)?<a class="headerlink" href="#does-an-object-have-weight-or-volume-so-you-cannot-carry-an-infinite-amount-of-them" title="Permalink to this headline"></a></h3>
<p>Limiting carrying weight is one way to stop players from hoarding. It also makes it more important
for players to pick only the equipment they need. Carrying limits can easily come across as
annoying to players though, so one needs to be careful with it.</p>
<p>Open Adventure rules include weight limits, so we will include them.</p>
<p>Limiting carrying weight is one way to stop players from hoarding. It also makes it more important for players to pick only the equipment they need. Carrying limits can easily come across as annoying to players though, so one needs to be careful with it.</p>
<p><strong>EvAdventure Answer</strong></p>
<p><em>Knave</em> limits your inventory to <code class="docutils literal notranslate"><span class="pre">Constitution</span> <span class="pre">+</span> <span class="pre">10</span></code> “slots”, where most items take up one slot and some large things, like armor, uses two. Small items (like rings) can fit 2-10 per slot and you can fit 100 coins in a slot. This is an important game mechanic to limit players from hoarding. Especially since you need coin to level up.</p>
</section>
<section id="can-objects-be-broken-can-they-be-repaired">
<h3>Can objects be broken? Can they be repaired?<a class="headerlink" href="#can-objects-be-broken-can-they-be-repaired" title="Permalink to this headline"></a></h3>
<p>Item breakage is very useful for a game economy; breaking weapons adds tactical considerations (if its not
too common, then it becomes annoying) and repairing things gives work for crafting players.</p>
<p>We wanted a crafting system, so this is what we will limit it to - repairing items using some sort
of raw materials.</p>
<p>Item breakage is very useful for a game economy; breaking weapons adds tactical considerations (if its not too common, then it becomes annoying) and repairing things gives work for crafting players.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>In <em>Knave</em>, items will break if you make a critical failure on using them (rolls a native 1 on d20). This means they lose a level of <code class="docutils literal notranslate"><span class="pre">quality</span></code> and once at 0, its unusable. We will not allow players to repair, but we could allow merchants to repair items for a fee.</p>
</section>
<section id="can-you-fight-with-a-chair-or-a-flower-or-must-you-use-a-special-weapon-kind-of-thing">
<h3>Can you fight with a chair or a flower or must you use a special weapon kind of thing?<a class="headerlink" href="#can-you-fight-with-a-chair-or-a-flower-or-must-you-use-a-special-weapon-kind-of-thing" title="Permalink to this headline"></a></h3>
<p>Traditionally, only weapons could be used to fight with. In the past this was a useful
simplification, but with Python classes and inheritance, its not actually more work to just
let all items in game work as a weapon in a pinch.</p>
<p>So for our game we will let a character use any item they want as a weapon. The difference will
be that non-weapon items will do less damage and also break and become unusable much quicker.</p>
simplification, but with Python classes and inheritance, its not actually more work to just let all items in game work as a weapon in a pinch.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>Since <em>Knave</em> deals with weapon lists and positions where items can be wielded, we will have a separate “Weapon” class for everything you can use for fighting. So, you wont be able to fight with a chair (unless we make it a weapon-inherited chair).</p>
</section>
<section id="will-characters-be-able-to-craft-new-objects">
<h3>Will characters be able to craft new objects?<a class="headerlink" href="#will-characters-be-able-to-craft-new-objects" title="Permalink to this headline"></a></h3>
<p>Crafting is a common feature in multiplayer games. In code it usually means using a skill-check
to combine base ingredients from a fixed recipe in order to create a new item. The classic
example is to combine <em>leather straps</em>, a <em>hilt</em>, a <em>pommel</em> and a <em>blade</em> to make a new <em>sword</em>.
A full-fledged crafting system could require multiple levels of crafting, including having to mine
for ore or cut down trees for wood.</p>
<p>In our case we will limit our crafting to repairing broken items. To show how its done, we will require
extra items (a recipe) in order to facilitate the repairs.</p>
<p>Crafting is a common feature in multiplayer games. In code it usually means using a skill-check to combine base ingredients from a fixed recipe in order to create a new item. The classic example is to combine <em>leather straps</em>, a <em>hilt</em>, a <em>pommel</em> and a <em>blade</em> to make a new <em>sword</em>.</p>
<p>A full-fledged crafting system could require multiple levels of crafting, including having to mine for ore or cut down trees for wood.</p>
<p>Evennias <a class="reference internal" href="../../../Contribs/Contrib-Crafting.html"><span class="doc std std-doc">Crafting</span></a> contrib adds a full crafting system to any game. Its based on <a class="reference internal" href="../../../Components/Tags.html"><span class="doc std std-doc">Tags</span></a>, meaning that pretty much any object can be made usable for crafting, even used in an unexpected way.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>In our case we will not add any crafting in order to limit the scope of our game. Maybe NPCs will be able to repair items - for a cost?</p>
</section>
<section id="should-mobs-npcs-have-some-sort-of-ai">
<h3>Should mobs/NPCs have some sort of AI?<a class="headerlink" href="#should-mobs-npcs-have-some-sort-of-ai" title="Permalink to this headline"></a></h3>
<p>A rule of adding Artificial Intelligence is that with todays technology you should not hope to fool
anyone with it anytime soon. Unless you have a side-gig as an AI researcher, users will likely
not notice any practical difference between a simple state-machine and you spending a lot of time learning
<p>As a rule, you should not hope to fool anyone into thinking your AI is actually intelligent. The best you will be able to do is to give interesting results and unless you have a side-gig as an AI researcher, users will likely not notice any practical difference between a simple state-machine and you spending a lot of time learning
how to train a neural net.</p>
<p>For this tutorial, we will show how to add a simple state-machine for monsters. NPCs will only be
shop-keepers and quest-gives so they wont need any real AI to speak of.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>For this tutorial, we will show how to add a simple state-machine AI for monsters. NPCs will only be shop-keepers and quest-gives so they wont need any real AI to speak of.</p>
</section>
<section id="are-npcs-and-mobs-different-entities-how-do-they-differ">
<h3>Are NPCs and mobs different entities? How do they differ?<a class="headerlink" href="#are-npcs-and-mobs-different-entities-how-do-they-differ" title="Permalink to this headline"></a></h3>
<p>“Mobs” or “mobiles” are things that move around. This is traditionally monsters you can fight with, but could
also be city guards or the baker going to chat with the neighbor. Back in the day, they were often fundamentally
different these days its often easier to just make NPCs and mobs essentially the same thing.</p>
<p>In EvAdventure, both Monsters and NPCs will be the same type of thing; A monster could give you a quest
and an NPC might fight you as a mob as well as trade with you.</p>
<p>“Mobs” or “mobiles” are things that move around. This is traditionally monsters you can fight with, but could also be city guards or the baker going to chat with the neighbor. Back in the day, they were often fundamentally different these days its often easier to just make NPCs and mobs essentially the same thing.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>In EvAdventure, Monsters and NPCs do very different things, so they will be different classes, sharing some code where possible.</p>
</section>
<section id="should-there-be-npcs-giving-quests-if-so-how-do-you-track-quest-status">
<h3>_Should there be NPCs giving quests? If so, how do you track Quest status?<a class="headerlink" href="#should-there-be-npcs-giving-quests-if-so-how-do-you-track-quest-status" title="Permalink to this headline"></a></h3>
<p>We will design a simple quest system to track the status of ongoing quests.</p>
<p>Quests are a staple of many classic RPGs.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will design a simple quest system with some simple conditions for success, like carrying the right item or items back to the quest giver.</p>
</section>
</section>
<section id="characters">
<h2>Characters<a class="headerlink" href="#characters" title="Permalink to this headline"></a></h2>
<section id="can-players-have-more-than-one-character-active-at-a-time-or-are-they-allowed-to-multi-play">
<h3>Can players have more than one Character active at a time or are they allowed to multi-play?<a class="headerlink" href="#can-players-have-more-than-one-character-active-at-a-time-or-are-they-allowed-to-multi-play" title="Permalink to this headline"></a></h3>
<p>Since Evennia differentiates between <code class="docutils literal notranslate"><span class="pre">Sessions</span></code> (the client-connection to the game), <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>
and <code class="docutils literal notranslate"><span class="pre">Character</span></code>s, it natively supports multi-play. This is controlled by the <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code>
setting, which has a value from <code class="docutils literal notranslate"><span class="pre">0</span></code> (default) to <code class="docutils literal notranslate"><span class="pre">3</span></code>.</p>
<p>Since Evennia differentiates between <code class="docutils literal notranslate"><span class="pre">Sessions</span></code> (the client-connection to the game), <code class="docutils literal notranslate"><span class="pre">Accounts</span></code> and <code class="docutils literal notranslate"><span class="pre">Character</span></code>s, it natively supports multi-play. This is controlled by the <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> setting, which has a value from <code class="docutils literal notranslate"><span class="pre">0</span></code> (default) to <code class="docutils literal notranslate"><span class="pre">3</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">0</span></code>- One Character per Account and one Session per Account. This means that if you login to the same
account from another client youll be disconnected from the first. When creating a new account, a Character
@ -347,31 +331,28 @@ open, but only one client per Character.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">3</span></code> - Multiple Characters per Account, Multiple Sessions per Character. This is like mode 2, except players
can control each Character from multiple clients, seeing the same output from each Character.</p></li>
</ul>
<p>We will go with a multi-role game, so we will use <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=3</span></code> for this tutorial.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>Due to the nature of <em>Knave</em>, characters are squishy and probably short-lived. So it makes little sense to keep a stable of them. Well use use mode 0 or 1.</p>
</section>
<section id="how-does-the-character-generation-work">
<h3>How does the character-generation work?<a class="headerlink" href="#how-does-the-character-generation-work" title="Permalink to this headline"></a></h3>
<p>There are a few common ways to do character generation:</p>
<ul class="simple">
<li><p>Rooms. This is the traditional way. Each rooms description tells you what command to use to modify
your character. When you are done you move to the next room. Only use this if you have another reason for
using a room, like having a training dummy to test skills on, for example.</p></li>
<li><p>A Menu. The Evennia <em>EvMenu</em> system allows you to code very flexible in-game menus without needing to walk
between rooms. You can both have a step-by-step menu (a wizard) or allow the user to jump between the
<li><p>Rooms. This is the traditional way. Each rooms description tells you what command to use to modify your character. When you are done you move to the next room. Only use this if you have another reason for using a room, like having a training dummy to test skills on, for example.</p></li>
<li><p>A Menu. The Evennia <em>EvMenu</em> system allows you to code very flexible in-game menus without needing to walk between rooms. You can both have a step-by-step menu (a wizard) or allow the user to jump between the
steps as they please. This tends to be a lot easier for newcomers to understand since it doesnt require
using custom commands they will likely never use again after this.</p></li>
<li><p>Questions. A fun way to build a character is to answer a series of questions. This is usually implemented
with a sequential menu.</p></li>
<li><p>Questions. A fun way to build a character is to answer a series of questions. This is usually implemented with a sequential menu.</p></li>
</ul>
<p>For the tutorial we will use a menu to let the user modify each section of their character sheet in any order
until they are happy.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>Knave randomizes almost aspects of the Character generation. Well use a menu to let the player add their name and sex as well as do the minor re-assignment of stats allowed by the rules.</p>
</section>
<section id="how-do-you-implement-different-classes-or-races">
<h3>How do you implement different “classes” or “races”?<a class="headerlink" href="#how-do-you-implement-different-classes-or-races" title="Permalink to this headline"></a></h3>
<p>The way classes and races work in most RPGs (as well as in OpenAdventure) is that they act as static templates
that inform which bonuses and special abilities you have. This means that all we need to store on the
Character is <em>which</em> class and <em>which</em> race they have; the actual logic can sit in Python code and just
be looked up when we need it.</p>
<p>The way classes and races work in most RPGs is that they act as static templates that inform which bonuses and special abilities you have. Much of this only comes into play during character generation or when leveling up.</p>
<p>Often all we need to store on the Character is <em>which</em> class and <em>which</em> race they have; the actual logic can sit in Python code and just be looked up when we need it.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>There are no races and no classes in <em>Knave</em>. Every character is a human.</p>
</section>
<section id="if-a-character-can-hide-in-a-room-what-skill-will-decide-if-they-are-detected">
<h3>If a Character can hide in a room, what skill will decide if they are detected?<a class="headerlink" href="#if-a-character-can-hide-in-a-room-what-skill-will-decide-if-they-are-detected" title="Permalink to this headline"></a></h3>
@ -384,15 +365,15 @@ or <code class="docutils literal notranslate"><span class="pre">look</span> <spa
find the person (probably based on skill checks).</p></li>
<li><p>The room will also need to be involved, maybe with some modifier as to how easy it is to hide in the room.</p></li>
</ul>
<p>We will <em>not</em> be including a hide-mechanic in EvAdventure though.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will not be including a hide-mechanic in EvAdventure.</p>
</section>
<section id="what-does-the-skill-tree-look-like-can-a-character-gain-experience-to-improve-by-killing-enemies-solving-quests-by-roleplaying">
<h3>What does the skill tree look like? Can a Character gain experience to improve? By killing enemies? Solving quests? By roleplaying?<a class="headerlink" href="#what-does-the-skill-tree-look-like-can-a-character-gain-experience-to-improve-by-killing-enemies-solving-quests-by-roleplaying" title="Permalink to this headline"></a></h3>
<p>Gaining experience points (XP) and improving ones character is a staple of roleplaying games. There are many
ways to implement this:</p>
<ul class="simple">
<li><p>Gaining XP from kills is very common; its easy to let a monster be worth a certain number of XP and its
easy to tell when you should gain it.</p></li>
<li><p>Gaining XP from kills is very common; its easy to let a monster be worth a certain number of XP and its easy to tell when you should gain it.</p></li>
<li><p>Gaining XP from quests is the same - each quest is worth XP and you get them when completing the test.</p></li>
<li><p>Gaining XP from roleplay is harder to define. Different games have tried a lot of different ways to do this:</p>
<ul>
@ -407,19 +388,16 @@ you gain XP only for running when you run, XP for your axe skill when you fight
</ul>
</li>
</ul>
<p>For EvAdventure we will use Open Adventures rules for XP, which will be driven by kills and quest successes.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will use an alternative rule in <em>Knave</em>, where Characters gain XP by spending coins they carry back from their adventures. The above-ground merchants will allow you to spend your coins and exchange them for XP 1:1. Each level costs 1000 coins. Every level you have <code class="docutils literal notranslate"><span class="pre">1d8</span>&#160; <span class="pre">*</span> <span class="pre">new</span> <span class="pre">level</span></code> (minimum what you had before + 1) HP, and can raise 3 different ability scores by 1 (max +10). There are no skills in <em>Knave</em>, but the principle of increasing them would be the same.</p>
</section>
<section id="may-player-characters-attack-each-other-pvp">
<h3>May player-characters attack each other (PvP)?<a class="headerlink" href="#may-player-characters-attack-each-other-pvp" title="Permalink to this headline"></a></h3>
<p>Deciding this affects the style of your entire game. PvP makes for exciting gameplay but it opens a whole new
can of worms when it comes to “fairness”. Players will usually accept dying to an overpowered NPC dragon. They
will not be as accepting if they perceive another player is perceived as being overpowered. PvP means that you
have to be very careful to balance the game - all characters does not have to be exactly equal but they should
all be viable to play a fun game with. PvP does not only mean combat though. Players can compete in all sorts of ways, including gaining influence in
a political game or gaining market share when selling their crafted merchandise.</p>
<p>For the EvAdventure we will support both Player-vs-environment combat and turn-based PvP. We will allow players
to barter with each other (so potentially scam others?) but thats the extent of it. We will focus on showing
off techniques and will not focus on making a balanced game.</p>
<p>Deciding this affects the style of your entire game. PvP makes for exciting gameplay but it opens a whole new can of worms when it comes to “fairness”. Players will usually accept dying to an overpowered NPC dragon. They will not be as accepting if they perceive another player as being overpowered. PvP means that you
have to be very careful to balance the game - all characters does not have to be exactly equal but they should all be viable to play a fun game with.</p>
<p>PvP does not only mean combat though. Players can compete in all sorts of ways, including gaining influence in a political game or gaining market share when selling their crafted merchandise.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>We will allow PvP only in one place - a special Dueling location where players can play-fight each other for training and prestige, but not actually get killed. Otherwise no PvP will be allowed. Note that without a full Barter system in place (just regular <code class="docutils literal notranslate"><span class="pre">give</span></code>, it makes it theoretically easier for players to scam one another.</p>
</section>
<section id="what-are-the-penalties-of-defeat-permanent-death-quick-respawn-time-in-prison">
<h3>What are the penalties of defeat? Permanent death? Quick respawn? Time in prison?<a class="headerlink" href="#what-are-the-penalties-of-defeat-permanent-death-quick-respawn-time-in-prison" title="Permalink to this headline"></a></h3>
@ -436,36 +414,34 @@ up for newcomers.</p></li>
</ul>
<p>Perma-death comes with some severe disadvantages however.</p>
<ul class="simple">
<li><p>Its impopular. Many players will just not play a game where they risk losing their beloved character
just like that.</p></li>
<li><p>Many players say they like the <em>idea</em> of permadeath except when it could happen to them.</p></li>
<li><p>It can limit roleplaying freedom and make people refuse to take any risks.</p></li>
<li><p>Some players refuse to take any risks if death is permanent.</p></li>
<li><p>It may make players even more reluctant to play conflict-driving bad guys.</p></li>
<li><p>Game balance is much, much more important when results are “final”. This escalates the severity of unfairness
a hundred-fold. Things like bugs or exploits can also lead to much more server effects.</p></li>
<li><p>Balancing PvP becomes very hard. Fairness and avoiding exploits becomes critical when the outcome
is permanent.</p></li>
</ul>
<p>For these reasons, its very common to do hybrid systems. Some tried variations:</p>
<ul class="simple">
<li><p>NPCs cannot kill you, only other players can.</p></li>
<li><p>Death is permanent, but its difficult to actually die - you are much more likely to end up being severely
hurt/incapacitated.</p></li>
<li><p>Death is permanent, but its difficult to actually die - you are much more likely to end up being severely hurt/incapacitated.</p></li>
<li><p>You can pre-pay insurance to magically/technologically avoid actually dying. Only if dont have insurance will
you die permanently.</p></li>
<li><p>Death just means harsh penalties, not actual death.</p></li>
<li><p>When you die you can fight your way back to life from some sort of afterlife.</p></li>
<li><p>Youll only die permanently if you as a player explicitly allows it.</p></li>
</ul>
<p>For our tutorial-game we will not be messing with perma-death; instead your defeat will mean you will re-spawn
back at your home location with a fraction of your health.</p>
<p><strong>EvAdventure Answer</strong></p>
<p>In <em>Knave</em>, when you hit 0 HP, you roll on a death table, with a 1/8 chance of immediate death (otherwise you lose
points in a random stat). We will offer an “Insurance” that allows you to resurrect if you carry enough coin on you when
you die. If not, you are perma-dead and have to create a new character (which is easy and quick since its mostly
randomized).</p>
</section>
</section>
<section id="conclusions">
<h2>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline"></a></h2>
<p>Going through the questions has helped us get a little bit more of a feel for the game we want to do. There are
many other things we could ask ourselves, but if we can cover these points we will be a good way towards a complete,
<p>Going through the questions has helped us get a little bit more of a feel for the game we want to do. There are many, many other things we could ask ourselves, but if we can cover these points we will be a good way towards a complete,
playable game!</p>
<p>Before starting to code in earnest a good coder should always do an inventory of all the stuff they <em>dont</em> need
to code themselves. So in the next lesson we will check out what help we have from Evennias <em>contribs</em>.</p>
<p>In the last of these planning lessons well sketch out how these ideas will map to Evennia.</p>
</section>
</section>
@ -492,6 +468,7 @@ to code themselves. So in the next lesson we will check out what help we have fr
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Planning our tutorial game</a><ul>
<li><a class="reference internal" href="#game-concept">Game concept</a></li>
<li><a class="reference internal" href="#administration">Administration</a><ul>
<li><a class="reference internal" href="#should-your-game-rules-be-enforced-by-coded-systems-by-human-game-masters">Should your game rules be enforced by coded systems by human game masters?</a></li>
<li><a class="reference internal" href="#what-is-the-staff-hierarchy-in-your-game-is-vanilla-evennia-roles-enough-or-do-you-need-something-else">What is the staff hierarchy in your game? Is vanilla Evennia roles enough or do you need something else?</a></li>
@ -522,7 +499,7 @@ to code themselves. So in the next lesson we will check out what help we have fr
<li><a class="reference internal" href="#objects">Objects</a><ul>
<li><a class="reference internal" href="#how-numerous-are-your-objects-do-you-want-large-loot-lists-or-are-objects-just-role-playing-props">How numerous are your objects? Do you want large loot-lists or are objects just role playing props?</a></li>
<li><a class="reference internal" href="#is-each-coin-a-separate-object-or-do-you-just-store-a-bank-account-value">Is each coin a separate object or do you just store a bank account value?</a></li>
<li><a class="reference internal" href="#do-multiple-similar-objects-form-stacks-and-how-are-those-stacks-handled-in-that-case">Do multiple similar objects form stacks and how are those stacks handled in that case?</a></li>
<li><a class="reference internal" href="#do-multiple-similar-objects-form-stack-and-how-are-those-stacks-handled-in-that-case">Do multiple similar objects form stack and how are those stacks handled in that case?</a></li>
<li><a class="reference internal" href="#does-an-object-have-weight-or-volume-so-you-cannot-carry-an-infinite-amount-of-them">Does an object have weight or volume (so you cannot carry an infinite amount of them)?</a></li>
<li><a class="reference internal" href="#can-objects-be-broken-can-they-be-repaired">Can objects be broken? Can they be repaired?</a></li>
<li><a class="reference internal" href="#can-you-fight-with-a-chair-or-a-flower-or-must-you-use-a-special-weapon-kind-of-thing">Can you fight with a chair or a flower or must you use a special weapon kind of thing?</a></li>
@ -548,15 +525,15 @@ to code themselves. So in the next lesson we will check out what help we have fr
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Planning-Some-Useful-Contribs.html"
title="previous chapter">Planning the use of some useful contribs</a></p>
<p class="topless"><a href="Beginner-Tutorial-Game-Planning.html"
title="previous chapter">On Planning a Game</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="../Part3/Beginner-Tutorial-Part3-Intro.html"
title="next chapter">Part 3: How we get there</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Planning-The-Tutorial-Game.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -572,7 +549,7 @@ to code themselves. So in the next lesson we will check out what help we have fr
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Planning-The-Tutorial-Game.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Planning-The-Tutorial-Game.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -593,7 +570,7 @@ to code themselves. So in the next lesson we will check out what help we have fr
<a href="../Part3/Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
>next</a> |</li>
<li class="right" >
<a href="Planning-Some-Useful-Contribs.html" title="Planning the use of some useful contribs"
<a href="Beginner-Tutorial-Game-Planning.html" title="On Planning a Game"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -17,7 +17,7 @@
<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="On Planning a Game" href="Game-Planning.html" />
<link rel="next" title="On Planning a Game" href="Beginner-Tutorial-Game-Planning.html" />
<link rel="prev" title="Part 2: What we want" href="Beginner-Tutorial-Part2-Intro.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
@ -30,7 +30,7 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Game-Planning.html" title="On Planning a Game"
<a href="Beginner-Tutorial-Game-Planning.html" title="On Planning a Game"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part2-Intro.html" title="Part 2: What we want"
@ -225,12 +225,12 @@ then try to answer those questions for the sake of creating our little tutorial
<p class="topless"><a href="Beginner-Tutorial-Part2-Intro.html"
title="previous chapter">Part 2: What we want</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Game-Planning.html"
<p class="topless"><a href="Beginner-Tutorial-Game-Planning.html"
title="next chapter">On Planning a Game</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Planning-Where-Do-I-Begin.md.txt"
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Beginner-Tutorial-Planning-Where-Do-I-Begin.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
@ -246,7 +246,7 @@ then try to answer those questions for the sake of creating our little tutorial
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Planning-Where-Do-I-Begin.html">1.0-dev (develop branch)</a></li>
<li><a href="Beginner-Tutorial-Planning-Where-Do-I-Begin.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
@ -264,7 +264,7 @@ then try to answer those questions for the sake of creating our little tutorial
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Game-Planning.html" title="On Planning a Game"
<a href="Beginner-Tutorial-Game-Planning.html" title="On Planning a Game"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part2-Intro.html" title="Part 2: What we want"

View file

@ -1,370 +0,0 @@
<!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>Planning the use of some useful contribs &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Planning our tutorial game" href="Planning-The-Tutorial-Game.html" />
<link rel="prev" title="On Planning a Game" href="Game-Planning.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="Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Game-Planning.html" title="On Planning a Game"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part2-Intro.html" accesskey="U">Part 2: What we want</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Planning the use of some useful contribs</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="planning-the-use-of-some-useful-contribs">
<h1>Planning the use of some useful contribs<a class="headerlink" href="#planning-the-use-of-some-useful-contribs" title="Permalink to this headline"></a></h1>
<p>Evennia is deliberately bare-bones out of the box. The idea is that you should be as unrestricted as possible
in designing your game. This is why you can easily replace the few defaults we have and why we dont try to
prescribe any major game systems on you.</p>
<p>That said, Evennia <em>does</em> offer some more game-opinionated <em>optional</em> stuff. These are referred to as <em>Contribs</em>
and is an ever-growing treasure trove of code snippets, concepts and even full systems you can pick and choose
from to use, tweak or take inspiration from when you make your game.</p>
<p>The <a class="reference internal" href="../../../Contribs/Contribs-Overview.html"><span class="doc std std-doc">Contrib overview</span></a> page gives the full list of the current roster of contributions. On
this page we will review a few contribs we will make use of for our game. We will do the actual installation
of them when we start coding in the next part of this tutorial series. While we will introduce them here, you
are wise to read their doc-strings yourself for the details.</p>
<p>This is the things we know we need:</p>
<ul class="simple">
<li><p>A barter system</p></li>
<li><p>Character generation</p></li>
<li><p>Some concept of wearing armor</p></li>
<li><p>The ability to roll dice</p></li>
<li><p>Rooms with awareness of day, night and season</p></li>
<li><p>Roleplaying with short-descs, poses and emotes</p></li>
<li><p>Quests</p></li>
<li><p>Combat (with players and against monsters)</p></li>
</ul>
<section id="barter-contrib">
<h2>Barter contrib<a class="headerlink" href="#barter-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.game_systems.barter.html"><span class="doc std std-doc">source</span></a></p>
<p>Reviewing this contrib suggests that it allows for safe trading between two parties. The basic principle
is that the parties puts up the stuff they want to sell and the system will guarantee that these systems are
exactly what is being offered. Both sides can modify their offers (bartering) until both mark themselves happy
with the deal. Only then the deal is sealed and the objects are exchanged automatically. Interestingly, this
works just fine for money too - just put coin objects on one side of the transaction.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Sue &gt; trade Tom: Hi, I have a necklace to sell; wanna trade for a healing potion?
Tom &gt; trade Sue: Hm, I could use a necklace ...
&lt;both accepted trade. Start trade&gt;
Sue &gt; offer necklace: This necklace is really worth it.
Tom &gt; evaluate necklace:
&lt;Tom sees necklace stats&gt;
Tom &gt; offer ration: I don&#39;t have a healing potion, but I&#39;ll trade you an iron ration!
Sue &gt; Hey, this is a nice necklace, I need more than a ration for it...
Tom &gt; offer ration, 10gold: Ok, a ration and 10 gold as well.
Sue &gt; accept: Ok, that sounds fair!
Tom &gt; accept: Good! Nice doing business with you.
&lt;goods change hands automatically. Trade ends&gt;
</pre></div>
</div>
<p>Arguably, in a small game you are just fine to just talk to people and use <code class="docutils literal notranslate"><span class="pre">give</span></code> to do the exchange. The
barter system guarantees trading safety if you dont trust your counterpart to try to give you the wrong thing or
to run away with your money.</p>
<p>We will use the barter contrib as an optional feature for player-player bartering. More importantly we can
add it for NPC shopkeepers and expand it with a little AI, which allows them to potentially trade in other
things than boring gold coin.</p>
</section>
<section id="clothing-contrib">
<h2>Clothing contrib<a class="headerlink" href="#clothing-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.game_systems.clothing.html"><span class="doc std std-doc">source</span></a></p>
<p>This contrib provides a full system primarily aimed at wearing clothes, but it could also work for armor. You wear
an object in a particular location and this will then be reflected in your characters description. You can
also add roleplaying flavor:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; wear helmet slightly askew on her head
look self
Username is wearing a helmet slightly askew on her head.
</pre></div>
</div>
<p>By default there are no body locations in this contrib, we will need to expand on it a little to make it useful
for things like armor. Its a good contrib to build from though, so thats what well do.</p>
</section>
<section id="dice-contrib">
<h2>Dice contrib<a class="headerlink" href="#dice-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.rpg.dice.html"><span class="doc std std-doc">source</span></a></p>
<p>The dice contrib presents a general dice roller to use in game.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; roll 2d6
Roll(s): 2 and 5. Total result is 7.
&gt; roll 1d100 + 2
Roll(s): 43. Total result is 47
&gt; roll 1d20 &gt; 12
Roll(s): 7. Total result is 7. This is a failure (by 5)
&gt; roll/hidden 1d20 &gt; 12
Roll(s): 18. Total result is 17. This is a success (by 6). (not echoed)
</pre></div>
</div>
<p>The contrib also has a python function for producing these results in-code. However, while
we will emulate rolls for our rule system, well do this as simply as possible with Pythons <code class="docutils literal notranslate"><span class="pre">random</span></code>
module.</p>
<p>So while this contrib is fun to have around for GMs or for players who want to get a random result
or play a game, we will not need it for the core of our game.</p>
</section>
<section id="extended-room-contrib">
<h2>Extended room contrib<a class="headerlink" href="#extended-room-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.grid.extended_room.html"><span class="doc std std-doc">source</span></a></p>
<p>This is a custom Room typeclass that changes its description based on time of day and season.</p>
<p>For example, at night, in wintertime you could show the room as being dark and frost-covered while in daylight
at summer it could describe a flowering meadow. The description can also contain special markers, so
<code class="docutils literal notranslate"><span class="pre">&lt;morning&gt;</span> <span class="pre">...</span> <span class="pre">&lt;/morning&gt;</span></code> would include text only visible at morning.</p>
<p>The extended room also supports <em>details</em>, which are things to “look at” in the room without there having
to be a separate database object created for it. For example, a player in a church may do <code class="docutils literal notranslate"><span class="pre">look</span> <span class="pre">window</span></code> and
get a description of the windows without there needing to be an actual <code class="docutils literal notranslate"><span class="pre">window</span></code> object in the room.</p>
<p>Adding all those extra descriptions can be a lot of work, so they are optional; if not given the room works
like a normal room.</p>
<p>The contrib is simple to add and provides a lot of optional flexibility, so well add it to our
game, why not!</p>
</section>
<section id="rp-system-contrib">
<h2>RP-System contrib<a class="headerlink" href="#rp-system-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.rpg.rpsystem.html"><span class="doc std std-doc">source</span></a></p>
<p>This contrib adds a full roleplaying subsystem to your game. It gives every character a “short-description”
(sdesc) that is what people will see when first meeting them. Lets say Tom has an sdesc “A tall man” and
Sue has the sdesc “A muscular, blonde woman”</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Tom &gt; look
Tom: &lt;room desc&gt; ... You see: A muscular, blonde woman
Tom &gt; emote /me smiles to /muscular.
Tom: Tom smiles to A muscular, blonde woman.
Sue: A tall man smiles to Sue.
Tom &gt; emote Leaning forward, /me says, &quot;Well hello, what&#39;s yer name?&quot;
Tom: Leaning forward, Tom says, &quot;Well hello...&quot;
Sue: Leaning forward, A tall man says, &quot;Well hello, what&#39;s yer name?&quot;
Sue &gt; emote /me grins. &quot;I&#39;m Angelica&quot;, she says.
Sue: Sue grins. &quot;I&#39;m Angelica&quot;, she says.
Tom: A muscular, blonde woman grins. &quot;I&#39;m Angelica&quot;, she says.
Tom &gt; recog muscular Angelica
Tom &gt; emote /me nods to /angelica: &quot;I have a message for you ...&quot;
Tom: Tom nods to Angelica: &quot;I have a message for you ...&quot;
Sue: A tall man nods to Sue: &quot;I have a message for you ...&quot;
</pre></div>
</div>
<p>Above, Sue introduces herself as “Angelica” and Tom uses this info to <code class="docutils literal notranslate"><span class="pre">recoc</span></code> her as “Angelica” hereafter. He
could have <code class="docutils literal notranslate"><span class="pre">recoc</span></code>-ed her with whatever name he liked - its only for his own benefit. There is no separate
<code class="docutils literal notranslate"><span class="pre">say</span></code>, the spoken words are embedded in the emotes in quotes <code class="docutils literal notranslate"><span class="pre">&quot;...&quot;</span></code>.</p>
<p>The RPSystem module also includes options for <code class="docutils literal notranslate"><span class="pre">poses</span></code>, which help to establish your position in the room
when others look at you.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Tom &gt; pose stands by the bar, looking bored.
Sue &gt; look
Sue: &lt;room desc&gt; ... A tall man stands by the bar, looking bored.
</pre></div>
</div>
<p>You can also wear a mask to hide your identity; your sdesc will then be changed to the sdesc of the mask,
like <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">person</span> <span class="pre">with</span> <span class="pre">a</span> <span class="pre">mask</span></code>.</p>
<p>The RPSystem gives a lot of roleplaying power out of the box, so we will add it. There is also a separate
<a class="reference internal" href="../../../api/evennia.contrib.rpg.rpsystem.html"><span class="doc std std-doc">rplanguage</span></a> module that integrates with the spoken words in your emotes and garbles them if you dont understand
the language spoken. In order to restrict the scope we will not include languages for the tutorial game.</p>
</section>
<section id="talking-npc-contrib">
<h2>Talking NPC contrib<a class="headerlink" href="#talking-npc-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.tutorials.talking_npc.html"><span class="doc std std-doc">source</span></a></p>
<p>This exemplifies an NPC with a menu-driven dialogue tree. We will not use this contrib explicitly, but its
good as inspiration for how well do quest-givers later.</p>
</section>
<section id="traits-contrib">
<h2>Traits contrib<a class="headerlink" href="#traits-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.rpg.traits.html"><span class="doc std std-doc">source</span></a></p>
<p>An issue with dealing with roleplaying attributes like strength, dexterity, or skills like hunting, sword etc
is how to keep track of the values in the moment. Your strength may temporarily be buffed by a strength-potion.
Your swordmanship may be worse because you are encumbered. And when you drink your health potion you must make
sure that those +20 health does not bring your health higher than its maximum. All this adds complexity.</p>
<p>The <em>Traits</em> contrib consists of several types of objects to help track and manage values like this. When
installed, the traits are accessed on a new handler <code class="docutils literal notranslate"><span class="pre">.traits</span></code>, for example</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.traits.hp.value
100
&gt; py self.traits.hp -= 20 # getting hurt
&gt; py self.traits.hp.value
80
&gt; py self.traits.hp.reset() # drink a potion
&gt; py self.traits.hp.value
100
</pre></div>
</div>
<p>A Trait is persistent (it uses an Attribute under the hood) and tracks changes, min/max and other things
automatically. They can also be added together in various mathematical operations.</p>
<p>The contrib introduces three main Trait-classes</p>
<ul class="simple">
<li><p><em>Static</em> traits for single values like str, dex, things that at most gets a modifier.</p></li>
<li><p><em>Counters</em> is a value that never moves outside a given range, even with modifiers. For example a skill
that can at most get a maximum amount of buff. Counters can also easily be <em>timed</em> so that they decrease
or increase with a certain rate per second. This could be good for a time-limited curse for example.</p></li>
<li><p><em>Gauge</em> is like a fuel-gauge; it starts at a max value and then empties gradually. This is perfect for
things like health, stamina and the like. Gauges can also change with a rate, which works well for the
effects of slow poisons and healing both.</p></li>
</ul>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">value</span>
<span class="mi">100</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">rate</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="c1"># poisoned!</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">ratetarget</span> <span class="o">=</span> <span class="mi">50</span> <span class="c1"># stop at 50 hp</span>
<span class="c1"># Wait 30s</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">value</span>
<span class="mi">70</span>
<span class="c1"># Wait another 30s</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">value</span>
<span class="mi">50</span> <span class="c1"># stopped at 50</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">rate</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># no more poison</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">rate</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># healing magic!</span>
<span class="c1"># wait 5s</span>
<span class="o">&gt;</span> <span class="n">pyself</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">hp</span><span class="o">.</span><span class="n">value</span>
<span class="mi">75</span>
</pre></div>
</div>
<p>Traits will be very practical to use for our character sheets.</p>
</section>
<section id="turnbattle-contrib">
<h2>Turnbattle contrib<a class="headerlink" href="#turnbattle-contrib" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../../../api/evennia.contrib.game_systems.turnbattle.html"><span class="doc std std-doc">source</span></a></p>
<p>This contrib consists of several implementations of a turn-based combat system, divivided into complexity:</p>
<ul class="simple">
<li><p>basic - initiative and turn order, attacks against defense values, damage.</p></li>
<li><p>equip - considers weapons and armor, wielding and weapon accuracy.</p></li>
<li><p>items - adds usable items with conditions and status effects</p></li>
<li><p>magic - adds spellcasting system using MP.</p></li>
<li><p>range - adds abstract positioning and 1D movement to differentiate between melee and ranged attacks.</p></li>
</ul>
<p>The turnbattle system is comprehensive, but its meant as a base to start from rather than offer
a complete system. Its also not built with <em>Traits</em> in mind, so we will need to adjust it for that.</p>
</section>
<section id="conclusions">
<h2>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline"></a></h2>
<p>With some contribs selected, we have pieces to build from and dont have to write everything from scratch.
We will need Quests and will likely need to do a bunch of work on Combat to adapt the combat contrib
to our needs.</p>
<p>We will now move into actually starting to implement our tutorial game
in the next part of this tutorial series. When doing this for yourself, remember to refer
back to your planning and adjust it as you learn what works and what does not.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Planning the use of some useful contribs</a><ul>
<li><a class="reference internal" href="#barter-contrib">Barter contrib</a></li>
<li><a class="reference internal" href="#clothing-contrib">Clothing contrib</a></li>
<li><a class="reference internal" href="#dice-contrib">Dice contrib</a></li>
<li><a class="reference internal" href="#extended-room-contrib">Extended room contrib</a></li>
<li><a class="reference internal" href="#rp-system-contrib">RP-System contrib</a></li>
<li><a class="reference internal" href="#talking-npc-contrib">Talking NPC contrib</a></li>
<li><a class="reference internal" href="#traits-contrib">Traits contrib</a></li>
<li><a class="reference internal" href="#turnbattle-contrib">Turnbattle contrib</a></li>
<li><a class="reference internal" href="#conclusions">Conclusions</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Game-Planning.html"
title="previous chapter">On Planning a Game</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Planning-The-Tutorial-Game.html"
title="next chapter">Planning our tutorial game</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part2/Planning-Some-Useful-Contribs.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Planning-Some-Useful-Contribs.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
>next</a> |</li>
<li class="right" >
<a href="Game-Planning.html" title="On Planning a Game"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part2-Intro.html" >Part 2: What we want</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Planning the use of some useful contribs</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -1,897 +0,0 @@
<!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>Making a sittable object &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Part 4: Using what we created" href="../Part4/Beginner-Tutorial-Part4-Intro.html" />
<link rel="prev" title="Turn based Combat System" href="Turn-based-Combat-System.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="../Part4/Beginner-Tutorial-Part4-Intro.html" title="Part 4: Using what we created"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Turn-based-Combat-System.html" title="Turn based Combat System"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Making a sittable object</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">prev lesson</span></a> | <a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">next lesson</span></a></p>
<section class="tex2jax_ignore mathjax_ignore" id="making-a-sittable-object">
<h1>Making a sittable object<a class="headerlink" href="#making-a-sittable-object" title="Permalink to this headline"></a></h1>
<p>In this lesson we will go through how to make a chair you can sit on. Sounds easy, right?
Well it is. But in the process of making the chair we will need to consider the various ways
to do it depending on how we want our game to work.</p>
<p>The goals of this lesson are as follows:</p>
<ul class="simple">
<li><p>We want a new sittable object, a Chair in particular”.</p></li>
<li><p>We want to be able to use a command to sit in the chair.</p></li>
<li><p>Once we are sitting in the chair it should affect us somehow. To demonstrate this well
set a flag “Resting” on the Character sitting in the Chair.</p></li>
<li><p>When you sit down you should not be able to walk to another room without first standing up.</p></li>
<li><p>A character should be able to stand up and move away from the chair.</p></li>
</ul>
<p>There are two main ways to design the commands for sitting and standing up.</p>
<ul class="simple">
<li><p>You can store the commands on the chair so they are only available when a chair is in the room</p></li>
<li><p>You can store the commands on the Character so they are always available and you must always specify
which chair to sit on.</p></li>
</ul>
<p>Both of these are very useful to know about, so in this lesson well try both. But first
we need to handle some basics.</p>
<section id="dont-move-us-when-resting">
<h2>Dont move us when resting<a class="headerlink" href="#dont-move-us-when-resting" title="Permalink to this headline"></a></h2>
<p>When you are sitting in a chair you cant just walk off without first standing up.
This requires a change to our Character typeclass. Open <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="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">at_pre_move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called by self.move_to when trying to move somewhere. If this returns</span>
<span class="sd"> False, the move is immediately cancelled.</span>
<span class="sd"> &quot;&quot;&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">is_resting</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You can&#39;t go anywhere while resting.&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>
</pre></div>
</div>
<p>When moving somewhere, <a class="reference internal" href="../../../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.move_to" title="evennia.objects.objects.DefaultObject.move_to"><span class="xref myst py py-meth">character.move_to</span></a> is called. This in turn
will call <code class="docutils literal notranslate"><span class="pre">character.at_pre_move</span></code>. Here we look for an Attribute <code class="docutils literal notranslate"><span class="pre">is_resting</span></code> (which we will assign below)
to determine if we are stuck on the chair or not.</p>
</section>
<section id="making-the-chair-itself">
<h2>Making the Chair itself<a class="headerlink" href="#making-the-chair-itself" title="Permalink to this headline"></a></h2>
<p>Next we need the Chair itself, or rather a whole family of “things you can sit on” that we will call
<em>sittables</em>. We cant just use a default Object since we want a sittable to contain some custom code. We need
a new, custom Typeclass. Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/sittables.py</span></code> with the following content:</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">DefaultObject</span>
<span class="k">class</span> <span class="nc">Sittable</span><span class="p">(</span><span class="n">DefaultObject</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="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitter</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">do_sit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sitter</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when trying to sit on/in this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> sitter (Object): The one trying to sit down.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">current</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">sitter</span>
<span class="k">if</span> <span class="n">current</span><span class="p">:</span>
<span class="k">if</span> <span class="n">current</span> <span class="o">==</span> <span class="n">sitter</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You are already sitting on </span><span class="si">{self.key}</span><span class="s2">.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You can&#39;t sit on </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> &quot;</span>
<span class="sa">f</span><span class="s2">&quot;- </span><span class="si">{</span><span class="n">current</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is already sitting there!&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">=</span> <span class="n">sitter</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_resting</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You sit on </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">do_stand</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stander</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when trying to stand from this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> stander (Object): The one trying to stand up.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">current</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">sitter</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">stander</span> <span class="o">==</span> <span class="n">current</span><span class="p">:</span>
<span class="n">stander</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 not sitting on </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">.&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">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">stander</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_resting</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">stander</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You stand up from </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Here we have a small Typeclass that handles someone trying to sit on it. It has two methods that we can simply
call from a Command later. We set the <code class="docutils literal notranslate"><span class="pre">is_resting</span></code> Attribute on the one sitting down.</p>
<p>One could imagine that one could have the future <code class="docutils literal notranslate"><span class="pre">sit</span></code> command check if someone is already sitting in the
chair instead. This would work too, but letting the <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> class handle the logic around who can sit on it makes
logical sense.</p>
<p>We let the typeclass handle the logic, and also let it do all the return messaging. This makes it easy to churn out
a bunch of chairs for people to sit on. But its not perfect. The <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> class is general. What if you want to
make an armchair. You sit “in” an armchair rather than “on” it. We <em>could</em> make a child class of <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> named
<code class="docutils literal notranslate"><span class="pre">SittableIn</span></code> that makes this change, but that feels excessive. Instead we will make it so that Sittables can
modify this per-instance:</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">DefaultObject</span>
<span class="k">class</span> <span class="nc">Sittable</span><span class="p">(</span><span class="n">DefaultObject</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="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitter</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># do you sit &quot;on&quot; or &quot;in&quot; this object?</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">adjective</span> <span class="o">=</span> <span class="s2">&quot;on&quot;</span>
<span class="k">def</span> <span class="nf">do_sit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sitter</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when trying to sit on/in this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> sitter (Object): The one trying to sit down.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">adjective</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">adjective</span>
<span class="n">current</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">sitter</span>
<span class="k">if</span> <span class="n">current</span><span class="p">:</span>
<span class="k">if</span> <span class="n">current</span> <span class="o">==</span> <span class="n">sitter</span><span class="p">:</span>
<span class="n">sitter</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 already sitting </span><span class="si">{</span><span class="n">adjective</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">key</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="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;You can&#39;t sit </span><span class="si">{</span><span class="n">adjective</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">key</span><span class="si">}</span><span class="s2"> &quot;</span>
<span class="sa">f</span><span class="s2">&quot;- </span><span class="si">{</span><span class="n">current</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is already sitting there!&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">=</span> <span class="n">sitter</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_resting</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You sit </span><span class="si">{</span><span class="n">adjective</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">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">do_stand</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stander</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when trying to stand from this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> stander (Object): The one trying to stand up.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">current</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">sitter</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">stander</span> <span class="o">==</span> <span class="n">current</span><span class="p">:</span>
<span class="n">stander</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 not sitting </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">adjective</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">key</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="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">stander</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_resting</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">stander</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You stand up from </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>We added a new Attribute <code class="docutils literal notranslate"><span class="pre">adjective</span></code> which will probably usually be <code class="docutils literal notranslate"><span class="pre">in</span></code> or <code class="docutils literal notranslate"><span class="pre">on</span></code> but could also be <code class="docutils literal notranslate"><span class="pre">at</span></code> if you
want to be able to sit <em>at a desk</em> for example. A regular builder would use it like this:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; create/drop armchair : sittables.Sittable
&gt; set armchair/adjective = in
</pre></div>
</div>
<p>This is probably enough. But all those strings are hard-coded. What if we want some more dramatic flair when you
sit down?</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You sit down and a whoopie cushion makes a loud fart noise!
</pre></div>
</div>
<p>For this we need to allow some further customization. Lets let the current strings be defaults that
we can replace.</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">DefaultObject</span>
<span class="k">class</span> <span class="nc">Sittable</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> An object one can sit on</span>
<span class="sd"> Customizable Attributes:</span>
<span class="sd"> adjective: How to sit (on, in, at etc)</span>
<span class="sd"> Return messages (set as Attributes):</span>
<span class="sd"> msg_already_sitting: Already sitting here</span>
<span class="sd"> format tokens {adjective} and {key}</span>
<span class="sd"> msg_other_sitting: Someone else is sitting here.</span>
<span class="sd"> format tokens {adjective}, {key} and {other}</span>
<span class="sd"> msg_sitting_down: Successfully sit down</span>
<span class="sd"> format tokens {adjective}, {key}</span>
<span class="sd"> msg_standing_fail: Fail to stand because not sitting.</span>
<span class="sd"> format tokens {adjective}, {key}</span>
<span class="sd"> msg_standing_up: Successfully stand up</span>
<span class="sd"> format tokens {adjective}, {key}</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitter</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># do you sit &quot;on&quot; or &quot;in&quot; this object?</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">adjective</span> <span class="o">=</span> <span class="s2">&quot;on&quot;</span>
<span class="k">def</span> <span class="nf">do_sit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sitter</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when trying to sit on/in this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> sitter (Object): The one trying to sit down.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">adjective</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">adjective</span>
<span class="n">current</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">sitter</span>
<span class="k">if</span> <span class="n">current</span><span class="p">:</span>
<span class="k">if</span> <span class="n">current</span> <span class="o">==</span> <span class="n">sitter</span><span class="p">:</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">msg_already_sitting</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</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">msg_already_sitting</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">adjective</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">adjective</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sitter</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 already sitting </span><span class="si">{</span><span class="n">adjective</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">key</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="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">msg_other_sitting</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</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">msg_already_sitting</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">other</span><span class="o">=</span><span class="n">current</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">adjective</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">adjective</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You can&#39;t sit </span><span class="si">{</span><span class="n">adjective</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">key</span><span class="si">}</span><span class="s2"> &quot;</span>
<span class="sa">f</span><span class="s2">&quot;- </span><span class="si">{</span><span class="n">current</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is already sitting there!&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">=</span> <span class="n">sitter</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_resting</span> <span class="o">=</span> <span class="kc">True</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">msg_sitting_down</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</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">msg_sitting_down</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">adjective</span><span class="o">=</span><span class="n">adjective</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sitter</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You sit </span><span class="si">{</span><span class="n">adjective</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">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">do_stand</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">stander</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when trying to stand from this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> stander (Object): The one trying to stand up.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">current</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">sitter</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">stander</span> <span class="o">==</span> <span class="n">current</span><span class="p">:</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">msg_standing_fail</span><span class="p">:</span>
<span class="n">stander</span><span class="o">.</span><span class="n">msg</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">msg_standing_fail</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">adjective</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">adjective</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">stander</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 not sitting </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">adjective</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">key</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="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">stander</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_resting</span> <span class="o">=</span> <span class="kc">False</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">msg_standing_up</span><span class="p">:</span>
<span class="n">stander</span><span class="o">.</span><span class="n">msg</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">msg_standing_up</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">adjective</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">adjective</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">stander</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You stand up from </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Here we really went all out with flexibility. If you need this much is up to you.
We added a bunch of optional Attributes to hold alternative versions of all the messages.
There are some things to note:</p>
<ul>
<li><p>We dont actually initiate those Attributes in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>. This is a simple
optimization. The assumption is that <em>most</em> chairs will probably not be this customized.
So initiating a bunch of Attributes to, say, empty strings would be a lot of useless database calls.
The drawback is that the available Attributes become less visible when reading the code. So we add a long
describing docstring to the end to explain all you can use.</p></li>
<li><p>We use <code class="docutils literal notranslate"><span class="pre">.format</span></code> to inject formatting-tokens in the text. The good thing about such formatting
markers is that they are <em>optional</em>. They are there if you want them, but Python will not complain
if you dont include some or any of them. Lets see an example:</p>
<blockquote>
<div><p>reload # if you have new code
create/drop armchair : sittables.Sittable
set armchair/adjective = in
set armchair/msg_sitting_down = As you sit down {adjective} {key}, life feels easier.
set armchair/msg_standing_up = You stand up from {key}. Life resumes.</p>
</div></blockquote>
</li>
</ul>
<p>The <code class="docutils literal notranslate"><span class="pre">{key}</span></code> and <code class="docutils literal notranslate"><span class="pre">{adjective}</span></code> are examples of optional formatting markers. Whenever the message is
returned, the format-tokens within will be replaced with <code class="docutils literal notranslate"><span class="pre">armchair</span></code> and <code class="docutils literal notranslate"><span class="pre">in</span></code> respectively. Should we
rename the chair later, this will show in the messages automatically (since <code class="docutils literal notranslate"><span class="pre">{key}</span></code> will change).</p>
<p>We have no Command to use this chair yet. But we can try it out with <code class="docutils literal notranslate"><span class="pre">py</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.search(&quot;armchair&quot;).do_sit(self)
As you sit down in armchair, life feels easier.
&gt; self.db.resting
True
&gt; py self.search(&quot;armchair&quot;).do_stand(self)
You stand up from armchair. Life resumes
&gt; self.db.resting
False
</pre></div>
</div>
<p>If you follow along and get a result like this, all seems to be working well!</p>
</section>
<section id="command-variant-1-commands-on-the-chair">
<h2>Command variant 1: Commands on the chair<a class="headerlink" href="#command-variant-1-commands-on-the-chair" title="Permalink to this headline"></a></h2>
<p>This way to implement <code class="docutils literal notranslate"><span class="pre">sit</span></code> and <code class="docutils literal notranslate"><span class="pre">stand</span></code> puts new cmdsets on the Sittable itself.
As weve learned before, commands on objects are made available to others in the room.
This makes the command easy but instead adds some complexity in the management of the CmdSet.</p>
<p>This is how it will look if <code class="docutils literal notranslate"><span class="pre">armchair</span></code> is in the room:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; sit
As you sit down in armchair, life feels easier.
</pre></div>
</div>
<p>What happens if there are sittables <code class="docutils literal notranslate"><span class="pre">sofa</span></code> and <code class="docutils literal notranslate"><span class="pre">barstool</span></code> also in the room? Evennia will automatically
handle this for us and allow us to specify which one we want:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; sit
More than one match for &#39;sit&#39; (please narrow target):
sit-1 (armchair)
sit-2 (sofa)
sit-3 (barstool)
&gt; sit-1
As you sit down in armchair, life feels easier.
</pre></div>
</div>
<p>To keep things separate well make a new module <code class="docutils literal notranslate"><span class="pre">mygame/commands/sittables.py</span></code>:</p>
<aside class="sidebar">
<p class="sidebar-title">Separate Commands and Typeclasses?</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>You can organize these things as you like. If you wanted you could put the sit-command + cmdset
together with the `Sittable` typeclass in `mygame/typeclasses/sittables.py`. That has the advantage of
keeping everything related to sitting in one place. But there is also some organizational merit to
keeping all Commands in one place as we do here.
</pre></div>
</div>
</aside>
<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="p">,</span> <span class="n">CmdSet</span>
<span class="k">class</span> <span class="nc">CmdSit</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Sit down.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;sit&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="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">CmdStand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Stand up.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;stand&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="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">do_stand</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">CmdSetSit</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="n">priority</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdSit</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdStand</span><span class="p">)</span>
</pre></div>
</div>
<p>As seen, the commands are nearly trivial. <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> is the object to which we added the cmdset with this
Command (so for example a chair). We just call the <code class="docutils literal notranslate"><span class="pre">do_sit/stand</span></code> on that object and the <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> will
do the rest.</p>
<p>Why that <code class="docutils literal notranslate"><span class="pre">priority</span> <span class="pre">=</span> <span class="pre">1</span></code> on <code class="docutils literal notranslate"><span class="pre">CmdSetSit</span></code>? This makes same-named Commands from this cmdset merge with a bit higher
priority than Commands from the Character-cmdset. Why this is a good idea will become clear shortly.</p>
<p>We also need to make a change to our <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> typeclass. Open <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/sittables.py</span></code>:</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">DefaultObject</span>
<span class="kn">from</span> <span class="nn">commands.sittables</span> <span class="kn">import</span> <span class="n">CmdSetSit</span> <span class="c1"># &lt;- new</span>
<span class="k">class</span> <span class="nc">Sittable</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (docstring)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitter</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># do you sit &quot;on&quot; or &quot;in&quot; this object?</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">adjective</span> <span class="o">=</span> <span class="s2">&quot;on&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add_default</span><span class="p">(</span><span class="n">CmdSetSit</span><span class="p">)</span> <span class="c1"># &lt;- new</span>
</pre></div>
</div>
<p>Any <em>new</em> Sittables will now have your <code class="docutils literal notranslate"><span class="pre">sit</span></code> Command. Your existing <code class="docutils literal notranslate"><span class="pre">armchair</span></code> will not,
since <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> will not re-run for already existing objects. We can update it manually:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; reload
&gt; update armchair
</pre></div>
</div>
<p>We could also update all existing sittables (all on one line):</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py from typeclasses.sittables import Sittable ;
[sittable.at_object_creation() for sittable in Sittable.objects.all()]
</pre></div>
</div>
<blockquote>
<div><p>The above shows an example of a <em>list comprehension</em>. Think of it as an efficient way to construct a new list
all in one line. You can read more about list comprehensions
<a class="reference external" href="https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions">here in the Python docs</a>.</p>
</div></blockquote>
<p>We should now be able to use <code class="docutils literal notranslate"><span class="pre">sit</span></code> while in the room with the armchair.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; sit
As you sit down in armchair, life feels easier.
&gt; stand
You stand up from armchair.
</pre></div>
</div>
<p>One issue with placing the <code class="docutils literal notranslate"><span class="pre">sit</span></code> (or <code class="docutils literal notranslate"><span class="pre">stand</span></code>) Command “on” the chair is that it will not be available when in a
room without a Sittable object:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; sit
Command &#39;sit&#39; is not available. ...
</pre></div>
</div>
<p>This is practical but not so good-looking; it makes it harder for the user to know a <code class="docutils literal notranslate"><span class="pre">sit</span></code> action is at all
possible. Here is a trick for fixing this. Lets add <em>another</em> Command to the bottom
of <code class="docutils literal notranslate"><span class="pre">mygame/commands/sittables.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
<span class="k">class</span> <span class="nc">CmdNoSitStand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Sit down or Stand up</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;sit&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;stand&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="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmdname</span> <span class="o">==</span> <span class="s2">&quot;sit&quot;</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You have nothing to sit on.&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">msg</span><span class="p">(</span><span class="s2">&quot;You are not sitting down.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Here we have a Command that is actually two - it will answer to both <code class="docutils literal notranslate"><span class="pre">sit</span></code> and <code class="docutils literal notranslate"><span class="pre">stand</span></code> since we
added <code class="docutils literal notranslate"><span class="pre">stand</span></code> to its <code class="docutils literal notranslate"><span class="pre">aliases</span></code>. In the command we look at <code class="docutils literal notranslate"><span class="pre">self.cmdname</span></code>, which is the string
<em>actually used</em> to call this command. We use this to return different messages.</p>
<p>We dont need a separate CmdSet for this, instead we will add this
to the default Character cmdset. Open <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">sittables</span>
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (docstring)</span>
<span class="sd"> &quot;&quot;&quot;</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">sittables</span><span class="o">.</span><span class="n">CmdNoSitStand</span><span class="p">)</span>
</pre></div>
</div>
<p>To test well build a new location without any comfy armchairs and go there:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; reload
&gt; tunnel n = kitchen
north
&gt; sit
You have nothing to sit on.
&gt; south
sit
As you sit down in armchair, life feels easier.
</pre></div>
</div>
<p>We now have a fully functioning <code class="docutils literal notranslate"><span class="pre">sit</span></code> action that is contained with the chair itself. When no chair is around, a
default error message is shown.</p>
<p>How does this work? There are two cmdsets at play, both of which have a <code class="docutils literal notranslate"><span class="pre">sit</span></code> Command. As you may remember we
set the chairs cmdset to <code class="docutils literal notranslate"><span class="pre">priority</span> <span class="pre">=</span> <span class="pre">1</span></code>. This is where that matters. The default Character cmdset has a
priority of 0. This means that whenever we enter a room with a Sittable thing, the <code class="docutils literal notranslate"><span class="pre">sit</span></code> command
from <em>its</em> cmdset will take <em>precedence</em> over the Character cmdsets version. So we are actually picking
<em>different</em> <code class="docutils literal notranslate"><span class="pre">sit</span></code> commands depending on circumstance! The user will never be the wiser.</p>
<p>So this handles <code class="docutils literal notranslate"><span class="pre">sit</span></code>. What about <code class="docutils literal notranslate"><span class="pre">stand</span></code>? That will work just fine:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; stand
You stand up from armchair.
&gt; north
&gt; stand
You are not sitting down.
</pre></div>
</div>
<p>We have one remaining problem with <code class="docutils literal notranslate"><span class="pre">stand</span></code> though - what happens when you are sitting down and try to
<code class="docutils literal notranslate"><span class="pre">stand</span></code> in a room with more than one chair:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; stand
More than one match for &#39;stand&#39; (please narrow target):
stand-1 (armchair)
stand-2 (sofa)
stand-3 (barstool)
</pre></div>
</div>
<p>Since all the sittables have the <code class="docutils literal notranslate"><span class="pre">stand</span></code> Command on them, youll get a multi-match error. This <em>works</em> … but
you could pick <em>any</em> of those sittables to “stand up from”. Thats really weird and non-intuitive. With <code class="docutils literal notranslate"><span class="pre">sit</span></code> it
was okay to get a choice - Evennia cant know which chair we intended to sit on. But we know which chair we
sit on so we should only get <em>its</em> <code class="docutils literal notranslate"><span class="pre">stand</span></code> command.</p>
<p>We will fix this with a <code class="docutils literal notranslate"><span class="pre">lock</span></code> and a custom <code class="docutils literal notranslate"><span class="pre">lock</span> <span class="pre">function</span></code>. We want a lock on the <code class="docutils literal notranslate"><span class="pre">stand</span></code> Command that only
makes it available when the caller is actually sitting on the chair the <code class="docutils literal notranslate"><span class="pre">stand</span></code> command is on.</p>
<p>First lets add the lock so we see what we want. Open <code class="docutils literal notranslate"><span class="pre">mygame/commands/sittables.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
<span class="k">class</span> <span class="nc">CmdStand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Stand up.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;stand&quot;</span>
<span class="n">lock</span> <span class="o">=</span> <span class="s2">&quot;cmd:sitsonthis()&quot;</span> <span class="c1"># &lt; this is new</span>
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">do_stand</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>We define a <a class="reference internal" href="../../../Components/Locks.html"><span class="doc std std-doc">Lock</span></a> on the command. The <code class="docutils literal notranslate"><span class="pre">cmd:</span></code> is in what situation Evennia will check
the lock. The <code class="docutils literal notranslate"><span class="pre">cmd</span></code> means that it will check the lock when determining if a user has access to this command or not.
What will be checked is the <code class="docutils literal notranslate"><span class="pre">sitsonthis</span></code> <em>lock function</em> which doesnt exist yet.</p>
<p>Open <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/lockfuncs.py</span></code> to add it!</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">(module lockstring)</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">sitsonthis</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> True if accessing_obj is sitting on/in the accessed_obj.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">accessed_obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sitting</span> <span class="o">==</span> <span class="n">accessing_obj</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>Evennia knows that all functions in <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/lockfuncs</span></code> should be possible to use in a lock definition.
The arguments are required and Evennia will pass all relevant objects to them:</p>
<aside class="sidebar">
<p class="sidebar-title">Lockfuncs</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Evennia provides a large number of default lockfuncs, such as checking permission-levels,
if you are carrying or are inside the accessed object etc. There is no concept of &#39;sitting&#39;
in default Evennia however, so this we need to specify ourselves.
</pre></div>
</div>
</aside>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> is the one trying to access the lock. So us, in this case.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">accessed_obj</span></code> is the entity we are trying to gain a particular type of access to. So the chair.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">args</span></code> is a tuple holding any arguments passed to the lockfunc. Since we use <code class="docutils literal notranslate"><span class="pre">sitsondthis()</span></code> this will
be empty (and if we add anything, it will be ignored).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">kwargs</span></code> is a tuple of keyword arguments passed to the lockfuncs. This will be empty as well in our example.</p></li>
</ul>
<p>If you are superuser, its important that you <code class="docutils literal notranslate"><span class="pre">quell</span></code> yourself before trying this out. This is because the superuser
bypasses all locks - it can never get locked out, but it means it will also not see the effects of a lock like this.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; reload
&gt; quell
&gt; stand
You stand up from armchair
</pre></div>
</div>
<p>None of the other sittables <code class="docutils literal notranslate"><span class="pre">stand</span></code> commands passed the lock and only the one we are actually sitting on did.</p>
<p>Adding a Command to the chair object like this is powerful and a good technique to know. It does come with some
caveats though that one needs to keep in mind.</p>
<p>Well now try another way to add the <code class="docutils literal notranslate"><span class="pre">sit/stand</span></code> commands.</p>
</section>
<section id="command-variant-2-command-on-character">
<h2>Command variant 2: Command on Character<a class="headerlink" href="#command-variant-2-command-on-character" title="Permalink to this headline"></a></h2>
<p>Before we start with this, delete the chairs youve created (<code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">armchair</span></code> etc) and then do the following
changes:</p>
<ul class="simple">
<li><p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/sittables.py</span></code>, comment out the line <code class="docutils literal notranslate"><span class="pre">self.cmdset.add_default(CmdSetSit)</span></code>.</p></li>
<li><p>In <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code>, comment out the line <code class="docutils literal notranslate"><span class="pre">self.add(sittables.CmdNoSitStand)</span></code>.</p></li>
</ul>
<p>This disables the on-object command solution so we can try an alternative. Make sure to <code class="docutils literal notranslate"><span class="pre">reload</span></code> so the
changes are known to Evennia.</p>
<p>In this variation we will put the <code class="docutils literal notranslate"><span class="pre">sit</span></code> and <code class="docutils literal notranslate"><span class="pre">stand</span></code> commands on the <code class="docutils literal notranslate"><span class="pre">Character</span></code> instead of on the chair. This
makes some things easier, but makes the Commands themselves more complex because they will not know which
chair to sit on. We cant just do <code class="docutils literal notranslate"><span class="pre">sit</span></code> anymore. This is how it will work.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; sit &lt;chair&gt;
You sit on chair.
&gt; stand
You stand up from chair.
</pre></div>
</div>
<p>Open <code class="docutils literal notranslate"><span class="pre">mygame/commands.sittables.py</span></code> again. Well add a new sit-command. We name the class <code class="docutils literal notranslate"><span class="pre">CmdSit2</span></code> since
we already have <code class="docutils literal notranslate"><span class="pre">CmdSit</span></code> from the previous example. We put everything at the end of the module to
keep it separate.</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="p">,</span> <span class="n">CmdSet</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">InterruptCommand</span> <span class="c1"># &lt;- this is new</span>
<span class="k">class</span> <span class="nc">CmdSit</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="c1"># ...</span>
<span class="c1"># ...</span>
<span class="c1"># new from here</span>
<span class="k">class</span> <span class="nc">CmdSit2</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Sit down.</span>
<span class="sd"> Usage:</span>
<span class="sd"> sit &lt;sittable&gt;</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;sit&quot;</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sit on what?&quot;</span><span class="p">)</span>
<span class="k">raise</span> <span class="n">InterruptCommand</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="c1"># self.search handles all error messages etc.</span>
<span class="n">sittable</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">sittable</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">sittable</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">AttributeError</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;You can&#39;t sit on that!&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>With this Command-variation we need to search for the sittable. A series of methods on the Command
are run in sequence:</p>
<ol class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">Command.at_pre_command</span></code> - this is not used by default</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Command.parse</span></code> - this should parse the input</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Command.func</span></code> - this should implement the actual Command functionality</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Command.at_post_func</span></code> - this is not used by default</p></li>
</ol>
<p>So if we just <code class="docutils literal notranslate"><span class="pre">return</span></code> in <code class="docutils literal notranslate"><span class="pre">.parse</span></code>, <code class="docutils literal notranslate"><span class="pre">.func</span></code> will still run, which is not what we want. To immediately
abort this sequence we need to <code class="docutils literal notranslate"><span class="pre">raise</span> <span class="pre">InterruptCommand</span></code>.</p>
<aside class="sidebar">
<p class="sidebar-title">Raising exceptions</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Raising an exception allows for immediately interrupting the current program flow. Python
automatically raises error-exceptions when detecting problems with the code. It will be
raised up through the sequence of called code (the &#39;stack&#39;) until it&#39;s either `caught` with
a `try ... except` or reaches the outermost scope where it&#39;ll be logged or displayed.
</pre></div>
</div>
</aside>
<p><code class="docutils literal notranslate"><span class="pre">InterruptCommand</span></code> is an <em>exception</em> that the Command-system catches with the understanding that we want
to do a clean abort. In the <code class="docutils literal notranslate"><span class="pre">.parse</span></code> method we strip any whitespaces from the argument and
sure there actuall <em>is</em> an argument. We abort immediately if there isnt.</p>
<p>We we get to <code class="docutils literal notranslate"><span class="pre">.func</span></code> at all, we know that we have an argument. We search for this and abort if we there was
a problem finding the target.</p>
<blockquote>
<div><p>We could have done <code class="docutils literal notranslate"><span class="pre">raise</span> <span class="pre">InterruptCommand</span></code> in <code class="docutils literal notranslate"><span class="pre">.func</span></code> as well, but <code class="docutils literal notranslate"><span class="pre">return</span></code> is a little shorter to write
and there is no harm done if <code class="docutils literal notranslate"><span class="pre">at_post_func</span></code> runs since its empty.</p>
</div></blockquote>
<p>Next we call the found sittables <code class="docutils literal notranslate"><span class="pre">do_sit</span></code> method. Note that we wrap this call like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># code</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="c1"># stuff to do if AttributeError exception was raised</span>
</pre></div>
</div>
<p>The reason is that <code class="docutils literal notranslate"><span class="pre">caller.search</span></code> has no idea we are looking for a Sittable. The user could have tried
<code class="docutils literal notranslate"><span class="pre">sit</span> <span class="pre">wall</span></code> or <code class="docutils literal notranslate"><span class="pre">sit</span> <span class="pre">sword</span></code>. These dont have a <code class="docutils literal notranslate"><span class="pre">do_sit</span></code> method <em>but we call it anyway and handle the error</em>.
This is a very “Pythonic” thing to do. The concept is often called “leap before you look” or “its easier to
ask for forgiveness than for permission”. If <code class="docutils literal notranslate"><span class="pre">sittable.do_sit</span></code> does not exist, Python will raise an <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code>.
We catch this with <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">except</span> <span class="pre">AttributeError</span></code> and convert it to a proper error message.</p>
<p>While its useful to learn about <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">except</span></code>, there is also a way to leverage Evennia to do this without
<code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">except</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="c1"># ...</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="c1"># self.search handles all error messages etc.</span>
<span class="n">sittable</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">,</span>
<span class="n">typeclass</span><span class="o">=</span><span class="s2">&quot;typeclasses.sittables.Sittable&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">sittable</span><span class="p">:</span>
<span class="k">return</span>
<span class="n">sittable</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
</pre></div>
</div>
<aside class="sidebar">
<p class="sidebar-title">Continuing across multiple lines</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Note how the `.search()` method&#39;s arguments are spread out over multiple
lines. This works for all lists, tuples and other listings and is
a good way to avoid very long and hard-to-read lines.
</pre></div>
</div>
</aside>
<p>The <code class="docutils literal notranslate"><span class="pre">caller.search</span></code> method has an keyword argument <code class="docutils literal notranslate"><span class="pre">typeclass</span></code> that can take either a python-path to a
typeclass, the typeclass itself, or a list of either to widen the allowed options. In this case we know
for sure that the <code class="docutils literal notranslate"><span class="pre">sittable</span></code> we get is actually a <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> class and we can call <code class="docutils literal notranslate"><span class="pre">sittable.do_sit</span></code> without
needing to worry about catching errors.</p>
<p>Lets do the <code class="docutils literal notranslate"><span class="pre">stand</span></code> command while we are at it. Again, since the Command is external to the chair we dont
know which object we are sitting in and have to search for it.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="k">class</span> <span class="nc">CmdStand2</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Stand up.</span>
<span class="sd"> Usage:</span>
<span class="sd"> stand</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;stand&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="c1"># find the thing we are sitting on/in, by finding the object</span>
<span class="c1"># in the current location that as an Attribute &quot;sitter&quot; set</span>
<span class="c1"># to the caller</span>
<span class="n">sittable</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">caller</span><span class="p">,</span>
<span class="n">candidates</span><span class="o">=</span><span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">contents</span><span class="p">,</span>
<span class="n">attribute_name</span><span class="o">=</span><span class="s2">&quot;sitter&quot;</span><span class="p">,</span>
<span class="n">typeclass</span><span class="o">=</span><span class="s2">&quot;typeclasses.sittables.Sittable&quot;</span><span class="p">)</span>
<span class="c1"># if this is None, the error was already reported to user</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">sittable</span><span class="p">:</span>
<span class="k">return</span>
<span class="n">sittable</span><span class="o">.</span><span class="n">do_stand</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span>
</pre></div>
</div>
<p>This forced us to to use the full power of the <code class="docutils literal notranslate"><span class="pre">caller.search</span></code> method. If we wanted to search for something
more complex we would likely need to break out a <a class="reference internal" href="../Part1/Django-queries.html"><span class="doc std std-doc">Django query</span></a> to do it. The key here is that
we know that the object we are looking for is a <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> and that it must have an Attribute named <code class="docutils literal notranslate"><span class="pre">sitter</span></code>
which should be set to us, the one sitting on/in the thing. Once we have that we just call <code class="docutils literal notranslate"><span class="pre">.do_stand</span></code> on it
and let the Typeclass handle the rest.</p>
<p>All that is left now is to make this available to us. This type of Command should be available to us all the time
so we can put it in the default Cmdset<code class="docutils literal notranslate"><span class="pre">on</span> <span class="pre">the</span> <span class="pre">Character.</span> <span class="pre">Open</span></code>mygame/default_cmdsets.py`</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">sittables</span>
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (docstring)</span>
<span class="sd"> &quot;&quot;&quot;</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">sittables</span><span class="o">.</span><span class="n">CmdSit2</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">sittables</span><span class="o">.</span><span class="n">CmdStand2</span><span class="p">)</span>
</pre></div>
</div>
<p>Now lets try it out:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; reload
&gt; create/drop sofa : sittables.Sittable
&gt; sit sofa
You sit down on sofa.
&gt; stand
You stand up from sofa.
</pre></div>
</div>
</section>
<section id="conclusions">
<h2>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline"></a></h2>
<p>In this lesson we accomplished quite a bit:</p>
<ul class="simple">
<li><p>We modified our <code class="docutils literal notranslate"><span class="pre">Character</span></code> class to avoid moving when sitting down.</p></li>
<li><p>We made a new <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> typeclass</p></li>
<li><p>We tried two ways to allow a user to interact with sittables using <code class="docutils literal notranslate"><span class="pre">sit</span></code> and <code class="docutils literal notranslate"><span class="pre">stand</span></code> commands.</p></li>
</ul>
<p>Eagle-eyed readers will notice that the <code class="docutils literal notranslate"><span class="pre">stand</span></code> command sitting “on” the chair (variant 1) would work just fine
together with the <code class="docutils literal notranslate"><span class="pre">sit</span></code> command sitting “on” the Character (variant 2). There is nothing stopping you from
mixing them, or even try a third solution that better fits what you have in mind.</p>
<p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">prev lesson</span></a> | <a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">next lesson</span></a></p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Making a sittable object</a><ul>
<li><a class="reference internal" href="#dont-move-us-when-resting">Dont move us when resting</a></li>
<li><a class="reference internal" href="#making-the-chair-itself">Making the Chair itself</a></li>
<li><a class="reference internal" href="#command-variant-1-commands-on-the-chair">Command variant 1: Commands on the chair</a></li>
<li><a class="reference internal" href="#command-variant-2-command-on-character">Command variant 2: Command on Character</a></li>
<li><a class="reference internal" href="#conclusions">Conclusions</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Turn-based-Combat-System.html"
title="previous chapter">Turn based Combat System</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="../Part4/Beginner-Tutorial-Part4-Intro.html"
title="next chapter">Part 4: Using what we created</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/A-Sittable-Object.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="A-Sittable-Object.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="../Part4/Beginner-Tutorial-Part4-Intro.html" title="Part 4: Using what we created"
>next</a> |</li>
<li class="right" >
<a href="Turn-based-Combat-System.html" title="Turn based Combat System"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Making a sittable object</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,540 @@
<!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>Player Characters &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="In-game Objects and items" href="Beginner-Tutorial-Objects.html" />
<link rel="prev" title="Rules and dice rolling" href="Beginner-Tutorial-Rules.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Objects.html" title="In-game Objects and items"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rules.html" title="Rules and dice rolling"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Player Characters</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="player-characters">
<h1>Player Characters<a class="headerlink" href="#player-characters" title="Permalink to this headline"></a></h1>
<p>In the <a class="reference internal" href="Beginner-Tutorial-Rules.html"><span class="doc std std-doc">previous lesson about rules and dice rolling</span></a> we made some
assumptions about the “Player Character” entity:</p>
<ul class="simple">
<li><p>It should store Abilities on itself as <code class="docutils literal notranslate"><span class="pre">character.strength</span></code>, <code class="docutils literal notranslate"><span class="pre">character.constitution</span></code> etc.</p></li>
<li><p>It should have a <code class="docutils literal notranslate"><span class="pre">.heal(amount)</span></code> method.</p></li>
</ul>
<p>So we have some guidelines of how it should look! A Character is a database entity with values that
should be able to be changed over time. It makes sense to base it off Evennias
<a class="reference internal" href="../../../Components/Typeclasses.html"><span class="doc std std-doc">DefaultCharacter Typeclass</span></a>. The Character class is like a character sheet in a tabletop
RPG, it will hold everything relevant to that PC.</p>
<section id="inheritance-structure">
<h2>Inheritance structure<a class="headerlink" href="#inheritance-structure" title="Permalink to this headline"></a></h2>
<p>Player Characters (PCs) are not the only “living” things in our world. We also have <em>NPCs</em>
(like shopkeepers and other friendlies) as well as <em>monsters</em> (mobs) that can attack us.</p>
<p>In code, there are a few ways we could structure this. If NPCs/monsters were just special cases of PCs,
we could use a class inheritance like this:</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">DefaultCharacter</span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># stuff </span>
<span class="k">class</span> <span class="nc">EvAdventureNPC</span><span class="p">(</span><span class="n">EvAdventureCharacter</span><span class="p">):</span>
<span class="c1"># more stuff </span>
<span class="k">class</span> <span class="nc">EvAdventureMob</span><span class="p">(</span><span class="n">EvAdventureNPC</span><span class="p">):</span>
<span class="c1"># more stuff </span>
</pre></div>
</div>
<p>All code we put on the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class would now be inherited to <code class="docutils literal notranslate"><span class="pre">NPC</span></code> and <code class="docutils literal notranslate"><span class="pre">Mob</span></code> automatically.</p>
<p>However, in <em>Knave</em>, NPCs and particularly monsters are <em>not</em> using the same rules as PCs - they are
simplified to use a Hit-Die (HD) concept. So while still character-like, NPCs should be separate from
PCs like this:</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">DefaultCharacter</span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># stuff </span>
<span class="k">class</span> <span class="nc">EvAdventureNPC</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># separate stuff </span>
<span class="k">class</span> <span class="nc">EvAdventureMob</span><span class="p">(</span><span class="n">EvadventureNPC</span><span class="p">):</span>
<span class="c1"># more separate stuff</span>
</pre></div>
</div>
<p>Nevertheless, there are some things that <em>should</em> be common for all living things:</p>
<ul class="simple">
<li><p>All can take damage.</p></li>
<li><p>All can die.</p></li>
<li><p>All can heal</p></li>
<li><p>All can hold and lose coins</p></li>
<li><p>All can loot their fallen foes.</p></li>
<li><p>All can get looted when defeated.</p></li>
</ul>
<p>We dont want to code this separately for every class but we no longer have a common parent
class to put it on. So instead well use the concept of a <em>mixin</em> class:</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">DefaultCharacter</span>
<span class="k">class</span> <span class="nc">LivingMixin</span><span class="p">:</span>
<span class="c1"># stuff common for all living things</span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># stuff </span>
<span class="k">class</span> <span class="nc">EvAdventureNPC</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># stuff </span>
<span class="k">class</span> <span class="nc">EvAdventureMob</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">EvadventureNPC</span><span class="p">):</span>
<span class="c1"># more stuff</span>
</pre></div>
</div>
<aside class="sidebar">
<p>In <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.characters.html#evennia-contrib-tutorials-evadventure-characters"><span class="std std-ref">evennia/contrib/tutorials/evadventure/characters.py</span></a>
is an example of a character class structure.</p>
</aside>
<p>Above, the <code class="docutils literal notranslate"><span class="pre">LivingMixin</span></code> class cannot work on its own - it just patches the other classes with some
extra functionality all living things should be able to do. This is an example of
<em>multiple inheritance</em>. Its useful to know about, but one should not over-do multiple inheritance
since it can also get confusing to follow the code.</p>
</section>
<section id="living-mixin-class">
<h2>Living mixin class<a class="headerlink" href="#living-mixin-class" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/characters.py</span></code></p>
</div></blockquote>
<p>Lets get some useful common methods all living things should have in our game.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/characters.py </span>
<span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
<span class="k">class</span> <span class="nc">LivingMixin</span><span class="p">:</span>
<span class="c1"># makes it easy for mobs to know to attack PCs</span>
<span class="n">is_pc</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">def</span> <span class="nf">heal</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">hp</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Heal hp amount of health, not allowing to exceed our max hp</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">damage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp</span>
<span class="n">healed</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">damage</span><span class="p">,</span> <span class="n">hp</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">hp</span> <span class="o">+=</span> <span class="n">healed</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You heal for </span><span class="si">{healed}</span><span class="s2"> HP.&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_pay</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;When paying coins, make sure to never detract more than we have&quot;&quot;&quot;</span>
<span class="n">amount</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">amount</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">coins</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">coins</span> <span class="o">-=</span> <span class="n">amount</span>
<span class="k">return</span> <span class="n">amount</span>
<span class="k">def</span> <span class="nf">at_damage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">damage</span><span class="p">,</span> <span class="n">attacker</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called when attacked and taking damage.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">hp</span> <span class="o">-=</span> <span class="n">damage</span>
<span class="k">def</span> <span class="nf">at_defeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called when defeated. By default this means death.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">at_death</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">at_death</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called when this thing dies.&quot;&quot;&quot;</span>
<span class="c1"># this will mean different things for different living things</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">at_do_loot</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looted</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called when looting another entity&quot;&quot;&quot;</span>
<span class="n">looted</span><span class="o">.</span><span class="n">at_looted</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_looted</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looter</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called when looted by another entity&quot;&quot;&quot;</span>
<span class="c1"># default to stealing some coins </span>
<span class="n">max_steal</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d10&quot;</span><span class="p">)</span>
<span class="n">stolen</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">at_pay</span><span class="p">(</span><span class="n">max_steal</span><span class="p">)</span>
<span class="n">looter</span><span class="o">.</span><span class="n">coins</span> <span class="o">+=</span> <span class="n">stolen</span>
</pre></div>
</div>
<p>Most of these are empty since they will behave differently for characters and npcs. But having them
in the mixin means we can expect these methods to be available for all living things.</p>
</section>
<section id="character-class">
<h2>Character class<a class="headerlink" href="#character-class" title="Permalink to this headline"></a></h2>
<p>We will now start making the basic Character class, based on what we need from <em>Knave</em>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/characters.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span><span class="p">,</span> <span class="n">AttributeProperty</span>
<span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
<span class="k">class</span> <span class="nc">LivingMixin</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> A character to use for EvAdventure. </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">is_pc</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">strength</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">dexterity</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">constitution</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">intelligence</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">wisdom</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">charisma</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">hp</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
<span class="n">hp_max</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span>
<span class="n">level</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">xp</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">coins</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_defeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Characters roll on the death table&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">allow_death</span><span class="p">:</span>
<span class="c1"># this allow rooms to have non-lethal battles</span>
<span class="n">dice</span><span class="o">.</span><span class="n">roll_death</span><span class="p">(</span><span class="bp">self</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">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span>
<span class="s2">&quot;$You() $conj(collapse) in a heap, alive but beaten.&quot;</span><span class="p">,</span>
<span class="n">from_obj</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_death</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;We rolled &#39;dead&#39; on the death table.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span>
<span class="s2">&quot;$You() collapse in a heap, embraced by death.&quot;</span><span class="p">,</span>
<span class="n">from_obj</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
<span class="c1"># TODO - go back into chargen to make a new character! </span>
</pre></div>
</div>
<p>We make an assumption about our rooms here - that they have a property <code class="docutils literal notranslate"><span class="pre">.allow_death</span></code>. We need
to make a note to actually add such a property to rooms later!</p>
<p>In our <code class="docutils literal notranslate"><span class="pre">Character</span></code> class we implement all attributes we want to simulate from the <em>Knave</em> ruleset.
The <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> is one way to add an Attribute in a field-like way; these will be accessible
on every character in several ways:</p>
<ul class="simple">
<li><p>As <code class="docutils literal notranslate"><span class="pre">character.strength</span></code></p></li>
<li><p>As <code class="docutils literal notranslate"><span class="pre">character.db.strength</span></code></p></li>
<li><p>As <code class="docutils literal notranslate"><span class="pre">character.attributes.get(&quot;strength&quot;)</span></code></p></li>
</ul>
<p>See <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> for seeing how Attributes work.</p>
<p>Unlike in base <em>Knave</em>, we store <code class="docutils literal notranslate"><span class="pre">coins</span></code> as a separate Attribute rather than as items in the inventory,
this makes it easier to handle barter and trading later.</p>
<p>We implement the Player Character versions of <code class="docutils literal notranslate"><span class="pre">at_defeat</span></code> and <code class="docutils literal notranslate"><span class="pre">at_death</span></code>. We also make use of <code class="docutils literal notranslate"><span class="pre">.heal()</span></code>
from the <code class="docutils literal notranslate"><span class="pre">LivingMixin</span></code> class.</p>
<section id="funcparser-inlines">
<h3>Funcparser inlines<a class="headerlink" href="#funcparser-inlines" title="Permalink to this headline"></a></h3>
<p>This piece of code is worth some more explanation:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span>
<span class="s2">&quot;$You() $conj(collapse) in a heap, alive but beaten.&quot;</span><span class="p">,</span>
<span class="n">from_obj</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
</pre></div>
</div>
<p>Remember that <code class="docutils literal notranslate"><span class="pre">self</span></code> is the Character instance here. So <code class="docutils literal notranslate"><span class="pre">self.location.msg_contents</span></code> means “send a
message to everything inside my current location”. In other words, send a message to everyone
in the same place as the character.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">$You()</span> <span class="pre">$conj(collapse)</span></code> are <a class="reference internal" href="../../../Components/FuncParser.html"><span class="doc std std-doc">FuncParser inlines</span></a>. These are functions that
execute
in the string. The resulting string may look different for different audiences. The <code class="docutils literal notranslate"><span class="pre">$You()</span></code> inline
function will use <code class="docutils literal notranslate"><span class="pre">from_obj</span></code> to figure out who you are and either show your name or You.
The <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> (verb conjugator) will tweak the (English) verb to match.</p>
<ul class="simple">
<li><p>You will see: <code class="docutils literal notranslate"><span class="pre">&quot;You</span> <span class="pre">collapse</span> <span class="pre">in</span> <span class="pre">a</span> <span class="pre">heap,</span> <span class="pre">alive</span> <span class="pre">but</span> <span class="pre">beaten.&quot;</span></code></p></li>
<li><p>Others in the room will see: <code class="docutils literal notranslate"><span class="pre">&quot;Thomas</span> <span class="pre">collapses</span> <span class="pre">in</span> <span class="pre">a</span> <span class="pre">heap,</span> <span class="pre">alive</span> <span class="pre">but</span> <span class="pre">beaten.&quot;</span></code></p></li>
</ul>
<p>Note how <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> chose <code class="docutils literal notranslate"><span class="pre">collapse/collapses</span></code> to make the sentences grammatically correct.</p>
</section>
<section id="backtracking">
<h3>Backtracking<a class="headerlink" href="#backtracking" title="Permalink to this headline"></a></h3>
<p>We make our first use of the <code class="docutils literal notranslate"><span class="pre">rules.dice</span></code> roller to roll on the death table! As you may recall, in the
previous lesson, we didnt know just what to do when rolling dead on this table. Now we know - we
should be calling <code class="docutils literal notranslate"><span class="pre">at_death</span></code> on the character. So lets add that where we had TODOs before:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/rules.py </span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">roll_death</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="n">ability_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d8&quot;</span><span class="p">,</span> <span class="n">death_table</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ability_name</span> <span class="o">==</span> <span class="s2">&quot;dead&quot;</span><span class="p">:</span>
<span class="c1"># kill the character!</span>
<span class="n">character</span><span class="o">.</span><span class="n">at_death</span><span class="p">()</span> <span class="c1"># &lt;------ TODO no more</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">if</span> <span class="n">current_ability</span> <span class="o">&lt;</span> <span class="o">-</span><span class="mi">10</span><span class="p">:</span>
<span class="c1"># kill the character!</span>
<span class="n">character</span><span class="o">.</span><span class="n">at_death</span><span class="p">()</span> <span class="c1"># &lt;------- TODO no more</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># ... </span>
</pre></div>
</div>
</section>
</section>
<section id="connecting-the-character-with-evennia">
<h2>Connecting the Character with Evennia<a class="headerlink" href="#connecting-the-character-with-evennia" title="Permalink to this headline"></a></h2>
<p>You can easily make yourself an <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> in-game by using the
<code class="docutils literal notranslate"><span class="pre">type</span></code> command:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>type self = evadventure.characters.EvAdventureCharacter
</pre></div>
</div>
<p>You can now do <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">self</span></code> to check your type updated.</p>
<p>If you want <em>all</em> new Characters to be of this type you need to tell Evennia about it. Evennia
uses a global setting <code class="docutils literal notranslate"><span class="pre">BASE_CHARACTER_TYPECLASS</span></code> to know which typeclass to use when creating
Characters (when logging in, for example). This defaults to <code class="docutils literal notranslate"><span class="pre">typeclasses.characters.Character</span></code> (that is,
the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>).</p>
<p>There are thus two ways to weave your new Character class into Evennia:</p>
<ol class="simple">
<li><p>Change <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and add <code class="docutils literal notranslate"><span class="pre">BASE_CHARACTER_CLASS</span> <span class="pre">=</span> <span class="pre">&quot;evadventure.characters.EvAdventureCharacter&quot;</span></code>.</p></li>
<li><p>Or, change <code class="docutils literal notranslate"><span class="pre">typeclasses.characters.Character</span></code> to inherit from <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code>.</p></li>
</ol>
<p>You must always reload the server for changes like this to take effect.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>In this tutorial we are making all changes in a folder <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/</span></code>. This means we can isolate
our code but means we need to do some extra steps to tie the character (and other objects) into Evennia.
For your own game it would be just fine to start editing <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> directly
instead.</p>
</div>
</section>
<section id="unit-testing">
<h2>Unit Testing<a class="headerlink" href="#unit-testing" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_characters.py</span></code></p>
</div></blockquote>
<p>For testing, we just need to create a new EvAdventure character and check
that calling the methods on it doesnt error out.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_characters.py </span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span>
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
<span class="kn">from</span> <span class="nn">..characters</span> <span class="kn">import</span> <span class="n">EvAdventureCharacter</span>
<span class="k">class</span> <span class="nc">TestCharacters</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">EvAdventureCharacter</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;testchar&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_heal</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp_max</span> <span class="o">=</span> <span class="mi">8</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># make sure we can&#39;t heal more than max</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">hp</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_at_pay</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">coins</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">at_pay</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">coins</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
<span class="c1"># can&#39;t get more coins than we have </span>
<span class="n">result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">at_pay</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="mi">40</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">coins</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="c1"># tests for other methods ... </span>
</pre></div>
</div>
<p>If you followed the previous lessons, these tests should look familiar. Consider adding
tests for other methods as practice. Refer to previous lessons for details.</p>
<p>For running the tests you do:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> evennia test --settings settings.py .evadventure.tests.test_character
</pre></div>
</div>
</section>
<section id="about-races-and-classes">
<h2>About races and classes<a class="headerlink" href="#about-races-and-classes" title="Permalink to this headline"></a></h2>
<p><em>Knave</em> doesnt have any D&amp;D-style <em>classes</em> (like Thief, Fighter etc). It also does not bother with
<em>races</em> (like dwarves, elves etc). This makes the tutorial shorter, but you may ask yourself how youd
add these functions.</p>
<p>In the framework we have sketched out for <em>Knave</em>, it would be simple - youd add your race/class as
an Attribute on your Character:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/characters.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span><span class="p">,</span> <span class="n">AttributeProperty</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="n">charclass</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="s2">&quot;Fighter&quot;</span><span class="p">)</span>
<span class="n">charrace</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="s2">&quot;Human&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>We use <code class="docutils literal notranslate"><span class="pre">charclass</span></code> rather than <code class="docutils literal notranslate"><span class="pre">class</span></code> here, because <code class="docutils literal notranslate"><span class="pre">class</span></code> is a reserved Python keyword. Naming
<code class="docutils literal notranslate"><span class="pre">race</span></code> as <code class="docutils literal notranslate"><span class="pre">charrace</span></code> thus matches in style.</p>
<p>Wed then need to expand our <a class="reference internal" href="Beginner-Tutorial-Rules.html"><span class="doc std std-doc">rules module</span></a> (and later
<a class="reference internal" href="Beginner-Tutorial-Chargen.html"><span class="doc std std-doc">character generation</span></a> to check and include what these classes mean.</p>
</section>
<section id="summary">
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline"></a></h2>
<p>With the <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> class in place, we have a better understanding of how our PCs will look
like under <em>Knave</em>.</p>
<p>For now, we only have bits and pieces and havent been testing this code in-game. But if you want
you can swap yourself into <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> right now. Log into your game and run
the command</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>type self = evadventure.characters.EvAdventureCharacter
</pre></div>
</div>
<p>If all went well, <code class="docutils literal notranslate"><span class="pre">ex</span> <span class="pre">self</span></code> will now show your typeclass as being <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code>.
Check out your strength with</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py self.strength = 3
</pre></div>
</div>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>When doing <code class="docutils literal notranslate"><span class="pre">ex</span> <span class="pre">self</span></code> you will <em>not</em> see all your Abilities listed yet. Thats because
Attributes added with <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> are not available until they have been accessed at
least once. So once you set (or look at) <code class="docutils literal notranslate"><span class="pre">.strength</span></code> above, <code class="docutils literal notranslate"><span class="pre">strength</span></code> will show in <code class="docutils literal notranslate"><span class="pre">examine</span></code> from
then on.</p>
</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="#">Player Characters</a><ul>
<li><a class="reference internal" href="#inheritance-structure">Inheritance structure</a></li>
<li><a class="reference internal" href="#living-mixin-class">Living mixin class</a></li>
<li><a class="reference internal" href="#character-class">Character class</a><ul>
<li><a class="reference internal" href="#funcparser-inlines">Funcparser inlines</a></li>
<li><a class="reference internal" href="#backtracking">Backtracking</a></li>
</ul>
</li>
<li><a class="reference internal" href="#connecting-the-character-with-evennia">Connecting the Character with Evennia</a></li>
<li><a class="reference internal" href="#unit-testing">Unit Testing</a></li>
<li><a class="reference internal" href="#about-races-and-classes">About races and classes</a></li>
<li><a class="reference internal" href="#summary">Summary</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
title="previous chapter">Rules and dice rolling</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Objects.html"
title="next chapter">In-game Objects and items</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Characters.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Characters.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Objects.html" title="In-game Objects and items"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rules.html" title="Rules and dice rolling"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Player Characters</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,808 @@
<!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>Character Generation &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="In-game Rooms" href="Beginner-Tutorial-Rooms.html" />
<link rel="prev" title="Handling Equipment" href="Beginner-Tutorial-Equipment.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rooms.html" title="In-game Rooms"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Equipment.html" title="Handling Equipment"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Character Generation</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="character-generation">
<h1>Character Generation<a class="headerlink" href="#character-generation" title="Permalink to this headline"></a></h1>
<p>In previous lessons we have established how a character looks. Now we need to give the player a
chance to create one.</p>
<section id="how-it-will-work">
<h2>How it will work<a class="headerlink" href="#how-it-will-work" title="Permalink to this headline"></a></h2>
<p>A fresh Evennia install will automatically create a new Character with the same name as your
Account when you log in. This is quick and simple and mimics older MUD styles. You could picture
doing this, and then customizing the Character in-place.</p>
<p>We will be a little more sophisticated though. We want the user to be able to create a character
using a menu when they log in.</p>
<p>We do this by editing <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and adding the line</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>AUTO_CREATE_CHARACTER_WITH_ACCOUNT = False
</pre></div>
</div>
<p>When doing this, connecting with the game with a new account will land you in “OOC” mode. The
ooc-version of <code class="docutils literal notranslate"><span class="pre">look</span></code> (sitting in the Account cmdset) will show a list of available characters
if you have any. You can also enter <code class="docutils literal notranslate"><span class="pre">charcreate</span></code> to make a new character. The <code class="docutils literal notranslate"><span class="pre">charcreate</span></code> is a
simple command coming with Evennia that just lets you make a new character with a given name and
description. We will later modify that to kick off our chargen. For now well just keep in mind
thats how well start off the menu.</p>
<p>In <em>Knave</em>, most of the character-generation is random. This means this tutorial can be pretty
compact while still showing the basic idea. What we will create is a menu looking like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Silas</span>
<span class="n">STR</span> <span class="o">+</span><span class="mi">1</span>
<span class="n">DEX</span> <span class="o">+</span><span class="mi">2</span>
<span class="n">CON</span> <span class="o">+</span><span class="mi">1</span>
<span class="n">INT</span> <span class="o">+</span><span class="mi">3</span>
<span class="n">WIS</span> <span class="o">+</span><span class="mi">1</span>
<span class="n">CHA</span> <span class="o">+</span><span class="mi">2</span>
<span class="n">You</span> <span class="n">are</span> <span class="n">lanky</span> <span class="k">with</span> <span class="n">a</span> <span class="n">sunken</span> <span class="n">face</span> <span class="ow">and</span> <span class="n">filthy</span> <span class="n">hair</span><span class="p">,</span> <span class="n">breathy</span> <span class="n">speech</span><span class="p">,</span> <span class="ow">and</span> <span class="n">foreign</span> <span class="n">clothing</span><span class="o">.</span>
<span class="n">You</span> <span class="n">were</span> <span class="n">a</span> <span class="n">herbalist</span><span class="p">,</span> <span class="n">but</span> <span class="n">you</span> <span class="n">were</span> <span class="n">pursued</span> <span class="ow">and</span> <span class="n">ended</span> <span class="n">up</span> <span class="n">a</span> <span class="n">knave</span><span class="o">.</span> <span class="n">You</span> <span class="n">are</span> <span class="n">honest</span> <span class="n">but</span> <span class="n">also</span>
<span class="n">suspicious</span><span class="o">.</span> <span class="n">You</span> <span class="n">are</span> <span class="n">of</span> <span class="n">the</span> <span class="n">neutral</span> <span class="n">alignment</span><span class="o">.</span>
<span class="n">Your</span> <span class="n">belongings</span><span class="p">:</span>
<span class="n">Brigandine</span> <span class="n">armor</span><span class="p">,</span> <span class="n">ration</span><span class="p">,</span> <span class="n">ration</span><span class="p">,</span> <span class="n">sword</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span> <span class="n">torch</span><span class="p">,</span>
<span class="n">tinderbox</span><span class="p">,</span> <span class="n">chisel</span><span class="p">,</span> <span class="n">whistle</span>
<span class="o">----------------------------------------------------------------------------------------</span>
<span class="mf">1.</span> <span class="n">Change</span> <span class="n">your</span> <span class="n">name</span>
<span class="mf">2.</span> <span class="n">Swap</span> <span class="n">two</span> <span class="n">of</span> <span class="n">your</span> <span class="n">ability</span> <span class="n">scores</span> <span class="p">(</span><span class="n">once</span><span class="p">)</span>
<span class="mf">3.</span> <span class="n">Accept</span> <span class="ow">and</span> <span class="n">create</span> <span class="n">character</span>
</pre></div>
</div>
<p>If you select 1, you get a new menu node:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Your</span> <span class="n">current</span> <span class="n">name</span> <span class="ow">is</span> <span class="n">Silas</span><span class="o">.</span> <span class="n">Enter</span> <span class="n">a</span> <span class="n">new</span> <span class="n">name</span> <span class="ow">or</span> <span class="n">leave</span> <span class="n">empty</span> <span class="n">to</span> <span class="n">abort</span><span class="o">.</span>
<span class="o">-----------------------------------------------------------------------------------------</span>
</pre></div>
</div>
<p>You can now enter a new name. When pressing return youll get back to the first menu node
showing your character, now with the new name.</p>
<p>If you select 2, you go to another menu node:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Your current abilities:
STR +1
DEX +2
CON +1
INT +3
WIS +1
CHA +2
You can swap the values of two abilities around.
You can only do this once, so choose carefully!
To swap the values of e.g. STR and INT, write &#39;STR INT&#39;. Empty to abort.
------------------------------------------------------------------------------------------
</pre></div>
</div>
<p>If you enter <code class="docutils literal notranslate"><span class="pre">WIS</span> <span class="pre">CHA</span></code> here, WIS will become <code class="docutils literal notranslate"><span class="pre">+2</span></code> and <code class="docutils literal notranslate"><span class="pre">CHA</span></code> <code class="docutils literal notranslate"><span class="pre">+1</span></code>. You will then again go back
to the main node to see your new character, but this time the option to swap will no longer be
available (you can only do it once).</p>
<p>If you finally select the <code class="docutils literal notranslate"><span class="pre">Accept</span> <span class="pre">and</span> <span class="pre">create</span> <span class="pre">character</span></code> option, the character will be created
and youll leave the menu;</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Character was created!
</pre></div>
</div>
</section>
<section id="random-tables">
<h2>Random tables<a class="headerlink" href="#random-tables" title="Permalink to this headline"></a></h2>
<aside class="sidebar">
<p>Full Knave random tables are found in
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.random_tables.html#evennia-contrib-tutorials-evadventure-random-tables"><span class="std std-ref">evennia/contrib/tutorials/evadventure/random_tables.py</span></a>.</p>
</aside>
<blockquote>
<div><p>Make a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/random_tables.py</span></code>.</p>
</div></blockquote>
<p>Since most of <em>Knave</em>s character generation is random we will need to roll on random tables
from the <em>Knave</em> rulebook. While we added the ability to roll on a random table back in the
<a class="reference internal" href="Beginner-Tutorial-Rules.html"><span class="doc std std-doc">Rules Tutorial</span></a>, we havent added the relevant tables yet.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/random_tables.py </span>
<span class="n">chargen_tables</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;physique&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">&quot;athletic&quot;</span><span class="p">,</span> <span class="s2">&quot;brawny&quot;</span><span class="p">,</span> <span class="s2">&quot;corpulent&quot;</span><span class="p">,</span> <span class="s2">&quot;delicate&quot;</span><span class="p">,</span> <span class="s2">&quot;gaunt&quot;</span><span class="p">,</span> <span class="s2">&quot;hulking&quot;</span><span class="p">,</span> <span class="s2">&quot;lanky&quot;</span><span class="p">,</span>
<span class="s2">&quot;ripped&quot;</span><span class="p">,</span> <span class="s2">&quot;rugged&quot;</span><span class="p">,</span> <span class="s2">&quot;scrawny&quot;</span><span class="p">,</span> <span class="s2">&quot;short&quot;</span><span class="p">,</span> <span class="s2">&quot;sinewy&quot;</span><span class="p">,</span> <span class="s2">&quot;slender&quot;</span><span class="p">,</span> <span class="s2">&quot;flabby&quot;</span><span class="p">,</span>
<span class="s2">&quot;statuesque&quot;</span><span class="p">,</span> <span class="s2">&quot;stout&quot;</span><span class="p">,</span> <span class="s2">&quot;tiny&quot;</span><span class="p">,</span> <span class="s2">&quot;towering&quot;</span><span class="p">,</span> <span class="s2">&quot;willowy&quot;</span><span class="p">,</span> <span class="s2">&quot;wiry&quot;</span><span class="p">,</span>
<span class="p">],</span>
<span class="s2">&quot;face&quot;</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">&quot;bloated&quot;</span><span class="p">,</span> <span class="s2">&quot;blunt&quot;</span><span class="p">,</span> <span class="s2">&quot;bony&quot;</span><span class="p">,</span> <span class="c1"># ... </span>
<span class="p">],</span> <span class="c1"># ... </span>
<span class="p">}</span>
</pre></div>
</div>
<p>The tables are just copied from the <em>Knave</em> rules. We group the aspects in a dict
<code class="docutils literal notranslate"><span class="pre">character_generation</span></code> to separate chargen-only tables from other random tables well also
keep in here.</p>
</section>
<section id="storing-state-of-the-menu">
<h2>Storing state of the menu<a class="headerlink" href="#storing-state-of-the-menu" title="Permalink to this headline"></a></h2>
<aside class="sidebar">
<p>There is a full implementation of the chargen in
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.chargen.html#evennia-contrib-tutorials-evadventure-chargen"><span class="std std-ref">evennia/contrib/tutorials/evadventure/chargen.py</span></a>.</p>
</aside>
<blockquote>
<div><p>create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/chargen.py</span></code>.</p>
</div></blockquote>
<p>During character generation we will need an entity to store/retain the changes, like a
temporary character sheet.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
<span class="kn">from</span> <span class="nn">.random_tables</span> <span class="kn">import</span> <span class="n">chargen_tables</span>
<span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
<span class="k">class</span> <span class="nc">TemporaryCharacterSheet</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">_random_ability</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">min</span><span class="p">(</span><span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d6&quot;</span><span class="p">),</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d6&quot;</span><span class="p">),</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d6&quot;</span><span class="p">))</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ability_changes</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># how many times we tried swap abilities</span>
<span class="c1"># name will likely be modified later</span>
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d282&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
<span class="c1"># base attribute values</span>
<span class="bp">self</span><span class="o">.</span><span class="n">strength</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">constitution</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">charisma</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_random_ability</span><span class="p">()</span>
<span class="c1"># physical attributes (only for rp purposes)</span>
<span class="n">physique</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;physique&quot;</span><span class="p">])</span>
<span class="n">face</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;face&quot;</span><span class="p">])</span>
<span class="n">skin</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;skin&quot;</span><span class="p">])</span>
<span class="n">hair</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;hair&quot;</span><span class="p">])</span>
<span class="n">clothing</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;clothing&quot;</span><span class="p">])</span>
<span class="n">speech</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;speech&quot;</span><span class="p">])</span>
<span class="n">virtue</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;virtue&quot;</span><span class="p">])</span>
<span class="n">vice</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;vice&quot;</span><span class="p">])</span>
<span class="n">background</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;background&quot;</span><span class="p">])</span>
<span class="n">misfortune</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;misfortune&quot;</span><span class="p">])</span>
<span class="n">alignment</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;alignment&quot;</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;You are </span><span class="si">{</span><span class="n">physique</span><span class="si">}</span><span class="s2"> with a </span><span class="si">{</span><span class="n">face</span><span class="si">}</span><span class="s2"> face, </span><span class="si">{</span><span class="n">skin</span><span class="si">}</span><span class="s2"> skin, </span><span class="si">{</span><span class="n">hair</span><span class="si">}</span><span class="s2"> hair, </span><span class="si">{</span><span class="n">speech</span><span class="si">}</span><span class="s2"> speech,&quot;</span>
<span class="sa">f</span><span class="s2">&quot; and </span><span class="si">{</span><span class="n">clothing</span><span class="si">}</span><span class="s2"> clothing. You were a </span><span class="si">{</span><span class="n">background</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="si">}</span><span class="s2">, but you were&quot;</span>
<span class="sa">f</span><span class="s2">&quot; </span><span class="si">{</span><span class="n">misfortune</span><span class="si">}</span><span class="s2"> and ended up a knave. You are </span><span class="si">{</span><span class="n">virtue</span><span class="si">}</span><span class="s2"> but also </span><span class="si">{</span><span class="n">vice</span><span class="si">}</span><span class="s2">. You are of the&quot;</span>
<span class="sa">f</span><span class="s2">&quot; </span><span class="si">{</span><span class="n">alignment</span><span class="si">}</span><span class="s2"> alignment.&quot;</span>
<span class="p">)</span>
<span class="c1"># </span>
<span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d8&quot;</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">hp</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span>
<span class="bp">self</span><span class="o">.</span><span class="n">xp</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># random equipment</span>
<span class="bp">self</span><span class="o">.</span><span class="n">armor</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;armor&quot;</span><span class="p">])</span>
<span class="n">_helmet_and_shield</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;helmets and shields&quot;</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">helmet</span> <span class="o">=</span> <span class="s2">&quot;helmet&quot;</span> <span class="k">if</span> <span class="s2">&quot;helmet&quot;</span> <span class="ow">in</span> <span class="n">_helmet_and_shield</span> <span class="k">else</span> <span class="s2">&quot;none&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">shield</span> <span class="o">=</span> <span class="s2">&quot;shield&quot;</span> <span class="k">if</span> <span class="s2">&quot;shield&quot;</span> <span class="ow">in</span> <span class="n">_helmet_and_shield</span> <span class="k">else</span> <span class="s2">&quot;none&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">weapon</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;starting weapon&quot;</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">backpack</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;ration&quot;</span><span class="p">,</span>
<span class="s2">&quot;ration&quot;</span><span class="p">,</span>
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;dungeoning gear&quot;</span><span class="p">]),</span>
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;dungeoning gear&quot;</span><span class="p">]),</span>
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;general gear 1&quot;</span><span class="p">]),</span>
<span class="n">dice</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">,</span> <span class="n">chargen_tables</span><span class="p">[</span><span class="s2">&quot;general gear 2&quot;</span><span class="p">]),</span>
<span class="p">]</span>
</pre></div>
</div>
<p>Here we have followed the <em>Knave</em> rulebook to randomize abilities, description and equipment.
The <code class="docutils literal notranslate"><span class="pre">dice.roll()</span></code> and <code class="docutils literal notranslate"><span class="pre">dice.roll_random_table</span></code> methods now become very useful! Everything here
should be easy to follow.</p>
<p>The main difference from baseline <em>Knave</em> is that we make a table of “starting weapon” (in Knave
you can pick whatever you like).</p>
<p>We also initialize <code class="docutils literal notranslate"><span class="pre">.ability_changes</span> <span class="pre">=</span> <span class="pre">0</span></code>. Knave only allows us to swap the values of two
Abilities <em>once</em>. We will use this to know if it has been done or not.</p>
<section id="showing-the-sheet">
<h3>Showing the sheet<a class="headerlink" href="#showing-the-sheet" title="Permalink to this headline"></a></h3>
<p>Now that we have our temporary character sheet, we should make it easy to visualize it.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
<span class="n">_TEMP_SHEET</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="si">{name}</span><span class="s2"></span>
<span class="s2">STR +</span><span class="si">{strength}</span><span class="s2"></span>
<span class="s2">DEX +</span><span class="si">{dexterity}</span><span class="s2"></span>
<span class="s2">CON +</span><span class="si">{constitution}</span><span class="s2"></span>
<span class="s2">INT +</span><span class="si">{intelligence}</span><span class="s2"></span>
<span class="s2">WIS +</span><span class="si">{wisdom}</span><span class="s2"></span>
<span class="s2">CHA +</span><span class="si">{charisma}</span><span class="s2"></span>
<span class="si">{description}</span><span class="s2"></span>
<span class="s2"> </span>
<span class="s2">Your belongings:</span>
<span class="si">{equipment}</span><span class="s2"></span>
<span class="s2">&quot;&quot;&quot;</span>
<span class="k">class</span> <span class="nc">TemporaryCharacterSheet</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">show_sheet</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">equipment</span> <span class="o">=</span> <span class="p">(</span>
<span class="nb">str</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">armor</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">shield</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpack</span>
<span class="k">if</span> <span class="n">item</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">_TEMP_SHEET</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">strength</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">strength</span><span class="p">,</span>
<span class="n">dexterity</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span><span class="p">,</span>
<span class="n">constitution</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">constitution</span><span class="p">,</span>
<span class="n">intelligence</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span><span class="p">,</span>
<span class="n">wisdom</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span><span class="p">,</span>
<span class="n">charisma</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">charisma</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">desc</span><span class="p">,</span>
<span class="n">equipment</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">equipment</span><span class="p">),</span>
<span class="p">)</span>
</pre></div>
</div>
<p>The new <code class="docutils literal notranslate"><span class="pre">show_sheet</span></code> method collect the data from the temporary sheet and return it in a pretty
form. Making a template string like <code class="docutils literal notranslate"><span class="pre">_TEMP_SHEET</span></code> makes it easier to change things later if you want
to change how things look.</p>
</section>
<section id="apply-character">
<h3>Apply character<a class="headerlink" href="#apply-character" title="Permalink to this headline"></a></h3>
<p>Once we are happy with our character, we need to actually create it with the stats we chose.
This is a bit more involved.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
<span class="c1"># ... </span>
<span class="kn">from</span> <span class="nn">.characters</span> <span class="kn">import</span> <span class="n">EvAdventureCharacter</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span>
<span class="kn">from</span> <span class="nn">evennia.prototypes.spawner</span> <span class="kn">import</span> <span class="n">spawn</span>
<span class="k">class</span> <span class="nc">TemporaryCharacterSheet</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">apply</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># create character object with given abilities</span>
<span class="n">new_character</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span>
<span class="n">EvAdventureCharacter</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">attrs</span><span class="o">=</span><span class="p">(</span>
<span class="p">(</span><span class="s2">&quot;strength&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">strength</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;dexterity&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">dexterity</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;constitution&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">constitution</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;intelligence&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">intelligence</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;wisdom&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;charisma&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">wisdom</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;hp&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;hp_max&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">hp_max</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;desc&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">desc</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="c1"># spawn equipment (will require prototypes created before it works)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">:</span>
<span class="n">weapon</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">weapon</span><span class="p">)</span>
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">weapon</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">shield</span><span class="p">:</span>
<span class="n">shield</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">shield</span><span class="p">)</span>
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">shield</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">armor</span><span class="p">:</span>
<span class="n">armor</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">armor</span><span class="p">)</span>
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">armor</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">:</span>
<span class="n">helmet</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">)</span>
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">move</span><span class="p">(</span><span class="n">helmet</span><span class="p">)</span>
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">backpack</span><span class="p">:</span>
<span class="n">item</span> <span class="o">=</span> <span class="n">spawn</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="n">new_character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">store</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="k">return</span> <span class="n">new_character</span>
</pre></div>
</div>
<p>We use <code class="docutils literal notranslate"><span class="pre">create_object</span></code> to create a new <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code>. We feed it with all relevant data
from the temporary character sheet. This is when these become an actual character.</p>
<aside class="sidebar">
<p>A prototype is basically a <code class="docutils literal notranslate"><span class="pre">dict</span></code> describing how the object should be created. Since
its just a piece of code, it can stored in a Python module and used to quickly <em>spawn</em> (create)
things from those prototypes.</p>
</aside>
<p>Each piece of equipment is an object in in its own right. We will here assume that all game
items are defined as <a class="reference internal" href="../../../Components/Prototypes.html"><span class="doc std std-doc">Prototypes</span></a> keyed to its name, such as “sword”, “brigandine
armor” etc.</p>
<p>We havent actually created those prototypes yet, so for now well need to assume they are there.
Once a piece of equipment has been spawned, we make sure to move it into the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> we
created in the <a class="reference internal" href="Beginner-Tutorial-Equipment.html"><span class="doc std std-doc">Equipment lesson</span></a>.</p>
</section>
</section>
<section id="initializing-evmenu">
<h2>Initializing EvMenu<a class="headerlink" href="#initializing-evmenu" title="Permalink to this headline"></a></h2>
<p>Evennia comes with a full menu-generation system based on <a class="reference internal" href="../../../Components/Command-Sets.html"><span class="doc std std-doc">Command sets</span></a>, called
<a class="reference internal" href="../../../Components/EvMenu.html"><span class="doc std std-doc">EvMenu</span></a>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">EvMenu</span>
<span class="c1"># ...</span>
<span class="c1"># chargen menu </span>
<span class="c1"># this goes to the bottom of the module</span>
<span class="k">def</span> <span class="nf">start_chargen</span><span class="p">(</span><span class="n">caller</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is a start point for spinning up the chargen from a command later.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">menutree</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># TODO!</span>
<span class="c1"># this generates all random components of the character</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">TemporaryCharacterSheet</span><span class="p">()</span>
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menutree</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="n">tmp_character</span><span class="o">=</span><span class="n">tmp_character</span><span class="p">)</span>
</pre></div>
</div>
<p>This first function is what we will call from elsewhere (for example from a custom <code class="docutils literal notranslate"><span class="pre">charcreate</span></code>
command) to kick the menu into gear.</p>
<p>It takes the <code class="docutils literal notranslate"><span class="pre">caller</span></code> (the one to want to start the menu) and a <code class="docutils literal notranslate"><span class="pre">session</span></code> argument. The latter will help
track just which client-connection we are using (depending on Evennia settings, you could be
connecting with multiple clients).</p>
<p>We create a <code class="docutils literal notranslate"><span class="pre">TemporaryCharacterSheet</span></code> and call <code class="docutils literal notranslate"><span class="pre">.generate()</span></code> to make a random character. We then
feed all this into <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>.</p>
<p>The moment this happens, the user will be in the menu, there are no further steps needed.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">menutree</span></code> is what well create next. It describes which menu nodes are available to jump
between.</p>
</section>
<section id="main-node-choosing-what-to-do">
<h2>Main Node: Choosing what to do<a class="headerlink" href="#main-node-choosing-what-to-do" title="Permalink to this headline"></a></h2>
<p>This is the first menu node. It will act as a central hub, from which one can choose different
actions.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
<span class="c1"># ...</span>
<span class="c1"># at the end of the module, but before the `start_chargen` function</span>
<span class="k">def</span> <span class="nf">node_chargen</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;tmp_character&quot;</span><span class="p">]</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">tmp_character</span><span class="o">.</span><span class="n">show_sheet</span><span class="p">()</span>
<span class="n">options</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span>
<span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Change your name&quot;</span><span class="p">,</span>
<span class="s2">&quot;goto&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;node_change_name&quot;</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="k">if</span> <span class="n">tmp_character</span><span class="o">.</span><span class="n">ability_changes</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">options</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Swap two of your ability scores (once)&quot;</span><span class="p">,</span>
<span class="s2">&quot;goto&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;node_swap_abilities&quot;</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">),</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="n">options</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Accept and create character&quot;</span><span class="p">,</span>
<span class="s2">&quot;goto&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;node_apply_character&quot;</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</span>
<span class="p">},</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>A lot to unpack here! In Evennia, its convention to name your node-functions <code class="docutils literal notranslate"><span class="pre">node_*</span></code>. While
not required, it helps you track what is a node and not.</p>
<p>Every menu-node, should accept <code class="docutils literal notranslate"><span class="pre">caller,</span> <span class="pre">raw_string,</span> <span class="pre">**kwargs</span></code> as arguments. Here <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the
<code class="docutils literal notranslate"><span class="pre">caller</span></code> you passed into the <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> call. <code class="docutils literal notranslate"><span class="pre">raw_string</span></code> is the input given by the user in order
to <em>get to this node</em>, so currently empty. The <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> are all extra keyword arguments passed
into <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>. They can also be passed between nodes. In this case, we passed the
keyword <code class="docutils literal notranslate"><span class="pre">tmp_character</span></code> to <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>. We now have the temporary character sheet available in the
node!</p>
<p>An <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> node must always return two things - <code class="docutils literal notranslate"><span class="pre">text</span></code> and <code class="docutils literal notranslate"><span class="pre">options</span></code>. The <code class="docutils literal notranslate"><span class="pre">text</span></code> is what will
show to the user when looking at this node. The <code class="docutils literal notranslate"><span class="pre">options</span></code> are, well, what options should be
presented to move on from here to some other place.</p>
<p>For the text, we simply get a pretty-print of the temporary character sheet. A single option is
defined as a <code class="docutils literal notranslate"><span class="pre">dict</span></code> like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="o">.</span> <span class="s2">&quot;alias1&quot;</span><span class="p">,</span> <span class="s2">&quot;alias2&quot;</span><span class="p">,</span> <span class="o">...</span><span class="p">),</span> <span class="c1"># if skipped, auto-show a number</span>
<span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;text to describe what happens when selecting option&quot;</span><span class="p">,</span><span class="o">.</span>
<span class="s2">&quot;goto&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;name of node or a callable&quot;</span><span class="p">,</span> <span class="n">kwargs_to_pass_into_next_node_or_callable</span><span class="p">)</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Multiple option-dicts are returned in a list or tuple. The <code class="docutils literal notranslate"><span class="pre">goto</span></code> option-key is important to
understand. The job of this is to either point directly to another node (by giving its name), or
by pointing to a Python callable (like a function) <em>that then returns that name</em>. You can also
pass kwargs (as a dict). This will be made available as <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> in the callable or next node.</p>
<p>While an option can have a <code class="docutils literal notranslate"><span class="pre">key</span></code>, you can also skip it to just get a running number.</p>
<p>In our <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> node, we point to three nodes by name: <code class="docutils literal notranslate"><span class="pre">node_change_name</span></code>,
<code class="docutils literal notranslate"><span class="pre">node_swap_abilities</span></code>, and <code class="docutils literal notranslate"><span class="pre">node_apply_character</span></code>. We also make sure to pass along <code class="docutils literal notranslate"><span class="pre">kwargs</span></code>
to each node, since that contains our temporary character sheet.</p>
<p>The middle of these options only appear if we havent already switched two abilities around - to
know this, we check the <code class="docutils literal notranslate"><span class="pre">.ability_changes</span></code> property to make sure its still 0.</p>
</section>
<section id="node-changing-your-name">
<h2>Node: Changing your name<a class="headerlink" href="#node-changing-your-name" title="Permalink to this headline"></a></h2>
<p>This is where you end up if you opted to change your name in <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py</span>
<span class="c1"># ...</span>
<span class="c1"># after previous node </span>
<span class="k">def</span> <span class="nf">_update_name</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Used by node_change_name below to check what user </span>
<span class="sd"> entered and update the name if appropriate.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">raw_string</span><span class="p">:</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;tmp_character&quot;</span><span class="p">]</span>
<span class="n">tmp_character</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">raw_string</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span>
<span class="k">return</span> <span class="s2">&quot;node_chargen&quot;</span><span class="p">,</span> <span class="n">kwargs</span>
<span class="k">def</span> <span class="nf">node_change_name</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Change the random name of the character.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;tmp_character&quot;</span><span class="p">]</span>
<span class="n">text</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;Your current name is |w</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">|n. &quot;</span>
<span class="s2">&quot;Enter a new name or leave empty to abort.&quot;</span>
<span class="p">)</span>
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;_default&quot;</span><span class="p">,</span>
<span class="s2">&quot;goto&quot;</span><span class="p">:</span> <span class="p">(</span><span class="n">_update_name</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
</pre></div>
</div>
<p>There are two functions here - the menu node itself (<code class="docutils literal notranslate"><span class="pre">node_change_name</span></code>) and a
helper <em>goto_function</em> (<code class="docutils literal notranslate"><span class="pre">_update_name</span></code>) to handle the users input.</p>
<p>For the (single) option, we use a special <code class="docutils literal notranslate"><span class="pre">key</span></code> named <code class="docutils literal notranslate"><span class="pre">_default</span></code>. This makes this option
a catch-all: If the user enters something that does not match any other option, this is
the option that will be used.
Since we have no other options here, we will always use this option no matter what the user enters.</p>
<p>Also note that the <code class="docutils literal notranslate"><span class="pre">goto</span></code> part of the option points to the <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> callable rather than to
the name of a node. Its important we keep passing <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> along to it!</p>
<p>When a user writes anything at this node, the <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> callable will be called. This has
the same arguments as a node, but it is <em>not</em> a node - we will only use it to <em>figure out</em> which
node to go to next.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> we now have a use for the <code class="docutils literal notranslate"><span class="pre">raw_string</span></code> argument - this is what was written by
the user on the previous node, remember? This is now either an empty string (meaning to ignore
it) or the new name of the character.</p>
<p>A goto-function like <code class="docutils literal notranslate"><span class="pre">_update_name</span></code> must return the name of the next node to use. It can also
optionally return the <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> to pass into that node - we want to always do this, so we dont
loose our temporary character sheet. Here we will always go back to the <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code>.</p>
<blockquote>
<div><p>Hint: If returning <code class="docutils literal notranslate"><span class="pre">None</span></code> from a goto-callable, you will always return to the last node you
were at.</p>
</div></blockquote>
</section>
<section id="node-swapping-abilities-around">
<h2>Node: Swapping Abilities around<a class="headerlink" href="#node-swapping-abilities-around" title="Permalink to this headline"></a></h2>
<p>You get here by selecting the second option from the <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> node.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/chargen.py </span>
<span class="c1"># ...</span>
<span class="c1"># after previous node </span>
<span class="n">_ABILITIES</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;STR&quot;</span><span class="p">:</span> <span class="s2">&quot;strength&quot;</span><span class="p">,</span>
<span class="s2">&quot;DEX&quot;</span><span class="p">:</span> <span class="s2">&quot;dexterity&quot;</span><span class="p">,</span>
<span class="s2">&quot;CON&quot;</span><span class="p">:</span> <span class="s2">&quot;constitution&quot;</span><span class="p">,</span>
<span class="s2">&quot;INT&quot;</span><span class="p">:</span> <span class="s2">&quot;intelligence&quot;</span><span class="p">,</span>
<span class="s2">&quot;WIS&quot;</span><span class="p">:</span> <span class="s2">&quot;wisdom&quot;</span><span class="p">,</span>
<span class="s2">&quot;CHA&quot;</span><span class="p">:</span> <span class="s2">&quot;charisma&quot;</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">def</span> <span class="nf">_swap_abilities</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Used by node_swap_abilities to parse the user&#39;s input and swap ability</span>
<span class="sd"> values.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">raw_string</span><span class="p">:</span>
<span class="n">abi1</span><span class="p">,</span> <span class="o">*</span><span class="n">abi2</span> <span class="o">=</span> <span class="n">raw_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">abi2</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;That doesn&#39;t look right.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="n">kwargs</span>
<span class="n">abi2</span> <span class="o">=</span> <span class="n">abi2</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">abi1</span><span class="p">,</span> <span class="n">abi2</span> <span class="o">=</span> <span class="n">abi1</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="n">abi2</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">if</span> <span class="n">abi1</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_ABILITIES</span> <span class="ow">or</span> <span class="n">abi2</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">_ABILITIES</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;Not a familiar set of abilites.&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="n">kwargs</span>
<span class="c1"># looks okay = swap values. We need to convert STR to strength etc</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;tmp_character&quot;</span><span class="p">]</span>
<span class="n">abi1</span> <span class="o">=</span> <span class="n">_ABILITIES</span><span class="p">[</span><span class="n">abi1</span><span class="p">]</span>
<span class="n">abi2</span> <span class="o">=</span> <span class="n">_ABILITIES</span><span class="p">[</span><span class="n">abi2</span><span class="p">]</span>
<span class="n">abival1</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi1</span><span class="p">)</span>
<span class="n">abival2</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi2</span><span class="p">)</span>
<span class="nb">setattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi1</span><span class="p">,</span> <span class="n">abival2</span><span class="p">)</span>
<span class="nb">setattr</span><span class="p">(</span><span class="n">tmp_character</span><span class="p">,</span> <span class="n">abi2</span><span class="p">,</span> <span class="n">abival1</span><span class="p">)</span>
<span class="n">tmp_character</span><span class="o">.</span><span class="n">ability_changes</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="s2">&quot;node_chargen&quot;</span><span class="p">,</span> <span class="n">kwargs</span>
<span class="k">def</span> <span class="nf">node_swap_abilities</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> One is allowed to swap the values of two abilities around, once.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;tmp_character&quot;</span><span class="p">]</span>
<span class="n">text</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2">Your current abilities:</span>
<span class="s2">STR +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">strength</span><span class="si">}</span><span class="s2"></span>
<span class="s2">DEX +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">dexterity</span><span class="si">}</span><span class="s2"></span>
<span class="s2">CON +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">constitution</span><span class="si">}</span><span class="s2"></span>
<span class="s2">INT +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">intelligence</span><span class="si">}</span><span class="s2"></span>
<span class="s2">WIS +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">wisdom</span><span class="si">}</span><span class="s2"></span>
<span class="s2">CHA +</span><span class="si">{</span><span class="n">tmp_character</span><span class="o">.</span><span class="n">charisma</span><span class="si">}</span><span class="s2"></span>
<span class="s2">You can swap the values of two abilities around.</span>
<span class="s2">You can only do this once, so choose carefully!</span>
<span class="s2">To swap the values of e.g. STR and INT, write |wSTR INT|n. Empty to abort.</span>
<span class="s2">&quot;&quot;&quot;</span>
<span class="n">options</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;_default&quot;</span><span class="p">,</span> <span class="s2">&quot;goto&quot;</span><span class="p">:</span> <span class="p">(</span><span class="n">_swap_abilities</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">)}</span>
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
</pre></div>
</div>
<p>This is more code, but the logic is the same - we have a node (<code class="docutils literal notranslate"><span class="pre">node_swap_abilities</span></code>) and
and a goto-callable helper (<code class="docutils literal notranslate"><span class="pre">_swap_abilities</span></code>). We catch everything the user writes on the
node (such as <code class="docutils literal notranslate"><span class="pre">WIS</span> <span class="pre">CON</span></code>) and feed it into the helper.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">_swap_abilities</span></code>, we need to analyze the <code class="docutils literal notranslate"><span class="pre">raw_string</span></code> from the user to see what they
want to do.</p>
<p>Most code in the helper is validating the user didnt enter nonsense. If they did,
we use <code class="docutils literal notranslate"><span class="pre">caller.msg()</span></code> to tell them and then return <code class="docutils literal notranslate"><span class="pre">None,</span> <span class="pre">kwargs</span></code>, which re-runs the same node (the
name-selection) all over again.</p>
<p>Since we want users to be able to write “CON” instead of the longer “constitution”, we need a
mapping <code class="docutils literal notranslate"><span class="pre">_ABILITIES</span></code> to easily convert between the two (its stored as <code class="docutils literal notranslate"><span class="pre">consitution</span></code> on the
temporary character sheet). Once we know which abilities they want to swap, we do so and tick up
the <code class="docutils literal notranslate"><span class="pre">.ability_changes</span></code> counter. This means this option will no longer be available from the main
node.</p>
<p>Finally, we return to <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> again.</p>
</section>
<section id="node-creating-the-character">
<h2>Node: Creating the Character<a class="headerlink" href="#node-creating-the-character" title="Permalink to this headline"></a></h2>
<p>We get here from the main node by opting to finish chargen.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">node_apply_character</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> End chargen and create the character. We will also puppet it.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;tmp_character&quot;</span><span class="p">]</span>
<span class="n">new_character</span> <span class="o">=</span> <span class="n">tmp_character</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span>
<span class="n">caller</span><span class="o">.</span><span class="n">account</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">_playable_characters</span> <span class="o">=</span> <span class="p">[</span><span class="n">new_character</span><span class="p">]</span>
<span class="n">text</span> <span class="o">=</span> <span class="s2">&quot;Character created!&quot;</span>
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="kc">None</span>
</pre></div>
</div>
<p>When entering the node, we will take the Temporary character sheet and use its <code class="docutils literal notranslate"><span class="pre">.appy</span></code> method to
create a new Character with all equipment.</p>
<p>This is what is called an <em>end node</em>, because it returns <code class="docutils literal notranslate"><span class="pre">None</span></code> instead of options. After this,
the menu will exit. We will be back to the default character selection screen. The characters
found on that screen are the ones listed in the <code class="docutils literal notranslate"><span class="pre">_playable_characters</span></code> Attribute, so we need to
also the new character to it.</p>
</section>
<section id="tying-the-nodes-together">
<h2>Tying the nodes together<a class="headerlink" href="#tying-the-nodes-together" title="Permalink to this headline"></a></h2>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">start_chargen</span><span class="p">(</span><span class="n">caller</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="sd">&quot;&quot;&quot;</span>
<span class="sd">This is a start point for spinning up the chargen from a command later.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">menutree</span> <span class="o">=</span> <span class="p">{</span> <span class="c1"># &lt;----- can now add this!</span>
<span class="s2">&quot;node_chargen&quot;</span><span class="p">:</span> <span class="n">node_chargen</span><span class="p">,</span>
<span class="s2">&quot;node_change_name&quot;</span><span class="p">:</span> <span class="n">node_change_name</span><span class="p">,</span>
<span class="s2">&quot;node_swap_abilities&quot;</span><span class="p">:</span> <span class="n">node_swap_abilities</span><span class="p">,</span>
<span class="s2">&quot;node_apply_character&quot;</span><span class="p">:</span> <span class="n">node_apply_character</span>
<span class="p">}</span>
<span class="c1"># this generates all random components of the character</span>
<span class="n">tmp_character</span> <span class="o">=</span> <span class="n">TemporaryCharacterSheet</span><span class="p">()</span>
<span class="n">tmp_character</span><span class="o">.</span><span class="n">generate</span><span class="p">()</span>
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menutree</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="n">startnode</span><span class="o">=</span><span class="s2">&quot;node_chargen&quot;</span><span class="p">,</span> <span class="c1"># &lt;----- </span>
<span class="n">tmp_character</span><span class="o">=</span><span class="n">tmp_character</span><span class="p">)</span>
</pre></div>
</div>
<p>Now that we have all the nodes, we add them to the <code class="docutils literal notranslate"><span class="pre">menutree</span></code> we left empty before. We only add
the nodes, <em>not</em> the goto-helpers! The keys we set in the <code class="docutils literal notranslate"><span class="pre">menutree</span></code> dictionary are the names we
should use to point to nodes from inside the menu (and we did).</p>
<p>We also add a keyword argument <code class="docutils literal notranslate"><span class="pre">startnode</span></code> pointing to the <code class="docutils literal notranslate"><span class="pre">node_chargen</span></code> node. This tells EvMenu
to first jump into that node when the menu is starting up.</p>
</section>
<section id="conclusions">
<h2>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline"></a></h2>
<p>This lesson taught us how to use <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> to make an interactive character generator. In an RPG
more complex than <em>Knave</em>, the menu would be bigger and more intricate, but the same principles
apply.</p>
<p>Together with the previous lessons we have now fished most of the basics around player
characters - how they store their stats, handle their equipment and how to create them.</p>
<p>In the next lesson well address how EvAdventure <em>Rooms</em> work.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Character Generation</a><ul>
<li><a class="reference internal" href="#how-it-will-work">How it will work</a></li>
<li><a class="reference internal" href="#random-tables">Random tables</a></li>
<li><a class="reference internal" href="#storing-state-of-the-menu">Storing state of the menu</a><ul>
<li><a class="reference internal" href="#showing-the-sheet">Showing the sheet</a></li>
<li><a class="reference internal" href="#apply-character">Apply character</a></li>
</ul>
</li>
<li><a class="reference internal" href="#initializing-evmenu">Initializing EvMenu</a></li>
<li><a class="reference internal" href="#main-node-choosing-what-to-do">Main Node: Choosing what to do</a></li>
<li><a class="reference internal" href="#node-changing-your-name">Node: Changing your name</a></li>
<li><a class="reference internal" href="#node-swapping-abilities-around">Node: Swapping Abilities around</a></li>
<li><a class="reference internal" href="#node-creating-the-character">Node: Creating the Character</a></li>
<li><a class="reference internal" href="#tying-the-nodes-together">Tying the nodes together</a></li>
<li><a class="reference internal" href="#conclusions">Conclusions</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Equipment.html"
title="previous chapter">Handling Equipment</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Rooms.html"
title="next chapter">In-game Rooms</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Chargen.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Chargen.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rooms.html" title="In-game Rooms"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Equipment.html" title="Handling Equipment"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Character Generation</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,141 @@
<!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>In-game Commands &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Part 4: Using what we created" href="../Part4/Beginner-Tutorial-Part4-Intro.html" />
<link rel="prev" title="Dynamically generated Dungeon" href="Beginner-Tutorial-Dungeon.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="../Part4/Beginner-Tutorial-Part4-Intro.html" title="Part 4: Using what we created"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Dungeon.html" title="Dynamically generated Dungeon"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Commands</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="in-game-commands">
<h1>In-game Commands<a class="headerlink" href="#in-game-commands" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This part of the Beginner tutorial is still being developed.</p>
</div>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Dungeon.html"
title="previous chapter">Dynamically generated Dungeon</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="../Part4/Beginner-Tutorial-Part4-Intro.html"
title="next chapter">Part 4: Using what we created</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Commands.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="../Part4/Beginner-Tutorial-Part4-Intro.html" title="Part 4: Using what we created"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Dungeon.html" title="Dynamically generated Dungeon"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Commands</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,141 @@
<!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>Dynamically generated Dungeon &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="In-game Commands" href="Beginner-Tutorial-Commands.html" />
<link rel="prev" title="In-game Shops" href="Beginner-Tutorial-Shops.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Commands.html" title="In-game Commands"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Shops.html" title="In-game Shops"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Dynamically generated Dungeon</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="dynamically-generated-dungeon">
<h1>Dynamically generated Dungeon<a class="headerlink" href="#dynamically-generated-dungeon" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This part of the Beginner tutorial is still being developed.</p>
</div>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Shops.html"
title="previous chapter">In-game Shops</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Commands.html"
title="next chapter">In-game Commands</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Dungeon.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Dungeon.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Commands.html" title="In-game Commands"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Shops.html" title="In-game Shops"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Dynamically generated Dungeon</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,708 @@
<!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>Handling Equipment &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Character Generation" href="Beginner-Tutorial-Chargen.html" />
<link rel="prev" title="In-game Objects and items" href="Beginner-Tutorial-Objects.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Chargen.html" title="Character Generation"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Objects.html" title="In-game Objects and items"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Handling Equipment</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="handling-equipment">
<h1>Handling Equipment<a class="headerlink" href="#handling-equipment" title="Permalink to this headline"></a></h1>
<p>In <em>Knave</em>, you have a certain number of inventory “slots”. The amount of slots is given by <code class="docutils literal notranslate"><span class="pre">CON</span> <span class="pre">+</span> <span class="pre">10</span></code>.
All items (except coins) have a <code class="docutils literal notranslate"><span class="pre">size</span></code>, indicating how many slots it uses. You cant carry more items
than you have slot-space for. Also items wielded or worn count towards the slots.</p>
<p>We still need to track what the character is using however: What weapon they have readied affects the damage
they can do. The shield, helmet and armor they use affects their defense.</p>
<p>We have already set up the possible wear/wield locations when we defined our Objects
<a class="reference internal" href="Beginner-Tutorial-Objects.html"><span class="doc std std-doc">in the previous lesson</span></a>. This is what we have in <code class="docutils literal notranslate"><span class="pre">enums.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
<span class="c1"># ...</span>
<span class="k">class</span> <span class="nc">WieldLocation</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">BACKPACK</span> <span class="o">=</span> <span class="s2">&quot;backpack&quot;</span>
<span class="n">WEAPON_HAND</span> <span class="o">=</span> <span class="s2">&quot;weapon_hand&quot;</span>
<span class="n">SHIELD_HAND</span> <span class="o">=</span> <span class="s2">&quot;shield_hand&quot;</span>
<span class="n">TWO_HANDS</span> <span class="o">=</span> <span class="s2">&quot;two_handed_weapons&quot;</span>
<span class="n">BODY</span> <span class="o">=</span> <span class="s2">&quot;body&quot;</span> <span class="c1"># armor</span>
<span class="n">HEAD</span> <span class="o">=</span> <span class="s2">&quot;head&quot;</span> <span class="c1"># helmets</span>
</pre></div>
</div>
<p>Basically, all the weapon/armor locations are exclusive - you can only have one item in each (or none).
The BACKPACK is special - it contains any number of items (up to the maximum slot usage).</p>
<section id="equipmenthandler-that-saves">
<h2>EquipmentHandler that saves<a class="headerlink" href="#equipmenthandler-that-saves" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/equipment.py</span></code>.</p>
</div></blockquote>
<aside class="sidebar">
<p>If you want to understand more about behind how Evennia uses handlers, there is a
<a class="reference internal" href="../../Tutorial-Persistent-Handler.html"><span class="doc std std-doc">dedicated tutorial</span></a> talking about the principle.</p>
</aside>
<p>In default Evennia, everything you pick up will end up “inside” your character object (that is, have
you as its <code class="docutils literal notranslate"><span class="pre">.location</span></code>). This is called your <em>inventory</em> and has no limit. We will keep moving items into us
when we pick them up, but we will add more functionality using an <em>Equipment handler</em>.</p>
<p>A handler is (for our purposes) an object that sits “on” another entity, containing functionality
for doing one specific thing (managing equipment, in our case).</p>
<p>This is the start of our handler:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/equipment.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span>
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
<span class="n">save_attribute</span> <span class="o">=</span> <span class="s2">&quot;inventory_slots&quot;</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
<span class="c1"># here obj is the character we store the handler on </span>
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">obj</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_load</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">_load</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Load our data from an Attribute on `self.obj`&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">save_attribute</span><span class="p">,</span>
<span class="n">category</span><span class="o">=</span><span class="s2">&quot;inventory&quot;</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="p">{</span>
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
<span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span> <span class="p">[]</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">_save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Save our data back to the same Attribute&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">save_attribute</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;inventory&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This is a compact and functional little handler. Before analyzing how it works, this is how
we will add it to the Character:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/characters.py</span>
<span class="c1"># ... </span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">lazy_property</span>
<span class="kn">from</span> <span class="nn">.equipment</span> <span class="kn">import</span> <span class="n">EquipmentHandler</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="nd">@lazy_property</span>
<span class="k">def</span> <span class="nf">equipment</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="n">EquipmentHandler</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
</pre></div>
</div>
<p>After reloading the server, the equipment-handler will now be accessible on character-instances as</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>character.equipment
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">&#64;lazy_property</span></code> works such that it will not load the handler until someone actually tries to
fetch it with <code class="docutils literal notranslate"><span class="pre">character.equipment</span></code>. When that
happens, we start up the handler and feed it <code class="docutils literal notranslate"><span class="pre">self</span></code> (the <code class="docutils literal notranslate"><span class="pre">Character</span></code> instance itself). This is what
enters <code class="docutils literal notranslate"><span class="pre">__init__</span></code> as <code class="docutils literal notranslate"><span class="pre">.obj</span></code> in the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> code above.</p>
<p>So we now have a handler on the character, and the handler has a back-reference to the character it sits
on.</p>
<p>Since the handler itself is just a regular Python object, we need to use the <code class="docutils literal notranslate"><span class="pre">Character</span></code> to store
our data - our <em>Knave</em> “slots”. We must save them to the database, because we want the server to remember
them even after reloading.</p>
<p>Using <code class="docutils literal notranslate"><span class="pre">self.obj.attributes.add()</span></code> and <code class="docutils literal notranslate"><span class="pre">.get()</span></code> we save the data to the Character in a specially named
<a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a>. Since we use a <code class="docutils literal notranslate"><span class="pre">category</span></code>, we are unlikely to collide with
other Attributes.</p>
<p>Our storage structure is a <code class="docutils literal notranslate"><span class="pre">dict</span></code> with keys after our available <code class="docutils literal notranslate"><span class="pre">WieldLocation</span></code> enums. Each can only
have one item except <code class="docutils literal notranslate"><span class="pre">WieldLocation.BACKPACK</span></code>, which is a list.</p>
</section>
<section id="connecting-the-equipmenthandler">
<h2>Connecting the EquipmentHandler<a class="headerlink" href="#connecting-the-equipmenthandler" title="Permalink to this headline"></a></h2>
<p>Whenever an object leaves from one location to the next, Evennia will call a set of <em>hooks</em> (methods) on the
object that moves, on the source-location and on its destination. This is the same for all moving things -
whether its a character moving between rooms or an item being dropping from your hand to the ground.</p>
<p>We need to tie our new <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> into this system. By reading the doc page on <a class="reference internal" href="../../../Components/Objects.html"><span class="doc std std-doc">Objects</span></a>,
or looking at the <a class="reference internal" href="../../../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.move_to" title="evennia.objects.objects.DefaultObject.move_to"><span class="xref myst py py-meth">DefaultObject.move_to</span></a> docstring, well
find out what hooks Evennia will call. Here <code class="docutils literal notranslate"><span class="pre">self</span></code> is the object being moved from
<code class="docutils literal notranslate"><span class="pre">source_location</span></code> to <code class="docutils literal notranslate"><span class="pre">destination</span></code>:</p>
<ol class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">self.at_pre_move(destination)</span></code> (abort if return False)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">source_location.at_pre_object_leave(self,</span> <span class="pre">destination)</span></code> (abort if return False)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">destination.at_pre_object_receive(self,</span> <span class="pre">source_location)</span></code> (abort if return False)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">source_location.at_object_leave(self,</span> <span class="pre">destination)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.announce_move_from(destination)</span></code></p></li>
<li><p>(move happens here)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.announce_move_to(source_location)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">destination.at_object_receive(self,</span> <span class="pre">source_location)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">self.at_post_move(source_location)</span></code></p></li>
</ol>
<p>All of these hooks can be overridden to customize movement behavior. In this case we are interested in
controlling how items enter and leave our character - being inside the character is the same as
them carrying it. We have three good hook-candidates to use for this.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">.at_pre_object_receive</span></code> - used to check if you can actually pick something up, or if your equipment-store is full.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.at_object_receive</span></code> - used to add the item to the equipmenthandler</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.at_object_leave</span></code> - used to remove the item from the equipmenthandler</p></li>
</ul>
<p>You could also picture using <code class="docutils literal notranslate"><span class="pre">.at_pre_object_leave</span></code> to restrict dropping (cursed?) items, but
we will skip that for this tutorial.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/character.py </span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureCharacter</span><span class="p">(</span><span class="n">LivingMixin</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">at_pre_object_receive</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">moved_object</span><span class="p">,</span> <span class="n">source_location</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called by Evennia before object arrives &#39;in&#39; this character (that is,</span>
<span class="sd"> if they pick up something). If it returns False, move is aborted.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">validate_slot_usage</span><span class="p">(</span><span class="n">moved_object</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_object_receive</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">moved_object</span><span class="p">,</span> <span class="n">source_location</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Called by Evennia when an object arrives &#39;in&#39; the character.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">moved_object</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_object_leave</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">moved_object</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Called by Evennia when object leaves the Character. </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">moved_object</span><span class="p">)</span>
</pre></div>
</div>
<p>Above we have assumed the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> (<code class="docutils literal notranslate"><span class="pre">.equipment</span></code>) has methods <code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code>,
<code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code>. But we havent actually added them yet - we just put some reasonable names! Before
we can use this, we need to go actually adding those methods.</p>
</section>
<section id="expanding-the-equipmenthandler">
<h2>Expanding the Equipmenthandler<a class="headerlink" href="#expanding-the-equipmenthandler" title="Permalink to this headline"></a></h2>
</section>
<section id="validate-slot-usage">
<h2><code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code><a class="headerlink" href="#validate-slot-usage" title="Permalink to this headline"></a></h2>
<p>Lets start with implementing the first method we came up with above, <code class="docutils literal notranslate"><span class="pre">validate_slot_usage</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
<span class="k">class</span> <span class="nc">EquipmentError</span><span class="p">(</span><span class="ne">TypeError</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;All types of equipment-errors&quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">max_slots</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Max amount of slots, based on CON defense (CON + 10)&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
<span class="k">def</span> <span class="nf">count_slots</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Count current slot usage&quot;&quot;&quot;</span>
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
<span class="n">wield_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">&quot;size&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">or</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">slot</span><span class="p">,</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
<span class="p">)</span>
<span class="n">backpack_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">&quot;size&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="ow">or</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">]</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">wield_usage</span> <span class="o">+</span> <span class="n">backpack_usage</span>
<span class="k">def</span> <span class="nf">validate_slot_usage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check if obj can fit in equipment, based on its size.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="c1"># in case we mix with non-evadventure objects</span>
<span class="k">raise</span> <span class="n">EquipmentError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> is not something that can be equipped.&quot;</span><span class="p">)</span>
<span class="n">size</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">size</span>
<span class="n">max_slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_slots</span>
<span class="n">current_slot_usage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">count_slots</span><span class="p">()</span>
<span class="k">return</span> <span class="n">current_slot_usage</span> <span class="o">+</span> <span class="n">size</span> <span class="o">&lt;=</span> <span class="n">max_slots</span><span class="p">:</span>
</pre></div>
</div>
<aside class="sidebar">
<p>The <code class="docutils literal notranslate"><span class="pre">&#64;property</span></code> decorator turns a method into a property so you dont need to call it.
That is, you can access <code class="docutils literal notranslate"><span class="pre">.max_slots</span></code> instead of <code class="docutils literal notranslate"><span class="pre">.max_slots()</span></code>. In this case, its just a
little less to type.</p>
</aside>
<p>We add two helpers - the <code class="docutils literal notranslate"><span class="pre">max_slots</span></code> <em>property</em> and <code class="docutils literal notranslate"><span class="pre">count_slots</span></code>, a method that calculate the current
slots being in use. Lets figure out how they work.</p>
<section id="max-slots">
<h3><code class="docutils literal notranslate"><span class="pre">.max_slots</span></code><a class="headerlink" href="#max-slots" title="Permalink to this headline"></a></h3>
<p>For <code class="docutils literal notranslate"><span class="pre">max_slots</span></code>, remember that <code class="docutils literal notranslate"><span class="pre">.obj</span></code> on the handler is a back-reference to the <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> we
put this handler on. <code class="docutils literal notranslate"><span class="pre">getattr</span></code> is a Python method for retrieving a named property on an object.
The <code class="docutils literal notranslate"><span class="pre">Enum</span></code> <code class="docutils literal notranslate"><span class="pre">Ability.CON.value</span></code> is the string <code class="docutils literal notranslate"><span class="pre">Constitution</span></code> (check out the
<a class="reference internal" href="Beginner-Tutorial-Utilities.html"><span class="doc std std-doc">first Utility and Enums tutorial</span></a> if you dont recall).</p>
<p>So to be clear,</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
</pre></div>
</div>
<p>is the same as writing</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">getattr</span><span class="p">(</span><span class="n">your_character</span><span class="p">,</span> <span class="s2">&quot;Constitution&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
</pre></div>
</div>
<p>which is the same as doing something like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">your_character</span><span class="o">.</span><span class="n">Constitution</span> <span class="o">+</span> <span class="mi">10</span>
</pre></div>
</div>
<p>In our code we write <code class="docutils literal notranslate"><span class="pre">getattr(self.obj,</span> <span class="pre">Ability.CON.value,</span> <span class="pre">1)</span></code> - that extra <code class="docutils literal notranslate"><span class="pre">1</span></code> means that if there
should happen to <em>not</em> be a property “Constitution” on <code class="docutils literal notranslate"><span class="pre">self.obj</span></code>, we should not error out but just
return 1.</p>
</section>
<section id="count-slots">
<h3><code class="docutils literal notranslate"><span class="pre">.count_slots</span></code><a class="headerlink" href="#count-slots" title="Permalink to this headline"></a></h3>
<p>In this helper we use two Python tools - the <code class="docutils literal notranslate"><span class="pre">sum()</span></code> function and a
<a class="reference external" href="https://www.w3schools.com/python/python_lists_comprehension.asp">list comprehension</a>. The former
simply adds the values of any iterable together. The latter is a more efficient way to create a list:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>new_list = [item for item in some_iterable if condition]
all_above_5 = [num for num in range(10) if num &gt; 5] # [6, 7, 8, 9]
all_below_5 = [num for num in range(10) if num &lt; 5] # [0, 1, 2, 3, 4]
</pre></div>
</div>
<p>To make it easier to understand, try reading the last line above as “for every number in the range 0-9,
pick all with a value below 5 and make a list of them”. You can also embed such comprehensions
directly in a function call like <code class="docutils literal notranslate"><span class="pre">sum()</span></code> without using <code class="docutils literal notranslate"><span class="pre">[]</span></code> around it.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">count_slots</span></code> we have this code:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">wield_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">&quot;size&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">slot</span><span class="p">,</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="o">.</span><span class="n">items</span><span class="p">()</span>
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
<span class="p">)</span>
</pre></div>
</div>
<p>We should be able to follow all except <code class="docutils literal notranslate"><span class="pre">slots.items()</span></code>. Since <code class="docutils literal notranslate"><span class="pre">slots</span></code> is a <code class="docutils literal notranslate"><span class="pre">dict</span></code>, we can use <code class="docutils literal notranslate"><span class="pre">.items()</span></code>
to get a sequence of <code class="docutils literal notranslate"><span class="pre">(key,</span> <span class="pre">value)</span></code> pairs. We store these in <code class="docutils literal notranslate"><span class="pre">slot</span></code> and <code class="docutils literal notranslate"><span class="pre">slotobj</span></code>. So the above can
be understood as “for every <code class="docutils literal notranslate"><span class="pre">slot</span></code> and <code class="docutils literal notranslate"><span class="pre">slotobj</span></code>-pair in <code class="docutils literal notranslate"><span class="pre">slots</span></code>, check which slot location it is.
If it is <em>not</em> in the backpack, get its size and add it to the list. Sum over all these
sizes”.</p>
<p>A less compact but maybe more readonable way to write this would be:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">backpack_item_sizes</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">slot</span><span class="p">,</span> <span class="n">slotobj</span> <span class="ow">in</span> <span class="n">slots</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span>
<span class="n">size</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">slotobj</span><span class="p">,</span> <span class="s2">&quot;size&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">backpack_item_sizes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">size</span><span class="p">)</span>
<span class="n">wield_usage</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">backpack_item_sizes</span><span class="p">)</span>
</pre></div>
</div>
<p>The same is done for the items actually in the BACKPACK slot. The total sizes are added
together.</p>
</section>
<section id="validating-slots">
<h3>Validating slots<a class="headerlink" href="#validating-slots" title="Permalink to this headline"></a></h3>
<p>With these helpers in place, <code class="docutils literal notranslate"><span class="pre">validate_slot_usage</span></code> now becomes simple. We use <code class="docutils literal notranslate"><span class="pre">max_slots</span></code> to see how much we can carry.
We then get how many slots we are already using (with <code class="docutils literal notranslate"><span class="pre">count_slots</span></code>) and see if our new <code class="docutils literal notranslate"><span class="pre">obj</span></code>s size
would be too much for us.</p>
</section>
</section>
<section id="add-and-remove">
<h2><code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code><a class="headerlink" href="#add-and-remove" title="Permalink to this headline"></a></h2>
<p>We will make it so <code class="docutils literal notranslate"><span class="pre">.add</span></code> puts something in the <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code> location and <code class="docutils literal notranslate"><span class="pre">remove</span></code> drops it, wherever
it is (even if it was in your hands).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Put something in the backpack.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">validate_slot_usage</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">slot</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove contents of a particular slot, for</span>
<span class="sd"> example `equipment.remove(WieldLocation.SHIELD_HAND)`</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
<span class="n">ret</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="n">slot</span> <span class="ow">is</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span>
<span class="c1"># empty entire backpack! </span>
<span class="n">ret</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">])</span>
<span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">ret</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">])</span>
<span class="n">slots</span><span class="p">[</span><span class="n">slot</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">ret</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
<span class="k">return</span> <span class="n">ret</span>
</pre></div>
</div>
<p>Both of these should be straight forward to follow. In <code class="docutils literal notranslate"><span class="pre">.add</span></code>, we make use of <code class="docutils literal notranslate"><span class="pre">validate_slot_usage</span></code> to
double-check we can actually fit the thing, then we add the item to the backpack.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">.delete</span></code>, we allow emptying by <code class="docutils literal notranslate"><span class="pre">WieldLocation</span></code> - we figure out what slot it is and return
the item within (if any). If we gave <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code> as the slot, we empty the backpack and
return all items.</p>
<p>Whenever we change the equipment loadout we must make sure to <code class="docutils literal notranslate"><span class="pre">._save()</span></code> the result, or it will
be lost after a server reload.</p>
</section>
<section id="moving-things-around">
<h2>Moving things around<a class="headerlink" href="#moving-things-around" title="Permalink to this headline"></a></h2>
<p>With the help of <code class="docutils literal notranslate"><span class="pre">.remove()</span></code> and <code class="docutils literal notranslate"><span class="pre">.add()</span></code> we can get things in and out of the <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code> equipment
location. We also need to grab stuff from the backpack and wield or wear it. We add a <code class="docutils literal notranslate"><span class="pre">.move</span></code> method
on the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> to do this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Move object from backpack to its intended `inventory_use_slot`.&quot;&quot;&quot;</span>
<span class="c1"># make sure to remove from equipment/backpack first, to avoid double-adding</span>
<span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
<span class="n">use_slot</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;inventory_use_slot&quot;</span><span class="p">,</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">)</span>
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">if</span> <span class="n">use_slot</span> <span class="ow">is</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">:</span>
<span class="c1"># two-handed weapons can&#39;t co-exist with weapon/shield-hand used items</span>
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">],</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">]]</span>
<span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">]</span> <span class="o">=</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
<span class="k">elif</span> <span class="n">use_slot</span> <span class="ow">in</span> <span class="p">(</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">,</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">):</span>
<span class="c1"># can&#39;t keep a two-handed weapon if adding a one-handed weapon or shield</span>
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">]]</span>
<span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
<span class="k">elif</span> <span class="n">use_slot</span> <span class="ow">is</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">:</span>
<span class="c1"># it belongs in backpack, so goes back to it</span>
<span class="n">to_backpack</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># for others (body, head), just replace whatever&#39;s there</span>
<span class="n">replaced</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span><span class="p">]</span>
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">obj</span>
<span class="k">for</span> <span class="n">to_backpack_obj</span> <span class="ow">in</span> <span class="n">to_backpack</span><span class="p">:</span>
<span class="c1"># put stuff in backpack</span>
<span class="n">slots</span><span class="p">[</span><span class="n">use_slot</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">to_backpack_obj</span><span class="p">)</span>
<span class="c1"># store new state</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
</pre></div>
</div>
<p>Here we remember that every <code class="docutils literal notranslate"><span class="pre">EvAdventureObject</span></code> has an <code class="docutils literal notranslate"><span class="pre">inventory_use_slot</span></code> property that tells us where
it goes. So we just need to move the object to that slot, replacing whatever is in that place
from before. Anything we replace goes back to the backpack.</p>
</section>
<section id="get-everything">
<h2>Get everything<a class="headerlink" href="#get-everything" title="Permalink to this headline"></a></h2>
<p>In order to visualize our inventory, we need some method to get everything we are carrying.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">all</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get all objects in inventory, regardless of location.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
<span class="n">lst</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">),</span>
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">),</span>
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">),</span>
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">),</span>
<span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">],</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">),</span>
<span class="p">]</span> <span class="o">+</span> <span class="p">[(</span><span class="n">item</span><span class="p">,</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">]]</span>
<span class="k">return</span> <span class="n">lst</span>
</pre></div>
</div>
<p>Here we get all the equipment locations and add their contents together into a list of tuples
<code class="docutils literal notranslate"><span class="pre">[(item,</span> <span class="pre">WieldLocation),</span> <span class="pre">...]</span></code>. This is convenient for display.</p>
</section>
<section id="weapon-and-armor">
<h2>Weapon and armor<a class="headerlink" href="#weapon-and-armor" title="Permalink to this headline"></a></h2>
<p>Its convenient to have the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> easily tell you what weapon is currently wielded
and what <em>armor</em> level all worn equipment provides. Otherwise youd need to figure out what item is
in which wield-slot and to add up armor slots manually every time you need to know.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/equipment.py </span>
<span class="kn">from</span> <span class="nn">.objects</span> <span class="kn">import</span> <span class="n">WeaponEmptyHand</span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">Ability</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EquipmentHandler</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">armor</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span>
<span class="p">(</span>
<span class="c1"># armor is listed using its defense, so we remove 10 from it</span>
<span class="c1"># (11 is base no-armor value in Knave)</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span><span class="p">],</span> <span class="s2">&quot;armor&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span>
<span class="c1"># shields and helmets are listed by their bonus to armor</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span><span class="p">],</span> <span class="s2">&quot;armor&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span><span class="p">],</span> <span class="s2">&quot;armor&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">weapon</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># first checks two-handed wield, then one-handed; the two</span>
<span class="c1"># should never appear simultaneously anyhow (checked in `move` method).</span>
<span class="n">slots</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">slots</span>
<span class="n">weapon</span> <span class="o">=</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span><span class="p">]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">weapon</span><span class="p">:</span>
<span class="n">weapon</span> <span class="o">=</span> <span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">weapon</span><span class="p">:</span>
<span class="n">weapon</span> <span class="o">=</span> <span class="n">WeaponEmptyHand</span><span class="p">()</span>
<span class="k">return</span> <span class="n">weapon</span>
</pre></div>
</div>
<p>In the <code class="docutils literal notranslate"><span class="pre">.armor()</span></code> method we get the item (if any) out of each relevant wield-slot (body, shield, head),
and grab their <code class="docutils literal notranslate"><span class="pre">armor</span></code> Attribute. We then <code class="docutils literal notranslate"><span class="pre">sum()</span></code> them all up.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">.weapon()</span></code>, we simply check which of the possible weapon slots (weapon-hand or two-hands) have
something in them. If not we fall back to the fake weapon <code class="docutils literal notranslate"><span class="pre">WeaponEmptyHand</span></code> which is just a dummy
object that represents your bare hands with damage and all.
(created in <a class="reference internal" href="Beginner-Tutorial-Objects.html#your-bare-hands"><span class="std std-doc">The Object tutorial</span></a> earlier).</p>
</section>
<section id="extra-credits">
<h2>Extra credits<a class="headerlink" href="#extra-credits" title="Permalink to this headline"></a></h2>
<p>This covers the basic functionality of the equipment handler. There are other useful methods that
can be added:</p>
<ul class="simple">
<li><p>Given an item, figure out which equipment slot it is currently in</p></li>
<li><p>Make a string representing the current loadout</p></li>
<li><p>Get everything in the backpack (only)</p></li>
<li><p>Get all wieldable items (weapons, shields) from backpack</p></li>
<li><p>Get all usable items (items with a use-location of <code class="docutils literal notranslate"><span class="pre">BACKPACK</span></code>) from the backpack</p></li>
</ul>
<p>Experiment with adding those. A full example is found in
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.equipment.html#evennia-contrib-tutorials-evadventure-equipment"><span class="std std-ref">evennia/contrib/tutorials/evadventure/equipment.py</span></a>.</p>
</section>
<section id="unit-testing">
<h2>Unit Testing<a class="headerlink" href="#unit-testing" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_equipment.py</span></code>.</p>
</div></blockquote>
<aside class="sidebar">
<p>See <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_equipment.html#evennia-contrib-tutorials-evadventure-tests-test-equipment"><span class="std std-ref">evennia/contrib/tutorials/evadventure/tests/test_equipment.py</span></a>
for a finished testing example.</p>
</aside>
<p>To test the <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code>, easiest is create an <code class="docutils literal notranslate"><span class="pre">EvAdventureCharacter</span></code> (this should by now
have <code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code> available on itself as <code class="docutils literal notranslate"><span class="pre">.equipment</span></code>) and a few test objects; then test
passing these into the handlers methods.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_equipment.py </span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span>
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
<span class="kn">from</span> <span class="nn">..objects</span> <span class="kn">import</span> <span class="n">EvAdventureRoom</span>
<span class="kn">from</span> <span class="nn">..enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span>
<span class="k">class</span> <span class="nc">TestEquipment</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">EvAdventureCharacter</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s1">&#39;testchar&#39;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">helmet</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">EvAdventureHelmet</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;helmet&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">weapon</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">EvAdventureWeapon</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;weapon&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_add_remove</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">],</span>
<span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">]</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">helmet</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">character</span><span class="o">.</span><span class="n">equipment</span><span class="o">.</span><span class="n">slots</span><span class="p">[</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span><span class="p">],</span> <span class="p">[])</span>
<span class="c1"># ... </span>
</pre></div>
</div>
</section>
<section id="summary">
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline"></a></h2>
<p><em>Handlers</em> are useful for grouping functionality together. Now that we spent our time making the
<code class="docutils literal notranslate"><span class="pre">EquipmentHandler</span></code>, we shouldnt need to worry about item-slots anymore - the handler handles all
the details for us. As long as we call its methods, the details can be forgotten about.</p>
<p>We also learned to use <em>hooks</em> to tie <em>Knave</em>s custom equipment handling into Evennia.</p>
<p>With <code class="docutils literal notranslate"><span class="pre">Characters</span></code>, <code class="docutils literal notranslate"><span class="pre">Objects</span></code> and now <code class="docutils literal notranslate"><span class="pre">Equipment</span></code> in place, we should be able to move on to character
generation - where players get to make their own character!</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Handling Equipment</a><ul>
<li><a class="reference internal" href="#equipmenthandler-that-saves">EquipmentHandler that saves</a></li>
<li><a class="reference internal" href="#connecting-the-equipmenthandler">Connecting the EquipmentHandler</a></li>
<li><a class="reference internal" href="#expanding-the-equipmenthandler">Expanding the Equipmenthandler</a></li>
<li><a class="reference internal" href="#validate-slot-usage"><code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code></a><ul>
<li><a class="reference internal" href="#max-slots"><code class="docutils literal notranslate"><span class="pre">.max_slots</span></code></a></li>
<li><a class="reference internal" href="#count-slots"><code class="docutils literal notranslate"><span class="pre">.count_slots</span></code></a></li>
<li><a class="reference internal" href="#validating-slots">Validating slots</a></li>
</ul>
</li>
<li><a class="reference internal" href="#add-and-remove"><code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code></a></li>
<li><a class="reference internal" href="#moving-things-around">Moving things around</a></li>
<li><a class="reference internal" href="#get-everything">Get everything</a></li>
<li><a class="reference internal" href="#weapon-and-armor">Weapon and armor</a></li>
<li><a class="reference internal" href="#extra-credits">Extra credits</a></li>
<li><a class="reference internal" href="#unit-testing">Unit Testing</a></li>
<li><a class="reference internal" href="#summary">Summary</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Objects.html"
title="previous chapter">In-game Objects and items</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Chargen.html"
title="next chapter">Character Generation</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Equipment.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Equipment.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Chargen.html" title="Character Generation"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Objects.html" title="In-game Objects and items"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Handling Equipment</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,141 @@
<!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>Non-Player-Characters (NPCs) &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Game Quests" href="Beginner-Tutorial-Quests.html" />
<link rel="prev" title="In-game Rooms" href="Beginner-Tutorial-Rooms.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Quests.html" title="Game Quests"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rooms.html" title="In-game Rooms"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Non-Player-Characters (NPCs)</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="non-player-characters-npcs">
<h1>Non-Player-Characters (NPCs)<a class="headerlink" href="#non-player-characters-npcs" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This part of the Beginner tutorial is still being developed.</p>
</div>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Rooms.html"
title="previous chapter">In-game Rooms</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Quests.html"
title="next chapter">Game Quests</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-NPCs.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-NPCs.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Quests.html" title="Game Quests"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rooms.html" title="In-game Rooms"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Non-Player-Characters (NPCs)</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,484 @@
<!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>In-game Objects and items &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Handling Equipment" href="Beginner-Tutorial-Equipment.html" />
<link rel="prev" title="Player Characters" href="Beginner-Tutorial-Characters.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Equipment.html" title="Handling Equipment"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Characters.html" title="Player Characters"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Objects and items</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="in-game-objects-and-items">
<h1>In-game Objects and items<a class="headerlink" href="#in-game-objects-and-items" title="Permalink to this headline"></a></h1>
<p>In the previous lesson we established what a Character is in our game. Before we continue
we also need to have a notion what an item or object is.</p>
<p>Looking at <em>Knave</em>s item lists, we can get some ideas of what we need to track:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">size</span></code> - this is how many slots the item uses in the characters inventory.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">value</span></code> - a base value if we want to sell or buy the item.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">inventory_use_slot</span></code> - some items can be worn or wielded. For example, a helmet needs to be
worn on the head and a shield in the shield hand. Some items cant be used this way at all, but
only belong in the backpack.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">obj_type</span></code> - Which type of item this is.</p></li>
</ul>
<section id="new-enums">
<h2>New Enums<a class="headerlink" href="#new-enums" title="Permalink to this headline"></a></h2>
<p>We added a few enumberations for Abilities back in the <a class="reference internal" href="Beginner-Tutorial-Utilities.html"><span class="doc std std-doc">Utilities tutorial</span></a>.
Before we continue, lets expand with enums for use-slots and object types.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
<span class="c1"># ...</span>
<span class="k">class</span> <span class="nc">WieldLocation</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">BACKPACK</span> <span class="o">=</span> <span class="s2">&quot;backpack&quot;</span>
<span class="n">WEAPON_HAND</span> <span class="o">=</span> <span class="s2">&quot;weapon_hand&quot;</span>
<span class="n">SHIELD_HAND</span> <span class="o">=</span> <span class="s2">&quot;shield_hand&quot;</span>
<span class="n">TWO_HANDS</span> <span class="o">=</span> <span class="s2">&quot;two_handed_weapons&quot;</span>
<span class="n">BODY</span> <span class="o">=</span> <span class="s2">&quot;body&quot;</span> <span class="c1"># armor</span>
<span class="n">HEAD</span> <span class="o">=</span> <span class="s2">&quot;head&quot;</span> <span class="c1"># helmets</span>
<span class="k">class</span> <span class="nc">ObjType</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">WEAPON</span> <span class="o">=</span> <span class="s2">&quot;weapon&quot;</span>
<span class="n">ARMOR</span> <span class="o">=</span> <span class="s2">&quot;armor&quot;</span>
<span class="n">SHIELD</span> <span class="o">=</span> <span class="s2">&quot;shield&quot;</span>
<span class="n">HELMET</span> <span class="o">=</span> <span class="s2">&quot;helmet&quot;</span>
<span class="n">CONSUMABLE</span> <span class="o">=</span> <span class="s2">&quot;consumable&quot;</span>
<span class="n">GEAR</span> <span class="o">=</span> <span class="s2">&quot;gear&quot;</span>
<span class="n">MAGIC</span> <span class="o">=</span> <span class="s2">&quot;magic&quot;</span>
<span class="n">QUEST</span> <span class="o">=</span> <span class="s2">&quot;quest&quot;</span>
<span class="n">TREASURE</span> <span class="o">=</span> <span class="s2">&quot;treasure&quot;</span>
</pre></div>
</div>
<p>Once we have these enums, we will use them for referencing things.</p>
</section>
<section id="the-base-object">
<h2>The base object<a class="headerlink" href="#the-base-object" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/objects.py</span></code></p>
</div></blockquote>
<aside class="sidebar">
<p><a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.objects.html#evennia-contrib-tutorials-evadventure-objects"><span class="std std-ref">evennia/contrib/tutorials/evadventure/objects.py</span></a> has
a full set of objects implemented.</p>
</aside>
<div style="clear: right;"></div>
<p>We will make a base <code class="docutils literal notranslate"><span class="pre">EvAdventureObject</span></code> class off Evennias standard <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. We will then add
child classes to represent the relevant types:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AttributeProperty</span><span class="p">,</span> <span class="n">DefaultObject</span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">make_iter</span>
<span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">get_obj_stats</span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">ObjType</span>
<span class="k">class</span> <span class="nc">EvAdventureObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Base for all evadventure objects. </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
<span class="n">size</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="c1"># this can be either a single type or a list of types (for objects able to be </span>
<span class="c1"># act as multiple). This is used to tag this object during creation.</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">GEAR</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="sd">&quot;&quot;&quot;Called when this object is first created. We convert the .obj_type </span>
<span class="sd"> property to a database tag.&quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">obj_type</span> <span class="ow">in</span> <span class="n">make_iter</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;obj_type&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_help</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Get any help text for this item&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="s2">&quot;No help for this item&quot;</span>
</pre></div>
</div>
<section id="using-attributes-or-not">
<h3>Using Attributes or not<a class="headerlink" href="#using-attributes-or-not" title="Permalink to this headline"></a></h3>
<p>In theory, <code class="docutils literal notranslate"><span class="pre">size</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code> does not change and <em>could</em> also be just set as a regular Python
property on the class:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">EvAdventureObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BACKPACK</span>
<span class="n">size</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">value</span> <span class="o">=</span> <span class="mi">0</span>
</pre></div>
</div>
<p>The problem with this is that if we want to make a new object of <code class="docutils literal notranslate"><span class="pre">size</span> <span class="pre">3</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">20</span></code>, we have to
make a new class for it. We cant change it on the fly because the change would only be in memory and
be lost on next server reload.</p>
<p>Because we use <code class="docutils literal notranslate"><span class="pre">AttributeProperties</span></code>, we can set <code class="docutils literal notranslate"><span class="pre">size</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code> to whatever we like when we
create the object (or later), and the Attributes will remember our changes to that object indefinitely.</p>
<p>To make this a little more efficient, we use <code class="docutils literal notranslate"><span class="pre">autocreate=False</span></code>. Normally when you create a
new object with defined <code class="docutils literal notranslate"><span class="pre">AttributeProperties</span></code>, a matching <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> is immediately created at
the same time. So normally, the object would be created along with two Attributes <code class="docutils literal notranslate"><span class="pre">size</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code>.
With <code class="docutils literal notranslate"><span class="pre">autocreate=False</span></code>, no Attribute will be created <em>unless the default is changed</em>. That is, as
long as your object has <code class="docutils literal notranslate"><span class="pre">size=1</span></code> no database <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> will be created at all. This saves time and
resources when creating large number of objects.</p>
<p>The drawback is that since no Attribute is created you cant refer to it
with <code class="docutils literal notranslate"><span class="pre">obj.db.size</span></code> or <code class="docutils literal notranslate"><span class="pre">obj.attributes.get(&quot;size&quot;)</span></code> <em>unless you change its default</em>. You also cant query
the database for all objects with <code class="docutils literal notranslate"><span class="pre">size=1</span></code>, since most objects would not yet have an in-database
<code class="docutils literal notranslate"><span class="pre">size</span></code> Attribute to search for.</p>
<p>In our case, well only refer to these properties as <code class="docutils literal notranslate"><span class="pre">obj.size</span></code> etc, and have no need to find
all objects of a particular size. So we should be safe.</p>
</section>
<section id="creating-tags-in-at-object-creation">
<h3>Creating tags in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code><a class="headerlink" href="#creating-tags-in-at-object-creation" title="Permalink to this headline"></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> is a method Evennia calls on every child of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> whenever it is
first created.</p>
<p>We do a tricky thing here, converting our <code class="docutils literal notranslate"><span class="pre">.obj_type</span></code> to one or more <a class="reference internal" href="../../../Components/Tags.html"><span class="doc std std-doc">Tags</span></a>. Tagging the
object like this means you can later efficiently find all objects of a given type (or combination of
types) with Evennias search functions:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">ObjType</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">search</span>
<span class="c1"># get all shields in the game</span>
<span class="n">all_shields</span> <span class="o">=</span> <span class="n">search</span><span class="o">.</span><span class="n">search_object_by_tag</span><span class="p">(</span><span class="n">ObjType</span><span class="o">.</span><span class="n">SHIELD</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;obj_type&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>We allow <code class="docutils literal notranslate"><span class="pre">.obj_type</span></code> to be given as a single value or a list of values. We use <code class="docutils literal notranslate"><span class="pre">make_iter</span></code> from the
evennia utility library to make sure we dont balk at either. This means you could have a Shield that
is also Magical, for example.</p>
</section>
</section>
<section id="other-object-types">
<h2>Other object types<a class="headerlink" href="#other-object-types" title="Permalink to this headline"></a></h2>
<p>Some of the other object types are very simple so far.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AttributeProperty</span><span class="p">,</span> <span class="n">DefaultObject</span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">ObjType</span>
<span class="k">class</span> <span class="nc">EvAdventureObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureQuestObject</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Quest objects should usually not be possible to sell or trade.&quot;&quot;&quot;</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">QUEST</span>
<span class="k">class</span> <span class="nc">EvAdventureTreasure</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Treasure is usually just for selling for coin&quot;&quot;&quot;</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">TREASURE</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="consumables">
<h2>Consumables<a class="headerlink" href="#consumables" title="Permalink to this headline"></a></h2>
<p>A consumable is an item that has a certain number of uses. Once fully consumed, it cant be used
anymore. An example would be a health potion.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureConsumable</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;An item that can be used up&quot;&quot;&quot;</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">CONSUMABLE</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mf">0.25</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">uses</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_pre_use</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called before using. If returning False, abort use.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">uses</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">at_use</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called when using the item&quot;&quot;&quot;</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">at_post_use</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called after using the item&quot;&quot;&quot;</span>
<span class="c1"># detract a usage, deleting the item if used up.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">user</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="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> was used up.&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
<p>What exactly each consumable does will vary - we will need to implement children of this class
later, overriding <code class="docutils literal notranslate"><span class="pre">at_use</span></code> with different effects.</p>
</section>
<section id="weapons">
<h2>Weapons<a class="headerlink" href="#weapons" title="Permalink to this headline"></a></h2>
<p>All weapons need properties that describe how efficient they are in battle.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">WieldLocation</span><span class="p">,</span> <span class="n">ObjType</span><span class="p">,</span> <span class="n">Ability</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureWeapon</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Base class for all weapons&quot;&quot;&quot;</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">WEAPON</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">quality</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">attack_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">defend_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">ARMOR</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">damage_roll</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="s2">&quot;1d6&quot;</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">quality</span></code> is something we need to track in <em>Knave</em>. When getting critical failures on attacks,
a weapons quality will go down. When it reaches 0, it will break.</p>
<p>The attack/defend type tracks how we resolve attacks with the weapon, like <code class="docutils literal notranslate"><span class="pre">roll</span> <span class="pre">+</span> <span class="pre">STR</span> <span class="pre">vs</span> <span class="pre">ARMOR</span> <span class="pre">+</span> <span class="pre">10</span></code>.</p>
</section>
<section id="magic">
<h2>Magic<a class="headerlink" href="#magic" title="Permalink to this headline"></a></h2>
<p>In <em>Knave</em>, anyone can use magic if they are wielding a rune stone (our name for spell books) in both
hands. You can only use a rune stone once per rest. So a rune stone is an example of a magical weapon
that is also a consumable of sorts.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureConsumable</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureWeapon</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureRuneStone</span><span class="p">(</span><span class="n">EvAdventureWeapon</span><span class="p">,</span> <span class="n">EvAdventureConsumable</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Base for all magical rune stones&quot;&quot;&quot;</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="p">(</span><span class="n">ObjType</span><span class="o">.</span><span class="n">WEAPON</span><span class="p">,</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">MAGIC</span><span class="p">)</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">TWO_HANDS</span> <span class="c1"># always two hands for magic</span>
<span class="n">quality</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">attack_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">INT</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">defend_type</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="n">Ability</span><span class="o">.</span><span class="n">DEX</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">damage_roll</span> <span class="o">=</span> <span class="n">AttibuteProperty</span><span class="p">(</span><span class="s2">&quot;1d8&quot;</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_post_use</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called after usage/spell was cast&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="c1"># we don&#39;t delete the rune stone here, but </span>
<span class="c1"># it must be reset on next rest.</span>
<span class="k">def</span> <span class="nf">refresh</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Refresh the rune stone (normally after rest)&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">uses</span> <span class="o">=</span> <span class="mi">1</span>
</pre></div>
</div>
<p>We make the rune stone a mix of weapon and consumable. Note that we dont have to add <code class="docutils literal notranslate"><span class="pre">.uses</span></code>
again, its inherited from <code class="docutils literal notranslate"><span class="pre">EvAdventureConsumable</span></code> parent. The <code class="docutils literal notranslate"><span class="pre">at_pre_use</span></code> and <code class="docutils literal notranslate"><span class="pre">at_use</span></code> methods
are also inherited; we only override <code class="docutils literal notranslate"><span class="pre">at_post_use</span></code> since we dont want the runestone to be deleted
when it runs out of uses.</p>
<p>We add a little convenience method <code class="docutils literal notranslate"><span class="pre">refresh</span></code> - we should call this when the character rests, to
make the runestone active again.</p>
<p>Exactly what rune stones <em>do</em> will be implemented in the <code class="docutils literal notranslate"><span class="pre">at_use</span></code> methods of subclasses to this
base class. Since magic in <em>Knave</em> tends to be pretty custom, it makes sense that it will lead to a lot
of custom code.</p>
</section>
<section id="armor">
<h2>Armor<a class="headerlink" href="#armor" title="Permalink to this headline"></a></h2>
<p>Armor, shields and helmets increase the <code class="docutils literal notranslate"><span class="pre">ARMOR</span></code> stat of the character. In <em>Knave</em>, what is stored is the
defense value of the armor (values 11-20). We will instead store the armor bonus (1-10). As we know,
defending is always <code class="docutils literal notranslate"><span class="pre">bonus</span> <span class="pre">+</span> <span class="pre">10</span></code>, so the result will be the same - this means
we can use <code class="docutils literal notranslate"><span class="pre">Ability.ARMOR</span></code> as any other defensive ability without worrying about a special case.</p>
<p>``</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/objects.py </span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureAmor</span><span class="p">(</span><span class="n">EvAdventureObject</span><span class="p">):</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">ARMOR</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">BODY</span>
<span class="n">armor</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">quality</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">EvAdventureShield</span><span class="p">(</span><span class="n">EvAdventureArmor</span><span class="p">):</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">SHIELD</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">SHIELD_HAND</span>
<span class="k">class</span> <span class="nc">EvAdventureHelmet</span><span class="p">(</span><span class="n">EvAdventureArmor</span><span class="p">):</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">HELMET</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">HEAD</span>
</pre></div>
</div>
</section>
<section id="your-bare-hands">
<h2>Your Bare hands<a class="headerlink" href="#your-bare-hands" title="Permalink to this headline"></a></h2>
<p>This is a dummy object that is not stored in the database. We will use this in the upcoming
<a class="reference internal" href="Beginner-Tutorial-Equipment.html"><span class="doc std std-doc">Equipment tutorial lesson</span></a> to represent when you have nothing
in your hands. This way we dont need to add any special case for this.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">WeaponEmptyHand</span><span class="p">:</span>
<span class="n">obj_type</span> <span class="o">=</span> <span class="n">ObjType</span><span class="o">.</span><span class="n">WEAPON</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;Empty Fists&quot;</span>
<span class="n">inventory_use_slot</span> <span class="o">=</span> <span class="n">WieldLocation</span><span class="o">.</span><span class="n">WEAPON_HAND</span>
<span class="n">attack_type</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">STR</span>
<span class="n">defense_type</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">ARMOR</span>
<span class="n">damage_roll</span> <span class="o">=</span> <span class="s2">&quot;1d4&quot;</span>
<span class="n">quality</span> <span class="o">=</span> <span class="mi">100000</span> <span class="c1"># let&#39;s assume fists are always available ...</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">&quot;&lt;WeaponEmptyHand&gt;&quot;</span>
</pre></div>
</div>
</section>
<section id="testing-and-extra-credits">
<h2>Testing and Extra credits<a class="headerlink" href="#testing-and-extra-credits" title="Permalink to this headline"></a></h2>
<p>Remember the <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> function from the <a class="reference internal" href="Beginner-Tutorial-Utilities.html"><span class="doc std std-doc">Utility Tutorial</span></a> earlier?
We had to use dummy-values since we didnt yet know how we would store properties on Objects in the game.</p>
<p>Well, we just figured out all we need! You can go back and update <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> to properly read the data
from the object it receives.</p>
<p>When you change this function you must also update the related unit test - so your existing test becomes a
nice way to test your new Objects as well! Add more tests showing the output of feeding different object-types
to <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code>.</p>
<p>Try it out yourself. If you need help, a finished utility example is found in <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.utils.html#evennia.contrib.tutorials.evadventure.utils.get_obj_stats" title="evennia.contrib.tutorials.evadventure.utils.get_obj_stats"><span class="xref myst py py-func">evennia/contrib/tutorials/evadventure/utils.py</span></a>.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">In-game Objects and items</a><ul>
<li><a class="reference internal" href="#new-enums">New Enums</a></li>
<li><a class="reference internal" href="#the-base-object">The base object</a><ul>
<li><a class="reference internal" href="#using-attributes-or-not">Using Attributes or not</a></li>
<li><a class="reference internal" href="#creating-tags-in-at-object-creation">Creating tags in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#other-object-types">Other object types</a></li>
<li><a class="reference internal" href="#consumables">Consumables</a></li>
<li><a class="reference internal" href="#weapons">Weapons</a></li>
<li><a class="reference internal" href="#magic">Magic</a></li>
<li><a class="reference internal" href="#armor">Armor</a></li>
<li><a class="reference internal" href="#your-bare-hands">Your Bare hands</a></li>
<li><a class="reference internal" href="#testing-and-extra-credits">Testing and Extra credits</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Characters.html"
title="previous chapter">Player Characters</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Equipment.html"
title="next chapter">Handling Equipment</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Objects.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Objects.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Equipment.html" title="Handling Equipment"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Characters.html" title="Player Characters"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Objects and items</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -17,8 +17,8 @@
<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="Implementing a game rule system" href="Implementing-a-game-rule-system.html" />
<link rel="prev" title="Planning our tutorial game" href="../Part2/Planning-The-Tutorial-Game.html" />
<link rel="next" title="Code structure and Utilities" href="Beginner-Tutorial-Utilities.html" />
<link rel="prev" title="Planning our tutorial game" href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -30,10 +30,10 @@
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Implementing-a-game-rule-system.html" title="Implementing a game rule system"
<a href="Beginner-Tutorial-Utilities.html" title="Code structure and Utilities"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="../Part2/Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
<a href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -50,6 +50,12 @@
<section class="tex2jax_ignore mathjax_ignore" id="part-3-how-we-get-there">
<h1>Part 3: How we get there<a class="headerlink" href="#part-3-how-we-get-there" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>The tutorial game is under development and is not yet complete, nor tested. Use the existing
lessons as inspiration and to help get you going, but dont expect out-of-the-box perfection
from it at this time.</p>
</div>
<aside class="sidebar">
<p class="sidebar-title">Beginner Tutorial Parts</p>
<dl class="simple">
@ -67,42 +73,145 @@
</dd>
</dl>
</aside>
<p>In part three of the Evennia Beginner tutorial we will go through the creation of several key parts of our tutorial
game <em>EvAdventure</em>. This is a pretty big part with plenty of examples.</p>
<p>If you followed the previous parts of this tutorial you will have some notions about Python and where to find
and make use of things in Evennia. We also have a good idea of the type of game we want.
Even if this is not the game-style you are interested in, following along will give you a lot of experience
with using Evennia. This be of much use when doing your own thing later.</p>
<p>In part three of the Evennia Beginner tutorial we will go through the actual creation of
our tutorial game <em>EvAdventure</em>, based on the <a class="reference external" href="https://www.drivethrurpg.com/product/250888/Knave">Knave</a>
RPG ruleset.</p>
<p>This is a big part. Youll be seeing a lot of code and there are plenty of lessons to go through.
Take your time!</p>
<p>If you followed the previous parts of this tutorial you will have some notions about Python and where to
find and make use of things in Evennia. We also have a good idea of the type of game we will
create.</p>
<p>Even if this is not the game-style you are interested in, following along will give you a lot
of experience using Evennia and be really helpful for doing your own thing later!</p>
<p>Fully coded examples of all code we make in this part can be found in the
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.html#evennia-contrib-tutorials-evadventure"><span class="std std-ref">evennia/contrib/tutorials/evadventure</span></a> package.</p>
<section id="lessons">
<h2>Lessons<a class="headerlink" href="#lessons" title="Permalink to this headline"></a></h2>
<p><em>TODO</em></p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Implementing-a-game-rule-system.html">Implementing a game rule system</a></li>
<li class="toctree-l1"><a class="reference internal" href="Turn-based-Combat-System.html">Turn based Combat System</a></li>
<li class="toctree-l1"><a class="reference internal" href="A-Sittable-Object.html">Making a sittable object</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Utilities.html">Code structure and Utilities</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rules.html">Rules and dice rolling</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Characters.html">Player Characters</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Objects.html">In-game Objects and items</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Equipment.html">Handling Equipment</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Chargen.html">Character Generation</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rooms.html">In-game Rooms</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-NPCs.html">Non-Player-Characters (NPCs)</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Quests.html">Game Quests</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Shops.html">In-game Shops</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Dungeon.html">Dynamically generated Dungeon</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Commands.html">In-game Commands</a></li>
</ul>
</div>
<ol class="simple">
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Changing settings</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Applying contribs</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Creating a rule module</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Tweaking the base Typeclasses</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Character creation menu</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Wearing armor and wielding weapons</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Two types of combat</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Monsters and AI</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Questing and rewards</span></a></p></li>
<li><p><a class="reference internal" href="../../../Unimplemented.html"><span class="doc std std-doc">Overview of Tech demo</span></a></p></li>
</ol>
</section>
<section id="table-of-contents">
<h2>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline"></a></h2>
<p><em>TODO</em></p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Implementing-a-game-rule-system.html">Implementing a game rule system</a></li>
<li class="toctree-l1"><a class="reference internal" href="A-Sittable-Object.html">Making a sittable object</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Utilities.html">Code structure and Utilities</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#folder-structure">Folder structure</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#enums">Enums</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#utility-module">Utility module</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#testing">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#running-your-test">Running your test</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Utilities.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rules.html">Rules and dice rolling</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#summary-of-knave-rules">Summary of <em>Knave</em> rules</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#making-a-rule-module">Making a rule module</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#rolling-dice">Rolling dice</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#generic-dice-roller">Generic dice roller</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#rolling-with-advantage">Rolling with advantage</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#saving-throws">Saving throws</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#opposed-saving-throw">Opposed saving throw</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#morale-check">Morale check</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#roll-for-healing">Roll for Healing</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#rolling-on-a-table">Rolling on a table</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#roll-for-death">Roll for death</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#testing">Testing</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Rules.html#mocking-and-patching">Mocking and patching</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Rules.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Characters.html">Player Characters</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#inheritance-structure">Inheritance structure</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#living-mixin-class">Living mixin class</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#character-class">Character class</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Characters.html#funcparser-inlines">Funcparser inlines</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Characters.html#backtracking">Backtracking</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#connecting-the-character-with-evennia">Connecting the Character with Evennia</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#unit-testing">Unit Testing</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#about-races-and-classes">About races and classes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Characters.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Objects.html">In-game Objects and items</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#new-enums">New Enums</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#the-base-object">The base object</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Objects.html#using-attributes-or-not">Using Attributes or not</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Objects.html#creating-tags-in-at-object-creation">Creating tags in <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code></a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#other-object-types">Other object types</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#consumables">Consumables</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#weapons">Weapons</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#magic">Magic</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#armor">Armor</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#your-bare-hands">Your Bare hands</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Objects.html#testing-and-extra-credits">Testing and Extra credits</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Equipment.html">Handling Equipment</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#equipmenthandler-that-saves">EquipmentHandler that saves</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#connecting-the-equipmenthandler">Connecting the EquipmentHandler</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#expanding-the-equipmenthandler">Expanding the Equipmenthandler</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#validate-slot-usage"><code class="docutils literal notranslate"><span class="pre">.validate_slot_usage</span></code></a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#max-slots"><code class="docutils literal notranslate"><span class="pre">.max_slots</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#count-slots"><code class="docutils literal notranslate"><span class="pre">.count_slots</span></code></a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#validating-slots">Validating slots</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#add-and-remove"><code class="docutils literal notranslate"><span class="pre">.add</span></code> and <code class="docutils literal notranslate"><span class="pre">.remove</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#moving-things-around">Moving things around</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#get-everything">Get everything</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#weapon-and-armor">Weapon and armor</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#extra-credits">Extra credits</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#unit-testing">Unit Testing</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Equipment.html#summary">Summary</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Chargen.html">Character Generation</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#how-it-will-work">How it will work</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#random-tables">Random tables</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#storing-state-of-the-menu">Storing state of the menu</a><ul>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#showing-the-sheet">Showing the sheet</a></li>
<li class="toctree-l3"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#apply-character">Apply character</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#initializing-evmenu">Initializing EvMenu</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#main-node-choosing-what-to-do">Main Node: Choosing what to do</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#node-changing-your-name">Node: Changing your name</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#node-swapping-abilities-around">Node: Swapping Abilities around</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#node-creating-the-character">Node: Creating the Character</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#tying-the-nodes-together">Tying the nodes together</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Chargen.html#conclusions">Conclusions</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Rooms.html">In-game Rooms</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-NPCs.html">Non-Player-Characters (NPCs)</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Quests.html">Game Quests</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Shops.html">In-game Shops</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Dungeon.html">Dynamically generated Dungeon</a></li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Commands.html">In-game Commands</a></li>
</ul>
</div>
</section>
@ -138,11 +247,11 @@ with using Evennia. This be of much use when doing your own thing later.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="../Part2/Planning-The-Tutorial-Game.html"
<p class="topless"><a href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html"
title="previous chapter">Planning our tutorial game</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Implementing-a-game-rule-system.html"
title="next chapter">Implementing a game rule system</a></p>
<p class="topless"><a href="Beginner-Tutorial-Utilities.html"
title="next chapter">Code structure and Utilities</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
@ -180,10 +289,10 @@ with using Evennia. This be of much use when doing your own thing later.</p>
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Implementing-a-game-rule-system.html" title="Implementing a game rule system"
<a href="Beginner-Tutorial-Utilities.html" title="Code structure and Utilities"
>next</a> |</li>
<li class="right" >
<a href="../Part2/Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
<a href="../Part2/Beginner-Tutorial-Planning-The-Tutorial-Game.html" title="Planning our tutorial game"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>

View file

@ -0,0 +1,141 @@
<!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>Game Quests &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="In-game Shops" href="Beginner-Tutorial-Shops.html" />
<link rel="prev" title="Non-Player-Characters (NPCs)" href="Beginner-Tutorial-NPCs.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Shops.html" title="In-game Shops"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-NPCs.html" title="Non-Player-Characters (NPCs)"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Game Quests</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="game-quests">
<h1>Game Quests<a class="headerlink" href="#game-quests" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This part of the Beginner tutorial is still being developed.</p>
</div>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-NPCs.html"
title="previous chapter">Non-Player-Characters (NPCs)</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Shops.html"
title="next chapter">In-game Shops</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Quests.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Quests.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Shops.html" title="In-game Shops"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-NPCs.html" title="Non-Player-Characters (NPCs)"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Game Quests</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,141 @@
<!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>In-game Rooms &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Non-Player-Characters (NPCs)" href="Beginner-Tutorial-NPCs.html" />
<link rel="prev" title="Character Generation" href="Beginner-Tutorial-Chargen.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-NPCs.html" title="Non-Player-Characters (NPCs)"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Chargen.html" title="Character Generation"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Rooms</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="in-game-rooms">
<h1>In-game Rooms<a class="headerlink" href="#in-game-rooms" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This part of the Beginner tutorial is still being developed.</p>
</div>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Chargen.html"
title="previous chapter">Character Generation</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-NPCs.html"
title="next chapter">Non-Player-Characters (NPCs)</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Rooms.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Rooms.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-NPCs.html" title="Non-Player-Characters (NPCs)"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Chargen.html" title="Character Generation"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Rooms</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,793 @@
<!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>Rules and dice rolling &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Player Characters" href="Beginner-Tutorial-Characters.html" />
<link rel="prev" title="Code structure and Utilities" href="Beginner-Tutorial-Utilities.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Characters.html" title="Player Characters"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Utilities.html" title="Code structure and Utilities"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Rules and dice rolling</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="rules-and-dice-rolling">
<h1>Rules and dice rolling<a class="headerlink" href="#rules-and-dice-rolling" title="Permalink to this headline"></a></h1>
<p>In <em>EvAdventure</em> we have decided to use the <a class="reference external" href="https://www.drivethrurpg.com/product/250888/Knave">Knave</a>
RPG ruleset. This is commercial, but released under Creative Commons 4.0, meaning its okay to share and
adapt <em>Knave</em> for any purpose, even commercially. If you dont want to buy it but still follow
along, you can find a <a class="reference external" href="http://abominablefancy.blogspot.com/2018/10/knaves-fancypants.html">free fan-version here</a>.</p>
<section id="summary-of-knave-rules">
<h2>Summary of <em>Knave</em> rules<a class="headerlink" href="#summary-of-knave-rules" title="Permalink to this headline"></a></h2>
<p>Knave, being inspired by early Dungeons &amp; Dragons, is very simple.</p>
<ul class="simple">
<li><p>It uses six Ability bonuses
<em>Strength</em> (STR), <em>Dexterity</em> (DEX), <em>Constitution</em> (CON), <em>Intelligence</em> (INT), <em>Wisdom</em> (WIS)
and <em>Charisma</em> (CHA). These are rated from <code class="docutils literal notranslate"><span class="pre">+1</span></code> to <code class="docutils literal notranslate"><span class="pre">+10</span></code>.</p></li>
<li><p>Rolls are made with a twenty-sided die (<code class="docutils literal notranslate"><span class="pre">1d20</span></code>), usually adding a suitable Ability bonus to the roll.</p></li>
<li><p>If you roll <em>with advantage</em>, you roll <code class="docutils literal notranslate"><span class="pre">2d20</span></code> and pick the
<em>highest</em> value, If you roll <em>with disadvantage</em>, you roll <code class="docutils literal notranslate"><span class="pre">2d20</span></code> and pick the <em>lowest</em>.</p></li>
<li><p>Rolling a natural <code class="docutils literal notranslate"><span class="pre">1</span></code> is a <em>critical failure</em>. A natural <code class="docutils literal notranslate"><span class="pre">20</span></code> is a <em>critical success</em>. Rolling such
in combat means your weapon or armor loses quality, which will eventually destroy it.</p></li>
<li><p>A <em>saving throw</em> (trying to succeed against the environment) means making a roll to beat <code class="docutils literal notranslate"><span class="pre">15</span></code> (always).
So if you are lifting a heavy stone and have <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+2</span></code>, youd roll <code class="docutils literal notranslate"><span class="pre">1d20</span> <span class="pre">+</span> <span class="pre">2</span></code> and hope the result
is higher than <code class="docutils literal notranslate"><span class="pre">15</span></code>.</p></li>
<li><p>An <em>opposed saving throw</em> means beating the enemys suitable Ability defense, which is always their
<code class="docutils literal notranslate"><span class="pre">Ability</span> <span class="pre">bonus</span> <span class="pre">+</span> <span class="pre">10</span></code>. So if you have <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+1</span></code> and are arm wrestling someone with <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+2</span></code>, you roll
<code class="docutils literal notranslate"><span class="pre">1d20</span> <span class="pre">+</span> <span class="pre">1</span></code> and hope to roll higher than <code class="docutils literal notranslate"><span class="pre">2</span> <span class="pre">+</span> <span class="pre">10</span> <span class="pre">=</span> <span class="pre">12</span></code>.</p></li>
<li><p>A special bonus is <code class="docutils literal notranslate"><span class="pre">Armor</span></code>, <code class="docutils literal notranslate"><span class="pre">+1</span></code> is unarmored, additional armor is given by equipment. Melee attacks
test <code class="docutils literal notranslate"><span class="pre">STR</span></code> versus the <code class="docutils literal notranslate"><span class="pre">Armor</span></code> defense value while ranged attacks uses <code class="docutils literal notranslate"><span class="pre">WIS</span></code> vs <code class="docutils literal notranslate"><span class="pre">Armor</span></code>.</p></li>
<li><p><em>Knave</em> has no skills or classes. Everyone can use all items and using magic means having a special
rune stone in your hands; one spell per stone and day.</p></li>
<li><p>A character has <code class="docutils literal notranslate"><span class="pre">CON</span> <span class="pre">+</span> <span class="pre">10</span></code> carry slots. Most normal items uses one slot, armor and large weapons uses
two or three.</p></li>
<li><p>Healing is random, <code class="docutils literal notranslate"><span class="pre">1d8</span> <span class="pre">+</span> <span class="pre">CON</span></code> health healed after food and sleep.</p></li>
<li><p>Monster difficulty is listed by hy many 1d8 HP they have; this is called their “hit die” or HD. If
needing to test Abilities, monsters have HD bonus in every Ability.</p></li>
<li><p>Monsters have a <em>morale rating</em>. When things go bad, they have a chance to panic and flee if
rolling <code class="docutils literal notranslate"><span class="pre">2d6</span></code> over their morale rating.</p></li>
<li><p>All Characters in <em>Knave</em> are mostly randomly generated. HP is <code class="docutils literal notranslate"><span class="pre">&lt;level&gt;d8</span></code> but we give every
new character max HP to start.</p></li>
<li><p><em>Knave</em> also have random tables, such as for starting equipment and to see if dying when
hitting 0. Death, if it happens, is permanent.</p></li>
</ul>
</section>
<section id="making-a-rule-module">
<h2>Making a rule module<a class="headerlink" href="#making-a-rule-module" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module mygame/evadventure/rules.py</p>
</div></blockquote>
<aside class="sidebar">
<p>A complete version of the rule module is found in
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.rules.html#evennia-contrib-tutorials-evadventure-rules"><span class="std std-ref">evennia/contrib/tutorials/evadventure/rules.py</span></a>.</p>
</aside>
<p>There are three broad sets of rules for most RPGS:</p>
<ul class="simple">
<li><p>Character generation rules, often only used during character creation</p></li>
<li><p>Regular gameplay rules - rolling dice and resolving game situations</p></li>
<li><p>Character improvement - getting and spending experience to improve the character</p></li>
</ul>
<p>We want our <code class="docutils literal notranslate"><span class="pre">rules</span></code> module to cover as many aspeects of what wed otherwise would have to look up
in a rulebook.</p>
</section>
<section id="rolling-dice">
<h2>Rolling dice<a class="headerlink" href="#rolling-dice" title="Permalink to this headline"></a></h2>
<p>We will start by making a dice roller. Lets group all of our dice rolling into a structure like this
(not functional code yet):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># get result of one generic roll, for any type and number of dice</span>
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># get result of normal d20 roll, with advantage/disadvantage (or not)</span>
<span class="k">def</span> <span class="nf">saving_throw</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># do a saving throw against a specific target number</span>
<span class="k">def</span> <span class="nf">opposed_saving_throw</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># do an opposed saving throw against a target&#39;s defense</span>
<span class="k">def</span> <span class="nf">roll_random_table</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># make a roll against a random table (loaded elsewere)</span>
<span class="k">def</span> <span class="nf">morale_check</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># roll a 2d6 morale check for a target</span>
<span class="k">def</span> <span class="nf">heal_from_rest</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># heal 1d8 when resting+eating, but not more than max value.</span>
<span class="k">def</span> <span class="nf">roll_death</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># roll to determine penalty when hitting 0 HP. </span>
<span class="n">dice</span> <span class="o">=</span> <span class="n">EvAdventureRollEngine</span><span class="p">()</span>
</pre></div>
</div>
<aside class="sidebar">
<p>This groups all dice-related code into one container that is easy to import. But its mostly a matter
of taste. You <em>could</em> also break up the class methods into normal functions at the top-level of the
module if you wanted.</p>
</aside>
<p>This structure (called a <em>singleton</em>) means we group all dice rolls into one class that we then initiate
into a variable <code class="docutils literal notranslate"><span class="pre">dice</span></code> at the end of the module. This means that we can do the following from other
modules:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">.rules</span> <span class="kn">import</span> <span class="n">dice</span>
<span class="n">dice</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d8&quot;</span><span class="p">)</span>
</pre></div>
</div>
<section id="generic-dice-roller">
<h3>Generic dice roller<a class="headerlink" href="#generic-dice-roller" title="Permalink to this headline"></a></h3>
<p>We want to be able to do <code class="docutils literal notranslate"><span class="pre">roll(&quot;1d20&quot;)</span></code> and get a random result back from the roll.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">roll_string</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Roll XdY dice, where X is the number of dice </span>
<span class="sd"> and Y the number of sides per die. </span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> roll_string (str): A dice string on the form XdY.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int: The result of the roll. </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># split the XdY input on the &#39;d&#39; one time</span>
<span class="n">number</span><span class="p">,</span> <span class="n">diesize</span> <span class="o">=</span> <span class="n">roll_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;d&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># convert from string to integers</span>
<span class="n">number</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">number</span><span class="p">)</span>
<span class="n">diesize</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">diesize</span><span class="p">)</span>
<span class="c1"># make the roll</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">diesize</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number</span><span class="p">))</span>
</pre></div>
</div>
<aside class="sidebar">
<p>For this tutorial we have opted to not use any contribs, so we create
our own dice roller. But normally you could instead use the <a class="reference internal" href="../../../Contribs/Contrib-Dice.html"><span class="doc std std-doc">dice</span></a> contrib for this.
Well point out possible helpful contribs in sidebars as we proceed.</p>
</aside>
<p>The <code class="docutils literal notranslate"><span class="pre">randint</span></code> standard Python library module produces a random integer<br />
in a specific range. The line</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nb">sum</span><span class="p">(</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">diesize</span><span class="p">)</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number</span><span class="p">))</span>
</pre></div>
</div>
<p>works like this:</p>
<ul class="simple">
<li><p>For a certain <code class="docutils literal notranslate"><span class="pre">number</span></code> of times …</p></li>
<li><p>… create a random integer between <code class="docutils literal notranslate"><span class="pre">1</span></code> and <code class="docutils literal notranslate"><span class="pre">diesize</span></code></p></li>
<li><p>… and <code class="docutils literal notranslate"><span class="pre">sum</span></code> all those integers together.</p></li>
</ul>
<p>You could write the same thing less compactly like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">rolls</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">number</span><span class="p">):</span>
<span class="n">random_result</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">diesize</span><span class="p">)</span>
<span class="n">rolls</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">random_result</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">sum</span><span class="p">(</span><span class="n">rolls</span><span class="p">)</span>
</pre></div>
</div>
<aside class="sidebar">
<p>Note that <code class="docutils literal notranslate"><span class="pre">range</span></code> generates a value <code class="docutils literal notranslate"><span class="pre">0...number-1</span></code>. We use <code class="docutils literal notranslate"><span class="pre">_</span></code> in the <code class="docutils literal notranslate"><span class="pre">for</span></code> loop to
indicate we dont really care what this value is - we just want to repeat the loop
a certain amount of times.</p>
</aside>
<p>We dont ever expect end users to call this method; if we did, we would have to validate the inputs
much more - We would have to make sure that <code class="docutils literal notranslate"><span class="pre">number</span></code> or <code class="docutils literal notranslate"><span class="pre">diesize</span></code> are valid inputs and not
crazy big so the loop takes forever!</p>
</section>
<section id="rolling-with-advantage">
<h3>Rolling with advantage<a class="headerlink" href="#rolling-with-advantage" title="Permalink to this headline"></a></h3>
<p>Now that we have the generic roller, we can start using it to do a more complex roll.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="n">roll_string</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">advantage</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="p">(</span><span class="n">advantage</span> <span class="ow">or</span> <span class="n">disadvantage</span><span class="p">)</span> <span class="ow">or</span> <span class="p">(</span><span class="n">advantage</span> <span class="ow">and</span> <span class="n">disadvantage</span><span class="p">):</span>
<span class="c1"># normal roll - advantage/disadvantage not set or they cancel </span>
<span class="c1"># each other out </span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">advantage</span><span class="p">:</span>
<span class="c1"># highest of two d20 rolls</span>
<span class="k">return</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># disadvantage - lowest of two d20 rolls </span>
<span class="k">return</span> <span class="nb">min</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d20&quot;</span><span class="p">))</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">min()</span></code> and <code class="docutils literal notranslate"><span class="pre">max()</span></code> functions are standard Python fare for getting the biggest/smallest
of two arguments.</p>
</section>
<section id="saving-throws">
<h3>Saving throws<a class="headerlink" href="#saving-throws" title="Permalink to this headline"></a></h3>
<p>We want the saving throw to itself figure out if it succeeded or not. This means it needs to know
the Ability bonus (like STR <code class="docutils literal notranslate"><span class="pre">+1</span></code>). It would be convenient if we could just pass the entity
doing the saving throw to this method, tell it what type of save was needed, and then
have it figure things out:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">result</span><span class="p">,</span> <span class="n">quality</span> <span class="o">=</span> <span class="n">dice</span><span class="o">.</span><span class="n">saving_throw</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">)</span>
</pre></div>
</div>
<p>The return will be a boolean <code class="docutils literal notranslate"><span class="pre">True/False</span></code> if they pass, as well as a <code class="docutils literal notranslate"><span class="pre">quality</span></code> that tells us if
a perfect fail/success was rolled or not.</p>
<p>To make the saving throw method this clever, we need to think some more about how we want to store our
data on the character.</p>
<p>For our purposes it sounds reasonable that we will be using <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> for storing
the Ability scores. To make it easy, we will name them the same as the
<a class="reference internal" href="Beginner-Tutorial-Utilities.html#enums"><span class="std std-doc">Enum values</span></a> we set up in the previous lesson. So if we have
an enum <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">=</span> <span class="pre">&quot;strength&quot;</span></code>, we want to store the Ability on the character as an Attribute <code class="docutils literal notranslate"><span class="pre">strength</span></code>.</p>
<p>From the Attribute documentation, we can see that we can use <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> to make it so the
Attribute is available as <code class="docutils literal notranslate"><span class="pre">character.strength</span></code>, and this is what we will do.</p>
<p>So, in short, well create the saving throws method with the assumption that we will be able to do
<code class="docutils literal notranslate"><span class="pre">character.strength</span></code>, <code class="docutils literal notranslate"><span class="pre">character.constitution</span></code>, <code class="docutils literal notranslate"><span class="pre">character.charisma</span></code> etc to get the relevant Abilities.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">saving_throw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="n">bonus_type</span><span class="o">=</span><span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">,</span> <span class="n">target</span><span class="o">=</span><span class="mi">15</span><span class="p">,</span>
<span class="n">advantage</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Do a saving throw, trying to beat a target.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> character (Character): A character (assumed to have Ability bonuses</span>
<span class="sd"> stored on itself as Attributes).</span>
<span class="sd"> bonus_type (Ability): A valid Ability bonus enum.</span>
<span class="sd"> target (int): The target number to beat. Always 15 in Knave.</span>
<span class="sd"> advantage (bool): If character has advantage on this roll.</span>
<span class="sd"> disadvantage (bool): If character has disadvantage on this roll.</span>
<span class="sd"> </span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: A tuple (bool, Ability), showing if the throw succeeded and </span>
<span class="sd"> the quality is one of None or Ability.CRITICAL_FAILURE/SUCCESS</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># make a roll </span>
<span class="n">dice_roll</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="n">advantage</span><span class="p">,</span> <span class="n">disadvantage</span><span class="p">)</span>
<span class="c1"># figure out if we had critical failure/success</span>
<span class="n">quality</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">dice_roll</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">quality</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CRITICAL_FAILURE</span>
<span class="k">elif</span> <span class="n">dice_roll</span> <span class="o">==</span> <span class="mi">20</span><span class="p">:</span>
<span class="n">quality</span> <span class="o">=</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CRITICAL_SUCCESS</span>
<span class="c1"># figure out bonus</span>
<span class="n">bonus</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">bonus_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># return a tuple (bool, quality)</span>
<span class="k">return</span> <span class="p">(</span><span class="n">dice_roll</span> <span class="o">+</span> <span class="n">bonus</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">target</span><span class="p">,</span> <span class="n">quality</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">getattr(obj,</span> <span class="pre">attrname,</span> <span class="pre">default)</span></code> function is a very useful Python tool for getting an attribute
off an object and getting a default value if the attribute is not defined.</p>
</section>
<section id="opposed-saving-throw">
<h3>Opposed saving throw<a class="headerlink" href="#opposed-saving-throw" title="Permalink to this headline"></a></h3>
<p>With the building pieces we already created, this method is simple. Remember that the defense you have
to beat is always the relevant bonus + 10 in <em>Knave</em>. So if the enemy defends with <code class="docutils literal notranslate"><span class="pre">STR</span> <span class="pre">+3</span></code>, you must
roll higher than <code class="docutils literal notranslate"><span class="pre">13</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">roll</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">roll_with_advantage_or_disadvantage</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">saving_throw</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">opposed_saving_throw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attacker</span><span class="p">,</span> <span class="n">defender</span><span class="p">,</span>
<span class="n">attack_type</span><span class="o">=</span><span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="p">,</span> <span class="n">defense_type</span><span class="o">=</span><span class="n">Ability</span><span class="o">.</span><span class="n">ARMOR</span><span class="p">,</span>
<span class="n">advantage</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="n">defender_defense</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">defender</span><span class="p">,</span> <span class="n">defense_type</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="mi">10</span>
<span class="n">result</span><span class="p">,</span> <span class="n">quality</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">saving_throw</span><span class="p">(</span><span class="n">attacker</span><span class="p">,</span> <span class="n">bonus_type</span><span class="o">=</span><span class="n">attack_type</span><span class="p">,</span>
<span class="n">target</span><span class="o">=</span><span class="n">defender_defense</span><span class="p">,</span>
<span class="n">advantage</span><span class="o">=</span><span class="n">advantave</span><span class="p">,</span> <span class="n">disadvantage</span><span class="o">=</span><span class="n">disadvantage</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span><span class="p">,</span> <span class="n">quality</span>
</pre></div>
</div>
</section>
<section id="morale-check">
<h3>Morale check<a class="headerlink" href="#morale-check" title="Permalink to this headline"></a></h3>
<p>We will make the assumption that the <code class="docutils literal notranslate"><span class="pre">morale</span></code> value is available from the creature simply as
<code class="docutils literal notranslate"><span class="pre">monster.morale</span></code> - we need to remember to make this so later!</p>
<p>In <em>Knave</em>, a creature have roll with <code class="docutils literal notranslate"><span class="pre">2d6</span></code> equal or under its morale to not flee or surrender
when things go south. The standard morale value is 9.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">morale_check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">defender</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;2d6&quot;</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">defender</span><span class="p">,</span> <span class="s2">&quot;morale&quot;</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="roll-for-healing">
<h3>Roll for Healing<a class="headerlink" href="#roll-for-healing" title="Permalink to this headline"></a></h3>
<p>To be able to handle healing, we need to make some more assumptions about how we store
health on game entities. We will need <code class="docutils literal notranslate"><span class="pre">hp_max</span></code> (the total amount of available HP) and <code class="docutils literal notranslate"><span class="pre">hp</span></code>
(the current health value). We again assume these will be available as <code class="docutils literal notranslate"><span class="pre">obj.hp</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.hp_max</span></code>.</p>
<p>According to the rules, after consuming a ration and having a full nights sleep, a character regains
<code class="docutils literal notranslate"><span class="pre">1d8</span> <span class="pre">+</span> <span class="pre">CON</span></code> HP.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">heal_from_rest</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> A night&#39;s rest retains 1d8 + CON HP </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">con_bonus</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">Ability</span><span class="o">.</span><span class="n">CON</span><span class="o">.</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">character</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d8&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="n">con_bonus</span><span class="p">)</span>
</pre></div>
</div>
<p>We make another assumption here - that <code class="docutils literal notranslate"><span class="pre">character.heal()</span></code> is a thing. We tell this function how
much the character should heal, and it will do so, making sure to not heal more than its max
number of HPs</p>
<blockquote>
<div><p>Knowing what is available on the character and what rule rolls we need is a bit of a chicken-and-egg
problem. We will make sure to implement the matching <em>Character</em> class next lesson.</p>
</div></blockquote>
</section>
<section id="rolling-on-a-table">
<h3>Rolling on a table<a class="headerlink" href="#rolling-on-a-table" title="Permalink to this headline"></a></h3>
<p>We occasionally need to roll on a table - a selection of choices. There are two main table-types
we need to support:</p>
<p>Simply one element per row of the table (same odds to get each result).</p>
<table class="colwidths-auto docutils align-default">
<thead>
<tr class="row-odd"><th class="text-align:center head"><p>Result</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td class="text-align:center"><p>item1</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>item2</p></td>
</tr>
<tr class="row-even"><td class="text-align:center"><p>item3</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>item4</p></td>
</tr>
</tbody>
</table>
<p>This we will simply represent as a plain list</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="s2">&quot;item1&quot;</span><span class="p">,</span> <span class="s2">&quot;item2&quot;</span><span class="p">,</span> <span class="s2">&quot;item3&quot;</span><span class="p">,</span> <span class="s2">&quot;item4&quot;</span><span class="p">]</span>
</pre></div>
</div>
<p>Ranges per item (varying odds per result):</p>
<table class="colwidths-auto docutils align-default">
<thead>
<tr class="row-odd"><th class="text-align:center head"><p>Range</p></th>
<th class="text-align:center head"><p>Result</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td class="text-align:center"><p>1-5</p></td>
<td class="text-align:center"><p>item1</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>6-15</p></td>
<td class="text-align:center"><p>item2</p></td>
</tr>
<tr class="row-even"><td class="text-align:center"><p>16-19</p></td>
<td class="text-align:center"><p>item3</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>20</p></td>
<td class="text-align:center"><p>item4</p></td>
</tr>
</tbody>
</table>
<p>This we will represent as a list of tuples:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">[(</span><span class="s2">&quot;1-5&quot;</span><span class="p">,</span> <span class="s2">&quot;item1&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;6-15&quot;</span><span class="p">,</span> <span class="s2">&quot;item2&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;16-19&quot;</span><span class="p">,</span> <span class="s2">&quot;item4&quot;</span><span class="p">),</span> <span class="p">(</span><span class="s2">&quot;20&quot;</span><span class="p">,</span> <span class="s2">&quot;item5&quot;</span><span class="p">)]</span>
</pre></div>
</div>
<p>We also need to know what die to roll to get a result on the table (it may not always
be obvious, and in some games you could be asked to roll a lower dice to only get
early table results, for example).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span><span class="p">,</span> <span class="n">choice</span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">roll_random_table</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dieroll</span><span class="p">,</span> <span class="n">table_choices</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Args: </span>
<span class="sd"> dieroll (str): A die roll string, like &quot;1d20&quot;.</span>
<span class="sd"> table_choices (iterable): A list of either single elements or </span>
<span class="sd"> of tuples.</span>
<span class="sd"> Returns: </span>
<span class="sd"> Any: A random result from the given list of choices.</span>
<span class="sd"> </span>
<span class="sd"> Raises:</span>
<span class="sd"> RuntimeError: If rolling dice giving results outside the table.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">roll_result</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="n">dieroll</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">table_choices</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="p">(</span><span class="nb">tuple</span><span class="p">,</span> <span class="nb">list</span><span class="p">)):</span>
<span class="c1"># the first element is a tuple/list; treat as on the form [(&quot;1-5&quot;, &quot;item&quot;),...]</span>
<span class="k">for</span> <span class="p">(</span><span class="n">valrange</span><span class="p">,</span> <span class="n">choice</span><span class="p">)</span> <span class="ow">in</span> <span class="n">table_choices</span><span class="p">:</span>
<span class="n">minval</span><span class="p">,</span> <span class="o">*</span><span class="n">maxval</span> <span class="o">=</span> <span class="n">valrange</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">minval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">minval</span><span class="p">))</span>
<span class="n">maxval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">maxval</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">maxval</span> <span class="k">else</span> <span class="n">minval</span><span class="p">)</span>
<span class="k">if</span> <span class="n">minval</span> <span class="o">&lt;=</span> <span class="n">roll_result</span> <span class="o">&lt;=</span> <span class="n">maxval</span><span class="p">:</span>
<span class="k">return</span> <span class="n">choice</span>
<span class="c1"># if we get here we must have set a dieroll producing a value </span>
<span class="c1"># outside of the table boundaries - raise error</span>
<span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;roll_random_table: Invalid die roll&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># a simple regular list</span>
<span class="n">roll_result</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">min</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">table_choices</span><span class="p">),</span> <span class="n">roll_result</span><span class="p">))</span>
<span class="k">return</span> <span class="n">table_choices</span><span class="p">[</span><span class="n">roll_result</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span>
</pre></div>
</div>
<p>Check that you understand what this does.</p>
<p>This may be confusing:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">minval</span><span class="p">,</span> <span class="o">*</span><span class="n">maxval</span> <span class="o">=</span> <span class="n">valrange</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;-&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">minval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">minval</span><span class="p">))</span>
<span class="n">maxval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">maxval</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">maxval</span> <span class="k">else</span> <span class="n">minval</span><span class="p">)</span>
</pre></div>
</div>
<p>If <code class="docutils literal notranslate"><span class="pre">valrange</span></code> is the string <code class="docutils literal notranslate"><span class="pre">1-5</span></code>, then <code class="docutils literal notranslate"><span class="pre">valrange.split(&quot;-&quot;,</span> <span class="pre">1)</span></code> would result in a tuple <code class="docutils literal notranslate"><span class="pre">(&quot;1&quot;,</span> <span class="pre">&quot;5&quot;)</span></code>.
But if the string was in fact just <code class="docutils literal notranslate"><span class="pre">&quot;20&quot;</span></code> (possible for a single entry in an RPG table), this would
lead to an error since it would only split out a single element - and we expected two.</p>
<p>By using <code class="docutils literal notranslate"><span class="pre">*maxval</span></code> (with the <code class="docutils literal notranslate"><span class="pre">*</span></code>), <code class="docutils literal notranslate"><span class="pre">maxval</span></code> is told to expect <em>0 or more</em> elements in a tuple.
So the result for <code class="docutils literal notranslate"><span class="pre">1-5</span></code> will be <code class="docutils literal notranslate"><span class="pre">(&quot;1&quot;,</span> <span class="pre">(&quot;5&quot;,))</span></code> and for <code class="docutils literal notranslate"><span class="pre">20</span></code> it will become <code class="docutils literal notranslate"><span class="pre">(&quot;20&quot;,</span> <span class="pre">())</span></code>. In the line</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">maxval</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">maxval</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">if</span> <span class="n">maxval</span> <span class="k">else</span> <span class="n">minval</span><span class="p">)</span>
</pre></div>
</div>
<p>we check if <code class="docutils literal notranslate"><span class="pre">maxval</span></code> actually has a value <code class="docutils literal notranslate"><span class="pre">(&quot;5&quot;,)</span></code> or if its empty <code class="docutils literal notranslate"><span class="pre">()</span></code>. The result is either
<code class="docutils literal notranslate"><span class="pre">&quot;5&quot;</span></code> or the value of <code class="docutils literal notranslate"><span class="pre">minval</span></code>.</p>
</section>
<section id="roll-for-death">
<h3>Roll for death<a class="headerlink" href="#roll-for-death" title="Permalink to this headline"></a></h3>
<p>While original Knave suggests hitting 0 HP means insta-death, we will grab the optional “death table”
from the “prettified” Knaves optional rules to make it a little less punishing. We also changed the
result of <code class="docutils literal notranslate"><span class="pre">2</span></code> to dead since we dont simulate dismemberment in this tutorial:</p>
<table class="colwidths-auto docutils align-default">
<thead>
<tr class="row-odd"><th class="text-align:center head"><p>Roll</p></th>
<th class="text-align:center head"><p>Result</p></th>
<th class="text-align:center head"><p>-1d4 Loss of Ability</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td class="text-align:center"><p>1-2</p></td>
<td class="text-align:center"><p>dead</p></td>
<td class="text-align:center"><p>-</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>3</p></td>
<td class="text-align:center"><p>weakened</p></td>
<td class="text-align:center"><p>STR</p></td>
</tr>
<tr class="row-even"><td class="text-align:center"><p>4</p></td>
<td class="text-align:center"><p>unsteady</p></td>
<td class="text-align:center"><p>DEX</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>5</p></td>
<td class="text-align:center"><p>sickly</p></td>
<td class="text-align:center"><p>CON</p></td>
</tr>
<tr class="row-even"><td class="text-align:center"><p>6</p></td>
<td class="text-align:center"><p>addled</p></td>
<td class="text-align:center"><p>INT</p></td>
</tr>
<tr class="row-odd"><td class="text-align:center"><p>7</p></td>
<td class="text-align:center"><p>rattled</p></td>
<td class="text-align:center"><p>WIS</p></td>
</tr>
<tr class="row-even"><td class="text-align:center"><p>8</p></td>
<td class="text-align:center"><p>disfigured</p></td>
<td class="text-align:center"><p>CHA</p></td>
</tr>
</tbody>
</table>
<p>All the non-dead values map to a loss of 1d4 in one of the six Abilities (but you get HP back).
We need to map back to this from the above table. One also cannot have less than -10 Ability bonus,
if you do, you die too.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/rules.py </span>
<span class="n">death_table</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="s2">&quot;1-2&quot;</span><span class="p">,</span> <span class="s2">&quot;dead&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;3&quot;</span><span class="p">:</span> <span class="s2">&quot;strength&quot;</span><span class="p">,</span>
<span class="p">(</span><span class="s2">&quot;4&quot;</span><span class="p">:</span> <span class="s2">&quot;dexterity&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;5&quot;</span><span class="p">:</span> <span class="s2">&quot;constitution&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;6&quot;</span><span class="p">:</span> <span class="s2">&quot;intelligence&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;7&quot;</span><span class="p">:</span> <span class="s2">&quot;wisdom&quot;</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;8&quot;</span><span class="p">:</span> <span class="s2">&quot;charisma&quot;</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">class</span> <span class="nc">EvAdventureRollEngine</span><span class="p">:</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">roll_random_table</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># ... </span>
<span class="k">def</span> <span class="nf">roll_death</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="n">ability_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_random_table</span><span class="p">(</span><span class="s2">&quot;1d8&quot;</span><span class="p">,</span> <span class="n">death_table</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ability_name</span> <span class="o">==</span> <span class="s2">&quot;dead&quot;</span><span class="p">:</span>
<span class="c1"># TODO - kill the character! </span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">loss</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d4&quot;</span><span class="p">)</span>
<span class="n">current_ability</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">ability_name</span><span class="p">)</span>
<span class="n">current_ability</span> <span class="o">-=</span> <span class="n">loss</span>
<span class="k">if</span> <span class="n">current_ability</span> <span class="o">&lt;</span> <span class="o">-</span><span class="mi">10</span><span class="p">:</span>
<span class="c1"># TODO - kill the character!</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># refresh 1d4 health, but suffer 1d4 ability loss</span>
<span class="bp">self</span><span class="o">.</span><span class="n">heal</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d4&quot;</span><span class="p">)</span>
<span class="nb">setattr</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">ability_name</span><span class="p">,</span> <span class="n">current_ability</span><span class="p">)</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span>
<span class="s2">&quot;You survive your brush with death, and while you recover &quot;</span>
<span class="sa">f</span><span class="s2">&quot;some health, you permanently lose </span><span class="si">{</span><span class="n">loss</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">ability_name</span><span class="si">}</span><span class="s2"> instead.&quot;</span>
<span class="p">)</span>
<span class="n">dice</span> <span class="o">=</span> <span class="n">EvAdventureRollEngine</span><span class="p">()</span>
</pre></div>
</div>
<p>Here we roll on the death table from the rules to see what happens. We give the character
a message if they survive, to let them know what happened.</p>
<p>We dont yet know what killing the character technically means, so we mark this as <code class="docutils literal notranslate"><span class="pre">TODO</span></code> and
return to it in a later lesson. We just know that we need to do <em>something</em> here to kill off the
character!</p>
</section>
</section>
<section id="testing">
<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Make a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_rules.py</span></code></p>
</div></blockquote>
<p>Testing the <code class="docutils literal notranslate"><span class="pre">rules</span></code> module will also showcase some very useful tools when testing.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_rules.py </span>
<span class="kn">from</span> <span class="nn">unittest.mock</span> <span class="kn">import</span> <span class="n">patch</span>
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
<span class="kn">from</span> <span class="nn">..</span> <span class="kn">import</span> <span class="n">rules</span>
<span class="k">class</span> <span class="nc">TestEvAdventureRuleEngine</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;Called before every test method&quot;&quot;&quot;</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">roll_engine</span> <span class="o">=</span> <span class="n">rules</span><span class="o">.</span><span class="n">EvAdventureRollEngine</span><span class="p">()</span>
<span class="nd">@patch</span><span class="p">(</span><span class="s2">&quot;evadventure.rules.randint&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">test_roll</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mock_randint</span><span class="p">):</span>
<span class="n">mock_randint</span><span class="o">.</span><span class="n">return_value</span> <span class="o">=</span> <span class="mi">4</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll_engine</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;1d6&quot;</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">roll_engine</span><span class="o">.</span><span class="n">roll</span><span class="p">(</span><span class="s2">&quot;2d6&quot;</span><span class="p">,</span> <span class="mi">2</span> <span class="o">*</span> <span class="mi">4</span><span class="p">)</span>
<span class="c1"># test of the other rule methods below ...</span>
</pre></div>
</div>
<p>As before, run the specific test with</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests.test_rules
</pre></div>
</div>
<section id="mocking-and-patching">
<h3>Mocking and patching<a class="headerlink" href="#mocking-and-patching" title="Permalink to this headline"></a></h3>
<aside class="sidebar">
<p>In <a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.tests.test_rules.html#evennia-contrib-tutorials-evadventure-tests-test-rules"><span class="std std-ref">evennia/contrib/tutorials/evadventure/tests/test_rules.py</span></a>
has a complete example of rule testing.</p>
</aside>
<p>The <code class="docutils literal notranslate"><span class="pre">setUp</span></code> method is a special method of the testing class. It will be run before every
test method. We use <code class="docutils literal notranslate"><span class="pre">super().setUp()</span></code> to make sure the parent class version of this method
always fire. Then we create a fresh <code class="docutils literal notranslate"><span class="pre">EvAdventureRollEngine</span></code> we can test with.</p>
<p>In our test, we import <code class="docutils literal notranslate"><span class="pre">patch</span></code> from the <code class="docutils literal notranslate"><span class="pre">unittest.mock</span></code> library. This is a very useful tool for testing.
Normally the <code class="docutils literal notranslate"><span class="pre">randint</span></code> function we imported in <code class="docutils literal notranslate"><span class="pre">rules</span></code> will return a random value. Thats very hard to
test for, since the value will be different every test.</p>
<p>With <code class="docutils literal notranslate"><span class="pre">&#64;patch</span></code> (this is called a <em>decorator</em>), we temporarily replace <code class="docutils literal notranslate"><span class="pre">rules.randint</span></code> with a mock - a
dummy entity. This mock is passed into the testing method. We then take this <code class="docutils literal notranslate"><span class="pre">mock_randint</span></code> and set
<code class="docutils literal notranslate"><span class="pre">.return_value</span> <span class="pre">=</span> <span class="pre">4</span></code> on it.</p>
<p>Adding <code class="docutils literal notranslate"><span class="pre">return_value</span></code> to the mock means that every time this mock is called, it will return 4. For the
duration of the test we can now check with <code class="docutils literal notranslate"><span class="pre">self.assertEqual</span></code> that our <code class="docutils literal notranslate"><span class="pre">roll</span></code> method always returns a
result as-if the random result was 4.</p>
<p>There are <a class="reference external" href="https://realpython.com/python-mock-library/">many resources for understanding mock</a>, refer to
them for further help.</p>
<blockquote>
<div><p>The <code class="docutils literal notranslate"><span class="pre">EvAdventureRollEngine</span></code> have many methods to test. We leave this as an extra exercise!</p>
</div></blockquote>
</section>
</section>
<section id="summary">
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline"></a></h2>
<p>This concludes all the core rule mechanics of <em>Knave</em> - the rules used during play. We noticed here
that we are going to soon need to establish how our <em>Character</em> actually stores data. So we will
address that next.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Rules and dice rolling</a><ul>
<li><a class="reference internal" href="#summary-of-knave-rules">Summary of <em>Knave</em> rules</a></li>
<li><a class="reference internal" href="#making-a-rule-module">Making a rule module</a></li>
<li><a class="reference internal" href="#rolling-dice">Rolling dice</a><ul>
<li><a class="reference internal" href="#generic-dice-roller">Generic dice roller</a></li>
<li><a class="reference internal" href="#rolling-with-advantage">Rolling with advantage</a></li>
<li><a class="reference internal" href="#saving-throws">Saving throws</a></li>
<li><a class="reference internal" href="#opposed-saving-throw">Opposed saving throw</a></li>
<li><a class="reference internal" href="#morale-check">Morale check</a></li>
<li><a class="reference internal" href="#roll-for-healing">Roll for Healing</a></li>
<li><a class="reference internal" href="#rolling-on-a-table">Rolling on a table</a></li>
<li><a class="reference internal" href="#roll-for-death">Roll for death</a></li>
</ul>
</li>
<li><a class="reference internal" href="#testing">Testing</a><ul>
<li><a class="reference internal" href="#mocking-and-patching">Mocking and patching</a></li>
</ul>
</li>
<li><a class="reference internal" href="#summary">Summary</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Utilities.html"
title="previous chapter">Code structure and Utilities</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Characters.html"
title="next chapter">Player Characters</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Rules.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Rules.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Characters.html" title="Player Characters"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Utilities.html" title="Code structure and Utilities"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Rules and dice rolling</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,141 @@
<!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>In-game Shops &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Dynamically generated Dungeon" href="Beginner-Tutorial-Dungeon.html" />
<link rel="prev" title="Game Quests" href="Beginner-Tutorial-Quests.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Dungeon.html" title="Dynamically generated Dungeon"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Quests.html" title="Game Quests"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Shops</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="in-game-shops">
<h1>In-game Shops<a class="headerlink" href="#in-game-shops" title="Permalink to this headline"></a></h1>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This part of the Beginner tutorial is still being developed.</p>
</div>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Quests.html"
title="previous chapter">Game Quests</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Dungeon.html"
title="next chapter">Dynamically generated Dungeon</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Shops.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Shops.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Dungeon.html" title="Dynamically generated Dungeon"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Quests.html" title="Game Quests"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">In-game Shops</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -0,0 +1,435 @@
<!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>Code structure and Utilities &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Rules and dice rolling" href="Beginner-Tutorial-Rules.html" />
<link rel="prev" title="Part 3: How we get there" href="Beginner-Tutorial-Part3-Intro.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rules.html" title="Rules and dice rolling"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Code structure and Utilities</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="code-structure-and-utilities">
<h1>Code structure and Utilities<a class="headerlink" href="#code-structure-and-utilities" title="Permalink to this headline"></a></h1>
<p>In this lesson we will set up the file structure for <em>EvAdventure</em>. We will make some
utilities that will be useful later. We will also learn how to write <em>tests</em>.</p>
<section id="folder-structure">
<h2>Folder structure<a class="headerlink" href="#folder-structure" title="Permalink to this headline"></a></h2>
<p>Create a new folder under your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder, named <code class="docutils literal notranslate"><span class="pre">evadventure</span></code>. Inside it, create
another folder <code class="docutils literal notranslate"><span class="pre">tests/</span></code> and make sure to put empty <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> files in both. This turns both
folders into packages Python understands to import from.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mygame</span><span class="o">/</span>
<span class="n">commands</span><span class="o">/</span>
<span class="n">evadventure</span><span class="o">/</span> <span class="o">&lt;---</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span> <span class="o">&lt;---</span>
<span class="n">tests</span><span class="o">/</span> <span class="o">&lt;---</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span> <span class="o">&lt;---</span>
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">README</span><span class="o">.</span><span class="n">md</span>
<span class="n">server</span><span class="o">/</span>
<span class="n">typeclasses</span><span class="o">/</span>
<span class="n">web</span><span class="o">/</span>
<span class="n">world</span><span class="o">/</span>
</pre></div>
</div>
<p>Importing anything from inside this folder from anywhere else under <code class="docutils literal notranslate"><span class="pre">mygame</span></code> will be done by</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from anywhere in mygame/</span>
<span class="kn">from</span> <span class="nn">evadventure.yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
</pre></div>
</div>
<p>This is the absolute path` type of import.</p>
<p>Between two modules both in <code class="docutils literal notranslate"><span class="pre">evadventure/</span></code>, you can use a relative import with <code class="docutils literal notranslate"><span class="pre">.</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from a module inside mygame/evadventure</span>
<span class="kn">from</span> <span class="nn">.yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
</pre></div>
</div>
<p>From e.g. inside <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/</span></code> you can import from one level above using <code class="docutils literal notranslate"><span class="pre">..</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from mygame/evadventure/tests/ </span>
<span class="kn">from</span> <span class="nn">..yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
</pre></div>
</div>
</section>
<section id="enums">
<h2>Enums<a class="headerlink" href="#enums" title="Permalink to this headline"></a></h2>
<aside class="sidebar">
<p>A full example of the enum module is found in
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.enums.html#evennia-contrib-tutorials-evadventure-enums"><span class="std std-ref">evennia/contrib/tutorials/evadventure/enums.py</span></a>.</p>
</aside>
<p>Create a new file <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/enums.py</span></code>.</p>
<p>An <a class="reference external" href="https://docs.python.org/3/library/enum.html">enum</a> (enumeration) is a way to establish constants
in Python. Best is to show an example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in a file mygame/evadventure/enums.py</span>
<span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
<span class="k">class</span> <span class="nc">Ability</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">STR</span> <span class="o">=</span> <span class="s2">&quot;strength&quot;</span>
</pre></div>
</div>
<p>You access an enum like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># from another module in mygame/evadventure</span>
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
<span class="n">Ability</span><span class="o">.</span><span class="n">STR</span> <span class="c1"># the enum itself </span>
<span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="o">.</span><span class="n">value</span> <span class="c1"># this is the string &quot;strength&quot;</span>
</pre></div>
</div>
<p>Having enums is recommended practice. With them set up, it means we can make sure to refer to the
same thing every time. Having all enums in one place also means you have a good overview of the
constants you are dealing with.</p>
<p>The alternative would be to for example pass around a string <code class="docutils literal notranslate"><span class="pre">&quot;constitution&quot;</span></code>. If you mis-spell
this (<code class="docutils literal notranslate"><span class="pre">&quot;consitution&quot;</span></code>), you would not necessarily know it right away - the error would happen later
when the string is not recognized. If you make a typo getting <code class="docutils literal notranslate"><span class="pre">Ability.COM</span></code> instead of <code class="docutils literal notranslate"><span class="pre">Ability.CON</span></code>,
Python will immediately raise an error since this enum is not recognized.</p>
<p>With enums you can also do nice direct comparisons like <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">ability</span> <span class="pre">is</span> <span class="pre">Ability.WIS:</span> <span class="pre">&lt;do</span> <span class="pre">stuff&gt;</span></code>.</p>
<p>Note that the <code class="docutils literal notranslate"><span class="pre">Ability.STR</span></code> enum does not have the actual <em>value</em> of e.g. your Strength.
Its just a fixed label for the Strength ability.</p>
<p>Here is the <code class="docutils literal notranslate"><span class="pre">enum.py</span></code> module needed for <em>Knave</em>. It covers the basic aspects of
rule systems we need to track (check out the <em>Knave</em> rules. If you use another rule system youll
likely gradually expand on your enums as you figure out what youll need).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
<span class="k">class</span> <span class="nc">Ability</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The six base ability-bonuses and other </span>
<span class="sd"> abilities</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">STR</span> <span class="o">=</span> <span class="s2">&quot;strength&quot;</span>
<span class="n">DEX</span> <span class="o">=</span> <span class="s2">&quot;dexterity&quot;</span>
<span class="n">CON</span> <span class="o">=</span> <span class="s2">&quot;constitution&quot;</span>
<span class="n">INT</span> <span class="o">=</span> <span class="s2">&quot;intelligence&quot;</span>
<span class="n">WIS</span> <span class="o">=</span> <span class="s2">&quot;wisdom&quot;</span>
<span class="n">CHA</span> <span class="o">=</span> <span class="s2">&quot;charisma&quot;</span>
<span class="n">ARMOR</span> <span class="o">=</span> <span class="s2">&quot;armor&quot;</span>
<span class="n">CRITICAL_FAILURE</span> <span class="o">=</span> <span class="s2">&quot;critical_failure&quot;</span>
<span class="n">CRITICAL_SUCCESS</span> <span class="o">=</span> <span class="s2">&quot;critical_success&quot;</span>
<span class="n">ALLEGIANCE_HOSTILE</span> <span class="o">=</span> <span class="s2">&quot;hostile&quot;</span>
<span class="n">ALLEGIANCE_NEUTRAL</span> <span class="o">=</span> <span class="s2">&quot;neutral&quot;</span>
<span class="n">ALLEGIANCE_FRIENDLY</span> <span class="o">=</span> <span class="s2">&quot;friendly&quot;</span>
</pre></div>
</div>
<p>Here the <code class="docutils literal notranslate"><span class="pre">Ability</span></code> class holds basic properties of a character sheet.</p>
</section>
<section id="utility-module">
<h2>Utility module<a class="headerlink" href="#utility-module" title="Permalink to this headline"></a></h2>
<blockquote>
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/utils.py</span></code></p>
</div></blockquote>
<aside class="sidebar">
<p>An example of the utility module is found in
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.utils.html#evennia-contrib-tutorials-evadventure-utils"><span class="std std-ref">evennia/contrib/tutorials/evadventure/utils.py</span></a></p>
</aside>
<p>This is for general functions we may need from all over. In this case we only picture one utility,
a function that produces a pretty display of any object we pass to it.</p>
<p>This is an example of the string we want to see:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Chipped</span> <span class="n">Sword</span>
<span class="n">Value</span><span class="p">:</span> <span class="o">~</span><span class="mi">10</span> <span class="n">coins</span> <span class="p">[</span><span class="n">wielded</span> <span class="ow">in</span> <span class="n">Weapon</span> <span class="n">hand</span><span class="p">]</span>
<span class="n">A</span> <span class="n">simple</span> <span class="n">sword</span> <span class="n">used</span> <span class="n">by</span> <span class="n">mercenaries</span> <span class="nb">all</span> <span class="n">over</span>
<span class="n">the</span> <span class="n">world</span><span class="o">.</span>
<span class="n">Slots</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="n">Used</span> <span class="n">from</span><span class="p">:</span> <span class="n">weapon</span> <span class="n">hand</span>
<span class="n">Quality</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="n">Uses</span><span class="p">:</span> <span class="kc">None</span>
<span class="n">Attacks</span> <span class="n">using</span> <span class="n">strength</span> <span class="n">against</span> <span class="n">armor</span><span class="o">.</span>
<span class="n">Damage</span> <span class="n">roll</span><span class="p">:</span> <span class="mi">1</span><span class="n">d6</span>
</pre></div>
</div>
<p>Heres the start of how the function could look:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/utils.py</span>
<span class="n">_OBJ_STATS</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">|c</span><span class="si">{key}</span><span class="s2">|n</span>
<span class="s2">Value: ~|y</span><span class="si">{value}</span><span class="s2">|n coins</span><span class="si">{carried}</span><span class="s2"></span>
<span class="si">{desc}</span><span class="s2"></span>
<span class="s2">Slots: |w</span><span class="si">{size}</span><span class="s2">|n, Used from: |w</span><span class="si">{use_slot_name}</span><span class="s2">|n</span>
<span class="s2">Quality: |w</span><span class="si">{quality}</span><span class="s2">|n, Uses: |wuses|n</span>
<span class="s2">Attacks using |w</span><span class="si">{attack_type_name}</span><span class="s2">|n against |w</span><span class="si">{defense_type_name}</span><span class="s2">|n</span>
<span class="s2">Damage roll: |w</span><span class="si">{damage_roll}</span><span class="s2">|n</span>
<span class="s2">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">get_obj_stats</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">owner</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd"> Get a string of stats about the object.</span>
<span class="sd"> </span>
<span class="sd"> Args:</span>
<span class="sd"> obj (Object): The object to get stats for.</span>
<span class="sd"> owner (Object): The one currently owning/carrying `obj`, if any. Can be </span>
<span class="sd"> used to show e.g. where they are wielding it.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str: A nice info string to display about the object.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">_OBJ_STATS</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">key</span><span class="o">=</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
<span class="n">value</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
<span class="n">carried</span><span class="o">=</span><span class="s2">&quot;[Not carried]&quot;</span><span class="p">,</span>
<span class="n">desc</span><span class="o">=</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span><span class="p">,</span>
<span class="n">size</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
<span class="n">quality</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
<span class="n">uses</span><span class="o">=</span><span class="s2">&quot;infinite&quot;</span>
<span class="n">use_slot_name</span><span class="o">=</span><span class="s2">&quot;backpack&quot;</span><span class="p">,</span>
<span class="n">attack_type_name</span><span class="o">=</span><span class="s2">&quot;strength&quot;</span>
<span class="n">defense_type_name</span><span class="o">=</span><span class="s2">&quot;armor&quot;</span>
<span class="n">damage_roll</span><span class="o">=</span><span class="s2">&quot;1d6&quot;</span>
<span class="p">)</span>
</pre></div>
</div>
<p>Here we set up the string template with place holders for where every piece of info should go.
Study this string so you understand what it does. The <code class="docutils literal notranslate"><span class="pre">|c</span></code>, <code class="docutils literal notranslate"><span class="pre">|y</span></code>, <code class="docutils literal notranslate"><span class="pre">|w</span></code> and <code class="docutils literal notranslate"><span class="pre">|n</span></code> markers are
<a class="reference internal" href="../../../Concepts/Colors.html"><span class="doc std std-doc">Evennia color markup</span></a> for making the text cyan, yellow, white and neutral-color respectively.</p>
<p>We can guess some things, such that <code class="docutils literal notranslate"><span class="pre">obj.key</span></code> is the name of the object, and that <code class="docutils literal notranslate"><span class="pre">obj.db.desc</span></code> will
hold its description (this is how it is in default Evennia).</p>
<p>But so far we have not established how to get any of the other properties like <code class="docutils literal notranslate"><span class="pre">size</span></code> or <code class="docutils literal notranslate"><span class="pre">attack_type</span></code>.
So we just set them to dummy values. Well need to get back to this when we have more code in place!</p>
</section>
<section id="testing">
<h2>Testing<a class="headerlink" href="#testing" title="Permalink to this headline"></a></h2>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Its useful for any game dev to know how to effectively test their code. So well try to include a
<em>Testing</em> section at the end of each of the implementation lessons to follow. Writing tests for your code
is optional but highly recommended; it can feel a little cumbersome at first, but youll thank yourself later.</p>
</div>
<blockquote>
<div><p>create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_utils.py</span></code></p>
</div></blockquote>
<p>How do you know if you made a typo in the code above? You could <em>manually</em> test it by reloading your
Evennia server and do the following from in-game:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py from evadventure.utils import get_obj_stats;print(get_obj_stats(self))
</pre></div>
</div>
<p>You should get back a nice string about yourself! If that works, great! But youll need to remember
doing that test when you change this code later.</p>
<aside class="sidebar">
<p>In [evennia/contrib/tutorials/evadventure/tests/test_utils.py](evennia.contrib.tutorials.
evadventure.tests.test_utils)
is an example of the testing module. To dive deeper into unit testing in Evennia, see the
<a class="reference internal" href="../../../Coding/Unit-Testing.html"><span class="doc std std-doc">Unit testing</span></a> documentation.</p>
</aside>
<p>A <em>unit test</em> allows you to set up automated testing of code. Once youve written your test you
can run it over and over and make sure later changes to your code didnt break things.</p>
<p>In this particular case, we <em>expect</em> to later have to update the test when <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> becomes more
complete and returns more reasonable data.</p>
<p>Evennia comes with extensive functionality to help you test your code. Heres a module for
testing <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_utils.py</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span>
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
<span class="kn">from</span> <span class="nn">..import</span> <span class="n">utils</span>
<span class="k">class</span> <span class="nc">TestUtils</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">test_get_obj_stats</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># make a simple object to test with </span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span>
<span class="n">key</span><span class="o">=</span><span class="s2">&quot;testobj&quot;</span><span class="p">,</span>
<span class="n">attributes</span><span class="o">=</span><span class="p">((</span><span class="s2">&quot;desc&quot;</span><span class="p">,</span> <span class="s2">&quot;A test object&quot;</span><span class="p">),)</span>
<span class="p">)</span>
<span class="c1"># run it through the function </span>
<span class="n">result</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">get_obj_stats</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
<span class="c1"># check that the result is what we expected</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span>
<span class="n">result</span><span class="p">,</span>
<span class="sd">&quot;&quot;&quot; </span>
<span class="sd">|ctestobj|n</span>
<span class="sd">Value: ~|y10|n coins</span>
<span class="sd">A test object</span>
<span class="sd">Slots: |w1|n, Used from: |wbackpack|n</span>
<span class="sd">Quality: |w3|n, Uses: |winfinite|n</span>
<span class="sd">Attacks using |wstrength|n against |warmor|n</span>
<span class="sd">Damage roll: |w1d6|n</span>
<span class="sd">&quot;&quot;&quot;</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="p">)</span>
</pre></div>
</div>
<p>What happens here is that we create a new test-class <code class="docutils literal notranslate"><span class="pre">TestUtils</span></code> that inherits from <code class="docutils literal notranslate"><span class="pre">BaseEvenniaTest</span></code>.
This inheritance is what makes this a testing class.</p>
<p>We can have any number of methods on this class. To have a method recognized as one containing
code to test, its name <em>must</em> start with <code class="docutils literal notranslate"><span class="pre">test_</span></code>. We have one - <code class="docutils literal notranslate"><span class="pre">test_get_obj_stats</span></code>.</p>
<p>In this method we create a dummy <code class="docutils literal notranslate"><span class="pre">obj</span></code> and gives it a <code class="docutils literal notranslate"><span class="pre">key</span></code> “testobj”. Note how we add the
<code class="docutils literal notranslate"><span class="pre">desc</span></code> <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a> directly in the <code class="docutils literal notranslate"><span class="pre">create_object</span></code> call by specifying the attribute as a
tuple <code class="docutils literal notranslate"><span class="pre">(name,</span> <span class="pre">value)</span></code>!</p>
<p>We then get the result of passing this dummy-object through <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> we imported earlier.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">assertEqual</span></code> method is available on all testing classes and checks that the <code class="docutils literal notranslate"><span class="pre">result</span></code> is equal
to the string we specify. If they are the same, the test <em>passes</em>, otherwise it <em>fails</em> and we
need to investigate what went wrong.</p>
<section id="running-your-test">
<h3>Running your test<a class="headerlink" href="#running-your-test" title="Permalink to this headline"></a></h3>
<p>To run your test you need to stand inside your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder and execute the following command:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests
</pre></div>
</div>
<p>This will run all your <code class="docutils literal notranslate"><span class="pre">evadventure</span></code> tests (if you had more of them). To only run your utility tests
you could do</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests.test_utils
</pre></div>
</div>
<p>If all goes well, you should get an <code class="docutils literal notranslate"><span class="pre">OK</span></code> back. Otherwise you need to check the failure, maybe
your return string doesnt quite match what you expected.</p>
</section>
</section>
<section id="summary">
<h2>Summary<a class="headerlink" href="#summary" title="Permalink to this headline"></a></h2>
<p>Its very important to understand how you import code between modules in Python, so if this is still
confusing to you, its worth to read up on this more.</p>
<p>That said, many newcomers are confused with how to begin, so by creating the folder structure, some
small modules and even making your first unit test, you are off to a great start!</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Code structure and Utilities</a><ul>
<li><a class="reference internal" href="#folder-structure">Folder structure</a></li>
<li><a class="reference internal" href="#enums">Enums</a></li>
<li><a class="reference internal" href="#utility-module">Utility module</a></li>
<li><a class="reference internal" href="#testing">Testing</a><ul>
<li><a class="reference internal" href="#running-your-test">Running your test</a></li>
</ul>
</li>
<li><a class="reference internal" href="#summary">Summary</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Part3-Intro.html"
title="previous chapter">Part 3: How we get there</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
title="next chapter">Rules and dice rolling</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Utilities.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Beginner-Tutorial-Utilities.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Rules.html" title="Rules and dice rolling"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Code structure and Utilities</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -1,408 +0,0 @@
<!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>Implementing a game rule system &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Turn based Combat System" href="Turn-based-Combat-System.html" />
<link rel="prev" title="Part 3: How we get there" href="Beginner-Tutorial-Part3-Intro.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Turn-based-Combat-System.html" title="Turn based Combat System"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Implementing a game rule system</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="implementing-a-game-rule-system">
<h1>Implementing a game rule system<a class="headerlink" href="#implementing-a-game-rule-system" title="Permalink to this headline"></a></h1>
<p>The simplest way to create an online roleplaying game (at least from a code perspective) is to
simply grab a paperback RPG rule book, get a staff of game masters together and start to run scenes
with whomever logs in. Game masters can roll their dice in front of their computers and tell the
players the results. This is only one step away from a traditional tabletop game and puts heavy
demands on the staff - it is unlikely staff will be able to keep up around the clock even if they
are very dedicated.</p>
<p>Many games, even the most roleplay-dedicated, thus tend to allow for players to mediate themselves
to some extent. A common way to do this is to introduce <em>coded systems</em> - that is, to let the
computer do some of the heavy lifting. A basic thing is to add an online dice-roller so everyone can
make rolls and make sure noone is cheating. Somewhere at this level you find the most bare-bones
roleplaying MUSHes.</p>
<p>The advantage of a coded system is that as long as the rules are fair the computer is too - it makes
no judgement calls and holds no personal grudges (and cannot be accused of holding any). Also, the
computer doesnt need to sleep and can always be online regardless of when a player logs on. The
drawback is that a coded system is not flexible and wont adapt to the unprogrammed actions human
players may come up with in role play. For this reason many roleplay-heavy MUDs do a hybrid
variation - they use coded systems for things like combat and skill progression but leave role play
to be mostly freeform, overseen by staff game masters.</p>
<p>Finally, on the other end of the scale are less- or no-roleplay games, where game mechanics (and
thus player fairness) is the most important aspect. In such games the only events with in-game value
are those resulting from code. Such games are very common and include everything from hack-and-slash
MUDs to various tactical simulations.</p>
<p>So your first decision needs to be just what type of system you are aiming for. This page will try
to give some ideas for how to organize the “coded” part of your system, however big that may be.</p>
<section id="overall-system-infrastructure">
<h2>Overall system infrastructure<a class="headerlink" href="#overall-system-infrastructure" title="Permalink to this headline"></a></h2>
<p>We strongly recommend that you code your rule system as stand-alone as possible. That is, dont
spread your skill check code, race bonus calculation, die modifiers or what have you all over your
game.</p>
<ul>
<li><p>Put everything you would need to look up in a rule book into a module in <code class="docutils literal notranslate"><span class="pre">mygame/world</span></code>. Hide away
as much as you can. Think of it as a black box (or maybe the code representation of an all-knowing
game master). The rest of your game will ask this black box questions and get answers back. Exactly
how it arrives at those results should not need to be known outside the box. Doing it this way
makes it easier to change and update things in one place later.</p></li>
<li><p>Store only the minimum stuff you need with each game object. That is, if your Characters need
values for Health, a list of skills etc, store those things on the Character - dont store how to
roll or change them.</p></li>
<li><p>Next is to determine just how you want to store things on your Objects and Characters. You can
choose to either store things as individual <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a>, like <code class="docutils literal notranslate"><span class="pre">character.db.STR=34</span></code> and
<code class="docutils literal notranslate"><span class="pre">character.db.Hunting_skill=20</span></code>. But you could also use some custom storage method, like a
dictionary <code class="docutils literal notranslate"><span class="pre">character.db.skills</span> <span class="pre">=</span> <span class="pre">{&quot;Hunting&quot;:34,</span> <span class="pre">&quot;Fishing&quot;:20,</span> <span class="pre">...}</span></code>. A much more fancy solution is
to look at the Ainneve <a class="reference external" href="https://github.com/evennia/ainneve/blob/master/world/traits.py">Trait
handler</a>. Finally you could even go
with a <a class="reference internal" href="../../../Concepts/New-Models.html"><span class="doc std std-doc">custom django model</span></a>. Which is the better depends on your game and the
complexity of your system.</p></li>
<li><p>Make a clear <a class="reference external" href="https://en.wikipedia.org/wiki/Application_programming_interface">API</a> into your
rules. That is, make methods/functions that you feed with, say, your Character and which skill you
want to check. That is, you want something similar to this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">world</span> <span class="kn">import</span> <span class="n">rules</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">rules</span><span class="o">.</span><span class="n">roll_skill</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="s2">&quot;hunting&quot;</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">rules</span><span class="o">.</span><span class="n">roll_challenge</span><span class="p">(</span><span class="n">character1</span><span class="p">,</span> <span class="n">character2</span><span class="p">,</span> <span class="s2">&quot;swords&quot;</span><span class="p">)</span>
</pre></div>
</div>
</li>
</ul>
<p>You might need to make these functions more or less complex depending on your game. For example the
properties of the room might matter to the outcome of a roll (if the room is dark, burning etc).
Establishing just what you need to send into your game mechanic module is a great way to also get a
feel for what you need to add to your engine.</p>
</section>
<section id="coded-systems">
<h2>Coded systems<a class="headerlink" href="#coded-systems" title="Permalink to this headline"></a></h2>
<p>Inspired by tabletop role playing games, most game systems mimic some sort of die mechanic. To this
end Evennia offers a full <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/contrib/dice.py">dice
roller</a> in its <code class="docutils literal notranslate"><span class="pre">contrib</span></code>
folder. For custom implementations, Python offers many ways to randomize a result using its in-built
<code class="docutils literal notranslate"><span class="pre">random</span></code> module. No matter how its implemented, we will in this text refer to the action of
determining an outcome as a “roll”.</p>
<p>In a freeform system, the result of the roll is just compared with values and people (or the game
master) just agree on what it means. In a coded system the result now needs to be processed somehow.
There are many things that may happen as a result of rule enforcement:</p>
<ul class="simple">
<li><p>Health may be added or deducted. This can effect the character in various ways.</p></li>
<li><p>Experience may need to be added, and if a level-based system is used, the player might need to be
informed they have increased a level.</p></li>
<li><p>Room-wide effects need to be reported to the room, possibly affecting everyone in the room.</p></li>
</ul>
<p>There are also a slew of other things that fall under “Coded systems”, including things like
weather, NPC artificial intelligence and game economy. Basically everything about the world that a
Game master would control in a tabletop role playing game can be mimicked to some level by coded
systems.</p>
</section>
<section id="example-of-rule-module">
<h2>Example of Rule module<a class="headerlink" href="#example-of-rule-module" title="Permalink to this headline"></a></h2>
<p>Here is a simple example of a rule module. This is what we assume about our simple example game:</p>
<ul class="simple">
<li><p>Characters have only four numerical values:</p>
<ul>
<li><p>Their <code class="docutils literal notranslate"><span class="pre">level</span></code>, which starts at 1.</p></li>
<li><p>A skill <code class="docutils literal notranslate"><span class="pre">combat</span></code>, which determines how good they are at hitting things. Starts between 5 and</p></li>
</ul>
</li>
</ul>
<ol class="simple">
<li><ul class="simple">
<li><p>Their Strength, <code class="docutils literal notranslate"><span class="pre">STR</span></code>, which determine how much damage they do. Starts between 1 and 10.</p></li>
<li><p>Their Health points, <code class="docutils literal notranslate"><span class="pre">HP</span></code>, which starts at 100.</p></li>
</ul>
</li>
</ol>
<ul class="simple">
<li><p>When a Character reaches <code class="docutils literal notranslate"><span class="pre">HP</span> <span class="pre">=</span> <span class="pre">0</span></code>, they are presumed “defeated”. Their HP is reset and they get a
failure message (as a stand-in for death code).</p></li>
<li><p>Abilities are stored as simple Attributes on the Character.</p></li>
<li><p>“Rolls” are done by rolling a 100-sided die. If the result is below the <code class="docutils literal notranslate"><span class="pre">combat</span></code> value, its a
success and damage is rolled. Damage is rolled as a six-sided die + the value of <code class="docutils literal notranslate"><span class="pre">STR</span></code> (for this
example we ignore weapons and assume <code class="docutils literal notranslate"><span class="pre">STR</span></code> is all that matters).</p></li>
<li><p>Every successful <code class="docutils literal notranslate"><span class="pre">attack</span></code> roll gives 1-3 experience points (<code class="docutils literal notranslate"><span class="pre">XP</span></code>). Every time the number of <code class="docutils literal notranslate"><span class="pre">XP</span></code>
reaches <code class="docutils literal notranslate"><span class="pre">(level</span> <span class="pre">+</span> <span class="pre">1)</span> <span class="pre">**</span> <span class="pre">2</span></code>, the Character levels up. When leveling up, the Characters <code class="docutils literal notranslate"><span class="pre">combat</span></code>
value goes up by 2 points and <code class="docutils literal notranslate"><span class="pre">STR</span></code> by one (this is a stand-in for a real progression system).</p></li>
</ul>
<section id="character">
<h3>Character<a class="headerlink" href="#character" title="Permalink to this headline"></a></h3>
<p>The Character typeclass is simple. It goes in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>. There is already
an empty <code class="docutils literal notranslate"><span class="pre">Character</span></code> class there that Evennia will look to and use.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Custom rule-restricted character. We randomize</span>
<span class="sd"> the initial skill and ability values bettween 1-10.</span>
<span class="sd"> &quot;&quot;&quot;</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 when first created&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">level</span> <span class="o">=</span> <span class="mi">1</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">HP</span> <span class="o">=</span> <span class="mi">100</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">XP</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">STR</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">10</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">combat</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">&#64;reload</span></code> the server to load up the new code. Doing <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">self</span></code> will however <em>not</em> show the new
Attributes on yourself. This is because the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook is only called on <em>new</em>
Characters. Your Character was already created and will thus not have them. To force a reload, use
the following command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@typeclass</span><span class="o">/</span><span class="n">force</span><span class="o">/</span><span class="n">reset</span> <span class="bp">self</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">self</span></code> command will now show the new Attributes.</p>
</section>
<section id="rule-module">
<h3>Rule module<a class="headerlink" href="#rule-module" title="Permalink to this headline"></a></h3>
<p>This is a module <code class="docutils literal notranslate"><span class="pre">mygame/world/rules.py</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randint</span>
<span class="k">def</span> <span class="nf">roll_hit</span><span class="p">():</span>
<span class="s2">&quot;Roll 1d100&quot;</span>
<span class="k">return</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">roll_dmg</span><span class="p">():</span>
<span class="s2">&quot;Roll 1d6&quot;</span>
<span class="k">return</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">6</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">check_defeat</span><span class="p">(</span><span class="n">character</span><span class="p">):</span>
<span class="s2">&quot;Checks if a character is &#39;defeated&#39;.&quot;</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">HP</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You fall down, defeated!&quot;</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">HP</span> <span class="o">=</span> <span class="mi">100</span> <span class="c1"># reset</span>
<span class="k">def</span> <span class="nf">add_XP</span><span class="p">(</span><span class="n">character</span><span class="p">,</span> <span class="n">amount</span><span class="p">):</span>
<span class="s2">&quot;Add XP to character, tracking level increases.&quot;</span>
<span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">XP</span> <span class="o">+=</span> <span class="n">amount</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">XP</span> <span class="o">&gt;=</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">level</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</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">level</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">STR</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">combat</span> <span class="o">+=</span> <span class="mi">2</span>
<span class="n">character</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 level </span><span class="si">{</span><span class="n">character</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">level</span><span class="si">}</span><span class="s2">!&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">skill_combat</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This determines outcome of combat. The one who</span>
<span class="sd"> rolls under their combat skill AND higher than</span>
<span class="sd"> their opponent&#39;s roll hits.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">char1</span><span class="p">,</span> <span class="n">char2</span> <span class="o">=</span> <span class="n">args</span>
<span class="n">roll1</span><span class="p">,</span> <span class="n">roll2</span> <span class="o">=</span> <span class="n">roll_hit</span><span class="p">(),</span> <span class="n">roll_hit</span><span class="p">()</span>
<span class="n">failtext_template</span> <span class="o">=</span> <span class="s2">&quot;You are hit by </span><span class="si">{attacker}</span><span class="s2"> for </span><span class="si">{dmg}</span><span class="s2"> damage!&quot;</span>
<span class="n">wintext_template</span> <span class="o">=</span> <span class="s2">&quot;You hit </span><span class="si">{target}</span><span class="s2"> for </span><span class="si">{dmg}</span><span class="s2"> damage!&quot;</span>
<span class="n">xp_gain</span> <span class="o">=</span> <span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="k">if</span> <span class="n">char1</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">combat</span> <span class="o">&gt;=</span> <span class="n">roll1</span> <span class="o">&gt;</span> <span class="n">roll2</span><span class="p">:</span>
<span class="c1"># char 1 hits</span>
<span class="n">dmg</span> <span class="o">=</span> <span class="n">roll_dmg</span><span class="p">()</span> <span class="o">+</span> <span class="n">char1</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">STR</span>
<span class="n">char1</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">wintext_template</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">char2</span><span class="p">,</span> <span class="n">dmg</span><span class="o">=</span><span class="n">dmg</span><span class="p">))</span>
<span class="n">add_XP</span><span class="p">(</span><span class="n">char1</span><span class="p">,</span> <span class="n">xp_gain</span><span class="p">)</span>
<span class="n">char2</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">failtext_template</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">attacker</span><span class="o">=</span><span class="n">char1</span><span class="p">,</span> <span class="n">dmg</span><span class="o">=</span><span class="n">dmg</span><span class="p">))</span>
<span class="n">char2</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">HP</span> <span class="o">-=</span> <span class="n">dmg</span>
<span class="n">check_defeat</span><span class="p">(</span><span class="n">char2</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">char2</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">combat</span> <span class="o">&gt;=</span> <span class="n">roll2</span> <span class="o">&gt;</span> <span class="n">roll1</span><span class="p">:</span>
<span class="c1"># char 2 hits</span>
<span class="n">dmg</span> <span class="o">=</span> <span class="n">roll_dmg</span><span class="p">()</span> <span class="o">+</span> <span class="n">char2</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">STR</span>
<span class="n">char1</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">failtext_template</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">attacker</span><span class="o">=</span><span class="n">char2</span><span class="p">,</span> <span class="n">dmg</span><span class="o">=</span><span class="n">dmg</span><span class="p">))</span>
<span class="n">char1</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">HP</span> <span class="o">-=</span> <span class="n">dmg</span>
<span class="n">check_defeat</span><span class="p">(</span><span class="n">char1</span><span class="p">)</span>
<span class="n">char2</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">wintext_template</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">char1</span><span class="p">,</span> <span class="n">dmg</span><span class="o">=</span><span class="n">dmg</span><span class="p">))</span>
<span class="n">add_XP</span><span class="p">(</span><span class="n">char2</span><span class="p">,</span> <span class="n">xp_gain</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># a draw</span>
<span class="n">drawtext</span> <span class="o">=</span> <span class="s2">&quot;Neither of you can find an opening.&quot;</span>
<span class="n">char1</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">drawtext</span><span class="p">)</span>
<span class="n">char2</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">drawtext</span><span class="p">)</span>
<span class="n">SKILLS</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;combat&quot;</span><span class="p">:</span> <span class="n">skill_combat</span><span class="p">}</span>
<span class="k">def</span> <span class="nf">roll_challenge</span><span class="p">(</span><span class="n">character1</span><span class="p">,</span> <span class="n">character2</span><span class="p">,</span> <span class="n">skillname</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Determine the outcome of a skill challenge between</span>
<span class="sd"> two characters based on the skillname given.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">skillname</span> <span class="ow">in</span> <span class="n">SKILLS</span><span class="p">:</span>
<span class="n">SKILLS</span><span class="p">[</span><span class="n">skillname</span><span class="p">](</span><span class="n">character1</span><span class="p">,</span> <span class="n">character2</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">RunTimeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Skillname </span><span class="si">{</span><span class="n">skillname</span><span class="si">}</span><span class="s2"> not found.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>These few functions implement the entirety of our simple rule system. We have a function to check
the “defeat” condition and reset the <code class="docutils literal notranslate"><span class="pre">HP</span></code> back to 100 again. We define a generic “skill” function.
Multiple skills could all be added with the same signature; our <code class="docutils literal notranslate"><span class="pre">SKILLS</span></code> dictionary makes it easy to
look up the skills regardless of what their actual functions are called. Finally, the access
function <code class="docutils literal notranslate"><span class="pre">roll_challenge</span></code> just picks the skill and gets the result.</p>
<p>In this example, the skill function actually does a lot - it not only rolls results, it also informs
everyone of their results via <code class="docutils literal notranslate"><span class="pre">character.msg()</span></code> calls.</p>
<p>Here is an example of usage in a game command:</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="kn">from</span> <span class="nn">world</span> <span class="kn">import</span> <span class="n">rules</span>
<span class="k">class</span> <span class="nc">CmdAttack</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> attack an opponent</span>
<span class="sd"> Usage:</span>
<span class="sd"> attack &lt;target&gt;</span>
<span class="sd"> This will attack a target in the same room, dealing</span>
<span class="sd"> damage with your bare hands.</span>
<span class="sd"> &quot;&quot;&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;Implementing combat&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;You need to pick a target to attack.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">target</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="n">target</span><span class="p">:</span>
<span class="n">rules</span><span class="o">.</span><span class="n">roll_challenge</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">target</span><span class="p">,</span> <span class="s2">&quot;combat&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Note how simple the command becomes and how generic you can make it. It becomes simple to offer any
number of Combat commands by just extending this functionality - you can easily roll challenges and
pick different skills to check. And if you ever decided to, say, change how to determine hit chance,
you dont have to change every command, but need only change the single <code class="docutils literal notranslate"><span class="pre">roll_hit</span></code> function inside
your <code class="docutils literal notranslate"><span class="pre">rules</span></code> module.</p>
</section>
</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="#">Implementing a game rule system</a><ul>
<li><a class="reference internal" href="#overall-system-infrastructure">Overall system infrastructure</a></li>
<li><a class="reference internal" href="#coded-systems">Coded systems</a></li>
<li><a class="reference internal" href="#example-of-rule-module">Example of Rule module</a><ul>
<li><a class="reference internal" href="#character">Character</a></li>
<li><a class="reference internal" href="#rule-module">Rule module</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Beginner-Tutorial-Part3-Intro.html"
title="previous chapter">Part 3: How we get there</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Turn-based-Combat-System.html"
title="next chapter">Turn based Combat System</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Implementing-a-game-rule-system.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Implementing-a-game-rule-system.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Turn-based-Combat-System.html" title="Turn based Combat System"
>next</a> |</li>
<li class="right" >
<a href="Beginner-Tutorial-Part3-Intro.html" title="Part 3: How we get there"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Implementing a game rule system</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -1,651 +0,0 @@
<!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>Turn based Combat System &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Making a sittable object" href="A-Sittable-Object.html" />
<link rel="prev" title="Implementing a game rule system" href="Implementing-a-game-rule-system.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="A-Sittable-Object.html" title="Making a sittable object"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Implementing-a-game-rule-system.html" title="Implementing a game rule system"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" accesskey="U">Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Turn based Combat System</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="turn-based-combat-system">
<h1>Turn based Combat System<a class="headerlink" href="#turn-based-combat-system" title="Permalink to this headline"></a></h1>
<p>This tutorial gives an example of a full, if simplified, combat system for Evennia. It was inspired
by the discussions held on the <a class="reference external" href="https://groups.google.com/forum/#%21msg/evennia/wnJNM2sXSfs/-dbLRrgWnYMJ">mailing
list</a>.</p>
<section id="overview-of-combat-system-concepts">
<h2>Overview of combat system concepts<a class="headerlink" href="#overview-of-combat-system-concepts" title="Permalink to this headline"></a></h2>
<p>Most MUDs will use some sort of combat system. There are several main variations:</p>
<ul class="simple">
<li><p><em>Freeform</em> - the simplest form of combat to implement, common to MUSH-style roleplaying games.
This means the system only supplies dice rollers or maybe commands to compare skills and spit out
the result. Dice rolls are done to resolve combat according to the rules of the game and to direct
the scene. A game master may be required to resolve rule disputes.</p></li>
<li><p><em>Twitch</em> - This is the traditional MUD hack&amp;slash style combat. In a twitch system there is often
no difference between your normal “move-around-and-explore mode” and the “combat mode”. You enter an
attack command and the system will calculate if the attack hits and how much damage was caused.
Normally attack commands have some sort of timeout or notion of recovery/balance to reduce the
advantage of spamming or client scripting. Whereas the simplest systems just means entering <code class="docutils literal notranslate"><span class="pre">kill</span> <span class="pre">&lt;target&gt;</span></code> over and over, more sophisticated twitch systems include anything from defensive stances
to tactical positioning.</p></li>
<li><p><em>Turn-based</em> - a turn based system means that the system pauses to make sure all combatants can
choose their actions before continuing. In some systems, such entered actions happen immediately
(like twitch-based) whereas in others the resolution happens simultaneously at the end of the turn.
The disadvantage of a turn-based system is that the game must switch to a “combat mode” and one also
needs to take special care of how to handle new combatants and the passage of time. The advantage is
that success is not dependent on typing speed or of setting up quick client macros. This potentially
allows for emoting as part of combat which is an advantage for roleplay-heavy games.</p></li>
</ul>
<p>To implement a freeform combat system all you need is a dice roller and a roleplaying rulebook. See
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/contrib/dice.py">contrib/dice.py</a> for an
example dice roller. To implement at twitch-based system you basically need a few combat
<a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc">commands</span></a>, possibly ones with a <a class="reference internal" href="../../Command-Cooldown.html"><span class="doc std std-doc">cooldown</span></a>. You also need a <a class="reference internal" href="Implementing-a-game-rule-system.html"><span class="doc std std-doc">game rule
module</span></a> that makes use of it. We will focus on the turn-based
variety here.</p>
</section>
<section id="tutorial-overview">
<h2>Tutorial overview<a class="headerlink" href="#tutorial-overview" title="Permalink to this headline"></a></h2>
<p>This tutorial will implement the slightly more complex turn-based combat system. Our example has the
following properties:</p>
<ul class="simple">
<li><p>Combat is initiated with <code class="docutils literal notranslate"><span class="pre">attack</span> <span class="pre">&lt;target&gt;</span></code>, this initiates the combat mode.</p></li>
<li><p>Characters may join an ongoing battle using <code class="docutils literal notranslate"><span class="pre">attack</span> <span class="pre">&lt;target&gt;</span></code> against a character already in
combat.</p></li>
<li><p>Each turn every combating character will get to enter two commands, their internal order matters
and they are compared one-to-one in the order given by each combatant. Use of <code class="docutils literal notranslate"><span class="pre">say</span></code> and <code class="docutils literal notranslate"><span class="pre">pose</span></code> is
free.</p></li>
<li><p>The commands are (in our example) simple; they can either <code class="docutils literal notranslate"><span class="pre">hit</span> <span class="pre">&lt;target&gt;</span></code>, <code class="docutils literal notranslate"><span class="pre">feint</span> <span class="pre">&lt;target&gt;</span></code> or
<code class="docutils literal notranslate"><span class="pre">parry</span> <span class="pre">&lt;target&gt;</span></code>. They can also <code class="docutils literal notranslate"><span class="pre">defend</span></code>, a generic passive defense. Finally they may choose to
<code class="docutils literal notranslate"><span class="pre">disengage/flee</span></code>.</p></li>
<li><p>When attacking we use a classic [rock-paper-scissors](<a class="reference external" href="https://en.wikipedia.org/wiki/Rock-paper-">https://en.wikipedia.org/wiki/Rock-paper-</a>
scissors) mechanic to determine success: <code class="docutils literal notranslate"><span class="pre">hit</span></code> defeats <code class="docutils literal notranslate"><span class="pre">feint</span></code>, which defeats <code class="docutils literal notranslate"><span class="pre">parry</span></code> which defeats
<code class="docutils literal notranslate"><span class="pre">hit</span></code>. <code class="docutils literal notranslate"><span class="pre">defend</span></code> is a general passive action that has a percentage chance to win against <code class="docutils literal notranslate"><span class="pre">hit</span></code>
(only).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">disengage/flee</span></code> must be entered two times in a row and will only succeed if there is no <code class="docutils literal notranslate"><span class="pre">hit</span></code>
against them in that time. If so they will leave combat mode.</p></li>
<li><p>Once every player has entered two commands, all commands are resolved in order and the result is
reported. A new turn then begins.</p></li>
<li><p>If players are too slow the turn will time out and any unset commands will be set to <code class="docutils literal notranslate"><span class="pre">defend</span></code>.</p></li>
</ul>
<p>For creating the combat system we will need the following components:</p>
<ul class="simple">
<li><p>A combat handler. This is the main mechanic of the system. This is a <a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Script</span></a> object
created for each combat. It is not assigned to a specific object but is shared by the combating
characters and handles all the combat information. Since Scripts are database entities it also means
that the combat will not be affected by a server reload.</p></li>
<li><p>A combat <a class="reference internal" href="../../../Components/Command-Sets.html"><span class="doc std std-doc">command set</span></a> with the relevant commands needed for combat, such as the
various attack/defend options and the <code class="docutils literal notranslate"><span class="pre">flee/disengage</span></code> command to leave the combat mode.</p></li>
<li><p>A rule resolution system. The basics of making such a module is described in the <a class="reference internal" href="Implementing-a-game-rule-system.html"><span class="doc std std-doc">rule system
tutorial</span></a>. We will only sketch such a module here for our end-turn
combat resolution.</p></li>
<li><p>An <code class="docutils literal notranslate"><span class="pre">attack</span></code> <a class="reference internal" href="../../../Components/Commands.html"><span class="doc std std-doc">command</span></a> for initiating the combat mode. This is added to the default
command set. It will create the combat handler and add the character(s) to it. It will also assign
the combat command set to the characters.</p></li>
</ul>
</section>
<section id="the-combat-handler">
<h2>The combat handler<a class="headerlink" href="#the-combat-handler" title="Permalink to this headline"></a></h2>
<p>The <em>combat handler</em> is implemented as a stand-alone <a class="reference internal" href="../../../Components/Scripts.html"><span class="doc std std-doc">Script</span></a>. This Script is created when
the first Character decides to attack another and is deleted when no one is fighting any more. Each
handler represents one instance of combat and one combat only. Each instance of combat can hold any
number of characters but each character can only be part of one combat at a time (a player would
need to disengage from the first combat before they could join another).</p>
<p>The reason we dont store this Script “on” any specific character is because any character may leave
the combat at any time. Instead the script holds references to all characters involved in the
combat. Vice-versa, all characters holds a back-reference to the current combat handler. While we
dont use this very much here this might allow the combat commands on the characters to access and
update the combat handler state directly.</p>
<p><em>Note: Another way to implement a combat handler would be to use a normal Python object and handle
time-keeping with the <a class="reference internal" href="../../../Components/TickerHandler.html"><span class="doc std std-doc">TickerHandler</span></a>. This would require either adding custom hook
methods on the character or to implement a custom child of the TickerHandler class to track turns.
Whereas the TickerHandler is easy to use, a Script offers more power in this case.</em></p>
<p>Here is a basic combat handler. Assuming our game folder is named <code class="docutils literal notranslate"><span class="pre">mygame</span></code>, we store it in
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/combat_handler.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/typeclasses/combat_handler.py</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
<span class="kn">from</span> <span class="nn">world.rules</span> <span class="kn">import</span> <span class="n">resolve_combat</span>
<span class="k">class</span> <span class="nc">CombatHandler</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This implements the combat handler.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># standard Script hooks </span>
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;Called when script is first created&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;combat_handler_</span><span class="si">{</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1000</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">&quot;handles combat&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">2</span> <span class="c1"># two minute timeout</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_delay</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">persistent</span> <span class="o">=</span> <span class="kc">True</span>
<span class="c1"># store all combatants</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># store all actions for each turn</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">turn_actions</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># number of actions entered per combatant</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">action_count</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">def</span> <span class="nf">_init_character</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This initializes handler back-reference </span>
<span class="sd"> and combat cmdset on a character</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">character</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span> <span class="o">=</span> <span class="bp">self</span>
<span class="n">character</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;commands.combat.CombatCmdSet&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">_cleanup_character</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove character from handler and clean </span>
<span class="sd"> it of the back-reference and cmdset</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">dbref</span> <span class="o">=</span> <span class="n">character</span><span class="o">.</span><span class="n">id</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">turn_actions</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">action_count</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span>
<span class="k">del</span> <span class="n">character</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span>
<span class="n">character</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s2">&quot;commands.combat.CombatCmdSet&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_start</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is called on first start but also when the script is restarted</span>
<span class="sd"> after a server reboot. We need to re-assign this combat handler to </span>
<span class="sd"> all characters as well as re-assign the cmdset.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">character</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_init_character</span><span class="p">(</span><span class="n">character</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_stop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;Called just before the script is stopped/destroyed.&quot;</span>
<span class="k">for</span> <span class="n">character</span> <span class="ow">in</span> <span class="nb">list</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">characters</span><span class="o">.</span><span class="n">values</span><span class="p">()):</span>
<span class="c1"># note: the list() call above disconnects list from database</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_cleanup_character</span><span class="p">(</span><span class="n">character</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is called every self.interval seconds (turn timeout) or </span>
<span class="sd"> when force_repeat is called (because everyone has entered their </span>
<span class="sd"> commands). We know this by checking the existence of the</span>
<span class="sd"> `normal_turn_end` NAttribute, set just before calling </span>
<span class="sd"> force_repeat.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">normal_turn_end</span><span class="p">:</span>
<span class="c1"># we get here because the turn ended normally</span>
<span class="c1"># (force_repeat was called) - no msg output</span>
<span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">normal_turn_end</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># turn timeout</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg_all</span><span class="p">(</span><span class="s2">&quot;Turn timer timed out. Continuing.&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">end_turn</span><span class="p">()</span>
<span class="c1"># Combat-handler methods</span>
<span class="k">def</span> <span class="nf">add_character</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="s2">&quot;Add combatant to handler&quot;</span>
<span class="n">dbref</span> <span class="o">=</span> <span class="n">character</span><span class="o">.</span><span class="n">id</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span> <span class="o">=</span> <span class="n">character</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">action_count</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">turn_actions</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&quot;defend&quot;</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="kc">None</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;defend&quot;</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="kc">None</span><span class="p">)]</span>
<span class="c1"># set up back-reference</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_init_character</span><span class="p">(</span><span class="n">character</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">remove_character</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">character</span><span class="p">):</span>
<span class="s2">&quot;Remove combatant from handler&quot;</span>
<span class="k">if</span> <span class="n">character</span><span class="o">.</span><span class="n">id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_cleanup_character</span><span class="p">(</span><span class="n">character</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">db</span><span class="o">.</span><span class="n">characters</span><span class="p">:</span>
<span class="c1"># if no more characters in battle, kill this handler</span>
<span class="bp">self</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">msg_all</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
<span class="s2">&quot;Send message to all combatants&quot;</span>
<span class="k">for</span> <span class="n">character</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">character</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">add_action</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called by combat commands to register an action with the handler.</span>
<span class="sd"> action - string identifying the action, like &quot;hit&quot; or &quot;parry&quot;</span>
<span class="sd"> character - the character performing the action</span>
<span class="sd"> target - the target character or None</span>
<span class="sd"> actions are stored in a dictionary keyed to each character, each</span>
<span class="sd"> of which holds a list of max 2 actions. An action is stored as</span>
<span class="sd"> a tuple (character, action, target). </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">dbref</span> <span class="o">=</span> <span class="n">character</span><span class="o">.</span><span class="n">id</span>
<span class="n">count</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">action_count</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span>
<span class="k">if</span> <span class="mi">0</span> <span class="o">&lt;=</span> <span class="n">count</span> <span class="o">&lt;=</span> <span class="mi">1</span><span class="p">:</span> <span class="c1"># only allow 2 actions </span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">turn_actions</span><span class="p">[</span><span class="n">dbref</span><span class="p">][</span><span class="n">count</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">action</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="n">target</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># report if we already used too many actions</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">action_count</span><span class="p">[</span><span class="n">dbref</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">def</span> <span class="nf">check_end_turn</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called by the command to eventually trigger </span>
<span class="sd"> the resolution of the turn. We check if everyone</span>
<span class="sd"> has added all their actions; if so we call force the</span>
<span class="sd"> script to repeat immediately (which will call</span>
<span class="sd"> `self.at_repeat()` while resetting all timers). </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">all</span><span class="p">(</span><span class="n">count</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="k">for</span> <span class="n">count</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">action_count</span><span class="o">.</span><span class="n">values</span><span class="p">()):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">normal_turn_end</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">force_repeat</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">end_turn</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This resolves all actions by calling the rules module. </span>
<span class="sd"> It then resets everything and starts the next turn. It</span>
<span class="sd"> is called by at_repeat().</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">resolve_combat</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">turn_actions</span><span class="p">)</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">db</span><span class="o">.</span><span class="n">characters</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
<span class="c1"># less than 2 characters in battle, kill this handler</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg_all</span><span class="p">(</span><span class="s2">&quot;Combat has ended&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># reset counters before next turn</span>
<span class="k">for</span> <span class="n">character</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">characters</span><span class="o">.</span><span class="n">values</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">characters</span><span class="p">[</span><span class="n">character</span><span class="o">.</span><span class="n">id</span><span class="p">]</span> <span class="o">=</span> <span class="n">character</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">action_count</span><span class="p">[</span><span class="n">character</span><span class="o">.</span><span class="n">id</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">turn_actions</span><span class="p">[</span><span class="n">character</span><span class="o">.</span><span class="n">id</span><span class="p">]</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&quot;defend&quot;</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="kc">None</span><span class="p">),</span>
<span class="p">(</span><span class="s2">&quot;defend&quot;</span><span class="p">,</span> <span class="n">character</span><span class="p">,</span> <span class="kc">None</span><span class="p">)]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg_all</span><span class="p">(</span><span class="s2">&quot;Next turn begins ...&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This implements all the useful properties of our combat handler. This Script will survive a reboot
and will automatically re-assert itself when it comes back online. Even the current state of the
combat should be unaffected since it is saved in Attributes at every turn. An important part to note
is the use of the Scripts standard <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook and the <code class="docutils literal notranslate"><span class="pre">force_repeat</span></code> method to end each turn.
This allows for everything to go through the same mechanisms with minimal repetition of code.</p>
<p>What is not present in this handler is a way for players to view the actions they set or to change
their actions once they have been added (but before the last one has added theirs). We leave this as
an exercise.</p>
</section>
<section id="combat-commands">
<h2>Combat commands<a class="headerlink" href="#combat-commands" title="Permalink to this headline"></a></h2>
<p>Our combat commands - the commands that are to be available to us during the combat - are (in our
example) very simple. In a full implementation the commands available might be determined by the
weapon(s) held by the player or by which skills they know.</p>
<p>We create them in <code class="docutils literal notranslate"><span class="pre">mygame/commands/combat.py</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/commands/combat.py</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">CmdHit</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> hit an enemy</span>
<span class="sd"> Usage:</span>
<span class="sd"> hit &lt;target&gt;</span>
<span class="sd"> Strikes the given enemy with your current weapon.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;hit&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;strike&quot;</span><span class="p">,</span> <span class="s2">&quot;slash&quot;</span><span class="p">]</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;combat&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;Implements the command&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Usage: hit &lt;target&gt;&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">:</span>
<span class="k">return</span>
<span class="n">ok</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span><span class="o">.</span><span class="n">add_action</span><span class="p">(</span><span class="s2">&quot;hit&quot;</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span>
<span class="n">target</span><span class="p">)</span>
<span class="k">if</span> <span class="n">ok</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;You add &#39;hit&#39; to the combat queue&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">msg</span><span class="p">(</span><span class="s2">&quot;You can only queue two actions per turn!&quot;</span><span class="p">)</span>
<span class="c1"># tell the handler to check if turn is over</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span><span class="o">.</span><span class="n">check_end_turn</span><span class="p">()</span>
</pre></div>
</div>
<p>The other commands <code class="docutils literal notranslate"><span class="pre">CmdParry</span></code>, <code class="docutils literal notranslate"><span class="pre">CmdFeint</span></code>, <code class="docutils literal notranslate"><span class="pre">CmdDefend</span></code> and <code class="docutils literal notranslate"><span class="pre">CmdDisengage</span></code> look basically the same.
We should also add a custom <code class="docutils literal notranslate"><span class="pre">help</span></code> command to list all the available combat commands and what they
do.</p>
<p>We just need to put them all in a cmdset. We do this at the end of the same module:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/commands/combat.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">CmdSet</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
<span class="k">class</span> <span class="nc">CombatCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;combat_cmdset&quot;</span>
<span class="n">mergetype</span> <span class="o">=</span> <span class="s2">&quot;Replace&quot;</span>
<span class="n">priority</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">no_exits</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdHit</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdParry</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdFeint</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdDefend</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdDisengage</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdHelp</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdPose</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdSay</span><span class="p">())</span>
</pre></div>
</div>
</section>
<section id="rules-module">
<h2>Rules module<a class="headerlink" href="#rules-module" title="Permalink to this headline"></a></h2>
<p>A general way to implement a rule module is found in the [rule system tutorial](Implementing-a-game-
rule-system). Proper resolution would likely require us to change our Characters to store things
like strength, weapon skills and so on. So for this example we will settle for a very simplistic
rock-paper-scissors kind of setup with some randomness thrown in. We will not deal with damage here
but just announce the results of each turn. In a real system the Character objects would hold stats
to affect their skills, their chosen weapon affect the choices, they would be able to lose health
etc.</p>
<p>Within each turn, there are “sub-turns”, each consisting of one action per character. The actions
within each sub-turn happens simultaneously and only once they have all been resolved we move on to
the next sub-turn (or end the full turn).</p>
<p><em>Note: In our simple example the sub-turns dont affect each other (except for <code class="docutils literal notranslate"><span class="pre">disengage/flee</span></code>),
nor do any effects carry over between turns. The real power of a turn-based system would be to add
real tactical possibilities here though; For example if your hit got parried you could be out of
balance and your next action would be at a disadvantage. A successful feint would open up for a
subsequent attack and so on …</em></p>
<p>Our rock-paper-scissor setup works like this:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">hit</span></code> beats <code class="docutils literal notranslate"><span class="pre">feint</span></code> and <code class="docutils literal notranslate"><span class="pre">flee/disengage</span></code>. It has a random chance to fail against <code class="docutils literal notranslate"><span class="pre">defend</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">parry</span></code> beats <code class="docutils literal notranslate"><span class="pre">hit</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">feint</span></code> beats <code class="docutils literal notranslate"><span class="pre">parry</span></code> and is then counted as a <code class="docutils literal notranslate"><span class="pre">hit</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">defend</span></code> does nothing but has a chance to beat <code class="docutils literal notranslate"><span class="pre">hit</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">flee/disengage</span></code> must succeed two times in a row (i.e. not beaten by a <code class="docutils literal notranslate"><span class="pre">hit</span></code> once during the
turn). If so the character leaves combat.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/world/rules.py</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="c1"># messages </span>
<span class="k">def</span> <span class="nf">resolve_combat</span><span class="p">(</span><span class="n">combat_handler</span><span class="p">,</span> <span class="n">actiondict</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is called by the combat handler</span>
<span class="sd"> actiondict is a dictionary with a list of two actions</span>
<span class="sd"> for each character:</span>
<span class="sd"> {char.id:[(action1, char, target), (action2, char, target)], ...}</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">flee</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># track number of flee commands per character</span>
<span class="k">for</span> <span class="n">isub</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
<span class="c1"># loop over sub-turns</span>
<span class="n">messages</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">subturn</span> <span class="ow">in</span> <span class="p">(</span><span class="n">sub</span><span class="p">[</span><span class="n">isub</span><span class="p">]</span> <span class="k">for</span> <span class="n">sub</span> <span class="ow">in</span> <span class="n">actiondict</span><span class="o">.</span><span class="n">values</span><span class="p">()):</span>
<span class="c1"># for each character, resolve the sub-turn</span>
<span class="n">action</span><span class="p">,</span> <span class="n">char</span><span class="p">,</span> <span class="n">target</span> <span class="o">=</span> <span class="n">subturn</span>
<span class="k">if</span> <span class="n">target</span><span class="p">:</span>
<span class="n">taction</span><span class="p">,</span> <span class="n">tchar</span><span class="p">,</span> <span class="n">ttarget</span> <span class="o">=</span> <span class="n">actiondict</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">id</span><span class="p">][</span><span class="n">isub</span><span class="p">]</span>
<span class="k">if</span> <span class="n">action</span> <span class="o">==</span> <span class="s2">&quot;hit&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;parry&quot;</span> <span class="ow">and</span> <span class="n">ttarget</span> <span class="o">==</span> <span class="n">char</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> tries to hit </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2">, but </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2"> parries the attack!&quot;</span>
<span class="p">)</span>
<span class="k">elif</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;defend&quot;</span> <span class="ow">and</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mf">0.5</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2"> defends against the attack by </span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2">.&quot;</span>
<span class="p">)</span>
<span class="k">elif</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;flee&quot;</span><span class="p">:</span>
<span class="n">flee</span><span class="p">[</span><span class="n">tchar</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> stops </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2"> from disengaging, with a hit!&quot;</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> hits </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2">, bypassing their </span><span class="si">{</span><span class="n">taction</span><span class="si">}</span><span class="s2">!&quot;</span>
<span class="p">)</span>
<span class="k">elif</span> <span class="n">action</span> <span class="o">==</span> <span class="s2">&quot;parry&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;hit&quot;</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> parries the attack by </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;feint&quot;</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> tries to parry, but </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2"> feints and hits!&quot;</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> parries to no avail.&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">action</span> <span class="o">==</span> <span class="s2">&quot;feint&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;parry&quot;</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> feints past </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2">&#39;s parry, landing a hit!&quot;</span>
<span class="p">)</span>
<span class="k">elif</span> <span class="n">taction</span> <span class="o">==</span> <span class="s2">&quot;hit&quot;</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> feints but is defeated by </span><span class="si">{</span><span class="n">tchar</span><span class="si">}</span><span class="s2">&#39;s hit!&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> feints to no avail.&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">action</span> <span class="o">==</span> <span class="s2">&quot;defend&quot;</span><span class="p">:</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> defends.&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">action</span> <span class="o">==</span> <span class="s2">&quot;flee&quot;</span><span class="p">:</span>
<span class="k">if</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">flee</span><span class="p">:</span>
<span class="n">flee</span><span class="p">[</span><span class="n">char</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">flee</span><span class="p">[</span><span class="n">char</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">messages</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> tries to disengage (two subsequent turns needed)&quot;</span>
<span class="p">)</span>
<span class="c1"># echo results of each subturn</span>
<span class="n">combat_handler</span><span class="o">.</span><span class="n">msg_all</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">messages</span><span class="p">))</span>
<span class="c1"># at the end of both sub-turns, test if anyone fled</span>
<span class="k">for</span> <span class="p">(</span><span class="n">char</span><span class="p">,</span> <span class="n">fleevalue</span><span class="p">)</span> <span class="ow">in</span> <span class="n">flee</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">fleevalue</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">combat_handler</span><span class="o">.</span><span class="n">msg_all</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">char</span><span class="si">}</span><span class="s2"> withdraws from combat.&quot;</span><span class="p">)</span>
<span class="n">combat_handler</span><span class="o">.</span><span class="n">remove_character</span><span class="p">(</span><span class="n">char</span><span class="p">)</span>
</pre></div>
</div>
<p>To make it simple (and to save space), this example rule module actually resolves each interchange
twice - first when it gets to each character and then again when handling the target. Also, since we
use the combat handlers <code class="docutils literal notranslate"><span class="pre">msg_all</span></code> method here, the system will get pretty spammy. To clean it up,
one could imagine tracking all the possible interactions to make sure each pair is only handled and
reported once.</p>
</section>
<section id="combat-initiator-command">
<h2>Combat initiator command<a class="headerlink" href="#combat-initiator-command" title="Permalink to this headline"></a></h2>
<p>This is the last component we need, a command to initiate combat. This will tie everything together.
We store this with the other combat commands.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/commands/combat.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_script</span>
<span class="k">class</span> <span class="nc">CmdAttack</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> initiates combat</span>
<span class="sd"> Usage:</span>
<span class="sd"> attack &lt;target&gt;</span>
<span class="sd"> This will initiate combat with &lt;target&gt;. If &lt;target is</span>
<span class="sd"> already in combat, you will join the combat. </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;attack&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;General&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;Handle command&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Usage: attack &lt;target&gt;&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">:</span>
<span class="k">return</span>
<span class="c1"># set up combat</span>
<span class="k">if</span> <span class="n">target</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span><span class="p">:</span>
<span class="c1"># target is already in combat - join it </span>
<span class="n">target</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span><span class="o">.</span><span class="n">add_character</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="n">target</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">combat_handler</span><span class="o">.</span><span class="n">msg_all</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="si">}</span><span class="s2"> joins combat!&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># create a new combat handler</span>
<span class="n">chandler</span> <span class="o">=</span> <span class="n">create_script</span><span class="p">(</span><span class="s2">&quot;combat_handler.CombatHandler&quot;</span><span class="p">)</span>
<span class="n">chandler</span><span class="o">.</span><span class="n">add_character</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
<span class="n">chandler</span><span class="o">.</span><span class="n">add_character</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;You attack </span><span class="si">{</span><span class="n">target</span><span class="si">}</span><span class="s2">! You are in combat.&quot;</span><span class="p">)</span>
<span class="n">target</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="si">}</span><span class="s2"> attacks you! You are in combat.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">attack</span></code> command will not go into the combat cmdset but rather into the default cmdset. See e.g.
the <a class="reference internal" href="../Part1/Adding-Commands.html"><span class="doc std std-doc">Adding Command Tutorial</span></a> if you are unsure about how to do this.</p>
</section>
<section id="expanding-the-example">
<h2>Expanding the example<a class="headerlink" href="#expanding-the-example" title="Permalink to this headline"></a></h2>
<p>At this point you should have a simple but flexible turn-based combat system. We have taken several
shortcuts and simplifications in this example. The output to the players is likely too verbose
during combat and too limited when it comes to informing about things surrounding it. Methods for
changing your commands or list them, view who is in combat etc is likely needed - this will require
play testing for each game and style. There is also currently no information displayed for other
people happening to be in the same room as the combat - some less detailed information should
probably be echoed to the room to
show others whats going on.</p>
</section>
</section>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<p><h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Turn based Combat System</a><ul>
<li><a class="reference internal" href="#overview-of-combat-system-concepts">Overview of combat system concepts</a></li>
<li><a class="reference internal" href="#tutorial-overview">Tutorial overview</a></li>
<li><a class="reference internal" href="#the-combat-handler">The combat handler</a></li>
<li><a class="reference internal" href="#combat-commands">Combat commands</a></li>
<li><a class="reference internal" href="#rules-module">Rules module</a></li>
<li><a class="reference internal" href="#combat-initiator-command">Combat initiator command</a></li>
<li><a class="reference internal" href="#expanding-the-example">Expanding the example</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Implementing-a-game-rule-system.html"
title="previous chapter">Implementing a game rule system</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="A-Sittable-Object.html"
title="next chapter">Making a sittable object</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Turn-based-Combat-System.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Turn-based-Combat-System.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="A-Sittable-Object.html" title="Making a sittable object"
>next</a> |</li>
<li class="right" >
<a href="Implementing-a-game-rule-system.html" title="Implementing a game rule system"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Intro.html" >Beginner Tutorial</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Intro.html" >Part 3: How we get there</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Turn based Combat System</a></li>
</ul>
<div class="develop">develop branch</div>
</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>

View file

@ -18,7 +18,7 @@
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
<link rel="next" title="Part 5: Showing the world" href="../Part5/Beginner-Tutorial-Part5-Intro.html" />
<link rel="prev" title="Making a sittable object" href="../Part3/A-Sittable-Object.html" />
<link rel="prev" title="In-game Commands" href="../Part3/Beginner-Tutorial-Commands.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
@ -33,7 +33,7 @@
<a href="../Part5/Beginner-Tutorial-Part5-Intro.html" title="Part 5: Showing the world"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="../Part3/A-Sittable-Object.html" title="Making a sittable object"
<a href="../Part3/Beginner-Tutorial-Commands.html" title="In-game Commands"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>
@ -116,8 +116,8 @@ and batchcode processors.</p>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="../Part3/A-Sittable-Object.html"
title="previous chapter">Making a sittable object</a></p>
<p class="topless"><a href="../Part3/Beginner-Tutorial-Commands.html"
title="previous chapter">In-game Commands</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="../Part5/Beginner-Tutorial-Part5-Intro.html"
title="next chapter">Part 5: Showing the world</a></p>
@ -161,7 +161,7 @@ and batchcode processors.</p>
<a href="../Part5/Beginner-Tutorial-Part5-Intro.html" title="Part 5: Showing the world"
>next</a> |</li>
<li class="right" >
<a href="../Part3/A-Sittable-Object.html" title="Making a sittable object"
<a href="../Part3/Beginner-Tutorial-Commands.html" title="In-game Commands"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howtos</a> &#187;</li>