Clean up contrib docs, autogeneration

This commit is contained in:
Griatch 2022-01-08 14:40:58 +01:00
parent b922cf9b3c
commit e96bbb4b86
94 changed files with 4126 additions and 2536 deletions

View file

@ -1,12 +1,10 @@
# AWSstorage system
Contrib by The Right Honourable Reverend (trhr) 2020
## What is this for?
Contrib by The Right Honourable Reverend (trhr), 2020
This plugin migrates the Web-based portion of Evennia, namely images,
javascript, and other items located inside staticfiles into Amazon AWS (S3) for
hosting.
javascript, and other items located inside staticfiles into Amazon AWS (S3)
cloud hosting. Great for those serving media with the game.
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,

View file

@ -1,15 +1,15 @@
# Input/Output Auditing
Contrib - Johnny 2017
Contribution by 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.
Utility that taps and intercepts all data sent to/from clients and the
server and passes it to a callback of your choosing. This is intended for
quality assurance, post-incident investigations and debugging.
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.
Note that this should be used with care since it can obviously 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.

View file

@ -1,18 +1,14 @@
# Barter system
Evennia contribution - Griatch 2012
Contribution by 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).
trade items between each other in code rather than simple `give/get`
commands. This increases both safety (at no time will one player have
both goods and payment in-hand) and speed, since agreed goods will
be moved automatically). By just replacing one side with coin objects,
(or a mix of coins and goods), this also works fine for regular money
transactions.
## Installation

View file

@ -1,10 +1,10 @@
# Batch processor examples
Contibution - Griatch 2012
Contibution by 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.
Simple examples for the batch-processor. 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:

View file

@ -1,9 +1,9 @@
# Script example
Griatch - 2012
Contribution by Griatch, 2012
Example script for testing. This adds a simple timer that has your
character make observations and notices at irregular intervals.
character make small verbal observations at irregular intervals.
To test, use (in game)

View file

@ -1,15 +1,13 @@
# Building menu
Module containing the building menu system.
Evennia contributor: vincent-lg 2018
Contrib by 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.
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 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

View file

@ -1,9 +1,9 @@
# Clothing
Evennia contribution - Tim Ashley Jenkins 2017
Contribution by Tim Ashley Jenkins, 2017
Provides a typeclass and commands for wearable clothing,
which is appended to a character's description when worn.
Provides a typeclass and commands for wearable clothing. These
look of these clothes are appended to the 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:
@ -13,6 +13,11 @@ in a list. For example, if wearing the following clothing items:
one nice hat
a very pretty dress
Would result in this added description:
Tim is wearing one nice hat, a thin and delicate necklace,
a very pretty dress and a pair of regular ol' shoes.
## Installation
To install, import this module and have your default character

View file

