Updated HTML docs

This commit is contained in:
Griatch 2021-10-26 21:41:11 +02:00
parent 66d0ad0bc9
commit 7900aad365
2073 changed files with 32986 additions and 41197 deletions

View file

@ -1,45 +1,45 @@
# Accounts
All *users* (real people) that starts a game [Session](./Sessions) on Evennia are doing so through an
All *users* (real people) that starts a game [Session](./Sessions.md) on Evennia are doing so through an
object called *Account*. The Account object has no in-game representation, it represents a unique
game account. In order to actually get on the game the Account must *puppet* an [Object](./Objects)
(normally a [Character](./Objects#Character)).
game account. In order to actually get on the game the Account must *puppet* an [Object](./Objects.md)
(normally a [Character](./Objects.md#characters)).
Exactly how many Sessions can interact with an Account and its Puppets at once is determined by
Evennia's [MULTISESSION_MODE](./Sessions#Multisession-mode) setting.
Evennia's [MULTISESSION_MODE](./Sessions.md#multisession-mode) setting.
Apart from storing login information and other account-specific data, the Account object is what is
chatting on [Channels](./Communications). It is also a good place to store [Permissions](./Locks) to be
chatting on [Channels](./Communications.md). It is also a good place to store [Permissions](./Locks.md) to be
consistent between different in-game characters as well as configuration options. The Account
object also has its own [CmdSet](./Command-Sets), the `AccountCmdSet`.
object also has its own [CmdSet](./Command-Sets.md), the `AccountCmdSet`.
Logged into default evennia, you can use the `ooc` command to leave your current
[character](./Objects) and go into OOC mode. You are quite limited in this mode, basically it works
[character](./Objects.md) and go into OOC mode. You are quite limited in this mode, basically it works
like a simple chat program. It acts as a staging area for switching between Characters (if your
game supports that) or as a safety mode if your Character gets deleted. Use `ic` to attempt to
(re)puppet a Character.
(re)puppet a Character.
Note that the Account object can have, and often does have, a different set of
[Permissions](./Locks#Permissions) from the Character they control. Normally you should put your
[Permissions](./Permissions.md) from the Character they control. Normally you should put your
permissions on the Account level - this will overrule permissions set on the Character level. For
the permissions of the Character to come into play the default `quell` command can be used. This
allows for exploring the game using a different permission set (but you can't escalate your
permissions this way - for hierarchical permissions like `Builder`, `Admin` etc, the *lower* of the
permissions on the Character/Account will always be used).
permissions on the Character/Account will always be used).
## How to create your own Account types
You will usually not want more than one Account typeclass for all new accounts (but you could in
principle create a system that changes an account's typeclass dynamically).
principle create a system that changes an account's typeclass dynamically).
An Evennia Account is, per definition, a Python class that includes `evennia.DefaultAccount` among
its parents. In `mygame/typeclasses/accounts.py` there is an empty class ready for you to modify.
Evennia defaults to using this (it inherits directly from `DefaultAccount`).
Evennia defaults to using this (it inherits directly from `DefaultAccount`).
Here's an example of modifying the default Account class in code:
Here's an example of modifying the default Account class in code:
```python
```python
# in mygame/typeclasses/accounts.py
from evennia import DefaultAccount
@ -51,7 +51,7 @@ Here's an example of modifying the default Account class in code:
self.db.config_1 = True # default config self.db.config_2 = False # "
self.db.config_3 = 1 # "
# ... whatever else our game needs to know ``` Reload the server with `reload`.
# ... whatever else our game needs to know ``` Reload the server with `reload`.
```
@ -65,7 +65,7 @@ using `py`:
``` py [account.at_account_creation() for account in evennia.managers.accounts.all()] ```
You should now see the Attributes on yourself.
You should now see the Attributes on yourself.
> If you wanted Evennia to default to a completely *different* Account class located elsewhere, you
@ -76,8 +76,8 @@ You should now see the Attributes on yourself.
## Properties on Accounts
Beyond those properties assigned to all typeclassed objects (see [Typeclasses](./Typeclasses)), the
Account also has the following custom properties:
Beyond those properties assigned to all typeclassed objects (see [Typeclasses](./Typeclasses.md)), the
Account also has the following custom properties:
- `user` - a unique link to a `User` Django object, representing the logged-in user.
- `obj` - an alias for `character`.
@ -91,12 +91,12 @@ as
- `is_superuser` (bool: True/False) - if this account is a superuser.
Special handlers:
- `cmdset` - This holds all the current [Commands](./Commands) of this Account. By default these are
- `cmdset` - This holds all the current [Commands](./Commands.md) of this Account. By default these are
the commands found in the cmdset defined by `settings.CMDSET_ACCOUNT`.
- `nicks` - This stores and handles [Nicks](./Nicks), in the same way as nicks it works on Objects.
- `nicks` - This stores and handles [Nicks](./Nicks.md), in the same way as nicks it works on Objects.
For Accounts, nicks are primarily used to store custom aliases for
[Channels](./Communications#Channels).
[Channels](./Channels.md).
Selection of special methods (see `evennia.DefaultAccount` for details):
- `get_puppet` - get a currently puppeted object connected to the Account and a given session id, if
any.
@ -104,4 +104,4 @@ Selection of special methods (see `evennia.DefaultAccount` for details):
- `unpuppet_object` - disconnect a session from a puppetable Object.
- `msg` - send text to the Account
- `execute_cmd` - runs a command as if this Account did it.
- `search` - search for Accounts.
- `search` - search for Accounts.

View file

@ -7,8 +7,8 @@ can give correct subsequent commands. If you are writing a combat system, you mi
combattant's next roll get easier dependent on if their opponent failed. Your characters will
probably need to store roleplaying-attributes like strength and agility. And so on.
[Typeclassed](./Typeclasses) game entities ([Accounts](./Accounts), [Objects](./Objects),
[Scripts](./Scripts) and [Channels](./Communications)) always have *Attributes* associated with them.
[Typeclassed](./Typeclasses.md) game entities ([Accounts](./Accounts.md), [Objects](./Objects.md),
[Scripts](./Scripts.md) and [Channels](./Communications.md)) always have *Attributes* associated with them.
Attributes are used to store any type of data 'on' such entities. This is different from storing
data in properties already defined on entities (such as `key` or `location`) - these have very
specific names and require very specific types of data (for example you couldn't assign a python
@ -16,12 +16,12 @@ specific names and require very specific types of data (for example you couldn't
want to assign arbitrary data to arbitrary names.
**Attributes are _not_ secure by default and any player may be able to change them unless you
[prevent this behavior](./Attributes#locking-and-checking-attributes).**
[prevent this behavior](./Attributes.md#locking-and-checking-attributes).**
## The .db and .ndb shortcuts
To save persistent data on a Typeclassed object you normally use the `db` (DataBase) operator. Let's
try to save some data to a *Rose* (an [Object](./Objects)):
try to save some data to a *Rose* (an [Object](./Objects.md)):
```python
# saving
@ -87,13 +87,13 @@ The handlers have normal access methods that allow you to manage and retrieve `A
returned, but the method takes keywords for returning the Attribute object itself. By supplying an
`accessing_object` to the call one can also make sure to check permissions before modifying
anything.
- `add(...)` - this adds a new Attribute to the object. An optional [lockstring](./Locks) can be
- `add(...)` - this adds a new Attribute to the object. An optional [lockstring](./Locks.md) can be
supplied here to restrict future access and also the call itself may be checked against locks.
- `remove(...)` - Remove the given Attribute. This can optionally be made to check for permission
before performing the deletion. - `clear(...)` - removes all Attributes from object.
- `all(...)` - returns all Attributes (of the given category) attached to this object.
See [this section](./Attributes#locking-and-checking-attributes) for more about locking down Attribute
See [this section](./Attributes.md#locking-and-checking-attributes) for more about locking down Attribute
access and editing. The `Nattribute` offers no concept of access control.
Some examples:
@ -118,23 +118,23 @@ An Attribute object is stored in the database. It has the following properties:
to `attrname`.
- `value` - this is the value of the Attribute. This value can be anything which can be pickled -
objects, lists, numbers or what have you (see
[this section](./Attributes#What_types_of_data_can_I_save_in_an_Attribute) for more info). In the
[this section](./Attributes.md#what-types-of-data-can-i-save-in-an-attribute) for more info). In the
example
`obj.db.attrname = value`, the `value` is stored here.
- `category` - this is an optional property that is set to None for most Attributes. Setting this
allows to use Attributes for different functionality. This is usually not needed unless you want
to use Attributes for very different functionality ([Nicks](./Nicks) is an example of using
to use Attributes for very different functionality ([Nicks](./Nicks.md) is an example of using
Attributes
in this way). To modify this property you need to use the [Attribute
Handler](Attributes#The_Attribute_Handler).
in this way). To modify this property you need to use the
[Attribute Handler](./Attributes.md#the-attributehandler).
- `strvalue` - this is a separate value field that only accepts strings. This severely limits the
data possible to store, but allows for easier database lookups. This property is usually not used
except when re-using Attributes for some other purpose ([Nicks](./Nicks) use it). It is only
accessible via the [Attribute Handler](./Attributes#The_Attribute_Handler).
except when re-using Attributes for some other purpose ([Nicks](./Nicks.md) use it). It is only
accessible via the [Attribute Handler](./Attributes.md#the-attributehandler).
There are also two special properties:
- `attrtype` - this is used internally by Evennia to separate [Nicks](./Nicks), from Attributes (Nicks
- `attrtype` - this is used internally by Evennia to separate [Nicks](./Nicks.md), from Attributes (Nicks
use Attributes behind the scenes).
- `model` - this is a *natural-key* describing the model this Attribute is attached to. This is on
the form *appname.modelclass*, like `objects.objectdb`. It is used by the Attribute and
@ -162,7 +162,7 @@ default
during heavy loads.
- A more valid reason for using non-persistent data is if you *want* to lose your state when logging
off. Maybe you are storing throw-away data that are re-initialized at server startup. Maybe you
are implementing some caching of your own. Or maybe you are testing a buggy [Script](./Scripts) that
are implementing some caching of your own. Or maybe you are testing a buggy [Script](./Scripts.md) that
does potentially harmful stuff to your character object. With non-persistent storage you can be
sure
that whatever is messed up, it's nothing a server reboot can't clear up.
@ -192,7 +192,7 @@ not a big deal. But if you are accessing the Attribute as part of some big loop
amount of reads/writes you should first extract it to a temporary variable, operate on *that* and
then save the result back to the Attribute. If you are storing a more complex structure like a
`dict` or a `list` you should make sure to "disconnect" it from the database before looping over it,
as mentioned in the [Retrieving Mutable Objects](./Attributes#retrieving-mutable-objects) section
as mentioned in the [Retrieving Mutable Objects](./Attributes.md#retrieving-mutable-objects) section
below.
### Storing single objects
@ -248,7 +248,7 @@ containing dicts, etc.
Since you can use any combination of the above iterables, this is generally not much of a
limitation.
Any entity listed in the [Single object](./Attributes#Storing-Single-Objects) section above can be
Any entity listed in the [Single object](./Attributes.md#storing-single-objects) section above can be
stored in the iterable.
> As mentioned in the previous section, database entities (aka typeclasses) are not possible to
@ -355,7 +355,7 @@ already disconnected from the database from the onset.
Attributes are normally not locked down by default, but you can easily change that for individual
Attributes (like those that may be game-sensitive in games with user-level building).
First you need to set a *lock string* on your Attribute. Lock strings are specified [Locks](./Locks).
First you need to set a *lock string* on your Attribute. Lock strings are specified [Locks](./Locks.md).
The relevant lock types are
- `attrread` - limits who may read the value of the Attribute

View file

@ -1,7 +1,7 @@
# Batch Code Processor
For an introduction and motivation to using batch processors, see [here](./Batch-Processors). This
For an introduction and motivation to using batch processors, see [here](./Batch-Processors.md). This
page describes the Batch-*code* processor. The Batch-*command* one is covered [here](Batch-Command-
Processor).
@ -191,7 +191,7 @@ connect that room with a room you built in the current block. There are two ways
- Perform a database search for the name of the room you created (since you cannot know in advance
which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of "A
dark forest" rooms). There is an easy way to handle this though - use [Tags](./Tags) or *Aliases*. You
dark forest" rooms). There is an easy way to handle this though - use [Tags](./Tags.md) or *Aliases*. You
can assign any number of tags and/or aliases to any object. Make sure that one of those tags or
aliases is unique to the room (like "room56") and you will henceforth be able to always uniquely
search and find it later.

View file

@ -1,7 +1,7 @@
# Batch Command Processor
For an introduction and motivation to using batch processors, see [here](./Batch-Processors). This
For an introduction and motivation to using batch processors, see [here](./Batch-Processors.md). This
page describes the Batch-*command* processor. The Batch-*code* one is covered [here](Batch-Code-
Processor).
@ -152,7 +152,7 @@ when creating the file, so that you can 'walk' (or teleport) to the right places
This also means there are several pitfalls when designing and adding certain types of objects. Here
are some examples:
- *Rooms that change your [Command Set](./Command-Sets)*: Imagine that you build a 'dark' room, which
- *Rooms that change your [Command Set](./Command-Sets.md)*: Imagine that you build a 'dark' room, which
severely limits the cmdsets of those entering it (maybe you have to find the light switch to
proceed). In your batch script you would create this room, then teleport to it - and promptly be
shifted into the dark state where none of your normal build commands work ...
@ -172,7 +172,7 @@ The fact that you build as 'yourself' can also be considered an advantage howeve
decide to change the default command to allow others than superusers to call the processor. Since
normal access-checks are still performed, a malevolent builder with access to the processor should
not be able to do all that much damage (this is the main drawback of the [Batch Code
Processor](Batch-Code-Processor))
Processor](./Batch-Code-Processor.md))
- [GNU Emacs](https://www.gnu.org/software/emacs/) users might find it interesting to use emacs'
*evennia mode*. This is an Emacs major mode found in `evennia/utils/evennia-mode.el`. It offers

View file

@ -35,8 +35,8 @@ just list in-game commands in a text file. The code-processor on the other hand
powerful but also more complex - it lets you use Evennia's API to code your world in full-fledged
Python code.
- The [Batch Command Processor](./Batch-Command-Processor)
- The [Batch Code Processor](./Batch-Code-Processor)
- The [Batch Command Processor](./Batch-Command-Processor.md)
- The [Batch Code Processor](./Batch-Code-Processor.md)
If you plan to use international characters in your batchfiles you are wise to read about *file
encodings* below.
@ -73,7 +73,7 @@ need to add the editor's encoding to Evennia's `ENCODINGS` list. If you are unsu
file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works
as it should.
More help with encodings can be found in the entry [Text Encodings](../Concepts/Text-Encodings) and also in the
More help with encodings can be found in the entry [Text Encodings](../Concepts/Text-Encodings.md) and also in the
Wikipedia article [here](https://en.wikipedia.org/wiki/Text_encodings).
**A footnote for the batch-code processor**: Just because *Evennia* can parse your file and your

View file

@ -2,8 +2,8 @@
Bootstrap provides many utilities and components you can use when customizing Evennia's web
presence. We'll go over a few examples here that you might find useful.
> Please take a look at either [the basic web tutorial](../Howto/Starting/Part5/Add-a-simple-new-web-page) or
>[the web character view tutorial](../Howto/Web-Character-View-Tutorial)
> Please take a look at either [the basic web tutorial](../Howto/Starting/Part5/Add-a-simple-new-web-page.md) or
>[the web character view tutorial](../Howto/Web-Character-View-Tutorial.md)
> to get a feel for how to add pages to Evennia's website to test these examples.
## General Styling
@ -77,4 +77,4 @@ width of the page - Evennia's base site uses the former.
### Forms
[Forms](https://getbootstrap.com/docs/4.0/components/forms/) are highly customizable with Bootstrap.
For a more in-depth look at how to use forms and their styles in your own Evennia site, please read
over [the web character gen tutorial.](../Howto/Web-Character-Generation)
over [the web character gen tutorial.](../Howto/Web-Character-Generation.md)

View file

@ -7,8 +7,8 @@ _Channels_ allows Evennia's to act as a fancy chat program. When a player is
connected to a channel, sending a message to it will automatically distribute
it to every other subscriber.
Channels can be used both for chats between [Accounts](./Accounts) and between
[Objects](./Objects) (usually Characters). Chats could be both OOC
Channels can be used both for chats between [Accounts](./Accounts.md) and between
[Objects](./Objects.md) (usually Characters). Chats could be both OOC
(out-of-character) or IC (in-charcter) in nature. Some examples:
- A support channel for contacting staff (OOC)
@ -20,7 +20,7 @@ Channels can be used both for chats between [Accounts](./Accounts) and between
- Group telephathy (IC)
- Walkie talkies (IC)
```versionchanged:: 1.0
```{versionchanged} 1.0
Channel system changed to use a central 'channel' command and nicks instead of
auto-generated channel-commands and -cmdset. ChannelHandler was removed.
@ -30,7 +30,8 @@ Channels can be used both for chats between [Accounts](./Accounts) and between
## Using channels in-game
In the default command set, channels are all handled via the mighty
[channel command](api:evennia.commands.default.comms.CmdChannel), `channel` (or
[channel
command](evennia.commands.default.comms.CmdChannel), `channel` (or
`chan`). By default, this command will assume all entities dealing with
channels are `Accounts`.
@ -66,7 +67,7 @@ system automatically sets up an personal alias so you can do this instead:
public Hello world
```warning::
```{warning}
This shortcut will not work if the channel-name has spaces in it.
So channels with long names should make sure to provide a one-word alias as
@ -91,7 +92,7 @@ But you can also use your alias with the `channel` command:
channel foo Hello world!
> What happens when aliasing is that a [nick](./Nicks) is created that maps your
> What happens when aliasing is that a [nick](./Nicks.md) is created that maps your
> alias + argument onto calling the `channel` command. So when you enter `foo hello`,
> what the server sees is actually `channel foo = hello`. The system is also
> clever enough to know that whenever you search for channels, your channel-nicks
@ -140,10 +141,10 @@ Banning adds the user to the channels blacklist. This means they will not be
able to _rejoin_ if you boot them. You will need to run `channel/boot` to
actually kick them out.
See the [Channel command](api:evennia.commands.default.comms.CmdChannel) api
See the [Channel command](evennia.commands.default.comms.CmdChannel) api
docs (and in-game help) for more details.
Admin-level users can also modify channel's [locks](./Locks):
Admin-level users can also modify channel's [locks](./Locks.md):
channel/lock buildchannel = listen:all();send:perm(Builders)
@ -158,7 +159,7 @@ Channels use three lock-types by default:
#### Restricting channel administration
By default everyone can use the channel command ([evennia.commands.default.comms.CmdChannel](api:evennia.commands.default.comms.CmdChannel))
By default everyone can use the channel command ([evennia.commands.default.comms.CmdChannel](evennia.commands.default.comms.CmdChannel))
to create channels and will then control the channels they created (to boot/ban
people etc). If you as a developer does not want regular players to do this
(perhaps you want only staff to be able to spawn new channels), you can
@ -170,7 +171,7 @@ The default `help` command has the following `locks` property:
locks = "cmd:not perm(channel_banned); admin:all(); manage:all(); changelocks: perm(Admin)"
```
This is a regular [lockstring](./Locks).
This is a regular [lockstring](./Locks.md).
- `cmd: pperm(channel_banned)` - The `cmd` locktype is the standard one used for all Commands.
an accessing object failing this will not even know that the command exists. The `pperm()` lockfunc
@ -204,14 +205,14 @@ access-denied error when trying to use use these switches.
## Allowing Characters to use Channels
The default `channel` command ([evennia.commands.default.comms.CmdChannel](api:evennia.commands.default.comms.CmdChannel))
sits in the `Account` [command set](./Command-Sets). It is set up such that it will
The default `channel` command ([evennia.commands.default.comms.CmdChannel](evennia.commands.default.comms.CmdChannel))
sits in the `Account` [command set](./Command-Sets.md). It is set up such that it will
always operate on `Accounts`, even if you were to add it to the
`CharacterCmdSet`.
It's a one-line change to make this command accept non-account callers. But for
convenience we provide a version for Characters/Objects. Just import
[evennia.commands.default.comms.CmdObjectChannel](api:evennia.commands.default.comms.CmdObjectChannel)
[evennia.commands.default.comms.CmdObjectChannel](evennia.commands.default.comms.CmdObjectChannel)
and inherit from that instead.
## Customizing channel output and behavior
@ -248,13 +249,13 @@ For most common changes, the default channel, the recipient hooks and possibly
overriding the `channel` command will get you very far. But you can also tweak
channels themselves.
Channels are [Typeclassed](./Typeclasses) entities. This means they are
persistent in the database, can have [attributes](./Attributes) and [Tags](./Tags)
Channels are [Typeclassed](./Typeclasses.md) entities. This means they are
persistent in the database, can have [attributes](./Attributes.md) and [Tags](./Tags.md)
and can be easily extended.
To change which channel typeclass Evennia uses for default commands, change
`settings.BASE_CHANNEL_TYPECLASS`. The base command class is
[`evennia.comms.comms.DefaultChannel`](api:evennia.comms.comms.DefaultChannel).
[`evennia.comms.comms.DefaultChannel`](evennia.comms.comms.DefaultChannel).
There is an empty child class in `mygame/typeclasses/channels.py`, same
as for other typelass-bases.
@ -299,11 +300,11 @@ details.
## Channel logging
```versionchanged:: 0.7
```{versionchanged} 0.7
Channels changed from using Msg to TmpMsg and optional log files.
```
```versionchanged:: 1.0
```{versionchanged} 1.0
Channels stopped supporting Msg and TmpMsg, using only log files.
```
@ -325,7 +326,7 @@ channel's `at_post_channel_msg` method.
Channels have all the standard properties of a Typeclassed entity (`key`,
`aliases`, `attributes`, `tags`, `locks` etc). This is not an exhaustive list;
see the [Channel api docs](api:evennia.comms.comms.DefaultChannel) for details.
see the [Channel api docs](evennia.comms.comms.DefaultChannel) for details.
- `send_to_online_only` - this class boolean defaults to `True` and is a
sensible optimization since people offline people will not see the message anyway.
@ -334,8 +335,8 @@ see the [Channel api docs](api:evennia.comms.comms.DefaultChannel) for details.
`mygame/server/logs/`). You should usually not change this.
- `channel_prefix_string` - this property is a string to easily change how
the channel is prefixed. It takes the `channelname` format key. Default is `"[{channelname}] "`
and produces output like `[public] ...``.
- `subscriptions` - this is the [SubscriptionHandler](api:evennia.comms.comms#SubscriptionHandler), which
and produces output like `[public] ...`.
- `subscriptions` - this is the [SubscriptionHandler](evennia.comms.models.SubscriptionHandler), which
has methods `has`, `add`, `remove`, `all`, `clear` and also `online` (to get
only actually online channel-members).
- `wholist`, `mutelist`, `banlist` are properties that return a list of subscribers,
@ -345,7 +346,7 @@ see the [Channel api docs](api:evennia.comms.comms.DefaultChannel) for details.
This pattern accepts an `{alias}` formatting marker. Don't mess with this unless you really
want to change how channels work.
- `channel_msg_nick_replacement` - this is a string on the [nick replacement
- form](Nicks). It accepts the `{channelname}` formatting tag. This is strongly tied to the
- form](./Nicks.md). It accepts the `{channelname}` formatting tag. This is strongly tied to the
`channel` command and is by default `channel {channelname} = $1`.
Notable `Channel` hooks:

View file

@ -29,13 +29,13 @@ If you need to search for objects in a code module you can use the functions in
obj = search_object(objname)
```
- [evennia.search_account](../wiki/evennia.accounts.manager#accountdbmanagersearch_account)
- [evennia.search_object](../wiki/evennia.objects.manager#objectdbmanagersearch_object)
- [evennia.search_object_by_tag](../wiki/evennia.utils.search#search_object_by_tag)
- [evennia.search_script](../wiki/evennia.scripts.manager#scriptdbmanagersearch_script)
- [evennia.search_channel](../wiki/evennia.comms.managers#channeldbmanagersearch_channel)
- [evennia.search_message](../wiki/evennia.comms.managers#msgmanagersearch_message)
- [evennia.search_help](../wiki/evennia.help.manager#helpentrymanagersearch_help)
- [`evennia.search_account`](evennia.accounts.manager.AccountDBManager.search_account)
- [`evennia.search_object`](evennia.objects.manager.ObjectDBManager.search_object)
- [`evennia.search(object)_by_tag`](evennia.utils.search.search_tag)
- [`evennia.search_script`](evennia.scripts.manager.ScriptDBManager.search_script)
- [`evennia.search_channel`](evennia.comms.managers.ChannelDBManager.search_channel)
- [`evennia.search_message`](evennia.comms.managers.MsgManager.search_message)
- [`evennia.search_help`](evennia.help.manager.HelpEntryManager.search_help)
Note that these latter methods will always return a `list` of results, even if the list has one or
zero entries.
@ -50,12 +50,12 @@ entities directly in code (for example when defining new create commands).
myobj = evennia.create_objects("game.gamesrc.objects.myobj.MyObj", key="MyObj")
```
- [evennia.create_account](../wiki/evennia.utils.create#create_account)
- [evennia.create_object](../wiki/evennia.utils.create#create_object)
- [evennia.create_script](../wiki/evennia.utils.create#create_script)
- [evennia.create_channel](../wiki/evennia.utils.create#create_channel)
- [evennia.create_help_entry](../wiki/evennia.utils.create#create_help_entry)
- [evennia.create_message](../wiki/evennia.utils.create#create_message)
- [`evennia.create_account`](evennia.utils.create.create_account)
- [`evennia.create_object`](evennia.utils.create.create_object)
- [`evennia.create_script`](evennia.utils.create.create_script)
- [`evennia.create_channel`](evennia.utils.create.create_channel)
- [`evennia.create_help_entry`](evennia.utils.create.create_help_entry)
- [`evennia.create_message`](evennia.utils.create.create_message)
Each of these create-functions have a host of arguments to further customize the created entity. See
`evennia/utils/create.py` for more information.
@ -137,7 +137,7 @@ setting `TIME_GAME_EPOCH` sets the starting game epoch (in seconds). The functio
you desire for your game. You can use the `@time` command to view the server time info.
You can also *schedule* things to happen at specific in-game times using the
[gametime.schedule](github:evennia.utils.gametime#schedule) function:
[gametime.schedule](evennia.utils.gametime.schedule) function:
```python
import evennia
@ -181,13 +181,13 @@ number of seconds. This is a very light wrapper over a Twisted
non-persistently, which means that if the server is `@reload`ed before the delay is over, the
callback will never run (the server forgets it). If setting `persistent` to True, the delay will be
stored in the database and survive a `@reload` - but for this to work it is susceptible to the same
limitations incurred when saving to an [Attribute](./Attributes).
limitations incurred when saving to an [Attribute](./Attributes.md).
The `deferred` return object can usually be ignored, but calling its `.cancel()` method will abort
the delay prematurely.
`utils.delay` is the lightest form of delayed call in Evennia. For other way to create time-bound
tasks, see the [TickerHandler](./TickerHandler) and [Scripts](./Scripts).
tasks, see the [TickerHandler](./TickerHandler.md) and [Scripts](./Scripts.md).
> Note that many delayed effects can be achieved without any need for an active timer. For example
if you have a trait that should recover a point every 5 seconds you might just need its value when
@ -203,7 +203,7 @@ classes, instances or python-paths-to-classes.
Note that Python code should usually work with [duck
typing](https://en.wikipedia.org/wiki/Duck_typing). But in Evennia's case it can sometimes be useful
to check if an object inherits from a given [Typeclass](./Typeclasses) as a way of identification. Say
to check if an object inherits from a given [Typeclass](./Typeclasses.md) as a way of identification. Say
for example that we have a typeclass *Animal*. This has a subclass *Felines* which in turn has a
subclass *HouseCat*. Maybe there are a bunch of other animal types too, like horses and dogs. Using
`inherits_from` will allow you to check for all animals in one go:
@ -274,17 +274,17 @@ need to send byte-data over the wire, `to_str` is the only one you'll need.
The difference from Python's in-built `str()` and `bytes()` operators are that
the Evennia ones makes use of the `ENCODINGS` setting and will try very hard to
never raise a traceback but instead echo errors through logging. See
[here](../Concepts/Text-Encodings) for more info.
[here](../Concepts/Text-Encodings.md) for more info.
### Ansi Coloring Tools
- [evennia.ansi](api:evennia.utils.ansi)
- [evennia.utils.ansi](evennia.utils.ansi)
## Display utilities
### Making ascii tables
The [EvTable](github:evennia.utils.evtable#evtable) class (`evennia/utils/evtable.py`) can be used
The [EvTable](evennia.utils.evtable.EvTable) class (`evennia/utils/evtable.py`) can be used
to create correctly formatted text tables. There is also
[EvForm](github:evennia.utils.evform#evform) (`evennia/utils/evform.py`). This reads a fixed-format
[EvForm](evennia.utils.evform.EvForm) (`evennia/utils/evform.py`). This reads a fixed-format
text template from a file in order to create any level of sophisticated ascii layout. Both evtable
and evform have lots of options and inputs so see the header of each module for help.
@ -294,4 +294,4 @@ ANSI colour. PrettyTable can be found in `evennia/utils/prettytable/`. See its
instructions.
### Menus
- [evennia.EvMenu](github:evennia.utils.evmenu#evmenu)
- [evennia.EvMenu](evennia.utils.evmenu.EvMenu)

View file

@ -1,7 +1,7 @@
# Command Sets
Command Sets are intimately linked with [Commands](./Commands) and you should be familiar with
Command Sets are intimately linked with [Commands](./Commands.md) and you should be familiar with
Commands before reading this page. The two pages were split for ease of reading.
A *Command Set* (often referred to as a CmdSet or cmdset) is the basic unit for storing one or more
@ -11,7 +11,7 @@ classes in a command set is the way to make commands available to use in your ga
When storing a CmdSet on an object, you will make the commands in that command set available to the
object. An example is the default command set stored on new Characters. This command set contains
all the useful commands, from `look` and `inventory` to `@dig` and `@reload`
([permissions](./Locks#Permissions) then limit which players may use them, but that's a separate
([permissions](./Permissions.md) then limit which players may use them, but that's a separate
topic).
When an account enters a command, cmdsets from the Account, Character, its location, and elsewhere
@ -26,7 +26,7 @@ on. The tutorial world included with Evennia showcases a dark room that replaces
commands with its own versions because the Character cannot see.
If you want a quick start into defining your first commands and using them with command sets, you
can head over to the [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands) which steps through things
can head over to the [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md) which steps through things
without the explanations.
## Defining Command Sets
@ -112,11 +112,11 @@ back even if all other cmdsets fail or are removed. It is always persistent and
by `cmdset.delete()`. To remove a default cmdset you must explicitly call `cmdset.remove_default()`.
Command sets are often added to an object in its `at_object_creation` method. For more examples of
adding commands, read the [Step by step tutorial](../Howto/Starting/Part1/Adding-Commands). Generally you can
adding commands, read the [Step by step tutorial](../Howto/Starting/Part1/Adding-Commands.md). Generally you can
customize which command sets are added to your objects by using `self.cmdset.add()` or
`self.cmdset.add_default()`.
> Important: Commands are identified uniquely by key *or* alias (see [Commands](./Commands)). If any
> Important: Commands are identified uniquely by key *or* alias (see [Commands](./Commands.md)). If any
overlap exists, two commands are considered identical. Adding a Command to a command set that
already has an identical command will *replace* the previous command. This is very important. You
must take this behavior into account when attempting to overload any default Evennia commands with
@ -127,7 +127,7 @@ new one that has a matching alias.
There are several extra flags that you can set on CmdSets in order to modify how they work. All are
optional and will be set to defaults otherwise. Since many of these relate to *merging* cmdsets,
you might want to read the [Adding and Merging Command Sets](./Command-Sets#adding-and-merging-
you might want to read the [Adding and Merging Command Sets](./Command-Sets.md#adding-and-merging-
command-sets) section for some of these to make sense.
- `key` (string) - an identifier for the cmdset. This is optional, but should be unique. It is used
@ -138,7 +138,7 @@ dictionary below.
- `priority` (int) - This defines the merge order of the merge stack - cmdsets will merge in rising
order of priority with the highest priority set merging last. During a merger, the commands from the
set with the higher priority will have precedence (just what happens depends on the [merge
type](Command-Sets#adding-and-merging-command-sets)). If priority is identical, the order in the
type](./Command-Sets.md#adding-and-merging-command-sets)). If priority is identical, the order in the
merge stack determines preference. The priority value must be greater or equal to `-100`. Most in-
game sets should usually have priorities between `0` and `100`. Evennia default sets have priorities
as follows (these can be changed if you want a different distribution):
@ -154,7 +154,7 @@ arguments, there is no collision between exits named the same as a channel even
differently with certain named cmdsets. If the cmdset to merge with has a `key` matching an entry in
`key_mergetype`, it will not be merged according to the setting in `mergetype` but according to the
mode in this dict. Please note that this is more complex than it may seem due to the [merge
order](Command-Sets#adding-and-merging-command-sets) of command sets. Please review that section
order](./Command-Sets.md#adding-and-merging-command-sets) of command sets. Please review that section
before using `key_mergetype`.
- `duplicates` (bool/None default `None`) - this determines what happens when merging same-priority
cmdsets containing same-key commands together. The`dupicate` option will *only* apply when merging
@ -195,15 +195,15 @@ priority determines what is used.
## Command Sets Searched
When a user issues a command, it is matched against the [merged](./Command-Sets#adding-and-merging-
When a user issues a command, it is matched against the [merged](./Command-Sets.md#adding-and-merging-
command-sets) command sets available to the player at the moment. Which those are may change at any
time (such as when the player walks into the room with the `Window` object described earlier).
The currently valid command sets are collected from the following sources:
- The cmdsets stored on the currently active [Session](./Sessions). Default is the empty
- The cmdsets stored on the currently active [Session](./Sessions.md). Default is the empty
`SessionCmdSet` with merge priority `-20`.
- The cmdsets defined on the [Account](./Accounts). Default is the AccountCmdSet with merge priority
- The cmdsets defined on the [Account](./Accounts.md). Default is the AccountCmdSet with merge priority
`-10`.
- All cmdsets on the Character/Object (assuming the Account is currently puppeting such a
Character/Object). Merge priority `0`.
@ -215,14 +215,14 @@ included if `no_objs` option is active in the merge stack.
`no_objs` option is active in the merge stack.
- The cmdsets of Exits in the location. Merge priority `+101`. Will not be included if `no_exits`
*or* `no_objs` option is active in the merge stack.
- The [channel](./Communications) cmdset containing commands for posting to all channels the account
- The [channel](./Communications.md) cmdset containing commands for posting to all channels the account
or character is currently connected to. Merge priority `+101`. Will not be included if `no_channels`
option is active in the merge stack.
Note that an object does not *have* to share its commands with its surroundings. A Character's
cmdsets should not be shared for example, or all other Characters would get multi-match errors just
by being in the same room. The ability of an object to share its cmdsets is managed by its `call`
[lock](./Locks). For example, [Character objects](./Objects) defaults to `call:false()` so that any
[lock](./Locks.md). For example, [Character objects](./Objects.md) defaults to `call:false()` so that any
cmdsets on them can only be accessed by themselves, not by other objects around them. Another
example might be to lock an object with `call:inside()` to only make their commands available to
objects inside them, or `cmd:holds()` to make their commands available only if they are held.

View file

@ -1,9 +1,9 @@
# Command System
- [Commands](./Commands)
- [Command Sets](./Command-Sets)
- [Command Auto-help](./Help-System#command-auto-help-system)
- [Commands](./Commands.md)
- [Command Sets](./Command-Sets.md)
- [Command Auto-help](./Help-System.md#command-auto-help-system)
See also:
- [Default Command Help](api:evennia.commands.default#modules)
- [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands)
- [Default Commands](./Default-Commands.md)
- [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md)

View file

@ -1,22 +1,22 @@
# Commands
Commands are intimately linked to [Command Sets](./Command-Sets) and you need to read that page too to
Commands are intimately linked to [Command Sets](./Command-Sets.md) and you need to read that page too to
be familiar with how the command system works. The two pages were split for easy reading.
The basic way for users to communicate with the game is through *Commands*. These can be commands
directly related to the game world such as *look*, *get*, *drop* and so on, or administrative
commands such as *examine* or *@dig*.
The [default commands](api:evennia.commands.default#modules) coming with Evennia are 'MUX-like' in that they use @
The [default commands](./Default-Commands.md) coming with Evennia are 'MUX-like' in that they use @
for admin commands, support things like switches, syntax with the '=' symbol etc, but there is
nothing that prevents you from implementing a completely different command scheme for your game. You
can find the default commands in `evennia/commands/default`. You should not edit these directly -
they will be updated by the Evennia team as new features are added. Rather you should look to them
for inspiration and inherit your own designs from them.
There are two components to having a command running - the *Command* class and the
[Command Set](./Command-Sets) (command sets were split into a separate wiki page for ease of reading).
There are two components to having a command running - the *Command* class and the
[Command Set](./Command-Sets.md) (command sets were split into a separate wiki page for ease of reading).
1. A *Command* is a python class containing all the functioning code for what a command does - for
example, a *get* command would contain code for picking up objects.
@ -28,8 +28,8 @@ object in various ways. Consider a "Tree" object with a cmdset defining the comm
*chop down*. Or a "Clock" with a cmdset containing the single command *check time*.
This page goes into full detail about how to use Commands. To fully use them you must also read the
page detailing [Command Sets](./Command-Sets). There is also a step-by-step
[Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands) that will get you started quickly without the
page detailing [Command Sets](./Command-Sets.md). There is also a step-by-step
[Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands.md) that will get you started quickly without the
extra explanations.
## Defining Commands
@ -81,15 +81,15 @@ In Evennia there are three types of objects that may call the command. It is im
of this since this will also assign appropriate `caller`, `session`, `sessid` and `account`
properties on the command body at runtime. Most often the calling type is `Session`.
* A [Session](./Sessions). This is by far the most common case when a user is entering a command in
* A [Session](./Sessions.md). This is by far the most common case when a user is entering a command in
their client.
* `caller` - this is set to the puppeted [Object](./Objects) if such an object exists. If no
* `caller` - this is set to the puppeted [Object](./Objects.md) if such an object exists. If no
puppet is found, `caller` is set equal to `account`. Only if an Account is not found either (such as
before being logged in) will this be set to the Session object itself.
* `session` - a reference to the [Session](./Sessions) object itself.
* `session` - a reference to the [Session](./Sessions.md) object itself.
* `sessid` - `sessid.id`, a unique integer identifier of the session.
* `account` - the [Account](./Accounts) object connected to this Session. None if not logged in.
* An [Account](./Accounts). This only happens if `account.execute_cmd()` was used. No Session
* `account` - the [Account](./Accounts.md) object connected to this Session. None if not logged in.
* An [Account](./Accounts.md). This only happens if `account.execute_cmd()` was used. No Session
information can be obtained in this case.
* `caller` - this is set to the puppeted Object if such an object can be determined (without
Session info this can only be determined in `MULTISESSION_MODE=0` or `1`). If no puppet is found,
@ -97,7 +97,7 @@ this is equal to `account`.
* `session` - `None*`
* `sessid` - `None*`
* `account` - Set to the Account object.
* An [Object](./Objects). This only happens if `object.execute_cmd()` was used (for example by an
* An [Object](./Objects.md). This only happens if `object.execute_cmd()` was used (for example by an
NPC).
* `caller` - This is set to the calling Object in question.
* `session` - `None*`
@ -120,10 +120,10 @@ it the following properties:
- `caller` - The character BigGuy, in this example. This is a reference to the object executing the
command. The value of this depends on what type of object is calling the command; see the previous
section.
- `session` - the [Session](./Sessions) Bob uses to connect to the game and control BigGuy (see also
- `session` - the [Session](./Sessions.md) Bob uses to connect to the game and control BigGuy (see also
previous section).
- `sessid` - the unique id of `self.session`, for quick lookup.
- `account` - the [Account](./Accounts) Bob (see previous section).
- `account` - the [Account](./Accounts.md) Bob (see previous section).
- `cmdstring` - the matched key for the command. This would be *look* in our example.
- `args` - this is the rest of the string, except the command name. So if the string entered was
*look at sword*, `args` would be " *at sword*". Note the space kept - Evennia would correctly
@ -131,7 +131,7 @@ interpret `lookat sword` too. This is useful for things like `/switches` that sh
In the `MuxCommand` class used for default commands, this space is stripped. Also see the
`arg_regex` property if you want to enforce a space to make `lookat sword` give a command-not-found
error.
- `obj` - the game [Object](./Objects) on which this command is defined. This need not be the caller,
- `obj` - the game [Object](./Objects.md) on which this command is defined. This need not be the caller,
but since `look` is a common (default) command, this is probably defined directly on *BigGuy* - so
`obj` will point to BigGuy. Otherwise `obj` could be an Account or any interactive object with
commands defined on it, like in the example of the "check time" command defined on a "Clock" object.
@ -143,18 +143,18 @@ for example*).
- `raw_string` - this is the raw input coming from the user, without stripping any surrounding
whitespace. The only thing that is stripped is the ending newline marker.
#### Other useful utility methods:
#### Other useful utility methods:
- `.get_help(caller, cmdset)` - Get the help entry for this command. By default the arguments are
not
used, but they could be used to implement alternate help-display systems.
- `.client_width()` - Shortcut for getting the client's screen-width. Note that not all clients will
truthfully report this value - that case the `settings.DEFAULT_SCREEN_WIDTH` will be returned.
- `.styled_table(*args, **kwargs)` - This returns an [EvTable](api:evennia.utils#module-
- `.styled_table(*args, **kwargs)` - This returns an [EvTable](module-
evennia.utils.evtable) styled based on the
session calling this command. The args/kwargs are the same as for EvTable, except styling defaults
are set.
- `.styled_header`, `_footer`, `separator` - These will produce styled decorations for
- `.styled_header`, `_footer`, `separator` - These will produce styled decorations for
display to the user. They are useful for creating listings and forms with colors adjustable per-
user.
@ -169,7 +169,7 @@ key can consist of more than one word, like "press button" or "pull left lever".
either matches. This is important for merging cmdsets described below.
- `aliases` (optional list) - a list of alternate names for the command (`["glance", "see", "l"]`).
Same name rules as for `key` applies.
- `locks` (string) - a [lock definition](./Locks), usually on the form `cmd:<lockfuncs>`. Locks is a
- `locks` (string) - a [lock definition](./Locks.md), usually on the form `cmd:<lockfuncs>`. Locks is a
rather big topic, so until you learn more about locks, stick to giving the lockstring `"cmd:all()"`
to make the command available to everyone (if you don't provide a lock string, this will be assigned
for you).
@ -181,9 +181,9 @@ by the next command by retrieving `self.caller.ndb.last_cmd`. The next run comma
or replace the storage.
- `arg_regex` (optional raw string): Used to force the parser to limit itself and tell it when the
command-name ends and arguments begin (such as requiring this to be a space or a /switch). This is
done with a regular expression. [See the arg_regex section](./Commands#on-arg_regex) for the details.
- `auto_help` (optional boolean). Defaults to `True`. This allows for turning off the
[auto-help system](./Help-System#command-auto-help-system) on a per-command basis. This could be useful if you
done with a regular expression. [See the arg_regex section](./Commands.md#on-arg_regex) for the details.
- `auto_help` (optional boolean). Defaults to `True`. This allows for turning off the
[auto-help system](./Help-System.md#command-auto-help-system) on a per-command basis. This could be useful if you
either want to write your help entries manually or hide the existence of a command from `help`'s
generated list.
- `is_exit` (bool) - this marks the command as being used for an in-game exit. This is, by default,
@ -219,7 +219,7 @@ from this method will be returned from the execution as a Twisted Deferred.
Finally, you should always make an informative [doc
string](https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring) (`__doc__`) at the top of
your class. This string is dynamically read by the [Help System](./Help-System) to create the help
your class. This string is dynamically read by the [Help System](./Help-System.md) to create the help
entry for this command. You should decide on a way to format your help and stick to that.
Below is how you define a simple alternative "`smile`" command:
@ -260,8 +260,8 @@ class CmdSmile(Command):
string = f"{caller.key} smiles"
else:
target = caller.search(self.target)
if not target:
return
if not target:
return
string = f"{caller.key} smiles at {target.key}"
caller.location.msg_contents(string)
@ -277,7 +277,7 @@ default commands thus need to implement `parse()` at all, but can assume the
incoming string is already split up and parsed in suitable ways by its parent.
Before you can actually use the command in your game, you must now store it
within a *command set*. See the [Command Sets](./Command-Sets) page.
within a *command set*. See the [Command Sets](./Command-Sets.md) page.
### On arg_regex
@ -428,7 +428,7 @@ will show.
> Note again that the `yield` keyword does not store state. If the game reloads while waiting for
the user to answer, the user will have to start over. It is not a good idea to use `yield` for
important or complex choices, a persistent [EvMenu](./EvMenu) might be more appropriate in this case.
important or complex choices, a persistent [EvMenu](./EvMenu.md) might be more appropriate in this case.
## System commands
@ -458,7 +458,7 @@ display the "Huh?" error message.
matches.
- User is not allowed to execute the command (`syscmdkeys.CMD_NOPERM`) - Default is to display the
"Huh?" error message.
- Channel (`syscmdkeys.CMD_CHANNEL`) - This is a [Channel](./Communications) name of a channel you are
- Channel (`syscmdkeys.CMD_CHANNEL`) - This is a [Channel](./Communications.md) name of a channel you are
subscribing to - Default is to relay the command's argument to that channel. Such commands are
created by the Comm system on the fly depending on your subscriptions.
- New session connection (`syscmdkeys.CMD_LOGINSTART`). This command name should be put in the
@ -485,7 +485,7 @@ work.
Normally Commands are created as fixed classes and used without modification. There are however
situations when the exact key, alias or other properties is not possible (or impractical) to pre-
code ([Exits](./Commands#Exits) is an example of this).
code ([Exits](./Commands.md#exits) is an example of this).
To create a command with a dynamic call signature, first define the command body normally in a class
(set your `key`, `aliases` to default values), then use the following call (assuming the command
@ -509,10 +509,10 @@ make your command completely customized at run-time.
*Note: This is an advanced topic.*
Exits are examples of the use of a [Dynamic Command](./Commands#Dynamic_Commands).
Exits are examples of the use of a [Dynamic Command](./Commands.md#dynamic-commands).
The functionality of [Exit](./Objects) objects in Evennia is not hard-coded in the engine. Instead
Exits are normal [typeclassed](./Typeclasses) objects that auto-create a [CmdSet](./Commands#CmdSets) on
The functionality of [Exit](./Objects.md) objects in Evennia is not hard-coded in the engine. Instead
Exits are normal [typeclassed](./Typeclasses.md) objects that auto-create a [CmdSet](./Command-Sets.md) on
themselves when they load. This cmdset has a single dynamically created Command with the same
properties (key, aliases and locks) as the Exit object itself. When entering the name of the exit,
this dynamic exit-command is triggered and (after access checks) moves the Character to the exit's
@ -610,9 +610,9 @@ cmdset, ignore.
- CmdSets defined on the current account, if caller is a puppeted object.
- CmdSets defined on the Session itself.
- The active CmdSets of eventual objects in the same location (if any). This includes commands
on [Exits](./Objects#Exits).
on [Exits](./Objects.md#exits).
- Sets of dynamically created *System commands* representing available
[Communications](./Communications#Channels).
[Communications](./Channels.md)
7. All CmdSets *of the same priority* are merged together in groups. Grouping avoids order-
dependent issues of merging multiple same-prio sets onto lower ones.
8. All the grouped CmdSets are *merged* in reverse priority into one combined CmdSet according to

View file

@ -2,7 +2,7 @@
TODO: Remove this page?
- [Channels](./Channels) - are used for implementing in-game chat rooms.
- [Msg](./Msg)-objects are used for storing messages in the database (email-like)
- [Channels](./Channels.md) - are used for implementing in-game chat rooms.
- [Msg](./Msg.md)-objects are used for storing messages in the database (email-like)
and is a building block for implementing other game systems. It's used by the
`page` command by default.

View file

@ -1,54 +1,54 @@
# Core Components
These are the 'building blocks' out of which Evennia is built. This documentation is complementary to, and often goes deeper
than, the doc-strings of each component in the [API](../Evennia-API).
than, the doc-strings of each component in the [API](../Evennia-API.md).
## Database entites
## Database entites
- [Typeclasses](./Typeclasses)
- [Sessions](./Sessions)
- [Acccounts](./Accounts)
- [Guests](../Concepts/Guest-Logins)
- [Objects](./Objects)
- [Scripts](./Scripts)
- [Channels and Messages](./Communications)
- [Attributes](./Attributes)
- [Nicks](./Nicks)
- [Tags](./Tags)
- [Spawner and prototypes](./Prototypes)
- [Help entries](./Help-System)
- [Typeclasses](./Typeclasses.md)
- [Sessions](./Sessions.md)
- [Acccounts](./Accounts.md)
- [Guests](../Concepts/Guest-Logins.md)
- [Objects](./Objects.md)
- [Scripts](./Scripts.md)
- [Channels and Messages](./Communications.md)
- [Attributes](./Attributes.md)
- [Nicks](./Nicks.md)
- [Tags](./Tags.md)
- [Spawner and prototypes](./Prototypes.md)
- [Help entries](./Help-System.md)
## Commands
## Commands
- [Command system](./Command-System)
- [Commands](./Commands)
- [Command-Sets](./Command-Sets)
- [The Connection Screen](./Connection-Screen)
- [Available default Commands](api:evennia.commands.default#modules)
- [Batch-Processors](./Batch-Processors)
- [Batch-Code-Processor](./Batch-Code-Processor)
- [Batch-Command-Processor](./Batch-Command-Processor)
- [Available Default Commands](./Default-Commands.md)
- [Command system](./Command-System.md)
- [Commands](./Commands.md)
- [Command-Sets](./Command-Sets.md)
- [The Connection Screen](./Connection-Screen.md)
- [Batch-Processors](./Batch-Processors.md)
- [Batch-Code-Processor](./Batch-Code-Processor.md)
- [Batch-Command-Processor](./Batch-Command-Processor.md)
## Utils and tools
- [Misc Utils](./Coding-Utils)
- [EvEditor](./EvEditor)
- [EvMenu](./EvMenu)
- [EvMore](./EvMore)
- [MonitorHandler](./MonitorHandler)
- [TickerHandler](./TickerHandler)
- [Lock system](./Locks)
- [FuncParser](./FuncParser)
- [Misc Utils](./Coding-Utils.md)
- [EvEditor](./EvEditor.md)
- [EvMenu](./EvMenu.md)
- [EvMore](./EvMore.md)
- [MonitorHandler](./MonitorHandler.md)
- [TickerHandler](./TickerHandler.md)
- [Lock system](./Locks.md)
- [FuncParser](./FuncParser.md)
## Server and network
- [Portal](./Portal-And-Server)
- [Inputfuncs](./Inputfuncs)
- [Outputfuncs](./Outputfuncs)
- [Protocols](../Concepts/Custom-Protocols)
- [Server](./Server)
- [Server conf object](./Server-Conf)
- [Webserver](./Webserver)
- [Webclient](./Webclient)
- [Bootstrap](./Bootstrap-Components-and-Utilities)
- [Signals](./Signals)
- [Portal](./Portal-And-Server.md)
- [Inputfuncs](./Inputfuncs.md)
- [Outputfuncs](./Outputfuncs.md)
- [Protocols](../Concepts/Custom-Protocols.md)
- [Server](./Server.md)
- [Server conf object](../Setup/Server-Conf.md)
- [Webserver](./Webserver.md)
- [Webclient](./Webclient.md)
- [Bootstrap](./Bootstrap-Components-and-Utilities.md)
- [Signals](./Signals.md)

View file

@ -1,17 +1,17 @@
# Connection Screen
When you first connect to your game you are greeted by Evennia's default connection screen.
When you first connect to your game you are greeted by Evennia's default connection screen.
==============================================================
Welcome to Evennia, version Beta-ra4d24e8a3cab+!
If you have an existing account, connect to it by typing:
connect <username> <password>
If you need to create an account, type (without the <>'s):
create <username> <password>
If you have spaces in your username, enclose it in quotes.
Enter help for more info. look will re-show this screen.
==============================================================
@ -20,17 +20,17 @@ Effective, but not very exciting. You will most likely want to change this to be
your game. This is simple:
1. Edit `mygame/server/conf/connection_screens.py`.
1. [Reload](../Setup/Start-Stop-Reload) Evennia.
1. [Reload](../Setup/Start-Stop-Reload.md) Evennia.
Evennia will look into this module and locate all *globally defined strings* in it. These strings
are used as the text in your connection screen and are shown to the user at startup. If more than
one such string/screen is defined in the module, a *random* screen will be picked from among those
available.
### Commands available at the Connection Screen
## Commands available at the Connection Screen
You can also customize the [Commands](./Commands) available to use while the connection screen is
You can also customize the [Commands](./Commands.md) available to use while the connection screen is
shown (`connect`, `create` etc). These commands are a bit special since when the screen is running
the account is not yet logged in. A command is made available at the login screen by adding them to
`UnloggedinCmdSet` in `mygame/commands/default_cmdset.py`. See [Commands](./Commands) and the
tutorial section on how to add new commands to a default command set.
`UnloggedinCmdSet` in `mygame/commands/default_cmdset.py`. See [Commands](./Commands.md) and the
tutorial section on how to add new commands to a default command set.

View file

@ -0,0 +1,106 @@
# Default Commands
The full set of default Evennia commands currently contains 97 commands in 9 source
files. Our policy for adding default commands is outlined [here](../Concepts/Using-MUX-as-a-Standard.md). The
[Commands](./Commands.md) documentation explains how Commands work as well as make new or customize
existing ones. Note that this page is auto-generated. Report problems to the [issue
tracker](github:issues).
```{note}
Some game-states adds their own Commands which are not listed here. Examples include editing a text
with [EvEditor](./EvEditor.md), flipping pages in [EvMore](./EvMore.md) or using the
[Batch-Processor](./Batch-Processors.md)'s interactive mode.
```
- [**__unloggedin_look_command** [l, look]](evennia.commands.default.unloggedin.CmdUnconnectedLook) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**about** [version]](evennia.commands.default.system.CmdAbout) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**access** [groups, hierarchy]](evennia.commands.default.general.CmdAccess) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**accounts** [listaccounts, account]](evennia.commands.default.system.CmdAccounts) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**addcom** [chanalias, aliaschan]](evennia.commands.default.comms.CmdAddCom) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**alias** [setobjalias]](evennia.commands.default.building.CmdSetObjAlias) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**allcom**](evennia.commands.default.comms.CmdAllCom) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**batchcode** [batchcodes]](evennia.commands.default.batchprocess.CmdBatchCode) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**batchcommands** [batchcmd, batchcommand]](evennia.commands.default.batchprocess.CmdBatchCommands) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**cboot**](evennia.commands.default.comms.CmdCBoot) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**ccreate** [channelcreate]](evennia.commands.default.comms.CmdChannelCreate) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**cdesc**](evennia.commands.default.comms.CmdCdesc) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**cdestroy**](evennia.commands.default.comms.CmdCdestroy) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**channel** [chan, channels]](evennia.commands.default.comms.CmdChannel) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**charcreate**](evennia.commands.default.account.CmdCharCreate) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**chardelete**](evennia.commands.default.account.CmdCharDelete) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**clock**](evennia.commands.default.comms.CmdClock) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**cmdsets** [listcmsets]](evennia.commands.default.building.CmdListCmdSets) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**color**](evennia.commands.default.account.CmdColorTest) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**connect** [conn, co, con]](evennia.commands.default.unloggedin.CmdUnconnectedConnect) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**copy**](evennia.commands.default.building.CmdCopy) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**cpattr**](evennia.commands.default.building.CmdCpAttr) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**create**](evennia.commands.default.building.CmdCreate) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**create** [cr, cre]](evennia.commands.default.unloggedin.CmdUnconnectedCreate) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**cwho**](evennia.commands.default.comms.CmdCWho) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**delcom** [delchanalias, delaliaschan]](evennia.commands.default.comms.CmdDelCom) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**desc** [describe]](evennia.commands.default.building.CmdDesc) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**destroy** [del, delete]](evennia.commands.default.building.CmdDestroy) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**dig**](evennia.commands.default.building.CmdDig) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**drop**](evennia.commands.default.general.CmdDrop) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**encoding** [encode]](evennia.commands.default.unloggedin.CmdUnconnectedEncoding) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**examine** [ex, exam]](evennia.commands.default.building.CmdExamine) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Building_)
- [**find** [locate, search]](evennia.commands.default.building.CmdFind) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**get** [grab]](evennia.commands.default.general.CmdGet) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**give**](evennia.commands.default.general.CmdGive) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**grapevine2chan**](evennia.commands.default.comms.CmdGrapevine2Chan) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**help** [?]](evennia.commands.default.help.CmdHelp) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**help** [h, ?]](evennia.commands.default.unloggedin.CmdUnconnectedHelp) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**home**](evennia.commands.default.general.CmdHome) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**ic** [puppet]](evennia.commands.default.account.CmdIC) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**info**](evennia.commands.default.unloggedin.CmdUnconnectedInfo) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**inventory** [i, inv]](evennia.commands.default.general.CmdInventory) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**irc2chan**](evennia.commands.default.comms.CmdIRC2Chan) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**ircstatus**](evennia.commands.default.comms.CmdIRCStatus) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**link**](evennia.commands.default.building.CmdLink) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**lock** [locks]](evennia.commands.default.building.CmdLock) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**look** [ls, l]](evennia.commands.default.account.CmdOOCLook) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**look** [ls, l]](evennia.commands.default.general.CmdLook) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**mvattr**](evennia.commands.default.building.CmdMvAttr) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**name** [rename]](evennia.commands.default.building.CmdName) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**nick** [nickname, nicks]](evennia.commands.default.general.CmdNick) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**objects** [listobjs, listobjects, db, stats]](evennia.commands.default.building.CmdObjects) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**ooc** [unpuppet]](evennia.commands.default.account.CmdOOC) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**open**](evennia.commands.default.building.CmdOpen) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**option** [options]](evennia.commands.default.account.CmdOption) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**page** [tell]](evennia.commands.default.comms.CmdPage) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**password**](evennia.commands.default.account.CmdPassword) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**pose** [:, emote]](evennia.commands.default.general.CmdPose) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**py** [!]](evennia.commands.default.system.CmdPy) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_)
- [**quell** [unquell]](evennia.commands.default.account.CmdQuell) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**quit**](evennia.commands.default.account.CmdQuit) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**quit** [qu, q]](evennia.commands.default.unloggedin.CmdUnconnectedQuit) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**reload** [restart]](evennia.commands.default.system.CmdReload) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_)
- [**reset** [reboot]](evennia.commands.default.system.CmdReset) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_)
- [**rss2chan**](evennia.commands.default.comms.CmdRSS2Chan) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_)
- [**say** [", ']](evennia.commands.default.general.CmdSay) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**screenreader**](evennia.commands.default.unloggedin.CmdUnconnectedScreenreader) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_)
- [**scripts** [script]](evennia.commands.default.building.CmdScripts) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**server** [serverload, serverprocess]](evennia.commands.default.system.CmdServerLoad) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**service** [services]](evennia.commands.default.system.CmdService) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**sessions**](evennia.commands.default.account.CmdSessions) (cmdset: [SessionCmdSet](evennia.commands.default.cmdset_session.SessionCmdSet), help-category: _General_)
- [**set**](evennia.commands.default.building.CmdSetAttribute) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**setdesc**](evennia.commands.default.general.CmdSetDesc) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**sethelp**](evennia.commands.default.help.CmdSetHelp) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**sethome**](evennia.commands.default.building.CmdSetHome) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**shutdown**](evennia.commands.default.system.CmdShutdown) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_)
- [**spawn** [olc]](evennia.commands.default.building.CmdSpawn) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**style**](evennia.commands.default.account.CmdStyle) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**tag** [tags]](evennia.commands.default.building.CmdTag) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**tasks** [task, delays]](evennia.commands.default.system.CmdTasks) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**tel** [teleport]](evennia.commands.default.building.CmdTeleport) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**tickers**](evennia.commands.default.system.CmdTickers) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**time** [uptime]](evennia.commands.default.system.CmdTime) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_)
- [**tunnel** [tun]](evennia.commands.default.building.CmdTunnel) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**typeclass** [swap, type, update, typeclasses, parent]](evennia.commands.default.building.CmdTypeclass) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**unlink**](evennia.commands.default.building.CmdUnLink) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)
- [**whisper**](evennia.commands.default.general.CmdWhisper) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_)
- [**who** [doing]](evennia.commands.default.account.CmdWho) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_)
- [**wipe**](evennia.commands.default.building.CmdWipe) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_)

