diff --git a/docs/pylib/auto_link_remapper.py b/docs/pylib/auto_link_remapper.py
index 0b971492bc..e8e37bb06d 100644
--- a/docs/pylib/auto_link_remapper.py
+++ b/docs/pylib/auto_link_remapper.py
@@ -9,7 +9,7 @@ import re
from collections import defaultdict
from sphinx.errors import DocumentError
from pathlib import Path
-from os.path import abspath, dirname, join as pathjoin, sep, relpath
+from os.path import abspath, dirname, join as pathjoin, relpath
_IGNORE_FILES = []
_SOURCEDIR_NAME = "source"
@@ -267,6 +267,7 @@ def auto_link_remapper(no_autodoc=False):
# we add a self-reference so the toc itself is also a part of a toctree
fil.write("\n```\n\n```{toctree}\n :hidden:\n\ntoc\n```")
+ print(" -- File toc.md updated.")
print(" -- Auto-Remapper finished.")
diff --git a/docs/pylib/contrib_readmes2docs.py b/docs/pylib/contrib_readmes2docs.py
index f6d67e8639..a37a4b52ff 100644
--- a/docs/pylib/contrib_readmes2docs.py
+++ b/docs/pylib/contrib_readmes2docs.py
@@ -3,16 +3,81 @@ Convert contribs' README files to proper documentation pages along with
an index.
"""
+from collections import defaultdict
from os.path import abspath, dirname, join as pathjoin, sep
from glob import glob
_EVENNIA_PATH = pathjoin(dirname(dirname(dirname(abspath(__file__)))))
_DOCS_PATH = pathjoin(_EVENNIA_PATH, "docs")
-_CONTRIB_PATH = pathjoin(_EVENNIA_PATH, "contrib")
-_SOURCE_DIR = pathjoin(_EVENNIA_PATH, "contrib")
+_SOURCE_DIR = pathjoin(_EVENNIA_PATH, "evennia", "contrib")
_OUT_DIR = pathjoin(_DOCS_PATH, "source", "Contribs")
-_OUT_INDEX_FILE = pathjoin(_OUT_DIR, "Contribs.md")
+_OUT_INDEX_FILE = pathjoin(_OUT_DIR, "Contrib-Overview.md")
+
+
+_CATEGORY_DESCS = {
+ "base_systems": """
+This category contains systems that are not necessarily tied to a specific
+in-game mechanic but is useful for the game as a whole. Examples include
+login systems, new command syntaxes, and build helpers.
+ """,
+ "full_systems": """
+This category contains 'complete' game engines that can be used directly
+to start creating content without no further additions (unless you want to).
+""",
+ "game_systems": """
+This category holds code implementing in-game gameplay systems like
+crafting, mail, combat and more. Each system is meant to be adopted
+piecemeal and adopted for your game. This does not include
+roleplaying-specific systems, those are found in the `rpg` folder.
+""",
+ "grid": """
+Systems related to the game world's topology and structure. This has
+contribs related to rooms, exits and map building.
+""",
+ "rpg": """
+These are systems specifically related to roleplaying
+and rule implementation like character traits, dice rolling and emoting.
+""",
+ "tutorials": """
+Helper resources specifically meant to teach a development concept or
+to exemplify an Evennia system. Any extra resources tied to documentation
+tutorials are found here. Also the home of the Tutorial World demo adventure.
+""",
+ "utils": """
+Miscellaneous, optional tools for manipulating text, auditing connections
+and more.
+"""
+}
+
+
+_FILENAME_MAP = {
+ "rpsystem": "RPSystem",
+ "xyzgrid": "XYZGrid",
+ "awsstorage": "AWSStorage"
+}
+
+HEADER = """# Contribs
+
+_Contribs_ are optional code snippets and systems contributed by
+the Evennia community. They vary in size and complexity and
+may be more specific about game types and styles than 'core' Evennia.
+This page is auto-generated and summarizes all contribs currently included.
+
+All contrib categories are imported from `evennia.contrib`, such as
+
+ from evennia.contrib.base_systems import building_menu
+
+Each contrib contains installation instructions for how to integrate it
+with your other code. If you want to tweak the code of a contrib, just
+copy its entire folder to your game directory and modify/use it from there.
+
+If you want to contribute yourself, see [here](Contributing)!
+
+> Hint: Additional (potentially un-maintained) code snippets from the community can be found
+in our discussion forum's [Community Contribs & Snippets](https://github.com/evennia/evennia/discussions/categories/community-contribs-snippets) category.
+
+"""
TOCTREE = """
@@ -23,26 +88,122 @@ TOCTREE = """
"""
+CATEGORY = """
+## {category}
-def readme2doc(directory):
+_{category_desc}_
+
+{blurbs}
+
+
+"""
+
+BLURB = """
+### Contrib: `{name}`
+
+{credits}
+
+{blurb}
+
+[Read the documentation]({filename})
+
+"""
+
+FOOTER = """
+
+----
+
+This document page is generated from `{path}`. Changes to this
+file will be overwritten, so edit that file rather than this one.
+"""
+
+INDEX_FOOTER = """
+
+----
+
+This document page is auto-generated from the sources. Manual changes
+will be overwritten.
+"""
+
+
+def readmes2docs(directory=_SOURCE_DIR):
"""
Parse directory for README files and convert them to doc pages.
"""
- indexfile = []
- listing = []
+ ncount = 0
+ categories = defaultdict(list)
- for file_path in glob(f"directory{sep}*{sep}*{sep}README.md"):
+ glob_path = f"{directory}{sep}*{sep}*{sep}README.md"
+ for file_path in glob(glob_path):
# paths are e.g. evennia/contrib/utils/auditing/README.md
_, category, name, _ = file_path.rsplit(sep, 3)
- filename = "-".join(part.capitalize() for part in name.split("_")) + ".md"
+ filename = "Contrib-" + "-".join(
+ _FILENAME_MAP.get(
+ part, part.capitalize() if part[0].islower() else part)
+ for part in name.split("_")) + ".md"
outfile = pathjoin(_OUT_DIR, filename)
with open(file_path) as fil:
data = fil.read()
+ clean_file_path = f"evennia{sep}contrib{file_path[len(directory):]}"
+ data += FOOTER.format(path=clean_file_path)
+
+ try:
+ credits = data.split("\n\n", 3)[1]
+ blurb = data.split("\n\n", 3)[2]
+ except IndexError:
+ blurb = name
+
with open(outfile, 'w') as fil:
fil.write(data)
+
+ categories[category].append((name, credits, blurb, filename))
+ ncount += 1
+
+ # build the index with blurbs
+
+ lines = [HEADER]
+ filenames = []
+ for category in sorted(categories):
+ contrib_tups = categories[category]
+ catlines = []
+ for tup in sorted(contrib_tups, key=lambda tup: tup[0].lower()):
+ catlines.append(
+ BLURB.format(
+ name=tup[0],
+ credits=tup[1],
+ blurb=tup[2],
+ filename=tup[3],
+ )
+ )
+ filenames.append(f"Contribs{sep}{tup[3]}")
+ lines.append(
+ CATEGORY.format(
+ category=category,
+ category_desc=_CATEGORY_DESCS[category].strip(),
+ blurbs="\n".join(catlines)
+ )
+ )
+ lines.append(TOCTREE.format(
+ listing="\n".join(filenames))
+ )
+
+ lines.append(INDEX_FOOTER)
+
+ text = "\n".join(lines)
+
+
+
+ with open(_OUT_INDEX_FILE, 'w') as fil:
+ fil.write(text)
+
+ print(f" -- Converted Contrib READMEs to {ncount} doc pages + index.")
+
+
+if __name__ == "__main__":
+ readmes2docs(_SOURCE_DIR)
diff --git a/docs/source/Contribs/Contrib-AWSStorage.md b/docs/source/Contribs/Contrib-AWSStorage.md
new file mode 100644
index 0000000000..c07e92ea6b
--- /dev/null
+++ b/docs/source/Contribs/Contrib-AWSStorage.md
@@ -0,0 +1,234 @@
+# AWSstorage system
+
+Contrib by The Right Honourable Reverend (trhr) 2020
+
+## What is this for?
+
+This plugin migrates the Web-based portion of Evennia, namely images,
+javascript, and other items located inside staticfiles into Amazon AWS (S3) for
+hosting.
+
+Files hosted on S3 are "in the cloud," and while your personal
+server may be sufficient for serving multimedia to a minimal number of users,
+the perfect use case for this plugin would be:
+
+- Servers supporting heavy web-based traffic (webclient, etc) ...
+- With a sizable number of users ...
+- Where the users are globally distributed ...
+- Where multimedia files are served to users as a part of gameplay
+
+Bottom line - if you're sending an image to a player every time they traverse a
+map, the bandwidth reduction of using this will be substantial. If not, probably
+skip this contrib.
+
+## On costs
+
+Note that storing and serving files via S3 is not technically free outside of
+Amazon's "free tier" offering, which you may or may not be eligible for;
+setting up a vanilla evennia server with this contrib currently requires 1.5MB
+of storage space on S3, making the current total cost of running this plugin
+~$0.0005 per year. If you have substantial media assets and intend to serve
+them to many users, caveat emptor on a total cost of ownership - check AWS's
+pricing structure.
+
+# Technical details
+
+This is a drop-in replacement that operates deeper than all of Evennia's code,
+so your existing code does not need to change at all to support it.
+
+For example, when Evennia (or Django), tries to save a file permanently (say, an
+image uploaded by a user), the save (or load) communication follows the path:
+
+ Evennia -> Django
+ Django -> Storage backend
+ Storage backend -> file storage location (e.g. hard drive)
+
+[django docs](https://docs.djangoproject.com/en/3.0/ref/settings/#std:setting-STATICFILES_STORAGE)
+
+This plugin, when enabled, overrides the default storage backend,
+which defaults to saving files at mygame/website/, instead,
+sending the files to S3 via the storage backend defined herein.
+
+There is no way (or need) to directly access or use the functions here with
+other contributions or custom code. Simply work how you would normally, Django
+will handle the rest.
+
+
+# Installation
+
+## Set up AWS account
+
+If you don't have an AWS S3 account, you should create one at
+https://aws.amazon.com/ - documentation for AWS S3 is available at:
+https://docs.aws.amazon.com/AmazonS3/latest/gsg/GetStartedWithS3.html
+
+Credentials required within the app are AWS IAM Access Key and Secret Keys,
+which can be generated/found in the AWS Console.
+
+The following example IAM Control Policy Permissions can be added to
+the IAM service inside AWS. Documentation for this can be found here:
+https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html
+
+Note that this is only required if you want to tightly secure the roles
+that this plugin has access to.
+
+```
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Sid": "evennia",
+ "Effect": "Allow",
+ "Action": [
+ "s3:PutObject",
+ "s3:GetObjectAcl",
+ "s3:GetObject",
+ "s3:ListBucket",
+ "s3:DeleteObject",
+ "s3:PutObjectAcl"
+ ],
+ "Resource": [
+ "arn:aws:s3:::YOUR_BUCKET_NAME/*",
+ "arn:aws:s3:::YOUR_BUCKET_NAME"
+ ]
+ }
+ ],
+ [
+ {
+ "Sid":"evennia",
+ "Effect":"Allow",
+ "Action":[
+ "s3:CreateBucket",
+ ],
+ "Resource":[
+ "arn:aws:s3:::*"
+ ]
+ }
+ ]
+}
+```
+
+Advanced Users: The second IAM statement, CreateBucket, is only needed
+for initial installation. You can remove it later, or you can
+create the bucket and set the ACL yourself before you continue.
+
+## Dependencies
+
+
+This package requires the dependency "boto3 >= 1.4.4", the official
+AWS python package. To install, it's easiest to just install Evennia's
+extra requirements;
+
+- Activate your `virtualenv`
+- `cd` to the root of the Evennia repository. There should be an `requirements_extra.txt`
+file here.
+- `pip install -r requirements_extra.txt`
+
+## Configure Evennia
+
+Customize the variables defined below in `secret_settings.py`. No further
+configuration is needed. Note the three lines that you need to set to your
+actual values.
+
+```python
+# START OF SECRET_SETTINGS.PY COPY/PASTE >>>
+
+AWS_ACCESS_KEY_ID = 'THIS_IS_PROVIDED_BY_AMAZON'
+AWS_SECRET_ACCESS_KEY = 'THIS_IS_PROVIDED_BY_AMAZON'
+AWS_STORAGE_BUCKET_NAME = 'mygame-evennia' # CHANGE ME! I suggest yourgamename-evennia
+
+# The settings below need to go in secret_settings,py as well, but will
+# not need customization unless you want to do something particularly fancy.
+
+AWS_S3_REGION_NAME = 'us-east-1' # N. Virginia
+AWS_S3_OBJECT_PARAMETERS = { 'Expires': 'Thu, 31 Dec 2099 20:00:00 GMT',
+ 'CacheControl': 'max-age=94608000', }
+AWS_DEFAULT_ACL = 'public-read'
+AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % settings.AWS_BUCKET_NAME
+AWS_AUTO_CREATE_BUCKET = True
+STATICFILES_STORAGE = 'evennia.contrib.base_systems.awsstorage.aws-s3-cdn.S3Boto3Storage'
+
+# <<< END OF SECRET_SETTINGS.PY COPY/PASTE
+```
+
+You may also store these keys as environment variables of the same name.
+For advanced configuration, refer to the docs for django-storages.
+
+After copying the above, run `evennia reboot`.
+
+## Check that it works
+
+Confirm that web assets are being served from S3 by visiting your website, then
+checking the source of any image (for instance, the logo). It should read
+`https://your-bucket-name.s3.amazonaws.com/path/to/file`. If so, the system
+works and you shouldn't need to do anything else.
+
+# Uninstallation
+
+If you haven't made changes to your static files (uploaded images, etc),
+you can simply remove the lines you added to `secret_settings.py`. If you
+have made changes and want to uninstall at a later date, you can export
+your files from your S3 bucket and put them in /static/ in the evennia
+directory.
+
+
+# License
+
+Draws heavily from code provided by django-storages, for which these contributors
+are authors:
+
+Marty Alchin (S3)
+David Larlet (S3)
+Arne Brodowski (S3)
+Sebastian Serrano (S3)
+Andrew McClain (MogileFS)
+Rafal Jonca (FTP)
+Chris McCormick (S3 with Boto)
+Ivanov E. (Database)
+Ariel Núñez (packaging)
+Wim Leers (SymlinkOrCopy + patches)
+Michael Elsdörfer (Overwrite + PEP8 compatibility)
+Christian Klein (CouchDB)
+Rich Leland (Mosso Cloud Files)
+Jason Christa (patches)
+Adam Nelson (patches)
+Erik CW (S3 encryption)
+Axel Gembe (Hash path)
+Waldemar Kornewald (MongoDB)
+Russell Keith-Magee (Apache LibCloud patches)
+Jannis Leidel (S3 and GS with Boto)
+Andrei Coman (Azure)
+Chris Streeter (S3 with Boto)
+Josh Schneier (Fork maintainer, Bugfixes, Py3K)
+Anthony Monthe (Dropbox)
+EunPyo (Andrew) Hong (Azure)
+Michael Barrientos (S3 with Boto3)
+piglei (patches)
+Matt Braymer-Hayes (S3 with Boto3)
+Eirik Martiniussen Sylliaas (Google Cloud Storage native support)
+Jody McIntyre (Google Cloud Storage native support)
+Stanislav Kaledin (Bug fixes in SFTPStorage)
+Filip Vavera (Google Cloud MIME types support)
+Max Malysh (Dropbox large file support)
+Scott White (Google Cloud updates)
+Alex Watt (Google Cloud Storage patch)
+Jumpei Yoshimura (S3 docs)
+Jon Dufresne
+Rodrigo Gadea (Dropbox fixes)
+Martey Dodoo
+Chris Rink
+Shaung Cheng (S3 docs)
+Andrew Perry (Bug fixes in SFTPStorage)
+
+The repurposed code from django-storages is released under BSD 3-Clause,
+same as Evennia, so for detailed licensing, refer to the Evennia license.
+
+# Versioning
+
+This is confirmed to work for Django 2 and Django 3.
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/awsstorage/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Auditing.md b/docs/source/Contribs/Contrib-Auditing.md
new file mode 100644
index 0000000000..60c2a59cc6
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Auditing.md
@@ -0,0 +1,77 @@
+# Input/Output Auditing
+
+Contrib - Johnny 2017
+
+This is a tap that optionally intercepts all data sent to/from clients and the
+server and passes it to a callback of your choosing.
+
+It is intended for quality assurance, post-incident investigations and debugging
+but obviously can be abused. All data is recorded in cleartext. Please
+be ethical, and if you are unwilling to properly deal with the implications of
+recording user passwords or private communications, please do not enable
+this module.
+
+Some checks have been implemented to protect the privacy of users.
+
+Files included in this module:
+
+ outputs.py - Example callback methods. This module ships with examples of
+ callbacks that send data as JSON to a file in your game/server/logs
+ dir or to your native Linux syslog daemon. You can of course write
+ your own to do other things like post them to Kafka topics.
+
+ server.py - Extends the Evennia ServerSession object to pipe data to the
+ callback upon receipt.
+
+ tests.py - Unit tests that check to make sure commands with sensitive
+ arguments are having their PII scrubbed.
+
+
+## Installation/Configuration:
+
+Deployment is completed by configuring a few settings in server.conf. This line
+is required:
+
+ SERVER_SESSION_CLASS = 'evennia.contrib.utils.auditing.server.AuditedServerSession'
+
+This tells Evennia to use this ServerSession instead of its own. Below are the
+other possible options along with the default value that will be used if unset.
+
+ # Where to send logs? Define the path to a module containing your callback
+ # function. It should take a single dict argument as input
+ AUDIT_CALLBACK = 'evennia.contrib.utils.auditing.outputs.to_file'
+
+ # Log user input? Be ethical about this; it will log all private and
+ # public communications between players and/or admins (default: False).
+ AUDIT_IN = False
+
+ # Log server output? This will result in logging of ALL system
+ # messages and ALL broadcasts to connected players, so on a busy game any
+ # broadcast to all users will yield a single event for every connected user!
+ AUDIT_OUT = False
+
+ # The default output is a dict. Do you want to allow key:value pairs with
+ # null/blank values? If you're just writing to disk, disabling this saves
+ # some disk space, but whether you *want* sparse values or not is more of a
+ # consideration if you're shipping logs to a NoSQL/schemaless database.
+ # (default: False)
+ AUDIT_ALLOW_SPARSE = False
+
+ # If you write custom commands that handle sensitive data like passwords,
+ # you must write a regular expression to remove that before writing to log.
+ # AUDIT_MASKS is a list of dictionaries that define the names of commands
+ # and the regexes needed to scrub them.
+ # The system already has defaults to filter out sensitive login/creation
+ # commands in the default command set. Your list of AUDIT_MASKS will be appended
+ # to those defaults.
+ #
+ # In the regex, the sensitive data itself must be captured in a named group with a
+ # label of 'secret' (see the Python docs on the `re` module for more info). For
+ # example: `{'authentication': r"^@auth\s+(?P[\w]+)"}`
+ AUDIT_MASKS = []
+
+
+----
+
+This document page is generated from `evennia/contrib/utils/auditing/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Barter.md b/docs/source/Contribs/Contrib-Barter.md
new file mode 100644
index 0000000000..5e60cc9be1
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Barter.md
@@ -0,0 +1,134 @@
+# Barter system
+
+Evennia contribution - Griatch 2012
+
+This implements a full barter system - a way for players to safely
+trade items between each other using code rather than simple free-form
+talking. The advantage of this is increased buy/sell safety but it
+also streamlines the process and makes it faster when doing many
+transactions (since goods are automatically exchanged once both
+agree).
+
+This system is primarily intended for a barter economy, but can easily
+be used in a monetary economy as well -- just let the "goods" on one
+side be coin objects (this is more flexible than a simple "buy"
+command since you can mix coins and goods in your trade).
+
+## Installation
+
+Just import the CmdsetTrade command into (for example) the default
+cmdset. This will make the trade (or barter) command available
+in-game.
+
+```python
+# in mygame/commands/default_cmdsets.py
+
+from evennia.contrib.game_systems import barter # <---
+
+# ...
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ # ...
+ def at cmdset_creation(self):
+ # ...
+ self.add(barter.CmdsetTrade) # <---
+
+```
+
+## Usage
+
+In this module, a "barter" is generally referred to as a "trade".
+
+Below is an example of a barter sequence. A and B are the parties.
+The `A>` and `B>` are their inputs.
+
+1) opening a trade
+
+ A> trade B: Hi, I have a nice extra sword. You wanna trade?
+
+ B sees:
+ A says: "Hi, I have a nice extra sword. You wanna trade?"
+ A wants to trade with you. Enter 'trade A ' to accept.
+
+ B> trade A: Hm, I could use a good sword ...
+
+ A sees:
+ B says: "Hm, I could use a good sword ...
+ B accepts the trade. Use 'trade help' for aid.
+
+ B sees:
+ You are now trading with A. Use 'trade help' for aid.
+
+2) negotiating
+
+ A> offer sword: This is a nice sword. I would need some rations in trade.
+
+ B sees: A says: "This is a nice sword. I would need some rations in trade."
+ [A offers Sword of might.]
+
+ B> evaluate sword
+ B sees:
+
+
+ B> offer ration: This is a prime ration.
+
+ A sees:
+ B says: "This is a prime ration."
+ [B offers iron ration]
+
+ A> say Hey, this is a nice sword, I need something more for it.
+
+ B sees:
+ A says: "Hey this is a nice sword, I need something more for it."
+
+ B> offer sword,apple: Alright. I will also include a magic apple. That's my last offer.
+
+ A sees:
+ B says: "Alright, I will also include a magic apple. That's my last offer."
+ [B offers iron ration and magic apple]
+
+ A> accept: You are killing me here, but alright.
+
+ B sees: A says: "You are killing me here, but alright."
+ [A accepts your offer. You must now also accept.]
+
+ B> accept: Good, nice making business with you.
+ You accept the deal. Deal is made and goods changed hands.
+
+ A sees: B says: "Good, nice making business with you."
+ B accepts the deal. Deal is made and goods changed hands.
+
+At this point the trading system is exited and the negotiated items
+are automatically exchanged between the parties. In this example B was
+the only one changing their offer, but also A could have changed their
+offer until the two parties found something they could agree on. The
+emotes are optional but useful for RP-heavy worlds.
+
+## Technical info
+
+The trade is implemented by use of a TradeHandler. This object is a
+common place for storing the current status of negotiations. It is
+created on the object initiating the trade, and also stored on the
+other party once that party agrees to trade. The trade request times
+out after a certain time - this is handled by a Script. Once trade
+starts, the CmdsetTrade cmdset is initiated on both parties along with
+the commands relevant for the trading.
+
+## Ideas for NPC bartering
+
+This module is primarily intended for trade between two players. But
+it can also in principle be used for a player negotiating with an
+AI-controlled NPC. If the NPC uses normal commands they can use it
+directly -- but more efficient is to have the NPC object send its
+replies directly through the tradehandler to the player. One may want
+to add some functionality to the decline command, so players can
+decline specific objects in the NPC offer (decline ) and allow
+the AI to maybe offer something else and make it into a proper
+barter. Along with an AI that "needs" things or has some sort of
+personality in the trading, this can make bartering with NPCs at least
+moderately more interesting than just plain 'buy'.
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/barter/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Batchprocessor.md b/docs/source/Contribs/Contrib-Batchprocessor.md
new file mode 100644
index 0000000000..a3510385eb
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Batchprocessor.md
@@ -0,0 +1,41 @@
+# Batch processor examples
+
+Contibution - Griatch 2012
+
+The batch processor is used for generating in-game content from one or more
+static files. Files can be stored with version control and then 'applied'
+to the game to create content.
+
+There are two batch processor types:
+
+- Batch-cmd processor: A list of `#`-separated Evennia commands being executed
+ in sequence, such as `create`, `dig`, `north` etc. When running a script
+ of this type (filename ending with `.ev`), the caller of the script will be
+ the one performing the script's actions.
+- Batch-code processor: A full Python script (filename ending with `.py` that
+ executes Evennia api calls to build, such as `evennia.create_object` or
+ `evennia.search_object` etc. It can be divided up into comment-separated
+ chunks so one can execute only parts of the script at a time (in this way it's
+ a little different than a normal Python file).
+
+## Usage
+
+To test the two example batch files, you need `Developer` or `superuser`
+permissions, be logged into the game and run of
+
+ > batchcommand/interactive tutorials.batchprocessor.example_batch_cmds
+ > batchcode/interactive tutorials.batchprocessor.example_batch_code
+
+The `/interactive` drops you in interactive mode so you can follow along what
+the scripts do. Skip it to build it all at once.
+
+Both commands produce the same results - they create a red-button object,
+a table and a chair. If you run either with the `/debug` switch, the objects will
+be deleted afterwards (for quick tests of syntax that you don't want to spam new
+objects, for example).
+
+
+----
+
+This document page is generated from `evennia/contrib/tutorials/batchprocessor/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Bodyfunctions.md b/docs/source/Contribs/Contrib-Bodyfunctions.md
new file mode 100644
index 0000000000..ffe39eac44
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Bodyfunctions.md
@@ -0,0 +1,22 @@
+# Script example
+
+Griatch - 2012
+
+Example script for testing. This adds a simple timer that has your
+character make observations and notices at irregular intervals.
+
+To test, use (in game)
+
+ > script me = contrib.tutorials.bodyfunctions.BodyFunctions
+
+## Notes
+
+Use `scripts me` to see the script running on you. Note that even though
+the timer ticks down to 0, you will _not_ see an echo every tick (it's
+random if an echo is given on a tick or not).
+
+
+----
+
+This document page is generated from `evennia/contrib/tutorials/bodyfunctions/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Building-Menu.md b/docs/source/Contribs/Contrib-Building-Menu.md
new file mode 100644
index 0000000000..a8a92c73ab
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Building-Menu.md
@@ -0,0 +1,134 @@
+# Building menu
+
+Module containing the building menu system.
+
+Evennia contributor: vincent-lg 2018
+
+Building menus are in-game menus, not unlike `EvMenu` though using a
+different approach. Building menus have been specifically designed to edit
+information as a builder. Creating a building menu in a command allows
+builders quick-editing of a given object, like a room. If you follow the
+steps below to add the contrib, you will have access to an `@edit` command
+that will edit any default object offering to change its key and description.
+
+## Install
+
+1. Import the `GenericBuildingCmd` class from this contrib in your
+ `mygame/commands/default_cmdset.py` file:
+
+ ```python
+ from evennia.contrib.base_systems.building_menu import GenericBuildingCmd
+ ```
+
+2. Below, add the command in the `CharacterCmdSet`:
+
+ ```python
+ # ... These lines should exist in the file
+ class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ key = "DefaultCharacter"
+
+ def at_cmdset_creation(self):
+ super(CharacterCmdSet, self).at_cmdset_creation()
+ # ... add the line below
+ self.add(GenericBuildingCmd())
+ ```
+
+## Usage
+
+The `edit` command will allow you to edit any object. You will need to
+specify the object name or ID as an argument. For instance: `edit here`
+will edit the current room. However, building menus can perform much more
+than this very simple example, read on for more details.
+
+Building menus can be set to edit about anything. Here is an example of
+output you could obtain when editing the room:
+
+```
+ Editing the room: Limbo(#2)
+
+ [T]itle: the limbo room
+ [D]escription
+ This is the limbo room. You can easily change this default description,
+ either by using the |y@desc/edit|n command, or simply by entering this
+ menu (enter |yd|n).
+ [E]xits:
+ north to A parking(#4)
+ [Q]uit this menu
+```
+
+From there, you can open the title choice by pressing t. You can then
+change the room title by simply entering text, and go back to the
+main menu entering @ (all this is customizable). Press q to quit this menu.
+
+The first thing to do is to create a new module and place a class
+inheriting from `BuildingMenu` in it.
+
+```python
+from evennia.contrib.base_systems.building_menu import BuildingMenu
+
+class RoomBuildingMenu(BuildingMenu):
+ # ...
+
+```
+
+Next, override the `init` method (not `__init__`!). You can add
+choices (like the title, description, and exits choices as seen above) by using
+the `add_choice` method.
+
+```python
+class RoomBuildingMenu(BuildingMenu):
+ def init(self, room):
+ self.add_choice("title", "t", attr="key")
+
+```
+
+That will create the first choice, the title choice. If one opens your menu
+and enter t, she will be in the title choice. She can change the title
+(it will write in the room's `key` attribute) and then go back to the
+main menu using `@`.
+
+`add_choice` has a lot of arguments and offers a great deal of
+flexibility. The most useful ones is probably the usage of callbacks,
+as you can set almost any argument in `add_choice` to be a callback, a
+function that you have defined above in your module. This function will be
+called when the menu element is triggered.
+
+Notice that in order to edit a description, the best method to call isn't
+`add_choice`, but `add_choice_edit`. This is a convenient shortcut
+which is available to quickly open an `EvEditor` when entering this choice
+and going back to the menu when the editor closes.
+
+```python
+class RoomBuildingMenu(BuildingMenu):
+ def init(self, room):
+ self.add_choice("title", "t", attr="key")
+ self.add_choice_edit("description", key="d", attr="db.desc")
+
+```
+
+When you wish to create a building menu, you just need to import your
+class, create it specifying your intended caller and object to edit,
+then call `open`:
+
+```python
+from import RoomBuildingMenu
+
+class CmdEdit(Command):
+
+ key = "redit"
+
+ def func(self):
+ menu = RoomBuildingMenu(self.caller, self.caller.location)
+ menu.open()
+
+```
+
+This is a very short introduction. For more details, see the [online
+tutorial](https://github.com/evennia/evennia/wiki/Building-menus) or read the
+heavily-documented code of the contrib itself.
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/building_menu/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Clothing.md b/docs/source/Contribs/Contrib-Clothing.md
new file mode 100644
index 0000000000..95109e5361
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Clothing.md
@@ -0,0 +1,90 @@
+# Clothing
+
+Evennia contribution - Tim Ashley Jenkins 2017
+
+Provides a typeclass and commands for wearable clothing,
+which is appended to a character's description when worn.
+
+Clothing items, when worn, are added to the character's description
+in a list. For example, if wearing the following clothing items:
+
+ a thin and delicate necklace
+ a pair of regular ol' shoes
+ one nice hat
+ a very pretty dress
+
+## Installation
+
+To install, import this module and have your default character
+inherit from ClothedCharacter in your game's characters.py file:
+
+```python
+
+from evennia.contrib.game_systems.clothing import ClothedCharacter
+
+class Character(ClothedCharacter):
+
+```
+
+And then add `ClothedCharacterCmdSet` in your character set in
+`mygame/commands/default_cmdsets.py`:
+
+```python
+
+from evennia.contrib.game_systems.clothing import ClothedCharacterCmdSet <--
+
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ # ...
+ at_cmdset_creation(self):
+
+ super().at_cmdset_creation()
+ ...
+ self.add(ClothedCharacterCmdSet) # <--
+
+```
+
+From here, you can use the default builder commands to create clothes
+with which to test the system:
+
+ create a pretty shirt : evennia.contrib.game_systems.clothing.Clothing
+ set shirt/clothing_type = 'top'
+ wear shirt
+
+A character's description may look like this:
+
+ Superuser(#1)
+ This is User #1.
+
+ Superuser is wearing one nice hat, a thin and delicate necklace,
+ a very pretty dress and a pair of regular ol' shoes.
+
+Characters can also specify the style of wear for their clothing - I.E.
+to wear a scarf 'tied into a tight knot around the neck' or 'draped
+loosely across the shoulders' - to add an easy avenue of customization.
+For example, after entering:
+
+ wear scarf draped loosely across the shoulders
+
+The garment appears like so in the description:
+
+ Superuser(#1)
+ This is User #1.
+
+ Superuser is wearing a fanciful-looking scarf draped loosely
+ across the shoulders.
+
+Items of clothing can be used to cover other items, and many options
+are provided to define your own clothing types and their limits and
+behaviors. For example, to have undergarments automatically covered
+by outerwear, or to put a limit on the number of each type of item
+that can be worn. The system as-is is fairly freeform - you
+can cover any garment with almost any other, for example - but it
+can easily be made more restrictive, and can even be tied into a
+system for armor or other equipment.
+
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/clothing/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Color-Markups.md b/docs/source/Contribs/Contrib-Color-Markups.md
new file mode 100644
index 0000000000..71226f9277
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Color-Markups.md
@@ -0,0 +1,63 @@
+# Color markups
+
+Contribution, Griatch 2017
+
+Additional color markup styles for Evennia (extending or replacing the default
+`|r`, `|234` etc).
+
+
+## Installation
+
+Import the desired style variables from this module into
+mygame/server/conf/settings.py and add them to the settings variables below.
+Each are specified as a list, and multiple such lists can be added to each
+variable to support multiple formats. Note that list order affects which regexes
+are applied first. You must restart both Portal and Server for color tags to
+update.
+
+Assign to the following settings variables (see below for example):
+
+ COLOR_ANSI_EXTRA_MAP - a mapping between regexes and ANSI colors
+ COLOR_XTERM256_EXTRA_FG - regex for defining XTERM256 foreground colors
+ COLOR_XTERM256_EXTRA_BG - regex for defining XTERM256 background colors
+ COLOR_XTERM256_EXTRA_GFG - regex for defining XTERM256 grayscale foreground colors
+ COLOR_XTERM256_EXTRA_GBG - regex for defining XTERM256 grayscale background colors
+ COLOR_ANSI_BRIGHT_BG_EXTRA_MAP = ANSI does not support bright backgrounds; we fake
+ this by mapping ANSI markup to matching bright XTERM256 backgrounds
+
+ COLOR_NO_DEFAULT - Set True/False. If False (default), extend the default
+ markup, otherwise replace it completely.
+
+## Example
+
+To add the {- "curly-bracket" style, add the following to your settings file,
+then reboot both Server and Portal:
+
+```python
+from evennia.contrib.base_systems import color_markups
+COLOR_ANSI_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_EXTRA_MAP
+COLOR_XTERM256_EXTRA_FG = color_markups.CURLY_COLOR_XTERM256_EXTRA_FG
+COLOR_XTERM256_EXTRA_BG = color_markups.CURLY_COLOR_XTERM256_EXTRA_BG
+COLOR_XTERM256_EXTRA_GFG = color_markups.CURLY_COLOR_XTERM256_EXTRA_GFG
+COLOR_XTERM256_EXTRA_GBG = color_markups.CURLY_COLOR_XTERM256_EXTRA_GBG
+COLOR_ANSI_BRIGHT_BG_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BG_EXTRA_MAP
+```
+
+To add the `%c-` "mux/mush" style, add the following to your settings file, then
+reboot both Server and Portal:
+
+```python
+from evennia.contrib.base_systems import color_markups
+COLOR_ANSI_EXTRA_MAP = color_markups.MUX_COLOR_ANSI_EXTRA_MAP
+COLOR_XTERM256_EXTRA_FG = color_markups.MUX_COLOR_XTERM256_EXTRA_FG
+COLOR_XTERM256_EXTRA_BG = color_markups.MUX_COLOR_XTERM256_EXTRA_BG
+COLOR_XTERM256_EXTRA_GFG = color_markups.MUX_COLOR_XTERM256_EXTRA_GFG
+COLOR_XTERM256_EXTRA_GBG = color_markups.MUX_COLOR_XTERM256_EXTRA_GBG
+COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP
+```
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/color_markups/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Cooldowns.md b/docs/source/Contribs/Contrib-Cooldowns.md
new file mode 100644
index 0000000000..5272053de2
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Cooldowns.md
@@ -0,0 +1,64 @@
+# Cooldown contrib module.
+
+Evennia contrib - owllex, 2021
+
+This contrib provides a simple cooldown handler that can be attached to any
+typeclassed Object or Account. A cooldown is a lightweight persistent
+asynchronous timer that you can query to see if it is ready.
+
+Cooldowns are good for modelling rate-limited actions, like how often a
+character can perform a given command.
+
+Cooldowns are completely asynchronous and must be queried to know their
+state. They do not fire callbacks, so are not a good fit for use cases
+where something needs to happen on a specific schedule (use delay or
+a TickerHandler for that instead).
+
+See also the evennia documentation for command cooldowns
+(https://github.com/evennia/evennia/wiki/Command-Cooldown) for more information
+about the concept.
+
+## Installation
+
+To use, simply add the following property to the typeclass definition of any
+object type that you want to support cooldowns. It will expose a new `cooldowns`
+property that persists data to the object's attribute storage. You can set this
+on your base `Object` typeclass to enable cooldown tracking on every kind of
+object, or just put it on your `Character` typeclass.
+
+By default the CooldownHandler will use the `cooldowns` property, but you can
+customize this if desired by passing a different value for the `db_attribute`
+parameter.
+
+```python
+from evennia.game_systems.contrib.cooldowns import Cooldownhandler
+from evennia.utils.utils import lazy_property
+
+@lazy_property
+def cooldowns(self):
+ return CooldownHandler(self, db_attribute="cooldowns")
+```
+
+# Example
+
+Assuming you've installed cooldowns on your Character typeclasses, you can use a
+cooldown to limit how often you can perform a command. The following code
+snippet will limit the use of a Power Attack command to once every 10 seconds
+per character.
+
+```python
+class PowerAttack(Command):
+ def func(self):
+ if self.caller.cooldowns.ready("power attack"):
+ self.do_power_attack()
+ self.caller.cooldowns.add("power attack", 10)
+ else:
+ self.caller.msg("That's not ready yet!")
+
+```
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/cooldowns/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Crafting.md b/docs/source/Contribs/Contrib-Crafting.md
new file mode 100644
index 0000000000..a03b8ea7bf
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Crafting.md
@@ -0,0 +1,108 @@
+# Crafting system
+
+Contrib - Griatch 2020
+
+This implements a full crafting system. The principle is that of a 'recipe':
+
+ ingredient1 + ingredient2 + ... + tool1 + tool2 + ... + craft_recipe -> objectA, objectB, ...
+
+Here, 'ingredients' are consumed by the crafting process, whereas 'tools' are
+necessary for the process by will not be destroyed by it.
+
+An example would be to use the tools 'bowl' and 'oven' to use the ingredients
+'flour', 'salt', 'yeast' and 'water' to create 'bread' using the 'bread recipe'.
+
+A recipe does not have to use tools, like 'snow' + 'snowball-recipe' becomes
+'snowball'. Conversely one could also imagine using tools without consumables,
+like using 'spell book' and 'wand' to produce 'fireball' by having the recipe
+check some magic skill on the character.
+
+The system is generic enough to be used also for adventure-like puzzles, like
+combining 'stick', 'string' and 'hook' to get a 'makeshift fishing rod' that
+you can use with 'storm drain' (treated as a tool) to get 'key' ...
+
+## Intallation and Usage
+
+Import the `CmdCraft` command from evennia/contrib/crafting/crafting.py and
+add it to your Character cmdset. Reload and the `craft` command will be
+available to you:
+
+ craft [from ,...] [using , ...]
+
+For example
+
+ craft toy car from plank, wooden wheels, nails using saw, hammer
+
+To use crafting you need recipes. Add a new variable to `mygame/server/conf/settings.py`:
+
+ CRAFT_RECIPE_MODULES = ['world.recipes']
+
+All top-level classes in these modules (whose name does not start with `_`)
+will be parsed by Evennia as recipes to make available to the crafting system.
+Using the above example, create `mygame/world/recipes.py` and add your recipies
+in there:
+
+```python
+
+from evennia.contrib.game_systems.crafting import CraftingRecipe, CraftingValidationError
+
+
+class RecipeBread(CraftingRecipe):
+ """
+ Bread is good for making sandwitches!
+
+ """
+
+ name = "bread" # used to identify this recipe in 'craft' command
+ tool_tags = ["bowl", "oven"]
+ consumable_tags = ["flour", "salt", "yeast", "water"]
+ output_prototypes = [
+ {"key": "Loaf of Bread",
+ "aliases": ["bread"],
+ "desc": "A nice load of bread.",
+ "typeclass": "typeclasses.objects.Food", # assuming this exists
+ "tags": [("bread", "crafting_material")] # this makes it usable in other recipes ...
+ }
+
+ ]
+
+ def pre_craft(self, **kwargs):
+ # validates inputs etc. Raise `CraftingValidationError` if fails
+
+ def craft(self, **kwargs):
+ # performs the craft - but it can still fail (check skills etc here)
+
+ def craft(self, result, **kwargs):
+ # any post-crafting effects. Always called, even if crafting failed (be
+ # result would be None then)
+
+```
+
+## Technical
+
+The Recipe is a class that specifies the consumables, tools and output along
+with various methods (that you can override) to do the the validation of inputs
+and perform the crafting itself.
+
+By default the input is a list of object-tags (using the "crafting_material"
+and "crafting_tool" tag-categories respectively). Providing a set of objects
+matching these tags are required for the crafting to be done. The use of tags
+means that multiple different objects could all work for the same recipe, as
+long as they have the right tag. This can be very useful for allowing players
+to experiment and explore alternative ways to create things!
+
+The output is given by a set of prototype-dicts. If the input is correct and
+other checks are passed (such as crafting skill, for example), these prototypes
+will be used to generate the new object(s) being crafted.
+
+Each recipe is a stand-alone entity which allows for very advanced
+customization for every recipe - for example one could have a recipe that
+checks other properties of the inputs (like quality, color etc) and have that
+affect the result. Your recipes could also (and likely would) tie into your
+game's skill system to determine the success or outcome of the crafting.
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/crafting/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Custom-Gametime.md b/docs/source/Contribs/Contrib-Custom-Gametime.md
new file mode 100644
index 0000000000..1d1f008182
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Custom-Gametime.md
@@ -0,0 +1,53 @@
+# Custom gameime
+
+Contrib - Griatch 2017, vlgeoff 2017
+
+This reimplements the `evennia.utils.gametime` module but supporting a custom
+calendar for your game world. It allows for scheduling events to happen at given
+in-game times, taking this custom calendar into account.
+
+## Installation
+
+Import and use this in the same way as you would the normal
+`evennia.utils.gametime` module.
+
+Customize the calendar by adding a `TIME_UNITS` dict to your settings (see
+example below).
+
+
+## Usage:
+
+```python
+ from evennia.contrib.base_systems import custom_gametime
+
+ gametime = custom_gametime.realtime_to_gametime(days=23)
+
+ # scedule an event to fire every in-game 10 hours
+ custom_gametime.schedule(callback, repeat=True, hour=10)
+
+```
+
+The calendar can be customized by adding the `TIME_UNITS` dictionary to your
+settings file. This maps unit names to their length, expressed in the smallest
+unit. Here's the default as an example:
+
+ TIME_UNITS = {
+ "sec": 1,
+ "min": 60,
+ "hr": 60 * 60,
+ "hour": 60 * 60,
+ "day": 60 * 60 * 24,
+ "week": 60 * 60 * 24 * 7,
+ "month": 60 * 60 * 24 * 7 * 4,
+ "yr": 60 * 60 * 24 * 7 * 4 * 12,
+ "year": 60 * 60 * 24 * 7 * 4 * 12, }
+
+When using a custom calendar, these time unit names are used as kwargs to
+the converter functions in this module. Even if your calendar uses other names
+for months/weeks etc the system needs the default names internally.
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/custom_gametime/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Dice.md b/docs/source/Contribs/Contrib-Dice.md
new file mode 100644
index 0000000000..e5b99e2e72
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Dice.md
@@ -0,0 +1,67 @@
+# Dice
+
+Rolls dice for roleplaying, in-game gambling or GM:ing
+
+Evennia contribution - Griatch 2012
+
+# Installation:
+
+
+Add the `CmdDice` command from this module to your character's cmdset
+(and then restart the server):
+
+```python
+# in mygame/commands/default_cmdsets.py
+
+# ...
+from evennia.contrib.rpg import dice <---
+
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ # ...
+ def at_object_creation(self):
+ # ...
+ self.add(dice.CmdDice()) # <---
+
+```
+
+# Usage:
+
+ > roll 1d100 + 2
+ > roll 1d20
+ > roll 1d20 - 4
+
+The result of the roll will be echoed to the room
+
+One can also specify a standard Python operator in order to specify
+eventual target numbers and get results in a fair and guaranteed
+unbiased way. For example:
+
+ > roll 2d6 + 2 < 8
+
+Rolling this will inform all parties if roll was indeed below 8 or not.
+
+ > roll/hidden
+
+Informs the room that the roll is being made without telling what the result
+was.
+
+ > roll/secret
+
+Is a hidden roll that does not inform the room it happened.
+
+## Rolling dice from code
+
+To roll dice in code, use the `roll` function from this module:
+
+```python
+
+from evennia.contrib.rpg import dice
+dice.roll(3, 10, ("+", 2)) # 3d10 + 2
+
+```
+
+
+----
+
+This document page is generated from `evennia/contrib/rpg/dice/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Email-Login.md b/docs/source/Contribs/Contrib-Email-Login.md
new file mode 100644
index 0000000000..4de1b66218
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Email-Login.md
@@ -0,0 +1,36 @@
+# Email-based login system
+
+Evennia contrib - Griatch 2012
+
+This is a variant of the login system that requires an email-address
+instead of a username to login.
+
+This used to be the default Evennia login before replacing it with a
+more standard username + password system (having to supply an email
+for some reason caused a lot of confusion when people wanted to expand
+on it. The email is not strictly needed internally, nor is any
+confirmation email sent out anyway).
+
+## Installation
+
+To your settings file, add/edit the line:
+
+```python
+CMDSET_UNLOGGEDIN = "contrib.base_systems.email_login.UnloggedinCmdSet"
+CONNECTION_SCREEN_MODULE = "contrib.base_systems.email_login.connection_screens"
+
+```
+
+That's it. Reload the server and reconnect to see it.
+
+## Notes:
+
+If you want to modify the way the connection screen looks, point
+`CONNECTION_SCREEN_MODULE` to your own module. Use the default as a
+guide (see also Evennia docs).
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/email_login/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Evscaperoom.md b/docs/source/Contribs/Contrib-Evscaperoom.md
new file mode 100644
index 0000000000..b675d3f5df
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Evscaperoom.md
@@ -0,0 +1,128 @@
+# EvscapeRoom
+
+Evennia contrib - Griatch 2019
+
+This 'Evennia escaperoom game engine' was created for the MUD Coders Guild game
+Jam, April 14-May 15 2019. The theme for the jam was "One Room". This contains the
+utilities and base classes and an empty example room.
+
+The original code for the contest is found at
+https://github.com/Griatch/evscaperoom but the version on the public Evennia
+demo is more updated, so if you really want the latest bug fixes etc you should
+rather look at https://github.com/evennia/evdemo/tree/master/evdemo/evscaperoom
+instead. A copy of the full game can also be played on the Evennia demo server
+at https://demo.evennia.com - just connect to the server and write `evscaperoom`
+in the first room to start!
+
+# Introduction
+
+Evscaperoom is, as it sounds, an escaperoom in text form. You start locked into
+a room and have to figure out how to get out. This engine contains everything
+needed to make a fully-featured puzzle game of this type!
+
+# Installation
+
+The Evscaperoom is installed by adding the `evscaperoom` command to your
+character cmdset. When you run that command in-game you're ready to play!
+
+In `mygame/commands/default_cmdsets.py`:
+
+```python
+
+from evennia.contrib.full_systems.evscaperoom.commands import CmdEvscapeRoomStart
+
+class CharacterCmdSet(...):
+
+ # ...
+
+ self.add(CmdEvscapeRoomStart())
+
+```
+
+Reload the server and the `evscaperoom` command will be available. The contrib
+comes with a small (very small) escape room as an example.
+
+# Making your own evscaperoom
+
+To do this, you need to make your own states. First make sure you can play the
+simple example room installed above.
+
+Copy `evennia/contrib/full_systems/evscaperoom/states` to somewhere in your game folder (let's
+assume you put it under `mygame/world/`).
+
+Next you need to re-point Evennia to look for states in this new location. Add
+the following to your `mygame/server/conf/settings.py` file:
+
+```python
+ EVSCAPEROOM_STATE_PACKAGE = "world.states"
+
+```
+
+Reload and the example evscaperoom should still work, but you can now modify and
+expand it from your game dir!
+
+## Other useful settings
+
+There are a few other settings that may be useful:
+
+- `EVSCAPEROOM_START_STATE` - default is `state_001_start` and is the name of
+ the state-module to start from (without `.py`). You can change this if you
+ want some other naming scheme.
+- `HELP_SUMMARY_TEXT` - this is the help blurb shown when entering `help` in
+ the room without an argument. The original is found at the top of
+ `evennia/contrib/full_systems/evscaperoom/commands.py`.
+
+# Playing the game
+
+You should start by `look`ing around and at objects.
+
+The `examine ` command allows you to 'focus' on an object. When you do
+you'll learn actions you could try for the object you are focusing on, such as
+turning it around, read text on it or use it with some other object. Note that
+more than one player can focus on the same object, so you won't block anyone
+when you focus. Focusing on another object or use `examine` again will remove
+focus.
+
+There is also a full hint system.
+
+# Technical
+
+When connecting to the game, the user has the option to join an existing room
+(which may already be in some state of ongoing progress), or may create a fresh
+room for them to start solving on their own (but anyone may still join them later).
+
+The room will go through a series of 'states' as the players progress through
+its challenges. These states are describes as modules in .states/ and the
+room will load and execute the State-object within each module to set up
+and transition between states as the players progress. This allows for isolating
+the states from each other and will hopefully make it easier to track
+the logic and (in principle) inject new puzzles later.
+
+Once no players remain in the room, the room and its state will be wiped.
+
+# Design Philosophy
+
+Some basic premises inspired the design of this.
+
+- You should be able to resolve the room alone. So no puzzles should require the
+ collaboration of multiple players. This is simply because there is no telling
+ if others will actually be online at a given time (or stay online throughout).
+- You should never be held up by the actions/inactions of other players. This
+ is why you cannot pick up anything (no inventory system) but only
+ focus/operate on items. This avoids the annoying case of a player picking up
+ a critical piece of a puzzle and then logging off.
+- A room's state changes for everyone at once. My first idea was to have a given
+ room have different states depending on who looked (so a chest could be open
+ and closed to two different players at the same time). But not only does this
+ add a lot of extra complexity, it also defeats the purpose of having multiple
+ players. This way people can help each other and collaborate like in a 'real'
+ escape room. For people that want to do it all themselves I instead made it
+ easy to start "fresh" rooms for them to take on.
+
+All other design decisions flowed from these.
+
+
+----
+
+This document page is generated from `evennia/contrib/full_systems/evscaperoom/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Extended-Room.md b/docs/source/Contribs/Contrib-Extended-Room.md
new file mode 100644
index 0000000000..b125b8abec
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Extended-Room.md
@@ -0,0 +1,82 @@
+# Extended Room
+
+Evennia Contribution - Griatch 2012, vincent-lg 2019
+
+This is an extended Room typeclass for Evennia. It is supported
+by an extended `Look` command and an extended `desc` command, also
+in this module.
+
+## Installation/testing:
+
+Adding the `ExtendedRoomCmdset` to the default character cmdset will add all
+new commands for use.
+
+In more detail, in `mygame/commands/default_cmdsets.py`:
+
+```python
+...
+from evennia.contrib import extended_room # <---
+
+class CharacterCmdset(default_cmds.Character_CmdSet):
+ ...
+ def at_cmdset_creation(self):
+ ...
+ self.add(extended_room.ExtendedRoomCmdSet) # <---
+
+```
+
+Then reload to make the bew commands available. Note that they only work
+on rooms with the typeclass `ExtendedRoom`. Create new rooms with the right
+typeclass or use the `typeclass` command to swap existing rooms.
+
+## Features
+
+### Time-changing description slots
+
+This allows to change the full description text the room shows
+depending on larger time variations. Four seasons (spring, summer,
+autumn and winter) are used by default. The season is calculated
+on-demand (no Script or timer needed) and updates the full text block.
+
+There is also a general description which is used as fallback if
+one or more of the seasonal descriptions are not set when their
+time comes.
+
+An updated `desc` command allows for setting seasonal descriptions.
+
+The room uses the `evennia.utils.gametime.GameTime` global script. This is
+started by default, but if you have deactivated it, you need to
+supply your own time keeping mechanism.
+
+### In-description changing tags
+
+Within each seasonal (or general) description text, you can also embed
+time-of-day dependent sections. Text inside such a tag will only show
+during that particular time of day. The tags looks like ` ...
+ `. By default there are four timeslots per day - morning,
+afternoon, evening and night.
+
+### Details
+
+The Extended Room can be "detailed" with special keywords. This makes
+use of a special `Look` command. Details are "virtual" targets to look
+at, without there having to be a database object created for it. The
+Details are simply stored in a dictionary on the room and if the look
+command cannot find an object match for a `look ` command it
+will also look through the available details at the current location
+if applicable. The `detail` command is used to change details.
+
+### Extra commands
+
+- `CmdExtendedRoomLook` - look command supporting room details
+- `CmdExtendedRoomDesc` - desc command allowing to add seasonal descs,
+- `CmdExtendedRoomDetail` - command allowing to manipulate details in this room
+ as well as listing them
+- `CmdExtendedRoomGameTime` - A simple `time` command, displaying the current
+ time and season.
+
+
+----
+
+This document page is generated from `evennia/contrib/grid/extended_room/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Fieldfill.md b/docs/source/Contribs/Contrib-Fieldfill.md
new file mode 100644
index 0000000000..4a0cf99c59
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Fieldfill.md
@@ -0,0 +1,163 @@
+# Easy fillable form
+
+Contrib - Tim Ashley Jenkins 2018
+
+This module contains a function that calls an easily customizable EvMenu - this
+menu presents the player with a fillable form, with fields that can be filled
+out in any order. Each field's value can be verified, with the function
+allowing easy checks for text and integer input, minimum and maximum values /
+character lengths, or can even be verified by a custom function. Once the form
+is submitted, the form's data is submitted as a dictionary to any callable of
+your choice.
+
+The function that initializes the fillable form menu is fairly simple, and
+includes the caller, the template for the form, and the callback(caller, result)
+to which the form data will be sent to upon submission.
+
+ init_fill_field(formtemplate, caller, formcallback)
+
+Form templates are defined as a list of dictionaries - each dictionary
+represents a field in the form, and contains the data for the field's name and
+behavior. For example, this basic form template will allow a player to fill out
+a brief character profile:
+
+ PROFILE_TEMPLATE = [
+ {"fieldname":"Name", "fieldtype":"text"},
+ {"fieldname":"Age", "fieldtype":"number"},
+ {"fieldname":"History", "fieldtype":"text"},
+ ]
+
+This will present the player with an EvMenu showing this basic form:
+
+```
+ Name:
+ Age:
+ History:
+```
+
+While in this menu, the player can assign a new value to any field with the
+syntax = , like so:
+
+```
+ > name = Ashley
+ Field 'Name' set to: Ashley
+```
+
+Typing 'look' by itself will show the form and its current values.
+
+```
+ > look
+
+ Name: Ashley
+ Age:
+ History:
+```
+
+Number fields require an integer input, and will reject any text that can't
+be converted into an integer.
+
+```
+ > age = youthful
+ Field 'Age' requires a number.
+ > age = 31
+ Field 'Age' set to: 31
+```
+
+Form data is presented as an EvTable, so text of any length will wrap cleanly.
+
+```
+ > history = EVERY MORNING I WAKE UP AND OPEN PALM SLAM[...]
+ Field 'History' set to: EVERY MORNING I WAKE UP AND[...]
+ > look
+
+ Name: Ashley
+ Age: 31
+ History: EVERY MORNING I WAKE UP AND OPEN PALM SLAM A VHS INTO THE SLOT.
+ IT'S CHRONICLES OF RIDDICK AND RIGHT THEN AND THERE I START DOING
+ THE MOVES ALONGSIDE WITH THE MAIN CHARACTER, RIDDICK. I DO EVERY
+ MOVE AND I DO EVERY MOVE HARD.
+```
+
+When the player types 'submit' (or your specified submit command), the menu
+quits and the form's data is passed to your specified function as a dictionary,
+like so:
+
+ formdata = {"Name":"Ashley", "Age":31, "History":"EVERY MORNING I[...]"}
+
+You can do whatever you like with this data in your function - forms can be used
+to set data on a character, to help builders create objects, or for players to
+craft items or perform other complicated actions with many variables involved.
+
+The data that your form will accept can also be specified in your form template -
+let's say, for example, that you won't accept ages under 18 or over 100. You can
+do this by specifying "min" and "max" values in your field's dictionary:
+
+```
+ PROFILE_TEMPLATE = [
+ {"fieldname":"Name", "fieldtype":"text"},
+ {"fieldname":"Age", "fieldtype":"number", "min":18, "max":100},
+ {"fieldname":"History", "fieldtype":"text"}
+ ]
+```
+
+Now if the player tries to enter a value out of range, the form will not acept the
+given value.
+
+```
+ > age = 10
+ Field 'Age' reqiures a minimum value of 18.
+ > age = 900
+ Field 'Age' has a maximum value of 100.
+```
+
+Setting 'min' and 'max' for a text field will instead act as a minimum or
+maximum character length for the player's input.
+
+There are lots of ways to present the form to the player - fields can have default
+values or show a custom message in place of a blank value, and player input can be
+verified by a custom function, allowing for a great deal of flexibility. There
+is also an option for 'bool' fields, which accept only a True / False input and
+can be customized to represent the choice to the player however you like (E.G.
+Yes/No, On/Off, Enabled/Disabled, etc.)
+
+This module contains a simple example form that demonstrates all of the included
+functionality - a command that allows a player to compose a message to another
+online character and have it send after a custom delay. You can test it by
+importing this module in your game's `default_cmdsets.py` module and adding
+CmdTestMenu to your default character's command set.
+
+## FIELD TEMPLATE KEYS:
+
+### Required:
+
+```
+ fieldname (str): Name of the field, as presented to the player.
+ fieldtype (str): Type of value required: 'text', 'number', or 'bool'.
+```
+
+### Optional:
+
+- max (int): Maximum character length (if text) or value (if number).
+- min (int): Minimum charater length (if text) or value (if number).
+- truestr (str): String for a 'True' value in a bool field.
+ (E.G. 'On', 'Enabled', 'Yes')
+- falsestr (str): String for a 'False' value in a bool field.
+ (E.G. 'Off', 'Disabled', 'No')
+- default (str): Initial value (blank if not given).
+- blankmsg (str): Message to show in place of value when field is blank.
+- cantclear (bool): Field can't be cleared if True.
+- required (bool): If True, form cannot be submitted while field is blank.
+- verifyfunc (callable): Name of a callable used to verify input - takes
+ (caller, value) as arguments. If the function returns True,
+ the player's input is considered valid - if it returns False,
+ the input is rejected. Any other value returned will act as
+ the field's new value, replacing the player's input. This
+ allows for values that aren't strings or integers (such as
+ object dbrefs). For boolean fields, return '0' or '1' to set
+ the field to False or True.
+
+
+----
+
+This document page is generated from `evennia/contrib/utils/fieldfill/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Gendersub.md b/docs/source/Contribs/Contrib-Gendersub.md
new file mode 100644
index 0000000000..8cde5eb57c
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Gendersub.md
@@ -0,0 +1,55 @@
+# Gendersub
+
+Contrib - Griatch 2015
+
+This is a simple gender-aware Character class for allowing users to
+insert custom markers in their text to indicate gender-aware
+messaging. It relies on a modified msg() and is meant as an
+inspiration and starting point to how to do stuff like this.
+
+An object can have the following genders:
+
+- male (he/his)
+- female (her/hers)
+- neutral (it/its)
+- ambiguous (they/them/their/theirs)
+
+## Installation
+
+Import and add the `SetGender` command to your default cmdset in
+`mygame/commands/default_cmdset.py`
+
+Make your `Character` inherit from `GenderCharacter`.
+
+
+## Usage
+
+When in use, messages can contain special tags to indicate pronouns gendered
+based on the one being addressed. Capitalization will be retained.
+
+- `|s`, `|S`: Subjective form: he, she, it, He, She, It, They
+- `|o`, `|O`: Objective form: him, her, it, Him, Her, It, Them
+- `|p`, `|P`: Possessive form: his, her, its, His, Her, Its, Their
+- `|a`, `|A`: Absolute Possessive form: his, hers, its, His, Hers, Its, Theirs
+
+For example,
+
+```
+char.msg("%s falls on |p face with a thud." % char.key)
+"Tom falls on his face with a thud"
+```
+
+The default gender is "ambiguous" (they/them/their/theirs).
+
+To use, have DefaultCharacter inherit from this, or change
+setting.DEFAULT_CHARACTER to point to this class.
+
+The `gender` command is used to set the gender. It needs to be added to the
+default cmdset before it becomes available.
+
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/gendersub/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Health-Bar.md b/docs/source/Contribs/Contrib-Health-Bar.md
new file mode 100644
index 0000000000..e9e000dc86
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Health-Bar.md
@@ -0,0 +1,42 @@
+# Health Bar
+
+Contrib - Tim Ashley Jenkins 2017
+
+The function provided in this module lets you easily display visual
+bars or meters - "health bar" is merely the most obvious use for this,
+though these bars are highly customizable and can be used for any sort
+of appropriate data besides player health.
+
+Today's players may be more used to seeing statistics like health,
+stamina, magic, and etc. displayed as bars rather than bare numerical
+values, so using this module to present this data this way may make it
+more accessible. Keep in mind, however, that players may also be using
+a screen reader to connect to your game, which will not be able to
+represent the colors of the bar in any way. By default, the values
+represented are rendered as text inside the bar which can be read by
+screen readers.
+
+## Usage
+
+No installation, just import and use `display_meter` from this
+module:
+
+```python
+ from evennia.contrib.rpg.health_bar import display_meter
+
+ # health is 23/100
+ health_bar = display_meter(23, 100)
+ caller.msg(prompt=health_bar)
+
+```
+
+The health bar will account for current values above the maximum or
+below 0, rendering them as a completely full or empty bar with the
+values displayed within.
+
+
+
+----
+
+This document page is generated from `evennia/contrib/rpg/health_bar/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Ingame-Python.md b/docs/source/Contribs/Contrib-Ingame-Python.md
new file mode 100644
index 0000000000..5cb3872922
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Ingame-Python.md
@@ -0,0 +1,888 @@
+# Evennia in-game Python system
+
+Vincent Le Goff 2017
+
+This contrib adds the system of in-game Python in Evennia, allowing immortals
+(or other trusted builders) to dynamically add features to individual objects.
+Using custom Python set in-game, every immortal or privileged users could have a
+specific room, exit, character, object or something else behave differently from
+its "cousins". For these familiar with the use of softcode in MU`*`, like SMAUG
+MudProgs, the ability to add arbitrary behavior to individual objects is a step
+toward freedom. Keep in mind, however, the warning below, and read it carefully
+before the rest of the documentation.
+
+## A WARNING REGARDING SECURITY
+
+Evennia's in-game Python system will run arbitrary Python code without much
+restriction. Such a system is as powerful as potentially dangerous, and you
+will have to keep in mind these points before deciding to install it:
+
+1. Untrusted people can run Python code on your game server with this system.
+ Be careful about who can use this system (see the permissions below).
+2. You can do all of this in Python outside the game. The in-game Python system
+ is not to replace all your game feature.
+
+## Basic structure and vocabulary
+
+- At the basis of the in-game Python system are **events**. An **event**
+ defines the context in which we would like to call some arbitrary code. For
+instance, one event is defined on exits and will fire every time a character
+traverses through this exit. Events are described on a [typeclass](../Components/Typeclasses.md)
+([exits](../Components/Objects.md#exits) in our example). All objects inheriting from this
+typeclass will have access to this event.
+- **Callbacks** can be set on individual objects, on events defined in code.
+ These **callbacks** can contain arbitrary code and describe a specific
+behavior for an object. When the event fires, all callbacks connected to this
+object's event are executed.
+
+To see the system in context, when an object is picked up (using the default
+`get` command), a specific event is fired:
+
+1. The event "get" is set on objects (on the `Object` typeclass).
+2. When using the "get" command to pick up an object, this object's `at_get`
+ hook is called.
+3. A modified hook of DefaultObject is set by the event system. This hook will
+ execute (or call) the "get" event on this object.
+4. All callbacks tied to this object's "get" event will be executed in order.
+ These callbacks act as functions containing Python code that you can write
+ in-game, using specific variables that will be listed when you edit the callback
+ itself.
+5. In individual callbacks, you can add multiple lines of Python code that will
+ be fired at this point. In this example, the `character` variable will
+ contain the character who has picked up the object, while `obj` will contain the
+ object that was picked up.
+
+Following this example, if you create a callback "get" on the object "a sword",
+and put in it:
+
+```python
+character.msg("You have picked up {} and have completed this quest!".format(obj.get_display_name(character)))
+
+```
+
+When you pick up this object you should see something like:
+
+ You pick up a sword.
+ You have picked up a sword and have completed this quest!
+
+## Installation
+
+Being in a separate contrib, the in-game Python system isn't installed by
+default. You need to do it manually, following these steps:
+
+This is the quick summary. Scroll down for more detailed help on each step.
+
+1. Launch the main script (important!):
+ ```py evennia.create_script("evennia.contrib.base_systems.ingame_python.scripts.EventHandler")```
+2. Set the permissions (optional):
+ - `EVENTS_WITH_VALIDATION`: a group that can edit callbacks, but will need approval (default to
+ `None`).
+ - `EVENTS_WITHOUT_VALIDATION`: a group with permission to edit callbacks without need of
+ validation (default to `"immortals"`).
+ - `EVENTS_VALIDATING`: a group that can validate callbacks (default to `"immortals"`).
+ - `EVENTS_CALENDAR`: type of the calendar to be used (either `None`, `"standard"` or `"custom"`,
+ default to `None`).
+3. Add the `call` command.
+4. Inherit from the custom typeclasses of the in-game Python system.
+ - `evennia.contrib.base_systems.ingame_python.typeclasses.EventCharacter`: to replace `DefaultCharacter`.
+ - `evennia.contrib.base_systems.ingame_python.typeclasses.EventExit`: to replace `DefaultExit`.
+ - `evennia.contrib.base_systems.ingame_python.typeclasses.EventObject`: to replace `DefaultObject`.
+ - `evennia.contrib.base_systems.ingame_python.typeclasses.EventRoom`: to replace `DefaultRoom`.
+
+The following sections describe in details each step of the installation.
+
+> Note: If you were to start the game without having started the main script (such as when
+resetting your database) you will most likely face a traceback when logging in, telling you
+that a 'callback' property is not defined. After performing step `1` the error will go away.
+
+### Starting the event script
+
+To start the event script, you only need a single command, using `@py`.
+
+ py evennia.create_script("evennia.contrib.base_systems.ingame_python.scripts.EventHandler")
+
+This command will create a global script (that is, a script independent from any object). This
+script will hold basic configuration, individual callbacks and so on. You may access it directly,
+but you will probably use the callback handler. Creating this script will also create a `callback`
+handler on all objects (see below for details).
+
+### Editing permissions
+
+This contrib comes with its own set of permissions. They define who can edit callbacks without
+validation, and who can edit callbacks but needs validation. Validation is a process in which an
+administrator (or somebody trusted as such) will check the callbacks produced by others and will
+accept or reject them. If accepted, the callbacks are connected, otherwise they are never run.
+
+By default, callbacks can only be created by immortals: no one except the immortals can edit
+callbacks, and immortals don't need validation. It can easily be changed, either through settings
+or dynamically by changing permissions of users.
+
+The ingame-python contrib adds three [permissions](../Components/Permissions.md)) in the settings. You can
+override them by changing the settings into your `server/conf/settings.py` file (see below for an
+example). The settings defined in the events contrib are:
+
+- `EVENTS_WITH_VALIDATION`: this defines a permission that can edit callbacks, but will need
+ approval. If you set this to `"wizards"`, for instance, users with the permission `"wizards"`
+will be able to edit callbacks. These callbacks will not be connected, though, and will need to be
+checked and approved by an administrator. This setting can contain `None`, meaning that no user is
+allowed to edit callbacks with validation.
+- `EVENTS_WITHOUT_VALIDATION`: this setting defines a permission allowing editing of callbacks
+ without needing validation. By default, this setting is set to `"immortals"`. It means that
+immortals can edit callbacks, and they will be connected when they leave the editor, without needing
+approval.
+- `EVENTS_VALIDATING`: this last setting defines who can validate callbacks. By default, this is
+ set to `"immortals"`, meaning only immortals can see callbacks needing validation, accept or
+reject them.
+
+You can override all these settings in your `server/conf/settings.py` file. For instance:
+
+```python
+# ... other settings ...
+
+# Event settings
+EVENTS_WITH_VALIDATION = "wizards"
+EVENTS_WITHOUT_VALIDATION = "immortals"
+EVENTS_VALIDATING = "immortals"
+```
+
+In addition, there is another setting that must be set if you plan on using the time-related events
+(events that are scheduled at specific, in-game times). You would need to specify the type of
+calendar you are using. By default, time-related events are disabled. You can change the
+`EVENTS_CALENDAR` to set it to:
+
+- `"standard"`: the standard calendar, with standard days, months, years and so on.
+- `"custom"`: a custom calendar that will use the `custom_gametime` contrib to schedule events.
+
+This contrib defines two additional permissions that can be set on individual users:
+
+- `events_without_validation`: this would give this user the rights to edit callbacks but not
+ require validation before they are connected.
+- `events_validating`: this permission allows this user to run validation checks on callbacks
+ needing to be validated.
+
+For instance, to give the right to edit callbacks without needing approval to the player 'kaldara',
+you might do something like:
+
+ perm *kaldara = events_without_validation
+
+To remove this same permission, just use the `/del` switch:
+
+ perm/del *kaldara = events_without_validation
+
+The rights to use the `call` command are directly related to these permissions: by default, only
+users who have the `events_without_validation` permission or are in (or above) the group defined in
+the `EVENTS_WITH_VALIDATION` setting will be able to call the command (with different switches).
+
+### Adding the `call` command
+
+You also have to add the `@call` command to your Character CmdSet. This command allows your users
+to add, edit and delete callbacks in-game. In your `commands/default_cmdsets, it might look like
+this:
+
+```python
+from evennia import default_cmds
+from evennia.contrib.base_systems.ingame_python.commands import CmdCallback
+
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ """
+ The `CharacterCmdSet` contains general in-game commands like `look`,
+ `get`, etc available on in-game Character objects. It is merged with
+ the `PlayerCmdSet` when a Player puppets a Character.
+ """
+ key = "DefaultCharacter"
+
+ def at_cmdset_creation(self):
+ """
+ Populates the cmdset
+ """
+ super(CharacterCmdSet, self).at_cmdset_creation()
+ self.add(CmdCallback())
+```
+
+### Changing parent classes of typeclasses
+
+Finally, to use the in-game Python system, you need to have your typeclasses inherit from the modified event
+classes. For instance, in your `typeclasses/characters.py` module, you should change inheritance
+like this:
+
+```python
+from evennia.contrib.base_systems.ingame_python.typeclasses import EventCharacter
+
+class Character(EventCharacter):
+
+ # ...
+```
+
+You should do the same thing for your rooms, exits and objects. Note that the
+in-game Python system works by overriding some hooks. Some of these features
+might not be accessible in your game if you don't call the parent methods when
+overriding hooks.
+
+## Using the `call` command
+
+The in-game Python system relies, to a great extent, on its `call` command.
+Who can execute this command, and who can do what with it, will depend on your
+set of permissions.
+
+The `call` command allows to add, edit and delete callbacks on specific objects' events. The event
+system can be used on most Evennia objects, mostly typeclassed objects (excluding players). The
+first argument of the `call` command is the name of the object you want to edit. It can also be
+used to know what events are available for this specific object.
+
+### Examining callbacks and events
+
+To see the events connected to an object, use the `call` command and give the name or ID of the
+object to examine. For instance, `call here` to examine the events on your current location. Or
+`call self` to see the events on yourself.
+
+This command will display a table, containing:
+
+- The name of each event in the first column.
+- The number of callbacks of this name, and the number of total lines of these callbacks in the
+ second column.
+- A short help to tell you when the event is triggered in the third column.
+
+If you execute `call #1` for instance, you might see a table like this:
+
+```
++------------------+---------+-----------------------------------------------+
+| Event name | Number | Description |
++~~~~~~~~~~~~~~~~~~+~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
+| can_delete | 0 (0) | Can the character be deleted? |
+| can_move | 0 (0) | Can the character move? |
+| can_part | 0 (0) | Can the departing character leave this room? |
+| delete | 0 (0) | Before deleting the character. |
+| greet | 0 (0) | A new character arrives in the location of |
+| | | this character. |
+| move | 0 (0) | After the character has moved into its new |
+| | | room. |
+| puppeted | 0 (0) | When the character has been puppeted by a |
+| | | player. |
+| time | 0 (0) | A repeated event to be called regularly. |
+| unpuppeted | 0 (0) | When the character is about to be un- |
+| | | puppeted. |
++------------------+---------+-----------------------------------------------+
+```
+
+### Creating a new callback
+
+The `/add` switch should be used to add a callback. It takes two arguments beyond the object's
+name/DBREF:
+
+1. After an = sign, the name of the event to be edited (if not supplied, will display the list of
+ possible events, like above).
+2. The parameters (optional).
+
+We'll see callbacks with parameters later. For the time being, let's try to prevent a character
+from going through the "north" exit of this room:
+
+```
+@call north
++------------------+---------+-----------------------------------------------+
+| Event name | Number | Description |
++~~~~~~~~~~~~~~~~~~+~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
+| can_traverse | 0 (0) | Can the character traverse through this exit? |
+| msg_arrive | 0 (0) | Customize the message when a character |
+| | | arrives through this exit. |
+| msg_leave | 0 (0) | Customize the message when a character leaves |
+| | | through this exit. |
+| time | 0 (0) | A repeated event to be called regularly. |
+| traverse | 0 (0) | After the character has traversed through |
+| | | this exit. |
++------------------+---------+-----------------------------------------------+
+```
+
+If we want to prevent a character from traversing through this exit, the best event for us would be
+"can_traverse".
+
+> Why not "traverse"? If you read the description of both events, you will see "traverse" is called
+ **after** the character has traversed through this exit. It would be too late to prevent it. On
+> the other hand, "can_traverse" is obviously checked before the character traverses.
+
+When we edit the event, we have some more information:
+
+ call/add north = can_traverse
+
+Can the character traverse through this exit?
+This event is called when a character is about to traverse this
+exit. You can use the deny() eventfunc to deny the character from
+exiting for this time.
+
+Variables you can use in this event:
+
+ - character: the character that wants to traverse this exit.
+ - exit: the exit to be traversed.
+ - room: the room in which stands the character before moving.
+
+The section dedicated to [eventfuncs](#the-eventfuncs) will elaborate on the `deny()` function and
+other eventfuncs. Let us say, for the time being, that it can prevent an action (in this case, it
+can prevent the character from traversing through this exit). In the editor that opened when you
+used `call/add`, you can type something like:
+
+```python
+if character.id == 1:
+ character.msg("You're the superuser, 'course I'll let you pass.")
+else:
+ character.msg("Hold on, what do you think you're doing?")
+ deny()
+```
+
+You can now enter `:wq` to leave the editor by saving the callback.
+
+If you enter `call north`, you should see that "can_traverse" now has an active callback. You can
+use `call north = can_traverse` to see more details on the connected callbacks:
+
+```
+call north = can_traverse
++--------------+--------------+----------------+--------------+--------------+
+| Number | Author | Updated | Param | Valid |
++~~~~~~~~~~~~~~+~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~+~~~~~~~~~~~~~~+
+| 1 | XXXXX | 5 seconds ago | | Yes |
++--------------+--------------+----------------+--------------+--------------+
+```
+
+The left column contains callback numbers. You can use them to have even more information on a
+specific event. Here, for instance:
+
+```
+call north = can_traverse 1
+Callback can_traverse 1 of north:
+Created by XXXXX on 2017-04-02 17:58:05.
+Updated by XXXXX on 2017-04-02 18:02:50
+This callback is connected and active.
+Callback code:
+if character.id == 1:
+ character.msg("You're the superuser, 'course I'll let you pass.")
+else:
+ character.msg("Hold on, what do you think you're doing?")
+ deny()
+```
+
+Then try to walk through this exit. Do it with another character if possible, too, to see the
+difference.
+
+### Editing and removing a callback
+
+You can use the `/edit` switch to the `@call` command to edit a callback. You should provide, after
+the name of the object to edit and the equal sign:
+
+1. The name of the event (as seen above).
+2. A number, if several callbacks are connected at this location.
+
+You can type `call/edit = ` to see the callbacks that are linked at this
+location. If there is only one callback, it will be opened in the editor; if more are defined, you
+will be asked for a number to provide (for instance, `call/edit north = can_traverse 2`).
+
+The command `call` also provides a `/del` switch to remove a callback. It takes the same arguments
+as the `/edit` switch.
+
+When removed, callbacks are logged, so an administrator can retrieve its content, assuming the
+`/del` was an error.
+
+### The code editor
+
+When adding or editing a callback, the event editor should open in code mode. The additional
+options supported by the editor in this mode are describe in [a dedicated section of the EvEditor's
+documentation](https://github.com/evennia/evennia/wiki/EvEditor#the-eveditor-to-edit-code).
+
+## Using events
+
+The following sections describe how to use events for various tasks, from the most simple to the
+most complex.
+
+### The eventfuncs
+
+In order to make development a little easier, the in-game Python system provides eventfuncs to be used in
+callbacks themselves. You don't have to use them, they are just shortcuts. An eventfunc is just a
+simple function that can be used inside of your callback code.
+
+Function | Argument | Description | Example
+-----------|--------------------------|-----------------------------------|--------
+deny | `()` | Prevent an action from happening. | `deny()`
+get | `(**kwargs)` | Get a single object. | `char = get(id=1)`
+call_event | `(obj, name, seconds=0)` | Call another event. | `call_event(char, "chain_1", 20)`
+
+#### deny
+
+The `deny()` function allows to interrupt the callback and the action that called it. In the
+`can_*` events, it can be used to prevent the action from happening. For instance, in `can_say` on
+rooms, it can prevent the character from saying something in the room. One could have a `can_eat`
+event set on food that would prevent this character from eating this food.
+
+Behind the scenes, the `deny()` function raises an exception that is being intercepted by the
+handler of events. The handler will then report that the action was cancelled.
+
+#### get
+
+The `get` eventfunc is a shortcut to get a single object with a specific identity. It's often used
+to retrieve an object with a given ID. In the section dedicated to [chained
+events](#chained-events), you will see a concrete example of this function in action.
+
+#### call_event
+
+Some callbacks will call other events. It is particularly useful for [chained
+events](#chained-events) that are described in a dedicated section. This eventfunc is used to call
+another event, immediately or in a defined time.
+
+You need to specify as first parameter the object containing the event. The second parameter is the
+name of the event to call. The third parameter is the number of seconds before calling this event.
+By default, this parameter is set to 0 (the event is called immediately).
+
+### Variables in callbacks
+
+In the Python code you will enter in individual callbacks, you will have access to variables in your
+locals. These variables will depend on the event, and will be clearly listed when you add or edit a
+callback. As you've seen in the previous example, when we manipulate characters or character
+actions, we often have a `character` variable that holds the character doing the action.
+
+In most cases, when an event is fired, all callbacks from this event are called. Variables are
+created for each event. Sometimes, however, the callback will execute and then ask for a variable
+in your locals: in other words, some callbacks can alter the actions being performed by changing
+values of variables. This is always clearly specified in the help of the event.
+
+One example that will illustrate this system is the "msg_leave" event that can be set on exits.
+This event can alter the message that will be sent to other characters when someone leaves through
+this exit.
+
+ call/add down = msg_leave
+
+Which should display:
+
+```
+Customize the message when a character leaves through this exit.
+This event is called when a character leaves through this exit.
+To customize the message that will be sent to the room where the
+character came from, change the value of the variable "message"
+to give it your custom message. The character itself will not be
+notified. You can use mapping between braces, like this:
+ message = "{character} falls into a hole!"
+In your mapping, you can use {character} (the character who is
+about to leave), {exit} (the exit), {origin} (the room in which
+the character is), and {destination} (the room in which the character
+is heading for). If you need to customize the message with other
+information, you can also set "message" to None and send something
+else instead.
+
+Variables you can use in this event:
+ character: the character who is leaving through this exit.
+ exit: the exit being traversed.
+ origin: the location of the character.
+ destination: the destination of the character.
+ message: the message to be displayed in the location.
+ mapping: a dictionary containing additional mapping.
+```
+
+If you write something like this in your event:
+
+```python
+message = "{character} falls into a hole in the ground!"
+
+```
+
+And if the character Wilfred takes this exit, others in the room will see:
+
+ Wildred falls into a hole in the ground!
+
+In this case, the in-game Python system placed the variable "message" in the callback locals, but will read
+from it when the event has been executed.
+
+### Callbacks with parameters
+
+Some callbacks are called without parameter. It has been the case for all examples we have seen
+before. In some cases, you can create callbacks that are triggered under only some conditions. A
+typical example is the room's "say" event. This event is triggered when somebody says something in
+the room. Individual callbacks set on this event can be configured to fire only when some words are
+used in the sentence.
+
+For instance, let's say we want to create a cool voice-operated elevator. You enter into the
+elevator and say the floor number... and the elevator moves in the right direction. In this case,
+we could create an callback with the parameter "one":
+
+ call/add here = say one
+
+This callback will only fire when the user says a sentence that contains "one".
+
+But what if we want to have a callback that would fire if the user says 1 or one? We can provide
+several parameters, separated by a comma.
+
+ call/add here = say 1, one
+
+Or, still more keywords:
+
+ call/add here = say 1, one, ground
+
+This time, the user could say something like "take me to the ground floor" ("ground" is one of our
+keywords defined in the above callback).
+
+Not all events can take parameters, and these who do have different ways of handling them. There
+isn't a single meaning to parameters that could apply to all events. Refer to the event
+documentation for details.
+
+> If you get confused between callback variables and parameters, think of parameters as checks
+> performed before the callback is run. Event with parameters will only fire some specific
+> callbacks, not all of them.
+
+### Time-related events
+
+Events are usually linked to commands, as we saw before. However, this is not always the case.
+Events can be triggered by other actions and, as we'll see later, could even be called from inside
+other events!
+
+There is a specific event, on all objects, that can trigger at a specific time. It's an event with
+a mandatory parameter, which is the time you expect this event to fire.
+
+For instance, let's add an event on this room that should trigger every day, at precisely 12:00 PM
+(the time is given as game time, not real time):
+
+ call here = time 12:00
+
+```python
+# This will be called every MUD day at 12:00 PM
+room.msg_contents("It's noon, time to have lunch!")
+
+```
+
+Now, at noon every MUD day, this event will fire and this callback will be executed. You can use
+this event on every kind of typeclassed object, to have a specific action done every MUD day at the
+same time.
+
+Time-related events can be much more complex than this. They can trigger every in-game hour or more
+often (it might not be a good idea to have events trigger that often on a lot of objects). You can
+have events that run every in-game week or month or year. It will greatly vary depending on the
+type of calendar used in your game. The number of time units is described in the game
+configuration.
+
+With a standard calendar, for instance, you have the following units: minutes, hours, days, months
+and years. You will specify them as numbers separated by either a colon (:), a space ( ), or a dash
+(-). Pick whatever feels more appropriate (usually, we separate hours and minutes with a colon, the
+other units with a dash).
+
+Some examples of syntax:
+
+- `18:30`: every day at 6:30 PM.
+- `01 12:00`: every month, the first day, at 12 PM.
+- `06-15 09:58`: every year, on the 15th of June (month comes before day), at 9:58 AM.
+- `2025-01-01 00:00`: January 1st, 2025 at midnight (obviously, this will trigger only once).
+
+Notice that we specify units in the reverse order (year, month, day, hour and minute) and separate
+them with logical separators. The smallest unit that is not defined is going to set how often the
+event should fire. That's why, if you use `12:00`, the smallest unit that is not defined is "day":
+the event will fire every day at the specified time.
+
+> You can use chained events (see below) in conjunction with time-related events to create more
+random or frequent actions in events.
+
+### Chained events
+
+Callbacks can call other events, either now or a bit later. It is potentially very powerful.
+
+To use chained events, just use the `call_event` eventfunc. It takes 2-3 arguments:
+
+- The object containing the event.
+- The name of the event to call.
+- Optionally, the number of seconds to wait before calling this event.
+
+All objects have events that are not triggered by commands or game-related operations. They are
+called "chain_X", like "chain_1", "chain_2", "chain_3" and so on. You can give them more specific
+names, as long as it begins by "chain_", like "chain_flood_room".
+
+Rather than a long explanation, let's look at an example: a subway that will go from one place to
+the next at regular times. Connecting exits (opening its doors), waiting a bit, closing them,
+rolling around and stopping at a different station. That's quite a complex set of callbacks, as it
+is, but let's only look at the part that opens and closes the doors:
+
+ call/add here = time 10:00
+
+```python
+# At 10:00 AM, the subway arrives in the room of ID 22.
+# Notice that exit #23 and #24 are respectively the exit leading
+# on the platform and back in the subway.
+station = get(id=22)
+to_exit = get(id=23)
+back_exit = get(id=24)
+
+# Open the door
+to_exit.name = "platform"
+to_exit.aliases = ["p"]
+to_exit.location = room
+to_exit.destination = station
+back_exit.name = "subway"
+back_exit.location = station
+back_exit.destination = room
+
+# Display some messages
+room.msg_contents("The doors open and wind gushes in the subway")
+station.msg_contents("The doors of the subway open with a dull clank.")
+
+# Set the doors to close in 20 seconds
+call_event(room, "chain_1", 20)
+```
+
+This callback will:
+
+1. Be called at 10:00 AM (specify 22:00 to set it to 10:00 PM).
+2. Set an exit between the subway and the station. Notice that the exits already exist (you will
+ not have to create them), but they don't need to have specific location and destination.
+3. Display a message both in the subway and on the platform.
+4. Call the event "chain_1" to execute in 20 seconds.
+
+And now, what should we have in "chain_1"?
+
+ call/add here = chain_1
+
+```python
+# Close the doors
+to_exit.location = None
+to_exit.destination = None
+back_exit.location = None
+back_exit.destination = None
+room.msg_content("After a short warning signal, the doors close and the subway begins moving.")
+station.msg_content("After a short warning signal, the doors close and the subway begins moving.")
+```
+
+Behind the scenes, the `call_event` function freezes all variables ("room", "station", "to_exit",
+"back_exit" in our example), so you don't need to define them again.
+
+A word of caution on callbacks that call chained events: it isn't impossible for a callback to call
+itself at some recursion level. If `chain_1` calls `chain_2` that calls `chain_3` that calls
+`chain_`, particularly if there's no pause between them, you might run into an infinite loop.
+
+Be also careful when it comes to handling characters or objects that may very well move during your
+pause between event calls. When you use `call_event()`, the MUD doesn't pause and commands can be
+entered by players, fortunately. It also means that, a character could start an event that pauses
+for awhile, but be gone when the chained event is called. You need to check that, even lock the
+character into place while you are pausing (some actions should require locking) or at least,
+checking that the character is still in the room, for it might create illogical situations if you
+don't.
+
+> Chained events are a special case: contrary to standard events, they are created in-game, not
+ through code. They usually contain only one callback, although nothing prevents you from creating
+ several chained events in the same object.
+
+## Using events in code
+
+This section describes callbacks and events from code, how to create new events, how to call them in
+a command, and how to handle specific cases like parameters.
+
+Along this section, we will see how to implement the following example: we would like to create a
+"push" command that could be used to push objects. Objects could react to this command and have
+specific events fired.
+
+### Adding new events
+
+Adding new events should be done in your typeclasses. Events are contained in the `_events` class
+variable, a dictionary of event names as keys, and tuples to describe these events as values. You
+also need to register this class, to tell the in-game Python system that it contains events to be added to
+this typeclass.
+
+Here, we want to add a "push" event on objects. In your `typeclasses/objects.py` file, you should
+write something like:
+
+```python
+from evennia.contrib.base_systems.ingame_python.utils import register_events
+from evennia.contrib.base_systems.ingame_python.typeclasses import EventObject
+
+EVENT_PUSH = """
+A character push the object.
+This event is called when a character uses the "push" command on
+an object in the same room.
+
+Variables you can use in this event:
+ character: the character that pushes this object.
+ obj: the object connected to this event.
+"""
+
+@register_events
+class Object(EventObject):
+ """
+ Class representing objects.
+ """
+
+ _events = {
+ "push": (["character", "obj"], EVENT_PUSH),
+ }
+```
+
+- Line 1-2: we import several things we will need from the in-game Python system. Note that we use
+ `EventObject` as a parent instead of `DefaultObject`, as explained in the installation.
+- Line 4-12: we usually define the help of the event in a separate variable, this is more readable,
+ though there's no rule against doing it another way. Usually, the help should contain a short
+explanation on a single line, a longer explanation on several lines, and then the list of variables
+with explanations.
+- Line 14: we call a decorator on the class to indicate it contains events. If you're not familiar
+ with decorators, you don't really have to worry about it, just remember to put this line just
+above the class definition if your class contains events.
+- Line 15: we create the class inheriting from `EventObject`.
+- Line 20-22: we define the events of our objects in an `_events` class variable. It is a
+ dictionary. Keys are event names. Values are a tuple containing:
+ - The list of variable names (list of str). This will determine what variables are needed when
+ the event triggers. These variables will be used in callbacks (as we'll see below).
+ - The event help (a str, the one we have defined above).
+
+If you add this code and reload your game, create an object and examine its events with `@call`, you
+should see the "push" event with its help. Of course, right now, the event exists, but it's not
+fired.
+
+### Calling an event in code
+
+The in-game Python system is accessible through a handler on all objects. This handler is named `callbacks`
+and can be accessed from any typeclassed object (your character, a room, an exit...). This handler
+offers several methods to examine and call an event or callback on this object.
+
+To call an event, use the `callbacks.call` method in an object. It takes as argument:
+
+- The name of the event to call.
+- All variables that will be accessible in the event as positional arguments. They should be
+ specified in the order chosen when [creating new events](#adding-new-events).
+
+Following the same example, so far, we have created an event on all objects, called "push". This
+event is never fired for the time being. We could add a "push" command, taking as argument the name
+of an object. If this object is valid, it will call its "push" event.
+
+```python
+from commands.command import Command
+
+class CmdPush(Command):
+
+ """
+ Push something.
+
+ Usage:
+ push
+
+ Push something where you are, like an elevator button.
+
+ """
+
+ key = "push"
+
+ def func(self):
+ """Called when pushing something."""
+ if not self.args.strip():
+ self.msg("Usage: push ")
+ return
+
+ # Search for this object
+ obj = self.caller.search(self.args)
+ if not obj:
+ return
+
+ self.msg("You push {}.".format(obj.get_display_name(self.caller)))
+
+ # Call the "push" event of this object
+ obj.callbacks.call("push", self.caller, obj)
+```
+
+Here we use `callbacks.call` with the following arguments:
+
+- `"push"`: the name of the event to be called.
+- `self.caller`: the one who pushed the button (this is our first variable, `character`).
+- `obj`: the object being pushed (our second variable, `obj`).
+
+In the "push" callbacks of our objects, we then can use the "character" variable (containing the one
+who pushed the object), and the "obj" variable (containing the object that was pushed).
+
+### See it all work
+
+To see the effect of the two modifications above (the added event and the "push" command), let us
+create a simple object:
+
+ @create/drop rock
+ @desc rock = It's a single rock, apparently pretty heavy. Perhaps you can try to push it though.
+ @call/add rock = push
+
+In the callback you could write:
+
+```python
+from random import randint
+number = randint(1, 6)
+character.msg("You push a rock... is... it... going... to... move?")
+if number == 6:
+ character.msg("The rock topples over to reveal a beautiful ant-hill!")
+```
+
+You can now try to "push rock". You'll try to push the rock, and once out of six times, you will
+see a message about a "beautiful ant-hill".
+
+### Adding new eventfuncs
+
+Eventfuncs, like `deny()`, are defined in
+`contrib/base_systesm/ingame_python/eventfuncs.py`. You can add your own
+eventfuncs by creating a file named `eventfuncs.py` in your `world` directory.
+The functions defined in this file will be added as helpers.
+
+You can also decide to create your eventfuncs in another location, or even in
+several locations. To do so, edit the `EVENTFUNCS_LOCATION` setting in your
+`server/conf/settings.py` file, specifying either a python path or a list of
+Python paths in which your helper functions are defined. For instance:
+
+```python
+EVENTFUNCS_LOCATIONS = [
+ "world.events.functions",
+]
+```
+
+### Creating events with parameters
+
+If you want to create events with parameters (if you create a "whisper" or "ask" command, for
+instance, and need to have some characters automatically react to words), you can set an additional
+argument in the tuple of events in your typeclass' `_events` class variable. This third argument
+must contain a callback that will be called to filter through the list of callbacks when the event
+fires. Two types of parameters are commonly used (but you can define more parameter types, although
+this is out of the scope of this documentation).
+
+- Keyword parameters: callbacks of this event will be filtered based on specific keywords. This is
+ useful if you want the user to specify a word and compare this word to a list.
+- Phrase parameters: callbacks will be filtered using an entire phrase and checking all its words.
+ The "say" command uses phrase parameters (you can set a "say" callback to fires if a phrase
+contains one specific word).
+
+In both cases, you need to import a function from
+`evennia.contrib.base_systems.ingame_python.utils` and use it as third parameter in your
+event definition.
+
+- `keyword_event` should be used for keyword parameters.
+- `phrase_event` should be used for phrase parameters.
+
+For example, here is the definition of the "say" event:
+
+```python
+from evennia.contrib.base_systems.ingame_python.utils import register_events, phrase_event
+# ...
+@register_events
+class SomeTypeclass:
+ _events = {
+ "say": (["speaker", "character", "message"], CHARACTER_SAY, phrase_event),
+ }
+```
+
+When you call an event using the `obj.callbacks.call` method, you should also provide the parameter,
+using the `parameters` keyword:
+
+```python
+obj.callbacks.call(..., parameters="")
+```
+
+It is necessary to specifically call the event with parameters, otherwise the system will not be
+able to know how to filter down the list of callbacks.
+
+## Disabling all events at once
+
+When callbacks are running in an infinite loop, for instance, or sending unwanted information to
+players or other sources, you, as the game administrator, have the power to restart without events.
+The best way to do this is to use a custom setting, in your setting file
+(`server/conf/settings.py`):
+
+```python
+# Disable all events
+EVENTS_DISABLED = True
+```
+
+The in-game Python system will still be accessible (you will have access to the `call` command, to debug),
+but no event will be called automatically.
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/ingame_python/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Mail.md b/docs/source/Contribs/Contrib-Mail.md
new file mode 100644
index 0000000000..027844ba84
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Mail.md
@@ -0,0 +1,46 @@
+# In-Game Mail system
+
+Evennia Contribution - grungies1138 2016
+
+A simple Brandymail style mail system that uses the Msg class from Evennia
+Core. It has two Commands, both of which can be used on their own:
+
+ - CmdMail - this should sit on the Account cmdset and makes the `mail` command
+ available both IC and OOC. Mails will always go to Accounts (other players).
+ - CmdMailCharacter - this should sit on the Character cmdset and makes the `mail`
+ command ONLY available when puppeting a character. Mails will be sent to other
+ Characters only and will not be available when OOC.
+ - If adding *both* commands to their respective cmdsets, you'll get two separate
+ IC and OOC mailing systems, with different lists of mail for IC and OOC modes.
+
+## Installation:
+
+Install one or both of the following (see above):
+
+- CmdMail (IC + OOC mail, sent between players)
+
+ # mygame/commands/default_cmds.py
+
+ from evennia.contrib.game_systems import mail
+
+ # in AccountCmdSet.at_cmdset_creation:
+ self.add(mail.CmdMail())
+
+- CmdMailCharacter (optional, IC only mail, sent between characters)
+
+ # mygame/commands/default_cmds.py
+
+ from evennia.contrib.game_systems import mail
+
+ # in CharacterCmdSet.at_cmdset_creation:
+ self.add(mail.CmdMailCharacter())
+
+Once installed, use `help mail` in game for help with the mail command. Use
+ic/ooc to switch in and out of IC/OOC modes.
+
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/mail/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Mapbuilder.md b/docs/source/Contribs/Contrib-Mapbuilder.md
new file mode 100644
index 0000000000..bbbc73def7
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Mapbuilder.md
@@ -0,0 +1,284 @@
+# Map Builder
+
+Contribution - Cloud_Keeper 2016
+
+Build a map from a 2D ASCII map.
+
+This is a command which takes two inputs:
+
+ ≈≈≈≈≈
+ ≈♣n♣≈ MAP_LEGEND = {("♣", "♠"): build_forest,
+ ≈∩▲∩≈ ("∩", "n"): build_mountains,
+ ≈♠n♠≈ ("▲"): build_temple}
+ ≈≈≈≈≈
+
+A string of ASCII characters representing a map and a dictionary of functions
+containing build instructions. The characters of the map are iterated over and
+compared to a list of trigger characters. When a match is found the
+corresponding function is executed generating the rooms, exits and objects as
+defined by the users build instructions. If a character is not a match to
+a provided trigger character (including spaces) it is simply skipped and the
+process continues.
+
+For instance, the above map represents a temple (▲) amongst mountains (n,∩)
+in a forest (♣,♠) on an island surrounded by water (≈). Each character on the
+first line is iterated over but as there is no match with our `MAP_LEGEND`, it
+is skipped. On the second line it finds "♣" which is a match and so the
+`build_forest` function is called. Next the `build_mountains` function is
+called and so on until the map is completed. Building instructions are passed
+the following arguments:
+
+ x - The rooms position on the maps x axis
+ y - The rooms position on the maps y axis
+ caller - The account calling the command
+ iteration - The current iterations number (0, 1 or 2)
+ room_dict - A dictionary containing room references returned by build
+ functions where tuple coordinates are the keys (x, y).
+ ie room_dict[(2, 2)] will return the temple room above.
+
+Building functions should return the room they create. By default these rooms
+are used to create exits between valid adjacent rooms to the north, south,
+east and west directions. This behaviour can turned off with the use of switch
+arguments. In addition to turning off automatic exit generation the switches
+allow the map to be iterated over a number of times. This is important for
+something like custom exit building. Exits require a reference to both the
+exits location and the exits destination. During the first iteration it is
+possible that an exit is created pointing towards a destination that
+has not yet been created resulting in error. By iterating over the map twice
+the rooms can be created on the first iteration and room reliant code can be
+be used on the second iteration. The iteration number and a dictionary of
+references to rooms previously created is passed to the build commands.
+
+You then call the command in-game using the path to the MAP and MAP_LEGEND vars
+The path you provide is relative to the evennia or mygame folder.
+
+# Installation
+
+Use by importing and including the command in your default_cmdsets module.
+For example:
+
+```python
+ # mygame/commands/default_cmdsets.py
+
+ from evennia.contrib.grid import mapbuilder
+
+ ...
+
+ self.add(mapbuilder.CmdMapBuilder())
+```
+
+
+# Usage:
+
+ mapbuilder[/switch]
+
+ one - execute build instructions once without automatic exit creation.
+ two - execute build instructions twice without automatic exit creation.
+
+# Examples
+
+ mapbuilder world.gamemap.MAP world.maplegend.MAP_LEGEND
+ mapbuilder evennia.contrib.grid.mapbuilder.EXAMPLE1_MAP EXAMPLE1_LEGEND
+ mapbuilder/two evennia.contrib.grid.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND
+ (Legend path defaults to map path)
+
+Below are two examples showcasing the use of automatic exit generation and
+custom exit generation. Whilst located, and can be used, from this module for
+convenience The below example code should be in mymap.py in mygame/world.
+
+## Example One
+
+```python
+
+from django.conf import settings
+from evennia.utils import utils
+
+# mapbuilder evennia.contrib.grid.mapbuilder.EXAMPLE1_MAP EXAMPLE1_LEGEND
+
+# -*- coding: utf-8 -*-
+
+# Add the necessary imports for your instructions here.
+from evennia import create_object
+from typeclasses import rooms, exits
+from random import randint
+import random
+
+
+# A map with a temple (▲) amongst mountains (n,∩) in a forest (♣,♠) on an
+# island surrounded by water (≈). By giving no instructions for the water
+# characters we effectively skip it and create no rooms for those squares.
+EXAMPLE1_MAP = '''
+≈≈≈≈≈
+≈♣n♣≈
+≈∩▲∩≈
+≈♠n♠≈
+≈≈≈≈≈
+'''
+
+def example1_build_forest(x, y, **kwargs):
+ '''A basic example of build instructions. Make sure to include **kwargs
+ in the arguments and return an instance of the room for exit generation.'''
+
+ # Create a room and provide a basic description.
+ room = create_object(rooms.Room, key="forest" + str(x) + str(y))
+ room.db.desc = "Basic forest room."
+
+ # Send a message to the account
+ kwargs["caller"].msg(room.key + " " + room.dbref)
+
+ # This is generally mandatory.
+ return room
+
+
+def example1_build_mountains(x, y, **kwargs):
+ '''A room that is a little more advanced'''
+
+ # Create the room.
+ room = create_object(rooms.Room, key="mountains" + str(x) + str(y))
+
+ # Generate a description by randomly selecting an entry from a list.
+ room_desc = [
+ "Mountains as far as the eye can see",
+ "Your path is surrounded by sheer cliffs",
+ "Haven't you seen that rock before?",
+ ]
+ room.db.desc = random.choice(room_desc)
+
+ # Create a random number of objects to populate the room.
+ for i in range(randint(0, 3)):
+ rock = create_object(key="Rock", location=room)
+ rock.db.desc = "An ordinary rock."
+
+ # Send a message to the account
+ kwargs["caller"].msg(room.key + " " + room.dbref)
+
+ # This is generally mandatory.
+ return room
+
+
+def example1_build_temple(x, y, **kwargs):
+ '''A unique room that does not need to be as general'''
+
+ # Create the room.
+ room = create_object(rooms.Room, key="temple" + str(x) + str(y))
+
+ # Set the description.
+ room.db.desc = (
+ "In what, from the outside, appeared to be a grand and "
+ "ancient temple you've somehow found yourself in the the "
+ "Evennia Inn! It consists of one large room filled with "
+ "tables. The bardisk extends along the east wall, where "
+ "multiple barrels and bottles line the shelves. The "
+ "barkeep seems busy handing out ale and chatting with "
+ "the patrons, which are a rowdy and cheerful lot, "
+ "keeping the sound level only just below thunderous. "
+ "This is a rare spot of mirth on this dread moor."
+ )
+
+ # Send a message to the account
+ kwargs["caller"].msg(room.key + " " + room.dbref)
+
+ # This is generally mandatory.
+ return room
+
+
+# Include your trigger characters and build functions in a legend dict.
+EXAMPLE1_LEGEND = {
+ ("♣", "♠"): example1_build_forest,
+ ("∩", "n"): example1_build_mountains,
+ ("▲"): example1_build_temple,
+}
+```
+
+## Example Two
+
+```python
+# @mapbuilder/two evennia.contrib.grid.mapbuilder.EXAMPLE2_MAP EXAMPLE2_LEGEND
+
+# -*- coding: utf-8 -*-
+
+# Add the necessary imports for your instructions here.
+# from evennia import create_object
+# from typeclasses import rooms, exits
+# from evennia.utils import utils
+# from random import randint
+# import random
+
+# This is the same layout as Example 1 but included are characters for exits.
+# We can use these characters to determine which rooms should be connected.
+EXAMPLE2_MAP = '''
+≈ ≈ ≈ ≈ ≈
+
+≈ ♣-♣-♣ ≈
+ | |
+≈ ♣ ♣ ♣ ≈
+ | | |
+≈ ♣-♣-♣ ≈
+
+≈ ≈ ≈ ≈ ≈
+'''
+
+def example2_build_forest(x, y, **kwargs):
+ '''A basic room'''
+ # If on anything other than the first iteration - Do nothing.
+ if kwargs["iteration"] > 0:
+ return None
+
+ room = create_object(rooms.Room, key="forest" + str(x) + str(y))
+ room.db.desc = "Basic forest room."
+
+ kwargs["caller"].msg(room.key + " " + room.dbref)
+
+ return room
+
+def example2_build_verticle_exit(x, y, **kwargs):
+ '''Creates two exits to and from the two rooms north and south.'''
+ # If on the first iteration - Do nothing.
+ if kwargs["iteration"] == 0:
+ return
+
+ north_room = kwargs["room_dict"][(x, y - 1)]
+ south_room = kwargs["room_dict"][(x, y + 1)]
+
+ # create exits in the rooms
+ create_object(
+ exits.Exit, key="south", aliases=["s"], location=north_room, destination=south_room
+ )
+
+ create_object(
+ exits.Exit, key="north", aliases=["n"], location=south_room, destination=north_room
+ )
+
+ kwargs["caller"].msg("Connected: " + north_room.key + " & " + south_room.key)
+
+
+def example2_build_horizontal_exit(x, y, **kwargs):
+ '''Creates two exits to and from the two rooms east and west.'''
+ # If on the first iteration - Do nothing.
+ if kwargs["iteration"] == 0:
+ return
+
+ west_room = kwargs["room_dict"][(x - 1, y)]
+ east_room = kwargs["room_dict"][(x + 1, y)]
+
+ create_object(exits.Exit, key="east", aliases=["e"], location=west_room, destination=east_room)
+
+ create_object(exits.Exit, key="west", aliases=["w"], location=east_room, destination=west_room)
+
+ kwargs["caller"].msg("Connected: " + west_room.key + " & " + east_room.key)
+
+
+# Include your trigger characters and build functions in a legend dict.
+EXAMPLE2_LEGEND = {
+ ("♣", "♠"): example2_build_forest,
+ ("|"): example2_build_verticle_exit,
+ ("-"): example2_build_horizontal_exit,
+}
+
+```
+
+
+----
+
+This document page is generated from `evennia/contrib/grid/mapbuilder/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Menu-Login.md b/docs/source/Contribs/Contrib-Menu-Login.md
new file mode 100644
index 0000000000..846fef07a2
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Menu-Login.md
@@ -0,0 +1,28 @@
+# Menu-based login system
+
+Contribution - Vincent-lg 2016, Griatch 2019 (rework for modern EvMenu)
+
+This changes the Evennia login to ask for the account name and password in
+sequence instead of requiring you to enter both at once. It uses EvMenu under
+the hood.
+
+## Installation
+
+To install, add this to `mygame/server/conf/settings.py`:
+
+ CMDSET_UNLOGGEDIN = "evennia.contrib.base_systems.menu_login.UnloggedinCmdSet"
+ CONNECTION_SCREEN_MODULE = "contrib.base_systems.menu_login.connection_screens"
+
+Reload the server and reconnect to see the changes.
+
+## Notes
+
+If you want to modify the way the connection screen looks, point
+`CONNECTION_SCREEN_MODULE` to your own module. Use the default as a
+guide (see also Evennia docs).
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/menu_login/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Mirror.md b/docs/source/Contribs/Contrib-Mirror.md
new file mode 100644
index 0000000000..87f872f2ea
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Mirror.md
@@ -0,0 +1,23 @@
+# TutorialMirror
+
+A simple mirror object to experiment with.
+
+A simple mirror object that
+
+- echoes back the description of the object looking at it
+- echoes back whatever is being sent to its .msg - to the
+ sender, if given, otherwise to the location of the mirror.
+
+## Installation
+
+Create the mirror with
+
+ create/drop mirror:contrib.tutorials.mirror.TutorialMirror
+
+Then look at it.
+
+
+----
+
+This document page is generated from `evennia/contrib/tutorials/mirror/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Multidescer.md b/docs/source/Contribs/Contrib-Multidescer.md
new file mode 100644
index 0000000000..842ac0ab41
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Multidescer.md
@@ -0,0 +1,30 @@
+# Evennia Multidescer
+
+Contrib - Griatch 2016
+
+A "multidescer" is a concept from the MUSH world. It allows for
+creating, managing and switching between multiple character
+descriptions. This multidescer will not require any changes to the
+Character class, rather it will use the `multidescs` Attribute (a
+list) and create it if it does not exist.
+
+This contrib also works well together with the rpsystem contrib (which
+also adds the short descriptions and the `sdesc` command).
+
+## Installation
+
+Edit `mygame/commands/default_cmdsets.py` and add
+`from evennia.contrib.game_systems.multidescer import CmdMultiDesc` to the top.
+
+Next, look up the `at_cmdset_create` method of the `CharacterCmdSet`
+class and add a line `self.add(CmdMultiDesc())` to the end
+of it.
+
+Reload the server and you should have the +desc command available (it
+will replace the default `desc` command).
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/multidescer/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Mux-Comms-Cmds.md b/docs/source/Contribs/Contrib-Mux-Comms-Cmds.md
new file mode 100644
index 0000000000..7ab4a10d5d
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Mux-Comms-Cmds.md
@@ -0,0 +1,48 @@
+# Legacy Comms-commands
+
+Contribution - Griatch 2021
+
+In Evennia 1.0, the old Channel commands (originally inspired by MUX) were
+replaced by the single `channel` command that performs all these function.
+That command is still required to talk on channels. This contrib (extracted
+from Evennia 0.9.5) reuses the channel-management of the base Channel command
+but breaks out its functionality into separate Commands with MUX-familiar names.
+
+- `allcom` - `channel/all` and `channel`
+- `addcom` - `channel/alias`, `channel/sub` and `channel/unmute`
+- `delcom` - `channel/unalias`, `alias/unsub` and `channel/mute`
+- `cboot` - `channel/boot` (`channel/ban` and `/unban` not supported)
+- `cwho` - `channel/who`
+- `ccreate` - `channel/create`
+- `cdestroy` - `channel/destroy`
+- `clock` - `channel/lock`
+- `cdesc` - `channel/desc`
+
+## Installation
+
+- Import the `CmdSetLegacyComms` cmdset from this module into `mygame/commands/default_cmdsets.py`
+- Add it to the CharacterCmdSet's `at_cmdset_creation` method (see below).
+- Reload the server.
+
+```python
+# in mygame/commands/default_cmdsets.py
+
+# ..
+from evennia.contrib.base_systems.mux_comms_cmds import CmdSetLegacyComms # <----
+
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ # ...
+ def at_cmdset_creation(self):
+ # ...
+ self.add(CmdSetLegacyComms) # <----
+
+```
+
+Note that you will still be able to use the `channel` command; this is actually
+still used under the hood by these commands.
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/mux_comms_cmds/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Overview.md b/docs/source/Contribs/Contrib-Overview.md
index 24d4ae9d8d..92a4de663e 100644
--- a/docs/source/Contribs/Contrib-Overview.md
+++ b/docs/source/Contribs/Contrib-Overview.md
@@ -1,335 +1,625 @@
-# Contrib modules
+# Contribs
-Contribs are found in [evennia/contrib/](evennia.contrib) and are optional game-specific code-snippets
-or even full systems you can use for your game. They are contributed by the Evennia community and
-released under the same license as Evennia itself. Each contrib has its own installation instructions.
-Bugs are reported to the Evennia [issue tracker](github:issue) as usual.
+_Contribs_ are optional code snippets and systems contributed by
+the Evennia community. They vary in size and complexity and
+may be more specific about game types and styles than 'core' Evennia.
+This page is auto-generated and summarizes all contribs currently included.
-## Character-related
+All contrib categories are imported from `evennia.contrib`, such as
-Contribs related to characters and character displays.
+ from evennia.contrib.base_systems import building_menu
-### CharGen
+Each contrib contains installation instructions for how to integrate it
+with your other code. If you want to tweak the code of a contrib, just
+copy its entire folder to your game directory and modify/use it from there.
-*Griatch 2011*
+If you want to contribute yourself, see [here](../Contributing.md)!
-A simple Character creator for OOC mode. Meant as a starting point for a more fleshed-out system.
+> Hint: Additional (potentially un-maintained) code snippets from the community can be found
+in our discussion forum's [Community Contribs & Snippets](https://github.com/evennia/evennia/discussions/categories/community-contribs-snippets) category.
-### Clothing
-*FlutterSprite 2017*
-A layered clothing system with slots for different types of garments auto-showing in description.
+## base_systems
-### Health Bar
+_This category contains systems that are not necessarily tied to a specific
+in-game mechanic but is useful for the game as a whole. Examples include
+login systems, new command syntaxes, and build helpers._
-*Tim Ashley Jenkins 2017*
-Tool to create colorful bars/meters.
+### Contrib: `awsstorage`
-### Multidescer
+Contrib by The Right Honourable Reverend (trhr) 2020
-*Griatch 2016*
+## What is this for?
-Advanced descriptions combined from many separate description components, inspired by MUSH.
+[Read the documentation](./Contrib-AWSStorage.md)
----
-## Rooms, movement and grid
-Contribs modifying locations, movement or helping to creating rooms.
+### Contrib: `building_menu`
-### XYZGrid
+Module containing the building menu system.
-*Griatch 2021*
+Evennia contributor: vincent-lg 2018
-Adds an XYZgrid to Evennia, with map-display and pathfinding. Created via map
-strings and maintained outside of the game via Evennia launch commands.
+[Read the documentation](./Contrib-Building-Menu.md)
-- [XYZGrid documentation](./XYZGrid.md)
-### Extended Room
-*Griatch 2012*
+### Contrib: `color_markups`
-An expanded Room typeclass with multiple descriptions for time and season as well as details.
+Contribution, Griatch 2017
-### Map Builder
+Additional color markup styles for Evennia (extending or replacing the default
+`|r`, `|234` etc).
-*CloudKeeper 2016*
+[Read the documentation](./Contrib-Color-Markups.md)
-Build a game area based on a 2D "graphical" unicode map. Supports asymmetric exits.
-- [Static in-game map](./Static-In-Game-Map.md)
-### Simple Door
+### Contrib: `custom_gametime`
-*Griatch 2014*
+Contrib - Griatch 2017, vlgeoff 2017
-Example of an exit that can be opened and closed from both sides.
+This reimplements the `evennia.utils.gametime` module but supporting a custom
+calendar for your game world. It allows for scheduling events to happen at given
+in-game times, taking this custom calendar into account.
-### Slow exit
+[Read the documentation](./Contrib-Custom-Gametime.md)
-*Griatch 2014*
-Custom Exit class that takes different time to pass depending on if you are walking/running etc.
-### Wilderness
+### Contrib: `email_login`
-*titeuf87 2017*
+Evennia contrib - Griatch 2012
-Make infinitely large wilderness areas with dynamically created locations.
+This is a variant of the login system that requires an email-address
+instead of a username to login.
-- [Dynamic in-game map](./Dynamic-In-Game-Map.md)
+[Read the documentation](./Contrib-Email-Login.md)
-----
-## Roleplaying and rules
-Contribs supporting roleplay and in-game roleplaying actions.
+### Contrib: `ingame_python`
-### Barter system
+Vincent Le Goff 2017
-*Griatch 2012*
+This contrib adds the system of in-game Python in Evennia, allowing immortals
+(or other trusted builders) to dynamically add features to individual objects.
+Using custom Python set in-game, every immortal or privileged users could have a
+specific room, exit, character, object or something else behave differently from
+its "cousins". For these familiar with the use of softcode in MU`*`, like SMAUG
+MudProgs, the ability to add arbitrary behavior to individual objects is a step
+toward freedom. Keep in mind, however, the warning below, and read it carefully
+before the rest of the documentation.
-A safe and effective barter-system for any game. Allows safe trading of any goods (including coin).
+[Read the documentation](./Contrib-Ingame-Python.md)
-### Crafting
-*Griatch 2020*
-A full, extendable crafting system.
+### Contrib: `menu_login`
-- [Crafting overview](./Crafting.md)
-- [Crafting API documentation](evennia.contrib.crafting.crafting)
-- [Example of a sword crafting tree](evennia.contrib.crafting.example_recipes)
+Contribution - Vincent-lg 2016, Griatch 2019 (rework for modern EvMenu)
-### Dice
+This changes the Evennia login to ask for the account name and password in
+sequence instead of requiring you to enter both at once. It uses EvMenu under
+the hood.
-*Griatch 2012*
+[Read the documentation](./Contrib-Menu-Login.md)
-A fully featured dice rolling system.
-### Mail
-*grungies1138 2016*
+### Contrib: `mux_comms_cmds`
-An in-game mail system for communication.
+Contribution - Griatch 2021
-### Puzzles
+In Evennia 1.0, the old Channel commands (originally inspired by MUX) were
+replaced by the single `channel` command that performs all these function.
+That command is still required to talk on channels. This contrib (extracted
+from Evennia 0.9.5) reuses the channel-management of the base Channel command
+but breaks out its functionality into separate Commands with MUX-familiar names.
-*Hendher 2019*
+[Read the documentation](./Contrib-Mux-Comms-Cmds.md)
-Combine objects to create new items, adventure-game style
-### RP System
-*Griatch 2015*
+### Contrib: `unixcommand`
-Full director-style emoting system replacing names with sdescs/recogs. Supports wearing masks.
+Evennia contribution, Vincent Le Geoff 2017
-### RP Language
+This module contains a command class that allows for unix-style command syntax
+in-game, using --options, positional arguments and stuff like -n 10 etc
+similarly to a unix command. It might not the best syntax for the average player
+but can be really useful for builders when they need to have a single command do
+many things with many options. It uses the ArgumentParser from Python's standard
+library under the hood.
-*Griatch 2015*
+[Read the documentation](./Contrib-Unixcommand.md)
-Dynamic obfuscation of emotes when speaking unfamiliar languages. Also obfuscates whispers.
-### Traits
-*Whitenoise 2014, Griatch2021*
-Powerful on-object properties (very extended Attributes) for representing
-health, mana, skill-levels etc, with automatic min/max value, base, modifiers
-and named tiers for different values. Also include timed rate increase/decrease
-to have values change over a period of time.
+## full_systems
-### Turnbattle
+_This category contains 'complete' game engines that can be used directly
+to start creating content without no further additions (unless you want to)._
-*FlutterSprite 2017*
-A turn-based combat engine meant as a start to build from. Has attack/disengage and turn timeouts,
-and includes optional expansions for equipment and combat movement, magic and ranged combat.
+### Contrib: `evscaperoom`
-----
+Evennia contrib - Griatch 2019
-## Building and server systems
+This 'Evennia escaperoom game engine' was created for the MUD Coders Guild game
+Jam, April 14-May 15 2019. The theme for the jam was "One Room". This contains the
+utilities and base classes and an empty example room.
-### Building menu
+[Read the documentation](./Contrib-Evscaperoom.md)
-*vincent-lg 2018*
-An `@edit` command for modifying objects using a generated menu. Customizable for different games.
-### Field Fill
-*FlutterSprite 2018*
-A simple system for creating an EvMenu that presents a player with a highly customizable fillable form
-### In-Game-Python
+## game_systems
-*Vincent Le Geoff 2017*
+_This category holds code implementing in-game gameplay systems like
+crafting, mail, combat and more. Each system is meant to be adopted
+piecemeal and adopted for your game. This does not include
+roleplaying-specific systems, those are found in the `rpg` folder._
-Allow Builders to add Python-scripted events to their objects (OBS-not for untrusted users!)
-- [A voice-operated elevator using events](./A-voice-operated-elevator-using-events.md)
-- [Dialogues using events](./Dialogues-in-events.md)
+### Contrib: `barter`
-### Menu-builder
+Evennia contribution - Griatch 2012
-A tool for building using an in-game menu instead of the normal build commands. Meant to
-be expanded for the needs of your game.
+This implements a full barter system - a way for players to safely
+trade items between each other using code rather than simple free-form
+talking. The advantage of this is increased buy/sell safety but it
+also streamlines the process and makes it faster when doing many
+transactions (since goods are automatically exchanged once both
+agree).
-- [Building Menus](./Building-menus.md)
+[Read the documentation](./Contrib-Barter.md)
-### Security/Auditing
-*Johhny 2018*
-Log server input/output for debug/security.
+### Contrib: `clothing`
-### Tree Select
+Evennia contribution - Tim Ashley Jenkins 2017
-*FlutterSprite 2017*
+Provides a typeclass and commands for wearable clothing,
+which is appended to a character's description when worn.
-A simple system for creating a branching EvMenu with selection options sourced from a single
-multi-line string.
+[Read the documentation](./Contrib-Clothing.md)
----
-## Snippets and config
-Contribs meant to be used as part of other code, or as replacements for default settings.
+### Contrib: `cooldowns`
-### Color-markups
+Evennia contrib - owllex, 2021
-*Griatch, 2017*
+This contrib provides a simple cooldown handler that can be attached to any
+typeclassed Object or Account. A cooldown is a lightweight persistent
+asynchronous timer that you can query to see if it is ready.
-Alternative in-game color markups.
+[Read the documentation](./Contrib-Cooldowns.md)
-### Custom gametime
-*Griatch, vlgeoff 2017*
-Implements Evennia's gametime module but for custom game world-specific calendars.
+### Contrib: `crafting`
-### Logins
+Contrib - Griatch 2020
-#### Email login
+This implements a full crafting system. The principle is that of a 'recipe':
-*Griatch 2012*
+[Read the documentation](./Contrib-Crafting.md)
-A variant of the standard login system that requires an email to login rather then just name+password.
-#### Menu login
-*Griatch 2011, 2019, Vincent-lg 2016*
+### Contrib: `gendersub`
-A login system using menus asking for name/password rather than giving them as one command.
+Contrib - Griatch 2015
-### Random String Generator
+This is a simple gender-aware Character class for allowing users to
+insert custom markers in their text to indicate gender-aware
+messaging. It relies on a modified msg() and is meant as an
+inspiration and starting point to how to do stuff like this.
-*Vincent Le Goff 2017*
+[Read the documentation](./Contrib-Gendersub.md)
-Simple pseudo-random generator of strings with rules, avoiding repetitions.
-### UnixCommand
-*Vincent Le Geoff 2017*
+### Contrib: `mail`
-Add commands with UNIX-style syntax.
+Evennia Contribution - grungies1138 2016
-----
+A simple Brandymail style mail system that uses the Msg class from Evennia
+Core. It has two Commands, both of which can be used on their own:
-## Examples
+[Read the documentation](./Contrib-Mail.md)
-Contribs not meant to be used as-is, but just as examples to learn from.
-### GenderSub
-*Griatch 2015*
+### Contrib: `multidescer`
-Simple example (only) of storing gender on a character and access it in an emote with a custom marker.
+Contrib - Griatch 2016
-### Talking NPC
+A "multidescer" is a concept from the MUSH world. It allows for
+creating, managing and switching between multiple character
+descriptions. This multidescer will not require any changes to the
+Character class, rather it will use the `multidescs` Attribute (a
+list) and create it if it does not exist.
-*Griatch 2011*
+[Read the documentation](./Contrib-Multidescer.md)
-A talking NPC object that offers a menu-driven conversation tree.
-### Tutorial examples
-*Griatch 2011, 2015*
+### Contrib: `puzzles`
-A folder of basic example objects, commands and scripts.
+Evennia contribution - Henddher 2018
-### The tutorial-world
+Provides a typeclass and commands for objects that can be combined (i.e. 'use'd)
+to produce new objects.
-*Griatch 2011, 2015*
+[Read the documentation](./Contrib-Puzzles.md)
-The Evennia single-player sole quest. Made to be analyzed to learn.
-- [The tutorial world introduction](../Howto/Starting/Part1/Tutorial-World-Introduction.md)
-----
+### Contrib: `turnbattle`
-## Full game systems
+Contrib - Tim Ashley Jenkins 2017
-Full game-dir replacement systems.
+This is a framework for a simple turn-based combat system, similar
+to those used in D&D-style tabletop role playing games. It allows
+any character to start a fight in a room, at which point initiative
+is rolled and a turn order is established. Each participant in combat
+has a limited time to decide their action for that turn (30 seconds by
+default), and combat progresses through the turn order, looping through
+the participants until the fight ends.
-### Ainneve
+[Read the documentation](./Contrib-Turnbattle.md)
-*Evennia community 2015-?*
-This is a community attempt to make an Evennia 'example game' using good practices. It is also a good
-place to jump in if you want to help in another project rather than run it alone. Development of this
-has stalled a bit so we are looking for enthusiastic people to lead the charge.
-- [evennia/ainneve repository](https://github.com/evennia/ainneve)
-- [Original discussion thread](https://groups.google.com/g/evennia/c/48PMDirb7go/m/Z9EAuvXZn7UJ) (external link)
-### Arxcode
-*Tehom 2019*
-Open source code release of the popular Evennia-based [Arx, after the reckoning](https://play.arxgame.org/).
-This is a fantasy game with a focus on roleplay and code-supported political intrigue. This code-release
-is maintained by Tehom in its own repository so bug reports should be directed there.
+## grid
-- [Arxcode repository on github](https://github.com/Arx-Game/arxcode)
-- [Arxcode issue tracker](https://github.com/Arx-Game/arxcode/issues)
-- [Arxcode installation help](./Arxcode-installing-help.md) - this may not always be fully up-to-date with
- latest Evennia. Report your findings!
+_Systems related to the game world's topology and structure. This has
+contribs related to rooms, exits and map building._
-### Evscaperoom
-*Griatch 2019*
+### Contrib: `extended_room`
+
+Evennia Contribution - Griatch 2012, vincent-lg 2019
+
+This is an extended Room typeclass for Evennia. It is supported
+by an extended `Look` command and an extended `desc` command, also
+in this module.
+
+[Read the documentation](./Contrib-Extended-Room.md)
+
+
+
+### Contrib: `mapbuilder`
+
+Contribution - Cloud_Keeper 2016
+
+Build a map from a 2D ASCII map.
+
+[Read the documentation](./Contrib-Mapbuilder.md)
+
+
+
+### Contrib: `simpledoor`
+
+Contribution - Griatch 2016
+
+A simple two-way exit that represents a door that can be opened and
+closed. Can easily be expanded from to make it lockable, destroyable
+etc. Note that the simpledoor is based on Evennia locks, so it will
+not work for a superuser (which bypasses all locks) - the superuser
+will always appear to be able to close/open the door over and over
+without the locks stopping you. To use the door, use `@quell` or a
+non-superuser account.
+
+[Read the documentation](./Contrib-Simpledoor.md)
+
+
+
+### Contrib: `slow_exit`
+
+Contribution - Griatch 2014
+
+This is an example of an Exit-type that delays its traversal. This simulates
+slow movement, common in many different types of games. The contrib also
+contains two commands, `CmdSetSpeed` and CmdStop for changing the movement speed
+and abort an ongoing traversal, respectively.
+
+[Read the documentation](./Contrib-Slow-Exit.md)
+
+
+
+### Contrib: `wilderness`
+
+Evennia contrib - titeuf87 2017
+
+This contrib provides a wilderness map without actually creating a large number
+of rooms - as you move, your room is instead updated with different
+descriptions. This means you can make huge areas with little database use as
+long as the rooms are relatively similar (name/desc changing).
+
+[Read the documentation](./Contrib-Wilderness.md)
+
+
+
+### Contrib: `xyzgrid`
+
+Full grid coordinate- pathfinding and visualization system
+Evennia Contrib by Griatch 2021
+
+The default Evennia's rooms are non-euclidian - they can connect
+to each other with any types of exits without necessarily having a clear
+position relative to each other. This gives maximum flexibility, but many games
+want to use cardinal movements (north, east etc) and also features like finding
+the shortest-path between two points.
+
+[Read the documentation](./Contrib-XYZGrid.md)
+
+
+
+
+
+
+## rpg
+
+_These are systems specifically related to roleplaying
+and rule implementation like character traits, dice rolling and emoting._
+
+
+### Contrib: `dice`
+
+Rolls dice for roleplaying, in-game gambling or GM:ing
+
+Evennia contribution - Griatch 2012
+
+[Read the documentation](./Contrib-Dice.md)
+
+
+
+### Contrib: `health_bar`
+
+Contrib - Tim Ashley Jenkins 2017
+
+The function provided in this module lets you easily display visual
+bars or meters - "health bar" is merely the most obvious use for this,
+though these bars are highly customizable and can be used for any sort
+of appropriate data besides player health.
+
+[Read the documentation](./Contrib-Health-Bar.md)
+
+
+
+### Contrib: `rpsystem`
+
+Roleplaying emotes/sdescs - Griatch, 2015
+Language/whisper emotes - Griatch, 2015
+
+## Roleplaying emotes
+
+[Read the documentation](./Contrib-RPSystem.md)
+
+
+
+### Contrib: `traits`
+
+Whitenoise 2014, Ainneve contributors,
+Griatch 2020
+
+A `Trait` represents a modifiable property on (usually) a Character. They can
+be used to represent everything from attributes (str, agi etc) to skills
+(hunting 10, swords 14 etc) and dynamically changing things like HP, XP etc.
+
+[Read the documentation](./Contrib-Traits.md)
+
+
+
+
+
+
+## tutorials
+
+_Helper resources specifically meant to teach a development concept or
+to exemplify an Evennia system. Any extra resources tied to documentation
+tutorials are found here. Also the home of the Tutorial World demo adventure._
+
+
+### Contrib: `batchprocessor`
+
+Contibution - Griatch 2012
+
+The batch processor is used for generating in-game content from one or more
+static files. Files can be stored with version control and then 'applied'
+to the game to create content.
+
+[Read the documentation](./Contrib-Batchprocessor.md)
+
+
+
+### Contrib: `bodyfunctions`
+
+Griatch - 2012
+
+Example script for testing. This adds a simple timer that has your
+character make observations and notices at irregular intervals.
+
+[Read the documentation](./Contrib-Bodyfunctions.md)
+
+
+
+### Contrib: `mirror`
+
+A simple mirror object to experiment with.
+
+A simple mirror object that
+
+[Read the documentation](./Contrib-Mirror.md)
+
+
+
+### Contrib: `red_button`
+
+Griatch - 2011
+
+This is a more advanced example object with its own functionality (commands)
+on it.
+
+[Read the documentation](./Contrib-Red-Button.md)
+
+
+
+### Contrib: `talking_npc`
+
+Contribution - Griatch 2011, grungies1138, 2016
+
+This is a static NPC object capable of holding a simple menu-driven
+conversation. It's just meant as an example.
+
+[Read the documentation](./Contrib-Talking-Npc.md)
+
+
+
+### Contrib: `tutorial_world`
+
+Griatch 2011, 2015
+
+This is a stand-alone tutorial area for an unmodified Evennia install.
+Think of it as a sort of single-player adventure rather than a
+full-fledged multi-player game world. The various rooms and objects
+herein are designed to show off features of the engine, not to be a
+very challenging (nor long) gaming experience. As such it's of course
+only skimming the surface of what is possible.
+
+[Read the documentation](./Contrib-Tutorial-World.md)
+
+
+
+
+
+
+## utils
+
+_Miscellaneous, optional tools for manipulating text, auditing connections
+and more._
+
+
+### Contrib: `auditing`
+
+Contrib - Johnny 2017
+
+This is a tap that optionally intercepts all data sent to/from clients and the
+server and passes it to a callback of your choosing.
+
+[Read the documentation](./Contrib-Auditing.md)
+
+
+
+### Contrib: `fieldfill`
+
+Contrib - Tim Ashley Jenkins 2018
+
+This module contains a function that calls an easily customizable EvMenu - this
+menu presents the player with a fillable form, with fields that can be filled
+out in any order. Each field's value can be verified, with the function
+allowing easy checks for text and integer input, minimum and maximum values /
+character lengths, or can even be verified by a custom function. Once the form
+is submitted, the form's data is submitted as a dictionary to any callable of
+your choice.
+
+[Read the documentation](./Contrib-Fieldfill.md)
+
+
+
+### Contrib: `random_string_generator`
+
+Contribution - Vincent Le Goff 2017
+
+This contrib can be used to generate pseudo-random strings of information
+with specific criteria. You could, for instance, use it to generate
+phone numbers, license plate numbers, validation codes, non-sensivite
+passwords and so on. The strings generated by the generator will be
+stored and won't be available again in order to avoid repetition.
+Here's a very simple example:
+
+[Read the documentation](./Contrib-Random-String-Generator.md)
+
+
+
+### Contrib: `tree_select`
+
+Contrib - Tim Ashley Jenkins 2017
+
+This module allows you to create and initialize an entire branching EvMenu
+instance with nothing but a multi-line string passed to one function.
+
+[Read the documentation](./Contrib-Tree-Select.md)
-A full engine for making multiplayer 'escape-rooms' completely in code.
-This is based on the 2019 MUD Game jam winner *Evscaperoom*.
-- [contrib/evscaperoom](evennia.contrib.evscaperoom) - game engine to make your own escape rooms.
-- [https://demo.evennia.com](https://demo.evennia.com) - a full installation of the original game can
- be played by entering the *evscaperoom* exit in the first Limbo room.
-- https://github.com/Griatch/evscaperoom - the original game's source code (warning for spoilers if you
- want to solve the puzzles and mystery yourself).
```{toctree}
-:hidden:
+:depth: 2
-./Crafting
-../api/evennia.contrib.crafting.crafting
-../api/evennia.contrib.crafting.example_recipes
-./A-voice-operated-elevator-using-events
-./Dialogues-in-events
-./Dynamic-In-Game-Map
-./Static-In-Game-Map
-../Howto/Starting/Part1/Tutorial-World-Introduction
-./Building-menus
+Contribs/Contrib-AWSStorage.md
+Contribs/Contrib-Building-Menu.md
+Contribs/Contrib-Color-Markups.md
+Contribs/Contrib-Custom-Gametime.md
+Contribs/Contrib-Email-Login.md
+Contribs/Contrib-Ingame-Python.md
+Contribs/Contrib-Menu-Login.md
+Contribs/Contrib-Mux-Comms-Cmds.md
+Contribs/Contrib-Unixcommand.md
+Contribs/Contrib-Evscaperoom.md
+Contribs/Contrib-Barter.md
+Contribs/Contrib-Clothing.md
+Contribs/Contrib-Cooldowns.md
+Contribs/Contrib-Crafting.md
+Contribs/Contrib-Gendersub.md
+Contribs/Contrib-Mail.md
+Contribs/Contrib-Multidescer.md
+Contribs/Contrib-Puzzles.md
+Contribs/Contrib-Turnbattle.md
+Contribs/Contrib-Extended-Room.md
+Contribs/Contrib-Mapbuilder.md
+Contribs/Contrib-Simpledoor.md
+Contribs/Contrib-Slow-Exit.md
+Contribs/Contrib-Wilderness.md
+Contribs/Contrib-XYZGrid.md
+Contribs/Contrib-Dice.md
+Contribs/Contrib-Health-Bar.md
+Contribs/Contrib-RPSystem.md
+Contribs/Contrib-Traits.md
+Contribs/Contrib-Batchprocessor.md
+Contribs/Contrib-Bodyfunctions.md
+Contribs/Contrib-Mirror.md
+Contribs/Contrib-Red-Button.md
+Contribs/Contrib-Talking-Npc.md
+Contribs/Contrib-Tutorial-World.md
+Contribs/Contrib-Auditing.md
+Contribs/Contrib-Fieldfill.md
+Contribs/Contrib-Random-String-Generator.md
+Contribs/Contrib-Tree-Select.md
-```
+
+
+
+----
+
+This document page is auto-generated from the sources. Manual changes
+will be overwritten.
diff --git a/docs/source/Contribs/Contrib-Puzzles.md b/docs/source/Contribs/Contrib-Puzzles.md
new file mode 100644
index 0000000000..ee37c819b8
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Puzzles.md
@@ -0,0 +1,74 @@
+# Puzzles System
+
+Evennia contribution - Henddher 2018
+
+Provides a typeclass and commands for objects that can be combined (i.e. 'use'd)
+to produce new objects.
+
+A Puzzle is a recipe of what objects (aka parts) must be combined by a player so
+a new set of objects (aka results) are automatically created.
+
+## Installation
+
+Add the PuzzleSystemCmdSet to all players (e.g. in their Character typeclass).
+
+Alternatively:
+
+ py self.cmdset.add('evennia.contrib.game_systems.puzzles.PuzzleSystemCmdSet')
+
+## Usage
+
+Consider this simple Puzzle:
+
+ orange, mango, yogurt, blender = fruit smoothie
+
+As a Builder:
+
+ create/drop orange
+ create/drop mango
+ create/drop yogurt
+ create/drop blender
+ create/drop fruit smoothie
+
+ puzzle smoothie, orange, mango, yogurt, blender = fruit smoothie
+ ...
+ Puzzle smoothie(#1234) created successfuly.
+
+ destroy/force orange, mango, yogurt, blender, fruit smoothie
+
+ armpuzzle #1234
+ Part orange is spawned at ...
+ Part mango is spawned at ...
+ ....
+ Puzzle smoothie(#1234) has been armed successfully
+
+As Player:
+
+ use orange, mango, yogurt, blender
+ ...
+ Genius, you blended all fruits to create a fruit smoothie!
+
+## Details
+
+Puzzles are created from existing objects. The given
+objects are introspected to create prototypes for the
+puzzle parts and results. These prototypes become the
+puzzle recipe. (See PuzzleRecipe and `puzzle`
+command). Once the recipe is created, all parts and result
+can be disposed (i.e. destroyed).
+
+At a later time, a Builder or a Script can arm the puzzle
+and spawn all puzzle parts in their respective
+locations (See armpuzzle).
+
+A regular player can collect the puzzle parts and combine
+them (See use command). If player has specified
+all pieces, the puzzle is considered solved and all
+its puzzle parts are destroyed while the puzzle results
+are spawened on their corresponding location.
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/puzzles/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-RPSystem.md b/docs/source/Contribs/Contrib-RPSystem.md
new file mode 100644
index 0000000000..9abee81e02
--- /dev/null
+++ b/docs/source/Contribs/Contrib-RPSystem.md
@@ -0,0 +1,263 @@
+# Roleplaying base system for Evennia
+
+Roleplaying emotes/sdescs - Griatch, 2015
+Language/whisper emotes - Griatch, 2015
+
+## Roleplaying emotes
+
+This module contains the ContribRPObject, ContribRPRoom and
+ContribRPCharacter typeclasses. If you inherit your
+objects/rooms/character from these (or make them the defaults) from
+these you will get the following features:
+
+- Objects/Rooms will get the ability to have poses and will report
+ the poses of items inside them (the latter most useful for Rooms).
+- Characters will get poses and also sdescs (short descriptions)
+ that will be used instead of their keys. They will gain commands
+ for managing recognition (custom sdesc-replacement), masking
+ themselves as well as an advanced free-form emote command.
+
+In more detail, This RP base system introduces the following features
+to a game, common to many RP-centric games:
+
+- emote system using director stance emoting (names/sdescs).
+ This uses a customizable replacement noun (/me, @ etc) to
+ represent you in the emote. You can use /sdesc, /nick, /key or
+ /alias to reference objects in the room. You can use any
+ number of sdesc sub-parts to differentiate a local sdesc, or
+ use /1-sdesc etc to differentiate them. The emote also
+ identifies nested says and separates case.
+- sdesc obscuration of real character names for use in emotes
+ and in any referencing such as object.search(). This relies
+ on an SdescHandler `sdesc` being set on the Character and
+ makes use of a custom Character.get_display_name hook. If
+ sdesc is not set, the character's `key` is used instead. This
+ is particularly used in the emoting system.
+- recog system to assign your own nicknames to characters, can then
+ be used for referencing. The user may recog a user and assign
+ any personal nick to them. This will be shown in descriptions
+ and used to reference them. This is making use of the nick
+ functionality of Evennia.
+- masks to hide your identity (using a simple lock).
+- pose system to set room-persistent poses, visible in room
+ descriptions and when looking at the person/object. This is a
+ simple Attribute that modifies how the characters is viewed when
+ in a room as sdesc + pose.
+- in-emote says, including seamless integration with language
+ obscuration routine (such as contrib/rplanguage.py)
+
+### Installation:
+
+Add `RPSystemCmdSet` from this module to your CharacterCmdSet:
+
+```python
+# mygame/commands/default_cmdsets.py
+
+# ...
+
+from evennia.contrib.rpg.rpsystem import RPSystemCmdSet <---
+
+class CharacterCmdSet(default_cmds.CharacterCmdset):
+ # ...
+ def at_cmdset_creation(self):
+ # ...
+ self.add(RPSystemCmdSet()) # <---
+
+```
+
+You also need to make your Characters/Objects/Rooms inherit from
+the typeclasses in this module:
+
+```python
+# in mygame/typeclasses/characters.py
+
+from evennia.contrib.rpg import ContribRPCharacter
+
+class Character(ContribRPCharacter):
+ # ...
+
+```
+
+```python
+# in mygame/typeclasses/objects.py
+
+from evennia.contrib.rpg import ContribRPObject
+
+class Object(ContribRPObject):
+ # ...
+
+```
+
+```python
+# in mygame/typeclasses/rooms.py
+
+from evennia.contrib.rpg import ContribRPRoom
+
+class Room(ContribRPRoom):
+ # ...
+
+```
+
+You will then need to reload the server and potentially force-reload
+your objects, if you originally created them without this.
+
+Example for your character:
+
+ > type/reset/force me = typeclasses.characters.Character
+
+
+Examples:
+
+> look
+Tavern
+The tavern is full of nice people
+
+*A tall man* is standing by the bar.
+
+Above is an example of a player with an sdesc "a tall man". It is also
+an example of a static *pose*: The "standing by the bar" has been set
+by the player of the tall man, so that people looking at him can tell
+at a glance what is going on.
+
+> emote /me looks at /Tall and says "Hello!"
+
+I see:
+ Griatch looks at Tall man and says "Hello".
+Tall man (assuming his name is Tom) sees:
+ The godlike figure looks at Tom and says "Hello".
+
+Note that by default, the case of the tag matters, so `/tall` will
+lead to 'tall man' while `/Tall` will become 'Tall man' and /TALL
+becomes /TALL MAN. If you don't want this behavior, you can pass
+case_sensitive=False to the `send_emote` function.
+
+
+## Language and whisper obfuscation system
+
+This module is intented to be used with an emoting system (such as
+`contrib/rpg/rpsystem.py`). It offers the ability to obfuscate spoken words
+in the game in various ways:
+
+- Language: The language functionality defines a pseudo-language map
+ to any number of languages. The string will be obfuscated depending
+ on a scaling that (most likely) will be input as a weighted average of
+ the language skill of the speaker and listener.
+- Whisper: The whisper functionality will gradually "fade out" a
+ whisper along as scale 0-1, where the fading is based on gradually
+ removing sections of the whisper that is (supposedly) easier to
+ overhear (for example "s" sounds tend to be audible even when no other
+ meaning can be determined).
+
+
+### Installation
+
+This module adds no new commands; embed it in your say/emote/whisper commands.
+
+### Usage:
+
+```python
+from evennia.contrib import rplanguage
+
+# need to be done once, here we create the "default" lang
+rplanguage.add_language()
+
+say = "This is me talking."
+whisper = "This is me whispering.
+
+print rplanguage.obfuscate_language(say, level=0.0)
+<<< "This is me talking."
+print rplanguage.obfuscate_language(say, level=0.5)
+<<< "This is me byngyry."
+print rplanguage.obfuscate_language(say, level=1.0)
+<<< "Daly ly sy byngyry."
+
+result = rplanguage.obfuscate_whisper(whisper, level=0.0)
+<<< "This is me whispering"
+result = rplanguage.obfuscate_whisper(whisper, level=0.2)
+<<< "This is m- whisp-ring"
+result = rplanguage.obfuscate_whisper(whisper, level=0.5)
+<<< "---s -s -- ---s------"
+result = rplanguage.obfuscate_whisper(whisper, level=0.7)
+<<< "---- -- -- ----------"
+result = rplanguage.obfuscate_whisper(whisper, level=1.0)
+<<< "..."
+
+```
+
+To set up new languages, import and use the `add_language()`
+helper method in this module. This allows you to customize the
+"feel" of the semi-random language you are creating. Especially
+the `word_length_variance` helps vary the length of translated
+words compared to the original and can help change the "feel" for
+the language you are creating. You can also add your own
+dictionary and "fix" random words for a list of input words.
+
+Below is an example of "elvish", using "rounder" vowels and sounds:
+
+```python
+# vowel/consonant grammar possibilities
+grammar = ("v vv vvc vcc vvcc cvvc vccv vvccv vcvccv vcvcvcc vvccvvcc "
+ "vcvvccvvc cvcvvcvvcc vcvcvvccvcvv")
+
+# all not in this group is considered a consonant
+vowels = "eaoiuy"
+
+# you need a representative of all of the minimal grammars here, so if a
+# grammar v exists, there must be atleast one phoneme available with only
+# one vowel in it
+phonemes = ("oi oh ee ae aa eh ah ao aw ay er ey ow ia ih iy "
+ "oy ua uh uw y p b t d f v t dh s z sh zh ch jh k "
+ "ng g m n l r w")
+
+# how much the translation varies in length compared to the original. 0 is
+# smallest, higher values give ever bigger randomness (including removing
+# short words entirely)
+word_length_variance = 1
+
+# if a proper noun (word starting with capitalized letter) should be
+# translated or not. If not (default) it means e.g. names will remain
+# unchanged across languages.
+noun_translate = False
+
+# all proper nouns (words starting with a capital letter not at the beginning
+# of a sentence) can have either a postfix or -prefix added at all times
+noun_postfix = "'la"
+
+# words in dict will always be translated this way. The 'auto_translations'
+# is instead a list or filename to file with words to use to help build a
+# bigger dictionary by creating random translations of each word in the
+# list *once* and saving the result for subsequent use.
+manual_translations = {"the":"y'e", "we":"uyi", "she":"semi", "he":"emi",
+ "you": "do", 'me':'mi','i':'me', 'be':"hy'e", 'and':'y'}
+
+rplanguage.add_language(key="elvish", phonemes=phonemes, grammar=grammar,
+ word_length_variance=word_length_variance,
+ noun_translate=noun_translate,
+ noun_postfix=noun_postfix, vowels=vowels,
+ manual_translations=manual_translations,
+ auto_translations="my_word_file.txt")
+
+```
+
+This will produce a decicively more "rounded" and "soft" language than the
+default one. The few `manual_translations` also make sure to make it at least
+look superficially "reasonable".
+
+The `auto_translations` keyword is useful, this accepts either a
+list or a path to a text-file (with one word per line). This listing
+of words is used to 'fix' translations for those words according to the
+grammatical rules. These translations are stored persistently as long as the
+language exists.
+
+This allows to quickly build a large corpus of translated words
+that never change. This produces a language that seem moderately
+consistent, since words like 'the' will always be translated to the same thing.
+The disadvantage (or advantage, depending on your game) is that players can
+end up learn what words mean even if their characters don't know the
+langauge.
+
+
+----
+
+This document page is generated from `evennia/contrib/rpg/rpsystem/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Random-String-Generator.md b/docs/source/Contribs/Contrib-Random-String-Generator.md
new file mode 100644
index 0000000000..936f0f9fbc
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Random-String-Generator.md
@@ -0,0 +1,58 @@
+# Pseudo-random generator and registry
+
+Contribution - Vincent Le Goff 2017
+
+This contrib can be used to generate pseudo-random strings of information
+with specific criteria. You could, for instance, use it to generate
+phone numbers, license plate numbers, validation codes, non-sensivite
+passwords and so on. The strings generated by the generator will be
+stored and won't be available again in order to avoid repetition.
+Here's a very simple example:
+
+```python
+
+from evennia.contrib.utils.random_string_generator import RandomStringGenerator
+
+# Create a generator for phone numbers
+phone_generator = RandomStringGenerator("phone number", r"555-[0-9]{3}-[0-9]{4}")
+
+# Generate a phone number (555-XXX-XXXX with X as numbers)
+number = phone_generator.get()
+
+# `number` will contain something like: "555-981-2207"
+# If you call `phone_generator.get`, it won't give the same anymore.phone_generator.all()
+# Will return a list of all currently-used phone numbers
+phone_generator.remove("555-981-2207")
+
+# The number can be generated again
+```
+
+## Importing
+
+1. Import the `RandomStringGenerator` class from the contrib.
+2. Create an instance of this class taking two arguments:
+ - The name of the gemerator (like "phone number", "license plate"...).
+ - The regular expression representing the expected results.
+3. Use the generator's `all`, `get` and `remove` methods as shown above.
+
+To understand how to read and create regular expressions, you can refer to
+[the documentation on the re module](https://docs.python.org/2/library/re.html).
+Some examples of regular expressions you could use:
+
+- `r"555-\d{3}-\d{4}"`: 555, a dash, 3 digits, another dash, 4 digits.
+- `r"[0-9]{3}[A-Z][0-9]{3}"`: 3 digits, a capital letter, 3 digits.
+- `r"[A-Za-z0-9]{8,15}"`: between 8 and 15 letters and digits.
+- ...
+
+Behind the scenes, a script is created to store the generated information
+for a single generator. The `RandomStringGenerator` object will also
+read the regular expression you give to it to see what information is
+required (letters, digits, a more restricted class, simple characters...)...
+More complex regular expressions (with branches for instance) might not be
+available.
+
+
+----
+
+This document page is generated from `evennia/contrib/utils/random_string_generator/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Red-Button.md b/docs/source/Contribs/Contrib-Red-Button.md
new file mode 100644
index 0000000000..70c1a771a6
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Red-Button.md
@@ -0,0 +1,40 @@
+# Red Button example
+
+Griatch - 2011
+
+This is a more advanced example object with its own functionality (commands)
+on it.
+
+Create the button with
+
+ create/drop button:tutorials.red_button.RedButton
+
+Note that you must drop the button before you can see its messages! It's
+imperative that you press the red button. You know you want to.
+
+Use `del button` to destroy/stop the button when you are done playing.
+
+## Technical
+
+The button's functionality is controlled by CmdSets that gets added and removed
+depending on the 'state' the button is in.
+
+- Lid-closed state: In this state the button is covered by a glass cover and
+ trying to 'push' it will fail. You can 'nudge', 'smash' or 'open' the lid.
+- Lid-open state: In this state the lid is open but will close again after a
+ certain time. Using 'push' now will press the button and trigger the
+ Blind-state.
+- Blind-state: In this mode you are blinded by a bright flash. This will affect
+ your normal commands like 'look' and help until the blindness wears off after
+ a certain time.
+
+Timers are handled by persistent delays on the button. These are examples of
+`evennia.utils.utils.delay` calls that wait a certain time before calling a
+method - such as when closing the lid and un-blinding a character.
+
+
+
+----
+
+This document page is generated from `evennia/contrib/tutorials/red_button/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Simpledoor.md b/docs/source/Contribs/Contrib-Simpledoor.md
new file mode 100644
index 0000000000..ea464fa613
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Simpledoor.md
@@ -0,0 +1,50 @@
+# SimpleDoor
+
+Contribution - Griatch 2016
+
+A simple two-way exit that represents a door that can be opened and
+closed. Can easily be expanded from to make it lockable, destroyable
+etc. Note that the simpledoor is based on Evennia locks, so it will
+not work for a superuser (which bypasses all locks) - the superuser
+will always appear to be able to close/open the door over and over
+without the locks stopping you. To use the door, use `@quell` or a
+non-superuser account.
+
+## Installation:
+
+Import `SimpleDoorCmdSet` from this module into `mygame/commands/default_cmdsets`
+and add it to your `CharacterCmdSet`:
+
+```python
+# in mygame/commands/default_cmdsets.py
+
+from evennia.contrib.grid import simpledoor <---
+
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ # ...
+ def at_cmdset_creation(self):
+ # ...
+ self.add(simpledoor.SimpleDoorCmdSet)
+
+```
+
+## Usage:
+
+To try it out, `dig` a new room and then use the (overloaded) `@open`
+commmand to open a new doorway to it like this:
+
+ @open doorway:contrib.grid.simpledoor.SimpleDoor = otherroom
+
+ open doorway
+ close doorway
+
+Note: This uses locks, so if you are a superuser you will not be blocked by
+a locked door - `quell` yourself, if so. Normal users will find that they
+cannot pass through either side of the door once it's closed from the other
+side.
+
+
+----
+
+This document page is generated from `evennia/contrib/grid/simpledoor/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Slow-Exit.md b/docs/source/Contribs/Contrib-Slow-Exit.md
new file mode 100644
index 0000000000..57ea4cac03
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Slow-Exit.md
@@ -0,0 +1,67 @@
+# Slow Exit
+
+Contribution - Griatch 2014
+
+This is an example of an Exit-type that delays its traversal. This simulates
+slow movement, common in many different types of games. The contrib also
+contains two commands, `CmdSetSpeed` and CmdStop for changing the movement speed
+and abort an ongoing traversal, respectively.
+
+## Installation:
+
+To try out an exit of this type, you could connect two existing rooms
+using something like this:
+
+ @open north:contrib.grid.slow_exit.SlowExit =
+
+To make this your new default exit, modify `mygame/typeclasses/exits.py`
+to import this module and change the default `Exit` class to inherit
+from `SlowExit` instead.
+
+```
+# in mygame/typeclasses/exits.py
+
+from evennia.contrib.grid.slowexit import SlowExit
+
+class Exit(SlowExit):
+ # ...
+
+```
+
+To get the ability to change your speed and abort your movement, import
+
+```python
+# in mygame/commands/default_cmdsets.py
+
+from evennia.contrib.grid import slow_exit <---
+
+class CharacterCmdSet(default_cmds.CharacterCmdSet):
+ # ...
+ def at_cmdset_creation(self):
+ # ...
+ self.add(slow_exit.SlowDoorCmdSet) <---
+
+```
+
+simply import and add CmdSetSpeed and CmdStop from this module to your
+default cmdset (see tutorials on how to do this if you are unsure).
+
+To try out an exit of this type, you could connect two existing rooms using
+something like this:
+
+ @open north:contrib.grid.slow_exit.SlowExit =
+
+
+## Notes:
+
+This implementation is efficient but not persistent; so incomplete
+movement will be lost in a server reload. This is acceptable for most
+game types - to simulate longer travel times (more than the couple of
+seconds assumed here), a more persistent variant using Scripts or the
+TickerHandler might be better.
+
+
+----
+
+This document page is generated from `evennia/contrib/grid/slow_exit/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Talking-Npc.md b/docs/source/Contribs/Contrib-Talking-Npc.md
new file mode 100644
index 0000000000..0d43feaa10
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Talking-Npc.md
@@ -0,0 +1,27 @@
+# Talkative NPC example
+
+Contribution - Griatch 2011, grungies1138, 2016
+
+This is a static NPC object capable of holding a simple menu-driven
+conversation. It's just meant as an example.
+
+## Installation
+
+Create the NPC by creating an object of typeclass `contrib.tutorials.talking_npc.TalkingNPC`,
+For example:
+
+ create/drop John : contrib.tutorials.talking_npc.TalkingNPC
+
+Use `talk` in the same room as the NPC to start a conversation.
+
+If there are many talkative npcs in the same room you will get to choose which
+one's talk command to call (Evennia handles this automatically).
+
+This use of EvMenu is very simplistic; See EvMenu for a lot more complex
+possibilities.
+
+
+----
+
+This document page is generated from `evennia/contrib/tutorials/talking_npc/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Traits.md b/docs/source/Contribs/Contrib-Traits.md
new file mode 100644
index 0000000000..a49d4f8679
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Traits.md
@@ -0,0 +1,449 @@
+# Traits
+
+Whitenoise 2014, Ainneve contributors,
+Griatch 2020
+
+A `Trait` represents a modifiable property on (usually) a Character. They can
+be used to represent everything from attributes (str, agi etc) to skills
+(hunting 10, swords 14 etc) and dynamically changing things like HP, XP etc.
+
+Traits differ from normal Attributes in that they track their changes and limit
+themselves to particular value-ranges. One can add/subtract from them easily and
+they can even change dynamically at a particular rate (like you being poisoned or
+healed).
+
+Traits use Evennia Attributes under the hood, making them persistent (they survive
+a server reload/reboot).
+
+## Installation
+
+Traits are always added to a typeclass, such as the Character class.
+
+There are two ways to set up Traits on a typeclass. The first sets up the `TraitHandler`
+as a property `.traits` on your class and you then access traits as e.g. `.traits.strength`.
+The other alternative uses a `TraitProperty`, which makes the trait available directly
+as e.g. `.strength`. This solution also uses the `TraitHandler`, but you don't need to
+define it explicitly. You can combine both styles if you like.
+
+### Traits with TraitHandler
+
+Here's an example for adding the TraitHandler to the Character class:
+
+```python
+# mygame/typeclasses/objects.py
+
+from evennia import DefaultCharacter
+from evennia.utils import lazy_property
+from evennia.contrib.rpg.traits import TraitHandler
+
+# ...
+
+class Character(DefaultCharacter):
+ ...
+ @lazy_property
+ def traits(self):
+ # this adds the handler as .traits
+ return TraitHandler(self)
+
+
+ def at_object_creation(self):
+ # (or wherever you want)
+ self.traits.add("str", "Strength", trait_type="static", base=10, mod=2)
+ self.traits.add("hp", "Health", trait_type="gauge", min=0, max=100)
+ self.traits.add("hunting", "Hunting Skill", trait_type="counter",
+ base=10, mod=1, min=0, max=100)
+
+
+```
+When adding the trait, you supply the name of the property (`hunting`) along
+with a more human-friendly name ("Hunting Skill"). The latter will show if you
+print the trait etc. The `trait_type` is important, this specifies which type
+of trait this is (see below).
+
+### TraitProperties
+
+Using `TraitProperties` makes the trait available directly on the class, much like Django model
+fields. The drawback is that you must make sure that the name of your Traits don't collide with any
+other properties/methods on your class.
+
+```python
+# mygame/typeclasses/objects.py
+
+from evennia import DefaultObject
+from evennia.utils import lazy_property
+from evennia.contrib.rpg.traits import TraitProperty
+
+# ...
+
+class Object(DefaultObject):
+ ...
+ strength = TraitProperty("Strength", trait_type="static", base=10, mod=2)
+ health = TraitProperty("Health", trait_type="gauge", min=0, base=100, mod=2)
+ hunting = TraitProperty("Hunting Skill", trait_type="counter", base=10, mod=1, min=0, max=100)
+
+```
+
+> Note that the property-name will become the name of the trait and you don't supply `trait_key`
+> separately.
+
+> The `.traits` TraitHandler will still be created (it's used under the
+> hood. But it will only be created when the TraitProperty has been accessed at least once,
+> so be careful if mixing the two styles. If you want to make sure `.traits` is always available,
+> add the `TraitHandler` manually like shown earlier - the `TraitProperty` will by default use
+> the same handler (`.traits`).
+
+## Using traits
+
+A trait is added to the traithandler (if you use `TraitProperty` the handler is just created under
+the hood) after which one can access it as a property on the handler (similarly to how you can do
+.db.attrname for Attributes in Evennia).
+
+All traits have a _read-only_ field `.value`. This is only used to read out results, you never
+manipulate it directly (if you try, it will just remain unchanged). The `.value` is calculated based
+on combining fields, like `.base` and `.mod` - which fields are available and how they relate to
+each other depends on the trait type.
+
+```python
+> obj.traits.strength.value
+12 # base + mod
+
+> obj.traits.strength.base += 5
+obj.traits.strength.value
+17
+
+> obj.traits.hp.value
+102 # base + mod
+
+> obj.traits.hp.base -= 200
+> obj.traits.hp.value
+0 # min of 0
+
+> obj.traits.hp.reset()
+> obj.traits.hp.value
+100
+
+# you can also access properties like a dict
+> obj.traits.hp["value"]
+100
+
+# you can store arbitrary data persistently for easy reference
+> obj.traits.hp.effect = "poisoned!"
+> obj.traits.hp.effect
+"poisoned!"
+
+# with TraitProperties:
+
+> obj.hunting.value
+12
+
+> obj.strength.value += 5
+> obj.strength.value
+17
+
+```
+
+## Trait types
+
+All default traits have a read-only `.value` property that shows the relevant or
+'current' value of the trait. Exactly what this means depends on the type of trait.
+
+Traits can also be combined to do arithmetic with their .value, if both have a
+compatible type.
+
+```python
+> trait1 + trait2
+54
+
+> trait1.value
+3
+
+> trait1 + 2
+> trait1.value
+5
+
+```
+
+Two numerical traits can also be compared (bigger-than etc), which is useful in
+all sorts of rule-resolution.
+
+```python
+
+if trait1 > trait2:
+ # do stuff
+
+```
+
+## Static trait
+
+`value = base + mod`
+
+The static trait has a `base` value and an optional `mod`-ifier. A typical use
+of a static trait would be a Strength stat or Skill value. That is, something
+that varies slowly or not at all, and which may be modified in-place.
+
+```python
+> obj.traits.add("str", "Strength", trait_type="static", base=10, mod=2)
+> obj.traits.mytrait.value
+
+12 # base + mod
+> obj.traits.mytrait.base += 2
+> obj.traits.mytrait.mod += 1
+> obj.traits.mytrait.value
+15
+
+> obj.traits.mytrait.mod = 0
+> obj.traits.mytrait.value
+12
+
+```
+
+### Counter
+
+
+ min/unset base base+mod max/unset
+ |--------------|--------|---------X--------X------------|
+ current value
+ = current
+ + mod
+
+A counter describes a value that can move from a base. The `.current` property
+is the thing usually modified. It starts at the `.base`. One can also add a
+modifier, which will both be added to the base and to current (forming
+`.value`). The min/max of the range are optional, a boundary set to None will
+remove it. A suggested use for a Counter Trait would be to track skill values.
+
+```python
+> obj.traits.add("hunting", "Hunting Skill", trait_type="counter",
+ base=10, mod=1, min=0, max=100)
+> obj.traits.hunting.value
+11 # current starts at base + mod
+
+> obj.traits.hunting.current += 10
+> obj.traits.hunting.value
+21
+
+# reset back to base+mod by deleting current
+> del obj.traits.hunting.current
+> obj.traits.hunting.value
+11
+> obj.traits.hunting.max = None # removing upper bound
+
+# for TraitProperties, pass the args/kwargs of traits.add() to the
+# TraitProperty constructor instead.
+
+
+```
+
+Counters have some extra properties:
+
+#### .descs
+
+The `descs` property is a dict `{upper_bound:text_description}`. This allows for easily
+storing a more human-friendly description of the current value in the
+interval. Here is an example for skill values between 0 and 10:
+
+ {0: "unskilled", 1: "neophyte", 5: "trained", 7: "expert", 9: "master"}
+
+The keys must be supplied from smallest to largest. Any values below the lowest and above the
+highest description will be considered to be included in the closest description slot.
+By calling `.desc()` on the Counter, you will get the text matching the current `value`.
+
+```python
+# (could also have passed descs= to traits.add())
+> obj.traits.hunting.descs = {
+ 0: "unskilled", 10: "neophyte", 50: "trained", 70: "expert", 90: "master"}
+> obj.traits.hunting.value
+11
+
+> obj.traits.hunting.desc()
+"neophyte"
+> obj.traits.hunting.current += 60
+> obj.traits.hunting.value
+71
+
+> obj.traits.hunting.desc()
+"expert"
+
+```
+
+#### .rate
+
+The `rate` property defaults to 0. If set to a value different from 0, it
+allows the trait to change value dynamically. This could be used for example
+for an attribute that was temporarily lowered but will gradually (or abruptly)
+recover after a certain time. The rate is given as change of the current
+`.value` per-second, and this will still be restrained by min/max boundaries,
+if those are set.
+
+It is also possible to set a `.ratetarget`, for the auto-change to stop at
+(rather than at the min/max boundaries). This allows the value to return to
+a previous value.
+
+```python
+
+> obj.traits.hunting.value
+71
+
+> obj.traits.hunting.ratetarget = 71
+# debuff hunting for some reason
+> obj.traits.hunting.current -= 30
+> obj.traits.hunting.value
+41
+
+> obj.traits.hunting.rate = 1 # 1/s increase
+# Waiting 5s
+> obj.traits.hunting.value
+46
+
+# Waiting 8s
+> obj.traits.hunting.value
+54
+
+# Waiting 100s
+> obj.traits.hunting.value
+71 # we have stopped at the ratetarget
+
+> obj.traits.hunting.rate = 0 # disable auto-change
+
+
+```
+Note that when retrieving the `current`, the result will always be of the same
+type as the `.base` even `rate` is a non-integer value. So if `base` is an `int`
+(default)`, the `current` value will also be rounded the closest full integer.
+If you want to see the exact `current` value, set `base` to a float - you
+will then need to use `round()` yourself on the result if you want integers.
+
+#### .percent()
+
+If both min and max are defined, the `.percent()` method of the trait will
+return the value as a percentage.
+
+```python
+> obj.traits.hunting.percent()
+"71.0%"
+
+> obj.traits.hunting.percent(formatting=None)
+71.0
+
+```
+
+### Gauge
+
+This emulates a [fuel-] gauge that empties from a base+mod value.
+
+ min/0 max=base+mod
+ |-----------------------X---------------------------|
+ value
+ = current
+
+The `.current` value will start from a full gauge. The .max property is
+read-only and is set by `.base` + `.mod`. So contrary to a `Counter`, the
+`.mod` modifier only applies to the max value of the gauge and not the current
+value. The minimum bound defaults to 0 if not set explicitly.
+
+This trait is useful for showing commonly depletable resources like health,
+stamina and the like.
+
+```python
+> obj.traits.add("hp", "Health", trait_type="gauge", base=100)
+> obj.traits.hp.value # (or .current)
+100
+
+> obj.traits.hp.mod = 10
+> obj.traits.hp.value
+110
+
+> obj.traits.hp.current -= 30
+> obj.traits.hp.value
+80
+
+```
+
+The Gauge trait is subclass of the Counter, so you have access to the same
+methods and properties where they make sense. So gauges can also have a
+`.descs` dict to describe the intervals in text, and can use `.percent()` to
+get how filled it is as a percentage etc.
+
+The `.rate` is particularly relevant for gauges - useful for everything
+from poison slowly draining your health, to resting gradually increasing it.
+
+### Trait
+
+A single value of any type.
+
+This is the 'base' Trait, meant to inherit from if you want to invent
+trait-types from scratch (most of the time you'll probably inherit from some of
+the more advanced trait-type classes though).
+
+Unlike other Trait-types, the single `.value` property of the base `Trait` can
+be editied. The value can hold any data that can be stored in an Attribute. If
+it's an integer/float you can do arithmetic with it, but otherwise this acts just
+like a glorified Attribute.
+
+
+```python
+> obj.traits.add("mytrait", "My Trait", trait_type="trait", value=30)
+> obj.traits.mytrait.value
+30
+
+> obj.traits.mytrait.value = "stringvalue"
+> obj.traits.mytrait.value
+"stringvalue"
+
+```
+
+## Expanding with your own Traits
+
+A Trait is a class inhering from `evennia.contrib.rpg.traits.Trait` (or from one of
+the existing Trait classes).
+
+```python
+# in a file, say, 'mygame/world/traits.py'
+
+from evennia.contrib.rpg.traits import StaticTrait
+
+class RageTrait(StaticTrait):
+
+ trait_type = "rage"
+ default_keys = {
+ "rage": 0
+ }
+
+ def berserk(self):
+ self.mod = 100
+
+ def sedate(self):
+ self.mod = 0
+
+
+```
+
+Above is an example custom-trait-class "rage" that stores a property "rage" on
+itself, with a default value of 0. This has all the functionality of a Trait -
+for example, if you do del on the `rage` property, it will be set back to its
+default (0). Above we also added some helper methods.
+
+To add your custom RageTrait to Evennia, add the following to your settings file
+(assuming your class is in mygame/world/traits.py):
+
+ TRAIT_CLASS_PATHS = ["world.traits.RageTrait"]
+
+Reload the server and you should now be able to use your trait:
+
+```python
+> obj.traits.add("mood", "A dark mood", rage=30, trait_type='rage')
+> obj.traits.mood.rage
+30
+
+# as TraitProperty
+
+class Character(DefaultCharacter):
+ rage = TraitProperty("A dark mood", rage=30, trait_type='rage')
+
+```
+
+
+----
+
+This document page is generated from `evennia/contrib/rpg/traits/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Tree-Select.md b/docs/source/Contribs/Contrib-Tree-Select.md
new file mode 100644
index 0000000000..a8445d9e50
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Tree-Select.md
@@ -0,0 +1,167 @@
+# Easy menu selection tree
+
+Contrib - Tim Ashley Jenkins 2017
+
+This module allows you to create and initialize an entire branching EvMenu
+instance with nothing but a multi-line string passed to one function.
+
+EvMenu is incredibly powerful and flexible, but using it for simple menus
+can often be fairly cumbersome - a simple menu that can branch into five
+categories would require six nodes, each with options represented as a list
+of dictionaries.
+
+This module provides a function, `init_tree_selection`, which acts as a frontend
+for EvMenu, dynamically sourcing the options from a multi-line string you
+provide. For example, if you define a string as such:
+
+ TEST_MENU = '''Foo
+ Bar
+ Baz
+ Qux'''
+
+And then use `TEST_MENU` as the 'treestr' source when you call
+`init_tree_selection` on a player:
+
+ init_tree_selection(TEST_MENU, caller, callback)
+
+The player will be presented with an EvMenu, like so:
+
+ ___________________________
+
+ Make your selection:
+ ___________________________
+
+ Foo
+ Bar
+ Baz
+ Qux
+
+Making a selection will pass the selection's key to the specified callback as a
+string along with the caller, as well as the index of the selection (the line
+number on the source string) along with the source string for the tree itself.
+
+In addition to specifying selections on the menu, you can also specify
+categories. Categories are indicated by putting options below it preceded with
+a '-' character. If a selection is a category, then choosing it will bring up a
+new menu node, prompting the player to select between those options, or to go
+back to the previous menu. In addition, categories are marked by default with a
+'[+]' at the end of their key. Both this marker and the option to go back can be
+disabled.
+
+Categories can be nested in other categories as well - just go another '-'
+deeper. You can do this as many times as you like. There's no hard limit to the
+number of categories you can go down.
+
+For example, let's add some more options to our menu, turning 'Bar' into a
+category.
+
+ TEST_MENU = '''Foo
+ Bar
+ -You've got to know
+ --When to hold em
+ --When to fold em
+ --When to walk away
+ Baz
+ Qux'''
+
+Now when we call the menu, we can see that 'Bar' has become a category instead of a
+selectable option.
+
+ _______________________________
+
+ Make your selection:
+ _______________________________
+
+ Foo
+ Bar [+]
+ Baz
+ Qux
+
+Note the [+] next to 'Bar'. If we select 'Bar', it'll show us the option listed
+under it.
+
+ ________________________________________________________________
+
+ Bar
+ ________________________________________________________________
+
+ You've got to know [+]
+ << Go Back: Return to the previous menu.
+
+Just the one option, which is a category itself, and the option to go back,
+which will take us back to the previous menu. Let's select 'You've got to know'.
+
+ ________________________________________________________________
+
+ You've got to know
+ ________________________________________________________________
+
+ When to hold em
+ When to fold em
+ When to walk away
+ << Go Back: Return to the previous menu.
+
+Now we see the three options listed under it, too. We can select one of them or
+use 'Go Back' to return to the 'Bar' menu we were just at before. It's very
+simple to make a branching tree of selections!
+
+One last thing - you can set the descriptions for the various options simply by
+adding a ':' character followed by the description to the option's line. For
+example, let's add a description to 'Baz' in our menu:
+
+ TEST_MENU = '''Foo
+ Bar
+ -You've got to know
+ --When to hold em
+ --When to fold em
+ --When to walk away
+ Baz: Look at this one: the best option.
+ Qux'''
+
+Now we see that the Baz option has a description attached that's separate from its key:
+
+ _______________________________________________________________
+
+ Make your selection:
+ _______________________________________________________________
+
+ Foo
+ Bar [+]
+ Baz: Look at this one: the best option.
+ Qux
+
+Once the player makes a selection - let's say, 'Foo' - the menu will terminate
+and call your specified callback with the selection, like so:
+
+ callback(caller, TEST_MENU, 0, "Foo")
+
+The index of the selection is given along with a string containing the
+selection's key. That way, if you have two selections in the menu with the same
+key, you can still differentiate between them.
+
+And that's all there is to it! For simple branching-tree selections, using this
+system is much easier than manually creating EvMenu nodes. It also makes
+generating menus with dynamic options much easier - since the source of the menu
+tree is just a string, you could easily generate that string procedurally before
+passing it to the `init_tree_selection` function. For example, if a player casts
+a spell or does an attack without specifying a target, instead of giving them an
+error, you could present them with a list of valid targets to select by
+generating a multi-line string of targets and passing it to
+`init_tree_selection`, with the callable performing the maneuver once a
+selection is made.
+
+This selection system only works for simple branching trees - doing anything
+really complicated like jumping between categories or prompting for arbitrary
+input would still require a full EvMenu implementation. For simple selections,
+however, I'm sure you will find using this function to be much easier!
+
+Included in this module is a sample menu and function which will let a player
+change the color of their name - feel free to mess with it to get a feel for how
+this system works by importing this module in your game's `default_cmdsets.py`
+module and adding `CmdNameColor` to your default character's command set.
+
+
+----
+
+This document page is generated from `evennia/contrib/utils/tree_select/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Turnbattle.md b/docs/source/Contribs/Contrib-Turnbattle.md
new file mode 100644
index 0000000000..d1b7b20bb4
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Turnbattle.md
@@ -0,0 +1,61 @@
+# Turn based battle system framework
+
+Contrib - Tim Ashley Jenkins 2017
+
+This is a framework for a simple turn-based combat system, similar
+to those used in D&D-style tabletop role playing games. It allows
+any character to start a fight in a room, at which point initiative
+is rolled and a turn order is established. Each participant in combat
+has a limited time to decide their action for that turn (30 seconds by
+default), and combat progresses through the turn order, looping through
+the participants until the fight ends.
+
+This folder contains multiple examples of how such a system can be
+implemented and customized:
+
+ tb_basic.py - The simplest system, which implements initiative and turn
+ order, attack rolls against defense values, and damage to hit
+ points. Only very basic game mechanics are included.
+
+ tb_equip.py - Adds weapons and armor to the basic implementation of
+ the battle system, including commands for wielding weapons and
+ donning armor, and modifiers to accuracy and damage based on
+ currently used equipment.
+
+ tb_items.py - Adds usable items and conditions/status effects, and gives
+ a lot of examples for each. Items can perform nearly any sort of
+ function, including healing, adding or curing conditions, or
+ being used to attack. Conditions affect a fighter's attributes
+ and options in combat and persist outside of fights, counting
+ down per turn in combat and in real time outside combat.
+
+ tb_magic.py - Adds a spellcasting system, allowing characters to cast
+ spells with a variety of effects by spending MP. Spells are
+ linked to functions, and as such can perform any sort of action
+ the developer can imagine - spells for attacking, healing and
+ conjuring objects are included as examples.
+
+ tb_range.py - Adds a system for abstract positioning and movement, which
+ tracks the distance between different characters and objects in
+ combat, as well as differentiates between melee and ranged
+ attacks.
+
+This system is meant as a basic framework to start from, and is modeled
+after the combat systems of popular tabletop role playing games rather than
+the real-time battle systems that many MMOs and some MUDs use. As such, it
+may be better suited to role-playing or more story-oriented games, or games
+meant to closely emulate the experience of playing a tabletop RPG.
+
+Each of these modules contains the full functionality of the battle system
+with different customizations added in - the instructions to install each
+one is contained in the module itself. It's recommended that you install
+and test `tb_basic` first, so you can better understand how the other
+modules expand on it and get a better idea of how you can customize the
+system to your liking and integrate the subsystems presented here into
+your own combat system.
+
+
+----
+
+This document page is generated from `evennia/contrib/game_systems/turnbattle/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Tutorial-World.md b/docs/source/Contribs/Contrib-Tutorial-World.md
new file mode 100644
index 0000000000..72d37fd601
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Tutorial-World.md
@@ -0,0 +1,113 @@
+# Evennia Tutorial World
+
+Griatch 2011, 2015
+
+This is a stand-alone tutorial area for an unmodified Evennia install.
+Think of it as a sort of single-player adventure rather than a
+full-fledged multi-player game world. The various rooms and objects
+herein are designed to show off features of the engine, not to be a
+very challenging (nor long) gaming experience. As such it's of course
+only skimming the surface of what is possible.
+
+The tutorial world also includes a game tutor menu example, exemplifying
+Evmenu.
+
+## Installation
+
+Log in as superuser (#1), then run
+
+ batchcommand tutorials.tutorial_world.build
+
+Wait a little while for building to complete and don't run the command
+again even if it's slow. This builds the world and connect it to Limbo
+and creates a new exit `tutorial`.
+
+If you are a superuser (User `#1`), use the `quell` command to play
+the tutorial as intended.
+
+
+## Comments
+
+The tutorial world is intended to be explored and analyzed. It will help you
+learn how to accomplish some more advanced effects and might give some good
+ideas along the way.
+
+It's suggested you play it through (as a normal user, NOT as Superuser!) and
+explore it a bit, then come back here and start looking into the (heavily
+documented) build/source code to find out how things tick - that's the
+"tutorial" in Tutorial world after all.
+
+Please report bugs in the tutorial to the Evennia issue tracker.
+
+
+
+
+
+
+**Spoilers below - don't read on unless you already played the
+tutorial game**
+
+
+
+
+
+
+
+## Tutorial World Room map
+
+ ?
+ |
+ +---+----+ +-------------------+ +--------+ +--------+
+ | | | | |gate | |corner |
+ | cliff +----+ bridge +----+ +---+ |
+ | | | | | | | |
+ +---+---\+ +---------------+---+ +---+----+ +---+----+
+ | \ | | castle |
+ | \ +--------+ +----+---+ +---+----+ +---+----+
+ | \ |under- | |ledge | |along | |court- |
+ | \|ground +--+ | |wall +---+yard |
+ | \ | | | | | | |
+ | +------\-+ +--------+ +--------+ +---+----+
+ | \ |
+ ++---------+ \ +--------+ +--------+ +---+----+
+ |intro | \ |cell | |trap | |temple |
+ o--+ | \| +----+ | | |
+ L | | \ | /| | | |
+ I +----+-----+ +--------+ / ---+-+-+-+ +---+----+
+ M | / | | | |
+ B +----+-----+ +--------+/ +--+-+-+---------+----+
+ O |outro | |tomb | |antechamber |
+ o--+ +----------+ | | |
+ | | | | | |
+ +----------+ +--------+ +---------------------+
+
+
+## Hints/Notes:
+
+* o-- connections to/from Limbo
+* intro/outro areas are rooms that automatically sets/cleans the
+ Character of any settings assigned to it during the
+ tutorial game.
+* The Cliff is a good place to get an overview of the surroundings.
+* The Bridge may seem like a big room, but it is really only one room
+ with custom move commands to make it take longer to cross. You can
+ also fall off the bridge if you are unlucky or take your time to
+ take in the view too long.
+* In the Castle areas an aggressive mob is patrolling. It implements
+ rudimentary AI but packs quite a punch unless you have
+ found yourself a weapon that can harm it. Combat is only
+ possible once you find a weapon.
+* The Antechamber features a puzzle for finding the correct Grave
+ chamber.
+* The Cell is your reward if you fail in various ways. Finding a
+ way out of it is a small puzzle of its own.
+* The Tomb is a nice place to find a weapon that can hurt the
+ castle guardian. This is the goal of the tutorial.
+ Explore on, or take the exit to finish the tutorial.
+* ? - look into the code if you cannot find this bonus area!
+
+
+----
+
+This document page is generated from `evennia/contrib/tutorials/tutorial_world/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Unixcommand.md b/docs/source/Contribs/Contrib-Unixcommand.md
new file mode 100644
index 0000000000..d9958e1c80
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Unixcommand.md
@@ -0,0 +1,71 @@
+# Unix-like Command style parent
+
+Evennia contribution, Vincent Le Geoff 2017
+
+This module contains a command class that allows for unix-style command syntax
+in-game, using --options, positional arguments and stuff like -n 10 etc
+similarly to a unix command. It might not the best syntax for the average player
+but can be really useful for builders when they need to have a single command do
+many things with many options. It uses the ArgumentParser from Python's standard
+library under the hood.
+
+## Installation
+
+To use, inherit `UnixCommand` from this module from your own commands. You need
+to override two methods:
+
+- The `init_parser` method, which adds options to the parser. Note that you
+ should normally *not* override the normal `parse` method when inheriting from
+ `UnixCommand`.
+- The `func` method, called to execute the command once parsed (like any Command).
+
+Here's a short example:
+
+```python
+from evennia.contrib.base_systems.unixcommand import UnixCommand
+
+
+class CmdPlant(UnixCommand):
+
+ '''
+ Plant a tree or plant.
+
+ This command is used to plant something in the room you are in.
+
+ Examples:
+ plant orange -a 8
+ plant strawberry --hidden
+ plant potato --hidden --age 5
+
+ '''
+
+ key = "plant"
+
+ def init_parser(self):
+ "Add the arguments to the parser."
+ # 'self.parser' inherits `argparse.ArgumentParser`
+ self.parser.add_argument("key",
+ help="the key of the plant to be planted here")
+ self.parser.add_argument("-a", "--age", type=int,
+ default=1, help="the age of the plant to be planted")
+ self.parser.add_argument("--hidden", action="store_true",
+ help="should the newly-planted plant be hidden to players?")
+
+ def func(self):
+ "func is called only if the parser succeeded."
+ # 'self.opts' contains the parsed options
+ key = self.opts.key
+ age = self.opts.age
+ hidden = self.opts.hidden
+ self.msg("Going to plant '{}', age={}, hidden={}.".format(
+ key, age, hidden))
+```
+
+To see the full power of argparse and the types of supported options, visit
+[the documentation of argparse](https://docs.python.org/2/library/argparse.html).
+
+
+----
+
+This document page is generated from `evennia/contrib/base_systems/unixcommand/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-Wilderness.md b/docs/source/Contribs/Contrib-Wilderness.md
new file mode 100644
index 0000000000..96fce8e37b
--- /dev/null
+++ b/docs/source/Contribs/Contrib-Wilderness.md
@@ -0,0 +1,119 @@
+# Wilderness system
+
+Evennia contrib - titeuf87 2017
+
+This contrib provides a wilderness map without actually creating a large number
+of rooms - as you move, your room is instead updated with different
+descriptions. This means you can make huge areas with little database use as
+long as the rooms are relatively similar (name/desc changing).
+
+## Installation
+
+This contrib does not provide any new commands. Instead the default `py` command
+is used to call functions/classes in this contrib directly.
+
+## Usage
+
+A wilderness map needs to created first. There can be different maps, all
+with their own name. If no name is provided, then a default one is used. Internally,
+the wilderness is stored as a Script with the name you specify. If you don't
+specify the name, a script named "default" will be created and used.
+
+ @py from evennia.contrib.grid import wilderness; wilderness.create_wilderness()
+
+Once created, it is possible to move into that wilderness map:
+
+ @py from evennia.contrib.grid import wilderness; wilderness.enter_wilderness(me)
+
+All coordinates used by the wilderness map are in the format of `(x, y)`
+tuples. x goes from left to right and y goes from bottom to top. So `(0, 0)`
+is the bottom left corner of the map.
+
+## Customisation
+
+The defaults, while useable, are meant to be customised. When creating a
+new wilderness map it is possible to give a "map provider": this is a
+python object that is smart enough to create the map.
+
+The default provider, `WildernessMapProvider`, just creates a grid area that
+is unlimited in size.
+This `WildernessMapProvider` can be subclassed to create more interesting
+maps and also to customize the room/exit typeclass used.
+
+There is also no command that allows players to enter the wilderness. This
+still needs to be added: it can be a command or an exit, depending on your
+needs.
+
+## Example
+
+To give an example of how to customize, we will create a very simple (and
+small) wilderness map that is shaped like a pyramid. The map will be
+provided as a string: a "." symbol is a location we can walk on.
+
+Let's create a file `world/pyramid.py`:
+
+```python
+# mygame/world/pyramid.py
+
+map_str = '''
+ .
+ ...
+ .....
+ .......
+'''
+
+from evennia.contrib.grid import wilderness
+
+class PyramidMapProvider(wilderness.WildernessMapProvider):
+
+ def is_valid_coordinates(self, wilderness, coordinates):
+ "Validates if these coordinates are inside the map"
+ x, y = coordinates
+ try:
+ lines = map_str.split("\n")
+ # The reverse is needed because otherwise the pyramid will be
+ # upside down
+ lines.reverse()
+ line = lines[y]
+ column = line[x]
+ return column == "."
+ except IndexError:
+ return False
+
+ def get_location_name(self, coordinates):
+ "Set the location name"
+ x, y = coordinates
+ if y == 3:
+ return "Atop the pyramid."
+ else:
+ return "Inside a pyramid."
+
+ def at_prepare_room(self, coordinates, caller, room):
+ "Any other changes done to the room before showing it"
+ x, y = coordinates
+ desc = "This is a room in the pyramid."
+ if y == 3 :
+ desc = "You can see far and wide from the top of the pyramid."
+ room.db.desc = desc
+```
+
+Now we can use our new pyramid-shaped wilderness map. From inside Evennia we
+create a new wilderness (with the name "default") but using our new map provider:
+
+ py from world import pyramid as p; p.wilderness.create_wilderness(mapprovider=p.PyramidMapProvider())
+ py from evennia.contrib import wilderness; wilderness.enter_wilderness(me, coordinates=(4, 1))
+
+## Implementation details
+
+When a character moves into the wilderness, they get their own room. If they
+move, instead of moving the character, the room changes to match the new
+coordinates. If a character meets another character in the wilderness, then
+their room merges. When one of the character leaves again, they each get their
+own separate rooms. Rooms are created as needed. Unneeded rooms are stored away
+to avoid the overhead cost of creating new rooms again in the future.
+
+
+----
+
+This document page is generated from `evennia/contrib/grid/wilderness/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/Contribs/Contrib-XYZGrid.md b/docs/source/Contribs/Contrib-XYZGrid.md
new file mode 100644
index 0000000000..77f6e854ab
--- /dev/null
+++ b/docs/source/Contribs/Contrib-XYZGrid.md
@@ -0,0 +1,72 @@
+# XYZgrid
+
+Full grid coordinate- pathfinding and visualization system
+Evennia Contrib by Griatch 2021
+
+The default Evennia's rooms are non-euclidian - they can connect
+to each other with any types of exits without necessarily having a clear
+position relative to each other. This gives maximum flexibility, but many games
+want to use cardinal movements (north, east etc) and also features like finding
+the shortest-path between two points.
+
+This contrib forces each room to exist on a 3-dimensional XYZ grid and also
+implements very efficient pathfinding along with tools for displaying
+your current visual-range and a lot of related features.
+
+The rooms of the grid are entirely controlled from outside the game, using
+python modules with strings and dicts defining the map(s) of the game. It's
+possible to combine grid- with non-grid rooms, and you can decorate
+grid rooms as much as you like in-game, but you cannot spawn new grid
+rooms without editing the map files outside of the game.
+
+The full docs are found as
+[Contribs/XYZGrid](https://evennia.com/docs/latest/Contributions/XYZGrid.html)
+in the docs.
+
+## Installation
+
+
+1. If you haven't before, install the extra contrib requirements.
+ You can do so by doing `pip install -r requirements_extra.txt` from the
+ `evennia/` folder.
+2. Import and add the `evennia.contrib.grid.xyzgrid.commands.XYZGridCmdSet` to the
+ `CharacterCmdset` cmdset in `mygame/commands.default_cmds.py`. Reload
+ the server. This makes the `map`, `goto/path` and modified `teleport` and
+ `open` commands available in-game.
+3. Edit `mygame/server/conf/settings.py` and set
+
+ EXTRA_LAUNCHER_COMMANDS['xyzgrid'] = 'evennia.contrib.grid.xyzgrid.launchcmd.xyzcommand'
+
+4. Run the new `evennia xyzgrid help` for instructions on how to spawn the grid.
+
+## Example usage
+
+After installation, do the following (from your command line, where the
+`evennia` command is available) to install an example grid:
+
+ evennia xyzgrid init
+ evennia xyzgrid add evennia.contrib.grid.xyzgrid.example
+ evennia xyzgrid list
+ evennia xyzgrid show "the large tree"
+ evennia xyzgrid show "the small cave"
+ evennia xyzgrid spawn
+ evennia reload
+
+(remember to reload the server after spawn operations).
+
+Now you can log into the
+server and do `teleport (3,0,the large tree)` to teleport into the map.
+
+You can use `open togrid = (3, 0, the large tree)` to open a permanent (one-way)
+exit from your current location into the grid. To make a way back to a non-grid
+location just stand in a grid room and open a new exit out of it:
+`open tolimbo = #2`.
+
+Try `goto view` to go to the top of the tree and `goto dungeon` to go down to
+the dungeon entrance at the bottom of the tree.
+
+
+----
+
+This document page is generated from `evennia/contrib/grid/xyzgrid/README.md`. Changes to this
+file will be overwritten, so edit that file rather than this one.
diff --git a/docs/source/api/evennia.contrib.awsstorage.md b/docs/source/api/evennia.contrib.awsstorage.md
deleted file mode 100644
index 352e1cea4f..0000000000
--- a/docs/source/api/evennia.contrib.awsstorage.md
+++ /dev/null
@@ -1,18 +0,0 @@
-```{eval-rst}
-evennia.contrib.awsstorage
-==================================
-
-.. automodule:: evennia.contrib.awsstorage
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.awsstorage.aws_s3_cdn
- evennia.contrib.awsstorage.tests
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.awsstorage.tests.md b/docs/source/api/evennia.contrib.awsstorage.tests.md
deleted file mode 100644
index 9f78aa2340..0000000000
--- a/docs/source/api/evennia.contrib.awsstorage.tests.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.awsstorage.tests
-=======================================
-
-.. automodule:: evennia.contrib.awsstorage.tests
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.barter.md b/docs/source/api/evennia.contrib.barter.md
deleted file mode 100644
index fe80a4cb16..0000000000
--- a/docs/source/api/evennia.contrib.barter.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.barter
-=============================
-
-.. automodule:: evennia.contrib.barter
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.md b/docs/source/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.md
new file mode 100644
index 0000000000..6b43c668d5
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.awsstorage.aws\_s3\_cdn
+============================================================
+
+.. automodule:: evennia.contrib.base_systems.awsstorage.aws_s3_cdn
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.awsstorage.md b/docs/source/api/evennia.contrib.base_systems.awsstorage.md
new file mode 100644
index 0000000000..5d5e9d93be
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.awsstorage.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.base\_systems.awsstorage
+================================================
+
+.. automodule:: evennia.contrib.base_systems.awsstorage
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.awsstorage.aws_s3_cdn
+ evennia.contrib.base_systems.awsstorage.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.ingame_python.callbackhandler.md b/docs/source/api/evennia.contrib.base_systems.awsstorage.tests.md
similarity index 53%
rename from docs/source/api/evennia.contrib.ingame_python.callbackhandler.md
rename to docs/source/api/evennia.contrib.base_systems.awsstorage.tests.md
index 54be3910c6..87c7cbb384 100644
--- a/docs/source/api/evennia.contrib.ingame_python.callbackhandler.md
+++ b/docs/source/api/evennia.contrib.base_systems.awsstorage.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.callbackhandler
+evennia.contrib.base\_systems.awsstorage.tests
=====================================================
-.. automodule:: evennia.contrib.ingame_python.callbackhandler
+.. automodule:: evennia.contrib.base_systems.awsstorage.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.base_systems.building_menu.building_menu.md b/docs/source/api/evennia.contrib.base_systems.building_menu.building_menu.md
new file mode 100644
index 0000000000..8a52b2ef18
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.building_menu.building_menu.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.building\_menu.building\_menu
+==================================================================
+
+.. automodule:: evennia.contrib.base_systems.building_menu.building_menu
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.building_menu.md b/docs/source/api/evennia.contrib.base_systems.building_menu.md
new file mode 100644
index 0000000000..f1facb337a
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.building_menu.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.base\_systems.building\_menu
+====================================================
+
+.. automodule:: evennia.contrib.base_systems.building_menu
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.building_menu.building_menu
+ evennia.contrib.base_systems.building_menu.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.building_menu.tests.md b/docs/source/api/evennia.contrib.base_systems.building_menu.tests.md
new file mode 100644
index 0000000000..a3d4d1738b
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.building_menu.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.building\_menu.tests
+=========================================================
+
+.. automodule:: evennia.contrib.base_systems.building_menu.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.color_markups.color_markups.md b/docs/source/api/evennia.contrib.base_systems.color_markups.color_markups.md
new file mode 100644
index 0000000000..f049b591d4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.color_markups.color_markups.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.color\_markups.color\_markups
+==================================================================
+
+.. automodule:: evennia.contrib.base_systems.color_markups.color_markups
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.color_markups.md b/docs/source/api/evennia.contrib.base_systems.color_markups.md
new file mode 100644
index 0000000000..9c33bf3120
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.color_markups.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.base\_systems.color\_markups
+====================================================
+
+.. automodule:: evennia.contrib.base_systems.color_markups
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.color_markups.color_markups
+ evennia.contrib.base_systems.color_markups.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.color_markups.tests.md b/docs/source/api/evennia.contrib.base_systems.color_markups.tests.md
new file mode 100644
index 0000000000..d196f83ab3
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.color_markups.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.color\_markups.tests
+=========================================================
+
+.. automodule:: evennia.contrib.base_systems.color_markups.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.md b/docs/source/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.md
new file mode 100644
index 0000000000..0dd0b36f5c
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.custom\_gametime.custom\_gametime
+======================================================================
+
+.. automodule:: evennia.contrib.base_systems.custom_gametime.custom_gametime
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.custom_gametime.md b/docs/source/api/evennia.contrib.base_systems.custom_gametime.md
new file mode 100644
index 0000000000..75eb879096
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.custom_gametime.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.base\_systems.custom\_gametime
+======================================================
+
+.. automodule:: evennia.contrib.base_systems.custom_gametime
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.custom_gametime.custom_gametime
+ evennia.contrib.base_systems.custom_gametime.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.custom_gametime.tests.md b/docs/source/api/evennia.contrib.base_systems.custom_gametime.tests.md
new file mode 100644
index 0000000000..ee5078381b
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.custom_gametime.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.custom\_gametime.tests
+===========================================================
+
+.. automodule:: evennia.contrib.base_systems.custom_gametime.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.email_login.connection_screens.md b/docs/source/api/evennia.contrib.base_systems.email_login.connection_screens.md
new file mode 100644
index 0000000000..d4acbcd9c2
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.email_login.connection_screens.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.email\_login.connection\_screens
+=====================================================================
+
+.. automodule:: evennia.contrib.base_systems.email_login.connection_screens
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_examples.example_batch_code.md b/docs/source/api/evennia.contrib.base_systems.email_login.email_login.md
similarity index 51%
rename from docs/source/api/evennia.contrib.tutorial_examples.example_batch_code.md
rename to docs/source/api/evennia.contrib.base_systems.email_login.email_login.md
index 1f23e16fbc..3c1b93b39e 100644
--- a/docs/source/api/evennia.contrib.tutorial_examples.example_batch_code.md
+++ b/docs/source/api/evennia.contrib.base_systems.email_login.email_login.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_examples.example\_batch\_code
+evennia.contrib.base\_systems.email\_login.email\_login
==============================================================
-.. automodule:: evennia.contrib.tutorial_examples.example_batch_code
+.. automodule:: evennia.contrib.base_systems.email_login.email_login
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.base_systems.email_login.md b/docs/source/api/evennia.contrib.base_systems.email_login.md
new file mode 100644
index 0000000000..72aae080a6
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.email_login.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.base\_systems.email\_login
+==================================================
+
+.. automodule:: evennia.contrib.base_systems.email_login
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.email_login.connection_screens
+ evennia.contrib.base_systems.email_login.email_login
+ evennia.contrib.base_systems.email_login.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_examples.bodyfunctions.md b/docs/source/api/evennia.contrib.base_systems.email_login.tests.md
similarity index 53%
rename from docs/source/api/evennia.contrib.tutorial_examples.bodyfunctions.md
rename to docs/source/api/evennia.contrib.base_systems.email_login.tests.md
index 7927676910..64a4094312 100644
--- a/docs/source/api/evennia.contrib.tutorial_examples.bodyfunctions.md
+++ b/docs/source/api/evennia.contrib.base_systems.email_login.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_examples.bodyfunctions
+evennia.contrib.base\_systems.email\_login.tests
=======================================================
-.. automodule:: evennia.contrib.tutorial_examples.bodyfunctions
+.. automodule:: evennia.contrib.base_systems.email_login.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.callbackhandler.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.callbackhandler.md
new file mode 100644
index 0000000000..fc9c7bf04e
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.callbackhandler.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.callbackhandler
+===================================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.callbackhandler
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.commands.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.commands.md
new file mode 100644
index 0000000000..6f163372f7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.commands.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.commands
+============================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.commands
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.eventfuncs.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.eventfuncs.md
new file mode 100644
index 0000000000..51597da8f7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.eventfuncs.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.eventfuncs
+==============================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.eventfuncs
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.md
new file mode 100644
index 0000000000..1f9f1074b6
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.md
@@ -0,0 +1,23 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python
+====================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.ingame_python.callbackhandler
+ evennia.contrib.base_systems.ingame_python.commands
+ evennia.contrib.base_systems.ingame_python.eventfuncs
+ evennia.contrib.base_systems.ingame_python.scripts
+ evennia.contrib.base_systems.ingame_python.tests
+ evennia.contrib.base_systems.ingame_python.typeclasses
+ evennia.contrib.base_systems.ingame_python.utils
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.scripts.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.scripts.md
new file mode 100644
index 0000000000..5b1bd4c5cc
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.scripts.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.scripts
+===========================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.scripts
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.tests.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.tests.md
new file mode 100644
index 0000000000..d2e3ca5a6c
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.tests
+=========================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.typeclasses.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.typeclasses.md
new file mode 100644
index 0000000000..8ca0ae4dfc
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.typeclasses.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.typeclasses
+===============================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.typeclasses
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.ingame_python.utils.md b/docs/source/api/evennia.contrib.base_systems.ingame_python.utils.md
new file mode 100644
index 0000000000..f322ad72b1
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.ingame_python.utils.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.ingame\_python.utils
+=========================================================
+
+.. automodule:: evennia.contrib.base_systems.ingame_python.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.md b/docs/source/api/evennia.contrib.base_systems.md
new file mode 100644
index 0000000000..3de3dc1e4e
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.md
@@ -0,0 +1,24 @@
+```{eval-rst}
+evennia.contrib.base\_systems
+=====================================
+
+.. automodule:: evennia.contrib.base_systems
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.awsstorage
+ evennia.contrib.base_systems.building_menu
+ evennia.contrib.base_systems.color_markups
+ evennia.contrib.base_systems.custom_gametime
+ evennia.contrib.base_systems.email_login
+ evennia.contrib.base_systems.ingame_python
+ evennia.contrib.base_systems.menu_login
+ evennia.contrib.base_systems.mux_comms_cmds
+ evennia.contrib.base_systems.unixcommand
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.menu_login.connection_screens.md b/docs/source/api/evennia.contrib.base_systems.menu_login.connection_screens.md
new file mode 100644
index 0000000000..1cd39cb4db
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.menu_login.connection_screens.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.menu\_login.connection\_screens
+====================================================================
+
+.. automodule:: evennia.contrib.base_systems.menu_login.connection_screens
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.menu_login.md b/docs/source/api/evennia.contrib.base_systems.menu_login.md
new file mode 100644
index 0000000000..36155a063f
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.menu_login.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.base\_systems.menu\_login
+=================================================
+
+.. automodule:: evennia.contrib.base_systems.menu_login
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.menu_login.connection_screens
+ evennia.contrib.base_systems.menu_login.menu_login
+ evennia.contrib.base_systems.menu_login.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.menu_login.menu_login.md b/docs/source/api/evennia.contrib.base_systems.menu_login.menu_login.md
new file mode 100644
index 0000000000..60e16c7fb1
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.menu_login.menu_login.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.menu\_login.menu\_login
+============================================================
+
+.. automodule:: evennia.contrib.base_systems.menu_login.menu_login
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.menu_login.tests.md b/docs/source/api/evennia.contrib.base_systems.menu_login.tests.md
new file mode 100644
index 0000000000..c485eee4df
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.menu_login.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.menu\_login.tests
+======================================================
+
+.. automodule:: evennia.contrib.base_systems.menu_login.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.md b/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.md
new file mode 100644
index 0000000000..8d901a3c32
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.base\_systems.mux\_comms\_cmds
+======================================================
+
+.. automodule:: evennia.contrib.base_systems.mux_comms_cmds
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds
+ evennia.contrib.base_systems.mux_comms_cmds.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.md b/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.md
new file mode 100644
index 0000000000..afbc3865d2
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.mux\_comms\_cmds.mux\_comms\_cmds
+======================================================================
+
+.. automodule:: evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.tests.md b/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.tests.md
new file mode 100644
index 0000000000..d89b5423f1
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.mux_comms_cmds.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.mux\_comms\_cmds.tests
+===========================================================
+
+.. automodule:: evennia.contrib.base_systems.mux_comms_cmds.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.unixcommand.md b/docs/source/api/evennia.contrib.base_systems.unixcommand.md
new file mode 100644
index 0000000000..ffe205ef0c
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.unixcommand.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.base\_systems.unixcommand
+=================================================
+
+.. automodule:: evennia.contrib.base_systems.unixcommand
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.base_systems.unixcommand.tests
+ evennia.contrib.base_systems.unixcommand.unixcommand
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.unixcommand.tests.md b/docs/source/api/evennia.contrib.base_systems.unixcommand.tests.md
new file mode 100644
index 0000000000..d09fba9c39
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.unixcommand.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.unixcommand.tests
+======================================================
+
+.. automodule:: evennia.contrib.base_systems.unixcommand.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.base_systems.unixcommand.unixcommand.md b/docs/source/api/evennia.contrib.base_systems.unixcommand.unixcommand.md
new file mode 100644
index 0000000000..b4d3374feb
--- /dev/null
+++ b/docs/source/api/evennia.contrib.base_systems.unixcommand.unixcommand.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.base\_systems.unixcommand.unixcommand
+============================================================
+
+.. automodule:: evennia.contrib.base_systems.unixcommand.unixcommand
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.building_menu.md b/docs/source/api/evennia.contrib.building_menu.md
deleted file mode 100644
index 68b3756b11..0000000000
--- a/docs/source/api/evennia.contrib.building_menu.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.building\_menu
-=====================================
-
-.. automodule:: evennia.contrib.building_menu
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.chargen.md b/docs/source/api/evennia.contrib.chargen.md
deleted file mode 100644
index 54e2b1c89c..0000000000
--- a/docs/source/api/evennia.contrib.chargen.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.chargen
-==============================
-
-.. automodule:: evennia.contrib.chargen
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.clothing.md b/docs/source/api/evennia.contrib.clothing.md
deleted file mode 100644
index 06b083fef6..0000000000
--- a/docs/source/api/evennia.contrib.clothing.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.clothing
-===============================
-
-.. automodule:: evennia.contrib.clothing
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.crafting.md b/docs/source/api/evennia.contrib.crafting.md
deleted file mode 100644
index 3093c21711..0000000000
--- a/docs/source/api/evennia.contrib.crafting.md
+++ /dev/null
@@ -1,19 +0,0 @@
-```{eval-rst}
-evennia.contrib.crafting
-================================
-
-.. automodule:: evennia.contrib.crafting
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.crafting.crafting
- evennia.contrib.crafting.example_recipes
- evennia.contrib.crafting.tests
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.crafting.tests.md b/docs/source/api/evennia.contrib.crafting.tests.md
deleted file mode 100644
index 0b0e3ae777..0000000000
--- a/docs/source/api/evennia.contrib.crafting.tests.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.crafting.tests
-=====================================
-
-.. automodule:: evennia.contrib.crafting.tests
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.dice.md b/docs/source/api/evennia.contrib.dice.md
deleted file mode 100644
index 2a9b9e0b21..0000000000
--- a/docs/source/api/evennia.contrib.dice.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.dice
-===========================
-
-.. automodule:: evennia.contrib.dice
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.email_login.md b/docs/source/api/evennia.contrib.email_login.md
deleted file mode 100644
index 2c9121c193..0000000000
--- a/docs/source/api/evennia.contrib.email_login.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.email\_login
-===================================
-
-.. automodule:: evennia.contrib.email_login
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.md b/docs/source/api/evennia.contrib.evscaperoom.md
deleted file mode 100644
index 2698a22e50..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.md
+++ /dev/null
@@ -1,24 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom
-===================================
-
-.. automodule:: evennia.contrib.evscaperoom
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.evscaperoom.commands
- evennia.contrib.evscaperoom.menu
- evennia.contrib.evscaperoom.objects
- evennia.contrib.evscaperoom.room
- evennia.contrib.evscaperoom.scripts
- evennia.contrib.evscaperoom.state
- evennia.contrib.evscaperoom.tests
- evennia.contrib.evscaperoom.utils
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.menu.md b/docs/source/api/evennia.contrib.evscaperoom.menu.md
deleted file mode 100644
index 7d0ecf8b14..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.menu.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.menu
-=======================================
-
-.. automodule:: evennia.contrib.evscaperoom.menu
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.objects.md b/docs/source/api/evennia.contrib.evscaperoom.objects.md
deleted file mode 100644
index 4df4d800fb..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.objects.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.objects
-==========================================
-
-.. automodule:: evennia.contrib.evscaperoom.objects
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.room.md b/docs/source/api/evennia.contrib.evscaperoom.room.md
deleted file mode 100644
index 4d6fd4a2de..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.room.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.room
-=======================================
-
-.. automodule:: evennia.contrib.evscaperoom.room
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.scripts.md b/docs/source/api/evennia.contrib.evscaperoom.scripts.md
deleted file mode 100644
index cd23004c16..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.scripts.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.scripts
-==========================================
-
-.. automodule:: evennia.contrib.evscaperoom.scripts
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.state.md b/docs/source/api/evennia.contrib.evscaperoom.state.md
deleted file mode 100644
index 266820c5c0..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.state.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.state
-========================================
-
-.. automodule:: evennia.contrib.evscaperoom.state
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.tests.md b/docs/source/api/evennia.contrib.evscaperoom.tests.md
deleted file mode 100644
index 7a78bd512c..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.tests.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.tests
-========================================
-
-.. automodule:: evennia.contrib.evscaperoom.tests
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.utils.md b/docs/source/api/evennia.contrib.evscaperoom.utils.md
deleted file mode 100644
index 83d3fd4fc0..0000000000
--- a/docs/source/api/evennia.contrib.evscaperoom.utils.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.evscaperoom.utils
-========================================
-
-.. automodule:: evennia.contrib.evscaperoom.utils
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.extended_room.md b/docs/source/api/evennia.contrib.extended_room.md
deleted file mode 100644
index 2abc52496d..0000000000
--- a/docs/source/api/evennia.contrib.extended_room.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.extended\_room
-=====================================
-
-.. automodule:: evennia.contrib.extended_room
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.fieldfill.md b/docs/source/api/evennia.contrib.fieldfill.md
deleted file mode 100644
index db6f38c686..0000000000
--- a/docs/source/api/evennia.contrib.fieldfill.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.fieldfill
-================================
-
-.. automodule:: evennia.contrib.fieldfill
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.commands.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.commands.md
new file mode 100644
index 0000000000..3a56b629d2
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.commands.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.commands
+=========================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.commands
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.md
new file mode 100644
index 0000000000..604b0d50ec
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.md
@@ -0,0 +1,24 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom
+=================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.full_systems.evscaperoom.commands
+ evennia.contrib.full_systems.evscaperoom.menu
+ evennia.contrib.full_systems.evscaperoom.objects
+ evennia.contrib.full_systems.evscaperoom.room
+ evennia.contrib.full_systems.evscaperoom.scripts
+ evennia.contrib.full_systems.evscaperoom.state
+ evennia.contrib.full_systems.evscaperoom.tests
+ evennia.contrib.full_systems.evscaperoom.utils
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_examples.red_button.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.menu.md
similarity index 53%
rename from docs/source/api/evennia.contrib.tutorial_examples.red_button.md
rename to docs/source/api/evennia.contrib.full_systems.evscaperoom.menu.md
index b37bb6bb06..db9c3f2cbd 100644
--- a/docs/source/api/evennia.contrib.tutorial_examples.red_button.md
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.menu.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_examples.red\_button
+evennia.contrib.full\_systems.evscaperoom.menu
=====================================================
-.. automodule:: evennia.contrib.tutorial_examples.red_button
+.. automodule:: evennia.contrib.full_systems.evscaperoom.menu
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.objects.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.objects.md
new file mode 100644
index 0000000000..434595928f
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.objects.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.objects
+========================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.objects
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.room.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.room.md
new file mode 100644
index 0000000000..1c82f2ee17
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.room.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.room
+=====================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.room
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.scripts.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.scripts.md
new file mode 100644
index 0000000000..4c0b70ffa2
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.scripts.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.scripts
+========================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.scripts
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.state.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.state.md
new file mode 100644
index 0000000000..d665b6cb64
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.state.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.state
+======================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.state
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.tests.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.tests.md
new file mode 100644
index 0000000000..63c00551b4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.tests
+======================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.evscaperoom.utils.md b/docs/source/api/evennia.contrib.full_systems.evscaperoom.utils.md
new file mode 100644
index 0000000000..0d4eacbdea
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.evscaperoom.utils.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.full\_systems.evscaperoom.utils
+======================================================
+
+.. automodule:: evennia.contrib.full_systems.evscaperoom.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.full_systems.md b/docs/source/api/evennia.contrib.full_systems.md
new file mode 100644
index 0000000000..5311302a4f
--- /dev/null
+++ b/docs/source/api/evennia.contrib.full_systems.md
@@ -0,0 +1,16 @@
+```{eval-rst}
+evennia.contrib.full\_systems
+=====================================
+
+.. automodule:: evennia.contrib.full_systems
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.full_systems.evscaperoom
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.barter.barter.md b/docs/source/api/evennia.contrib.game_systems.barter.barter.md
new file mode 100644
index 0000000000..3581712b10
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.barter.barter.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.barter.barter
+==================================================
+
+.. automodule:: evennia.contrib.game_systems.barter.barter
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.barter.md b/docs/source/api/evennia.contrib.game_systems.barter.md
new file mode 100644
index 0000000000..bca3bcb495
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.barter.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.barter
+============================================
+
+.. automodule:: evennia.contrib.game_systems.barter
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.barter.barter
+ evennia.contrib.game_systems.barter.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.ingame_python.typeclasses.md b/docs/source/api/evennia.contrib.game_systems.barter.tests.md
similarity index 54%
rename from docs/source/api/evennia.contrib.ingame_python.typeclasses.md
rename to docs/source/api/evennia.contrib.game_systems.barter.tests.md
index 6db7d68994..2d2e0b440a 100644
--- a/docs/source/api/evennia.contrib.ingame_python.typeclasses.md
+++ b/docs/source/api/evennia.contrib.game_systems.barter.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.typeclasses
+evennia.contrib.game\_systems.barter.tests
=================================================
-.. automodule:: evennia.contrib.ingame_python.typeclasses
+.. automodule:: evennia.contrib.game_systems.barter.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.game_systems.clothing.clothing.md b/docs/source/api/evennia.contrib.game_systems.clothing.clothing.md
new file mode 100644
index 0000000000..314dcd4731
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.clothing.clothing.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.clothing.clothing
+======================================================
+
+.. automodule:: evennia.contrib.game_systems.clothing.clothing
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.clothing.md b/docs/source/api/evennia.contrib.game_systems.clothing.md
new file mode 100644
index 0000000000..06a1cf1dc1
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.clothing.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.clothing
+==============================================
+
+.. automodule:: evennia.contrib.game_systems.clothing
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.clothing.clothing
+ evennia.contrib.game_systems.clothing.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.clothing.tests.md b/docs/source/api/evennia.contrib.game_systems.clothing.tests.md
new file mode 100644
index 0000000000..dfcfffebe5
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.clothing.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.clothing.tests
+===================================================
+
+.. automodule:: evennia.contrib.game_systems.clothing.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.cooldowns.cooldowns.md b/docs/source/api/evennia.contrib.game_systems.cooldowns.cooldowns.md
new file mode 100644
index 0000000000..49a16396fa
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.cooldowns.cooldowns.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.cooldowns.cooldowns
+========================================================
+
+.. automodule:: evennia.contrib.game_systems.cooldowns.cooldowns
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.cooldowns.md b/docs/source/api/evennia.contrib.game_systems.cooldowns.md
new file mode 100644
index 0000000000..2331ec94af
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.cooldowns.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.cooldowns
+===============================================
+
+.. automodule:: evennia.contrib.game_systems.cooldowns
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.cooldowns.cooldowns
+ evennia.contrib.game_systems.cooldowns.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.cooldowns.tests.md b/docs/source/api/evennia.contrib.game_systems.cooldowns.tests.md
new file mode 100644
index 0000000000..fb6bea9a1e
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.cooldowns.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.cooldowns.tests
+====================================================
+
+.. automodule:: evennia.contrib.game_systems.cooldowns.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.crafting.crafting.md b/docs/source/api/evennia.contrib.game_systems.crafting.crafting.md
new file mode 100644
index 0000000000..ac26805ed4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.crafting.crafting.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.crafting.crafting
+======================================================
+
+.. automodule:: evennia.contrib.game_systems.crafting.crafting
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.crafting.example_recipes.md b/docs/source/api/evennia.contrib.game_systems.crafting.example_recipes.md
new file mode 100644
index 0000000000..6c17b90c27
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.crafting.example_recipes.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.crafting.example\_recipes
+==============================================================
+
+.. automodule:: evennia.contrib.game_systems.crafting.example_recipes
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.crafting.md b/docs/source/api/evennia.contrib.game_systems.crafting.md
new file mode 100644
index 0000000000..f5b2fee341
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.crafting.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.game\_systems.crafting
+==============================================
+
+.. automodule:: evennia.contrib.game_systems.crafting
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.crafting.crafting
+ evennia.contrib.game_systems.crafting.example_recipes
+ evennia.contrib.game_systems.crafting.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.crafting.tests.md b/docs/source/api/evennia.contrib.game_systems.crafting.tests.md
new file mode 100644
index 0000000000..ee979eb1e7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.crafting.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.crafting.tests
+===================================================
+
+.. automodule:: evennia.contrib.game_systems.crafting.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.gendersub.gendersub.md b/docs/source/api/evennia.contrib.game_systems.gendersub.gendersub.md
new file mode 100644
index 0000000000..6b3e550a90
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.gendersub.gendersub.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.gendersub.gendersub
+========================================================
+
+.. automodule:: evennia.contrib.game_systems.gendersub.gendersub
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.gendersub.md b/docs/source/api/evennia.contrib.game_systems.gendersub.md
new file mode 100644
index 0000000000..5436c0f0ae
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.gendersub.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.gendersub
+===============================================
+
+.. automodule:: evennia.contrib.game_systems.gendersub
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.gendersub.gendersub
+ evennia.contrib.game_systems.gendersub.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.gendersub.tests.md b/docs/source/api/evennia.contrib.game_systems.gendersub.tests.md
new file mode 100644
index 0000000000..41a1d7afd3
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.gendersub.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.gendersub.tests
+====================================================
+
+.. automodule:: evennia.contrib.game_systems.gendersub.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.awsstorage.aws_s3_cdn.md b/docs/source/api/evennia.contrib.game_systems.mail.mail.md
similarity index 55%
rename from docs/source/api/evennia.contrib.awsstorage.aws_s3_cdn.md
rename to docs/source/api/evennia.contrib.game_systems.mail.mail.md
index 9b0e3f4ab0..05f856044c 100644
--- a/docs/source/api/evennia.contrib.awsstorage.aws_s3_cdn.md
+++ b/docs/source/api/evennia.contrib.game_systems.mail.mail.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.awsstorage.aws\_s3\_cdn
+evennia.contrib.game\_systems.mail.mail
==============================================
-.. automodule:: evennia.contrib.awsstorage.aws_s3_cdn
+.. automodule:: evennia.contrib.game_systems.mail.mail
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.game_systems.mail.md b/docs/source/api/evennia.contrib.game_systems.mail.md
new file mode 100644
index 0000000000..02fbf1f343
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.mail.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.mail
+==========================================
+
+.. automodule:: evennia.contrib.game_systems.mail
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.mail.mail
+ evennia.contrib.game_systems.mail.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_examples.tests.md b/docs/source/api/evennia.contrib.game_systems.mail.tests.md
similarity index 55%
rename from docs/source/api/evennia.contrib.tutorial_examples.tests.md
rename to docs/source/api/evennia.contrib.game_systems.mail.tests.md
index 9e27c81be5..0c6a5e965c 100644
--- a/docs/source/api/evennia.contrib.tutorial_examples.tests.md
+++ b/docs/source/api/evennia.contrib.game_systems.mail.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_examples.tests
+evennia.contrib.game\_systems.mail.tests
===============================================
-.. automodule:: evennia.contrib.tutorial_examples.tests
+.. automodule:: evennia.contrib.game_systems.mail.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.game_systems.md b/docs/source/api/evennia.contrib.game_systems.md
new file mode 100644
index 0000000000..b321dd8abc
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.md
@@ -0,0 +1,24 @@
+```{eval-rst}
+evennia.contrib.game\_systems
+=====================================
+
+.. automodule:: evennia.contrib.game_systems
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.barter
+ evennia.contrib.game_systems.clothing
+ evennia.contrib.game_systems.cooldowns
+ evennia.contrib.game_systems.crafting
+ evennia.contrib.game_systems.gendersub
+ evennia.contrib.game_systems.mail
+ evennia.contrib.game_systems.multidescer
+ evennia.contrib.game_systems.puzzles
+ evennia.contrib.game_systems.turnbattle
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.multidescer.md b/docs/source/api/evennia.contrib.game_systems.multidescer.md
new file mode 100644
index 0000000000..61e24aefa3
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.multidescer.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.multidescer
+=================================================
+
+.. automodule:: evennia.contrib.game_systems.multidescer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.multidescer.multidescer
+ evennia.contrib.game_systems.multidescer.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.multidescer.multidescer.md b/docs/source/api/evennia.contrib.game_systems.multidescer.multidescer.md
new file mode 100644
index 0000000000..37562e89d7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.multidescer.multidescer.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.multidescer.multidescer
+============================================================
+
+.. automodule:: evennia.contrib.game_systems.multidescer.multidescer
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.multidescer.tests.md b/docs/source/api/evennia.contrib.game_systems.multidescer.tests.md
new file mode 100644
index 0000000000..45c9005719
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.multidescer.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.multidescer.tests
+======================================================
+
+.. automodule:: evennia.contrib.game_systems.multidescer.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.puzzles.md b/docs/source/api/evennia.contrib.game_systems.puzzles.md
new file mode 100644
index 0000000000..13a233ce40
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.puzzles.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.game\_systems.puzzles
+=============================================
+
+.. automodule:: evennia.contrib.game_systems.puzzles
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.puzzles.puzzles
+ evennia.contrib.game_systems.puzzles.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.puzzles.puzzles.md b/docs/source/api/evennia.contrib.game_systems.puzzles.puzzles.md
new file mode 100644
index 0000000000..47b27e65ff
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.puzzles.puzzles.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.puzzles.puzzles
+====================================================
+
+.. automodule:: evennia.contrib.game_systems.puzzles.puzzles
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.puzzles.tests.md b/docs/source/api/evennia.contrib.game_systems.puzzles.tests.md
new file mode 100644
index 0000000000..507fed2ddf
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.puzzles.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.puzzles.tests
+==================================================
+
+.. automodule:: evennia.contrib.game_systems.puzzles.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.md
new file mode 100644
index 0000000000..9dc068cd74
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.md
@@ -0,0 +1,22 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle
+================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.game_systems.turnbattle.tb_basic
+ evennia.contrib.game_systems.turnbattle.tb_equip
+ evennia.contrib.game_systems.turnbattle.tb_items
+ evennia.contrib.game_systems.turnbattle.tb_magic
+ evennia.contrib.game_systems.turnbattle.tb_range
+ evennia.contrib.game_systems.turnbattle.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_basic.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_basic.md
new file mode 100644
index 0000000000..84dcd9bedb
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_basic.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle.tb\_basic
+=========================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle.tb_basic
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_equip.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_equip.md
new file mode 100644
index 0000000000..77af0c59f8
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_equip.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle.tb\_equip
+=========================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle.tb_equip
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_items.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_items.md
new file mode 100644
index 0000000000..48c82ed705
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_items.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle.tb\_items
+=========================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle.tb_items
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_magic.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_magic.md
new file mode 100644
index 0000000000..a2326b44cd
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_magic.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle.tb\_magic
+=========================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle.tb_magic
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_range.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_range.md
new file mode 100644
index 0000000000..4c8ce513f3
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.tb_range.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle.tb\_range
+=========================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle.tb_range
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.game_systems.turnbattle.tests.md b/docs/source/api/evennia.contrib.game_systems.turnbattle.tests.md
new file mode 100644
index 0000000000..81f21bbcf0
--- /dev/null
+++ b/docs/source/api/evennia.contrib.game_systems.turnbattle.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.game\_systems.turnbattle.tests
+=====================================================
+
+.. automodule:: evennia.contrib.game_systems.turnbattle.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.gendersub.md b/docs/source/api/evennia.contrib.gendersub.md
deleted file mode 100644
index e741f28541..0000000000
--- a/docs/source/api/evennia.contrib.gendersub.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.gendersub
-================================
-
-.. automodule:: evennia.contrib.gendersub
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.extended_room.extended_room.md b/docs/source/api/evennia.contrib.grid.extended_room.extended_room.md
new file mode 100644
index 0000000000..c36822314a
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.extended_room.extended_room.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.extended\_room.extended\_room
+=========================================================
+
+.. automodule:: evennia.contrib.grid.extended_room.extended_room
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.extended_room.md b/docs/source/api/evennia.contrib.grid.extended_room.md
new file mode 100644
index 0000000000..807c1a9b80
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.extended_room.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.grid.extended\_room
+===========================================
+
+.. automodule:: evennia.contrib.grid.extended_room
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.extended_room.extended_room
+ evennia.contrib.grid.extended_room.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.crafting.example_recipes.md b/docs/source/api/evennia.contrib.grid.extended_room.tests.md
similarity index 54%
rename from docs/source/api/evennia.contrib.crafting.example_recipes.md
rename to docs/source/api/evennia.contrib.grid.extended_room.tests.md
index e162f98c73..64b2e2eceb 100644
--- a/docs/source/api/evennia.contrib.crafting.example_recipes.md
+++ b/docs/source/api/evennia.contrib.grid.extended_room.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.crafting.example\_recipes
+evennia.contrib.grid.extended\_room.tests
================================================
-.. automodule:: evennia.contrib.crafting.example_recipes
+.. automodule:: evennia.contrib.grid.extended_room.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.grid.mapbuilder.mapbuilder.md b/docs/source/api/evennia.contrib.grid.mapbuilder.mapbuilder.md
new file mode 100644
index 0000000000..d52ad81098
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.mapbuilder.mapbuilder.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.mapbuilder.mapbuilder
+=================================================
+
+.. automodule:: evennia.contrib.grid.mapbuilder.mapbuilder
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.mapbuilder.md b/docs/source/api/evennia.contrib.grid.mapbuilder.md
new file mode 100644
index 0000000000..cc6ea452fc
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.mapbuilder.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.grid.mapbuilder
+=======================================
+
+.. automodule:: evennia.contrib.grid.mapbuilder
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.mapbuilder.mapbuilder
+ evennia.contrib.grid.mapbuilder.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.mapbuilder.tests.md b/docs/source/api/evennia.contrib.grid.mapbuilder.tests.md
new file mode 100644
index 0000000000..e6e3277dec
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.mapbuilder.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.mapbuilder.tests
+============================================
+
+.. automodule:: evennia.contrib.grid.mapbuilder.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.md b/docs/source/api/evennia.contrib.grid.md
new file mode 100644
index 0000000000..2000a6de80
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.md
@@ -0,0 +1,21 @@
+```{eval-rst}
+evennia.contrib.grid
+============================
+
+.. automodule:: evennia.contrib.grid
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.extended_room
+ evennia.contrib.grid.mapbuilder
+ evennia.contrib.grid.simpledoor
+ evennia.contrib.grid.slow_exit
+ evennia.contrib.grid.wilderness
+ evennia.contrib.grid.xyzgrid
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.simpledoor.md b/docs/source/api/evennia.contrib.grid.simpledoor.md
new file mode 100644
index 0000000000..12088ac347
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.simpledoor.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.grid.simpledoor
+=======================================
+
+.. automodule:: evennia.contrib.grid.simpledoor
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.simpledoor.simpledoor
+ evennia.contrib.grid.simpledoor.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.simpledoor.simpledoor.md b/docs/source/api/evennia.contrib.grid.simpledoor.simpledoor.md
new file mode 100644
index 0000000000..15ce6141b3
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.simpledoor.simpledoor.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.simpledoor.simpledoor
+=================================================
+
+.. automodule:: evennia.contrib.grid.simpledoor.simpledoor
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.simpledoor.tests.md b/docs/source/api/evennia.contrib.grid.simpledoor.tests.md
new file mode 100644
index 0000000000..1eb82139ad
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.simpledoor.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.simpledoor.tests
+============================================
+
+.. automodule:: evennia.contrib.grid.simpledoor.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.slow_exit.md b/docs/source/api/evennia.contrib.grid.slow_exit.md
new file mode 100644
index 0000000000..d7f55608cf
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.slow_exit.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.grid.slow\_exit
+=======================================
+
+.. automodule:: evennia.contrib.grid.slow_exit
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.slow_exit.slow_exit
+ evennia.contrib.grid.slow_exit.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.slow_exit.slow_exit.md b/docs/source/api/evennia.contrib.grid.slow_exit.slow_exit.md
new file mode 100644
index 0000000000..2a570bca98
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.slow_exit.slow_exit.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.slow\_exit.slow\_exit
+=================================================
+
+.. automodule:: evennia.contrib.grid.slow_exit.slow_exit
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_world.rooms.md b/docs/source/api/evennia.contrib.grid.slow_exit.tests.md
similarity index 56%
rename from docs/source/api/evennia.contrib.tutorial_world.rooms.md
rename to docs/source/api/evennia.contrib.grid.slow_exit.tests.md
index 9dc28d3c58..d73e617173 100644
--- a/docs/source/api/evennia.contrib.tutorial_world.rooms.md
+++ b/docs/source/api/evennia.contrib.grid.slow_exit.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_world.rooms
+evennia.contrib.grid.slow\_exit.tests
============================================
-.. automodule:: evennia.contrib.tutorial_world.rooms
+.. automodule:: evennia.contrib.grid.slow_exit.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.grid.wilderness.md b/docs/source/api/evennia.contrib.grid.wilderness.md
new file mode 100644
index 0000000000..40874fc1bb
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.wilderness.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.grid.wilderness
+=======================================
+
+.. automodule:: evennia.contrib.grid.wilderness
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.wilderness.tests
+ evennia.contrib.grid.wilderness.wilderness
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.wilderness.tests.md b/docs/source/api/evennia.contrib.grid.wilderness.tests.md
new file mode 100644
index 0000000000..fc3910a4ac
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.wilderness.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.wilderness.tests
+============================================
+
+.. automodule:: evennia.contrib.grid.wilderness.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.wilderness.wilderness.md b/docs/source/api/evennia.contrib.grid.wilderness.wilderness.md
new file mode 100644
index 0000000000..5c24257c00
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.wilderness.wilderness.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.wilderness.wilderness
+=================================================
+
+.. automodule:: evennia.contrib.grid.wilderness.wilderness
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.xyzgrid.commands.md b/docs/source/api/evennia.contrib.grid.xyzgrid.commands.md
new file mode 100644
index 0000000000..b586dfae16
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.commands.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.xyzgrid.commands
+============================================
+
+.. automodule:: evennia.contrib.grid.xyzgrid.commands
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.evscaperoom.commands.md b/docs/source/api/evennia.contrib.grid.xyzgrid.example.md
similarity index 56%
rename from docs/source/api/evennia.contrib.evscaperoom.commands.md
rename to docs/source/api/evennia.contrib.grid.xyzgrid.example.md
index 4862735b58..bffd8efc1d 100644
--- a/docs/source/api/evennia.contrib.evscaperoom.commands.md
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.example.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.evscaperoom.commands
+evennia.contrib.grid.xyzgrid.example
===========================================
-.. automodule:: evennia.contrib.evscaperoom.commands
+.. automodule:: evennia.contrib.grid.xyzgrid.example
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.ingame_python.scripts.md b/docs/source/api/evennia.contrib.grid.xyzgrid.launchcmd.md
similarity index 55%
rename from docs/source/api/evennia.contrib.ingame_python.scripts.md
rename to docs/source/api/evennia.contrib.grid.xyzgrid.launchcmd.md
index 25dd4ee6e4..b17b1aa411 100644
--- a/docs/source/api/evennia.contrib.ingame_python.scripts.md
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.launchcmd.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.scripts
+evennia.contrib.grid.xyzgrid.launchcmd
=============================================
-.. automodule:: evennia.contrib.ingame_python.scripts
+.. automodule:: evennia.contrib.grid.xyzgrid.launchcmd
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.grid.xyzgrid.md b/docs/source/api/evennia.contrib.grid.xyzgrid.md
new file mode 100644
index 0000000000..653ecbf52e
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.md
@@ -0,0 +1,26 @@
+```{eval-rst}
+evennia.contrib.grid.xyzgrid
+====================================
+
+.. automodule:: evennia.contrib.grid.xyzgrid
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.grid.xyzgrid.commands
+ evennia.contrib.grid.xyzgrid.example
+ evennia.contrib.grid.xyzgrid.launchcmd
+ evennia.contrib.grid.xyzgrid.prototypes
+ evennia.contrib.grid.xyzgrid.tests
+ evennia.contrib.grid.xyzgrid.utils
+ evennia.contrib.grid.xyzgrid.xymap
+ evennia.contrib.grid.xyzgrid.xymap_legend
+ evennia.contrib.grid.xyzgrid.xyzgrid
+ evennia.contrib.grid.xyzgrid.xyzroom
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.ingame_python.commands.md b/docs/source/api/evennia.contrib.grid.xyzgrid.prototypes.md
similarity index 55%
rename from docs/source/api/evennia.contrib.ingame_python.commands.md
rename to docs/source/api/evennia.contrib.grid.xyzgrid.prototypes.md
index dbe8d1d206..da57152549 100644
--- a/docs/source/api/evennia.contrib.ingame_python.commands.md
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.prototypes.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.commands
+evennia.contrib.grid.xyzgrid.prototypes
==============================================
-.. automodule:: evennia.contrib.ingame_python.commands
+.. automodule:: evennia.contrib.grid.xyzgrid.prototypes
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.xyzgrid.prototypes.md b/docs/source/api/evennia.contrib.grid.xyzgrid.tests.md
similarity index 56%
rename from docs/source/api/evennia.contrib.xyzgrid.prototypes.md
rename to docs/source/api/evennia.contrib.grid.xyzgrid.tests.md
index 6cb097dfc0..b9e711c8a2 100644
--- a/docs/source/api/evennia.contrib.xyzgrid.prototypes.md
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.xyzgrid.prototypes
+evennia.contrib.grid.xyzgrid.tests
=========================================
-.. automodule:: evennia.contrib.xyzgrid.prototypes
+.. automodule:: evennia.contrib.grid.xyzgrid.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.grid.xyzgrid.utils.md b/docs/source/api/evennia.contrib.grid.xyzgrid.utils.md
new file mode 100644
index 0000000000..c19523d7f4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.utils.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.xyzgrid.utils
+=========================================
+
+.. automodule:: evennia.contrib.grid.xyzgrid.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.xyzgrid.xymap.md b/docs/source/api/evennia.contrib.grid.xyzgrid.xymap.md
new file mode 100644
index 0000000000..a219d54a43
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.xymap.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.xyzgrid.xymap
+=========================================
+
+.. automodule:: evennia.contrib.grid.xyzgrid.xymap
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.grid.xyzgrid.xymap_legend.md b/docs/source/api/evennia.contrib.grid.xyzgrid.xymap_legend.md
new file mode 100644
index 0000000000..cf2548736a
--- /dev/null
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.xymap_legend.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.grid.xyzgrid.xymap\_legend
+=================================================
+
+.. automodule:: evennia.contrib.grid.xyzgrid.xymap_legend
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.ingame_python.tests.md b/docs/source/api/evennia.contrib.grid.xyzgrid.xyzgrid.md
similarity index 56%
rename from docs/source/api/evennia.contrib.ingame_python.tests.md
rename to docs/source/api/evennia.contrib.grid.xyzgrid.xyzgrid.md
index 5392da43f0..ccff5fc06e 100644
--- a/docs/source/api/evennia.contrib.ingame_python.tests.md
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.xyzgrid.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.tests
+evennia.contrib.grid.xyzgrid.xyzgrid
===========================================
-.. automodule:: evennia.contrib.ingame_python.tests
+.. automodule:: evennia.contrib.grid.xyzgrid.xyzgrid
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.ingame_python.utils.md b/docs/source/api/evennia.contrib.grid.xyzgrid.xyzroom.md
similarity index 56%
rename from docs/source/api/evennia.contrib.ingame_python.utils.md
rename to docs/source/api/evennia.contrib.grid.xyzgrid.xyzroom.md
index ef6d6abe8e..e07726a43d 100644
--- a/docs/source/api/evennia.contrib.ingame_python.utils.md
+++ b/docs/source/api/evennia.contrib.grid.xyzgrid.xyzroom.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.utils
+evennia.contrib.grid.xyzgrid.xyzroom
===========================================
-.. automodule:: evennia.contrib.ingame_python.utils
+.. automodule:: evennia.contrib.grid.xyzgrid.xyzroom
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.health_bar.md b/docs/source/api/evennia.contrib.health_bar.md
deleted file mode 100644
index 7796497196..0000000000
--- a/docs/source/api/evennia.contrib.health_bar.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.health\_bar
-==================================
-
-.. automodule:: evennia.contrib.health_bar
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.ingame_python.md b/docs/source/api/evennia.contrib.ingame_python.md
deleted file mode 100644
index 75930be320..0000000000
--- a/docs/source/api/evennia.contrib.ingame_python.md
+++ /dev/null
@@ -1,23 +0,0 @@
-```{eval-rst}
-evennia.contrib.ingame\_python
-======================================
-
-.. automodule:: evennia.contrib.ingame_python
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.ingame_python.callbackhandler
- evennia.contrib.ingame_python.commands
- evennia.contrib.ingame_python.eventfuncs
- evennia.contrib.ingame_python.scripts
- evennia.contrib.ingame_python.tests
- evennia.contrib.ingame_python.typeclasses
- evennia.contrib.ingame_python.utils
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.mail.md b/docs/source/api/evennia.contrib.mail.md
deleted file mode 100644
index 98b7d74e29..0000000000
--- a/docs/source/api/evennia.contrib.mail.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.mail
-===========================
-
-.. automodule:: evennia.contrib.mail
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.mapbuilder.md b/docs/source/api/evennia.contrib.mapbuilder.md
deleted file mode 100644
index cefd748613..0000000000
--- a/docs/source/api/evennia.contrib.mapbuilder.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.mapbuilder
-=================================
-
-.. automodule:: evennia.contrib.mapbuilder
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.md b/docs/source/api/evennia.contrib.md
index 4c8f484653..04c5631e9f 100644
--- a/docs/source/api/evennia.contrib.md
+++ b/docs/source/api/evennia.contrib.md
@@ -1,5 +1,5 @@
```{eval-rst}
-evennia.contrib
+evennia.contrib
=======================
.. automodule:: evennia.contrib
@@ -8,52 +8,15 @@ evennia.contrib
:show-inheritance:
-
.. toctree::
:maxdepth: 6
- evennia.contrib.barter
- evennia.contrib.building_menu
- evennia.contrib.chargen
- evennia.contrib.clothing
- evennia.contrib.color_markups
- evennia.contrib.custom_gametime
- evennia.contrib.dice
- evennia.contrib.email_login
- evennia.contrib.extended_room
- evennia.contrib.fieldfill
- evennia.contrib.gendersub
- evennia.contrib.health_bar
- evennia.contrib.mail
- evennia.contrib.mapbuilder
- evennia.contrib.menu_login
- evennia.contrib.multidescer
- evennia.contrib.mux_comms_cmds
- evennia.contrib.puzzles
- evennia.contrib.random_string_generator
- evennia.contrib.rplanguage
- evennia.contrib.rpsystem
- evennia.contrib.simpledoor
- evennia.contrib.slow_exit
- evennia.contrib.talking_npc
- evennia.contrib.test_traits
- evennia.contrib.traits
- evennia.contrib.tree_select
- evennia.contrib.unixcommand
- evennia.contrib.wilderness
+ evennia.contrib.base_systems
+ evennia.contrib.full_systems
+ evennia.contrib.game_systems
+ evennia.contrib.grid
+ evennia.contrib.rpg
+ evennia.contrib.tutorials
+ evennia.contrib.utils
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.awsstorage
- evennia.contrib.crafting
- evennia.contrib.evscaperoom
- evennia.contrib.ingame_python
- evennia.contrib.security
- evennia.contrib.turnbattle
- evennia.contrib.tutorial_examples
- evennia.contrib.tutorial_world
- evennia.contrib.grid.xyzgrid
-
-```
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.menu_login.md b/docs/source/api/evennia.contrib.menu_login.md
deleted file mode 100644
index 75f3ba790d..0000000000
--- a/docs/source/api/evennia.contrib.menu_login.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.menu\_login
-==================================
-
-.. automodule:: evennia.contrib.menu_login
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.multidescer.md b/docs/source/api/evennia.contrib.multidescer.md
deleted file mode 100644
index 34c7f089c6..0000000000
--- a/docs/source/api/evennia.contrib.multidescer.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.multidescer
-==================================
-
-.. automodule:: evennia.contrib.multidescer
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.puzzles.md b/docs/source/api/evennia.contrib.puzzles.md
deleted file mode 100644
index 09940d7206..0000000000
--- a/docs/source/api/evennia.contrib.puzzles.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.puzzles
-==============================
-
-.. automodule:: evennia.contrib.puzzles
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.random_string_generator.md b/docs/source/api/evennia.contrib.random_string_generator.md
deleted file mode 100644
index 1c943f6140..0000000000
--- a/docs/source/api/evennia.contrib.random_string_generator.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.random\_string\_generator
-================================================
-
-.. automodule:: evennia.contrib.random_string_generator
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.tests.md b/docs/source/api/evennia.contrib.rpg.dice.dice.md
similarity index 58%
rename from docs/source/api/evennia.contrib.xyzgrid.tests.md
rename to docs/source/api/evennia.contrib.rpg.dice.dice.md
index 382cc88e68..c632dc4f19 100644
--- a/docs/source/api/evennia.contrib.xyzgrid.tests.md
+++ b/docs/source/api/evennia.contrib.rpg.dice.dice.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.xyzgrid.tests
+evennia.contrib.rpg.dice.dice
====================================
-.. automodule:: evennia.contrib.xyzgrid.tests
+.. automodule:: evennia.contrib.rpg.dice.dice
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.security.md b/docs/source/api/evennia.contrib.rpg.dice.md
similarity index 50%
rename from docs/source/api/evennia.contrib.security.md
rename to docs/source/api/evennia.contrib.rpg.dice.md
index 157574ff02..ba7f7308c3 100644
--- a/docs/source/api/evennia.contrib.security.md
+++ b/docs/source/api/evennia.contrib.rpg.dice.md
@@ -1,16 +1,18 @@
```{eval-rst}
-evennia.contrib.security
+evennia.contrib.rpg.dice
================================
-.. automodule:: evennia.contrib.security
+.. automodule:: evennia.contrib.rpg.dice
:members:
:undoc-members:
:show-inheritance:
+
.. toctree::
:maxdepth: 6
- evennia.contrib.security.auditing
+ evennia.contrib.rpg.dice.dice
+ evennia.contrib.rpg.dice.tests
```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.color_markups.md b/docs/source/api/evennia.contrib.rpg.dice.tests.md
similarity index 58%
rename from docs/source/api/evennia.contrib.color_markups.md
rename to docs/source/api/evennia.contrib.rpg.dice.tests.md
index 6f1040358e..f6dbd1d877 100644
--- a/docs/source/api/evennia.contrib.color_markups.md
+++ b/docs/source/api/evennia.contrib.rpg.dice.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.color\_markups
+evennia.contrib.rpg.dice.tests
=====================================
-.. automodule:: evennia.contrib.color_markups
+.. automodule:: evennia.contrib.rpg.dice.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.tutorial_world.intro_menu.md b/docs/source/api/evennia.contrib.rpg.health_bar.health_bar.md
similarity index 54%
rename from docs/source/api/evennia.contrib.tutorial_world.intro_menu.md
rename to docs/source/api/evennia.contrib.rpg.health_bar.health_bar.md
index 7e844136b9..8213d81955 100644
--- a/docs/source/api/evennia.contrib.tutorial_world.intro_menu.md
+++ b/docs/source/api/evennia.contrib.rpg.health_bar.health_bar.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_world.intro\_menu
+evennia.contrib.rpg.health\_bar.health\_bar
==================================================
-.. automodule:: evennia.contrib.tutorial_world.intro_menu
+.. automodule:: evennia.contrib.rpg.health_bar.health_bar
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.rpg.health_bar.md b/docs/source/api/evennia.contrib.rpg.health_bar.md
new file mode 100644
index 0000000000..4e26bf9206
--- /dev/null
+++ b/docs/source/api/evennia.contrib.rpg.health_bar.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.rpg.health\_bar
+=======================================
+
+.. automodule:: evennia.contrib.rpg.health_bar
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.rpg.health_bar.health_bar
+ evennia.contrib.rpg.health_bar.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.xymap_legend.md b/docs/source/api/evennia.contrib.rpg.health_bar.tests.md
similarity index 56%
rename from docs/source/api/evennia.contrib.xyzgrid.xymap_legend.md
rename to docs/source/api/evennia.contrib.rpg.health_bar.tests.md
index 340647af94..8727383b32 100644
--- a/docs/source/api/evennia.contrib.xyzgrid.xymap_legend.md
+++ b/docs/source/api/evennia.contrib.rpg.health_bar.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.xyzgrid.xymap\_legend
+evennia.contrib.rpg.health\_bar.tests
============================================
-.. automodule:: evennia.contrib.xyzgrid.xymap_legend
+.. automodule:: evennia.contrib.rpg.health_bar.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.rpg.md b/docs/source/api/evennia.contrib.rpg.md
new file mode 100644
index 0000000000..ea6607f239
--- /dev/null
+++ b/docs/source/api/evennia.contrib.rpg.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.rpg
+===========================
+
+.. automodule:: evennia.contrib.rpg
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.rpg.dice
+ evennia.contrib.rpg.health_bar
+ evennia.contrib.rpg.rpsystem
+ evennia.contrib.rpg.traits
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.rpg.rpsystem.md b/docs/source/api/evennia.contrib.rpg.rpsystem.md
new file mode 100644
index 0000000000..2bbb132610
--- /dev/null
+++ b/docs/source/api/evennia.contrib.rpg.rpsystem.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.rpg.rpsystem
+====================================
+
+.. automodule:: evennia.contrib.rpg.rpsystem
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.rpg.rpsystem.rplanguage
+ evennia.contrib.rpg.rpsystem.rpsystem
+ evennia.contrib.rpg.rpsystem.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.security.auditing.tests.md b/docs/source/api/evennia.contrib.rpg.rpsystem.rplanguage.md
similarity index 55%
rename from docs/source/api/evennia.contrib.security.auditing.tests.md
rename to docs/source/api/evennia.contrib.rpg.rpsystem.rplanguage.md
index 97f359435e..ed8d67938d 100644
--- a/docs/source/api/evennia.contrib.security.auditing.tests.md
+++ b/docs/source/api/evennia.contrib.rpg.rpsystem.rplanguage.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.security.auditing.tests
+evennia.contrib.rpg.rpsystem.rplanguage
==============================================
-.. automodule:: evennia.contrib.security.auditing.tests
+.. automodule:: evennia.contrib.rpg.rpsystem.rplanguage
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.rpg.rpsystem.rpsystem.md b/docs/source/api/evennia.contrib.rpg.rpsystem.rpsystem.md
new file mode 100644
index 0000000000..0f7ed6fb65
--- /dev/null
+++ b/docs/source/api/evennia.contrib.rpg.rpsystem.rpsystem.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.rpg.rpsystem.rpsystem
+============================================
+
+.. automodule:: evennia.contrib.rpg.rpsystem.rpsystem
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.rpg.rpsystem.tests.md b/docs/source/api/evennia.contrib.rpg.rpsystem.tests.md
new file mode 100644
index 0000000000..8ec1576cd4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.rpg.rpsystem.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.rpg.rpsystem.tests
+=========================================
+
+.. automodule:: evennia.contrib.rpg.rpsystem.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.rpg.traits.md b/docs/source/api/evennia.contrib.rpg.traits.md
new file mode 100644
index 0000000000..82b2c3abc8
--- /dev/null
+++ b/docs/source/api/evennia.contrib.rpg.traits.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.rpg.traits
+==================================
+
+.. automodule:: evennia.contrib.rpg.traits
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.rpg.traits.tests
+ evennia.contrib.rpg.traits.traits
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.custom_gametime.md b/docs/source/api/evennia.contrib.rpg.traits.tests.md
similarity index 57%
rename from docs/source/api/evennia.contrib.custom_gametime.md
rename to docs/source/api/evennia.contrib.rpg.traits.tests.md
index b0292d6405..c96dad0e56 100644
--- a/docs/source/api/evennia.contrib.custom_gametime.md
+++ b/docs/source/api/evennia.contrib.rpg.traits.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.custom\_gametime
+evennia.contrib.rpg.traits.tests
=======================================
-.. automodule:: evennia.contrib.custom_gametime
+.. automodule:: evennia.contrib.rpg.traits.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.crafting.crafting.md b/docs/source/api/evennia.contrib.rpg.traits.traits.md
similarity index 57%
rename from docs/source/api/evennia.contrib.crafting.crafting.md
rename to docs/source/api/evennia.contrib.rpg.traits.traits.md
index 48924ab015..afcaaf55de 100644
--- a/docs/source/api/evennia.contrib.crafting.crafting.md
+++ b/docs/source/api/evennia.contrib.rpg.traits.traits.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.crafting.crafting
+evennia.contrib.rpg.traits.traits
========================================
-.. automodule:: evennia.contrib.crafting.crafting
+.. automodule:: evennia.contrib.rpg.traits.traits
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.rplanguage.md b/docs/source/api/evennia.contrib.rplanguage.md
deleted file mode 100644
index dcce2f960a..0000000000
--- a/docs/source/api/evennia.contrib.rplanguage.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.rplanguage
-=================================
-
-.. automodule:: evennia.contrib.rplanguage
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.rpsystem.md b/docs/source/api/evennia.contrib.rpsystem.md
deleted file mode 100644
index f968540d66..0000000000
--- a/docs/source/api/evennia.contrib.rpsystem.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.rpsystem
-===============================
-
-.. automodule:: evennia.contrib.rpsystem
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.security.auditing.md b/docs/source/api/evennia.contrib.security.auditing.md
deleted file mode 100644
index 93f07ffb58..0000000000
--- a/docs/source/api/evennia.contrib.security.auditing.md
+++ /dev/null
@@ -1,19 +0,0 @@
-```{eval-rst}
-evennia.contrib.security.auditing
-=========================================
-
-.. automodule:: evennia.contrib.security.auditing
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.security.auditing.outputs
- evennia.contrib.security.auditing.server
- evennia.contrib.security.auditing.tests
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.security.auditing.outputs.md b/docs/source/api/evennia.contrib.security.auditing.outputs.md
deleted file mode 100644
index 9841ec0d70..0000000000
--- a/docs/source/api/evennia.contrib.security.auditing.outputs.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.security.auditing.outputs
-================================================
-
-.. automodule:: evennia.contrib.security.auditing.outputs
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.simpledoor.md b/docs/source/api/evennia.contrib.simpledoor.md
deleted file mode 100644
index 9546d763ff..0000000000
--- a/docs/source/api/evennia.contrib.simpledoor.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.simpledoor
-=================================
-
-.. automodule:: evennia.contrib.simpledoor
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.slow_exit.md b/docs/source/api/evennia.contrib.slow_exit.md
deleted file mode 100644
index e201bc5ce0..0000000000
--- a/docs/source/api/evennia.contrib.slow_exit.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.slow\_exit
-=================================
-
-.. automodule:: evennia.contrib.slow_exit
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.talking_npc.md b/docs/source/api/evennia.contrib.talking_npc.md
deleted file mode 100644
index 822a12f136..0000000000
--- a/docs/source/api/evennia.contrib.talking_npc.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.talking\_npc
-===================================
-
-.. automodule:: evennia.contrib.talking_npc
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.test_traits.md b/docs/source/api/evennia.contrib.test_traits.md
deleted file mode 100644
index 4c807c6eac..0000000000
--- a/docs/source/api/evennia.contrib.test_traits.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.test\_traits
-===================================
-
-.. automodule:: evennia.contrib.test_traits
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.traits.md b/docs/source/api/evennia.contrib.traits.md
deleted file mode 100644
index e9db4e5aa3..0000000000
--- a/docs/source/api/evennia.contrib.traits.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.traits
-=============================
-
-.. automodule:: evennia.contrib.traits
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tree_select.md b/docs/source/api/evennia.contrib.tree_select.md
deleted file mode 100644
index 65322c3bc7..0000000000
--- a/docs/source/api/evennia.contrib.tree_select.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.tree\_select
-===================================
-
-.. automodule:: evennia.contrib.tree_select
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.turnbattle.md b/docs/source/api/evennia.contrib.turnbattle.md
deleted file mode 100644
index 267e02d20c..0000000000
--- a/docs/source/api/evennia.contrib.turnbattle.md
+++ /dev/null
@@ -1,21 +0,0 @@
-```{eval-rst}
-evennia.contrib.turnbattle
-==================================
-
-.. automodule:: evennia.contrib.turnbattle
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.turnbattle.tb_basic
- evennia.contrib.turnbattle.tb_equip
- evennia.contrib.turnbattle.tb_items
- evennia.contrib.turnbattle.tb_magic
- evennia.contrib.turnbattle.tb_range
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.turnbattle.tb_equip.md b/docs/source/api/evennia.contrib.turnbattle.tb_equip.md
deleted file mode 100644
index 14fc4b0a7c..0000000000
--- a/docs/source/api/evennia.contrib.turnbattle.tb_equip.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.turnbattle.tb\_equip
-===========================================
-
-.. automodule:: evennia.contrib.turnbattle.tb_equip
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.turnbattle.tb_items.md b/docs/source/api/evennia.contrib.turnbattle.tb_items.md
deleted file mode 100644
index cec6a5562e..0000000000
--- a/docs/source/api/evennia.contrib.turnbattle.tb_items.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.turnbattle.tb\_items
-===========================================
-
-.. automodule:: evennia.contrib.turnbattle.tb_items
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.turnbattle.tb_magic.md b/docs/source/api/evennia.contrib.turnbattle.tb_magic.md
deleted file mode 100644
index 402f06e966..0000000000
--- a/docs/source/api/evennia.contrib.turnbattle.tb_magic.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.turnbattle.tb\_magic
-===========================================
-
-.. automodule:: evennia.contrib.turnbattle.tb_magic
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.turnbattle.tb_range.md b/docs/source/api/evennia.contrib.turnbattle.tb_range.md
deleted file mode 100644
index 1643487f16..0000000000
--- a/docs/source/api/evennia.contrib.turnbattle.tb_range.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.turnbattle.tb\_range
-===========================================
-
-.. automodule:: evennia.contrib.turnbattle.tb_range
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_examples.md b/docs/source/api/evennia.contrib.tutorial_examples.md
deleted file mode 100644
index 182e3968d7..0000000000
--- a/docs/source/api/evennia.contrib.tutorial_examples.md
+++ /dev/null
@@ -1,21 +0,0 @@
-```{eval-rst}
-evennia.contrib.tutorial\_examples
-==========================================
-
-.. automodule:: evennia.contrib.tutorial_examples
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.tutorial_examples.bodyfunctions
- evennia.contrib.tutorial_examples.example_batch_code
- evennia.contrib.tutorial_examples.mirror
- evennia.contrib.tutorial_examples.red_button
- evennia.contrib.tutorial_examples.tests
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_examples.mirror.md b/docs/source/api/evennia.contrib.tutorial_examples.mirror.md
deleted file mode 100644
index c086b8f2d9..0000000000
--- a/docs/source/api/evennia.contrib.tutorial_examples.mirror.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.tutorial\_examples.mirror
-================================================
-
-.. automodule:: evennia.contrib.tutorial_examples.mirror
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_world.md b/docs/source/api/evennia.contrib.tutorial_world.md
deleted file mode 100644
index 50c4b54d16..0000000000
--- a/docs/source/api/evennia.contrib.tutorial_world.md
+++ /dev/null
@@ -1,20 +0,0 @@
-```{eval-rst}
-evennia.contrib.tutorial\_world
-=======================================
-
-.. automodule:: evennia.contrib.tutorial_world
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.tutorial_world.intro_menu
- evennia.contrib.tutorial_world.mob
- evennia.contrib.tutorial_world.objects
- evennia.contrib.tutorial_world.rooms
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_world.mob.md b/docs/source/api/evennia.contrib.tutorial_world.mob.md
deleted file mode 100644
index 1780dc3f8b..0000000000
--- a/docs/source/api/evennia.contrib.tutorial_world.mob.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.tutorial\_world.mob
-==========================================
-
-.. automodule:: evennia.contrib.tutorial_world.mob
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.md b/docs/source/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.md
new file mode 100644
index 0000000000..de1e3dfcf7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.batchprocessor.example\_batch\_code
+====================================================================
+
+.. automodule:: evennia.contrib.tutorials.batchprocessor.example_batch_code
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.batchprocessor.md b/docs/source/api/evennia.contrib.tutorials.batchprocessor.md
new file mode 100644
index 0000000000..d39d021988
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.batchprocessor.md
@@ -0,0 +1,17 @@
+```{eval-rst}
+evennia.contrib.tutorials.batchprocessor
+================================================
+
+.. automodule:: evennia.contrib.tutorials.batchprocessor
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.batchprocessor.example_batch_code
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.md b/docs/source/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.md
new file mode 100644
index 0000000000..d010a76e96
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.bodyfunctions.bodyfunctions
+============================================================
+
+.. automodule:: evennia.contrib.tutorials.bodyfunctions.bodyfunctions
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.bodyfunctions.md b/docs/source/api/evennia.contrib.tutorials.bodyfunctions.md
new file mode 100644
index 0000000000..7fa7d564de
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.bodyfunctions.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.tutorials.bodyfunctions
+===============================================
+
+.. automodule:: evennia.contrib.tutorials.bodyfunctions
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.bodyfunctions.bodyfunctions
+ evennia.contrib.tutorials.bodyfunctions.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.bodyfunctions.tests.md b/docs/source/api/evennia.contrib.tutorials.bodyfunctions.tests.md
new file mode 100644
index 0000000000..b389eb324f
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.bodyfunctions.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.bodyfunctions.tests
+====================================================
+
+.. automodule:: evennia.contrib.tutorials.bodyfunctions.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.md b/docs/source/api/evennia.contrib.tutorials.md
new file mode 100644
index 0000000000..3dad058938
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.md
@@ -0,0 +1,21 @@
+```{eval-rst}
+evennia.contrib.tutorials
+=================================
+
+.. automodule:: evennia.contrib.tutorials
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.batchprocessor
+ evennia.contrib.tutorials.bodyfunctions
+ evennia.contrib.tutorials.mirror
+ evennia.contrib.tutorials.red_button
+ evennia.contrib.tutorials.talking_npc
+ evennia.contrib.tutorials.tutorial_world
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.mirror.md b/docs/source/api/evennia.contrib.tutorials.mirror.md
new file mode 100644
index 0000000000..b56fe8f7f4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.mirror.md
@@ -0,0 +1,17 @@
+```{eval-rst}
+evennia.contrib.tutorials.mirror
+========================================
+
+.. automodule:: evennia.contrib.tutorials.mirror
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.mirror.mirror
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorial_world.objects.md b/docs/source/api/evennia.contrib.tutorials.mirror.mirror.md
similarity index 55%
rename from docs/source/api/evennia.contrib.tutorial_world.objects.md
rename to docs/source/api/evennia.contrib.tutorials.mirror.mirror.md
index 7565805f52..b206377144 100644
--- a/docs/source/api/evennia.contrib.tutorial_world.objects.md
+++ b/docs/source/api/evennia.contrib.tutorials.mirror.mirror.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.tutorial\_world.objects
+evennia.contrib.tutorials.mirror.mirror
==============================================
-.. automodule:: evennia.contrib.tutorial_world.objects
+.. automodule:: evennia.contrib.tutorials.mirror.mirror
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.tutorials.red_button.md b/docs/source/api/evennia.contrib.tutorials.red_button.md
new file mode 100644
index 0000000000..582318b92d
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.red_button.md
@@ -0,0 +1,17 @@
+```{eval-rst}
+evennia.contrib.tutorials.red\_button
+=============================================
+
+.. automodule:: evennia.contrib.tutorials.red_button
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.red_button.red_button
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.red_button.red_button.md b/docs/source/api/evennia.contrib.tutorials.red_button.red_button.md
new file mode 100644
index 0000000000..6b968bcf3e
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.red_button.red_button.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.red\_button.red\_button
+========================================================
+
+.. automodule:: evennia.contrib.tutorials.red_button.red_button
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.talking_npc.md b/docs/source/api/evennia.contrib.tutorials.talking_npc.md
new file mode 100644
index 0000000000..899e4b0519
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.talking_npc.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.tutorials.talking\_npc
+==============================================
+
+.. automodule:: evennia.contrib.tutorials.talking_npc
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.talking_npc.talking_npc
+ evennia.contrib.tutorials.talking_npc.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.talking_npc.talking_npc.md b/docs/source/api/evennia.contrib.tutorials.talking_npc.talking_npc.md
new file mode 100644
index 0000000000..5069419161
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.talking_npc.talking_npc.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.talking\_npc.talking\_npc
+==========================================================
+
+.. automodule:: evennia.contrib.tutorials.talking_npc.talking_npc
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.talking_npc.tests.md b/docs/source/api/evennia.contrib.tutorials.talking_npc.tests.md
new file mode 100644
index 0000000000..72661eb879
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.talking_npc.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.talking\_npc.tests
+===================================================
+
+.. automodule:: evennia.contrib.tutorials.talking_npc.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.tutorial_world.intro_menu.md b/docs/source/api/evennia.contrib.tutorials.tutorial_world.intro_menu.md
new file mode 100644
index 0000000000..dfcc268d97
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.tutorial_world.intro_menu.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.tutorial\_world.intro\_menu
+============================================================
+
+.. automodule:: evennia.contrib.tutorials.tutorial_world.intro_menu
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.tutorial_world.md b/docs/source/api/evennia.contrib.tutorials.tutorial_world.md
new file mode 100644
index 0000000000..cd9b7a47d3
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.tutorial_world.md
@@ -0,0 +1,21 @@
+```{eval-rst}
+evennia.contrib.tutorials.tutorial\_world
+=================================================
+
+.. automodule:: evennia.contrib.tutorials.tutorial_world
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.tutorials.tutorial_world.intro_menu
+ evennia.contrib.tutorials.tutorial_world.mob
+ evennia.contrib.tutorials.tutorial_world.objects
+ evennia.contrib.tutorials.tutorial_world.rooms
+ evennia.contrib.tutorials.tutorial_world.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.tutorial_world.mob.md b/docs/source/api/evennia.contrib.tutorials.tutorial_world.mob.md
new file mode 100644
index 0000000000..42325eea24
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.tutorial_world.mob.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.tutorial\_world.mob
+====================================================
+
+.. automodule:: evennia.contrib.tutorials.tutorial_world.mob
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.tutorial_world.objects.md b/docs/source/api/evennia.contrib.tutorials.tutorial_world.objects.md
new file mode 100644
index 0000000000..b70af1db31
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.tutorial_world.objects.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.tutorial\_world.objects
+========================================================
+
+.. automodule:: evennia.contrib.tutorials.tutorial_world.objects
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.tutorial_world.rooms.md b/docs/source/api/evennia.contrib.tutorials.tutorial_world.rooms.md
new file mode 100644
index 0000000000..94219a1e7e
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.tutorial_world.rooms.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.tutorial\_world.rooms
+======================================================
+
+.. automodule:: evennia.contrib.tutorials.tutorial_world.rooms
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.tutorials.tutorial_world.tests.md b/docs/source/api/evennia.contrib.tutorials.tutorial_world.tests.md
new file mode 100644
index 0000000000..56ca945f80
--- /dev/null
+++ b/docs/source/api/evennia.contrib.tutorials.tutorial_world.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.tutorials.tutorial\_world.tests
+======================================================
+
+.. automodule:: evennia.contrib.tutorials.tutorial_world.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.unixcommand.md b/docs/source/api/evennia.contrib.unixcommand.md
deleted file mode 100644
index 7cd2bdab3a..0000000000
--- a/docs/source/api/evennia.contrib.unixcommand.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.unixcommand
-==================================
-
-.. automodule:: evennia.contrib.unixcommand
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.auditing.md b/docs/source/api/evennia.contrib.utils.auditing.md
new file mode 100644
index 0000000000..014ec1b155
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.auditing.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.utils.auditing
+======================================
+
+.. automodule:: evennia.contrib.utils.auditing
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.utils.auditing.outputs
+ evennia.contrib.utils.auditing.server
+ evennia.contrib.utils.auditing.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.auditing.outputs.md b/docs/source/api/evennia.contrib.utils.auditing.outputs.md
new file mode 100644
index 0000000000..8c03ec0dd4
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.auditing.outputs.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.utils.auditing.outputs
+=============================================
+
+.. automodule:: evennia.contrib.utils.auditing.outputs
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.auditing.server.md b/docs/source/api/evennia.contrib.utils.auditing.server.md
new file mode 100644
index 0000000000..8fea2f2386
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.auditing.server.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.utils.auditing.server
+============================================
+
+.. automodule:: evennia.contrib.utils.auditing.server
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.turnbattle.tb_basic.md b/docs/source/api/evennia.contrib.utils.auditing.tests.md
similarity index 56%
rename from docs/source/api/evennia.contrib.turnbattle.tb_basic.md
rename to docs/source/api/evennia.contrib.utils.auditing.tests.md
index b65fe3ceb5..b6ace0b9c6 100644
--- a/docs/source/api/evennia.contrib.turnbattle.tb_basic.md
+++ b/docs/source/api/evennia.contrib.utils.auditing.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.turnbattle.tb\_basic
+evennia.contrib.utils.auditing.tests
===========================================
-.. automodule:: evennia.contrib.turnbattle.tb_basic
+.. automodule:: evennia.contrib.utils.auditing.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.ingame_python.eventfuncs.md b/docs/source/api/evennia.contrib.utils.fieldfill.fieldfill.md
similarity index 54%
rename from docs/source/api/evennia.contrib.ingame_python.eventfuncs.md
rename to docs/source/api/evennia.contrib.utils.fieldfill.fieldfill.md
index b2dc7c0b57..903a37e81d 100644
--- a/docs/source/api/evennia.contrib.ingame_python.eventfuncs.md
+++ b/docs/source/api/evennia.contrib.utils.fieldfill.fieldfill.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.ingame\_python.eventfuncs
+evennia.contrib.utils.fieldfill.fieldfill
================================================
-.. automodule:: evennia.contrib.ingame_python.eventfuncs
+.. automodule:: evennia.contrib.utils.fieldfill.fieldfill
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.utils.fieldfill.md b/docs/source/api/evennia.contrib.utils.fieldfill.md
new file mode 100644
index 0000000000..37e6768e77
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.fieldfill.md
@@ -0,0 +1,17 @@
+```{eval-rst}
+evennia.contrib.utils.fieldfill
+=======================================
+
+.. automodule:: evennia.contrib.utils.fieldfill
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.utils.fieldfill.fieldfill
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.md b/docs/source/api/evennia.contrib.utils.md
new file mode 100644
index 0000000000..2c2a5ba509
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.md
@@ -0,0 +1,19 @@
+```{eval-rst}
+evennia.contrib.utils
+=============================
+
+.. automodule:: evennia.contrib.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.utils.auditing
+ evennia.contrib.utils.fieldfill
+ evennia.contrib.utils.random_string_generator
+ evennia.contrib.utils.tree_select
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.random_string_generator.md b/docs/source/api/evennia.contrib.utils.random_string_generator.md
new file mode 100644
index 0000000000..6fff95d6b7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.random_string_generator.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.utils.random\_string\_generator
+=======================================================
+
+.. automodule:: evennia.contrib.utils.random_string_generator
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.utils.random_string_generator.random_string_generator
+ evennia.contrib.utils.random_string_generator.tests
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.random_string_generator.random_string_generator.md b/docs/source/api/evennia.contrib.utils.random_string_generator.random_string_generator.md
new file mode 100644
index 0000000000..7ee5fcb03f
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.random_string_generator.random_string_generator.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.utils.random\_string\_generator.random\_string\_generator
+================================================================================
+
+.. automodule:: evennia.contrib.utils.random_string_generator.random_string_generator
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.random_string_generator.tests.md b/docs/source/api/evennia.contrib.utils.random_string_generator.tests.md
new file mode 100644
index 0000000000..cfb4329483
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.random_string_generator.tests.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.utils.random\_string\_generator.tests
+============================================================
+
+.. automodule:: evennia.contrib.utils.random_string_generator.tests
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.utils.tree_select.md b/docs/source/api/evennia.contrib.utils.tree_select.md
new file mode 100644
index 0000000000..5a7b6fd1ea
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.tree_select.md
@@ -0,0 +1,18 @@
+```{eval-rst}
+evennia.contrib.utils.tree\_select
+==========================================
+
+.. automodule:: evennia.contrib.utils.tree_select
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+
+
+.. toctree::
+ :maxdepth: 6
+
+ evennia.contrib.utils.tree_select.tests
+ evennia.contrib.utils.tree_select.tree_select
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.security.auditing.server.md b/docs/source/api/evennia.contrib.utils.tree_select.tests.md
similarity index 55%
rename from docs/source/api/evennia.contrib.security.auditing.server.md
rename to docs/source/api/evennia.contrib.utils.tree_select.tests.md
index 8d03d16ab2..2e556c716a 100644
--- a/docs/source/api/evennia.contrib.security.auditing.server.md
+++ b/docs/source/api/evennia.contrib.utils.tree_select.tests.md
@@ -1,8 +1,8 @@
```{eval-rst}
-evennia.contrib.security.auditing.server
+evennia.contrib.utils.tree\_select.tests
===============================================
-.. automodule:: evennia.contrib.security.auditing.server
+.. automodule:: evennia.contrib.utils.tree_select.tests
:members:
:undoc-members:
:show-inheritance:
diff --git a/docs/source/api/evennia.contrib.utils.tree_select.tree_select.md b/docs/source/api/evennia.contrib.utils.tree_select.tree_select.md
new file mode 100644
index 0000000000..f1d0f1c0c7
--- /dev/null
+++ b/docs/source/api/evennia.contrib.utils.tree_select.tree_select.md
@@ -0,0 +1,10 @@
+```{eval-rst}
+evennia.contrib.utils.tree\_select.tree\_select
+======================================================
+
+.. automodule:: evennia.contrib.utils.tree_select.tree_select
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.wilderness.md b/docs/source/api/evennia.contrib.wilderness.md
deleted file mode 100644
index 86f91a7e09..0000000000
--- a/docs/source/api/evennia.contrib.wilderness.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.wilderness
-=================================
-
-.. automodule:: evennia.contrib.wilderness
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.commands.md b/docs/source/api/evennia.contrib.xyzgrid.commands.md
deleted file mode 100644
index 92a9c607ae..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.commands.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.grid.xyzgrid.commands
-=======================================
-
-.. automodule:: evennia.contrib.xyzgrid.commands
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
diff --git a/docs/source/api/evennia.contrib.xyzgrid.example.md b/docs/source/api/evennia.contrib.xyzgrid.example.md
deleted file mode 100644
index d8dde90b40..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.example.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid.example
-======================================
-
-.. automodule:: evennia.contrib.xyzgrid.example
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.launchcmd.md b/docs/source/api/evennia.contrib.xyzgrid.launchcmd.md
deleted file mode 100644
index 720a27963e..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.launchcmd.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid.launchcmd
-========================================
-
-.. automodule:: evennia.contrib.xyzgrid.launchcmd
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.md b/docs/source/api/evennia.contrib.xyzgrid.md
deleted file mode 100644
index 91993133e9..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.md
+++ /dev/null
@@ -1,26 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid
-===============================
-
-.. automodule:: evennia.contrib.xyzgrid
- :members:
- :undoc-members:
- :show-inheritance:
-
-
-
-.. toctree::
- :maxdepth: 6
-
- evennia.contrib.xyzgrid.commands
- evennia.contrib.xyzgrid.example
- evennia.contrib.xyzgrid.launchcmd
- evennia.contrib.xyzgrid.prototypes
- evennia.contrib.xyzgrid.tests
- evennia.contrib.xyzgrid.utils
- evennia.contrib.xyzgrid.xymap
- evennia.contrib.xyzgrid.xymap_legend
- evennia.contrib.xyzgrid.xyzgrid
- evennia.contrib.xyzgrid.xyzroom
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.utils.md b/docs/source/api/evennia.contrib.xyzgrid.utils.md
deleted file mode 100644
index cacbf0b2ea..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.utils.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid.utils
-====================================
-
-.. automodule:: evennia.contrib.xyzgrid.utils
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.xymap.md b/docs/source/api/evennia.contrib.xyzgrid.xymap.md
deleted file mode 100644
index 54f2d922bc..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.xymap.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid.xymap
-====================================
-
-.. automodule:: evennia.contrib.xyzgrid.xymap
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.xyzgrid.md b/docs/source/api/evennia.contrib.xyzgrid.xyzgrid.md
deleted file mode 100644
index caed6f4b32..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.xyzgrid.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid.xyzgrid
-======================================
-
-.. automodule:: evennia.contrib.xyzgrid.xyzgrid
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/api/evennia.contrib.xyzgrid.xyzroom.md b/docs/source/api/evennia.contrib.xyzgrid.xyzroom.md
deleted file mode 100644
index 228882ca01..0000000000
--- a/docs/source/api/evennia.contrib.xyzgrid.xyzroom.md
+++ /dev/null
@@ -1,10 +0,0 @@
-```{eval-rst}
-evennia.contrib.xyzgrid.xyzroom
-======================================
-
-.. automodule:: evennia.contrib.xyzgrid.xyzroom
- :members:
- :undoc-members:
- :show-inheritance:
-
-```
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
index aa256861df..2c4c846a39 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -345,12 +345,12 @@ def setup(app):
# build toctree file
sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
- from docs.pylib import auto_link_remapper, update_default_cmd_index
+ from docs.pylib import auto_link_remapper, update_default_cmd_index, contrib_readmes2docs
_no_autodoc = os.environ.get("NOAUTODOC")
update_default_cmd_index.run_update(no_autodoc=_no_autodoc)
+ contrib_readmes2docs.readmes2docs()
auto_link_remapper.auto_link_remapper(no_autodoc=_no_autodoc)
- print("Updated source/toc.md file")
# custom lunr-based search
# from docs import search
diff --git a/docs/source/toc.md b/docs/source/toc.md
index 2dc81b8ec6..43cd46d9ab 100644
--- a/docs/source/toc.md
+++ b/docs/source/toc.md
@@ -78,7 +78,46 @@ Concepts/Zones
Contribs/A-voice-operated-elevator-using-events
Contribs/Arxcode-installing-help
Contribs/Building-menus
+Contribs/Contrib-AWSStorage
+Contribs/Contrib-Auditing
+Contribs/Contrib-Barter
+Contribs/Contrib-Batchprocessor
+Contribs/Contrib-Bodyfunctions
+Contribs/Contrib-Building-Menu
+Contribs/Contrib-Clothing
+Contribs/Contrib-Color-Markups
+Contribs/Contrib-Cooldowns
+Contribs/Contrib-Crafting
+Contribs/Contrib-Custom-Gametime
+Contribs/Contrib-Dice
+Contribs/Contrib-Email-Login
+Contribs/Contrib-Evscaperoom
+Contribs/Contrib-Extended-Room
+Contribs/Contrib-Fieldfill
+Contribs/Contrib-Gendersub
+Contribs/Contrib-Health-Bar
+Contribs/Contrib-Ingame-Python
+Contribs/Contrib-Mail
+Contribs/Contrib-Mapbuilder
+Contribs/Contrib-Menu-Login
+Contribs/Contrib-Mirror
+Contribs/Contrib-Multidescer
+Contribs/Contrib-Mux-Comms-Cmds
Contribs/Contrib-Overview
+Contribs/Contrib-Puzzles
+Contribs/Contrib-RPSystem
+Contribs/Contrib-Random-String-Generator
+Contribs/Contrib-Red-Button
+Contribs/Contrib-Simpledoor
+Contribs/Contrib-Slow-Exit
+Contribs/Contrib-Talking-Npc
+Contribs/Contrib-Traits
+Contribs/Contrib-Tree-Select
+Contribs/Contrib-Turnbattle
+Contribs/Contrib-Tutorial-World
+Contribs/Contrib-Unixcommand
+Contribs/Contrib-Wilderness
+Contribs/Contrib-XYZGrid
Contribs/Crafting
Contribs/Dialogues-in-events
Contribs/Dynamic-In-Game-Map
@@ -200,91 +239,157 @@ api/evennia.comms.comms
api/evennia.comms.managers
api/evennia.comms.models
api/evennia.contrib
-api/evennia.contrib.awsstorage
-api/evennia.contrib.awsstorage.aws_s3_cdn
-api/evennia.contrib.awsstorage.tests
-api/evennia.contrib.barter
-api/evennia.contrib.building_menu
-api/evennia.contrib.chargen
-api/evennia.contrib.clothing
-api/evennia.contrib.color_markups
-api/evennia.contrib.crafting
-api/evennia.contrib.crafting.crafting
-api/evennia.contrib.crafting.example_recipes
-api/evennia.contrib.crafting.tests
-api/evennia.contrib.custom_gametime
-api/evennia.contrib.dice
-api/evennia.contrib.email_login
-api/evennia.contrib.evscaperoom
-api/evennia.contrib.evscaperoom.commands
-api/evennia.contrib.evscaperoom.menu
-api/evennia.contrib.evscaperoom.objects
-api/evennia.contrib.evscaperoom.room
-api/evennia.contrib.evscaperoom.scripts
-api/evennia.contrib.evscaperoom.state
-api/evennia.contrib.evscaperoom.tests
-api/evennia.contrib.evscaperoom.utils
-api/evennia.contrib.extended_room
-api/evennia.contrib.fieldfill
-api/evennia.contrib.gendersub
-api/evennia.contrib.health_bar
-api/evennia.contrib.ingame_python
-api/evennia.contrib.ingame_python.callbackhandler
-api/evennia.contrib.ingame_python.commands
-api/evennia.contrib.ingame_python.eventfuncs
-api/evennia.contrib.ingame_python.scripts
-api/evennia.contrib.ingame_python.tests
-api/evennia.contrib.ingame_python.typeclasses
-api/evennia.contrib.ingame_python.utils
-api/evennia.contrib.mail
-api/evennia.contrib.mapbuilder
-api/evennia.contrib.menu_login
-api/evennia.contrib.multidescer
-api/evennia.contrib.puzzles
-api/evennia.contrib.random_string_generator
-api/evennia.contrib.rplanguage
-api/evennia.contrib.rpsystem
-api/evennia.contrib.security
-api/evennia.contrib.security.auditing
-api/evennia.contrib.security.auditing.outputs
-api/evennia.contrib.security.auditing.server
-api/evennia.contrib.security.auditing.tests
-api/evennia.contrib.simpledoor
-api/evennia.contrib.slow_exit
-api/evennia.contrib.talking_npc
-api/evennia.contrib.test_traits
-api/evennia.contrib.traits
-api/evennia.contrib.tree_select
-api/evennia.contrib.turnbattle
-api/evennia.contrib.turnbattle.tb_basic
-api/evennia.contrib.turnbattle.tb_equip
-api/evennia.contrib.turnbattle.tb_items
-api/evennia.contrib.turnbattle.tb_magic
-api/evennia.contrib.turnbattle.tb_range
-api/evennia.contrib.tutorial_examples
-api/evennia.contrib.tutorial_examples.bodyfunctions
-api/evennia.contrib.tutorial_examples.example_batch_code
-api/evennia.contrib.tutorial_examples.mirror
-api/evennia.contrib.tutorial_examples.red_button
-api/evennia.contrib.tutorial_examples.tests
-api/evennia.contrib.tutorial_world
-api/evennia.contrib.tutorial_world.intro_menu
-api/evennia.contrib.tutorial_world.mob
-api/evennia.contrib.tutorial_world.objects
-api/evennia.contrib.tutorial_world.rooms
-api/evennia.contrib.unixcommand
-api/evennia.contrib.wilderness
-api/evennia.contrib.xyzgrid
-api/evennia.contrib.xyzgrid.commands
-api/evennia.contrib.xyzgrid.example
-api/evennia.contrib.xyzgrid.launchcmd
-api/evennia.contrib.xyzgrid.prototypes
-api/evennia.contrib.xyzgrid.tests
-api/evennia.contrib.xyzgrid.utils
-api/evennia.contrib.xyzgrid.xymap
-api/evennia.contrib.xyzgrid.xymap_legend
-api/evennia.contrib.xyzgrid.xyzgrid
-api/evennia.contrib.xyzgrid.xyzroom
+api/evennia.contrib.base_systems
+api/evennia.contrib.base_systems.awsstorage
+api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn
+api/evennia.contrib.base_systems.awsstorage.tests
+api/evennia.contrib.base_systems.building_menu
+api/evennia.contrib.base_systems.building_menu.building_menu
+api/evennia.contrib.base_systems.building_menu.tests
+api/evennia.contrib.base_systems.color_markups
+api/evennia.contrib.base_systems.color_markups.color_markups
+api/evennia.contrib.base_systems.color_markups.tests
+api/evennia.contrib.base_systems.custom_gametime
+api/evennia.contrib.base_systems.custom_gametime.custom_gametime
+api/evennia.contrib.base_systems.custom_gametime.tests
+api/evennia.contrib.base_systems.email_login
+api/evennia.contrib.base_systems.email_login.connection_screens
+api/evennia.contrib.base_systems.email_login.email_login
+api/evennia.contrib.base_systems.email_login.tests
+api/evennia.contrib.base_systems.ingame_python
+api/evennia.contrib.base_systems.ingame_python.callbackhandler
+api/evennia.contrib.base_systems.ingame_python.commands
+api/evennia.contrib.base_systems.ingame_python.eventfuncs
+api/evennia.contrib.base_systems.ingame_python.scripts
+api/evennia.contrib.base_systems.ingame_python.tests
+api/evennia.contrib.base_systems.ingame_python.typeclasses
+api/evennia.contrib.base_systems.ingame_python.utils
+api/evennia.contrib.base_systems.menu_login
+api/evennia.contrib.base_systems.menu_login.connection_screens
+api/evennia.contrib.base_systems.menu_login.menu_login
+api/evennia.contrib.base_systems.menu_login.tests
+api/evennia.contrib.base_systems.mux_comms_cmds
+api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds
+api/evennia.contrib.base_systems.mux_comms_cmds.tests
+api/evennia.contrib.base_systems.unixcommand
+api/evennia.contrib.base_systems.unixcommand.tests
+api/evennia.contrib.base_systems.unixcommand.unixcommand
+api/evennia.contrib.full_systems
+api/evennia.contrib.full_systems.evscaperoom
+api/evennia.contrib.full_systems.evscaperoom.commands
+api/evennia.contrib.full_systems.evscaperoom.menu
+api/evennia.contrib.full_systems.evscaperoom.objects
+api/evennia.contrib.full_systems.evscaperoom.room
+api/evennia.contrib.full_systems.evscaperoom.scripts
+api/evennia.contrib.full_systems.evscaperoom.state
+api/evennia.contrib.full_systems.evscaperoom.tests
+api/evennia.contrib.full_systems.evscaperoom.utils
+api/evennia.contrib.game_systems
+api/evennia.contrib.game_systems.barter
+api/evennia.contrib.game_systems.barter.barter
+api/evennia.contrib.game_systems.barter.tests
+api/evennia.contrib.game_systems.clothing
+api/evennia.contrib.game_systems.clothing.clothing
+api/evennia.contrib.game_systems.clothing.tests
+api/evennia.contrib.game_systems.cooldowns
+api/evennia.contrib.game_systems.cooldowns.cooldowns
+api/evennia.contrib.game_systems.cooldowns.tests
+api/evennia.contrib.game_systems.crafting
+api/evennia.contrib.game_systems.crafting.crafting
+api/evennia.contrib.game_systems.crafting.example_recipes
+api/evennia.contrib.game_systems.crafting.tests
+api/evennia.contrib.game_systems.gendersub
+api/evennia.contrib.game_systems.gendersub.gendersub
+api/evennia.contrib.game_systems.gendersub.tests
+api/evennia.contrib.game_systems.mail
+api/evennia.contrib.game_systems.mail.mail
+api/evennia.contrib.game_systems.mail.tests
+api/evennia.contrib.game_systems.multidescer
+api/evennia.contrib.game_systems.multidescer.multidescer
+api/evennia.contrib.game_systems.multidescer.tests
+api/evennia.contrib.game_systems.puzzles
+api/evennia.contrib.game_systems.puzzles.puzzles
+api/evennia.contrib.game_systems.puzzles.tests
+api/evennia.contrib.game_systems.turnbattle
+api/evennia.contrib.game_systems.turnbattle.tb_basic
+api/evennia.contrib.game_systems.turnbattle.tb_equip
+api/evennia.contrib.game_systems.turnbattle.tb_items
+api/evennia.contrib.game_systems.turnbattle.tb_magic
+api/evennia.contrib.game_systems.turnbattle.tb_range
+api/evennia.contrib.game_systems.turnbattle.tests
+api/evennia.contrib.grid
+api/evennia.contrib.grid.extended_room
+api/evennia.contrib.grid.extended_room.extended_room
+api/evennia.contrib.grid.extended_room.tests
+api/evennia.contrib.grid.mapbuilder
+api/evennia.contrib.grid.mapbuilder.mapbuilder
+api/evennia.contrib.grid.mapbuilder.tests
+api/evennia.contrib.grid.simpledoor
+api/evennia.contrib.grid.simpledoor.simpledoor
+api/evennia.contrib.grid.simpledoor.tests
+api/evennia.contrib.grid.slow_exit
+api/evennia.contrib.grid.slow_exit.slow_exit
+api/evennia.contrib.grid.slow_exit.tests
+api/evennia.contrib.grid.wilderness
+api/evennia.contrib.grid.wilderness.tests
+api/evennia.contrib.grid.wilderness.wilderness
+api/evennia.contrib.grid.xyzgrid
+api/evennia.contrib.grid.xyzgrid.commands
+api/evennia.contrib.grid.xyzgrid.example
+api/evennia.contrib.grid.xyzgrid.launchcmd
+api/evennia.contrib.grid.xyzgrid.prototypes
+api/evennia.contrib.grid.xyzgrid.tests
+api/evennia.contrib.grid.xyzgrid.utils
+api/evennia.contrib.grid.xyzgrid.xymap
+api/evennia.contrib.grid.xyzgrid.xymap_legend
+api/evennia.contrib.grid.xyzgrid.xyzgrid
+api/evennia.contrib.grid.xyzgrid.xyzroom
+api/evennia.contrib.rpg
+api/evennia.contrib.rpg.dice
+api/evennia.contrib.rpg.dice.dice
+api/evennia.contrib.rpg.dice.tests
+api/evennia.contrib.rpg.health_bar
+api/evennia.contrib.rpg.health_bar.health_bar
+api/evennia.contrib.rpg.health_bar.tests
+api/evennia.contrib.rpg.rpsystem
+api/evennia.contrib.rpg.rpsystem.rplanguage
+api/evennia.contrib.rpg.rpsystem.rpsystem
+api/evennia.contrib.rpg.rpsystem.tests
+api/evennia.contrib.rpg.traits
+api/evennia.contrib.rpg.traits.tests
+api/evennia.contrib.rpg.traits.traits
+api/evennia.contrib.tutorials
+api/evennia.contrib.tutorials.batchprocessor
+api/evennia.contrib.tutorials.batchprocessor.example_batch_code
+api/evennia.contrib.tutorials.bodyfunctions
+api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions
+api/evennia.contrib.tutorials.bodyfunctions.tests
+api/evennia.contrib.tutorials.mirror
+api/evennia.contrib.tutorials.mirror.mirror
+api/evennia.contrib.tutorials.red_button
+api/evennia.contrib.tutorials.red_button.red_button
+api/evennia.contrib.tutorials.talking_npc
+api/evennia.contrib.tutorials.talking_npc.talking_npc
+api/evennia.contrib.tutorials.talking_npc.tests
+api/evennia.contrib.tutorials.tutorial_world
+api/evennia.contrib.tutorials.tutorial_world.intro_menu
+api/evennia.contrib.tutorials.tutorial_world.mob
+api/evennia.contrib.tutorials.tutorial_world.objects
+api/evennia.contrib.tutorials.tutorial_world.rooms
+api/evennia.contrib.tutorials.tutorial_world.tests
+api/evennia.contrib.utils
+api/evennia.contrib.utils.auditing
+api/evennia.contrib.utils.auditing.outputs
+api/evennia.contrib.utils.auditing.server
+api/evennia.contrib.utils.auditing.tests
+api/evennia.contrib.utils.fieldfill
+api/evennia.contrib.utils.fieldfill.fieldfill
+api/evennia.contrib.utils.random_string_generator
+api/evennia.contrib.utils.random_string_generator.random_string_generator
+api/evennia.contrib.utils.random_string_generator.tests
+api/evennia.contrib.utils.tree_select
+api/evennia.contrib.utils.tree_select.tests
+api/evennia.contrib.utils.tree_select.tree_select
api/evennia.help
api/evennia.help.filehelp
api/evennia.help.manager