evennia/docs/1.0-dev/_modules/evennia/contrib/extended_room.html
2021-03-06 01:37:43 +01:00

698 lines
No EOL
75 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.contrib.extended_room &#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" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.contrib.extended_room</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.contrib.extended_room</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Extended Room</span>
<span class="sd">Evennia Contribution - Griatch 2012, vincent-lg 2019</span>
<span class="sd">This is an extended Room typeclass for Evennia. It is supported</span>
<span class="sd">by an extended `Look` command and an extended `desc` command, also</span>
<span class="sd">in this module.</span>
<span class="sd">Features:</span>
<span class="sd">1) Time-changing description slots</span>
<span class="sd">This allows to change the full description text the room shows</span>
<span class="sd">depending on larger time variations. Four seasons (spring, summer,</span>
<span class="sd">autumn and winter) are used by default. The season is calculated</span>
<span class="sd">on-demand (no Script or timer needed) and updates the full text block.</span>
<span class="sd">There is also a general description which is used as fallback if</span>
<span class="sd">one or more of the seasonal descriptions are not set when their</span>
<span class="sd">time comes.</span>
<span class="sd">An updated `desc` command allows for setting seasonal descriptions.</span>
<span class="sd">The room uses the `evennia.utils.gametime.GameTime` global script. This is</span>
<span class="sd">started by default, but if you have deactivated it, you need to</span>
<span class="sd">supply your own time keeping mechanism.</span>
<span class="sd">2) In-description changing tags</span>
<span class="sd">Within each seasonal (or general) description text, you can also embed</span>
<span class="sd">time-of-day dependent sections. Text inside such a tag will only show</span>
<span class="sd">during that particular time of day. The tags looks like `&lt;timeslot&gt; ...</span>
<span class="sd">&lt;/timeslot&gt;`. By default there are four timeslots per day - morning,</span>
<span class="sd">afternoon, evening and night.</span>
<span class="sd">3) Details</span>
<span class="sd">The Extended Room can be &quot;detailed&quot; with special keywords. This makes</span>
<span class="sd">use of a special `Look` command. Details are &quot;virtual&quot; targets to look</span>
<span class="sd">at, without there having to be a database object created for it. The</span>
<span class="sd">Details are simply stored in a dictionary on the room and if the look</span>
<span class="sd">command cannot find an object match for a `look &lt;target&gt;` command it</span>
<span class="sd">will also look through the available details at the current location</span>
<span class="sd">if applicable. The `@detail` command is used to change details.</span>
<span class="sd">4) Extra commands</span>
<span class="sd"> CmdExtendedRoomLook - look command supporting room details</span>
<span class="sd"> CmdExtendedRoomDesc - desc command allowing to add seasonal descs,</span>
<span class="sd"> CmdExtendedRoomDetail - command allowing to manipulate details in this room</span>
<span class="sd"> as well as listing them</span>
<span class="sd"> CmdExtendedRoomGameTime - A simple `time` command, displaying the current</span>
<span class="sd"> time and season.</span>
<span class="sd">Installation/testing:</span>
<span class="sd">Adding the `ExtendedRoomCmdset` to the default character cmdset will add all</span>
<span class="sd">new commands for use.</span>
<span class="sd">In more detail, in mygame/commands/default_cmdsets.py:</span>
<span class="sd">```</span>
<span class="sd">...</span>
<span class="sd">from evennia.contrib import extended_room # &lt;-new</span>
<span class="sd">class CharacterCmdset(default_cmds.Character_CmdSet):</span>
<span class="sd"> ...</span>
<span class="sd"> def at_cmdset_creation(self):</span>
<span class="sd"> ...</span>
<span class="sd"> self.add(extended_room.ExtendedRoomCmdSet) # &lt;-new</span>
<span class="sd">```</span>
<span class="sd">Then reload to make the bew commands available. Note that they only work</span>
<span class="sd">on rooms with the typeclass `ExtendedRoom`. Create new rooms with the right</span>
<span class="sd">typeclass or use the `typeclass` command to swap existing rooms.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">datetime</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultRoom</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">gametime</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">CmdSet</span>
<span class="c1"># error return function, needed by Extended Look command</span>
<span class="n">_AT_SEARCH_RESULT</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">variable_from_module</span><span class="p">(</span><span class="o">*</span><span class="n">settings</span><span class="o">.</span><span class="n">SEARCH_AT_RESULT</span><span class="o">.</span><span class="n">rsplit</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="c1"># regexes for in-desc replacements</span>
<span class="n">RE_MORNING</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;&lt;morning&gt;(.*?)&lt;/morning&gt;&quot;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">)</span>
<span class="n">RE_AFTERNOON</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;&lt;afternoon&gt;(.*?)&lt;/afternoon&gt;&quot;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">)</span>
<span class="n">RE_EVENING</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;&lt;evening&gt;(.*?)&lt;/evening&gt;&quot;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">)</span>
<span class="n">RE_NIGHT</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;&lt;night&gt;(.*?)&lt;/night&gt;&quot;</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">)</span>
<span class="c1"># this map is just a faster way to select the right regexes (the first</span>
<span class="c1"># regex in each tuple will be parsed, the following will always be weeded out)</span>
<span class="n">REGEXMAP</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;morning&quot;</span><span class="p">:</span> <span class="p">(</span><span class="n">RE_MORNING</span><span class="p">,</span> <span class="n">RE_AFTERNOON</span><span class="p">,</span> <span class="n">RE_EVENING</span><span class="p">,</span> <span class="n">RE_NIGHT</span><span class="p">),</span>
<span class="s2">&quot;afternoon&quot;</span><span class="p">:</span> <span class="p">(</span><span class="n">RE_AFTERNOON</span><span class="p">,</span> <span class="n">RE_MORNING</span><span class="p">,</span> <span class="n">RE_EVENING</span><span class="p">,</span> <span class="n">RE_NIGHT</span><span class="p">),</span>
<span class="s2">&quot;evening&quot;</span><span class="p">:</span> <span class="p">(</span><span class="n">RE_EVENING</span><span class="p">,</span> <span class="n">RE_MORNING</span><span class="p">,</span> <span class="n">RE_AFTERNOON</span><span class="p">,</span> <span class="n">RE_NIGHT</span><span class="p">),</span>
<span class="s2">&quot;night&quot;</span><span class="p">:</span> <span class="p">(</span><span class="n">RE_NIGHT</span><span class="p">,</span> <span class="n">RE_MORNING</span><span class="p">,</span> <span class="n">RE_AFTERNOON</span><span class="p">,</span> <span class="n">RE_EVENING</span><span class="p">),</span>
<span class="p">}</span>
<span class="c1"># set up the seasons and time slots. This assumes gametime started at the</span>
<span class="c1"># beginning of the year (so month 1 is equivalent to January), and that</span>
<span class="c1"># one CAN divide the game&#39;s year into four seasons in the first place ...</span>
<span class="n">MONTHS_PER_YEAR</span> <span class="o">=</span> <span class="mi">12</span>
<span class="n">SEASONAL_BOUNDARIES</span> <span class="o">=</span> <span class="p">(</span><span class="mi">3</span> <span class="o">/</span> <span class="mf">12.0</span><span class="p">,</span> <span class="mi">6</span> <span class="o">/</span> <span class="mf">12.0</span><span class="p">,</span> <span class="mi">9</span> <span class="o">/</span> <span class="mf">12.0</span><span class="p">)</span>
<span class="n">HOURS_PER_DAY</span> <span class="o">=</span> <span class="mi">24</span>
<span class="n">DAY_BOUNDARIES</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">6</span> <span class="o">/</span> <span class="mf">24.0</span><span class="p">,</span> <span class="mi">12</span> <span class="o">/</span> <span class="mf">24.0</span><span class="p">,</span> <span class="mi">18</span> <span class="o">/</span> <span class="mf">24.0</span><span class="p">)</span>
<span class="c1"># implements the Extended Room</span>
<div class="viewcode-block" id="ExtendedRoom"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom">[docs]</a><span class="k">class</span> <span class="nc">ExtendedRoom</span><span class="p">(</span><span class="n">DefaultRoom</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This room implements a more advanced `look` functionality depending on</span>
<span class="sd"> time. It also allows for &quot;details&quot;, together with a slightly modified</span>
<span class="sd"> look command.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="ExtendedRoom.at_object_creation"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.at_object_creation">[docs]</a> <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 room is first created only.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">spring_desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">summer_desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">autumn_desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">winter_desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="c1"># the general desc is used as a fallback if a seasonal one is not set</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">general_desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="c1"># will be set dynamically. Can contain raw timeslot codes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">raw_desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="c1"># this will be set dynamically at first look. Parsed for timeslot codes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="c1"># these will be filled later</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_season</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_timeslot</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># detail storage</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">details</span> <span class="o">=</span> <span class="p">{}</span></div>
<div class="viewcode-block" id="ExtendedRoom.get_time_and_season"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.get_time_and_season">[docs]</a> <span class="k">def</span> <span class="nf">get_time_and_season</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Calculate the current time and season ids.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># get the current time as parts of year and parts of day.</span>
<span class="c1"># we assume a standard calendar here and use 24h format.</span>
<span class="n">timestamp</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">gametime</span><span class="p">(</span><span class="n">absolute</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="c1"># note that fromtimestamp includes the effects of server time zone!</span>
<span class="n">datestamp</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">timestamp</span><span class="p">)</span>
<span class="n">season</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">datestamp</span><span class="o">.</span><span class="n">month</span><span class="p">)</span> <span class="o">/</span> <span class="n">MONTHS_PER_YEAR</span>
<span class="n">timeslot</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">datestamp</span><span class="o">.</span><span class="n">hour</span><span class="p">)</span> <span class="o">/</span> <span class="n">HOURS_PER_DAY</span>
<span class="c1"># figure out which slots these represent</span>
<span class="k">if</span> <span class="n">SEASONAL_BOUNDARIES</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">season</span> <span class="o">&lt;</span> <span class="n">SEASONAL_BOUNDARIES</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">curr_season</span> <span class="o">=</span> <span class="s2">&quot;spring&quot;</span>
<span class="k">elif</span> <span class="n">SEASONAL_BOUNDARIES</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">season</span> <span class="o">&lt;</span> <span class="n">SEASONAL_BOUNDARIES</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span>
<span class="n">curr_season</span> <span class="o">=</span> <span class="s2">&quot;summer&quot;</span>
<span class="k">elif</span> <span class="n">SEASONAL_BOUNDARIES</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">season</span> <span class="o">&lt;</span> <span class="mf">1.0</span> <span class="o">+</span> <span class="n">SEASONAL_BOUNDARIES</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
<span class="n">curr_season</span> <span class="o">=</span> <span class="s2">&quot;autumn&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">curr_season</span> <span class="o">=</span> <span class="s2">&quot;winter&quot;</span>
<span class="k">if</span> <span class="n">DAY_BOUNDARIES</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">timeslot</span> <span class="o">&lt;</span> <span class="n">DAY_BOUNDARIES</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">curr_timeslot</span> <span class="o">=</span> <span class="s2">&quot;night&quot;</span>
<span class="k">elif</span> <span class="n">DAY_BOUNDARIES</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">timeslot</span> <span class="o">&lt;</span> <span class="n">DAY_BOUNDARIES</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span>
<span class="n">curr_timeslot</span> <span class="o">=</span> <span class="s2">&quot;morning&quot;</span>
<span class="k">elif</span> <span class="n">DAY_BOUNDARIES</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">timeslot</span> <span class="o">&lt;</span> <span class="n">DAY_BOUNDARIES</span><span class="p">[</span><span class="mi">3</span><span class="p">]:</span>
<span class="n">curr_timeslot</span> <span class="o">=</span> <span class="s2">&quot;afternoon&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">curr_timeslot</span> <span class="o">=</span> <span class="s2">&quot;evening&quot;</span>
<span class="k">return</span> <span class="n">curr_season</span><span class="p">,</span> <span class="n">curr_timeslot</span></div>
<div class="viewcode-block" id="ExtendedRoom.replace_timeslots"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.replace_timeslots">[docs]</a> <span class="k">def</span> <span class="nf">replace_timeslots</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_desc</span><span class="p">,</span> <span class="n">curr_time</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Filter so that only time markers `&lt;timeslot&gt;...&lt;/timeslot&gt;` of</span>
<span class="sd"> the correct timeslot remains in the description.</span>
<span class="sd"> Args:</span>
<span class="sd"> raw_desc (str): The unmodified description.</span>
<span class="sd"> curr_time (str): A timeslot identifier.</span>
<span class="sd"> Returns:</span>
<span class="sd"> description (str): A possibly moified description.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">raw_desc</span><span class="p">:</span>
<span class="n">regextuple</span> <span class="o">=</span> <span class="n">REGEXMAP</span><span class="p">[</span><span class="n">curr_time</span><span class="p">]</span>
<span class="n">raw_desc</span> <span class="o">=</span> <span class="n">regextuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;\1&quot;</span><span class="p">,</span> <span class="n">raw_desc</span><span class="p">)</span>
<span class="n">raw_desc</span> <span class="o">=</span> <span class="n">regextuple</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">raw_desc</span><span class="p">)</span>
<span class="n">raw_desc</span> <span class="o">=</span> <span class="n">regextuple</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">raw_desc</span><span class="p">)</span>
<span class="k">return</span> <span class="n">regextuple</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">raw_desc</span><span class="p">)</span>
<span class="k">return</span> <span class="n">raw_desc</span></div>
<div class="viewcode-block" id="ExtendedRoom.return_detail"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.return_detail">[docs]</a> <span class="k">def</span> <span class="nf">return_detail</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This will attempt to match a &quot;detail&quot; to look for in the room.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str): A detail identifier.</span>
<span class="sd"> Returns:</span>
<span class="sd"> detail (str or None): A detail matching the given key.</span>
<span class="sd"> Notes:</span>
<span class="sd"> A detail is a way to offer more things to look at in a room</span>
<span class="sd"> without having to add new objects. For this to work, we</span>
<span class="sd"> require a custom `look` command that allows for `look</span>
<span class="sd"> &lt;detail&gt;` - the look command should defer to this method on</span>
<span class="sd"> the current location (if it exists) before giving up on</span>
<span class="sd"> finding the target.</span>
<span class="sd"> Details are not season-sensitive, but are parsed for timeslot</span>
<span class="sd"> markers.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">detail</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">details</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="kc">None</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="c1"># this happens if no attribute details is set at all</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">detail</span><span class="p">:</span>
<span class="n">season</span><span class="p">,</span> <span class="n">timeslot</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_time_and_season</span><span class="p">()</span>
<span class="n">detail</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">replace_timeslots</span><span class="p">(</span><span class="n">detail</span><span class="p">,</span> <span class="n">timeslot</span><span class="p">)</span>
<span class="k">return</span> <span class="n">detail</span>
<span class="k">return</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="ExtendedRoom.set_detail"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.set_detail">[docs]</a> <span class="k">def</span> <span class="nf">set_detail</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">detailkey</span><span class="p">,</span> <span class="n">description</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This sets a new detail, using an Attribute &quot;details&quot;.</span>
<span class="sd"> Args:</span>
<span class="sd"> detailkey (str): The detail identifier to add (for</span>
<span class="sd"> aliases you need to add multiple keys to the</span>
<span class="sd"> same description). Case-insensitive.</span>
<span class="sd"> description (str): The text to return when looking</span>
<span class="sd"> at the given detailkey.</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">details</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">details</span><span class="p">[</span><span class="n">detailkey</span><span class="o">.</span><span class="n">lower</span><span class="p">()]</span> <span class="o">=</span> <span class="n">description</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">details</span> <span class="o">=</span> <span class="p">{</span><span class="n">detailkey</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> <span class="n">description</span><span class="p">}</span></div>
<div class="viewcode-block" id="ExtendedRoom.del_detail"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.del_detail">[docs]</a> <span class="k">def</span> <span class="nf">del_detail</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">detailkey</span><span class="p">,</span> <span class="n">description</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Delete a detail.</span>
<span class="sd"> The description is ignored.</span>
<span class="sd"> Args:</span>
<span class="sd"> detailkey (str): the detail to remove (case-insensitive).</span>
<span class="sd"> description (str, ignored): the description.</span>
<span class="sd"> The description is only included for compliance but is completely</span>
<span class="sd"> ignored. Note that this method doesn&#39;t raise any exception if</span>
<span class="sd"> the detail doesn&#39;t exist in this room.</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">details</span> <span class="ow">and</span> <span class="n">detailkey</span><span class="o">.</span><span class="n">lower</span><span class="p">()</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">details</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">details</span><span class="p">[</span><span class="n">detailkey</span><span class="o">.</span><span class="n">lower</span><span class="p">()]</span></div>
<div class="viewcode-block" id="ExtendedRoom.return_appearance"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.return_appearance">[docs]</a> <span class="k">def</span> <span class="nf">return_appearance</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looker</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is called when e.g. the look command wants to retrieve</span>
<span class="sd"> the description of this object.</span>
<span class="sd"> Args:</span>
<span class="sd"> looker (Object): The object looking at us.</span>
<span class="sd"> **kwargs (dict): Arbitrary, optional arguments for users</span>
<span class="sd"> overriding the call (unused by default).</span>
<span class="sd"> Returns:</span>
<span class="sd"> description (str): Our description.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># ensures that our description is current based on time/season</span>
<span class="bp">self</span><span class="o">.</span><span class="n">update_current_description</span><span class="p">()</span>
<span class="c1"># run the normal return_appearance method, now that desc is updated.</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">(</span><span class="n">ExtendedRoom</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">return_appearance</span><span class="p">(</span><span class="n">looker</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<div class="viewcode-block" id="ExtendedRoom.update_current_description"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoom.update_current_description">[docs]</a> <span class="k">def</span> <span class="nf">update_current_description</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 will update the description of the room if the time or season</span>
<span class="sd"> has changed since last checked.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">update</span> <span class="o">=</span> <span class="kc">False</span>
<span class="c1"># get current time and season</span>
<span class="n">curr_season</span><span class="p">,</span> <span class="n">curr_timeslot</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_time_and_season</span><span class="p">()</span>
<span class="c1"># compare with previously stored slots</span>
<span class="n">last_season</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_season</span>
<span class="n">last_timeslot</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_timeslot</span>
<span class="k">if</span> <span class="n">curr_season</span> <span class="o">!=</span> <span class="n">last_season</span><span class="p">:</span>
<span class="c1"># season changed. Load new desc, or a fallback.</span>
<span class="n">new_raw_desc</span> <span class="o">=</span> <span class="bp">self</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="s2">&quot;</span><span class="si">%s</span><span class="s2">_desc&quot;</span> <span class="o">%</span> <span class="n">curr_season</span><span class="p">)</span>
<span class="k">if</span> <span class="n">new_raw_desc</span><span class="p">:</span>
<span class="n">raw_desc</span> <span class="o">=</span> <span class="n">new_raw_desc</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># no seasonal desc set. Use fallback</span>
<span class="n">raw_desc</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">general_desc</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">raw_desc</span> <span class="o">=</span> <span class="n">raw_desc</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_season</span> <span class="o">=</span> <span class="n">curr_season</span>
<span class="n">update</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">curr_timeslot</span> <span class="o">!=</span> <span class="n">last_timeslot</span><span class="p">:</span>
<span class="c1"># timeslot changed. Set update flag.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_timeslot</span> <span class="o">=</span> <span class="n">curr_timeslot</span>
<span class="n">update</span> <span class="o">=</span> <span class="kc">True</span>
<span class="k">if</span> <span class="n">update</span><span class="p">:</span>
<span class="c1"># if anything changed we have to re-parse</span>
<span class="c1"># the raw_desc for time markers</span>
<span class="c1"># and re-save the description again.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">replace_timeslots</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">raw_desc</span><span class="p">,</span> <span class="n">curr_timeslot</span><span class="p">)</span></div></div>
<span class="c1"># Custom Look command supporting Room details. Add this to</span>
<span class="c1"># the Default cmdset to use.</span>
<div class="viewcode-block" id="CmdExtendedRoomLook"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomLook">[docs]</a><span class="k">class</span> <span class="nc">CmdExtendedRoomLook</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdLook</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> look</span>
<span class="sd"> Usage:</span>
<span class="sd"> look</span>
<span class="sd"> look &lt;obj&gt;</span>
<span class="sd"> look &lt;room detail&gt;</span>
<span class="sd"> look *&lt;account&gt;</span>
<span class="sd"> Observes your location, details at your location or objects in your vicinity.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="CmdExtendedRoomLook.func"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomLook.func">[docs]</a> <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="sd">&quot;&quot;&quot;</span>
<span class="sd"> Handle the looking - add fallback to details.</span>
<span class="sd"> &quot;&quot;&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="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span>
<span class="k">if</span> <span class="n">args</span><span class="p">:</span>
<span class="n">looking_at_obj</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span>
<span class="n">args</span><span class="p">,</span>
<span class="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="o">+</span> <span class="n">caller</span><span class="o">.</span><span class="n">contents</span><span class="p">,</span>
<span class="n">use_nicks</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">quiet</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">looking_at_obj</span><span class="p">:</span>
<span class="c1"># no object found. Check if there is a matching</span>
<span class="c1"># detail at location.</span>
<span class="n">location</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">location</span>
<span class="k">if</span> <span class="p">(</span>
<span class="n">location</span>
<span class="ow">and</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">location</span><span class="p">,</span> <span class="s2">&quot;return_detail&quot;</span><span class="p">)</span>
<span class="ow">and</span> <span class="n">callable</span><span class="p">(</span><span class="n">location</span><span class="o">.</span><span class="n">return_detail</span><span class="p">)</span>
<span class="p">):</span>
<span class="n">detail</span> <span class="o">=</span> <span class="n">location</span><span class="o">.</span><span class="n">return_detail</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
<span class="k">if</span> <span class="n">detail</span><span class="p">:</span>
<span class="c1"># we found a detail instead. Show that.</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">detail</span><span class="p">)</span>
<span class="k">return</span>
<span class="c1"># no detail found. Trigger delayed error messages</span>
<span class="n">_AT_SEARCH_RESULT</span><span class="p">(</span><span class="n">looking_at_obj</span><span class="p">,</span> <span class="n">caller</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">quiet</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># we need to extract the match manually.</span>
<span class="n">looking_at_obj</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">make_iter</span><span class="p">(</span><span class="n">looking_at_obj</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">looking_at_obj</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">location</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">looking_at_obj</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You have no location to look at!&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">looking_at_obj</span><span class="p">,</span> <span class="s2">&quot;return_appearance&quot;</span><span class="p">):</span>
<span class="c1"># this is likely due to us having an account instead</span>
<span class="n">looking_at_obj</span> <span class="o">=</span> <span class="n">looking_at_obj</span><span class="o">.</span><span class="n">character</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">looking_at_obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">&quot;view&quot;</span><span class="p">):</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Could not find &#39;</span><span class="si">%s</span><span class="s2">&#39;.&quot;</span> <span class="o">%</span> <span class="n">args</span><span class="p">)</span>
<span class="k">return</span>
<span class="c1"># get object&#39;s appearance</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">looking_at_obj</span><span class="o">.</span><span class="n">return_appearance</span><span class="p">(</span><span class="n">caller</span><span class="p">))</span>
<span class="c1"># the object&#39;s at_desc() method.</span>
<span class="n">looking_at_obj</span><span class="o">.</span><span class="n">at_desc</span><span class="p">(</span><span class="n">looker</span><span class="o">=</span><span class="n">caller</span><span class="p">)</span></div></div>
<span class="c1"># Custom build commands for setting seasonal descriptions</span>
<span class="c1"># and detailing extended rooms.</span>
<div class="viewcode-block" id="CmdExtendedRoomDesc"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomDesc">[docs]</a><span class="k">class</span> <span class="nc">CmdExtendedRoomDesc</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdDesc</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> `desc` - describe an object or room.</span>
<span class="sd"> Usage:</span>
<span class="sd"> desc[/switch] [&lt;obj&gt; =] &lt;description&gt;</span>
<span class="sd"> Switches for `desc`:</span>
<span class="sd"> spring - set description for &lt;season&gt; in current room.</span>
<span class="sd"> summer</span>
<span class="sd"> autumn</span>
<span class="sd"> winter</span>
<span class="sd"> Sets the &quot;desc&quot; attribute on an object. If an object is not given,</span>
<span class="sd"> describe the current room.</span>
<span class="sd"> You can also embed special time markers in your room description, like this:</span>
<span class="sd"> ```</span>
<span class="sd"> &lt;night&gt;In the darkness, the forest looks foreboding.&lt;/night&gt;.</span>
<span class="sd"> ```</span>
<span class="sd"> Text marked this way will only display when the server is truly at the given</span>
<span class="sd"> timeslot. The available times are night, morning, afternoon and evening.</span>
<span class="sd"> Note that seasons and time-of-day slots only work on rooms in this</span>
<span class="sd"> version of the `desc` command.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;describe&quot;</span><span class="p">]</span>
<span class="n">switch_options</span> <span class="o">=</span> <span class="p">()</span> <span class="c1"># Inherits from default_cmds.CmdDesc, but unused here</span>
<div class="viewcode-block" id="CmdExtendedRoomDesc.reset_times"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomDesc.reset_times">[docs]</a> <span class="k">def</span> <span class="nf">reset_times</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;By deleteting the caches we force a re-load.&quot;&quot;&quot;</span>
<span class="n">obj</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_season</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">obj</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">last_timeslot</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="CmdExtendedRoomDesc.func"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomDesc.func">[docs]</a> <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="sd">&quot;&quot;&quot;Define extended command&quot;&quot;&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="n">location</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">location</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="k">if</span> <span class="n">location</span><span class="p">:</span>
<span class="n">string</span> <span class="o">=</span> <span class="s2">&quot;|wDescriptions on </span><span class="si">%s</span><span class="s2">|n:</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="o">.</span><span class="n">key</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot; |wspring:|n </span><span class="si">%s</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">spring_desc</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot; |wsummer:|n </span><span class="si">%s</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">summer_desc</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot; |wautumn:|n </span><span class="si">%s</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">autumn_desc</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot; |wwinter:|n </span><span class="si">%s</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">winter_desc</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot; |wgeneral:|n </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">general_desc</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;spring&quot;</span><span class="p">,</span> <span class="s2">&quot;summer&quot;</span><span class="p">,</span> <span class="s2">&quot;autumn&quot;</span><span class="p">,</span> <span class="s2">&quot;winter&quot;</span><span class="p">):</span>
<span class="c1"># a seasonal switch was given</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Seasonal descs only work with rooms, not objects.&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">switch</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">location</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;No location was found!&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">if</span> <span class="n">switch</span> <span class="o">==</span> <span class="s2">&quot;spring&quot;</span><span class="p">:</span>
<span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">spring_desc</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span>
<span class="k">elif</span> <span class="n">switch</span> <span class="o">==</span> <span class="s2">&quot;summer&quot;</span><span class="p">:</span>
<span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">summer_desc</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span>
<span class="k">elif</span> <span class="n">switch</span> <span class="o">==</span> <span class="s2">&quot;autumn&quot;</span><span class="p">:</span>
<span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">autumn_desc</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span>
<span class="k">elif</span> <span class="n">switch</span> <span class="o">==</span> <span class="s2">&quot;winter&quot;</span><span class="p">:</span>
<span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">winter_desc</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span>
<span class="c1"># clear flag to force an update</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reset_times</span><span class="p">(</span><span class="n">location</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;Seasonal description was set on </span><span class="si">%s</span><span class="s2">.&quot;</span> <span class="o">%</span> <span class="n">location</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="c1"># No seasonal desc set, maybe this is not an extended room</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="p">:</span>
<span class="n">text</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span>
<span class="n">obj</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">lhs</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="p">:</span>
<span class="k">return</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">text</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">location</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="o">=</span> <span class="n">text</span> <span class="c1"># a compatibility fallback</span>
<span class="k">if</span> <span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">has</span><span class="p">(</span><span class="s2">&quot;general_desc&quot;</span><span class="p">):</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">general_desc</span> <span class="o">=</span> <span class="n">text</span>
<span class="bp">self</span><span class="o">.</span><span class="n">reset_times</span><span class="p">(</span><span class="n">obj</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;General description was set on </span><span class="si">%s</span><span class="s2">.&quot;</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="k">else</span><span class="p">:</span>
<span class="c1"># this is not an ExtendedRoom.</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The description was set on </span><span class="si">%s</span><span class="s2">.&quot;</span> <span class="o">%</span> <span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="CmdExtendedRoomDetail"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomDetail">[docs]</a><span class="k">class</span> <span class="nc">CmdExtendedRoomDetail</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">MuxCommand</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> sets a detail on a room</span>
<span class="sd"> Usage:</span>
<span class="sd"> @detail[/del] &lt;key&gt; [= &lt;description&gt;]</span>
<span class="sd"> @detail &lt;key&gt;;&lt;alias&gt;;... = description</span>
<span class="sd"> Example:</span>
<span class="sd"> @detail</span>
<span class="sd"> @detail walls = The walls are covered in ...</span>
<span class="sd"> @detail castle;ruin;tower = The distant ruin ...</span>
<span class="sd"> @detail/del wall</span>
<span class="sd"> @detail/del castle;ruin;tower</span>
<span class="sd"> This command allows to show the current room details if you enter it</span>
<span class="sd"> without any argument. Otherwise, sets or deletes a detail on the current</span>
<span class="sd"> room, if this room supports details like an extended room. To add new</span>
<span class="sd"> detail, just use the @detail command, specifying the key, an equal sign</span>
<span class="sd"> and the description. You can assign the same description to several</span>
<span class="sd"> details using the alias syntax (replace key by alias1;alias2;alias3;...).</span>
<span class="sd"> To remove one or several details, use the @detail/del switch.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;@detail&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:perm(Builder)&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;Building&quot;</span>
<div class="viewcode-block" id="CmdExtendedRoomDetail.func"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomDetail.func">[docs]</a> <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">location</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">location</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">details</span> <span class="o">=</span> <span class="n">location</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">details</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">details</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;|rThe room </span><span class="si">{}</span><span class="s2"> doesn&#39;t have any detail set.|n&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">location</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">details</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">([</span><span class="s2">&quot;|y</span><span class="si">{}</span><span class="s2">|n: </span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">desc</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">desc</span> <span class="ow">in</span> <span class="n">details</span><span class="o">.</span><span class="n">items</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;Details on Room:</span><span class="se">\n</span><span class="s2">&quot;</span> <span class="o">+</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">details</span><span class="p">))</span>
<span class="k">return</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span> <span class="ow">and</span> <span class="s2">&quot;del&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span><span class="p">:</span>
<span class="n">detail</span> <span class="o">=</span> <span class="n">location</span><span class="o">.</span><span class="n">return_detail</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lhs</span><span class="p">)</span>
<span class="k">if</span> <span class="n">detail</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;Detail &#39;|y</span><span class="si">{}</span><span class="s2">|n&#39; on Room:</span><span class="se">\n</span><span class="si">{}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lhs</span><span class="p">,</span> <span class="n">detail</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;Detail &#39;</span><span class="si">{}</span><span class="s2">&#39; not found.&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lhs</span><span class="p">))</span>
<span class="k">return</span>
<span class="n">method</span> <span class="o">=</span> <span class="s2">&quot;set_detail&quot;</span> <span class="k">if</span> <span class="s2">&quot;del&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span> <span class="k">else</span> <span class="s2">&quot;del_detail&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">location</span><span class="p">,</span> <span class="n">method</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;Details cannot be set on </span><span class="si">%s</span><span class="s2">.&quot;</span> <span class="o">%</span> <span class="n">location</span><span class="p">)</span>
<span class="k">return</span>
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">lhs</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="c1"># loop over all aliases, if any (if not, this will just be</span>
<span class="c1"># the one key to loop over)</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">location</span><span class="p">,</span> <span class="n">method</span><span class="p">)(</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;del&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">switches</span><span class="p">:</span>
<span class="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;Detail </span><span class="si">%s</span><span class="s2"> deleted, if it existed.&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">lhs</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;Detail set &#39;</span><span class="si">%s</span><span class="s2">&#39;: &#39;</span><span class="si">%s</span><span class="s2">&#39;&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lhs</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span><span class="p">))</span></div></div>
<span class="c1"># Simple command to view the current time and season</span>
<div class="viewcode-block" id="CmdExtendedRoomGameTime"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomGameTime">[docs]</a><span class="k">class</span> <span class="nc">CmdExtendedRoomGameTime</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">MuxCommand</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check the game time</span>
<span class="sd"> Usage:</span>
<span class="sd"> time</span>
<span class="sd"> Shows the current in-game time and season.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;time&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:all()&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;General&quot;</span>
<div class="viewcode-block" id="CmdExtendedRoomGameTime.func"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.CmdExtendedRoomGameTime.func">[docs]</a> <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="sd">&quot;&quot;&quot;Reads time info from current room&quot;&quot;&quot;</span>
<span class="n">location</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">location</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">location</span> <span class="ow">or</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">location</span><span class="p">,</span> <span class="s2">&quot;get_time_and_season&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;No location available - you are outside time.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">season</span><span class="p">,</span> <span class="n">timeslot</span> <span class="o">=</span> <span class="n">location</span><span class="o">.</span><span class="n">get_time_and_season</span><span class="p">()</span>
<span class="n">prep</span> <span class="o">=</span> <span class="s2">&quot;a&quot;</span>
<span class="k">if</span> <span class="n">season</span> <span class="o">==</span> <span class="s2">&quot;autumn&quot;</span><span class="p">:</span>
<span class="n">prep</span> <span class="o">=</span> <span class="s2">&quot;an&quot;</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;It&#39;s </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> day, in the </span><span class="si">%s</span><span class="s2">.&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">prep</span><span class="p">,</span> <span class="n">season</span><span class="p">,</span> <span class="n">timeslot</span><span class="p">))</span></div></div>
<span class="c1"># CmdSet for easily install all commands</span>
<div class="viewcode-block" id="ExtendedRoomCmdSet"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoomCmdSet">[docs]</a><span class="k">class</span> <span class="nc">ExtendedRoomCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Groups the extended-room commands.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="ExtendedRoomCmdSet.at_cmdset_creation"><a class="viewcode-back" href="../../../api/evennia.contrib.extended_room.html#evennia.contrib.extended_room.ExtendedRoomCmdSet.at_cmdset_creation">[docs]</a> <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">CmdExtendedRoomLook</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">CmdExtendedRoomDesc</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">CmdExtendedRoomDetail</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">CmdExtendedRoomGameTime</span><span class="p">)</span></div></div>
</pre></div>
<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><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
<a href="https://discord.gg/NecFePw">Discord</a> -
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
</li>
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="extended_room.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="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="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.contrib.extended_room</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>