View file

@ -5,15 +5,15 @@ Evennia offers a powerful in-game line editor in `evennia.utils.eveditor.EvEdito
mimicking the well-known VI line editor. It offers line-by-line editing, undo/redo, line deletes,
search/replace, fill, dedent and more.
### Launching the editor
## Launching the editor
The editor is created as follows:
The editor is created as follows:
```python
from evennia.utils.eveditor import EvEditor
EvEditor(caller,
loadfunc=None, savefunc=None, quitfunc=None,
EvEditor(caller,
loadfunc=None, savefunc=None, quitfunc=None,
key="")
```
@ -29,7 +29,7 @@ cleanup and exit messages to the user must be handled by this function.
It has no other mechanical function.
- `persistent` (default `False`): if set to `True`, the editor will survive a reboot.
### Example of usage
## Example of usage
This is an example command for setting a specific Attribute using the editor.
@ -39,7 +39,7 @@ from evennia.utils import eveditor
class CmdSetTestAttr(Command):
"""
Set the "test" Attribute using
Set the "test" Attribute using
the line editor.
Usage:
@ -60,12 +60,12 @@ class CmdSetTestAttr(Command):
caller.msg("Editor exited")
key = f"{self.caller}/test"
# launch the editor
eveditor.EvEditor(self.caller,
loadfunc=load, savefunc=save, quitfunc=quit,
key=key)
eveditor.EvEditor(self.caller,
loadfunc=load, savefunc=save, quitfunc=quit,
key=key)
```
### Persistent editor
## Persistent editor
If you set the `persistent` keyword to `True` when creating the editor, it will remain open even
when reloading the game. In order to be persistent, an editor needs to have its callback functions
@ -90,7 +90,7 @@ def quit(caller):
class CmdSetTestAttr(Command):
"""
Set the "test" Attribute using
Set the "test" Attribute using
the line editor.
Usage:
@ -102,12 +102,12 @@ class CmdSetTestAttr(Command):
"Set up the callbacks and launch the editor"
key = f"{self.caller}/test"
# launch the editor
eveditor.EvEditor(self.caller,
loadfunc=load, savefunc=save, quitfunc=quit,
key=key, persistent=True)
eveditor.EvEditor(self.caller,
loadfunc=load, savefunc=save, quitfunc=quit,
key=key, persistent=True)
```
### Line editor usage
## Line editor usage
The editor mimics the `VIM` editor as best as possible. The below is an excerpt of the return from
the in-editor help command (`:h`).
@ -154,7 +154,7 @@ the in-editor help command (`:h`).
<txt> - longer string, usually not needed to be enclosed in quotes.
```
### The EvEditor to edit code
## The EvEditor to edit code
The `EvEditor` is also used to edit some Python code in Evennia. The `@py` command supports an
`/edit` switch that will open the EvEditor in code mode. This mode isn't significantly different
@ -178,4 +178,4 @@ to paste several lines of code that are already correctly indented, for instance
To see the EvEditor in code mode, you can use the `@py/edit` command. Type in your code (on one or
several lines). You can then use the `:w` option (save without quitting) and the code you have
typed will be executed. The `:!` will do the same thing. Executing code while not closing the
editor can be useful if you want to test the code you have typed but add new lines after your test.
editor can be useful if you want to test the code you have typed but add new lines after your test.

View file

@ -33,7 +33,7 @@ said functions, like `{"nodename": <function>, ...}`
## Launching the menu
Initializing the menu is done using a call to the `evennia.utils.evmenu.EvMenu` class. This is the
most common way to do so - from inside a [Command](./Commands):
most common way to do so - from inside a [Command](./Commands.md):
```python
# in, for example gamedir/commands/command.py
@ -70,7 +70,7 @@ EvMenu(caller, menu_data,
```
- `caller` (Object or Account): is a reference to the object using the menu. This object will get a
new [CmdSet](./Command-Sets) assigned to it, for handling the menu.
new [CmdSet](./Command-Sets.md) assigned to it, for handling the menu.
- `menu_data` (str, module or dict): is a module or python path to a module where the global-level
functions will each be considered to be a menu node. Their names in the module will be the names
by which they are referred to in the module. Importantly, function names starting with an
@ -107,7 +107,7 @@ after
- `startnode_input` (str or (str, dict) tuple): Pass an input text or a input text + kwargs to the
start node as if it was entered on a fictional previous node. This can be very useful in order to
start a menu differently depending on the Command's arguments in which it was initialized.
- `session` (Session): Useful when calling the menu from an [Account](./Accounts) in
- `session` (Session): Useful when calling the menu from an [Account](./Accounts.md) in
`MULTISESSION_MODDE` higher than 2, to make sure only the right Session sees the menu output.
- `debug` (bool): If set, the `menudebug` command will be made available in the menu. Use it to
list the current state of the menu and use `menudebug <variable>` to inspect a specific state
@ -428,16 +428,15 @@ See `evennia/utils/evmenu.py` for the details of their default implementations.
## Examples:
- **[Simple branching menu](./EvMenu#example-simple-branching-menu)** - choose from options
- **[Dynamic goto](./EvMenu#example-dynamic-goto)** - jumping to different nodes based on response
- **[Set caller properties](./EvMenu#example-set-caller-properties)** - a menu that changes things
- **[Getting arbitrary input](./EvMenu#example-get-arbitrary-input)** - entering text
- **[Storing data between nodes](./EvMenu#example-storing-data-between-nodes)** - keeping states and
- **[Simple branching menu](./EvMenu.md#example-simple-branching-menu)** - choose from options
- **[Dynamic goto](./EvMenu.md#example-dynamic-goto)** - jumping to different nodes based on response
- **[Set caller properties](./EvMenu.md#example-set-caller-properties)** - a menu that changes things
- **[Getting arbitrary input](./EvMenu.md#example-get-arbitrary-input)** - entering text
- **[Storing data between nodes](./EvMenu.md#example-storing-data-between-nodes)** - keeping states and
information while in the menu
- **[Repeating the same node](./EvMenu#example-repeating-the-same-node)** - validating within the node
- **[Repeating the same node](./EvMenu.md#example-repeating-the-same-node)** - validating within the node
before moving to the next
- **[Full Menu](./EvMenu#example-full-menu):** a complete example
- **[Yes/No prompt](./EvMenu#example-yesno-prompt)** - entering text with limited possible responses
- **[Yes/No prompt](#example-yesno-prompt)** - entering text with limited possible responses
(this is *not* using EvMenu but the conceptually similar yet technically unrelated `get_input`
helper function accessed as `evennia.utils.evmenu.get_input`).
@ -507,7 +506,7 @@ def enter_guild:
This simple callable goto will analyse what happens depending on who the `caller` is. The
`enter_guild` node will give you a choice of what to say to the guard. If you try to enter, you will
end up in different nodes depending on (in this example) if you have the right [Tag](./Tags) set on
end up in different nodes depending on (in this example) if you have the right [Tag](./Tags.md) set on
yourself or not. Note that since we don't include any 'key's in the option dictionary, you will just
get to pick between numbers.
@ -805,7 +804,7 @@ function - for example you can't use other Python keywords like `if` inside the
Unless you are dealing with a relatively simple dynamic menu, defining menus with lambda's is
probably more work than it's worth: You can create dynamic menus by instead making each node
function more clever. See the [NPC shop tutorial](../Howto/NPC-shop-Tutorial) for an example of this.
function more clever. See the [NPC shop tutorial](../Howto/NPC-shop-Tutorial.md) for an example of this.
## Ask for simple input
@ -906,7 +905,7 @@ return True from the callback to repeat the prompt until you pass whatever check
> Note: You *cannot* link consecutive questions by putting a new `get_input` call inside the
> callback If you want that you should use an EvMenu instead (see the [Repeating the same
> node](EvMenu#example-repeating-the-same-node) example above). Otherwise you can either peek at the
> node](./EvMenu.md#example-repeating-the-same-node) example above). Otherwise you can either peek at the
> implementation of `get_input` and implement your own mechanism (it's just using cmdset nesting) or
> you can look at [this extension suggested on the mailing
> list](https://groups.google.com/forum/#!category-topic/evennia/evennia-questions/16pi0SfMO5U).
@ -993,9 +992,9 @@ auto-created by the `list_node` decorator.
## Assorted notes
The EvMenu is implemented using [Commands](./Commands). When you start a new EvMenu, the user of the
menu will be assigned a [CmdSet](./Command-Sets) with the commands they need to navigate the menu.
The EvMenu is implemented using [Commands](./Commands.md). When you start a new EvMenu, the user of the
menu will be assigned a [CmdSet](./Command-Sets.md) with the commands they need to navigate the menu.
This means that if you were to, from inside the menu, assign a new command set to the caller, *you
may override the Menu Cmdset and kill the menu*. If you want to assign cmdsets to the caller as part
of the menu, you should store the cmdset on `caller.ndb._menutree` and wait to actually assign it
until the exit node.
until the exit node.

View file

@ -7,7 +7,7 @@ page of text at a time. It is usually used via its access function, `evmore.msg`
The name comes from the famous unix pager utility *more* which performs just this function.
### Using EvMore
## Using EvMore
To use the pager, just pass the long text through it:
@ -16,7 +16,7 @@ from evennia.utils import evmore
evmore.msg(receiver, long_text)
```
Where receiver is an [Object](./Objects) or a [Account](./Accounts). If the text is longer than the
Where receiver is an [Object](./Objects.md) or a [Account](./Accounts.md). If the text is longer than the
client's screen height (as determined by the NAWS handshake or by `settings.CLIENT_DEFAULT_HEIGHT`)
the pager will show up, something like this:

View file

@ -1,16 +1,12 @@
# The Inline Function Parser
```
```
The [FuncParser](api:evennia.utils.funcparser#evennia.utils.funcparser.FuncParser) extracts and executes
The [FuncParser](evennia.utils.funcparser.FuncParser) extracts and executes
'inline functions'
embedded in a string on the form `$funcname(args, kwargs)`. Under the hood, this will
lead to a call to a Python function you control. The inline function call will be replaced by
embedded in a string on the form `$funcname(args, kwargs)`. Under the hood, this will
lead to a call to a Python function you control. The inline function call will be replaced by
the return from the function.
```python
```python
from evennia.utils.funcparser import FuncParser
def _power_callable(*args, **kwargs):
@ -48,72 +44,72 @@ parser.parse("This is an escaped $$pow(4) and so is this \$pow(3)")
The FuncParser can be applied to any string. Out of the box it's applied in a few situations:
- _Outgoing messages_. All messages sent from the server is processed through FuncParser and every
callable is provided the [Session](./Sessions) of the object receiving the message. This potentially
callable is provided the [Session](./Sessions.md) of the object receiving the message. This potentially
allows a message to be modified on the fly to look different for different recipients.
- _Prototype values_. A [Prototype](./Prototypes) dict's values are run through the parser such that every
- _Prototype values_. A [Prototype](./Prototypes.md) dict's values are run through the parser such that every
callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders
to safely call functions to set non-string values to prototype values, get random values, reference
other fields of the prototype, and more.
- _Actor-stance in messages to others_. In the
[Object.msg_contents](api:evennia.objects.objects#DefaultObject.msg_contents) method,
[Object.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method,
the outgoing string is parsed for special `$You()` and `$conj()` callables to decide if a given recipient
should see "You" or the character's name.
```important::
```{important}
The inline-function parser is not intended as a 'softcode' programming language. It does not
have things like loops and conditionals, for example. While you could in principle extend it to
do very advanced things and allow builders a lot of power, all-out coding is something
have things like loops and conditionals, for example. While you could in principle extend it to
do very advanced things and allow builders a lot of power, all-out coding is something
Evennia expects you to do in a proper text editor, outside of the game, not from inside it.
```
## Using the FuncParser
You can apply inline function parsing to any string. The
[FuncParser](api:evennia.utils.funcparser.FuncParser) is imported as `evennia.utils.funcparser`.
## Using the FuncParser
You can apply inline function parsing to any string. The
[FuncParser](evennia.utils.funcparser.FuncParser) is imported as `evennia.utils.funcparser`.
```python
from evennia.utils import funcparser
parser = FuncParser(callables, **default_kwargs)
parsed_string = parser.parser(input_string, raise_errors=False,
escape=False, strip=False,
parsed_string = parser.parser(input_string, raise_errors=False,
escape=False, strip=False,
return_str=True, **reserved_kwargs)
# callables can also be passed as paths to modules
parser = FuncParser(["game.myfuncparser_callables", "game.more_funcparser_callables"])
```
Here, `callables` points to a collection of normal Python functions (see next section) for you to make
Here, `callables` points to a collection of normal Python functions (see next section) for you to make
available to the parser as you parse strings with it. It can either be
- A `dict` of `{"functionname": callable, ...}`. This allows you do pick and choose exactly which callables
to include and how they should be named. Do you want a callable to be available under more than one name?
Just add it multiple times to the dict, with a different key.
- A `module` or (more commonly) a `python-path` to a module. This module can define a dict
- A `module` or (more commonly) a `python-path` to a module. This module can define a dict
`FUNCPARSER_CALLABLES = {"funcname": callable, ...}` - this will be imported and used like the `dict` above.
If no such variable is defined, _every_ top-level function in the module (whose name doesn't start with
an underscore `_`) will be considered a suitable callable. The name of the function will be the `$funcname`
If no such variable is defined, _every_ top-level function in the module (whose name doesn't start with
an underscore `_`) will be considered a suitable callable. The name of the function will be the `$funcname`
by which it can be called.
- A `list` of modules/paths. This allows you to pull in modules from many sources for your parsing.
The other arguments to the parser:
- `raise_errors` - By default, any errors from a callable will be quietly ignored and the result
will be that the failing function call will show verbatim. If `raise_errors` is set,
then parsing will stop and whatever exception happened will be raised. It'd be up to you to handle
- `raise_errors` - By default, any errors from a callable will be quietly ignored and the result
will be that the failing function call will show verbatim. If `raise_errors` is set,
then parsing will stop and whatever exception happened will be raised. It'd be up to you to handle
this properly.
- `escape` - Returns a string where every `$func(...)` has been escaped as `\$func()`.
- `strip` - Remove all `$func(...)` calls from string (as if each returned `''`).
- `return_str` - When `True` (default), `parser` always returns a string. If `False`, it may return
the return value of a single function call in the string. This is the same as using the `.parse_to_any`
- `return_str` - When `True` (default), `parser` always returns a string. If `False`, it may return
the return value of a single function call in the string. This is the same as using the `.parse_to_any`
method.
- The `**default/reserved_keywords` are optional and allow you to pass custom data into _every_ function
call. This is great for including things like the current session or config options. Defaults can be
replaced if the user gives the same-named kwarg in the string's function call. Reserved kwargs are always passed,
ignoring defaults or what the user passed. In addition, the `funcparser` and `raise_errors`
ignoring defaults or what the user passed. In addition, the `funcparser` and `raise_errors`
reserved kwargs are always passed - the first is a back-reference to the `FuncParser` instance and the second
is the `raise_errors` boolean passed into `FuncParser.parse`.
Here's an example of using the default/reserved keywords:
Here's an example of using the default/reserved keywords:
```python
def _test(*args, **kwargs):
@ -123,15 +119,15 @@ def _test(*args, **kwargs):
parser = funcparser.FuncParser({"test": _test}, mydefault=2)
result = parser.parse("$test(foo, bar=4)", myreserved=[1, 2, 3])
```
Here the callable will be called as
Here the callable will be called as
```python
_test('foo', bar='4', mydefault=2, myreserved=[1, 2, 3],
funcparser=<FuncParser>, raise_errors=False)
_test('foo', bar='4', mydefault=2, myreserved=[1, 2, 3],
funcparser=<FuncParser>, raise_errors=False)
```
The `mydefault=2` kwarg could be overwritten if we made the call as `$test(mydefault=...)`
but `myreserved=[1, 2, 3]` will _always_ be sent as-is and will override a call `$test(myreserved=...)`.
The `mydefault=2` kwarg could be overwritten if we made the call as `$test(mydefault=...)`
but `myreserved=[1, 2, 3]` will _always_ be sent as-is and will override a call `$test(myreserved=...)`.
The `funcparser`/`raise_errors` kwargs are also always included as reserved kwargs.
## Defining custom callables
@ -144,44 +140,44 @@ def funcname(*args, **kwargs):
return something
```
> The `*args` and `**kwargs` must always be included. If you are unsure how `*args` and `**kwargs` work in Python,
> The `*args` and `**kwargs` must always be included. If you are unsure how `*args` and `**kwargs` work in Python,
> [read about them here](https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3).
The input from the innermost `$funcname(...)` call in your callable will always be a `str`. Here's
The input from the innermost `$funcname(...)` call in your callable will always be a `str`. Here's
an example of an `$toint` function; it converts numbers to integers.
"There's a $toint(22.0)% chance of survival."
What will enter the `$toint` callable (as `args[0]`) is the _string_ `"22.0"`. The function is responsible
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
inputs (like non-numbers).
If you want to mark an error, raise `evennia.utils.funcparser.ParsingError`. This stops the entire parsing
of the string and may or may not raise the exception depending on what you set `raise_errors` to when you
of the string and may or may not raise the exception depending on what you set `raise_errors` to when you
created the parser.
However, if you _nest_ functions, the return of the innermost function may be something other than
a string. Let's introduce the `$eval` function, which evaluates simple expressions using
However, if you _nest_ functions, the return of the innermost function may be something other than
a string. Let's introduce the `$eval` function, which evaluates simple expressions using
Python's `literal_eval` and/or `simple_eval`.
"There's a $toint($eval(10 * 2.2))% chance of survival."
"There's a $toint($eval(10 * 2.2))% chance of survival."
Since the `$eval` is the innermost call, it will get a string as input - the string `"10 * 2.2"`.
It evaluates this and returns the `float` `22.0`. This time the outermost `$toint` will be called with
this `float` instead of with a string.
Since the `$eval` is the innermost call, it will get a string as input - the string `"10 * 2.2"`.
It evaluates this and returns the `float` `22.0`. This time the outermost `$toint` will be called with
this `float` instead of with a string.
> It's important to safely validate your inputs since users may end up nesting your callables in any order.
> It's important to safely validate your inputs since users may end up nesting your callables in any order.
> See the next section for useful tools to help with this.
In these examples, the result will be embedded in the larger string, so the result of the entire parsing
will be a string:
In these examples, the result will be embedded in the larger string, so the result of the entire parsing
will be a string:
```python
parser.parse(above_string)
"There's a 22% chance of survival."
```
However, if you use the `parse_to_any` (or `parse(..., return_str=True)`) and _don't add any extra string around the outermost function call_,
However, if you use the `parse_to_any` (or `parse(..., return_str=True)`) and _don't add any extra string around the outermost function call_,
you'll get the return type of the outermost callable back:
```python
@ -194,13 +190,13 @@ parser.parse_to_any("$toint($eval(10 * 2.2)")
### Safe convertion of inputs
Since you don't know in which order users may use your callables, they should always check the types
of its inputs and convert to the type the callable needs. Note also that when converting from strings,
there are limits what inputs you can support. This is because FunctionParser strings are often used by
non-developer players/builders and some things (such as complex classes/callables etc) are just not
of its inputs and convert to the type the callable needs. Note also that when converting from strings,
there are limits what inputs you can support. This is because FunctionParser strings are often used by
non-developer players/builders and some things (such as complex classes/callables etc) are just not
safe/possible to convert from string representation.
In `evennia.utils.utils` is a helper called
[safe_convert_to_types](api:evennia.utils.utils#evennia.utils.utils.safe_convert_to_types). This function
In `evennia.utils.utils` is a helper called
[safe_convert_to_types](evennia.utils.utils.safe_convert_to_types). This function
automates the conversion of simple data types in a safe way:
```python
@ -208,94 +204,94 @@ from evennia.utils.utils import safe_convert_to_types
def _process_callable(*args, **kwargs):
"""
A callable with a lot of custom options
$process(expression, local, extra=34, extra2=foo)
A callable with a lot of custom options
$process(expression, local, extra=34, extra2=foo)
"""
args, kwargs = safe_convert_to_type(
(('py', 'py'), {'extra1': int, 'extra2': str}),
(('py', 'py'), {'extra1': int, 'extra2': str}),
*args, **kwargs)
# args/kwargs should be correct types now
# args/kwargs should be correct types now
```
In other words,
```python
```python
args, kwargs = safe_convert_to_type(
(tuple_of_arg_converters, dict_of_kwarg_converters), *args, **kwargs)
```
Each converter should be a callable taking one argument - this will be the arg/kwarg-value to convert. The
special converter `"py"` will try to convert a string argument to a Python structure with the help of the
following tools (which you may also find useful to experiment with on your own):
Each converter should be a callable taking one argument - this will be the arg/kwarg-value to convert. The
special converter `"py"` will try to convert a string argument to a Python structure with the help of the
following tools (which you may also find useful to experiment with on your own):
- [ast.literal_eval](https://docs.python.org/3.8/library/ast.html#ast.literal_eval) is an in-built Python
function. It
_only_ supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and `None`. That's
it - no arithmetic or modifications of data is allowed. This is good for converting individual values and
lists/dicts from the input line to real Python objects.
- [simpleeval](https://pypi.org/project/simpleeval/) is a third-party tool included with Evennia. This
allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings
with +-/* as well as do simple comparisons like `4 > 3` and more. It does _not_ accept more complex
- [simpleeval](https://pypi.org/project/simpleeval/) is a third-party tool included with Evennia. This
allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings
with `+-/*` as well as do simple comparisons like `4 > 3` and more. It does _not_ accept more complex
containers like lists/dicts etc, so this and `literal_eval` are complementary to each other.
```warning::
It may be tempting to run use Python's in-built ``eval()`` or ``exec()`` functions as converters since
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
know that ONLY developers will ever modify the string going into the callable. The parser is intended
for untrusted users (if you were trusted you'd have access to Python already). Letting untrusted users
pass strings to ``eval``/``exec`` is a MAJOR security risk. It allows the caller to run arbitrary
Python code on your server. This is the path to maliciously deleted hard drives. Just don't do it and
```{warning}
It may be tempting to run use Python's in-built ``eval()`` or ``exec()`` functions as converters since
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
know that ONLY developers will ever modify the string going into the callable. The parser is intended
for untrusted users (if you were trusted you'd have access to Python already). Letting untrusted users
pass strings to ``eval``/``exec`` is a MAJOR security risk. It allows the caller to run arbitrary
Python code on your server. This is the path to maliciously deleted hard drives. Just don't do it and
sleep better at night.
```
## Default callables
These are some example callables you can import and add your parser. They are divided into
global-level dicts in `evennia.utils.funcparser`. Just import the dict(s) and merge/add one or
These are some example callables you can import and add your parser. They are divided into
global-level dicts in `evennia.utils.funcparser`. Just import the dict(s) and merge/add one or
more to them when you create your `FuncParser` instance to have those callables be available.
### `evennia.utils.funcparser.FUNCPARSER_CALLABLES`
These are the 'base' callables.
- `$eval(expression)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_eval)) -
this uses `literal_eval` and `simple_eval` (see previous section) attemt to convert a string expression
- `$eval(expression)` ([code](evennia.utils.funcparser.funcparser_callable_eval)) -
this uses `literal_eval` and `simple_eval` (see previous section) attemt to convert a string expression
to a python object. This handles e.g. lists of literals `[1, 2, 3]` and simple expressions like `"1 + 2"`.
- `$toint(number)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_toint)) -
- `$toint(number)` ([code](evennia.utils.funcparser.funcparser_callable_toint)) -
always converts an output to an integer, if possible.
- `$add/sub/mult/div(obj1, obj2)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_add)) -
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
`$eval`, this could for example be used also to add two lists together, which is not possible with `eval`;
- `$add/sub/mult/div(obj1, obj2)` ([code](evennia.utils.funcparser.funcparser_callable_add)) -
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
`$eval`, this could for example be used also to add two lists together, which is not possible with `eval`;
for example `$add($eval([1,2,3]), $eval([4,5,6])) -> [1, 2, 3, 4, 5, 6]`.
- `$round(float, significant)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_round)) -
- `$round(float, significant)` ([code](evennia.utils.funcparser.funcparser_callable_round)) -
rounds an input float into the number of provided significant digits. For example `$round(3.54343, 3) -> 3.543`.
- `$random([start, [end]])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_random)) -
this works like the Python `random()` function, but will randomize to an integer value if both start/end are
- `$random([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_random)) -
this works like the Python `random()` function, but will randomize to an integer value if both start/end are
integers. Without argument, will return a float between 0 and 1.
- `$randint([start, [end]])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_randint)) -
- `$randint([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_randint)) -
works like the `randint()` python function and always returns an integer.
- `$choice(list)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_choice)) -
the input will automatically be parsed the same way as `$eval` and is expected to be an iterable. A random
- `$choice(list)` ([code](evennia.utils.funcparser.funcparser_callable_choice)) -
the input will automatically be parsed the same way as `$eval` and is expected to be an iterable. A random
element of this list will be returned.
- `$pad(text[, width, align, fillchar])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_pad)) -
- `$pad(text[, width, align, fillchar])` ([code](evennia.utils.funcparser.funcparser_callable_pad)) -
this will pad content. `$pad("Hello", 30, c, -)` will lead to a text centered in a 30-wide block surrounded by `-`
characters.
- `$crop(text, width=78, suffix='[...]')` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_crop)) -
- `$crop(text, width=78, suffix='[...]')` ([code](evennia.utils.funcparser.funcparser_callable_crop)) -
this will crop a text longer than the width, by default ending it with a `[...]`-suffix that also fits within
the width. If no width is given, the client width or `settings.DEFAULT_CLIENT_WIDTH` will be used.
- `$space(num)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_space)) -
- `$space(num)` ([code](evennia.utils.funcparser.funcparser_callable_space)) -
this will insert `num` spaces.
- `$just(string, width=40, align=c, indent=2)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_justify)) -
- `$just(string, width=40, align=c, indent=2)` ([code](evennia.utils.funcparser.funcparser_callable_justify)) -
justifies the text to a given width, aligning it left/right/center or 'f' for full (spread text across width).
- `$ljust` - shortcut to justify-left. Takes all other kwarg of `$just`.
- `$rjust` - shortcut to right justify.
- `$cjust` - shortcut to center justify.
- `$clr(startcolor, text[, endcolor])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_clr)) -
color text. The color is given with one or two characters without the preceeding `|`. If no endcolor is
- `$clr(startcolor, text[, endcolor])` ([code](evennia.utils.funcparser.funcparser_callable_clr)) -
color text. The color is given with one or two characters without the preceeding `|`. If no endcolor is
given, the string will go back to neutral, so `$clr(r, Hello)` is equivalent to `|rHello|n`.
### `evennia.utils.funcparser.SEARCHING_CALLABLES`
@ -304,15 +300,16 @@ These are callables that requires access-checks in order to search for objects.
extra reserved kwargs to be passed when running the parser:
```python
parser.parse_to_any(string, caller=<object or account>, access="control", ...)`
parser.parse_to_any(string, caller=<object or account>, access="control", ...)
```
The `caller` is required, it's the the object to do the access-check for. The `access` kwarg is the
[lock type](./Locks) to check, default being `"control"`.
The `caller` is required, it's the the object to do the access-check for. The `access` kwarg is the
[lock type](./Locks.md) to check, default being `"control"`.
- `$search(query,type=account|script,return_list=False)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_search)) -
this will look up and try to match an object by key or alias. Use the `type` kwarg to
search for `account` or `script` instead. By default this will return nothing if there are more than one
- `$search(query,type=account|script,return_list=False)` ([code](evennia.utils.funcparser.funcparser_callable_search)) -
this will look up and try to match an object by key or alias. Use the `type` kwarg to
search for `account` or `script` instead. By default this will return nothing if there are more than one
match; if `return_list` is `True` a list of 0, 1 or more matches will be returned instead.
- `$obj(query)`, `$dbref(query)` - legacy aliases for `$search`.
- `$objlist(query)` - legacy alias for `$search`, always returning a list.
@ -320,9 +317,9 @@ The `caller` is required, it's the the object to do the access-check for. The `a
### `evennia.utils.funcparser.ACTOR_STANCE_CALLABLES`
These are used to implement actor-stance emoting. They are used by the
[DefaultObject.msg_contents](api:evennia.objects.objects#evennia.objects.objects.DefaultObject.msg_contents) method
by default.
These are used to implement actor-stance emoting. They are used by the
[DefaultObject.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method
by default.
These all require extra kwargs be passed into the parser:
@ -333,16 +330,16 @@ parser.parse(string, caller=<obj>, receiver=<obj>, mapping={'key': <obj>, ...})
Here the `caller` is the one sending the message and `receiver` the one to see it. The `mapping` contains
references to other objects accessible via these callables.
- `$you([key])` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_you)) -
if no `key` is given, this represents the `caller`, otherwise an object from `mapping`
will be used. As this message is sent to different recipients, the `receiver` will change and this will
be replaced either with the string `you` (if you and the receiver is the same entity) or with the
- `$you([key])` ([code](evennia.utils.funcparser.funcparser_callable_you)) -
if no `key` is given, this represents the `caller`, otherwise an object from `mapping`
will be used. As this message is sent to different recipients, the `receiver` will change and this will
be replaced either with the string `you` (if you and the receiver is the same entity) or with the
result of `you_obj.get_display_name(looker=receiver)`. This allows for a single string to echo differently
depending on who sees it, and also to reference other people in the same way.
- `$You([key])` - same as `$you` but always capitalized.
- `$conj(verb)` ([code](api:evennia.utils.funcparser#evennia.utils.funcparser.funcparser_callable_conjugate)) -- conjugates a verb between 4nd person presens to 3rd person presence depending on who
- `$conj(verb)` ([code](evennia.utils.funcparser.funcparser_callable_conjugate)) -- conjugates a verb between 4nd person presens to 3rd person presence depending on who
sees the string. For example `"$You() $conj(smiles)".` will show as "You smile." and "Tom smiles." depending
on who sees it. This makes use of the tools in [evennia.utils.verb_conjugation](api:evennia.utils.verb_conjugation)
on who sees it. This makes use of the tools in [evennia.utils.verb_conjugation](evennia.utils.verb_conjugation)
to do this, and only works for English verbs.
### Example
@ -377,10 +374,10 @@ result = parser.parse(string)
```
Above we define two callables `_dashline` and `_uptime` and map them to names `"dashline"` and `"uptime"`,
which is what we then can call as `$header` and `$uptime` in the string. We also have access to
which is what we then can call as `$header` and `$uptime` in the string. We also have access to
all the defaults (like `$toint()`).
The parsed result of the above would be something like this:
The parsed result of the above would be something like this:
This is the current uptime:
------- 343 seconds -------
------- 343 seconds -------

View file

@ -64,7 +64,7 @@ regular code editor, see below).
Evennia collects help entries from three sources:
- _Auto-generated command help_ - this is literally the doc-strings of
the [Command classes](./Commands). The idea is that the command docs are
the [Command classes](./Commands.md). The idea is that the command docs are
easier to maintain and keep up-to-date if the developer can change them at the
same time as they do the code.
- _Database-stored help entries_ - These are created in-game (using the
@ -93,14 +93,14 @@ All help entries (no matter the source) have the following properties:
extra space at beginning and end.
A `text` that scrolls off the screen will automatically be paginated by
the [EvMore](./EvMore) pager (you can control this with
the [EvMore](./EvMore.md) pager (you can control this with
`settings.HELP_MORE_ENABLED=False`). If you use EvMore and want to control
exactly where the pager should break the page, mark the break with the control
character `\f`.
#### Subtopics
```versionadded:: 1.0
```{versionadded} 1.0
```
Rather than making a very long help entry, the `text` may also be broken up
@ -199,7 +199,7 @@ The text at the very top of the command class definition is the class'
consistent format - all default commands are using the structure shown above.
You can limit access to the help entry by the `view` and/or `read` locks on the
Command. See [the section below](#Locking-help-entries) for details.
Command. See [the section below](./Help-System.md#locking-help-entries) for details.
You should also supply the `help_category` class property if you can; this helps
to group help entries together for people to more easily find them. See the
@ -209,7 +209,7 @@ used.
If you don't want your command to be picked up by the auto-help system at all
(like if you want to write its docs manually using the info in the next section
or you use a [cmdset](./Command-Sets) that has its own help functionality) you
or you use a [cmdset](./Command-Sets.md) that has its own help functionality) you
can explicitly set `auto_help` class property to `False` in your command
definition.
@ -233,8 +233,8 @@ entry = create_help_entry("emote",
category="Roleplaying", locks="view:all()")
```
The entity being created is a [evennia.help.models.HelpEntry](api:evennia.help.models.HelpEntry)
object. This is _not_ a [Typeclassed](./Typeclasses) entity and is not meant to
The entity being created is a [evennia.help.models.HelpEntry](evennia.help.models.HelpEntry)
object. This is _not_ a [Typeclassed](./Typeclasses.md) entity and is not meant to
be modified to any great degree. It holds the properties listed earlier. The
text is stored in a field `entrytext`. It does not provide a `get_help` method
like commands, stores and returns the `entrytext` directly.
@ -244,7 +244,7 @@ this will not return the two other types of help entries.
### File-help entries
```versionadded:: 1.0
```{versionadded} 1.0
```
File-help entries are created by the game development team outside of the game. The
@ -369,7 +369,7 @@ help_entry = {
```
```versionchanged:: 1.0
```{versionchanged} 1.0
Changed the old 'view' lock to control the help-index inclusion and added
the new 'read' lock-type to control access to the entry itself.
```
@ -377,7 +377,7 @@ help_entry = {
## Customizing the look of the help system
This is done almost exclusively by overriding the `help` command
[evennia.commands.default.help.CmdHelp](api:evennia.commands.default.help#CmdHelp).
[evennia.commands.default.help.CmdHelp](evennia.commands.default.help.CmdHelp).
Since the available commands may vary from moment to moment, `help` is
responsible for collating the three sources of help-entries (commands/db/file)
@ -401,7 +401,7 @@ Once the main entry has been found, subtopics are then searched with
simple `==`, `startswith` and `in` matching (there are so relatively few of them
at that point).
```versionchanged:: 1.0
```{versionchanged} 1.0
Replaced the old bag-of-words algorithm with lunr package.
```

View file

@ -1,9 +1,9 @@
# Inputfuncs
An *inputfunc* is an Evennia function that handles a particular input (an [inputcommand](../Concepts/OOB)) from
An *inputfunc* is an Evennia function that handles a particular input (an [inputcommand](../Concepts/OOB.md)) from
the client. The inputfunc is the last destination for the inputcommand along the [ingoing message
path](Messagepath#the-ingoing-message-path). The inputcommand always has the form `(commandname,
path](../Concepts/Messagepath.md#the-ingoing-message-path). The inputcommand always has the form `(commandname,
(args), {kwargs})` and Evennia will use this to try to find and call an inputfunc on the form
```python
@ -42,7 +42,7 @@ Evennia defines a few default inputfuncs to handle the common cases. These are d
This is the most common of inputcommands, and the only one supported by every traditional mud. The
argument is usually what the user sent from their command line. Since all text input from the user
like this is considered a [Command](./Commands), this inputfunc will do things like nick-replacement
like this is considered a [Command](./Commands.md), this inputfunc will do things like nick-replacement
and then pass on the input to the central Commandhandler.
### echo
@ -134,7 +134,7 @@ to expand. By default the following values can be retrieved:
accepted names if given an unfamiliar callback name.
This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes
this will set up a [Ticker](./TickerHandler). Only previously acceptable functions are possible to
this will set up a [Ticker](./TickerHandler.md). Only previously acceptable functions are possible to
repeat-call in this way, you'll need to overload this inputfunc to add the ones you want to offer.
By default only two example functions are allowed, "test1" and "test2", which will just echo a text
back at the given interval. Stop the repeat by sending `"stop": True` (note that you must include
@ -155,7 +155,7 @@ This is a convenience wrapper for sending "stop" to the `repeat` inputfunc.
This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute
changes in any way, the outputcommand will be sent. This is using the
[MonitorHandler](./MonitorHandler) behind the scenes. Pass the "stop" key to stop monitoring. Note
[MonitorHandler](./MonitorHandler.md) behind the scenes. Pass the "stop" key to stop monitoring. Note
that you must supply the name also when stopping to let the system know which monitor should be
cancelled.

View file

@ -2,9 +2,9 @@
For most games it is a good idea to restrict what people can do. In Evennia such restrictions are
applied and checked by something called *locks*. All Evennia entities ([Commands](./Commands),
[Objects](./Objects), [Scripts](./Scripts), [Accounts](./Accounts), [Help System](./Help-System),
[messages](./Communications#Msg) and [channels](./Communications#Channels)) are accessed through locks.
applied and checked by something called *locks*. All Evennia entities ([Commands](./Commands.md),
[Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md), [Help System](./Help-System.md),
[messages](./Msg.md) and [channels](./Channels.md)) are accessed through locks.
A lock can be thought of as an "access rule" restricting a particular use of an Evennia entity.
Whenever another entity wants that kind of access the lock will analyze that entity in different
@ -92,9 +92,9 @@ the default command set) actually checks for, as in the example of `delete` abov
Below are the access_types checked by the default commandset.
- [Commands](./Commands)
- [Commands](./Commands.md)
- `cmd` - this defines who may call this command at all.
- [Objects](./Objects):
- [Objects](./Objects.md):
- `control` - who is the "owner" of the object. Can set locks, delete it etc. Defaults to the
creator of the object.
- `call` - who may call Object-commands stored on this Object except for the Object itself. By
@ -109,26 +109,26 @@ something like `call:false()`.
- `get`- who may pick up the object and carry it around.
- `puppet` - who may "become" this object and control it as their "character".
- `attrcreate` - who may create new attributes on the object (default True)
- [Characters](./Objects#Characters):
- [Characters](./Objects.md#characters):
- Same as for Objects
- [Exits](./Objects#Exits):
- [Exits](./Objects.md#exits):
- Same as for Objects
- `traverse` - who may pass the exit.
- [Accounts](./Accounts):
- [Accounts](./Accounts.md):
- `examine` - who may examine the account's properties.
- `delete` - who may delete the account.
- `edit` - who may edit the account's attributes and properties.
- `msg` - who may send messages to the account.
- `boot` - who may boot the account.
- [Attributes](./Attributes): (only checked by `obj.secure_attr`)
- [Attributes](./Attributes.md): (only checked by `obj.secure_attr`)
- `attrread` - see/access attribute
- `attredit` - change/delete attribute
- [Channels](./Communications#Channels):
- [Channels](./Channels.md):
- `control` - who is administrating the channel. This means the ability to delete the channel,
boot listeners etc.
- `send` - who may send to the channel.
- `listen` - who may subscribe and listen to the channel.
- [HelpEntry](./Help-System):
- [HelpEntry](./Help-System.md):
- `examine` - who may view this help entry (usually everyone)
- `edit` - who may edit this help entry.
@ -214,10 +214,10 @@ Some useful default lockfuncs (see `src/locks/lockfuncs.py` for more):
- `false()/none()/superuser()` - give access to none. Superusers bypass the check entirely and are
thus the only ones who will pass this check.
- `perm(perm)` - this tries to match a given `permission` property, on an Account firsthand, on a
Character second. See [below](./Locks#permissions).
Character second. See [below](./Permissions.md).
- `perm_above(perm)` - like `perm` but requires a "higher" permission level than the one given.
- `id(num)/dbref(num)` - checks so the access_object has a certain dbref/id.
- `attr(attrname)` - checks if a certain [Attribute](./Attributes) exists on accessing_object.
- `attr(attrname)` - checks if a certain [Attribute](./Attributes.md) exists on accessing_object.
- `attr(attrname, value)` - checks so an attribute exists on accessing_object *and* has the given
value.
- `attr_gt(attrname, value)` - checks so accessing_object has a value larger (`>`) than the given
@ -250,7 +250,7 @@ a Lock lookup.
## Default locks
Evennia sets up a few basic locks on all new objects and accounts (if we didn't, noone would have
any access to anything from the start). This is all defined in the root [Typeclasses](./Typeclasses)
any access to anything from the start). This is all defined in the root [Typeclasses](./Typeclasses.md)
of the respective entity, in the hook method `basetype_setup()` (which you usually don't want to
edit unless you want to change how basic stuff like rooms and exits store their internal variables).
This is called once, before `at_object_creation`, so just put them in the latter method on your
@ -300,7 +300,7 @@ whereas only Admins and the creator may delete it. Everyone can pick it up.
## A complete example of setting locks on an object
Assume we have two objects - one is ourselves (not superuser) and the other is an [Object](./Objects)
Assume we have two objects - one is ourselves (not superuser) and the other is an [Object](./Objects.md)
called `box`.
> create/drop box
@ -326,7 +326,7 @@ This is defined in `evennia/commands/default/general.py`. In its code we find th
```
So the `get` command looks for a lock with the type *get* (not so surprising). It also looks for an
[Attribute](./Attributes) on the checked object called _get_err_msg_ in order to return a customized
[Attribute](./Attributes.md) on the checked object called _get_err_msg_ in order to return a customized
error message. Sounds good! Let's start by setting that on the box:
> set box/get_err_msg = You are not strong enough to lift this box.

View file

@ -23,10 +23,10 @@ MONITOR_HANDLER.add(obj, fieldname, callback,
```
- `obj` ([Typeclassed](./Typeclasses) entity) - the object to monitor. Since this must be
typeclassed, it means you can't monitor changes on [Sessions](./Sessions) with the monitorhandler, for
- `obj` ([Typeclassed](./Typeclasses.md) entity) - the object to monitor. Since this must be
typeclassed, it means you can't monitor changes on [Sessions](./Sessions.md) with the monitorhandler, for
example.
- `fieldname` (str) - the name of a field or [Attribute](./Attributes) on `obj`. If you want to
- `fieldname` (str) - the name of a field or [Attribute](./Attributes.md) on `obj`. If you want to
monitor a database field you must specify its full name, including the starting `db_` (like
`db_key`, `db_location` etc). Any names not starting with `db_` are instead assumed to be the names
of Attributes. This difference matters, since the MonitorHandler will automatically know to watch

View file

@ -1,6 +1,6 @@
# Msg
The [Msg](api:evennia.comms.models.Msg) object represents a database-saved
The [Msg](evennia.comms.models.Msg) object represents a database-saved
piece of communication. Think of it as a discrete piece of email - it contains
a message, some metadata and will always have a sender and one or more
recipients.
@ -14,7 +14,7 @@ good uses for `Msg` objects:
- game-wide email stored in 'mailboxes'.
```important::
```{important}
A `Msg` does not have any in-game representation. So if you want to use them
to represent in-game mail/letters, the physical letters would never be
@ -25,15 +25,15 @@ good uses for `Msg` objects:
```
```versionchanged:: 1.0
```{versionchanged} 1.0
Channels dropped Msg-support. Now only used in `page` command by default.
```
## Msg in code
The Msg is intended to be used exclusively in code, to build other game systems. It is _not_
a [Typeclassed](./Typeclasses) entity, which means it cannot (easily) be overridden. It
doesn't support Attributes (but it _does_ support [Tags](./Tags)). It tries to be lean
a [Typeclassed](./Typeclasses.md) entity, which means it cannot (easily) be overridden. It
doesn't support Attributes (but it _does_ support [Tags](./Tags.md)). It tries to be lean
and small since a new one is created for every message.
You create a new message with `evennia.create_message`:
@ -62,7 +62,7 @@ You can search for `Msg` objects in various ways:
### Properties on Msg
- `senders` - there must always be at least one sender. This is a set of
- [Account](./Accounts), [Object](./Objects), [Script](./Scripts)
- [Account](./Accounts.md), [Object](./Objects.md), [Script](./Scripts.md)
or `str` in any combination (but usually a message only targets one type).
Using a `str` for a sender indicates it's an 'external' sender and
and can be used to point to a sender that is not a typeclassed entity. This is not used by default
@ -70,17 +70,17 @@ You can search for `Msg` objects in various ways:
python-path, for example). While most systems expect a single sender, it's
possible to have any number of them.
- `receivers` - these are the ones to see the Msg. These are again any combination of
[Account](./Accounts), [Object](./Objects) or [Script](./Scripts) or `str` (an 'external' receiver).
[Account](./Accounts.md), [Object](./Objects.md) or [Script](./Scripts.md) or `str` (an 'external' receiver).
It's in principle possible to have zero receivers but most usages of Msg expects one or more.
- `header` - this is an optional text field that can contain meta-information about the message. For
an email-like system it would be the subject line. This can be independently searched, making
this a powerful place for quickly finding messages.
- `message` - the actual text being sent.
- `date_sent` - this is auto-set to the time the Msg was created (and thus presumably sent).
- `locks` - the Evennia [lock handler](./Locks). Use with `locks.add()` etc and check locks with `msg.access()`
- `locks` - the Evennia [lock handler](./Locks.md). Use with `locks.add()` etc and check locks with `msg.access()`
like for all other lockable entities. This can be used to limit access to the contents
of the Msg. The default lock-type to check is `'read'`.
- `hide_from` - this is an optional list of [Accounts](./Accounts) or [Objects](./Objects) that
- `hide_from` - this is an optional list of [Accounts](./Accounts.md) or [Objects](./Objects.md) that
will not see this Msg. This relationship is available mainly for optimization
reasons since it allows quick filtering of messages not intended for a given
target.
@ -88,7 +88,7 @@ You can search for `Msg` objects in various ways:
## TempMsg
[evennia.comms.models.TempMsg](api:evennia.comms.models.TempMsg) is an object
[evennia.comms.models.TempMsg](evennia.comms.models.TempMsg) is an object
that implements the same API as the regular `Msg`, but which has no database
component (and thus cannot be searched). It's meant to plugged into systems
expecting a `Msg` but where you just want to process the message without saving

View file

@ -1,7 +1,7 @@
# Nicks
*Nicks*, short for *Nicknames* is a system allowing an object (usually a [Account](./Accounts)) to
*Nicks*, short for *Nicknames* is a system allowing an object (usually a [Account](./Accounts.md)) to
assign custom replacement names for other game entities.
Nicks are not to be confused with *Aliases*. Setting an Alias on a game entity actually changes an
@ -75,7 +75,7 @@ You can also use [shell-type wildcards](http://www.linfo.org/wildcard.html):
## Coding with nicks
Nicks are stored as the `Nick` database model and are referred from the normal Evennia
[object](./Objects) through the `nicks` property - this is known as the *NickHandler*. The NickHandler
[object](./Objects.md) through the `nicks` property - this is known as the *NickHandler*. The NickHandler
offers effective error checking, searches and conversion.
```python
@ -101,12 +101,12 @@ offers effective error checking, searches and conversion.
In a command definition you can reach the nick handler through `self.caller.nicks`. See the `nick`
command in `evennia/commands/default/general.py` for more examples.
As a last note, The Evennia [channel](./Communications) alias systems are using nicks with the
As a last note, The Evennia [channel](./Communications.md) alias systems are using nicks with the
`nick_type="channel"` in order to allow users to create their own custom aliases to channels.
# Advanced note
Internally, nicks are [Attributes](./Attributes) saved with the `db_attrype` set to "nick" (normal
Internally, nicks are [Attributes](./Attributes.md) saved with the `db_attrype` set to "nick" (normal
Attributes has this set to `None`).
The nick stores the replacement data in the Attribute.db_value field as a tuple with four fields

View file

@ -3,7 +3,7 @@
All in-game objects in Evennia, be it characters, chairs, monsters, rooms or hand grenades are
represented by an Evennia *Object*. Objects form the core of Evennia and is probably what you'll
spend most time working with. Objects are [Typeclassed](./Typeclasses) entities.
spend most time working with. Objects are [Typeclassed](./Typeclasses.md) entities.
## How to create your own object types
@ -48,17 +48,17 @@ thing yourself in code:
call manually you have to give the full path to the class. The `create.create_object` function is
powerful and should be used for all coded object creating (so this is what you use when defining
your own building commands). Check out the `ev.create_*` functions for how to build other entities
like [Scripts](./Scripts)).
like [Scripts](./Scripts.md)).
This particular Rose class doesn't really do much, all it does it make sure the attribute
`desc`(which is what the `look` command looks for) is pre-set, which is pretty pointless since you
will usually want to change this at build time (using the `@desc` command or using the
[Spawner](./Prototypes)). The `Object` typeclass offers many more hooks that is available
[Spawner](./Prototypes.md)). The `Object` typeclass offers many more hooks that is available
to use though - see next section.
## Properties and functions on Objects
Beyond the properties assigned to all [typeclassed](./Typeclasses) objects (see that page for a list
Beyond the properties assigned to all [typeclassed](./Typeclasses.md) objects (see that page for a list
of those), the Object also has the following custom properties:
- `aliases` - a handler that allows you to add and remove aliases from this object. Use
@ -67,12 +67,12 @@ of those), the Object also has the following custom properties:
- `home` is a backup location. The main motivation is to have a safe place to move the object to if
its `location` is destroyed. All objects should usually have a home location for safety.
- `destination` - this holds a reference to another object this object links to in some way. Its
main use is for [Exits](./Objects#Exits), it's otherwise usually unset.
- `nicks` - as opposed to aliases, a [Nick](./Nicks) holds a convenient nickname replacement for a
main use is for [Exits](./Objects.md#exits), it's otherwise usually unset.
- `nicks` - as opposed to aliases, a [Nick](./Nicks.md) holds a convenient nickname replacement for a
real name, word or sequence, only valid for this object. This mainly makes sense if the Object is
used as a game character - it can then store briefer shorts, example so as to quickly reference game
commands or other characters. Use nicks.add(alias, realname) to add a new one.
- `account` - this holds a reference to a connected [Account](./Accounts) controlling this object (if
- `account` - this holds a reference to a connected [Account](./Accounts.md) controlling this object (if
any). Note that this is set also if the controlling account is *not* currently online - to test if
an account is online, use the `has_account` property instead.
- `sessions` - if `account` field is set *and the account is online*, this is a list of all active
@ -87,9 +87,9 @@ object set as their `location`).
The last two properties are special:
- `cmdset` - this is a handler that stores all [command sets](./Commands#Command_Sets) defined on the
- `cmdset` - this is a handler that stores all [command sets](./Command-Sets.md) defined on the
object (if any).
- `scripts` - this is a handler that manages [Scripts](./Scripts) attached to the object (if any).
- `scripts` - this is a handler that manages [Scripts](./Scripts.md) attached to the object (if any).
The Object also has a host of useful utility functions. See the function headers in
`src/objects/objects.py` for their arguments and more details.
@ -104,7 +104,7 @@ on).
- `execute_cmd()` - Lets the object execute the given string as if it was given on the command line.
- `move_to` - perform a full move of this object to a new location. This is the main move method
and will call all relevant hooks, do all checks etc.
- `clear_exits()` - will delete all [Exits](./Objects#Exits) to *and* from this object.
- `clear_exits()` - will delete all [Exits](./Objects.md#exits) to *and* from this object.
- `clear_contents()` - this will not delete anything, but rather move all contents (except Exits) to
their designated `Home` locations.
- `delete()` - deletes this object, first calling `clear_exits()` and
@ -113,8 +113,7 @@ their designated `Home` locations.
The Object Typeclass defines many more *hook methods* beyond `at_object_creation`. Evennia calls
these hooks at various points. When implementing your custom objects, you will inherit from the
base parent and overload these hooks with your own custom code. See `evennia.objects.objects` for an
updated list of all the available hooks or the [API for DefaultObject
here](api:evennia.objects.objects#defaultobject).
updated list of all the available hooks or the [API for DefaultObject here](evennia.objects.objects.DefaultObject).
## Subclasses of `Object`
@ -126,10 +125,10 @@ practice they are all pretty similar to the base Object.
### Characters
Characters are objects controlled by [Accounts](./Accounts). When a new Account
Characters are objects controlled by [Accounts](./Accounts.md). When a new Account
logs in to Evennia for the first time, a new `Character` object is created and
the Account object is assigned to the `account` attribute. A `Character` object
must have a [Default Commandset](./Commands#Command_Sets) set on itself at
must have a [Default Commandset](./Command-Sets.md) set on itself at
creation, or the account will not be able to issue any commands! If you just
inherit your own class from `evennia.DefaultCharacter` and make sure to use
`super()` to call the parent methods you should be fine. In
@ -150,21 +149,21 @@ you to modify.
*in* might be an exit, as well as *door*, *portal* or *jump out the window*. An exit has two things
that separate them from other objects. Firstly, their *destination* property is set and points to a
valid object. This fact makes it easy and fast to locate exits in the database. Secondly, exits
define a special [Transit Command](./Commands) on themselves when they are created. This command is
define a special [Transit Command](./Commands.md) on themselves when they are created. This command is
named the same as the exit object and will, when called, handle the practicalities of moving the
character to the Exits's *destination* - this allows you to just enter the name of the exit on its
own to move around, just as you would expect.
The exit functionality is all defined on the Exit typeclass, so you could in principle completely
change how exits work in your game (it's not recommended though, unless you really know what you are
doing). Exits are [locked](./Locks) using an access_type called *traverse* and also make use of a few
doing). Exits are [locked](./Locks.md) using an access_type called *traverse* and also make use of a few
hook methods for giving feedback if the traversal fails. See `evennia.DefaultExit` for more info.
In `mygame/typeclasses/exits.py` there is an empty `Exit` class for you to modify.
The process of traversing an exit is as follows:
1. The traversing `obj` sends a command that matches the Exit-command name on the Exit object. The
[cmdhandler](./Commands) detects this and triggers the command defined on the Exit. Traversal always
[cmdhandler](./Commands.md) detects this and triggers the command defined on the Exit. Traversal always
involves the "source" (the current location) and the `destination` (this is stored on the Exit
object).
1. The Exit command checks the `traverse` lock on the Exit object

View file

@ -1,3 +1,3 @@
# Outputfuncs
TODO. For now info about outputfuncs are found in [OOB](../Concepts/OOB).
TODO. For now info about outputfuncs are found in [OOB](../Concepts/OOB.md).

View file

@ -1,15 +1,15 @@
# Permissions
A *permission* is simply a text string stored in the handler `permissions` on `Objects`
and `Accounts`. Think of it as a specialized sort of [Tag](./Tags) - one specifically dedicated
to access checking. They are thus often tightly coupled to [Locks](./Locks).
and `Accounts`. Think of it as a specialized sort of [Tag](./Tags.md) - one specifically dedicated
to access checking. They are thus often tightly coupled to [Locks](./Locks.md).
Permission strings are not case-sensitive, so "Builder" is the same as "builder"
etc.
Permissions are used as a convenient way to structure access levels and
hierarchies. It is set by the `perm` command and checked by the
`PermissionHandler.check` method as well as by the specially the `perm()` and
`pperm()` [lock functions](./Locks).
`pperm()` [lock functions](./Locks.md).
All new accounts are given a default set of permissions defined by
`settings.PERMISSION_ACCOUNT_DEFAULT`.
@ -22,7 +22,7 @@ In-game, you use the `perm` command to add and remove permissions
perm/account/del Tommy = Builders
Note the use of the `/account` switch. It means you assign the permission to the
[Accounts](./Accounts) Tommy instead of any [Character](./Objects) that also
[Accounts](./Accounts.md) Tommy instead of any [Character](./Objects.md) that also
happens to be named "Tommy".
There can be reasons for putting permissions on Objects (especially NPCS), but
@ -32,7 +32,7 @@ of which Character they are currently puppeting. This is especially important to
remember when assigning permissions from the *hierarchy tree* (see below), as an
Account's permissions will overrule that of its character. So to be sure to
avoid confusion you should generally put hierarchy permissions on the Account,
not on their Characters (but see also [quelling](./Locks#Quelling)).
not on their Characters (but see also [quelling](#quelling)).
In code, you add/remove Permissions via the `PermissionHandler`, which sits on all
typeclassed entities as the property `.permissions`:
@ -73,7 +73,7 @@ that permission to pass.
## Checking permissions
It's important to note that you check for the permission of a *puppeted*
[Object](./Objects) (like a Character), the check will always first use the
[Object](./Objects.md) (like a Character), the check will always first use the
permissions of any `Account` connected to that Object before checking for
permissions on the Object. In the case of hierarchical permissions (Admins,
Builders etc), the Account permission will always be used (this stops an Account
@ -99,7 +99,7 @@ _PermissionHandler_, stored as `.permissions` on all typeclassed entities.
Using the `.check` method is the way to go, it will take hierarchical
permissions into account, check accounts/sessions etc.
```warning
```{warning}
Don't confuse `.permissions.check()` with `.permissions.has()`. The .has()
method checks if a string is defined specifically on that PermissionHandler.
@ -111,7 +111,7 @@ permissions into account, check accounts/sessions etc.
### Lock funcs
While the `PermissionHandler` offers a simple way to check perms, [Lock
strings](Locks) offers a mini-language for describing how something is accessed.
strings](./Locks.md) offers a mini-language for describing how something is accessed.
The `perm()` _lock function_ is the main tool for using Permissions in locks.
Let's say we have a `red_key` object. We also have red chests that we want to
@ -153,7 +153,6 @@ There are several variations to the default `perm` lockfunc:
objects (regardless of hierarchical perm or not).
- `pperm_above` - like `perm_above`, but for Accounts only.
### Some examples
Adding permissions and checking with locks

View file

@ -2,7 +2,7 @@
Evennia consists of two processes, known as *Portal* and *Server*. They can be controlled from
inside the game or from the command line as described [here](../Setup/Start-Stop-Reload).
inside the game or from the command line as described [here](../Setup/Start-Stop-Reload.md).
If you are new to the concept, the main purpose of separating the two is to have accounts connect to
the Portal but keep the MUD running on the Server. This way one can restart/reload the game (the

View file

@ -2,10 +2,10 @@
The *spawner* is a system for defining and creating individual objects from a base template called a
*prototype*. It is only designed for use with in-game [Objects](./Objects), not any other type of
*prototype*. It is only designed for use with in-game [Objects](./Objects.md), not any other type of
entity.
The normal way to create a custom object in Evennia is to make a [Typeclass](./Typeclasses). If you
The normal way to create a custom object in Evennia is to make a [Typeclass](./Typeclasses.md). If you
haven't read up on Typeclasses yet, think of them as normal Python classes that save to the database
behind the scenes. Say you wanted to create a "Goblin" enemy. A common way to do this would be to
first create a `Mobile` typeclass that holds everything common to mobiles in the game, like generic
@ -105,12 +105,12 @@ instead.
exist.
- `destination` - a valid `#dbref`. Only used by exits.
- `permissions` - list of permission strings, like `["Accounts", "may_use_red_door"]`
- `locks` - a [lock-string](./Locks) like `"edit:all();control:perm(Builder)"`
- `locks` - a [lock-string](./Locks.md) like `"edit:all();control:perm(Builder)"`
- `aliases` - list of strings for use as aliases
- `tags` - list [Tags](./Tags). These are given as tuples `(tag, category, data)`.
- `attrs` - list of [Attributes](./Attributes). These are given as tuples `(attrname, value,
- `tags` - list [Tags](./Tags.md). These are given as tuples `(tag, category, data)`.
- `attrs` - list of [Attributes](./Attributes.md). These are given as tuples `(attrname, value,
category, lockstring)`
- Any other keywords are interpreted as non-category [Attributes](./Attributes) and their values.
- Any other keywords are interpreted as non-category [Attributes](./Attributes.md) and their values.
This is
convenient for simple Attributes - use `attrs` for full control of Attributes.
@ -119,7 +119,7 @@ Deprecated as of Evennia 0.8:
- `ndb_<name>` - sets the value of a non-persistent attribute (`"ndb_"` is stripped from the name).
This is simply not useful in a prototype and is deprecated.
- `exec` - This accepts a code snippet or a list of code snippets to run. This should not be used -
use callables or [$protfuncs](./Prototypes#protfuncs) instead (see below).
use callables or [$protfuncs](./Prototypes.md#protfuncs) instead (see below).
### Prototype values
@ -160,10 +160,8 @@ that you embed in strings and that has a `$` in front, like
"He has $randint(2,5) skulls in a chain around his neck."}
```
At execution time, the place of the protfunc will be replaced with the result of that protfunc being
called (this is always a string). A protfunc works in much the same way as an
[InlineFunc](../Concepts/TextTags#inline-functions) - they are actually
parsed using the same parser - except protfuncs are run every time the prototype is used to spawn a
new object (whereas an inlinefunc is called when a text is returned to the user).
called (this is always a string). A protfunc is a [FuncParser function](./FuncParser.md) run
every time the prototype is used to spawn a new object.
Here is how a protfunc is defined (same as an inlinefunc).
@ -233,7 +231,7 @@ A prototype can be defined and stored in two ways, either in the database or as
### Database prototypes
Stored as [Scripts](./Scripts) in the database. These are sometimes referred to as *database-
Stored as [Scripts](./Scripts.md) in the database. These are sometimes referred to as *database-
prototypes* This is the only way for in-game builders to modify and add prototypes. They have the
advantage of being easily modifiable and sharable between builders but you need to work with them
using in-game tools.

View file

@ -1,19 +1,19 @@
# Scripts
[Script API reference](api:evennia.scripts.scripts)
[Script API reference](evennia.scripts.scripts)
*Scripts* are the out-of-character siblings to the in-character
[Objects](./Objects). Scripts are so flexible that the name "Script" is a bit limiting
[Objects](./Objects.md). Scripts are so flexible that the name "Script" is a bit limiting
in itself - but we had to pick _something_ to name them. Other possible names
(depending on what you'd use them for) would be `OOBObjects`, `StorageContainers` or `TimerObjects`.
If you ever consider creating an [Object](./Objects) with a `None`-location just to store some game data,
If you ever consider creating an [Object](./Objects.md) with a `None`-location just to store some game data,
you should really be using a Script instead.
- Scripts are full [Typeclassed](./Typeclasses) entities - they have [Attributes](./Attributes) and
- Scripts are full [Typeclassed](./Typeclasses.md) entities - they have [Attributes](./Attributes.md) and
can be modified in the same way. But they have _no in-game existence_, so no
location or command-execution like [Objects](./Objects) and no connection to a particular
player/session like [Accounts](./Accounts). This means they are perfectly suitable for acting
location or command-execution like [Objects](./Objects.md) and no connection to a particular
player/session like [Accounts](./Accounts.md). This means they are perfectly suitable for acting
as database-storage backends for game _systems_: Storing the current state of the economy,
who is involved in the current fight, tracking an ongoing barter and so on. They are great as
persistent system handlers.
@ -21,22 +21,22 @@ you should really be using a Script instead.
to tick the `at_repeat` hook on the Script at a certain interval. The timer can be controlled
independently of the rest of the script as needed. This component is optional
and complementary to other timing functions in Evennia, like
[evennia.utils.delay](api:evennia.utils.utils#evennia.utils.utils.delay) and
[evennia.utils.repeat](api:evennia.utils.utils#evennia.utils.utils.repeat).
[evennia.utils.delay](evennia.utils.utils.delay) and
[evennia.utils.repeat](evennia.utils.utils.repeat).
- Scripts can _attach_ to Objects and Accounts via e.g. `obj.scripts.add/remove`. In the
script you can then access the object/account as `self.obj` or `self.account`. This can be used to
dynamically extend other typeclasses but also to use the timer component to affect the parent object
in various ways. For historical reasons, a Script _not_ attached to an object is referred to as a
_Global_ Script.
```versionchanged:: 1.0
```{versionchanged} 1.0
In previus Evennia versions, stopping the Script's timer also meant deleting the Script object.
Starting with this version, the timer can be start/stopped separately and `.delete()` must be called
on the Script explicitly to delete it.
```
### In-game command examples
## In-game command examples
There are two main commands controlling scripts in the default cmdset:
@ -52,11 +52,11 @@ The `scripts` command is used to view all scripts and perform operations on them
> scripts/pause #11
> scripts/delete #566
```versionchanged:: 1.0
```{versionchanged} 1.0
The `addscript` command used to be only `script` which was easy to confuse with `scripts`.
```
### Code examples
## Code examples
Here are some examples of working with Scripts in-code (more details to follow in later
sections).
@ -111,13 +111,13 @@ new_script.delete()
timed_script.delete()
```
## Defining new Scripts
# Defining new Scripts
A Script is defined as a class and is created in the same way as other
[typeclassed](./Typeclasses) entities. The parent class is `evennia.DefaultScript`.
[typeclassed](./Typeclasses.md) entities. The parent class is `evennia.DefaultScript`.
### Simple storage script
## Simple storage script
In `mygame/typeclasses/scripts.py` is an empty `Script` class already set up. You
can use this as a base for your own scripts.
@ -162,12 +162,12 @@ evennia.create_script('typeclasses.scripts.MyScript', key="another name",
```
See the [create_script](api:evennia.utils.create#evennia.utils.create.create_script) and
[search_script](api:evennia.utils.search#evennia.utils.search.search_script) API documentation for more options
See the [create_script](evennia.utils.create.create_script) and
[search_script](evennia.utils.search.search_script) API documentation for more options
on creating and finding Scripts.
### Timed Scripts
## Timed Scripts
There are several properties one can set on the Script to control its timer component.
@ -229,11 +229,11 @@ The timer component is controlled with methods on the Script class:
- `.force_repeat()` - this prematurely forces `at_repeat` to be called right away. Doing so will reset the
countdown so that next call will again happen after `interval` seconds.
#### Script timers vs delay/repeat
### Script timers vs delay/repeat
If the _only_ goal is to get a repeat/delay effect, the
[evennia.utils.delay](api:evennia.utils.utils#evennia.utils.utils.delay) and
[evennia.utils.repeat](api:evennia.utils.utils#evennia.utils.utils.repeat) functions
[evennia.utils.delay](evennia.utils.utils.delay) and
[evennia.utils.repeat](evennia.utils.utils.repeat) functions
should generally be considered first. A Script is a lot 'heavier' to create/delete on the fly.
In fact, for making a single delayed call (`script.repeats==1`), the `utils.delay` call is
probably always the better choice.
@ -249,9 +249,9 @@ It's also worth noting that once the script object has _already been created_,
starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update
methods of the script also offers a bit more fine-control than using `utils.delays/repeat`.
### Script attached to another object
## Script attached to another object
Scripts can be attached to an [Account](./Accounts) or (more commonly) an [Object](./Objects).
Scripts can be attached to an [Account](./Accounts.md) or (more commonly) an [Object](./Objects.md).
If so, the 'parent object' will be available to the script as either `.obj` or `.account`.
@ -303,10 +303,10 @@ You can also attach the script as part of creating it:
create_script('typeclasses.weather.Weather', obj=myroom)
```
## Other Script methods
# Other Script methods
A Script has all the properties of a typeclassed object, such as `db` and `ndb`(see
[Typeclasses](./Typeclasses)). Setting `key` is useful in order to manage scripts (delete them by name
[Typeclasses](./Typeclasses.md)). Setting `key` is useful in order to manage scripts (delete them by name
etc). These are usually set up in the Script's typeclass, but can also be assigned on the fly as
keyword arguments to `evennia.create_script`.
@ -325,12 +325,12 @@ reload.
- `delete()` - same as for other typeclassed entities, this will delete the Script. Of note is that
it will also stop the timer (if it runs), leading to the `at_stop` hook being called.
In addition, Scripts support [Attributes](./Attributes), [Tags](./Tags) and [Locks](./Locks) etc like other
In addition, Scripts support [Attributes](./Attributes.md), [Tags](./Tags.md) and [Locks](./Locks.md) etc like other
Typeclassed entities.
See also the methods involved in controlling a [Timed Script](#Timed_Scripts) above.
See also the methods involved in controlling a [Timed Script](#timed-scripts) above.
## The GLOBAL_SCRIPTS container
# The GLOBAL_SCRIPTS container
A Script not attached to another entity is commonly referred to as a _Global_ script since it't available
to access from anywhere. This means they need to be searched for in order to be used.
@ -353,7 +353,7 @@ GLOBAL_SCRIPTS.weather.db.current_weather = "Cloudy"
```
```warning::
```{warning}
Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`.
If you were to create two global scripts with the same `key` (even with different typeclasses),
the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in
@ -389,10 +389,10 @@ GLOBAL_SCRIPTS = {
Above we add two scripts with keys `myscript` and `storagescript`respectively. The following dict
can be empty - the `settings.BASE_SCRIPT_TYPECLASS` will then be used. Under the hood, the provided
dict (along with the `key`) will be passed into `create_script` automatically, so
all the [same keyword arguments as for create_script](api:evennia.utils.create.create_script) are
all the [same keyword arguments as for create_script](evennia.utils.create.create_script) are
supported here.
```warning::
```{warning}
Before setting up Evennia to manage your script like this, make sure that your Script typeclass
does not have any critical errors (test it separately). If there are, you'll see errors in your log
and your Script will temporarily fall back to being a `DefaultScript` type.
@ -413,7 +413,7 @@ That is, if the script is deleted, next time you get it from `GLOBAL_SCRIPTS`, E
information in settings to recreate it for you on the fly.
## Hints: Dealing with Script Errors
# Hints: Dealing with Script Errors
Errors inside a timed, executing script can sometimes be rather terse or point to
parts of the execution mechanism that is hard to interpret. One way to make it

View file

@ -1,104 +0,0 @@
# Server Conf
Evennia runs out of the box without any changes to its settings. But there are several important
ways to customize the server and expand it with your own plugins.
## Settings file
The "Settings" file referenced throughout the documentation is the file
`mygame/server/conf/settings.py`. This is automatically created on the first run of `evennia --init`
(see the [Setup Quickstart](../Setup/Setup-Quickstart) page).
Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is actually
[evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default.py)
and is considerably more extensive (it is also heavily documented so you should refer to this file
directly for the available settings).
Since `mygame/server/conf/settings.py` is a normal Python module, it simply imports
`evennia/settings_default.py` into itself at the top.
This means that if any setting you want to change were to depend on some *other* default setting,
you might need to copy & paste both in order to change them and get the effect you want (for most
commonly changed settings, this is not something you need to worry about).
You should never edit `evennia/settings_default.py`. Rather you should copy&paste the select
variables you want to change into your `settings.py` and edit them there. This will overload the
previously imported defaults.
> Warning: It may be tempting to copy everything from `settings_default.py` into your own settings
file. There is a reason we don't do this out of the box though: it makes it directly clear what
changes you did. Also, if you limit your copying to the things you really need you will directly be
able to take advantage of upstream changes and additions to Evennia for anything you didn't
customize.
In code, the settings is accessed through
```python
from django.conf import settings
# or (shorter):
from evennia import settings
# example:
servername = settings.SERVER_NAME
```
Each setting appears as a property on the imported `settings` object. You can also explore all
possible options with `evennia.settings_full` (this also includes advanced Django defaults that are
not touched in default Evennia).
> It should be pointed out that when importing `settings` into your code like this, it will be *read
only*. You *cannot* edit your settings from your code! The only way to change an Evennia setting is
to edit `mygame/server/conf/settings.py` directly. You also generally need to restart the server
(possibly also the Portal) before a changed setting becomes available.
## Other files in the `server/conf` directory
Apart from the main `settings.py` file,
- `at_initial_setup.py` - this allows you to add a custom startup method to be called (only) the
very first time Evennia starts (at the same time as user #1 and Limbo is created). It can be made to
start your own global scripts or set up other system/world-related things your game needs to have
running from the start.
- `at_server_startstop.py` - this module contains two functions that Evennia will call every time
the Server starts and stops respectively - this includes stopping due to reloading and resetting as
well as shutting down completely. It's a useful place to put custom startup code for handlers and
other things that must run in your game but which has no database persistence.
- `connection_screens.py` - all global string variables in this module are interpreted by Evennia as
a greeting screen to show when an Account first connects. If more than one string variable is
present in the module a random one will be picked.
- `inlinefuncs.py` - this is where you can define custom [Inline functions](../Concepts/TextTags#inlinefuncs).
- `inputfuncs.py` - this is where you define custom [Input functions](./Inputfuncs) to handle data
from the client.
- `lockfuncs.py` - this is one of many possible modules to hold your own "safe" *lock functions* to
make available to Evennia's [Locks](./Locks).
- `mssp.py` - this holds meta information about your game. It is used by MUD search engines (which
you often have to register with) in order to display what kind of game you are running along with
statistics such as number of online accounts and online status.
- `oobfuncs.py` - in here you can define custom [OOB functions](../Concepts/OOB).
- `portal_services_plugin.py` - this allows for adding your own custom services/protocols to the
Portal. It must define one particular function that will be called by Evennia at startup. There can
be any number of service plugin modules, all will be imported and used if defined. More info can be
found [here](https://code.google.com/p/evennia/wiki/SessionProtocols#Adding_custom_Protocols).
- `server_services_plugin.py` - this is equivalent to the previous one, but used for adding new
services to the Server instead. More info can be found
[here](https://code.google.com/p/evennia/wiki/SessionProtocols#Adding_custom_Protocols).
Some other Evennia systems can be customized by plugin modules but has no explicit template in
`conf/`:
- *cmdparser.py* - a custom module can be used to totally replace Evennia's default command parser.
All this does is to split the incoming string into "command name" and "the rest". It also handles
things like error messages for no-matches and multiple-matches among other things that makes this
more complex than it sounds. The default parser is *very* generic, so you are most often best served
by modifying things further down the line (on the command parse level) than here.
- *at_search.py* - this allows for replacing the way Evennia handles search results. It allows to
change how errors are echoed and how multi-matches are resolved and reported (like how the default
understands that "2-ball" should match the second "ball" object if there are two of them in the
room).
## ServerConf
There is a special database model called `ServerConf` that stores server internal data and settings
such as current account count (for interfacing with the webserver), startup status and many other
things. It's rarely of use outside the server core itself but may be good to
know about if you are an Evennia developer.

View file

@ -1,3 +1,3 @@
# Server component
TODO: This is currently in [Portal-and-Server](./Portal-And-Server).
TODO: This is currently in [Portal-and-Server](./Portal-And-Server.md).

View file

@ -5,14 +5,14 @@ An Evennia *Session* represents one single established connection to the server.
Evennia session, it is possible for a person to connect multiple times, for example using different
clients in multiple windows. Each such connection is represented by a session object.
A session object has its own [cmdset](./Command-Sets), usually the "unloggedin" cmdset. This is what
A session object has its own [cmdset](./Command-Sets.md), usually the "unloggedin" cmdset. This is what
is used to show the login screen and to handle commands to create a new account (or
[Account](./Accounts) in evennia lingo) read initial help and to log into the game with an existing
[Account](./Accounts.md) in evennia lingo) read initial help and to log into the game with an existing
account. A session object can either be "logged in" or not. Logged in means that the user has
authenticated. When this happens the session is associated with an Account object (which is what
holds account-centric stuff). The account can then in turn puppet any number of objects/characters.
> Warning: A Session is not *persistent* - it is not a [Typeclass](./Typeclasses) and has no
> Warning: A Session is not *persistent* - it is not a [Typeclass](./Typeclasses.md) and has no
connection to the database. The Session will go away when a user disconnects and you will lose any
custom data on it if the server reloads. The `.db` handler on Sessions is there to present a uniform
API (so you can assume `.db` exists even if you don't know if you receive an Object or a Session),
@ -26,13 +26,13 @@ Here are some important properties available on (Server-)Sessions
- `sessid` - The unique session-id. This is an integer starting from 1.
- `address` - The connected client's address. Different protocols give different information here.
- `logged_in` - `True` if the user authenticated to this session.
- `account` - The [Account](./Accounts) this Session is attached to. If not logged in yet, this is
- `account` - The [Account](./Accounts.md) this Session is attached to. If not logged in yet, this is
`None`.
- `puppet` - The [Character/Object](./Objects) currently puppeted by this Account/Session combo. If
- `puppet` - The [Character/Object](./Objects.md) currently puppeted by this Account/Session combo. If
not logged in or in OOC mode, this is `None`.
- `ndb` - The [Non-persistent Attribute](./Attributes) handler.
- `ndb` - The [Non-persistent Attribute](./Attributes.md) handler.
- `db` - As noted above, Sessions don't have regular Attributes. This is an alias to `ndb`.
- `cmdset` - The Session's [CmdSetHandler](./Command-Sets)
- `cmdset` - The Session's [CmdSetHandler](./Command-Sets.md)
Session statistics are mainly used internally by Evennia.
@ -99,7 +99,7 @@ transparently detect which session was triggering the command (if any) and redir
`command.msg()` is often the safest bet.
You can get the `session` in two main ways:
* [Accounts](./Accounts) and [Objects](./Objects) (including Characters) have a `sessions` property.
* [Accounts](./Accounts.md) and [Objects](./Objects.md) (including Characters) have a `sessions` property.
This is a *handler* that tracks all Sessions attached to or puppeting them. Use e.g.
`accounts.sessions.get()` to get a list of Sessions attached to that entity.
* A Command instance has a `session` property that always points back to the Session that triggered
@ -132,7 +132,7 @@ changes carefully.
*Note: This is considered an advanced topic. You don't need to know this on a first read-through.*
Evennia is split into two parts, the [Portal and the Server](./Portal-And-Server). Each side tracks
Evennia is split into two parts, the [Portal and the Server](./Portal-And-Server.md). Each side tracks
its own Sessions, syncing them to each other.
The "Session" we normally refer to is actually the `ServerSession`. Its counter-part on the Portal
@ -172,7 +172,7 @@ server reboot (assuming the Portal is not stopped at the same time, obviously).
Both the Portal and Server each have a *sessionhandler* to manage the connections. These handlers
are global entities contain all methods for relaying data across the AMP bridge. All types of
Sessions hold a reference to their respective Sessionhandler (the property is called
`sessionhandler`) so they can relay data. See [protocols](../Concepts/Custom-Protocols) for more info
`sessionhandler`) so they can relay data. See [protocols](../Concepts/Custom-Protocols.md) for more info
on building new protocols.
To get all Sessions in the game (i.e. all currently connected clients), you access the server-side

View file

@ -69,7 +69,7 @@ be extracted from the `**kwargs` dict in the signal handler.
used way for users to themselves create accounts during login. It passes and extra kwarg `ip` with
the client IP of the connecting account.
- `SIGNAL_ACCOUNT_POST_LOGIN` - this will always fire when the account has authenticated. Sends
extra kwarg `session` with the new [Session](./Sessions) object involved.
extra kwarg `session` with the new [Session](./Sessions.md) object involved.
- `SIGNAL_ACCCOUNT_POST_FIRST_LOGIN` - this fires just before `SIGNAL_ACCOUNT_POST_LOGIN` but only
if
this is the *first* connection done (that is, if there are no previous sessions connected). Also

View file

@ -10,11 +10,11 @@ currently dead.
*Tags* are short text labels that you attach to objects so as to easily be able to retrieve and
group them. An Evennia entity can be tagged with any number of Tags. On the database side, Tag
entities are *shared* between all objects with that tag. This makes them very efficient but also
fundamentally different from [Attributes](./Attributes), each of which always belongs to one *single*
fundamentally different from [Attributes](./Attributes.md), each of which always belongs to one *single*
object.
In Evennia, Tags are technically also used to implement `Aliases` (alternative names for objects)
and `Permissions` (simple strings for [Locks](./Locks) to check for).
and `Permissions` (simple strings for [Locks](./Locks.md) to check for).
## Properties of Tags (and Aliases and Permissions)
@ -26,7 +26,7 @@ unique key + category combination.
When Tags are assigned to game entities, these entities are actually sharing the same Tag. This
means that Tags are not suitable for storing information about a single object - use an
[Attribute](./Attributes) for this instead. Tags are a lot more limited than Attributes but this also
[Attribute](./Attributes.md) for this instead. Tags are a lot more limited than Attributes but this also
makes them very quick to lookup in the database - this is the whole point.
Tags have the following properties, stored in the database:
@ -52,8 +52,8 @@ free up the *category* property for any use you desire.
## Adding/Removing Tags
You can tag any *typeclassed* object, namely [Objects](./Objects), [Accounts](./Accounts),
[Scripts](./Scripts) and [Channels](./Communications). General tags are added by the *Taghandler*. The
You can tag any *typeclassed* object, namely [Objects](./Objects.md), [Accounts](./Accounts.md),
[Scripts](./Scripts.md) and [Channels](./Communications.md). General tags are added by the *Taghandler*. The
tag handler is accessed as a property `tags` on the relevant entity:
```python
@ -135,7 +135,7 @@ objs = evennia.search_tag(category="bar")
There is also an in-game command that deals with assigning and using ([Object-](./Objects)) tags:
There is also an in-game command that deals with assigning and using ([Object-](./Objects.md)) tags:
@tag/search furniture
@ -166,4 +166,4 @@ That said, tag categories can be useful if you build some game system that uses
use tag categories to make sure to separate tags created with this system from any other tags
created elsewhere. You can then supply custom search methods that *only* find objects tagged with
tags of that category. An example of this
is found in the [Zone tutorial](../Concepts/Zones).
is found in the [Zone tutorial](../Concepts/Zones.md).

View file

@ -11,7 +11,7 @@ hard-coded to rely on the concept of the global 'tick'. Evennia has no such noti
use tickers is very much up to the need of your game and which requirements you have. The "ticker
recipe" is just one way of cranking the wheels.
The most fine-grained way to manage the flow of time is of course to use [Scripts](./Scripts). Many
The most fine-grained way to manage the flow of time is of course to use [Scripts](./Scripts.md). Many
types of operations (weather being the classic example) are however done on multiple objects in the
same way at regular intervals, and for this, storing separate Scripts on each object is inefficient.
The way to do this is to use a ticker with a "subscription model" - let objects sign up to be
@ -98,13 +98,13 @@ The `callable` can be on any form as long as it accepts the arguments you give t
> Note that everything you supply to the TickerHandler will need to be pickled at some point to be
saved into the database. Most of the time the handler will correctly store things like database
objects, but the same restrictions as for [Attributes](./Attributes) apply to what the TickerHandler
objects, but the same restrictions as for [Attributes](./Attributes.md) apply to what the TickerHandler
may store.
When testing, you can stop all tickers in the entire game with `tickerhandler.clear()`. You can also
view the currently subscribed objects with `tickerhandler.all()`.
See the [Weather Tutorial](../Howto/Weather-Tutorial) for an example of using the TickerHandler.
See the [Weather Tutorial](../Howto/Weather-Tutorial.md) for an example of using the TickerHandler.
### When *not* to use TickerHandler

View file

@ -5,8 +5,8 @@
different game entities as Python classes, without having to modify the database schema for every
new type.
In Evennia the most important game entities, [Accounts](./Accounts), [Objects](./Objects),
[Scripts](./Scripts) and [Channels](./Communications#Channels) are all Python classes inheriting, at
In Evennia the most important game entities, [Accounts](./Accounts.md), [Objects](./Objects.md),
[Scripts](./Scripts.md) and [Channels](./Channels.md) are all Python classes inheriting, at
varying distance, from `evennia.typeclasses.models.TypedObject`. In the documentation we refer to
these objects as being "typeclassed" or even "being a typeclass".
@ -48,14 +48,14 @@ module from anywhere, the `typeclass/list` will not find it. To make it known
to Evennia you must import that module from somewhere.
### Difference between typeclasses and classes
## Difference between typeclasses and classes
All Evennia classes inheriting from class in the table above share one important feature and two
important limitations. This is why we don't simply call them "classes" but "typeclasses".
1. A typeclass can save itself to the database. This means that some properties (actually not that
many) on the class actually represents database fields and can only hold very specific data types.
This is detailed [below](./Typeclasses#about-typeclass-properties).
This is detailed [below](./Typeclasses.md#about-typeclass-properties).
1. Due to its connection to the database, the typeclass' name must be *unique* across the _entire_
server namespace. That is, there must never be two same-named classes defined anywhere. So the below
code would give an error (since `DefaultObject` is now globally found both in this module and in the
@ -82,7 +82,7 @@ both accept arbitrary keyword arguments and use `super` to call its parent::
```
Apart from this, a typeclass works like any normal Python class and you can
treat it as such.
treat it as such.
## Creating a new typeclass
@ -129,11 +129,11 @@ argument; this can both be the actual class or the python path to the typeclass
game directory. So if your `Furniture` typeclass sits in `mygame/typeclasses/furniture.py`, you
could point to it as `typeclasses.furniture.Furniture`. Since Evennia will itself look in
`mygame/typeclasses`, you can shorten this even further to just `furniture.Furniture`. The create-
functions take a lot of extra keywords allowing you to set things like [Attributes](./Attributes) and
[Tags](./Tags) all in one go. These keywords don't use the `db_*` prefix. This will also automatically
functions take a lot of extra keywords allowing you to set things like [Attributes](./Attributes.md) and
[Tags](./Tags.md) all in one go. These keywords don't use the `db_*` prefix. This will also automatically
save the new instance to the database, so you don't need to call `save()` explicitly.
### About typeclass properties
## About typeclass properties
An example of a database field is `db_key`. This stores the "name" of the entity you are modifying
and can thus only hold a string. This is one way of making sure to update the `db_key`:
@ -178,36 +178,36 @@ returns the string form "#id".
The typeclassed entity has several common handlers:
- `tags` - the [TagHandler](./Tags) that handles tagging. Use `tags.add()` , `tags.get()` etc.
- `locks` - the [LockHandler](./Locks) that manages access restrictions. Use `locks.add()`,
- `tags` - the [TagHandler](./Tags.md) that handles tagging. Use `tags.add()` , `tags.get()` etc.
- `locks` - the [LockHandler](./Locks.md) that manages access restrictions. Use `locks.add()`,
`locks.get()` etc.
- `attributes` - the [AttributeHandler](./Attributes) that manages Attributes on the object. Use
- `attributes` - the [AttributeHandler](./Attributes.md) that manages Attributes on the object. Use
`attributes.add()`
etc.
- `db` (DataBase) - a shortcut property to the AttributeHandler; allowing `obj.db.attrname = value`
- `nattributes` - the [Non-persistent AttributeHandler](./Attributes) for attributes not saved in the
- `nattributes` - the [Non-persistent AttributeHandler](./Attributes.md) for attributes not saved in the
database.
- `ndb` (NotDataBase) - a shortcut property to the Non-peristent AttributeHandler. Allows
`obj.ndb.attrname = value`
Each of the typeclassed entities then extend this list with their own properties. Go to the
respective pages for [Objects](./Objects), [Scripts](./Scripts), [Accounts](./Accounts) and
[Channels](./Communications) for more info. It's also recommended that you explore the available
entities using [Evennia's flat API](../Evennia-API) to explore which properties and methods they have
respective pages for [Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md) and
[Channels](./Communications.md) for more info. It's also recommended that you explore the available
entities using [Evennia's flat API](../Evennia-API.md) to explore which properties and methods they have
available.
### Overloading hooks
## Overloading hooks
The way to customize typeclasses is usually to overload *hook methods* on them. Hooks are methods
that Evennia call in various situations. An example is the `at_object_creation` hook on `Objects`,
which is only called once, the very first time this object is saved to the database. Other examples
are the `at_login` hook of Accounts and the `at_repeat` hook of Scripts.
### Querying for typeclasses
## Querying for typeclasses
Most of the time you search for objects in the database by using convenience methods like the
`caller.search()` of [Commands](./Commands) or the search functions like `evennia.search_objects`.
`caller.search()` of [Commands](./Commands.md) or the search functions like `evennia.search_objects`.
You can however also query for them directly using [Django's query
language](https://docs.djangoproject.com/en/1.7/topics/db/queries/). This makes use of a _database
@ -245,13 +245,13 @@ matches = ScriptDB.objects.filter(db_key__contains="Combat")
When querying from the database model parent you don't need to use `filter_family` or `get_family` -
you will always query all children on the database model.
## Updating existing typeclass instances
# Updating existing typeclass instances
If you already have created instances of Typeclasses, you can modify the *Python code* at any time -
due to how Python inheritance works your changes will automatically be applied to all children once
you have reloaded the server.
However, database-saved data, like `db_*` fields, [Attributes](./Attributes), [Tags](./Tags) etc, are
However, database-saved data, like `db_*` fields, [Attributes](./Attributes.md), [Tags](./Tags.md) etc, are
not themselves embedded into the class and will *not* be updated automatically. This you need to
manage yourself, by searching for all relevant objects and updating or adding the data:
@ -317,7 +317,7 @@ The arguments to this method are described [in the API docs
here](github:evennia.typeclasses.models#typedobjectswap_typeclass).
## How typeclasses actually work
# How typeclasses actually work
*This is considered an advanced section.*
@ -325,7 +325,7 @@ Technically, typeclasses are [Django proxy
models](https://docs.djangoproject.com/en/1.7/topics/db/models/#proxy-models). The only database
models that are "real" in the typeclass system (that is, are represented by actual tables in the
database) are `AccountDB`, `ObjectDB`, `ScriptDB` and `ChannelDB` (there are also
[Attributes](./Attributes) and [Tags](./Tags) but they are not typeclasses themselves). All the
[Attributes](./Attributes.md) and [Tags](./Tags.md) but they are not typeclasses themselves). All the
subclasses of them are "proxies", extending them with Python code without actually modifying the
database layout.
@ -334,7 +334,7 @@ Evennia modifies Django's proxy model in various ways to allow them to work with
handles this for you using metaclasses). Evennia also makes sure you can query subclasses as well as
patches django to allow multiple inheritance from the same base class.
### Caveats
## Caveats
Evennia uses the *idmapper* to cache its typeclasses (Django proxy models) in memory. The idmapper
allows things like on-object handlers and properties to be stored on typeclass instances and to not

View file

@ -11,7 +11,7 @@ meant to be accessed in code, by other programs.
The API is using [Django Rest Framework][drf]. This automates the process
of setting up _views_ (Python code) to process the result of web requests.
The process of retrieving data is similar to that explained on the
[Webserver](./Webserver) page, except the views will here return [JSON][json]
[Webserver](./Webserver.md) page, except the views will here return [JSON][json]
data for the resource you want. You can also _send_ such JSON data
in order to update the database from the outside.
@ -25,7 +25,7 @@ To activate the API, add this to your settings file.
The main controlling setting is `REST_FRAMEWORK`, which is a dict. The keys
`DEFAULT_LIST_PERMISSION` and `DEFAULT_CREATE_PERMISSIONS` control who may
view and create new objects via the api respectively. By default, users with
['Builder'-level permission](./Permissions) or higher may access both actions.
['Builder'-level permission](./Permissions.md) or higher may access both actions.
While the api is meant to be expanded upon, Evennia supplies several operations
out of the box. If you click the `Autodoc` button in the upper right of the `/api`
@ -74,7 +74,7 @@ permissions:
"results": [{"username": "bob",...}]
}
Now suppose that you want to use the API to create an [Object](./Objects):
Now suppose that you want to use the API to create an [Object](./Objects.md):
>>> data = {"db_key": "A shiny sword"}
>>> response = requests.post("https://www.mygame.com/api/objects",
@ -108,7 +108,7 @@ Overall, reading up on [Django Rest Framework ViewSets](https://www.django-rest-
other parts of their documentation is required for expanding and
customizing the API.
Check out the [Website](./Website) page for help on how to override code, templates
Check out the [Website](./Website.md) page for help on how to override code, templates
and static files.
- API templates (for the web-display) is located in `evennia/web/api/templates/rest_framework/` (it must
be named such to allow override of the original REST framework templates).

View file

@ -29,7 +29,7 @@ objects are actually stored as a `tuple` with object-unique data.
you'll find the field _Serialized string_. This string shows a Python tuple like
('__packed_dbobj__', ('objects', 'objectdb'), '2021:05:15-08:59:30:624660', 358)
Mark and copy this tuple-string to your clipboard exactly as it stands (parentheses and all).
2. Go to the entity that should have the new Attribute and create the Attribute. In its `value`
field, paste the tuple-string you copied before. Save!
@ -86,21 +86,21 @@ Only Superusers can change the `Superuser status` flag, and grant new
permissions to accounts. The superuser is the only permission level that is
also relevant in-game. `User Permissions` and `Groups` found on the `Account`
admin page _only_ affects the admin - they have no connection to the in-game
[Permissions](./Permissions) (Player, Builder, Admin etc).
[Permissions](./Permissions.md) (Player, Builder, Admin etc).
For a staffer with `Staff status` to be able to actually do anything, the
superuser must grant at least some permissions for them on their Account. This
can also be good in order to limit mistakes. It can be a good idea to not allow
the `Can delete Account` permission, for example.
```important::
```{important}
If you grant staff-status and permissions to an Account and they still cannot
access the admin's content, try reloading the server.
```
```warning::
```{warning}
If a staff member has access to the in-game ``py`` command, they can just as
well have their admin ``Superuser status`` set too. The reason is that ``py``
@ -112,25 +112,25 @@ the `Can delete Account` permission, for example.
## Customizing the web admin
Customizing the admin is a big topic and something beyond the scope of this
Customizing the admin is a big topic and something beyond the scope of this
documentation. See the [official Django docs](https://docs.djangoproject.com/en/3.2/ref/contrib/admin/) for
the details. This is just a brief summary.
the details. This is just a brief summary.
See the [Website](./Website) page for an overview of the components going into
See the [Website](./Website.md) page for an overview of the components going into
generating a web page. The Django admin uses the same principle except that
Django provides a lot of tools to automate the admin-generation for us.
Admin templates are found in `evennia/web/templates/admin/` but you'll find
this is relatively empty. This is because most of the templates are just
inherited directly from their original location in the Django package
(`django/contrib/admin/templates/`). So if you wanted to override one you'd have
(`django/contrib/admin/templates/`). So if you wanted to override one you'd have
to copy it from _there_ into your `mygame/templates/admin/` folder. Same is true
for CSS files.
The admin site's backend code (the views) is found in `evennia/web/admin/`. It
is organized into `admin`-classes, like `ObjectAdmin`, `AccountAdmin` etc.
These automatically use the underlying database models to generate useful views
for us without us havint go code the forms etc ourselves.
for us without us havint go code the forms etc ourselves.
The top level `AdminSite` (the admin configuration referenced in django docs)
is found in `evennia/web/utils/adminsite.py`.
@ -138,7 +138,7 @@ is found in `evennia/web/utils/adminsite.py`.
### Change the title of the admin
By default the admin's title is `Evennia web admin`. To change this, add the
By default the admin's title is `Evennia web admin`. To change this, add the
following to your `mygame/web/urls.py`:
```python

View file

@ -4,7 +4,7 @@ When Evennia starts it also spins up its own Twisted-based web server. The
webserver is responsible for serving the html pages of the game's website. It
can also serve static resources like images and music.
The webclient runs as part of the [Server](./Portal-And-Server) process of
The webclient runs as part of the [Server](./Portal-And-Server.md) process of
Evennia. This means that it can directly access cached objects modified
in-game, and there is no risk of working with objects that are temporarily
out-of-sync in the database.
@ -12,17 +12,17 @@ out-of-sync in the database.
The webserver runs on Twisted and is meant to be used in a production
environment. It leverages the Django web framework and provides:
- A [Game Website](./Website) - this is what you see when you go to
- A [Game Website](./Website.md) - this is what you see when you go to
`localhost:4001`. The look of the website is meant to be customized to your
game. Users logged into the website will be auto-logged into the game if they
do so with the webclient since they share the same login credentials (there
is no way to safely do auto-login with telnet clients).
- The [Web Admin](./Web-Admin) is based on the Django web admin and allows you to
- The [Web Admin](./Web-Admin.md) is based on the Django web admin and allows you to
edit the game database in a graphical interface.
- The [Webclient](./Webclient) page is served by the webserver, but the actual
- The [Webclient](./Webclient.md) page is served by the webserver, but the actual
game communication (sending/receiving data) is done by the javascript client
on the page opening a websocket connection directly to Evennia's Portal.
- The [Evennia REST-API](./Web-API) allows for accessing the database from outside the game
- The [Evennia REST-API](./Web-API.md) allows for accessing the database from outside the game
(only if `REST_API_ENABLED=True).
@ -62,7 +62,7 @@ it operates independently from Evennia. Small snippets of javascript can be
used on a page to have buttons react, make small animations etc that doesn't
require the server.
In the case of the [Webclient](./Webclient), Evennia will load the Webclient page
In the case of the [Webclient](./Webclient.md), Evennia will load the Webclient page
as above, but the page then initiates Javascript code (a lot of it) responsible
for actually displaying the client GUI, allows you to resize windows etc.

View file

@ -1,14 +1,14 @@
# Game website
When Evennia starts it will also start a [Webserver](./Webserver) as part of the
[Server](./Portal-And-Server) process. This uses [Django](https://docs.djangoproject.com)
When Evennia starts it will also start a [Webserver](./Webserver.md) as part of the
[Server](./Portal-And-Server.md) process. This uses [Django](https://docs.djangoproject.com)
to present a simple but functional default game website. With the default setup,
open your browser to [localhost:4001](http://localhost:4001) or [127.0.0.1:4001](http://127.0.0.1:4001)
open your browser to [localhost:4001](http://localhost:4001) or [127.0.0.1:4001](http://127.0.0.1:4001)
to see it.
The website allows existing players to log in using an account-name and
password they previously used to register with the game. If a user logs in with
the [Webclient](./Webclient) they will also log into the website and vice-versa.
the [Webclient](./Webclient.md) they will also log into the website and vice-versa.
So if you are logged into the website, opening the webclient will automatically
log you into the game as that account.
@ -28,15 +28,15 @@ In the top menu you can find
show a list of all channels available to you and allow you to view the latest
discussions. Most channels require logging in, but the `Public` channel can
also be viewed by non-loggedin users.
- _Help_ - This ties the in-game [Help system](./Help-System) to the website. All
- _Help_ - This ties the in-game [Help system](./Help-System.md) to the website. All
database-based help entries that are publicly available or accessible to your
account can be read. This is a good way to present a body of help for people
to read outside of the game.
- _Play Online_ - This opens the [Webclient](./Webclient) in the browser.
- _Play Online_ - This opens the [Webclient](./Webclient.md) in the browser.
- _Admin_ The [Web admin](Web admin) will only show if you are logged in.
- _Log in/out_ - Allows you to authenticate using the same credentials you use
in the game.
- _Register_ - Allows you to register a new account. This is the same as
- _Register_ - Allows you to register a new account. This is the same as
creating a new account upon first logging into the game).
## Modifying the default Website
@ -52,7 +52,7 @@ You'll mostly be doing so in your settings file
> DEBUG mode leaks memory (for retaining debug info) and is *not* safe to use
> for a production game!
As explained on the [Webserver](./Webserver) page, the process for getting a web
As explained on the [Webserver](./Webserver.md) page, the process for getting a web
page is
1. Web browser sends HTTP request to server with an URL
@ -115,7 +115,7 @@ This is the layout of the `mygame/web/` folder relevant for the website:
```
```versionchanged:: 1.0
```{versionchanged} 1.0
Game folders created with older versions of Evennia will lack most of this
convenient `mygame/web/` layout. If you use a game dir from an older version,
@ -139,7 +139,7 @@ version rather than it using the original.
## Examples of commom web changes
```important::
```{important}
Django is a very mature web-design framework. There are endless
internet-tutorials, courses and books available to explain how to use Django.
@ -206,8 +206,8 @@ There's a lot more information to be found in the [Django template language docu
### Change webpage colors and styling
You can tweak the [CSS](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) of the entire
website. If you investigate the `evennia/web/templates/website/base.html` file you'll see that we
You can tweak the [CSS](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) of the entire
website. If you investigate the `evennia/web/templates/website/base.html` file you'll see that we
use the [Bootstrap
4](https://getbootstrap.com/docs/4.6/getting-started/introduction/) toolkit.
@ -220,8 +220,8 @@ The website's custom CSS is found in
empty) `custom.css` in the same location. You can override either, but it may
be easier to revert your changes if you only add things to `custom.css`.
Copy the CSS file you want to modify to the corresponding location in `mygame/web`.
Modify it and reload the server to see your changes.
Copy the CSS file you want to modify to the corresponding location in `mygame/web`.
Modify it and reload the server to see your changes.
You can also apply static files without reloading, but running this in the
terminal:
@ -233,8 +233,8 @@ terminal:
> Note that before you see new CSS files applied you may need to refresh your
> browser without cache (Ctrl-F5 in Firefox, for example).
As an example, add/copy `custom.css` to `mygame/web/static/website/css/` and
add the following:
As an example, add/copy `custom.css` to `mygame/web/static/website/css/` and
add the following:
```css
@ -271,14 +271,14 @@ look in `evennia/web/website/urls.py`. Here we find the following line:
```
The first `""` is the empty url - root - what you get if you just enter `localhost:4001/`
The first `""` is the empty url - root - what you get if you just enter `localhost:4001/`
with no extra path. As expected, this leads to the index page. By looking at the imports
we find the view is in in `evennia/web/website/views/index.py`.
we find the view is in in `evennia/web/website/views/index.py`.
Copy this file to the corresponding location in `mygame/web`. Then tweak your `mygame/web/website/urls.py`
Copy this file to the corresponding location in `mygame/web`. Then tweak your `mygame/web/website/urls.py`
file to point to the new file:
```python
```python
# in mygame/web/website/urls.py
# ...
@ -292,8 +292,8 @@ urlpatterns = [
# ...
```
So we just import `index` from the new location and point to it. After a reload
So we just import `index` from the new location and point to it. After a reload
the front page will now redirect to use your copy rather than the original.
The frontpage view is a class `EvenniaIndexView`. This is a [Django class-based view](https://docs.djangoproject.com/en/3.2/topics/class-based-views/).
@ -321,7 +321,7 @@ your copy. Just remember to reload.
### Using Flat Pages
The absolutely simplest way to add a new web page is to use the `Flat Pages`
app available in the [Web Admin](./Web-Admin). The page will appear with the same
app available in the [Web Admin](./Web-Admin.md). The page will appear with the same
styling as the rest of the site.
For the `Flat pages` module to work you must first set up a _Site_ (or
@ -337,7 +337,7 @@ experimentation, add the domain `localhost:4001`. Note the `id` of the domain
Next you create new pages easily.
- Go the `Flat Pages` web admin and choose to add a new flat page.
- Set the url. If you want the page to appear as e.g. `localhost:4001/test/`, then
- Set the url. If you want the page to appear as e.g. `localhost:4001/test/`, then
add `/test/` here. You need to add both leading and trailing slashes.
- Set `Title` to the name of the page.
- The `Content` is the HTML content of the body of the page. Go wild!
@ -348,16 +348,16 @@ You can now go to `localhost:4001/test/` and see your new page!
### Add Custom new page
The `Flat Pages` page doesn't allow for (much) dynamic content and customization. For
The `Flat Pages` page doesn't allow for (much) dynamic content and customization. For
this you need to add the needed components yourself.
Let's see how to make a `/test/` page from scratch.
- Add a new `test.html` file under `mygame/web/templates/website/`. Easiest is to base
this off an existing file. Make sure to `{% extend base.html %}` if you want to
- Add a new `test.html` file under `mygame/web/templates/website/`. Easiest is to base
this off an existing file. Make sure to `{% extend base.html %}` if you want to
get the same styling as the rest of your site.
- Add a new view `testview.py` under `mygame/web/website/views/` (don't name it `test.py` or
Django/Evennia will think it contains unit tests). Add a view there to process
- Add a new view `testview.py` under `mygame/web/website/views/` (don't name it `test.py` or
Django/Evennia will think it contains unit tests). Add a view there to process
your page. This is a minimal view to start from (read much more [in the Django docs](https://docs.djangoproject.com/en/3.2/topics/class-based-views/)):
```python
@ -385,7 +385,7 @@ Let's see how to make a `/test/` page from scratch.
path("test/", testview.MyTestView.as_view())
]
```
```
- Reload the server and your new page is available. You can now continue to add
all sorts of advanced dynamic content through your view and template!
@ -395,13 +395,13 @@ Let's see how to make a `/test/` page from scratch.
All the pages created so far deal with _presenting_ information to the user.
It's also possible for the user to _input_ data on the page through _forms_. An
example would be a page of fields and sliders you fill in to create a
character, with a big 'Submit' button at the bottom.
character, with a big 'Submit' button at the bottom.
Firstly, this must be represented in HTML. The `<form> ... </form>` is a
standard HTML element you need to add to your template. It also has some other
requirements, such as `<input>` and often Javascript components as well (but
usually Django will help with this). If you are unfamiliar with how HTML forms
work, [read about them here](https://docs.djangoproject.com/en/3.2/topics/forms/#html-forms).
work, [read about them here](https://docs.djangoproject.com/en/3.2/topics/forms/#html-forms).
The basic gist of it is that when you click to 'submit' the form, a POST HTML
request will be sent to the server containing the data the user entered. It's
@ -412,9 +412,9 @@ On the backend side, we need to specify the logic for validating and processing
the form data. This is done by the `Form` [Django class](https://docs.djangoproject.com/en/3.2/topics/forms/#forms-in-django).
This specifies _fields_ on itself that define how to validate that piece of data.
The form is then linked into the view-class by adding `form_class = MyFormClass` to
The form is then linked into the view-class by adding `form_class = MyFormClass` to
the view (next to `template_name`).
There are several example forms in `evennia/web/website/forms.py`. It's also a good
There are several example forms in `evennia/web/website/forms.py`. It's also a good
idea to read [Building a form in Django](https://docs.djangoproject.com/en/3.2/topics/forms/#building-a-form-in-django)
on the Django website - it covers all you need.