@ -1,9 +1,10 @@
# Color markups
Contribution, Griatch 2017
Contrib by Griatch, 2017
Additional color markup styles for Evennia (extending or replacing the default
`|r`, `|234` etc).
`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia
(`{r`, `{123`).
## Installation

View file

@ -1,13 +1,12 @@
# Cooldown contrib module.
# Cooldowns
Evennia contrib - owllex, 2021
Contribution by 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 used modelling rate-limited actions, like how often a
character can perform a given action; until a certain time has passed their
command can not be used again. This contrib provides a simple cooldown
handler that can be attached to any typeclass. A cooldown is a lightweight persistent
asynchronous timer that you can query to see if a certain time has yet passed.
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

View file

@ -1,25 +1,46 @@
# Crafting system
Contrib - Griatch 2020
Contribution by Griatch 2020
This implements a full crafting system. The principle is that of a 'recipe':
This implements a full crafting system. The principle is that of a 'recipe',
where you combine items (tagged as ingredients) create something new. The recipe can also
require certain (non-consumed) tools. An example would be to use the 'bread recipe' to
combine 'flour', 'water' and 'yeast' with an 'oven' to bake a 'loaf of bread'.
ingredient1 + ingredient2 + ... + tool1 + tool2 + ... + craft_recipe -> objectA, objectB, ...
The recipe process can be understood like this:
ingredient(s) + tool(s) + recipe -> object(s)
Here, 'ingredients' are consumed by the crafting process, whereas 'tools' are
necessary for the process by will not be destroyed by it.
necessary for the process but 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'.
The included `craft` command works like this:
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.
craft <recipe> [from <ingredient>,...] [using <tool>, ...]
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' ...
## Examples
Using the `craft` command:
craft toy car from plank, wooden wheels, nails using saw, hammer
A recipe does not have to use tools or even multiple ingredients:
snow + snowball_recipe -> snowball
Conversely one could also imagine using tools without consumables, like
spell_book + wand + fireball_recipe -> fireball
The system is generic enough to be used also for adventure-like puzzles (but
one would need to change the command and determine the recipe on based on what
is being combined instead):
stick + string + hook -> makeshift_fishing_rod
makeshift_fishing_rod + storm_drain -> key
See the [sword example](evennia.contrib.game_systems.crafting.example_recipes) for an example
of how to design a recipe tree for crafting a sword from base elements.
## Intallation and Usage
@ -29,18 +50,30 @@ available to you:
craft <recipe> [from <ingredient>,...] [using <tool>, ...]
For example
In code, you can craft using the
`evennia.contrib.game_systems.crafting.craft` function:
craft toy car from plank, wooden wheels, nails using saw, hammer
```python
from evennia.contrib.game_systems.crafting import craft
To use crafting you need recipes. Add a new variable to `mygame/server/conf/settings.py`:
result = craft(caller, "recipename", *inputs)
```
Here, `caller` is the one doing the crafting and `*inputs` is any combination of
consumables and/or tool Objects. The system will identify which is which by the
[Tags](../Components/Tags.md) on them (see below) The `result` is always a list.
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:
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:
A quick example (read on for more details):
```python
@ -69,37 +102,202 @@ class RecipeBread(CraftingRecipe):
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 do_craft(self, **kwargs):
# performs the craft - report errors directly to user and return None (if
# failed) and the created object(s) if successful.
def craft(self, result, **kwargs):
# any post-crafting effects. Always called, even if crafting failed (be
def post_craft(self, result, **kwargs):
# any post-crafting effects. Always called, even if do_craft failed (the
# result would be None then)
```
## Technical
## Adding new recipes
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.
A *recipe* is a class inheriting from
`evennia.contrib.crafting.crafting.CraftingRecipe`. This class implements the
most common form of crafting - that using in-game objects. Each recipe is a
separate class which gets initialized with the consumables/tools you provide.
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!
For the `craft` command to find your custom recipes, you need to tell Evennia
where they are. Add a new line to your `mygame/server/conf/settings.py` file,
with a list to any new modules with recipe classes.
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.
```python
CRAFT_RECIPE_MODULES = ["world.myrecipes"]
```
(You need to reload after adding this). All global-level classes in these
modules (whose names don't start with underscore) are considered by the system
as viable recipes.
Here we assume you created `mygame/world/myrecipes.py` to match the above
example setting:
```python
# in mygame/world/myrecipes.py
from evennia.contrib.crafting.crafting import CraftingRecipe
class WoodenPuppetRecipe(CraftingRecipe):
"""A puppet""""
name = "wooden puppet" # name to refer to this recipe as
tool_tags = ["knife"]
consumable_tags = ["wood"]
output_prototypes = [
{"key": "A carved wooden doll",
"typeclass": "typeclasses.objects.decorations.Toys",
"desc": "A small carved doll"}
]
```
This specifies which tags to look for in the inputs. It defines a
[Prototype](../Components/Prototypes.md) for the recipe to use to spawn the
result on the fly (a recipe could spawn more than one result if needed).
Instead of specifying the full prototype-dict, you could also just provide a
list of `prototype_key`s to existing prototypes you have.
After reloading the server, this recipe would now be available to use. To try it
we should create materials and tools to insert into the recipe.
The recipe analyzes inputs, looking for [Tags](../Components/Tags.md) with
specific tag-categories. The tag-category used can be set per-recipe using the
(`.consumable_tag_category` and `.tool_tag_category` respectively). The defaults
are `crafting_material` and `crafting_tool`. For
the puppet we need one object with the `wood` tag and another with the `knife`
tag:
```python
from evennia import create_object
knife = create_object(key="Hobby knife", tags=[("knife", "crafting_tool")])
wood = create_object(key="Piece of wood", tags[("wood", "crafting_material")])
```
Note that the objects can have any name, all that matters is the
tag/tag-category. This means if a "bayonet" also had the "knife" crafting tag,
it could also be used to carve a puppet. This is also potentially interesting
for use in puzzles and to allow users to experiment and find alternatives to
know ingredients.
By the way, there is also a simple shortcut for doing this:
```
tools, consumables = WoodenPuppetRecipe.seed()
```
The `seed` class-method will create simple dummy objects that fulfills the
recipe's requirements. This is great for testing.
Assuming these objects were put in our inventory, we could now craft using the
in-game command:
```bash
> craft wooden puppet from wood using hobby knife
```
In code we would do
```python
from evennia.contrub.crafting.crafting import craft
puppet = craft(crafter, "wooden puppet", knife, wood)
```
In the call to `craft`, the order of `knife` and `wood` doesn't matter - the
recipe will sort out which is which based on their tags.
## Deeper customization of recipes
For customizing recipes further, it helps to understand how to use the
recipe-class directly:
```python
class MyRecipe(CraftingRecipe):
# ...
tools, consumables = MyRecipe.seed()
recipe = MyRecipe(crafter, *(tools + consumables))
result = recipe.craft()
```
This is useful for testing and allows you to use the class directly without
adding it to a module in `settings.CRAFTING_RECIPE_MODULES`.
Even without modifying more than the class properties, there are a lot of
options to set on the `CraftingRecipe` class. Easiest is to refer to the
[CraftingRecipe api
documentation](evennia.contrib.game_systems.crafting.crafting.CraftingRecipe). For example,
you can customize the validation-error messages, decide if the ingredients have
to be exactly right, if a failure still consumes the ingredients or not, and
much more.
For even more control you can override hooks in your own class:
- `pre_craft` - this should handle input validation and store its data in `.validated_consumables` and
`validated_tools` respectively. On error, this reports the error to the crafter and raises the
`CraftingValidationError`.
- `craft` - this will only be called if `pre_craft` finished without an exception. This should
return the result of the crafting, by spawnging the prototypes. Or the empty list if crafting
fails for some reason. This is the place to add skill-checks or random chance if you need it
for your game.
- `post_craft` - this receives the result from `craft` and handles error messages and also deletes
any consumables as needed. It may also modify the result before returning it.
- `msg` - this is a wrapper for `self.crafter.msg` and should be used to send messages to the
crafter. Centralizing this means you can also easily modify the sending style in one place later.
The class constructor (and the `craft` access function) takes optional `**kwargs`. These are passed
into each crafting hook. These are unused by default but could be used to customize things per-call.
### Skilled crafters
What the crafting system does not have out of the box is a 'skill' system - the
notion of being able to fail the craft if you are not skilled enough. Just how
skills work is game-dependent, so to add this you need to make your own recipe
parent class and have your recipes inherit from this.
```python
from random import randint
from evennia.contrib.crafting.crafting import CraftingRecipe
class SkillRecipe(CraftingRecipe):
"""A recipe that considers skill"""
difficulty = 20
def craft(self, **kwargs):
"""The input is ok. Determine if crafting succeeds"""
# this is set at initialization
crafter = self.crafte
# let's assume the skill is stored directly on the crafter
# - the skill is 0..100.
crafting_skill = crafter.db.skill_crafting
# roll for success:
if randint(1, 100) <= (crafting_skill - self.difficulty):
# all is good, craft away
return super().craft()
else:
self.msg("You are not good enough to craft this. Better luck next time!")
return []
```
In this example we introduce a `.difficulty` for the recipe and makes a 'dice roll' to see
if we succed. We would of course make this a lot more immersive and detailed in a full game. In
principle you could customize each recipe just the way you want it, but you could also inherit from
a central parent like this to cut down on work.
The [sword recipe example module](evennia.contrib.game_systems.crafting.example_recipes) also shows an example
of a random skill-check being implemented in a parent and then inherited for multiple use.
## Even more customization
If you want to build something even more custom (maybe using different input types of validation logic)
you could also look at the `CraftingRecipe` parent class `CraftingRecipeBase`.
It implements just the minimum needed to be a recipe and for big changes you may be better off starting
from this rather than the more opinionated `CraftingRecipe`.
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.
----

View file

@ -1,10 +1,11 @@
# Custom gameime
Contrib - Griatch 2017, vlgeoff 2017
Contrib by vlgeoff, 2017 - based on Griatch's core original
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.
This reimplements the `evennia.utils.gametime` module but with a _custom_
calendar (unusual number of days per week/month/year etc) for your game world.
Like the original, it allows for scheduling events to happen at given
in-game times, but now taking this custom calendar into account.
## Installation

View file

@ -1,8 +1,12 @@
# Dice
Rolls dice for roleplaying, in-game gambling or GM:ing
Contribution by Griatch, 2012
A dice roller for any number and side of dice. Adds in-game dice rolling
(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target)
and functions for rolling dice in code. Command also supports hidden or secret
rolls for use by a human game master.
Evennia contribution - Griatch 2012
# Installation:

View file

@ -1,9 +1,10 @@
# Email-based login system
Evennia contrib - Griatch 2012
Contrib by Griatch, 2012
This is a variant of the login system that requires an email-address
instead of a username to login.
This is a variant of the login system that asks for an email-address
instead of a username to login. Note that it does not verify the email,
it just uses it as the identifier rather than a username.
This used to be the default Evennia login before replacing it with a
more standard username + password system (having to supply an email

View file

@ -1,16 +1,18 @@
# EvscapeRoom
Evennia contrib - Griatch 2019
Contribution by 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.
A full engine for creating multiplayer escape-rooms in Evennia. Allows players to
spawn and join puzzle rooms that track their state independently. Any number of players
can join to solve a room together. This is the engine created for 'EvscapeRoom', which won
the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game
content but 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
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!

View file

@ -1,10 +1,11 @@
# Extended Room
Evennia Contribution - Griatch 2012, vincent-lg 2019
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.
This extends the normal `Room` typeclass to allow its description to change
with time-of-day and/or season. It also adds 'details' for the player to look at
in the room (without having to create a new in-game object for each). The room is
supported by new `look` and `desc` commands.
## Installation/testing:

View file

@ -1,14 +1,16 @@
# Easy fillable form
Contrib - Tim Ashley Jenkins 2018
Contribution by 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.
This module contains a function that generates an `EvMenu` for you - this
menu presents the player with a form of fields that can be filled
out in any order (e.g. for character generation or building). 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.
## Usage
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)

View file

@ -1,6 +1,6 @@
# Gendersub
Contrib - Griatch 2015
Contribution by Griatch 2015
This is a simple gender-aware Character class for allowing users to
insert custom markers in their text to indicate gender-aware

View file

@ -1,11 +1,11 @@
# Health Bar
Contrib - Tim Ashley Jenkins 2017
Contribution by 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.
bars or meters as a colorful bar instead of just a number. A "health bar"
is merely the most obvious use for this, but the bar is 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

View file

@ -1,23 +1,19 @@
# Dialogues in events
- Next tutorial: [adding a voice-operated elevator with events](A-voice-operated-elevator-using-
events).
This tutorial will walk you through the steps to create several dialogues with characters, using the
[in-game Python
system](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md).
This tutorial assumes the in-game Python system is installed in your game. If it isn't, you can
follow the installation steps given in [the documentation on in-game
Python](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md), and
come back on this tutorial once the system is installed. **You do not need to read** the entire
documentation, it's a good reference, but not the easiest way to learn about it. Hence these
This tutorial will walk you through the steps to create several dialogues with
characters, using the Ingame-Python system. This tutorial assumes the in-game
Python system is installed in your game. If it isn't, you can follow the
installation steps given in [The main In-game Python
docs](./Contrib-Ingame-Python.md) and come back on this tutorial once the
system is installed. **You do not need to read** the entire documentation, it's
a good reference, but not the easiest way to learn about it. Hence these
tutorials.
The in-game Python system allows to run code on individual objects in some situations. You don't
have to modify the source code to add these features, past the installation. The entire system
makes it easy to add specific features to some objects, but not all. This is why it can be very
useful to create a dialogue system taking advantage of the in-game Python system.
The in-game Python system allows to run code on individual objects in some
situations. You don't have to modify the source code to add these features,
past the installation. The entire system makes it easy to add specific features
to some objects, but not all. This is why it can be very useful to create a
dialogue system taking advantage of the in-game Python system.
> What will we try to do?
@ -115,7 +111,7 @@ This command has opened an editor where we can type our Python code.
```
----------Line Editor [Callback say of a merchant]--------------------------------
01|
01|
----------[l:01 w:000 c:0000]------------(:h for help)----------------------------
```
@ -246,4 +242,4 @@ could share the same events as well. It is possible to do but requires modifica
code.
- Next tutorial: [adding a voice-operated elevator with events](A-voice-operated-elevator-using-
events).
events).

View file

@ -1,15 +1,8 @@
# A voice operated elevator using events
- Previous tutorial: [Adding dialogues in events](./Dialogues-in-events.md)
This tutorial will walk you through the steps to create a voice-operated elevator, using the [in-
game Python
system](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md).
This tutorial assumes the in-game Python system is installed in your game. If it isn't, you can
follow the installation steps given in [the documentation on in-game
Python](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md), and
come back on this tutorial once the system is installed. **You do not need to read** the entire
game Python system](./Contrib-Ingame-Python.md). This tutorial assumes the in-game Python
system is installed per the instructions in that doc. **You do not need to read** the entire
documentation, it's a good reference, but not the easiest way to learn about it. Hence these
tutorials.
@ -97,7 +90,8 @@ things to decorate it a bit.
But what we want now is to be able to say "1", "2" or "3" and have the elevator move in that
direction.
If you have read [the previous tutorial about adding dialogues in events](./Dialogues-in-events.md), you
If you have read
[the other in-game Python tutorial about adding dialogues in events](./Contrib-Ingame-Python-Tutorial-Dialogue.md), you
may remember what we need to do. If not, here's a summary: we need to run some code when somebody
speaks in the room. So we need to create a callback (the callback will contain our lines of code).
We just need to know on which event this should be set. You can enter `call here` to see the
@ -132,7 +126,7 @@ Variables you can use in this event:
message: the text having been spoken by the character.
----------Line Editor [Callback say of Inside of an elevator]---------------------
01|
01|
----------[l:01 w:000 c:0000]------------(:h for help)----------------------------
```
@ -244,7 +238,7 @@ This is a great opportunity to learn about chained events. Chained events are v
pauses. Contrary to the events we have seen so far, chained events aren't called automatically.
They must be called by you, and can be called after some time.
- Chained events always have the name "chain_X". Usually, X is a number, but you can give the
- Chained events always have the name `"chain_X"`. Usually, X is a number, but you can give the
chained event a more explicit name.
- In our original callback, we will call our chained events in, say, 15 seconds.
- We'll also have to make sure the elevator isn't already moving.
@ -254,7 +248,7 @@ event in our elevator, that will only contain the code necessary to open the doo
call/add here = chain_1
The callback is added to the "chain_1" event, an event that will not be automatically called by the
The callback is added to the `"chain_1"` event, an event that will not be automatically called by the
system when something happens. Inside this event, you can paste the code to open the doors at the
new floor. You can notice a few differences:
@ -273,7 +267,7 @@ Now let's edit our callback in the "say" event. We'll have to change it a bit:
- The callback will have to check the elevator isn't already moving.
- It must change the exits when the elevator move.
- It has to call the "chain_1" event we have defined. It should call it 15 seconds later.
- It has to call the `"chain_1"` event we have defined. It should call it 15 seconds later.
Let's see the code in our callback.
@ -415,8 +409,8 @@ constraints on persistent attributes. A callback will not be stored in this way
This variable will not be available in your chained event.
- **Q:** when you say I can call my chained events something else than "chain_1", "chain_2" and
such, what is the naming convention?
- **A:** chained events have names beginning by "chain_". This is useful for you and for the
system. But after the underscore, you can give a more useful name, like "chain_open_doors" in our
- **A:** chained events have names beginning by `"chain_"`. This is useful for you and for the
system. But after the underscore, you can give a more useful name, like `"chain_open_doors"` in our
case.
- **Q:** do I have to pause several seconds to call a chained event?
- **A:** no, you can call it right away. Just leave the third parameter of `call_event` out (it
@ -424,13 +418,11 @@ will default to 0, meaning the chained event will be called right away). This w
task.
- **Q:** can I have chained events calling themselves?
- **A:** you can. There's no limitation. Just be careful, a callback that calls itself,
particularly without delay, might be a good recipe for an infinite loop. However, in some cases, it
particularly without delay, might be a good recipe for an infinite loop. However, in some cases, it
is useful to have chained events calling themselves, to do the same repeated action every X seconds
for instance.
- **Q:** what if I need several elevators, do I need to copy/paste these callbacks each time?
- **A:** not advisable. There are definitely better ways to handle this situation. One of them is
to consider adding the code in the source itself. Another possibility is to call chained events
with the expected behavior, which makes porting code very easy. This side of chained events will be
with the expected behavior, which makes porting code very easy. This side of chained events will be
shown in the next tutorial.
- Previous tutorial: [Adding dialogues in events](./Dialogues-in-events.md)

View file

@ -1,15 +1,15 @@
# Evennia in-game Python system
Vincent Le Goff 2017
Contrib by 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.
This contrib adds the ability to script with Python in-game. It allows trusted
staff/builders to dynamically add features and triggers to individual objects
without needing to do it in external Python modules. Using custom Python in-game,
specific rooms, exits, characters, objects etc can be made to behave differently from
its "cousins". This is similar to how softcode works for MU or MudProgs for DIKU.
Keep in mind, however, that allowing Python in-game comes with _severe_
security concerns (you must trust your builders deeply), so read the warnings in
this module carefully before continuing.
## A WARNING REGARDING SECURITY
@ -22,6 +22,17 @@ will have to keep in mind these points before deciding to install it:
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.
## Extra tutorials
These tutorials cover examples of using ingame python. Once you have the system
installed (see below) they may be an easier way to learn than reading the full
documentation from beginning to end.
- [Dialogue events](./Contrib-Ingame-Python-Tutorial-Dialogue.md), where
NPCs react to things said.
- [A voice operated elevator](./Contrib-Ingame-Python-Tutorial-Elevator.md)
using ingame-python events.
## Basic structure and vocabulary
- At the basis of the in-game Python system are **events**. An **event**
@ -73,7 +84,9 @@ 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")```
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`).
@ -176,7 +189,7 @@ the `EVENTS_WITH_VALIDATION` setting will be able to call the command (with diff
### 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
to add, edit and delete callbacks in-game. In your `commands/default_cmdsets`, it might look like
this:
```python
@ -277,7 +290,7 @@ We'll see callbacks with parameters later. For the time being, let's try to pre
from going through the "north" exit of this room:
```
@call north
call north
+------------------+---------+-----------------------------------------------+
| Event name | Number | Description |
+~~~~~~~~~~~~~~~~~~+~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+

View file

@ -1,13 +1,15 @@
# In-Game Mail system
Evennia Contribution - grungies1138 2016
Contribution by 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:
A simple Brandymail style mail system that uses the `Msg` class from Evennia
Core. It has two Commands for either sending mails between Accounts (out of game)
or between Characters (in-game). The two types of mails can be used together or
on their own.
- CmdMail - this should sit on the Account cmdset and makes the `mail` command
- `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`
- `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

View file

@ -1,8 +1,8 @@
# Map Builder
Contribution - Cloud_Keeper 2016
Contribution by Cloud_Keeper 2016
Build a map from a 2D ASCII map.
Build a game map from the drawing of a 2D ASCII map.
This is a command which takes two inputs:

View file

@ -1,10 +1,10 @@
# Menu-based login system
Contribution - Vincent-lg 2016, Griatch 2019 (rework for modern EvMenu)
Contribution by Vincent-lg 2016. Reworked for modern EvMenu by Griatch, 2019.
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.
This changes the Evennia login to ask for the account name and password as a series
of questions instead of requiring you to enter both at once. It uses Evennia's
menu system `EvMenu` under the hood.
## Installation

View file

@ -1,8 +1,8 @@
# TutorialMirror
A simple mirror object to experiment with.
Contribution by Griatch, 2017
A simple mirror object that
A simple mirror object to experiment with. It will respond to being looked at.
- echoes back the description of the object looking at it
- echoes back whatever is being sent to its .msg - to the

View file

@ -1,15 +1,16 @@
# Evennia Multidescer
Contrib - Griatch 2016
Contribution by 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.
descriptions and is a way for quickly managing your look (such as when
changing clothes) in more free-form roleplaying systems. This will also
work well together with the `rpsystem` contrib.
This contrib also works well together with the rpsystem contrib (which
also adds the short descriptions and the `sdesc` command).
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.
## Installation

View file

@ -1,22 +1,24 @@
# Legacy Comms-commands
Contribution - Griatch 2021
Contribution by 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.
In Evennia 1.0+, the old Channel commands (originally inspired by MUX) were
replaced by the single `channel` command that performs all these functions.
This contrib (extracted from Evennia 0.9.5) breaks out the functionality into
separate Commands more familiar to MU* users. This is just for show though, the
main `channel` command is still called under the hood.
- `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`
| Contrib syntax | Default `channel` syntax |
| -------------- | --------------------------------------------------------- |
| `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

View file

@ -13,11 +13,10 @@ 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.md)!
> 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.
If you want to contribute yourself, see [here](../Contributing.md)!
## base_systems
@ -29,113 +28,123 @@ login systems, new command syntaxes, and build helpers._
### Contrib: `awsstorage`
Contrib by The Right Honourable Reverend (trhr) 2020
_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)
cloud hosting. Great for those serving media with the game.
[Read the documentation](./Contrib-AWSStorage.md)
[Read the documentation](./Contrib-AWSStorage.md) - [Browse the Code](evennia.contrib.base_systems.awsstorage)
### Contrib: `building_menu`
Module containing the building menu system.
_Contrib by vincent-lg, 2018_
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 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.
[Read the documentation](./Contrib-Building-Menu.md)
[Read the documentation](./Contrib-Building-Menu.md) - [Browse the Code](evennia.contrib.base_systems.building_menu)
### Contrib: `color_markups`
Contribution, Griatch 2017
_Contrib by Griatch, 2017_
Additional color markup styles for Evennia (extending or replacing the default
`|r`, `|234` etc).
`|r`, `|234`). Adds support for MUSH-style (`%cr`, `%c123`) and/or legacy-Evennia
(`{r`, `{123`).
[Read the documentation](./Contrib-Color-Markups.md)
[Read the documentation](./Contrib-Color-Markups.md) - [Browse the Code](evennia.contrib.base_systems.color_markups)
### Contrib: `custom_gametime`
Contrib - Griatch 2017, vlgeoff 2017
_Contrib by vlgeoff, 2017 - based on Griatch's core original_
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.
This reimplements the `evennia.utils.gametime` module but with a _custom_
calendar (unusual number of days per week/month/year etc) for your game world.
Like the original, it allows for scheduling events to happen at given
in-game times, but now taking this custom calendar into account.
[Read the documentation](./Contrib-Custom-Gametime.md)
[Read the documentation](./Contrib-Custom-Gametime.md) - [Browse the Code](evennia.contrib.base_systems.custom_gametime)
### Contrib: `email_login`
Evennia contrib - Griatch 2012
_Contrib by Griatch, 2012_
This is a variant of the login system that requires an email-address
instead of a username to login.
This is a variant of the login system that asks for an email-address
instead of a username to login. Note that it does not verify the email,
it just uses it as the identifier rather than a username.
[Read the documentation](./Contrib-Email-Login.md)
[Read the documentation](./Contrib-Email-Login.md) - [Browse the Code](evennia.contrib.base_systems.email_login)
### Contrib: `ingame_python`
Vincent Le Goff 2017
_Contrib by 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.
This contrib adds the ability to script with Python in-game. It allows trusted
staff/builders to dynamically add features and triggers to individual objects
without needing to do it in external Python modules. Using custom Python in-game,
specific rooms, exits, characters, objects etc can be made to behave differently from
its "cousins". This is similar to how softcode works for MU or MudProgs for DIKU.
Keep in mind, however, that allowing Python in-game comes with _severe_
security concerns (you must trust your builders deeply), so read the warnings in
this module carefully before continuing.
[Read the documentation](./Contrib-Ingame-Python.md)
[Read the documentation](./Contrib-Ingame-Python.md) - [Browse the Code](evennia.contrib.base_systems.ingame_python)
### Contrib: `menu_login`
Contribution - Vincent-lg 2016, Griatch 2019 (rework for modern EvMenu)
_Contribution by Vincent-lg 2016. Reworked for modern EvMenu by Griatch, 2019._
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.
This changes the Evennia login to ask for the account name and password as a series
of questions instead of requiring you to enter both at once. It uses Evennia's
menu system `EvMenu` under the hood.
[Read the documentation](./Contrib-Menu-Login.md)
[Read the documentation](./Contrib-Menu-Login.md) - [Browse the Code](evennia.contrib.base_systems.menu_login)
### Contrib: `mux_comms_cmds`
Contribution - Griatch 2021
_Contribution by 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.
In Evennia 1.0+, the old Channel commands (originally inspired by MUX) were
replaced by the single `channel` command that performs all these functions.
This contrib (extracted from Evennia 0.9.5) breaks out the functionality into
separate Commands more familiar to MU* users. This is just for show though, the
main `channel` command is still called under the hood.
[Read the documentation](./Contrib-Mux-Comms-Cmds.md)
[Read the documentation](./Contrib-Mux-Comms-Cmds.md) - [Browse the Code](evennia.contrib.base_systems.mux_comms_cmds)
### Contrib: `unixcommand`
Evennia contribution, Vincent Le Geoff 2017
_Contribution by Vincent Le Geoff (vlgeoff), 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
This module contains a command class with an alternate syntax parser implementing
Unix-style command syntax in-game. This means `--options`, positional arguments
and stuff like `-n 10`. 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
many things with many options. It uses the `ArgumentParser` from Python's standard
library under the hood.
[Read the documentation](./Contrib-Unixcommand.md)
[Read the documentation](./Contrib-Unixcommand.md) - [Browse the Code](evennia.contrib.base_systems.unixcommand)
@ -150,13 +159,15 @@ to start creating content without no further additions (unless you want to)._
### Contrib: `evscaperoom`
Evennia contrib - Griatch 2019
_Contribution by 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.
A full engine for creating multiplayer escape-rooms in Evennia. Allows players to
spawn and join puzzle rooms that track their state independently. Any number of players
can join to solve a room together. This is the engine created for 'EvscapeRoom', which won
the MUD Coders Guild "One Room" Game Jam in April-May, 2019. The contrib has no game
content but contains the utilities and base classes and an empty example room.
[Read the documentation](./Contrib-Evscaperoom.md)
[Read the documentation](./Contrib-Evscaperoom.md) - [Browse the Code](evennia.contrib.full_systems.evscaperoom)
@ -173,104 +184,115 @@ roleplaying-specific systems, those are found in the `rpg` folder._
### Contrib: `barter`
Evennia contribution - Griatch 2012
_Contribution by 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).
trade items between each other in code rather than simple `give/get`
commands. This increases both safety (at no time will one player have
both goods and payment in-hand) and speed, since agreed goods will
be moved automatically). By just replacing one side with coin objects,
(or a mix of coins and goods), this also works fine for regular money
transactions.
[Read the documentation](./Contrib-Barter.md)
[Read the documentation](./Contrib-Barter.md) - [Browse the Code](evennia.contrib.game_systems.barter)
### Contrib: `clothing`
Evennia contribution - Tim Ashley Jenkins 2017
_Contribution by Tim Ashley Jenkins, 2017_
Provides a typeclass and commands for wearable clothing,
which is appended to a character's description when worn.
Provides a typeclass and commands for wearable clothing. These
look of these clothes are appended to the character's description when worn.
[Read the documentation](./Contrib-Clothing.md)
[Read the documentation](./Contrib-Clothing.md) - [Browse the Code](evennia.contrib.game_systems.clothing)
### Contrib: `cooldowns`
Evennia contrib - owllex, 2021
_Contribution by 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 used modelling rate-limited actions, like how often a
character can perform a given action; until a certain time has passed their
command can not be used again. This contrib provides a simple cooldown
handler that can be attached to any typeclass. A cooldown is a lightweight persistent
asynchronous timer that you can query to see if a certain time has yet passed.
[Read the documentation](./Contrib-Cooldowns.md)
[Read the documentation](./Contrib-Cooldowns.md) - [Browse the Code](evennia.contrib.game_systems.cooldowns)
### Contrib: `crafting`
Contrib - Griatch 2020
_Contribution by Griatch 2020_
This implements a full crafting system. The principle is that of a 'recipe':
This implements a full crafting system. The principle is that of a 'recipe',
where you combine items (tagged as ingredients) create something new. The recipe can also
require certain (non-consumed) tools. An example would be to use the 'bread recipe' to
combine 'flour', 'water' and 'yeast' with an 'oven' to bake a 'loaf of bread'.
[Read the documentation](./Contrib-Crafting.md)
[Read the documentation](./Contrib-Crafting.md) - [Browse the Code](evennia.contrib.game_systems.crafting)
### Contrib: `gendersub`
Contrib - Griatch 2015
_Contribution by 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.
[Read the documentation](./Contrib-Gendersub.md)
[Read the documentation](./Contrib-Gendersub.md) - [Browse the Code](evennia.contrib.game_systems.gendersub)
### Contrib: `mail`
Evennia Contribution - grungies1138 2016
_Contribution by 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:
A simple Brandymail style mail system that uses the `Msg` class from Evennia
Core. It has two Commands for either sending mails between Accounts (out of game)
or between Characters (in-game). The two types of mails can be used together or
on their own.
[Read the documentation](./Contrib-Mail.md)
[Read the documentation](./Contrib-Mail.md) - [Browse the Code](evennia.contrib.game_systems.mail)
### Contrib: `multidescer`
Contrib - Griatch 2016
_Contribution by 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.
descriptions and is a way for quickly managing your look (such as when
changing clothes) in more free-form roleplaying systems. This will also
work well together with the `rpsystem` contrib.
[Read the documentation](./Contrib-Multidescer.md)
[Read the documentation](./Contrib-Multidescer.md) - [Browse the Code](evennia.contrib.game_systems.multidescer)
### Contrib: `puzzles`
Evennia contribution - Henddher 2018
_Contribution by Henddher 2018_
Provides a typeclass and commands for objects that can be combined (i.e. 'use'd)
to produce new objects.
Intended for adventure-game style combination puzzles, such as combining fruits
and a blender to create a smoothie. Provides a typeclass and commands for objects
that can be combined (i.e. used together). Unlike the `crafting` contrib, each
puzzle is built from unique objects rather than using tags and a builder can create
the puzzle entirely from in-game.
[Read the documentation](./Contrib-Puzzles.md)
[Read the documentation](./Contrib-Puzzles.md) - [Browse the Code](evennia.contrib.game_systems.puzzles)
### Contrib: `turnbattle`
Contrib - Tim Ashley Jenkins 2017
_Contribution by 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
@ -280,7 +302,7 @@ 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.
[Read the documentation](./Contrib-Turnbattle.md)
[Read the documentation](./Contrib-Turnbattle.md) - [Browse the Code](evennia.contrib.game_systems.turnbattle)
@ -295,80 +317,77 @@ contribs related to rooms, exits and map building._
### Contrib: `extended_room`
Evennia Contribution - Griatch 2012, vincent-lg 2019
_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.
This extends the normal `Room` typeclass to allow its description to change
with time-of-day and/or season. It also adds 'details' for the player to look at
in the room (without having to create a new in-game object for each). The room is
supported by new `look` and `desc` commands.
[Read the documentation](./Contrib-Extended-Room.md)
[Read the documentation](./Contrib-Extended-Room.md) - [Browse the Code](evennia.contrib.grid.extended_room)
### Contrib: `mapbuilder`
Contribution - Cloud_Keeper 2016
_Contribution by Cloud_Keeper 2016_
Build a map from a 2D ASCII map.
Build a game map from the drawing of a 2D ASCII map.
[Read the documentation](./Contrib-Mapbuilder.md)
[Read the documentation](./Contrib-Mapbuilder.md) - [Browse the Code](evennia.contrib.grid.mapbuilder)
### Contrib: `simpledoor`
Contribution - Griatch 2016
_Contribution by 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.
closed from both sides. Can easily be expanded to make it lockable,
destroyable etc.
[Read the documentation](./Contrib-Simpledoor.md)
[Read the documentation](./Contrib-Simpledoor.md) - [Browse the Code](evennia.contrib.grid.simpledoor)
### Contrib: `slow_exit`
Contribution - Griatch 2014
_Contribution by 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
An example of an Exit-type that delays its traversal. This simulates
slow movement, common in many games. The contrib also
contains two commands, `setspeed` and `stop` for changing the movement speed
and abort an ongoing traversal, respectively.
[Read the documentation](./Contrib-Slow-Exit.md)
[Read the documentation](./Contrib-Slow-Exit.md) - [Browse the Code](evennia.contrib.grid.slow_exit)
### Contrib: `wilderness`
Evennia contrib - titeuf87 2017
_Contribution by 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
of rooms - as you move, you instead end up back in the same room but its description
changes. 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)
[Read the documentation](./Contrib-Wilderness.md) - [Browse the Code](evennia.contrib.grid.wilderness)
### Contrib: `xyzgrid`
Full grid coordinate- pathfinding and visualization system
Evennia Contrib by Griatch 2021
_Contribution 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.
Places Evennia's game world on an xy (z being different maps) coordinate grid.
Grid is created and maintained externally by drawing and parsing 2D ASCII maps,
including teleports, map transitions and special markers to aid pathfinding.
Supports very fast shortest-route pathfinding on each map. Also includes a
fast view function for seeing only a limited number of steps away from your
current location (useful for displaying the grid as an in-game, updating map).
[Read the documentation](./Contrib-XYZGrid.md)
[Read the documentation](./Contrib-XYZGrid.md) - [Browse the Code](evennia.contrib.grid.xyzgrid)
@ -383,48 +402,59 @@ and rule implementation like character traits, dice rolling and emoting._
### Contrib: `dice`
Rolls dice for roleplaying, in-game gambling or GM:ing
_Contribution by Griatch, 2012_
Evennia contribution - Griatch 2012
A dice roller for any number and side of dice. Adds in-game dice rolling
(`roll 2d10 + 1`) as well as conditionals (roll under/over/equal to a target)
and functions for rolling dice in code. Command also supports hidden or secret
rolls for use by a human game master.
[Read the documentation](./Contrib-Dice.md)
[Read the documentation](./Contrib-Dice.md) - [Browse the Code](evennia.contrib.rpg.dice)
### Contrib: `health_bar`
Contrib - Tim Ashley Jenkins 2017
_Contribution by 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.
bars or meters as a colorful bar instead of just a number. A "health bar"
is merely the most obvious use for this, but the bar is highly customizable
and can be used for any sort of appropriate data besides player health.
[Read the documentation](./Contrib-Health-Bar.md)
[Read the documentation](./Contrib-Health-Bar.md) - [Browse the Code](evennia.contrib.rpg.health_bar)
### Contrib: `rpsystem`
Roleplaying emotes/sdescs - Griatch, 2015
Language/whisper emotes - Griatch, 2015
_Contribution by Griatch, 2015_
## Roleplaying emotes
A full roleplaying emote system. Short-descriptions and recognition (only
know people by their looks until you assign a name to them). Room poses. Masks/disguises
(hide your description). Speak directly in emote, with optional language obscuration
(words get garbled if you don't know the language, you can also have different languages
with different 'sounding' garbling). Whispers can be partly overheard from a distance. A
very powerful in-emote reference system, for referencing and differentiate targets
(including objects).
[Read the documentation](./Contrib-RPSystem.md)
[Read the documentation](./Contrib-RPSystem.md) - [Browse the Code](evennia.contrib.rpg.rpsystem)
### Contrib: `traits`
Whitenoise 2014, Ainneve contributors,
Griatch 2020
_Contribution by Griatch 2020, based on code by Whitenoise and Ainneve contribs, 2014_
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.
(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).
[Read the documentation](./Contrib-Traits.md)
[Read the documentation](./Contrib-Traits.md) - [Browse the Code](evennia.contrib.rpg.traits)
@ -440,71 +470,72 @@ tutorials are found here. Also the home of the Tutorial World demo adventure._
### Contrib: `batchprocessor`
Contibution - Griatch 2012
_Contibution by 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.
Simple examples for the batch-processor. 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)
[Read the documentation](./Contrib-Batchprocessor.md) - [Browse the Code](evennia.contrib.tutorials.batchprocessor)
### Contrib: `bodyfunctions`
Griatch - 2012
_Contribution by Griatch, 2012_
Example script for testing. This adds a simple timer that has your
character make observations and notices at irregular intervals.
character make small verbal observations at irregular intervals.
[Read the documentation](./Contrib-Bodyfunctions.md)
[Read the documentation](./Contrib-Bodyfunctions.md) - [Browse the Code](evennia.contrib.tutorials.bodyfunctions)
### Contrib: `mirror`
A simple mirror object to experiment with.
_Contribution by Griatch, 2017_
A simple mirror object that
A simple mirror object to experiment with. It will respond to being looked at.
[Read the documentation](./Contrib-Mirror.md)
[Read the documentation](./Contrib-Mirror.md) - [Browse the Code](evennia.contrib.tutorials.mirror)
### Contrib: `red_button`
Griatch - 2011
_Contribution by Griatch, 2011_
This is a more advanced example object with its own functionality (commands)
on it.
A red button that you can press to have an effect. This is a more advanced example
object with its own functionality and state tracking.
[Read the documentation](./Contrib-Red-Button.md)
[Read the documentation](./Contrib-Red-Button.md) - [Browse the Code](evennia.contrib.tutorials.red_button)
### Contrib: `talking_npc`
Contribution - Griatch 2011, grungies1138, 2016
_Contribution by Griatch 2011. Updated by grungies1138, 2016_
This is a static NPC object capable of holding a simple menu-driven
conversation. It's just meant as an example.
This is an example of a static NPC object capable of holding a simple menu-driven
conversation. Suitable for example as a quest giver or merchant.
[Read the documentation](./Contrib-Talking-Npc.md)
[Read the documentation](./Contrib-Talking-Npc.md) - [Browse the Code](evennia.contrib.tutorials.talking_npc)
### Contrib: `tutorial_world`
Griatch 2011, 2015
_Contribution by Griatch 2011, 2015_
This is a stand-alone tutorial area for an unmodified Evennia install.
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
are designed to show off features of Evennia, not to be a
very challenging (nor long) gaming experience. As such it's of course
only skimming the surface of what is possible.
only skimming the surface of what is possible. Taking this apart
is a great way to start learning the system.
[Read the documentation](./Contrib-Tutorial-World.md)
[Read the documentation](./Contrib-Tutorial-World.md) - [Browse the Code](evennia.contrib.tutorials.tutorial_world)
@ -519,54 +550,53 @@ and more._
### Contrib: `auditing`
Contrib - Johnny 2017
_Contribution by 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.
Utility that taps and intercepts all data sent to/from clients and the
server and passes it to a callback of your choosing. This is intended for
quality assurance, post-incident investigations and debugging.
[Read the documentation](./Contrib-Auditing.md)
[Read the documentation](./Contrib-Auditing.md) - [Browse the Code](evennia.contrib.utils.auditing)
### Contrib: `fieldfill`
Contrib - Tim Ashley Jenkins 2018
_Contribution by 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.
This module contains a function that generates an `EvMenu` for you - this
menu presents the player with a form of fields that can be filled
out in any order (e.g. for character generation or building). 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)
[Read the documentation](./Contrib-Fieldfill.md) - [Browse the Code](evennia.contrib.utils.fieldfill)
### Contrib: `random_string_generator`
Contribution - Vincent Le Goff 2017
_Contribution by Vincent Le Goff (vlgeoff), 2017_
This contrib can be used to generate pseudo-random strings of information
This utility 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:
phone numbers, license plate numbers, validation codes, in-game security
passwords and so on. The strings generated will be stored and won't be repeated.
[Read the documentation](./Contrib-Random-String-Generator.md)
[Read the documentation](./Contrib-Random-String-Generator.md) - [Browse the Code](evennia.contrib.utils.random_string_generator)
### Contrib: `tree_select`
Contrib - Tim Ashley Jenkins 2017
_Contribution by 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.
This utility allows you to create and initialize an entire branching EvMenu
instance from a multi-line string passed to one function.
[Read the documentation](./Contrib-Tree-Select.md)
[Read the documentation](./Contrib-Tree-Select.md) - [Browse the Code](evennia.contrib.utils.tree_select)
@ -574,52 +604,52 @@ instance with nothing but a multi-line string passed to one function.
```{toctree}
:depth: 2
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
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
```
----
<small>This document page is auto-generated from the sources. Manual changes
<small>This document page is auto-generated. Manual changes
will be overwritten.</small>

View file

@ -1,18 +1,21 @@
# Puzzles System
Evennia contribution - Henddher 2018
Contribution by Henddher 2018
Provides a typeclass and commands for objects that can be combined (i.e. 'use'd)
to produce new objects.
Intended for adventure-game style combination puzzles, such as combining fruits
and a blender to create a smoothie. Provides a typeclass and commands for objects
that can be combined (i.e. used together). Unlike the `crafting` contrib, each
puzzle is built from unique objects rather than using tags and a builder can create
the puzzle entirely from in-game.
A Puzzle is a recipe of what objects (aka parts) must be combined by a player so
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).
Add the `PuzzleSystemCmdSet` to all players (e.g. in their Character typeclass).
Alternatively:
Alternatively (for quick testing):
py self.cmdset.add('evennia.contrib.game_systems.puzzles.PuzzleSystemCmdSet')

View file

@ -1,7 +1,17 @@
# Roleplaying base system for Evennia
Roleplaying emotes/sdescs - Griatch, 2015
Language/whisper emotes - Griatch, 2015
Contribution by Griatch, 2015
A full roleplaying emote system. Short-descriptions and recognition (only
know people by their looks until you assign a name to them). Room poses. Masks/disguises
(hide your description). Speak directly in emote, with optional language obscuration
(words get garbled if you don't know the language, you can also have different languages
with different 'sounding' garbling). Whispers can be partly overheard from a distance. A
very powerful in-emote reference system, for referencing and differentiate targets
(including objects).
The system contains of two main modules - the roleplaying emote system and the language
obscuration module.
## Roleplaying emotes

View file

@ -1,12 +1,14 @@
# Pseudo-random generator and registry
Contribution - Vincent Le Goff 2017
Contribution by Vincent Le Goff (vlgeoff), 2017
This contrib can be used to generate pseudo-random strings of information
This utility 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.
phone numbers, license plate numbers, validation codes, in-game security
passwords and so on. The strings generated will be stored and won't be repeated.
## Usage Example
Here's a very simple example:
```python

View file

@ -1,9 +1,9 @@
# Red Button example
Griatch - 2011
Contribution by Griatch, 2011
This is a more advanced example object with its own functionality (commands)
on it.
A red button that you can press to have an effect. This is a more advanced example
object with its own functionality and state tracking.
Create the button with

View file

@ -1,13 +1,15 @@
# SimpleDoor
Contribution - Griatch 2016
Contribution by 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
closed from both sides. Can easily be expanded 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
without the locks stopping you. To use the door, use `quell` or a
non-superuser account.
## Installation:

View file

@ -1,10 +1,10 @@
# Slow Exit
Contribution - Griatch 2014
Contribution by 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
An example of an Exit-type that delays its traversal. This simulates
slow movement, common in many games. The contrib also
contains two commands, `setspeed` and `stop` for changing the movement speed
and abort an ongoing traversal, respectively.
## Installation:

View file

@ -1,9 +1,9 @@
# Talkative NPC example
Contribution - Griatch 2011, grungies1138, 2016
Contribution by Griatch 2011. Updated by grungies1138, 2016
This is a static NPC object capable of holding a simple menu-driven
conversation. It's just meant as an example.
This is an example of a static NPC object capable of holding a simple menu-driven
conversation. Suitable for example as a quest giver or merchant.
## Installation

View file

@ -1,12 +1,10 @@
# Traits
Whitenoise 2014, Ainneve contributors,
Griatch 2020
Contribution by Griatch 2020, based on code by Whitenoise and Ainneve contribs, 2014
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.
(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

View file

@ -1,14 +1,16 @@
# Easy menu selection tree
Contrib - Tim Ashley Jenkins 2017
Contribution by 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.
This utility allows you to create and initialize an entire branching EvMenu
instance from 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.
> Note: Since the time this contrib was created, EvMenu itself got its own templating
> language that has more features and is not compatible with the style used in
> this contrib. Both can still be used in parallel.
`EvMenu` is incredibly powerful and flexible but it can be a little overwhelming
and offers a lot of power that may not be needed for a simple multiple-choice menu.
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

View file

@ -1,6 +1,6 @@
# Turn based battle system framework
Contrib - Tim Ashley Jenkins 2017
Contribution by 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

View file

@ -1,13 +1,14 @@
# Evennia Tutorial World
Griatch 2011, 2015
Contribution by Griatch 2011, 2015
This is a stand-alone tutorial area for an unmodified Evennia install.
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
are designed to show off features of Evennia, not to be a
very challenging (nor long) gaming experience. As such it's of course
only skimming the surface of what is possible.
only skimming the surface of what is possible. Taking this apart
is a great way to start learning the system.
The tutorial world also includes a game tutor menu example, exemplifying
Evmenu.

View file

@ -1,12 +1,12 @@
# Unix-like Command style parent
Evennia contribution, Vincent Le Geoff 2017
Contribution by Vincent Le Geoff (vlgeoff), 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
This module contains a command class with an alternate syntax parser implementing
Unix-style command syntax in-game. This means `--options`, positional arguments
and stuff like `-n 10`. 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
many things with many options. It uses the `ArgumentParser` from Python's standard
library under the hood.
## Installation

View file

@ -1,10 +1,10 @@
# Wilderness system
Evennia contrib - titeuf87 2017
Contribution by 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
of rooms - as you move, you instead end up back in the same room but its description
changes. This means you can make huge areas with little database use as
long as the rooms are relatively similar (name/desc changing).
## Installation

File diff suppressed because it is too large Load diff

View file

@ -1,222 +0,0 @@
# Crafting system contrib
_Contrib by Griatch 2020_
```{versionadded} 1.0
```
This contrib implements a full Crafting system that can be expanded and modified to fit your game.
- See the [evennia/contrib/crafting/crafting.py API](evennia.contrib.crafting.crafting) for installation
instructrions.
- See the [sword example](evennia.contrib.crafting.example_recipes) for an example of how to design
a crafting tree for crafting a sword from base elements.
From in-game it uses the new `craft` command:
```bash
> craft bread from flour, eggs, salt, water, yeast using oven, roller
> craft bandage from cloth using scissors
```
The syntax is `craft <recipe> [from <ingredient>,...][ using <tool>,...]`.
The above example uses the `bread` *recipe* and requires `flour`, `eggs`, `salt`, `water` and `yeast` objects
to be in your inventory. These will be consumed as part of crafting (baking) the bread.
The `oven` and `roller` are "tools" that can be either in your inventory or in your current location (you are not carrying an oven
around with you after all). Tools are *not* consumed in the crafting. If the added ingredients/tools matches
the requirements of the recipe, a new `bread` object will appear in the crafter's inventory.
If you wanted, you could also picture recipes without any consumables:
```
> craft fireball using wand, spellbook
```
With a little creativity, the 'recipe' concept could be adopted to all sorts of things, like puzzles or
magic systems.
In code, you can craft using the `evennia.contrib.crafting.crafting.craft` function:
```python
from evennia.contrib.crafting.crafting import craft
result = craft(caller, "recipename", *inputs)
```
Here, `caller` is the one doing the crafting and `*inputs` is any combination of consumables and/or tool
Objects. The system will identify which is which by the [Tags](../Components/Tags.md) on them (see below)
The `result` is always a list.
## Adding new recipes
A *recipe* is a class inheriting from `evennia.contrib.crafting.crafting.CraftingRecipe`. This class
implements the most common form of crafting - that using in-game objects. Each recipe is a separate class
which gets initialized with the consumables/tools you provide.
For the `craft` command to find your custom recipes, you need to tell Evennia where they are. Add a new
line to your `mygame/server/conf/settings.py` file, with a list to any new modules with recipe classes.
```python
CRAFT_RECIPE_MODULES = ["world.myrecipes"]
```
(You need to reload after adding this). All global-level classes in these modules (whose names don't start
with underscore) are considered by the system as viable recipes.
Here we assume you created `mygame/world/myrecipes.py` to match the above example setting:
```python
# in mygame/world/myrecipes.py
from evennia.contrib.crafting.crafting import CraftingRecipe
class WoodenPuppetRecipe(CraftingRecipe):
"""A puppet""""
name = "wooden puppet" # name to refer to this recipe as
tool_tags = ["knife"]
consumable_tags = ["wood"]
output_prototypes = [
{"key": "A carved wooden doll",
"typeclass": "typeclasses.objects.decorations.Toys",
"desc": "A small carved doll"}
]
```
This specifies which tags to look for in the inputs. It defines a [Prototype](../Components/Prototypes.md)
for the recipe to use to spawn the result on the fly (a recipe could spawn more than one result if needed).
Instead of specifying the full prototype-dict, you could also just provide a list of `prototype_key`s to
existing prototypes you have.
After reloading the server, this recipe would now be available to use. To try it we should
create materials and tools to insert into the recipe.
The recipe analyzes inputs, looking for [Tags](../Components/Tags.md) with specific tag-categories.
The tag-category used can be set per-recipe using the (`.consumable_tag_category` and
`.tool_tag_category` respectively). The defaults are `crafting_material` and `crafting_tool`. For
the puppet we need one object with the `wood` tag and another with the `knife` tag:
```python
from evennia import create_object
knife = create_object(key="Hobby knife", tags=[("knife", "crafting_tool")])
wood = create_object(key="Piece of wood", tags[("wood", "crafting_material")])
```
Note that the objects can have any name, all that matters is the tag/tag-category. This means if a
"bayonet" also had the "knife" crafting tag, it could also be used to carve a puppet. This is also
potentially interesting for use in puzzles and to allow users to experiment and find alternatives to
know ingredients.
By the way, there is also a simple shortcut for doing this:
```
tools, consumables = WoodenPuppetRecipe.seed()
```
The `seed` class-method will create simple dummy objects that fulfills the recipe's requirements. This
is great for testing.
Assuming these objects were put in our inventory, we could now craft using the in-game command:
```bash
> craft wooden puppet from wood using hobby knife
```
In code we would do
```python
from evennia.contrub.crafting.crafting import craft
puppet = craft(crafter, "wooden puppet", knife, wood)
```
In the call to `craft`, the order of `knife` and `wood` doesn't matter - the recipe will sort out which
is which based on their tags.
## Deeper customization of recipes
For customizing recipes further, it helps to understand how to use the recipe-class directly:
```python
class MyRecipe(CraftingRecipe):
# ...
tools, consumables = MyRecipe.seed()
recipe = MyRecipe(crafter, *(tools + consumables))
result = recipe.craft()
```
This is useful for testing and allows you to use the class directly without adding it to a module
in `settings.CRAFTING_RECIPE_MODULES`.
Even without modifying more than the class properties, there are a lot of options to set on
the `CraftingRecipe` class. Easiest is to refer to the
[CraftingRecipe api documentation](evennia.contrib.crafting.crafting.CraftingRecipe).
For example, you can customize the validation-error messages, decide if the ingredients have
to be exactly right, if a failure still consumes the ingredients or not, and much more.
For even more control you can override hooks in your own class:
- `pre_craft` - this should handle input validation and store its data in `.validated_consumables` and
`validated_tools` respectively. On error, this reports the error to the crafter and raises the
`CraftingValidationError`.
- `craft` - this will only be called if `pre_craft` finished without an exception. This should
return the result of the crafting, by spawnging the prototypes. Or the empty list if crafting
fails for some reason. This is the place to add skill-checks or random chance if you need it
for your game.
- `post_craft` - this receives the result from `craft` and handles error messages and also deletes
any consumables as needed. It may also modify the result before returning it.
- `msg` - this is a wrapper for `self.crafter.msg` and should be used to send messages to the
crafter. Centralizing this means you can also easily modify the sending style in one place later.
The class constructor (and the `craft` access function) takes optional `**kwargs`. These are passed
into each crafting hook. These are unused by default but could be used to customize things per-call.
### Skilled crafters
What the crafting system does not have out of the box is a 'skill' system - the notion of being able
to fail the craft if you are not skilled enough. Just how skills work is game-dependent, so to add
this you need to make your own recipe parent class and have your recipes inherit from this.
```python
from random import randint
from evennia.contrib.crafting.crafting import CraftingRecipe
class SkillRecipe(CraftingRecipe):
"""A recipe that considers skill"""
difficulty = 20
def craft(self, **kwargs):
"""The input is ok. Determine if crafting succeeds"""
# this is set at initialization
crafter = self.crafte
# let's assume the skill is stored directly on the crafter
# - the skill is 0..100.
crafting_skill = crafter.db.skill_crafting
# roll for success:
if randint(1, 100) <= (crafting_skill - self.difficulty):
# all is good, craft away
return super().craft()
else:
self.msg("You are not good enough to craft this. Better luck next time!")
return []
```
In this example we introduce a `.difficulty` for the recipe and makes a 'dice roll' to see
if we succed. We would of course make this a lot more immersive and detailed in a full game. In
principle you could customize each recipe just the way you want it, but you could also inherit from
a central parent like this to cut down on work.
The [sword recipe example module](evennia.contrib.crafting.example_recipes) also shows an example
of a random skill-check being implemented in a parent and then inherited for multiple use.
## Even more customization
If you want to build something even more custom (maybe using different input types of validation logic)
you could also look at the `CraftingRecipe` parent class `CraftingRecipeBase`.
It implements just the minimum needed to be a recipe and for big changes you may be better off starting
from this rather than the more opinionated `CraftingRecipe`.

View file

@ -1,495 +0,0 @@
# Dynamic In Game Map
## Introduction
An often desired feature in a MUD is to show an in-game map to help navigation. The [Static in-game
map](./Static-In-Game-Map.md) tutorial solves this by creating a *static* map, meaning the map is pre-
drawn once and for all - the rooms are then created to match that map. When walking around, parts of
the static map is then cut out and displayed next to the room description.
In this tutorial we'll instead do it the other way around; We will dynamically draw the map based on
the relationships we find between already existing rooms.
## The Grid of Rooms
There are at least two requirements needed for this tutorial to work.
1. The structure of your mud has to follow a logical layout. Evennia supports the layout of your
world to be 'logically' impossible with rooms looping to themselves or exits leading to the other
side of the map. Exits can also be named anything, from "jumping out the window" to "into the fifth
dimension". This tutorial assumes you can only move in the cardinal directions (N, E, S and W).
2. Rooms must be connected and linked together for the map to be generated correctly. Vanilla
Evennia comes with a admin command [tunnel](evennia.commands.default.building.CmdTunnel) that allows a
user to create rooms in the cardinal directions, but additional work is needed to assure that rooms
are connected. For example, if you `tunnel east` and then immediately do `tunnel west` you'll find
that you have created two completely stand-alone rooms. So care is needed if you want to create a
"logical" layout. In this tutorial we assume you have such a grid of rooms that we can generate the
map from.
## Concept
Before getting into the code, it is beneficial to understand and conceptualize how this is going to
work. The idea is analogous to a worm that starts at your current position. It chooses a direction
and 'walks' outward from it, mapping its route as it goes. Once it has traveled a pre-set distance
it stops and starts over in another direction. An important note is that we want a system which is
easily callable and not too complicated. Therefore we will wrap this entire code into a custom
Python class (not a typeclass as this doesn't use any core objects from evennia itself).
We are going to create something that displays like this when you type 'look':
```
Hallway
[.] [.]
[@][.][.][.][.]
[.] [.] [.]
The distant echoes of the forgotten
wail throughout the empty halls.
Exits: North, East, South
```
Your current location is defined by `[@]` while the `[.]`s are other rooms that the "worm" has seen
since departing from your location.
## Setting up the Map Display
First we must define the components for displaying the map. For the "worm" to know what symbol to
draw on the map we will have it check an Attribute on the room it visits called `sector_type`. For
this tutorial we understand two symbols - a normal room and the room with us in it. We also define a
fallback symbol for rooms without said Attribute - that way the map will still work even if we
didn't prepare the room correctly. Assuming your game folder is named `mygame`, we create this code
in `mygame/world/map.py.`
```python
# in mygame/world/map.py
# the symbol is identified with a key "sector_type" on the
# Room. Keys None and "you" must always exist.
SYMBOLS = { None : ' . ', # for rooms without sector_type Attribute
'you' : '[@]',
'SECT_INSIDE': '[.]' }
```
Since trying to access an unset Attribute returns `None`, this means rooms without the `sector_type`
Atttribute will show as ` . `. Next we start building the custom class `Map`. It will hold all
methods we need.
```python
# in mygame/world/map.py
class Map(object):
def __init__(self, caller, max_width=9, max_length=9):
self.caller = caller
self.max_width = max_width
self.max_length = max_length
self.worm_has_mapped = {}
self.curX = None
self.curY = None
```
- `self.caller` is normally your Character object, the one using the map.
- `self.max_width/length` determine the max width and length of the map that will be generated. Note
that it's important that these variables are set to *odd* numbers to make sure the display area has
a center point.
- ` self.worm_has_mapped` is building off the worm analogy above. This dictionary will store all
rooms the "worm" has mapped as well as its relative position within the grid. This is the most
important variable as it acts as a 'checker' and 'address book' that is able to tell us where the
worm has been and what it has mapped so far.
- `self.curX/Y` are coordinates representing the worm's current location on the grid.
Before any sort of mapping can actually be done we need to create an empty display area and do some
sanity checks on it by using the following methods.
```python
# in mygame/world/map.py
class Map(object):
# [... continued]
def create_grid(self):
# This method simply creates an empty grid/display area
# with the specified variables from __init__(self):
board = []
for row in range(self.max_width):
board.append([])
for column in range(self.max_length):
board[row].append(' ')
return board
def check_grid(self):
# this method simply checks the grid to make sure
# that both max_l and max_w are odd numbers.
return True if self.max_length % 2 != 0 or self.max_width % 2 != 0\
else False
```
Before we can set our worm on its way, we need to know some of the computer science behind all this
called 'Graph Traversing'. In Pseudo code what we are trying to accomplish is this:
```python
# pseudo code
def draw_room_on_map(room, max_distance):
self.draw(room)
if max_distance == 0:
return
for exit in room.exits:
if self.has_drawn(exit.destination):
# skip drawing if we already visited the destination
continue
else:
# first time here!
self.draw_room_on_map(exit.destination, max_distance - 1)
```
The beauty of Python is that our actual code of doing this doesn't differ much if at all from this
Pseudo code example.
- `max_distance` is a variable indicating to our Worm how many rooms AWAY from your current location
will it map. Obviously the larger the number the more time it will take if your current location has
many many rooms around you.
The first hurdle here is what value to use for 'max_distance'. There is no reason for the worm to
travel further than what is actually displayed to you. For example, if your current location is
placed in the center of a display area of size `max_length = max_width = 9`, then the worm need only
go `4` spaces in either direction:
```
[.][.][.][.][@][.][.][.][.]
4 3 2 1 0 1 2 3 4
```
The max_distance can be set dynamically based on the size of the display area. As your width/length
changes it becomes a simple algebraic linear relationship which is simply `max_distance =
(min(max_width, max_length) -1) / 2`.
## Building the Mapper
Now we can start to fill our Map object with some methods. We are still missing a few methods that
are very important:
* `self.draw(self, room)` - responsible for actually drawing room to grid.
* `self.has_drawn(self, room)` - checks to see if the room has been mapped and worm has already been
here.
* `self.median(self, number)` - a simple utility method that finds the median (middle point) from 0,
n
* `self.update_pos(self, room, exit_name)` - updates the worm's physical position by reassigning
self.curX/Y. .accordingly
* `self.start_loc_on_grid(self)` - the very first initial draw on the grid representing your
location in the middle of the grid
* 'self.show_map` - after everything is done convert the map into a readable string`
* `self.draw_room_on_map(self, room, max_distance)` - the main method that ties it all together.`
Now that we know which methods we need, let's refine our initial `__init__(self)` to pass some
conditional statements and set it up to start building the display.
```python
#mygame/world/map.py
class Map(object):
def __init__(self, caller, max_width=9, max_length=9):
self.caller = caller
self.max_width = max_width
self.max_length = max_length
self.worm_has_mapped = {}
self.curX = None
self.curY = None
if self.check_grid():
# we have to store the grid into a variable
self.grid = self.create_grid()
# we use the algebraic relationship
self.draw_room_on_map(caller.location,
((min(max_width, max_length) -1 ) / 2)
```
Here we check to see if the parameters for the grid are okay, then we create an empty canvas and map
our initial location as the first room!
As mentioned above, the code for the `self.draw_room_on_map()` is not much different than the Pseudo
code. The method is shown below:
```python
# in mygame/world/map.py, in the Map class
def draw_room_on_map(self, room, max_distance):
self.draw(room)
if max_distance == 0:
return
for exit in room.exits:
if exit.name not in ("north", "east", "west", "south"):
# we only map in the cardinal directions. Mapping up/down would be
# an interesting learning project for someone who wanted to try it.
continue
if self.has_drawn(exit.destination):
# we've been to the destination already, skip ahead.
continue
self.update_pos(room, exit.name.lower())
self.draw_room_on_map(exit.destination, max_distance - 1)
```
The first thing the "worm" does is to draw your current location in `self.draw`. Lets define that...
```python
#in mygame/word/map.py, in the Map class
def draw(self, room):
# draw initial ch location on map first!
if room == self.caller.location:
self.start_loc_on_grid()
self.worm_has_mapped[room] = [self.curX, self.curY]
else:
# map all other rooms
self.worm_has_mapped[room] = [self.curX, self.curY]
# this will use the sector_type Attribute or None if not set.
self.grid[self.curX][self.curY] = SYMBOLS[room.db.sector_type]
```
In `self.start_loc_on_grid()`:
```python
def median(self, num):
lst = sorted(range(0, num))
n = len(lst)
m = n -1
return (lst[n//2] + lst[m//2]) / 2.0
def start_loc_on_grid(self):
x = self.median(self.max_width)
y = self.median(self.max_length)
# x and y are floats by default, can't index lists with float types
x, y = int(x), int(y)
self.grid[x][y] = SYMBOLS['you']
self.curX, self.curY = x, y # updating worms current location
```
After the system has drawn the current map it checks to see if the `max_distance` is `0` (since this
is the inital start phase it is not). Now we handle the iteration once we have each individual exit
in the room. The first thing it does is check if the room the Worm is in has been mapped already..
lets define that...
```python
def has_drawn(self, room):
return True if room in self.worm_has_mapped.keys() else False
```
If `has_drawn` returns `False` that means the worm has found a room that hasn't been mapped yet. It
will then 'move' there. The self.curX/Y sort of lags behind, so we have to make sure to track the
position of the worm; we do this in `self.update_pos()` below.
```python
def update_pos(self, room, exit_name):
# this ensures the coordinates stays up to date
# to where the worm is currently at.
self.curX, self.curY = \
self.worm_has_mapped[room][0], self.worm_has_mapped[room][1]
# now we have to actually move the pointer
# variables depending on which 'exit' it found
if exit_name == 'east':
self.curY += 1
elif exit_name == 'west':
self.curY -= 1
elif exit_name == 'north':
self.curX -= 1
elif exit_name == 'south':
self.curX += 1
```
Once the system updates the position of the worm it feeds the new room back into the original
`draw_room_on_map()` and starts the process all over again..
That is essentially the entire thing. The final method is to bring it all together and make a nice
presentational string out of it using the `self.show_map()` method.
```python
def show_map(self):
map_string = ""
for row in self.grid:
map_string += " ".join(row)
map_string += "\n"
return map_string
```
## Using the Map
In order for the map to get triggered we store it on the Room typeclass. If we put it in
`return_appearance` we will get the map back every time we look at the room.
> `return_appearance` is a default Evennia hook available on all objects; it is called e.g. by the
`look` command to get the description of something (the room in this case).
```python
# in mygame/typeclasses/rooms.py
from evennia import DefaultRoom
from world.map import Map
class Room(DefaultRoom):
def return_appearance(self, looker):
# [...]
string = f"{Map(looker).show_map()}\n"
# Add all the normal stuff like room description,
# contents, exits etc.
string += "\n" + super().return_appearance(looker)
return string
```
Obviously this method of generating maps doesn't take into account of any doors or exits that are
hidden.. etc.. but hopefully it serves as a good base to start with. Like previously mentioned, it
is very important to have a solid foundation on rooms before implementing this. You can try this on
vanilla evennia by using @tunnel and essentially you can just create a long straight/edgy non-
looping rooms that will show on your in-game map.
The above example will display the map above the room description. You could also use an
[EvTable](github:evennia.utils.evtable) to place description and map next to each other. Some other
things you can do is to have a [Command](../Components/Commands.md) that displays with a larger radius, maybe with a
legend and other features.
Below is the whole `map.py` for your reference. You need to update your `Room` typeclass (see above)
to actually call it. Remember that to see different symbols for a location you also need to set the
`sector_type` Attribute on the room to one of the keys in the `SYMBOLS` dictionary. So in this
example, to make a room be mapped as `[.]` you would set the room's `sector_type` to
`"SECT_INSIDE"`. Try it out with `@set here/sector_type = "SECT_INSIDE"`. If you wanted all new
rooms to have a given sector symbol, you could change the default in the `SYMBOLS´ dictionary below,
or you could add the Attribute in the Room's `at_object_creation` method.
```python
#mygame/world/map.py
# These are keys set with the Attribute sector_type on the room.
# The keys None and "you" must always exist.
SYMBOLS = { None : ' . ', # for rooms without a sector_type attr
'you' : '[@]',
'SECT_INSIDE': '[.]' }
class Map(object):
def __init__(self, caller, max_width=9, max_length=9):
self.caller = caller
self.max_width = max_width
self.max_length = max_length
self.worm_has_mapped = {}
self.curX = None
self.curY = None
if self.check_grid():
# we actually have to store the grid into a variable
self.grid = self.create_grid()
self.draw_room_on_map(caller.location,
((min(max_width, max_length) -1 ) / 2))
def update_pos(self, room, exit_name):
# this ensures the pointer variables always
# stays up to date to where the worm is currently at.
self.curX, self.curY = \
self.worm_has_mapped[room][0], self.worm_has_mapped[room][1]
# now we have to actually move the pointer
# variables depending on which 'exit' it found
if exit_name == 'east':
self.curY += 1
elif exit_name == 'west':
self.curY -= 1
elif exit_name == 'north':
self.curX -= 1
elif exit_name == 'south':
self.curX += 1
def draw_room_on_map(self, room, max_distance):
self.draw(room)
if max_distance == 0:
return
for exit in room.exits:
if exit.name not in ("north", "east", "west", "south"):
# we only map in the cardinal directions. Mapping up/down would be
# an interesting learning project for someone who wanted to try it.
continue
if self.has_drawn(exit.destination):
# we've been to the destination already, skip ahead.
continue
self.update_pos(room, exit.name.lower())
self.draw_room_on_map(exit.destination, max_distance - 1)
def draw(self, room):
# draw initial caller location on map first!
if room == self.caller.location:
self.start_loc_on_grid()
self.worm_has_mapped[room] = [self.curX, self.curY]
else:
# map all other rooms
self.worm_has_mapped[room] = [self.curX, self.curY]
# this will use the sector_type Attribute or None if not set.
self.grid[self.curX][self.curY] = SYMBOLS[room.db.sector_type]
def median(self, num):
lst = sorted(range(0, num))
n = len(lst)
m = n -1
return (lst[n//2] + lst[m//2]) / 2.0
def start_loc_on_grid(self):
x = self.median(self.max_width)
y = self.median(self.max_length)
# x and y are floats by default, can't index lists with float types
x, y = int(x), int(y)
self.grid[x][y] = SYMBOLS['you']
self.curX, self.curY = x, y # updating worms current location
def has_drawn(self, room):
return True if room in self.worm_has_mapped.keys() else False
def create_grid(self):
# This method simply creates an empty grid
# with the specified variables from __init__(self):
board = []
for row in range(self.max_width):
board.append([])
for column in range(self.max_length):
board[row].append(' ')
return board
def check_grid(self):
# this method simply checks the grid to make sure
# both max_l and max_w are odd numbers
return True if self.max_length % 2 != 0 or \
self.max_width % 2 != 0 else False
def show_map(self):
map_string = ""
for row in self.grid:
map_string += " ".join(row)
map_string += "\n"
return map_string
```
## Final Comments
The Dynamic map could be expanded with further capabilities. For example, it could mark exits or
allow NE, SE etc directions as well. It could have colors for different terrain types. One could
also look into up/down directions and figure out how to display that in a good way.

View file

@ -1,416 +0,0 @@
# Static In Game Map
## Introduction
This tutorial describes the creation of an in-game map display based on a pre-drawn map. It also
details how to use the [Batch code processor](../Components/Batch-Code-Processor.md) for advanced building. There is
also the [Dynamic in-game map tutorial](./Dynamic-In-Game-Map.md) that works in the opposite direction,
by generating a map from an existing grid of rooms.
Evennia does not require its rooms to be positioned in a "logical" way. Your exits could be named
anything. You could make an exit "west" that leads to a room described to be in the far north. You
could have rooms inside one another, exits leading back to the same room or describing spatial
geometries impossible in the real world.
That said, most games *do* organize their rooms in a logical fashion, if nothing else to retain the
sanity of their players. And when they do, the game becomes possible to map. This tutorial will give
an example of a simple but flexible in-game map system to further help player's to navigate. We will
To simplify development and error-checking we'll break down the work into bite-size chunks, each
building on what came before. For this we'll make extensive use of the [Batch code processor](Batch-
Code-Processor), so you may want to familiarize yourself with that.
1. **Planning the map** - Here we'll come up with a small example map to use for the rest of the
tutorial.
2. **Making a map object** - This will showcase how to make a static in-game "map" object a
Character could pick up and look at.
3. **Building the map areas** - Here we'll actually create the small example area according to the
map we designed before.
4. **Map code** - This will link the map to the location so our output looks something like this:
```
crossroads(#3)
↑╚∞╝↑
≈↑│↑∩ The merger of two roads. To the north looms a mighty castle.
O─O─O To the south, the glow of a campfire can be seen. To the east lie
≈↑│↑∩ the vast mountains and to the west is heard the waves of the sea.
↑▲O▲↑
Exits: north(#8), east(#9), south(#10), west(#11)
```
We will henceforth assume your game folder is name named `mygame` and that you haven't modified the
default commands. We will also not be using [Colors](../Concepts/Colors.md) for our map since they
don't show in the documentation wiki.
## Planning the Map
Let's begin with the fun part! Maps in MUDs come in many different [shapes and
sizes](http://journal.imaginary-realities.com/volume-05/issue-01/modern-interface-modern-
mud/index.html). Some appear as just boxes connected by lines. Others have complex graphics that are
external to the game itself.
Our map will be in-game text but that doesn't mean we're restricted to the normal alphabet! If
you've ever selected the [Wingdings font](https://en.wikipedia.org/wiki/Wingdings) in Microsoft Word
you will know there are a multitude of other characters around to use. When creating your game with
Evennia you have access to the [UTF-8 character encoding](https://en.wikipedia.org/wiki/UTF-8) which
put at your disposal [thousands of letters, number and geometric shapes](https://mcdlr.com/utf-8/#1).
For this exercise, we've copy-and-pasted from the pallet of special characters used over at
[Dwarf Fortress](https://dwarffortresswiki.org/index.php/Character_table) to create what is hopefully
a pleasing and easy to understood landscape:
```
≈≈↑↑↑↑↑∩∩
≈≈↑╔═╗↑∩∩ Places the account can visit are indicated by "O".
≈≈↑║O║↑∩∩ Up the top is a castle visitable by the account.
≈≈↑╚∞╝↑∩∩ To the right is a cottage and to the left the beach.
≈≈≈↑│↑∩∩∩ And down the bottom is a camp site with tents.
≈≈O─O─O⌂∩ In the center is the starting location, a crossroads
≈≈≈↑│↑∩∩∩ which connect the four other areas.
≈≈↑▲O▲↑∩∩
≈≈↑↑▲↑↑∩∩
≈≈↑↑↑↑↑∩∩
```
There are many considerations when making a game map depending on the play style and requirements
you intend to implement. Here we will display a 5x5 character map of the area surrounding the
account. This means making sure to account for 2 characters around every visitable location. Good
planning at this stage can solve many problems before they happen.
## Creating a Map Object
In this section we will try to create an actual "map" object that an account can pick up and look
at.
Evennia offers a range of [default commands](../Components/Default-Commands.md) for
[creating objects and rooms in-game](../Howto/Starting/Part1/Building-Quickstart.md). While readily accessible, these commands are made to do very
specific, restricted things and will thus not offer as much flexibility to experiment (for an
advanced exception see [the FuncParser](../Components/FuncParser.md)). Additionally, entering long
descriptions and properties over and over in the game client can become tedious; especially when
testing and you may want to delete and recreate things over and over.
To overcome this, Evennia offers [batch processors](../Components/Batch-Processors.md) that work as input-files
created out-of-game. In this tutorial we'll be using the more powerful of the two available batch
processors, the [Batch Code Processor ](../Components/Batch-Code-Processor.md), called with the `@batchcode` command.
This is a very powerful tool. It allows you to craft Python files to act as blueprints of your
entire game world. These files have access to use Evennia's Python API directly. Batchcode allows
for easy editing and creation in whatever text editor you prefer, avoiding having to manually build
the world line-by-line inside the game.
> Important warning: `@batchcode`'s power is only rivaled by the `@py` command. Batchcode is so
powerful it should be reserved only for the [superuser](../Concepts/Building-Permissions.md). Think carefully
before you let others (such as `Developer`- level staff) run `@batchcode` on their own - make sure
you are okay with them running *arbitrary Python code* on your server.
While a simple example, the map object it serves as good way to try out `@batchcode`. Go to
`mygame/world` and create a new file there named `batchcode_map.py`:
```Python
# mygame/world/batchcode_map.py
from evennia import create_object
from evennia import DefaultObject
# We use the create_object function to call into existence a
# DefaultObject named "Map" wherever you are standing.
map = create_object(DefaultObject, key="Map", location=caller.location)
# We then access its description directly to make it our map.
map.db.desc = """
≈≈↑↑↑↑↑∩∩
≈≈↑╔═╗↑∩∩
≈≈↑║O║↑∩∩
≈≈↑╚∞╝↑∩∩
≈≈≈↑│↑∩∩∩
≈≈O─O─O⌂∩
≈≈≈↑│↑∩∩∩
≈≈↑▲O▲↑∩∩
≈≈↑↑▲↑↑∩∩
≈≈↑↑↑↑↑∩∩
"""
# This message lets us know our map was created successfully.
caller.msg("A map appears out of thin air and falls to the ground.")
```
Log into your game project as the superuser and run the command
```
@batchcode batchcode_map
```
This will load your `batchcode_map.py` file and execute the code (Evennia will look in your `world/`
folder automatically so you don't need to specify it).
A new map object should have appeared on the ground. You can view the map by using `look map`. Let's
take it with the `get map` command. We'll need it in case we get lost!
## Building the map areas
We've just used batchcode to create an object useful for our adventures. But the locations on that
map does not actually exist yet - we're all mapped up with nowhere to go! Let's use batchcode to
build a game area based on our map. We have five areas outlined: a castle, a cottage, a campsite, a
coastal beach and the crossroads which connects them. Create a new batchcode file for this in
`mygame/world`, named `batchcode_world.py`.
```Python
# mygame/world/batchcode_world.py
from evennia import create_object, search_object
from typeclasses import rooms, exits
# We begin by creating our rooms so we can detail them later.
centre = create_object(rooms.Room, key="crossroads")
north = create_object(rooms.Room, key="castle")
east = create_object(rooms.Room, key="cottage")
south = create_object(rooms.Room, key="camp")
west = create_object(rooms.Room, key="coast")
# This is where we set up the cross roads.
# The rooms description is what we see with the 'look' command.
centre.db.desc = """
The merger of two roads. A single lamp post dimly illuminates the lonely crossroads.
To the north looms a mighty castle. To the south the glow of a campfire can be seen.
To the east lie a wall of mountains and to the west the dull roar of the open sea.
"""
# Here we are creating exits from the centre "crossroads" location to
# destinations to the north, east, south, and west. We will be able
# to use the exit by typing it's key e.g. "north" or an alias e.g. "n".
centre_north = create_object(exits.Exit, key="north",
aliases=["n"], location=centre, destination=north)
centre_east = create_object(exits.Exit, key="east",
aliases=["e"], location=centre, destination=east)
centre_south = create_object(exits.Exit, key="south",
aliases=["s"], location=centre, destination=south)
centre_west = create_object(exits.Exit, key="west",
aliases=["w"], location=centre, destination=west)
# Now we repeat this for the other rooms we'll be implementing.
# This is where we set up the northern castle.
north.db.desc = "An impressive castle surrounds you. " \
"There might be a princess in one of these towers."
north_south = create_object(exits.Exit, key="south",
aliases=["s"], location=north, destination=centre)
# This is where we set up the eastern cottage.
east.db.desc = "A cosy cottage nestled among mountains " \
"stretching east as far as the eye can see."
east_west = create_object(exits.Exit, key="west",
aliases=["w"], location=east, destination=centre)
# This is where we set up the southern camp.
south.db.desc = "Surrounding a clearing are a number of " \
"tribal tents and at their centre a roaring fire."
south_north = create_object(exits.Exit, key="north",
aliases=["n"], location=south, destination=centre)
# This is where we set up the western coast.
west.db.desc = "The dark forest halts to a sandy beach. " \
"The sound of crashing waves calms the soul."
west_east = create_object(exits.Exit, key="east",
aliases=["e"], location=west, destination=centre)
# Lastly, lets make an entrance to our world from the default Limbo room.
limbo = search_object('Limbo')[0]
limbo_exit = create_object(exits.Exit, key="enter world",
aliases=["enter"], location=limbo, destination=centre)
```
Apply this new batch code with `@batchcode batchcode_world`. If there are no errors in the code we
now have a nice mini-world to explore. Remember that if you get lost you can look at the map we
created!
## In-game minimap
Now we have a landscape and matching map, but what we really want is a mini-map that displays
whenever we move to a room or use the `look` command.
We *could* manually enter a part of the map into the description of every room like we did our map
object description. But some MUDs have tens of thousands of rooms! Besides, if we ever changed our
map we would have to potentially alter a lot of those room descriptions manually to match the
change. So instead we will make one central module to hold our map. Rooms will reference this
central location on creation and the map changes will thus come into effect when next running our
batchcode.
To make our mini-map we need to be able to cut our full map into parts. To do this we need to put it
in a format which allows us to do that easily. Luckily, python allows us to treat strings as lists
of characters allowing us to pick out the characters we need.
`mygame/world/map_module.py`
```Python
# We place our map into a sting here.
world_map = """\
≈≈↑↑↑↑↑∩∩
≈≈↑╔═╗↑∩∩
≈≈↑║O║↑∩∩
≈≈↑╚∞╝↑∩∩
≈≈≈↑│↑∩∩∩
≈≈O─O─O⌂∩
≈≈≈↑│↑∩∩∩
≈≈↑▲O▲↑∩∩
≈≈↑↑▲↑↑∩∩
≈≈↑↑↑↑↑∩∩
"""
# This turns our map string into a list of rows. Because python
# allows us to treat strings as a list of characters, we can access
# those characters with world_map[5][5] where world_map[row][column].
world_map = world_map.split('\n')
def return_map():
"""
This function returns the whole map
"""
map = ""
#For each row in our map, add it to map
for valuey in world_map:
map += valuey
map += "\n"
return map
def return_minimap(x, y, radius = 2):
"""
This function returns only part of the map.
Returning all chars in a 2 char radius from (x,y)
"""
map = ""
#For each row we need, add the characters we need.
for valuey in world_map[y-radius:y+radius+1]: for valuex in valuey[x-radius:x+radius+1]:
map += valuex
map += "\n"
return map
```
With our map_module set up, let's replace our hardcoded map in `mygame/world/batchcode_map.py` with
a reference to our map module. Make sure to import our map_module!
```python
# mygame/world/batchcode_map.py
from evennia import create_object
from evennia import DefaultObject
from world import map_module
map = create_object(DefaultObject, key="Map", location=caller.location)
map.db.desc = map_module.return_map()
caller.msg("A map appears out of thin air and falls to the ground.")
```
Log into Evennia as the superuser and run this batchcode. If everything worked our new map should
look exactly the same as the old map - you can use `@delete` to delete the old one (use a number to
pick which to delete).
Now, lets turn our attention towards our game's rooms. Let's use the `return_minimap` method we
created above in order to include a minimap in our room descriptions. This is a little more
complicated.
By itself we would have to settle for either the map being *above* the description with
`room.db.desc = map_string + description_string`, or the map going *below* by reversing their order.
Both options are rather unsatisfactory - we would like to have the map next to the text! For this
solution we'll explore the utilities that ship with Evennia. Tucked away in `evennia\evennia\utils`
is a little module called [EvTable](github:evennia.utils.evtable) . This is an advanced ASCII table
creator for you to utilize in your game. We'll use it by creating a basic table with 1 row and two
columns (one for our map and one for our text) whilst also hiding the borders. Open the batchfile
again
```python
# mygame\world\batchcode_world.py
# Add to imports
from evennia.utils import evtable
from world import map_module
# [...]
# Replace the descriptions with the below code.
# The cross roads.
# We pass what we want in our table and EvTable does the rest.
# Passing two arguments will create two columns but we could add more.
# We also specify no border.
centre.db.desc = evtable.EvTable(map_module.return_minimap(4,5),
"The merger of two roads. A single lamp post dimly " \
"illuminates the lonely crossroads. To the north " \
"looms a mighty castle. To the south the glow of " \
"a campfire can be seen. To the east lie a wall of " \
"mountains and to the west the dull roar of the open sea.",
border=None)
# EvTable allows formatting individual columns and cells. We use that here
# to set a maximum width for our description, but letting the map fill
# whatever space it needs.
centre.db.desc.reformat_column(1, width=70)
# [...]
# The northern castle.
north.db.desc = evtable.EvTable(map_module.return_minimap(4,2),
"An impressive castle surrounds you. There might be " \
"a princess in one of these towers.",
border=None)
north.db.desc.reformat_column(1, width=70)
# [...]
# The eastern cottage.
east.db.desc = evtable.EvTable(map_module.return_minimap(6,5),
"A cosy cottage nestled among mountains stretching " \
"east as far as the eye can see.",
border=None)
east.db.desc.reformat_column(1, width=70)
# [...]
# The southern camp.
south.db.desc = evtable.EvTable(map_module.return_minimap(4,7),
"Surrounding a clearing are a number of tribal tents " \
"and at their centre a roaring fire.",
border=None)
south.db.desc.reformat_column(1, width=70)
# [...]
# The western coast.
west.db.desc = evtable.EvTable(map_module.return_minimap(2,5),
"The dark forest halts to a sandy beach. The sound of " \
"crashing waves calms the soul.",
border=None)
west.db.desc.reformat_column(1, width=70)
```
Before we run our new batchcode, if you are anything like me you would have something like 100 maps
lying around and 3-4 different versions of our rooms extending from limbo. Let's wipe it all and
start with a clean slate. In Command Prompt you can run `evennia flush` to clear the database and
start anew. It won't reset dbref values however, so if you are at #100 it will start from there.
Alternatively you can navigate to `mygame/server` and delete the `evennia.db3` file. Now in Command
Prompt use `evennia migrate` to have a completely freshly made database.
Log in to evennia and run `@batchcode batchcode_world` and you'll have a little world to explore.
## Conclusions
You should now have a mapped little world and a basic understanding of batchcode, EvTable and how
easily new game defining features can be added to Evennia.
You can easily build from this tutorial by expanding the map and creating more rooms to explore. Why
not add more features to your game by trying other tutorials: [Add weather to your world](Weather-
Tutorial), [fill your world with NPC's](../Howto/Tutorial-Aggressive-NPCs.md) or
[implement a combat system](../Howto/Starting/Part3/Turn-based-Combat-System.md).

File diff suppressed because it is too large Load diff