Updated ReST docs.

This commit is contained in:
Griatch 2013-12-02 16:43:44 +01:00
parent 3aeec1298a
commit 64a30c655d
29 changed files with 1391 additions and 1186 deletions

View file

@ -20,9 +20,9 @@ new additional commands of your own.
but in this example we assume you don't.
#. Edit ``game/settings.py``, adding the following line:
``CMDSET_DEFAULT="game.gamesrc.commands.cmdset.DefaultCmdSet"``
``CMDSET_CHARACTER="game.gamesrc.commands.cmdset.CharacterCmdSet"``
Evennia will now look for default commands in the ``DefaultCmdSet``
Evennia will now look for default commands in the ``CharacterCmdSet``
class of your newly copied module. You only need to do this once.
Creating a custom command
@ -45,6 +45,7 @@ Creating a custom command
# file game/gamesrc/commands/command.py
#[...]
from ev import default_cmds
class CmdEcho(default_cmds.MuxCommand):
"""
Simple command example
@ -65,30 +66,30 @@ Creating a custom command
else:
self.caller.msg("You gave the string: '%s'" % self.args)
Adding the Command to a Cmdset
------------------------------
Adding the Command to a default Cmdset
--------------------------------------
The command is not available to use until it is part of a Command Set.
In this example we will go the easiest route and add it to the default
command set we already prepared.
Character command set we already prepared.
#. Edit your recently copied ``game/gamesrc/commands/cmdset.py``
#. In this copied module you will find the ``DefaultCmdSet`` class
already imported and prepared for you. Import your new command module
here with ``from game.gamesrc.commands.command import CmdEcho``.
#. Add a line ``self.add(CmdEcho())`` to ``DefaultCmdSet``, in the
#. Add a line ``self.add(CmdEcho())`` to ``CharacterCmdSet``, in the
``at_cmdset_creation`` method (the template tells you where). This is
approximately how it should look at this point:
::
# file gamesrc/commands/examples/cmdset.py
# file gamesrc/commands/cmdset.py
#[...]
from game.gamesrc.commands.command import CmdEcho
#[...]
class DefaultCmdSet(default_cmds.DefaultCmdSet):
class CharacterCmdSet(default_cmds.CharacterCmdSet):
key = DefaultMUX
key = DefaultCharacter
def at_cmdset_creation(self):
@ -115,3 +116,73 @@ old one - it will overload the default one. Just remember that you must
See `Commands <Commands.html>`_ for many more details and possibilities
when defining Commands and using Cmdsets in various ways.
Adding the command to specific object types
-------------------------------------------
You do not *have* to expand the ``CharacterCmdSet``, it's just the
easiest example. The cmdset system is very generic. You can create your
own cmdsets and add them to objects as you please (just how to control
how they merge with the existing set is described in detail in the
[Commands#Command\_Sets Command Set documentation]).
::
# file gamesrc/commands/cmdset.py
#[...]
from game.gamesrc.commands.command import CmdEcho
#[...]
class MyCmdSet(default_cmds.CmdSet):
key = MyCmdSet
def at_cmdset_creation(self):
self.add(CmdEcho())
Now you just need to add this to an object. To test things (as
superuser) you can do
::
@py self.cmdset.add("cmdset.MyCmdSet")
This will add the cmdset (and the echo command) to yourself so you can
test it. This is not permanent though, if you do a ``@reload`` the
merger will be gone. You *can* add the ``permanent=True`` keyword to the
``cmdset.add`` call. This will however only make the new merged cmdset
permanent on that single object, not on other objects of that type,
which is usually what you want.
To make sure all new created objects get your new merged set, put the
``cmdset.add`` call in your custom `Typeclass <Typeclasses.html>`_'
``at_object_creation`` method:
::
from ev import Object
class MyObject(Object):
def at_object_creation(self):
"called when the object is first created"
self.cmdset.add("cmdset.MyCmdSet")
All new objects of this typeclass will now start with this cmdset.
*Note:* An important caveat with this is that ``at_object_creation`` is
only called *once*, when the object is first created. This means that if
you already have existing objects in your databases using that
typeclass, they will not have been initiated the same way. There are
many ways to update them; since it's a one-time update you can usually
just simply loop through them. As superuser, try the following:
::
@py [obj.cmdset.add("cmdset.MyCmdSet") for obj in
ev.managers.typeclass_search("game.gamesrc.objects.objects.mytypeclass.MyTypeClass"]
This goes through all objects in your database having the right
typeclass, adding the new cmdset to each. The good news is that you only
have to do this if you want to post-add cmdsets. If you just want to add
a new command, you can just add that command to the cmdset's
``at_cmdset_creation`` and @reload.

View file

@ -66,16 +66,19 @@ that characters should not have the ability to pick up.
That's it. Below is a ``Heavy`` Typeclass that you could try. Note that
the `lock <Locks.html>`_ and `Attribute <Attribute.html>`_ here set in
the typeclass could just as well have been set using commands in-game,
so this is a *very* simple example.
so this is a *very* simple example. We also add a custom
[Commands#Command\_Sets Command set] to it.
::
# file game/gamesrc/objects/heavy.py
from ev import Object
# let's assume we defined our own cmdset earlier
from game.gamesrc.commands.mycmdsets import HeavySet
class Heavy(Object):
"Heavy object"
at_object_creation(self):
def at_object_creation(self):
"Called whenever a new object is created"
# lock the object down by default
self.locks.add("get:false()")
@ -84,6 +87,8 @@ so this is a *very* simple example.
# this, you'd have to look at the code of the 'get' command to
# find out).
self.db.get_err_msg = "This is too heavy for you to pick up."
# expand the default cmdset with your own custom set (defined elsewhere)
self.cmdset.add(HeavySet)
Change Default Rooms, Exits, Character Typeclass
------------------------------------------------

View file

@ -17,6 +17,7 @@ Installation and Early Life
Customizing the server
----------------------
- `Changing the Settings <SettingsDefault.html>`_
- `Change Evennia's language <Internationalization.html>`_
- `Apache webserver configuration <ApacheConfig.html>`_ (optional)
- `Changing text encodings used by the server <TextEncodings.html>`_
@ -34,4 +35,5 @@ Working with Evennia
- `Setting up your work environment with version
control <VersionControl.html>`_
- `First steps coding with Evennia <FirstStepsCoding.html>`_

View file

@ -62,19 +62,84 @@ will for example delete an ``Attribute``:
del rose.db.has_thorns
Both ``db`` and ``ndb`` defaults to offering an ``all`` property on
Both ``db`` and ``ndb`` defaults to offering an ``all()`` method on
themselves. This returns all associated attributes or non-persistent
properties.
::
list_of_all_rose_attributes = rose.db.all
list_of_all_rose_ndb_attrs = rose.ndb.all
list_of_all_rose_attributes = rose.db.all()
list_of_all_rose_ndb_attrs = rose.ndb.all()
If you use ``all`` as the name of an attribute, this will be used
instead. Later deleting your custom ``all`` will return the default
behaviour.
Properties of Attributes
------------------------
An Attribute object is stored in the database. It has the following
properties:
- ``key`` - the name of the Attribute. When doing e.g.
``obj.db.attrname = value``, this property is set 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
[Attributes#What\_types\_of\_data\_can\_I\_save\_in\_an\_Attribute
this section] 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.html>`_ is
an example of using Attributes in this way). To modify this property
you need to use the [Attributes#The\_Attribute\_Handler Attribute
Handler].
- ``strvalue`` - this is a separate value field that only accepts
strings. This severaly 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.html>`_ use it). It is only accessible via the
[Attributes#The\_Attribute\_Handler Attribute Handler].
Non-database attributes have no equivalence to category nor strvalue.
The Attribute Handler
---------------------
The Attribute handler is what is used under the hood to manage the
Attributes on an object. It is accessible as ``obj.attributes``. For
most operations, the ``db`` or ``ndb`` wrappers are enough. But
sometimes you won't know the attribute name beforehand or you need to
manipulate your Attributes in more detail. The Attribute handler has the
following methods (the argument lists are mostly shortened; you can see
the full call signatures in ``src.typeclasses.models``):
- ``attributes.has(...)`` - this checks if the object has an Attribute
with this key. This is equivalent to doing ``obj.db.key``.
- ``get(...)`` - this retrieves the given Attribute. Normally the
``value`` property of the Attribute is returned, but the method takes
keywords for returning the Attribute object itself. By supplying an
``accessing_object`` oto 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.html>`_ 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 [Attributes#Locking\_and\_checking\_Attributes this section] for
more about locking down Attribute access and editing.
There is an equivalent ``nattribute`` handler for managing non-database
Attributes. This has the same methods but is much simpler since it does
not concern itself with category nor strvalue. It also offers no concept
of access control.
Persistent vs non-persistent
----------------------------
@ -248,15 +313,15 @@ are specified `here <Locks.html>`_. The relevant lock types are
- *attrread* - limits who may read the value of the Attribute
- *attredit* - limits who may set/change this Attribute
You cannot use e.g. ``obj.db.attrname`` handler to modify Attribute
objects (such as setting a lock on them - you will only get the
Attribute *value* that way, not the actual Attribute *object*. You get
the latter with ``get_attribute_obj`` (see next section) which allows
you to set the lock something like this:
You cannot use the ``db`` handler to modify Attribute object (such as
setting a lock on them) - The ``db`` handler will return the Attribute's
*value*, not the Attribute object itself. Instead you use
``get_attribute_obj`` (see next section) which allows you to set the
lock something like this:
::
obj.get_attribute_obj.locks.add("attread:all();attredit:perm(Wizards)")
obj.attributes.get("myattr", return_obj=True).locks.add("attread:all();attredit:perm(Wizards)")
A lock is no good if nothing checks it -- and by default Evennia does
not check locks on Attributes. You have to add a check to your
@ -266,60 +331,12 @@ commands/code wherever it fits (such as before setting an Attribute).
# in some command code where we want to limit
# setting of a given attribute name on an object
attr = obj.get_attribute_obj(attrname, default=None)
if not (attr and attr.locks.check(caller, 'attredit', default=True)):
attr = obj.attributes.get(attrname, return_obj=True, accessing_obj=caller, default=None, default_access=False)
if not attr:
caller.msg("You cannot edit that Attribute!")
return
# edit the Attribute here
Note that in this example this lock check will default to ``True`` if no
lock was defined on the Attribute (which is the normal case). You can
set this to False if you know all your Attributes always check access in
all situations. If you want some special control over what the default
Attribute access is (such as allowing everyone to view, but never
allowing anyone to edit unless explicitly allowing it with a lock), you
can use the ``secure_attr`` method on Typeclassed objects like this:
::
obj.secure_attr(caller, attrname, value=None,
delete=False,
default_access_read=True,
default_access_edit=False,
default_access_create=True)
The secure\_attr will try to retrieve the attribute value of an existing
Attribute if the ``value`` keyword is not set and create/set/delete it
otherwise. The *default\_access* keywords specify what should be the
default policy for each operation if no appropriate lock string is set
on the Attribute.
Other ways to access Attributes
-------------------------------
Normally ``db`` is all you need. But there there are also several other
ways to access information about Attributes, some of which cannot be
replicated by ``db``. These are available on all Typeclassed objects:
- ``has_attribute(attrname)`` - checks if the object has an attribute
with the given name. This is equivalent to doing ``obj.db.attrname``.
- ``set_attribute(attrname, value)`` - equivalent to
``obj.db.attrname = value``.
- ``get_attribute(attrname)`` - returns the attribute value. Equivalent
to ``obj.db.attrname``.
- ``get_attribute_raise(attrname)`` - returns the attribute value, but
instead of returning ``None`` if no such attribute is found, this
method raises ``AttributeError``.
- ``get_attribute_obj(attrname)`` - returns the attribute *object*
itself rather than the value stored in it.
- ``del_attribute(attrname)`` - equivalent to ``del obj.db.attrname``.
Quietly fails if ``attrname`` is not found.
- ``del_attribute_raise(attrname)`` - deletes attribute, raising
``AttributeError`` if no matching Attribute is found.
- ``get_all_attributes`` - equivalent to ``obj.db.all``
- ``attr(attrname, value=None, delete=False)`` - this is a convenience
function for getting, setting and deleting Attributes. It's
recommended to use ``db`` instead.
- ``secure_attr(...)`` - lock-checking version of ``attr``. See example
in previous section.
The same keywords are available to use with ``obj.attributes.set()`` and
``obj.attributes.remove()``, those will check for the *attredit* lock
type.

View file

@ -39,7 +39,7 @@ To temporarily step down from your superuser position you can use the
::
@quell
> @quell
This will make you start using the permission of your current
`Character <Objects.html>`_ instead of your superuser level. If you
@ -64,19 +64,18 @@ rather short name, let's is give a few aliases.
::
> @name box = very large box;box;very;bo;crate
> @name box = very large box;box;very;crate
We now actually renamed the box to *very large box* (and this is what we
will see when looking at the room), but we will also recognize it by any
of the other names we give - like *crate* or simply *box* as before. We
will see when looking at it), but we will also recognize it by any of
the other names we give - like *crate* or simply *box* as before. We
could have given these aliases directly after the name in the
``@create`` command, this is true for all creation commands - you can
always tag on a list of ;-separated aliases to the name of your new
object. If you had wanted to not change the name itself, but to only add
aliases, you could have used the ``@alias`` command.
We are currently carrying the box, which you can see if you give the
command ``inventory`` (or ``i``). Let's drop it.
We are currently carrying the box. Let's drop it.
::
@ -118,8 +117,7 @@ box was dropped in the room, then try this:
Locks are a rather `big topic <Locks.html>`_, but for now that will do
what we want. This will lock the box so noone can lift it. The exception
is superusers, they override all locks and will pick it up anyway. Make
sure you are using your builder account and not the superuser account
and try to get the box now:
sure you are quelling your superuser powers and try to get the box now:
::
@ -134,7 +132,7 @@ attributes using the ``@set`` command:
::
> @set box/get_err_msg = The box is way too heavy for you to lift.
> @set box/get_err_msg = It's way too heavy for you to lift.
Try to get it now and you should see a nicer error message echoed back
to you.
@ -178,7 +176,7 @@ Pushing your buttons
If we get back to the box we made, there is only so much fun you can do
with it at this point. It's just a dumb generic object. If you renamed
it ``carpet`` and changed its description noone would be the wiser.
it to ``stone`` and changed its description noone would be the wiser.
However, with the combined use of custom
`Typeclasses <Typeclasses.html>`_, `Scripts <Scripts.html>`_ and
object-based `Commands <Commands.html>`_, you could expand it and other
@ -201,7 +199,7 @@ Python except Evennia defaults to looking in ``game/gamesrc/objects/``
so you don't have to write the full path every time. There you go - one
red button.
The RedButton is an example object intended to show off many of
The RedButton is an example object intended to show off a few of
Evennia's features. You will find that the `Scripts <Scripts.html>`_ and
`Commands <Commands.html>`_ controlling it are scattered in
``examples``-folders all across ``game/gamesrc/``.
@ -210,8 +208,8 @@ If you wait for a while (make sure you dropped it!) the button will
blink invitingly. Why don't you try to push it ...? Surely a big red
button is meant to be pushed. You know you want to.
Creating a room called 'house'
------------------------------
Making yourself a house
-----------------------
The main command for shaping the game world is ``@dig``. For example, if
you are standing in Limbo you can dig a route to your new house location
@ -240,8 +238,7 @@ This will create a new room "cliff" with an exit "southwest" leading
there and a path "northeast" leading back from the cliff to your current
location.
You can create exits from anywhere at any time using the ``@open``
command:
You can create new exits from where you are using the ``@open`` command:
::
@ -251,9 +248,9 @@ This opens an exit ``north`` to the previously created room ``house``.
If you have many rooms named ``house`` you will get a list of matches
and have to select which one you want to link to. You can also give its
database ref number, which is unique to every object. This can be found
with the ``examine`` command or by looking at the latest constructions
with ``@objects``.
database (#dbref) number, which is unique to every object. This can be
found with the ``examine`` command or by looking at the latest
constructions with ``@objects``.
Follow the north exit to your 'house' or ``@teleport`` to it:
@ -276,37 +273,46 @@ To manually open an exit back to Limbo (if you didn't do so with the
(or give limbo's dbref which is #2)
Finding and manipulating existing objects
-----------------------------------------
Reshuffling the world
---------------------
To re-point an exit at another room or object, you can use
You can find things using the ``@find`` command. Assuming you are back
at ``Limbo``, let's teleport the *large box to our house*.
::
> @link <room name> = <new_target name>
> @teleport box = house
very large box is leaving Limbo, heading for house.
Teleported very large box -> house.
To find something, use
We can still find the box by using @find:
::
> @find <name>
> @find box
One Match(#1-#8):
very large box(#8) - src.objects.objects.Object
This will return a list of dbrefs that have a similar name.
To teleport something somewhere, one uses
Knowing the #dbref of the box (#8 in this example), you can grab the box
and get it back here without actually yourself going to ``house`` first:
::
> @teleport <object> = <destination>
> @teleport #8 = here
To destroy something existing, use
(You can usually use ``here`` to refer to your current location. To
refer to yourself you can use ``self`` or ``me``). The box should now be
back in Limbo with you.
We are getting tired of the box. Let's destroy it.
::
> @destroy <object>
> @destroy box
You can destroy many objects in one go by giving a comma-separated list
of objects to the command.
of objects (or their #dbrefs, if they are not in the same location) to
the command.
Adding a help entry
-------------------
@ -322,16 +328,27 @@ command.
Adding a World
--------------
Evennia comes with a tutorial world for you to build. To build this you
need to log back in as *superuser*. Place yourself in Limbo and do:
After this brief introduction to building you may be ready to see a more
fleshed-out example. Evennia comes with a tutorial world for you to
explore.
First you need to switch back to *superuser* by using the ``@unquell``
command. Next, place yourself in ``Limbo`` and run the following
command:
::
@batchcommand contrib.tutorial_world.build
> @batchcommand contrib.tutorial_world.build
This will take a while, but you will see a lot of messages as the world
is built for you. You will end up with a new exit from Limbo named
*tutorial*. See more info about the tutorial world
`here <TutorialWorldIntroduction.html>`_. Read
``contrib/tutorial_world/build.ev`` to see exactly how it's built, step
by step.
This will take a while (be patient and don't re-run the command). You
will see all the commands used to build the world scroll by as the world
is built for you.
You will end up with a new exit from Limbo named *tutorial*. Apart from
being a little solo-adventure in its own right, the tutorial world is a
good source for learning Evennia building (and coding).
Read
`contrib/tutorial\_world/build.ev <https://code.google.com/p/evennia/source/browse/contrib/tutorial_world/build.ev>`_
to see exactly how it's built, step by step. See also more info about
the tutorial world `here <TutorialWorldIntroduction.html>`_.

View file

@ -60,8 +60,8 @@ clean the idmapper cache, the safest way is therefore a soft-reload of
the server (via e.g. the ``@reload`` command).
Most developers will not need to care with the idmapper cache - it just
makes models work intuitively. It is visible mostly in that all database
models in Evennia inherits from
makes models work intuitively. It is visible mostly in that many
database models in Evennia inherit from
``src.utils.idmapper.models.SharedMemoryModel``.
On-object variable cache
@ -95,24 +95,6 @@ latter will give an invalid-field error. If you use Evennia's own search
methods you don't need to worry about this, they look for the right
things behind the scenes for you.
Mutable variable caches
~~~~~~~~~~~~~~~~~~~~~~~
Some object properties may appear mutable - that is, they return lists.
One such example is the ``permissions`` property. This is however not
actually a list - it's just a handler that *returns* and *accepts*
lists. ``db_permissions`` is actually stored as a comma-separated
string. The uptake of this is that you cannot do list operations on the
handler. So ``obj.permissions.append('Immortals')`` will not work.
Rather, you will have to do such operations on what is returned. Like
this:
::
perms = obj.permissions # this returns a list!
perms.append("Immortals")
obj.permissions = perms # overwrites with new list
Content cache
~~~~~~~~~~~~~
@ -162,6 +144,8 @@ as fast as accessing any normal python property - this removes the
necessity for subsequent database look-ups in order to retrieve
attributes. Both ``db`` and ``ndn`` work the same way in this regard.
Apart from the lookup, each Attribute object itself caches the values
stored in it. Again this means that (after the first time) accessing an
attribute is equivalent to accessing any normal Python property.
Due to the possibility of storing objects in Attributes, the system
cannot cache the value of data stored in the Attribute (this would allow
for the system not detecting a stored Object being deleted elsewhere -
it would still be accessible from the Attribute). So having to re-access
such objects every load does incur a minor speed penalty.

View file

@ -1,3 +1,6 @@
*This tutorial requires that you first well understand how
`Commands <Commands.html>`_ work.*
Cooldowns
=========

File diff suppressed because one or more lines are too long

View file

@ -7,7 +7,9 @@ system. Stock evennia implements a 'MUX-like' system of channels, but
there is nothing stopping you from changing things to better suit your
taste.
Comms rely on two main database objects - ``Msg`` and ``Channel``.
Comms rely on two main database objects - ``Msg`` and ``Channel``. There
is also the ``TempMsg`` which mimics the API of a ``Msg`` but has no
connection to the database.
Msg
---
@ -67,10 +69,15 @@ next section).
Channels
--------
Channels are `Typeclassed <Typeclass.html>`_ entities, which mean they
can be easily extended and their functionality modified. To change which
channel typeclass Evennia uses, change
settings.BASE\_CHANNEL\_TYPECLASS.
Channels act as generic distributors of messages. Think of them as
"switch boards" redistributing ``Msg`` objects. Internally they hold a
list of "listening" objects and any ``Msg`` sent to the channel will be
distributed out to all channel listeners. Channels have
list of "listening" objects and any ``Msg`` (or ``TempMsg`` sent to the
channel will be distributed out to all channel listeners. Channels have
`Locks <Locks.html>`_ to limit who may listen and/or send messages
through them.
@ -92,11 +99,12 @@ methods of channels:
channel.msg(msgobj, header=None, senders=None, persistent=True)
The argument ``msgobj`` can be a previously constructed ``Msg`` or
``TempMsg`` - in that case all the following keywords are ignored. If
``msgobj`` is a string, the other keywords are used for creating a new
``Msg`` or ``TempMsg`` on the fly, depending on if ``persistent`` is set
or not.
The argument ``msgobj`` can be either a string, a previously constructed
``Msg`` or a ``TempMsg`` - in the latter cases all the following
keywords are ignored. If ``msgobj`` is a string, the other keywords are
used for creating a new ``Msg`` or ``TempMsg`` on the fly, depending on
if ``persistent`` is set or not. Default is to use ``TempMsg`` for
channel communication (i.e. not save everything to the database).
::
@ -108,18 +116,13 @@ or not.
# use the Msg object directly, no other keywords are needed
mychan.msg(mymsg)
# create a Msg automatically behind the scenes
# Send a non-persistent message to a channel
mychan.msg("Hello!", senders=[sender])
# send a non-persistent TempMsg (note that the senders
# keyword can also be used without a list if there is
# only one sender)
mychan.msg("Hello!", senders=sender, persistent=False)
# this is a shortcut that always sends a non-persistent TempMsg
# also if a full Msg was supplied to it (it also creates TempMsgs
# on the fly if given a string).
mychan.tempmsg(mymsg)
# send a message to list, save it to the database
# (note how the senders keyword can also be used
# without a list if there is only one sender)
mychan.msg("Hello!", senders=sender, persistent=True)
On a more advanced note, when a player enters something like
``ooc Hello!`` (where ``ooc`` is the name/alias of a channel), this is

View file

@ -58,6 +58,12 @@ do this once):
Once you have an online clone and a local copy of it:
#. Make sure that you have edited Mercurial's config file (``hgrc``) and
under the header ``[ui]`` added the line
``username=Yourname <your email>``. This is important for proper
crediting and eventual conversions. See the first point of the
`Mercurial
Quickstart <http://mercurial.selenic.com/wiki/QuickStart>`_.
#. Code away on your computer, fixing bugs or whatnot (you can be
offline for this). Commit your code to your local clone as you work,
as often as you like. There are some suggestions for setting up a

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@ General Evennia development information
- `Setting up a Mercurial environment for
coding <VersionControl.html>`_
- `Planning your own Evennia game <GamePlanning.html>`_
- `First steps coding Evennia <FirstStepsCoding.html>`_
Evennia Component Documentation
-------------------------------
@ -34,21 +35,25 @@ Evennia Component Documentation
- `Directory Overview <DirectoryOverview.html>`_
- `Portal and Server <PortalAndServer.html>`_
- `Session <Session.html>`_
- `Commands <Commands.html>`_
- `Typeclass system <Typeclasses.html>`_
- `Objects <Objects.html>`_
- `Scripts <Scripts.html>`_
- `Players <Players.html>`_
- [Communications#Channels Channels]
- `Attributes <Attributes.html>`_
- `Locks and Permissions <Locks.html>`_
- `Communications <Communications.html>`_
- `Help System <HelpSystem.html>`_
- `Nicks <Nicks.html>`_
- `Tags <Tags.html>`_
- `Sessions and Protocols <SessionProtocols.html>`_
- `Caches <Caches.html>`_
- `Web features <WebFeatures.html>`_
- `Out-of-band communication <OOB.html>`_
- `Configuration and module plugins <ServerConf.html>`_
Programming Evennia
@ -59,6 +64,7 @@ Programming Evennia
- `Useful coding utilities <CodingUtils.html>`_
- `Running and writing unit tests for Evennia <UnitTesting.html>`_
- `Running processes asynchronously <AsyncProcess.html>`_
- `Expanding Evennia with new database models <NewModels.html>`_
Work in Progress - Developer brainstorms and whitepages
-------------------------------------------------------
@ -70,6 +76,5 @@ the road.*
- `Basic game system implementation <WorkshopDefaultGame.html>`_
(inactive)
- `Rtclient protocol <Workshop.html>`_ (deprecated)
- `Summary of changes <EvenniaDevel.html>`_ of latest version vs old
Evennia (implemented in aug2010)
- `Change log <EvenniaDevel.html>`_ of big Evennia updates over time

View file

@ -188,6 +188,7 @@ or features missing, file a bug report or send us a message.
players/
scripts/
server/
portal/
typeclasses/
utils/
web/
@ -277,10 +278,10 @@ connection timeouts) are also defined here.
~~~~~~~~~~~~~~~
This directory is the heart of Evennia. It holds the server process
itself (started from ``game/evennia.py``), the portal and all `sessions
and protocols <SessionProtocols.html>`_ that allow users to connect to
the game. It also knows how to store dynamic server info in the
database.
itself (started from ``game/evennia.py``). Its subfolder ``portal/``
holds the portal and all `sessions and
protocols <SessionProtocols.html>`_ that allow users to connect to the
game.
\`src/typeclasses/\`
~~~~~~~~~~~~~~~~~~~~

File diff suppressed because one or more lines are too long

View file

@ -17,14 +17,15 @@ Quick start
For you who are extremely impatient, here's the gist of getting a
vanilla Evennia install running.
#. *Get the pre-requisites (Python, Django, Twisted and Mercurial)*.
#. *Get the pre-requisites (Python, Django, Twisted, South and
Mercurial)*.
#. *Start a command terminal/dos prompt and change directory to where
you want to have your 'evennia' folder appear*.
#. ``hg clone https://code.google.com/p/evennia/ evennia``
#. *Change directory to evennia/game*.
#. ``python manage.py``
#. ``python manage.py syncdb``
#. ``python manage.py migrate`` (only if using South)
#. ``python manage.py migrate``
#. ``python evennia.py -i start``
Evennia should now be running and you can connect to it by pointing a
@ -40,7 +41,7 @@ As far as operating systems go, any system with Python support should
work.
- Linux/Unix
- Windows (2000, XP, Vista, Win7)
- Windows (2000, XP, Vista, Win7, Win8)
- Mac OSX (>=10.5 recommended)
If you run into problems, or have success running Evennia on another
@ -55,19 +56,19 @@ Evennia:
`ActivePython <http://www.activestate.com/activepython/downloads>`_
instead.
- **`Twisted <http://twistedmatrix.com>`_** (v10.0+)
- **`Twisted <http://twistedmatrix.com>`_** (v11.0+)
- `ZopeInterface <http://www.zope.org/Products/ZopeInterface>`_
(v3.0+) - usually included in Twisted packages
- Windows users might also need
`pywin32 <http://sourceforge.net/projects/pywin32>`_.
- **`Django <http://www.djangoproject.com>`_** (v1.4+)
- **`Django <http://www.djangoproject.com>`_** (v1.5+)
- `PIL <http://www.pythonware.com/products/pil>`_ (Python Image
Library) - often distributed with Django.
- **`South <http://south.aeracode.org/>`_** (v0.7+)
- **`South <http://south.aeracode.org/>`_** (v0.8+)
- South is used to track and apply changes to the database's
structure.
@ -145,22 +146,14 @@ Optional:
problems compiling the ``PIL`` library on Mac, it's however not
strictly required in order to use Django (it's used for images).
\_Note (June 2012): Some versions of MacOSX does not seem to have
a locale setting out of the box, and this causes a traceback
during database creation. This is a known upstream bug in Django
1.4, described
`here <http://code.google.com/p/evennia/wiki/Quirks#Known_upstream_bugs>`_.
In the bug comments is also described how to add the locale and
circumvent this bug for now. This affects also Unix/Linux systems,
but those usually have the locale set out of the box.
**Windows** users should first and foremost recognize that the Evennia
server is run from the command line, something which some might not be
familiar with (based on the questions we have received). In the Windows
launch menu, just start *All Programs -> Accessories -> command prompt*
and you will get the Windows command line interface. There are plenty of
online tutorials on using the Windows command line, one example is found
`here <http://www.bleepingcomputer.com/tutorials/windows-command-prompt-introduction/>`_.
**Windows** users should first and foremost recognize that the
Evennia server is run from the command line, something which some
might not be familiar with (based on the questions we have
received). In the Windows launch menu, just start \_All Programs
-> Accessories -> command prompt and you will get the Windows
command line interface. There are plenty of online tutorials on
using the Windows command line, one example is found
`here <http://www.bleepingcomputer.com/tutorials/windows-command-prompt-introduction/>`_.
Windows users may want to install
`ActivePython <http://www.activestate.com/activepython/downloads>`_
@ -169,11 +162,12 @@ one won't let you download any packages without paying for a "Business"
license). If ActivePython is installed, you can use
`pypm <http://docs.activestate.com/activepython/2.6/pypm.html>`_ in the
same manner as ``easy_install``/``pip`` above. This *greatly* simplifies
getting started on Windows - that platform defaults to missing many of
the sane developer tools that Linux users take for granted.
getting started on Windows - this platform defaults to lacking sane
developer tools and package management.
After installing ActivePython you may need to restart the terminal/DOS
window to make the pypm command available on the command line:
window to make the pypm command available on the command line. Then
write:
::
@ -260,24 +254,19 @@ with the standard tables and values:
python manage.py syncdb
You should be asked for a superuser username, email, and password. Make
**sure** you create a superuser here when asked, this becomes your login
name for the superuser account ``#1`` in game. After this you will see a
lot of spammy install messages. If all goes well, you're ready to
continue to the next step. If not, look at the error messages and
double-check your ``settings.py`` file.
You will see a lot of spammy install messages. If all goes well, you're
ready to continue to the next step. If not, look at the error messages
and double-check your ``settings.py`` file.
If you installed ``South`` for database schema migrations, you will then
need to do this:
Next you migrate the database to the current revision:
::
python manage.py migrate
This will migrate the server to the latest version. If you don't use
``South``, migrations will not be used and your server will already be
at the latest version (but your existing database might have to be
manually edited to match eventual future schema changes that we do).
This can take a while. When we make changes to the database schema in
the future (we announce this on the homepage) you just need to re-run
this command to have your existing database converted for you.
Step 3: Starting and Stopping the Server
----------------------------------------
@ -289,10 +278,18 @@ and execute ``evennia.py`` like this:
python evennia.py -i start
This starts the server and portal. The ``-i`` flag means that the server
starts in *interactive mode*, as a foreground process. You will see
debug/log messages directly in the terminal window instead of logging
them to a file.
(The ``-i`` flag means that the server starts in *interactive mode*, as
a foreground process. You will see debug/log messages directly in the
terminal window instead of logging them to a file.)
You should be asked to create a superuser. Make **sure** you create a
superuser here when asked, this becomes your login name for the
superuser (owner) account in game. It will ask for email address and
password. The email address does not have to be an existing one.
After entering the superuser information, the server and portal will
start for the first time. Evennia will quickly run some first-time
configurations, restart once and then be running.
To stop Evennia, do:

View file

@ -55,10 +55,15 @@ For testing, we choose the *Freenode* network, ``irc.freenode.net``. We
will connect to a test channel, let's call it *#myevennia-test* (an IRC
channel always begins with ``#``). It's best if you pick an obscure
channel name that didn't exist previously - if it didn't exist it will
be created for you. *Don't* connect to ``#evennia``, that is Evennia's
official chat channel!
be created for you. *Don't* connect to ``#evennia`` for testing and
debugging, that is Evennia's official chat channel!
A *port* needed depends on the network. For Freenode this is ``6667``.
(By the way, you *are* welcome to connect your game to ``#evennia`` once
you have everything working - it can be a good way to get help and
ideas. But if you do, please do so with an in-game channel open only to
your game admins and developers).
The *port* needed depends on the network. For Freenode this is ``6667``.
What will happen is that your Evennia server will connect to this IRC
channel as a normal user. This "user" (or "bot") needs a name, which you

View file

@ -40,6 +40,10 @@ Third-party Evennia links
- `Latitude <https://github.com/dbenoy/latitude>`_ (MUCK under
development, using Evennia)
- `notimetoplay
post <http://notimetoplay.org/2013/08/29/evennia-a-mud-building-toolkit/>`_
about Evennia
General mud/game development ideas and discussions
--------------------------------------------------
@ -77,7 +81,26 @@ General mud/game development ideas and discussions
discussion about rule systems and game balance that could be
applicable also for MUDs.
x
Litterature
-----------
- Richard Bartle *Designing Virtual Worlds* (`amazon
page <http://www.amazon.com/Designing-Virtual-Worlds-Richard-Bartle/dp/0131018167>`_)
- Essential reading for the design of any persistent game world,
written by the co-creator of the original game *MUD*. Discusses
basically everything you need to think about and more.
- Richard Cantillon *An Essay on Economic Theory* (`free
pdf <http://mises.org/books/essay_on_economic_theory_cantillon.pdf>`_)
- A very good English translation of *Essai sur la Nature du Commerce
en Général*, one of the foundations of modern economic theory.
Written in 1730 but the translation is annotated and is very easy to
follow for a modern reader. Required reading if you think of
implementing a sane game economic system.
- David M. Beazley *Python Essential Reference (4th ed)* (`amazon
page <http://www.amazon.com/Python-Essential-Reference-David-Beazley/dp/0672329786/>`_)
- Our recommended book on Python; it not only efficiently summarizes
the language but is also an excellent reference to the standard
library for more experienced Python coders.
Frameworks
----------

View file

@ -221,6 +221,25 @@ Some useful default lockfuncs (see ``src/locks/lockfuncs.py`` for more):
``id/dbref`` but always looks for permissions and dbrefs of
*Players*, not on Characters.
Checking simple strings
-----------------------
Sometimes you don't really need to look up a certain lock, you just want
to check a lockstring. A common use is inside Commands, in order to
check if a user has a certain permission. The lockhandler has a method
``check_lockstring(accessing_obj, lockstring, bypass_superuser=False)``
that allows this.
::
# inside command definition
if not self.caller.locks.check_lockstring(self.caller, "dummy:perm(Wizards)"):
self.caller.msg("You must be Wizard or higher to do this!"
return
Note here that the ``access_type`` can be left to a dummy value since
this method does not actually do a Lock lookup.
Default locks
-------------

View file

@ -78,8 +78,8 @@ Coding with nicks
Nicks are are stored as the ``Nick`` database model and are referred
from the normal Evennia `object <Objects.html>`_ through the ``nicks``
property. `` nicks`` is a special handler that offers effective error
checking, searches and conversion.
property - this is known as the NickHandler. The NickHandler offers
effective error checking, searches and conversion.
::
@ -87,16 +87,16 @@ checking, searches and conversion.
object.nicks.add("greetjack", "tell Jack = Hello pal!")
# An object nick:
object.nicks.add("rose", "The red flower", nick_type="object")
obj.nicks.add("rose", "The red flower", nick_type="object")
# An player nick:
object.nicks("tom", "Tommy Hill", nick_type="player")
obj.nicks.add("tom", "Tommy Hill", nick_type="player")
# My own custom nick type (handled by my own game code somehow):
object.nicks.add("hood", "The hooded man", nick_type="my_identsystem")
obj.nicks.add("hood", "The hooded man", nick_type="my_identsystem")
# get back the translated nick:
full_name = object.nicks.get("rose", nick_type="object")
full_name = obj.nicks.get("rose", nick_type="object")
# delete a previous set nick
object.nicks.del("rose", nick_type="object")

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,11 @@
Players
=======
All gamers (real people) that opens a game *Session* on Evennia are
doing so through an object called *Player*. The Player object has no
in-game representation, it represents the account the gamer has on the
game. In order to actually get on the game the Player must *puppet* an
`Object <Objects.html>`_ (normally a Character).
All *gamers* (real people) that opens a game `Session <Session.html>`_
on Evennia are doing so through an object called *Player*. The Player
object has no in-game representation, it represents the account the
gamer has on the game. In order to actually get on the game the Player
must *puppet* an `Object <Objects.html>`_ (normally a Character).
Just how this works depends on the configuration option
``MULTISESSION_MODE``. There are three multisession modes, described in
@ -25,7 +25,7 @@ or some of the other protocols Evennia supports.
client is doing exactly the same thing as doing so in any other
connected client. All sessions will see the same output and e.g.
giving the @quit command will kill all sessions.
- In mode 2 (right) eeach Player can hold any number of sessions and
- In mode 2 (right) each Player can hold any number of sessions and
they are kept separate from one another. This allows a single player
to puppet any number of Characters and Objects.
@ -39,19 +39,18 @@ characters as well as configuration options. Players are
`CmdSet <Commands.html>`_ defaulting to the set defined by
``settings.CMDSET_PLAYER``.
If you are logged in into default Evennia under any multisession mode,
you can use the ``@ooc`` command to leave your current
`Character <Objects.html>`_ 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``
attempt to puppet a Character.
Logged into default Evennia, you can use the ``@ooc`` command to leave
your current `Character <Objects.html>`_ 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 puppet a Character.
Note that the Player object can and often do have a different set of
[Locks#Permissions Permissions] from the Character they control.
Normally you should put your permissions on the Player level - only if
your Player does not have a given permission will the permissions on the
Character be checked.
Normally you should put your permissions on the Player level - this will
overrule permissions set on the Character level (unless ``@quell``-ing
is used).
How to create your own Player types
-----------------------------------

View file

@ -4,7 +4,7 @@ Evennia Quirks
This is a list of various problems or stumbling blocks that people often
ask about or report when using (or trying to use) Evennia. These are
common stumbling blocks, non-intuitive behaviour and common newbie
mistakes when working with Evennia. They are not bugs.
mistakes when working with Evennia. They are not Evennia bugs.
Actual Evennia bugs should be reported in
`Issues <https://code.google.com/p/evennia/issues/list>`_.
@ -48,9 +48,10 @@ Web admin to create new Player
------------------------------
If you use the default login system and is trying to use the Web admin
to create a new Player account, you need to thread carefully. The
default login system *requires* the Player object to already have a
connected Character object - there is no character creation screen by
to create a new Player account, you need to consider which
MULTIPLAYER\_MODE you are in. If you are in MULTIPLAYER\_MODE 0 or 1,
the login system expects each Player to also have a Character object
named the same as the Player - there is no character creation screen by
default. If using the normal mud login screen, a Character with the same
name is automatically created and connected to your Player. From the web
interface you must do this manually.
@ -62,13 +63,6 @@ property on the Character and the "character" property on the Player to
point to each other. You must also set the lockstring of the Character
to allow the Player to "puppet" this particular character.
The default login system is very simple and intended for you to easily
get into the game. The more advanced login system in ``contrib/`` along
with the example character-creation system does not require such an
initial coupling (i.e. you can create the coupling in-game). For your
initial experiments, it's easist to create your characters from the
normal MUD connection screen instead.
Mutable attributes and their connection to the database
-------------------------------------------------------
@ -117,22 +111,4 @@ appreciate getting more input and help.
Known upstream bugs
===================
These are known bugs in in the libraries Evennia uses, i.e. things out
of our control.
Error during manage.py syncdb
-----------------------------
This error can be seen using Django 1.4 without a *locale* set. It
causes a traceback during the ``manage.py syncdb`` phase, just when
trying to create the superuser.
::
TypeError: decode() argument 1 must be string, not None
This opaque error means no locale could be found. Not properly handling
this is a bug in Django 1.4 reported
`here <https://code.djangoproject.com/ticket/16017>`_. You resolve it by
setting your locale (this is a good thing to have in any case). See the
comments to that bug report for how to do this.
There are no known upstream bugs at this time.

View file

@ -143,10 +143,10 @@ find longer descriptions of these in ``src/scripts/scripts.py``.
situations such as reloads. This is also useful for using scripts as
state managers. If the method returns ``False``, the script is
stopped and cleanly removed.
- ``at_start()`` - this is called when the script first starts. For
persistent scripts this is at least once ever server startup. Note
that this will *always* be called right away, also if ``start_delay``
is ``True``.
- ``at_start()`` - this is called when the script starts or is
unpaused. For persistent scripts this is at least once ever server
startup. Note that this will *always* be called right away, also if
``start_delay`` is ``True``.
- ``at_repeat()`` - this is called every ``interval`` seconds, or not
at all. It is called right away at startup, unless ``start_delay`` is
``True``, in which case the system will wait ``interval`` seconds
@ -173,10 +173,10 @@ possible to also invoke manually)
resumed. This is called automatically when the server reloads. No
hooks are called - as far as the script knows, it never stopped -
this is a suspension of the script, not a change of state.
- ``unpause()`` - resumes a previously paused script. Timers etc are
restored to what they were before pause. The server unpauses all
paused scripts after a server reload. No hooks are called - as far as
the script is concerned, it never stopped running.
- ``unpause()`` - resumes a previously paused script. The at\_start()
hook will be called to allow it to reclaim its internal state. Timers
etc are restored to what they were before pause. The server unpauses
all paused scripts after a server reload.
- ``time_until_next_repeat()`` - for timed scripts, this returns the
time in seconds until it next fires. Returns ``None`` if
``interval==0``.

View file

@ -43,11 +43,11 @@ code. The only way to change an Evennia setting is to edit
\`game/gamesrc/conf\` directory
-------------------------------
The ``game/gamesrc/conf/`` directory contains module templates for
customizing Evennia. Common for all these is that you should *copy* the
template up one level (to ``game/gamesrc/conf/``) and edit the copy, not
the original. You then need to change your settings file to point the
right variable at your new module. Each template header describes
The ``game/gamesrc/conf/examples/`` directory contains module templates
for customizing Evennia. Common for all these is that you should *copy*
the template up one level (to ``game/gamesrc/conf/``) and edit the copy,
not the original. You then need to change your settings file to point
the right variable at your new module. Each template header describes
exactly how to use it and which settings variable needs to be changed
for Evennia to be able to locate it.

View file

@ -81,6 +81,72 @@ MUSH parsers have jumped light years ahead of where they were even seven
or eight years ago, they can still stutter under the weight of the more
complex systems if not designed properly.
To further illustrate the lack of readability for building larger
systems in softcode, here is another example, PennMush softcode this
time, for implementing an "+info" command (it allows you to store pages
of extra character info that is later confirmed by admins and can be
viewed by other players):
::
&INC`SET u(ifo)=@include u(ifo)/INC`TARGET;@include \
u(ifo)/INC`FILENAME;@assert strlen(%q<filename>)=@nspemit \
%#=announce(INFO)%BERROR: Info file name empty.;@switch/inline \
gt(strlen(setr(attr,u(u(ifo)/FUN`FINDFILE,%q<target>,%q<filename>))),0)=1,{@assert \
or(isadmin(%#),strmatch(%q<target>,%#))=@nspemit \
%#=announce(INFO)%BERROR: You may not change another's Info \
files.;@switch/inline \
or(getstat(%q<target>/%q<attr>`FLAGS,Hidden),getstat(%q<target>/%q<attr>`FLAGS,Approved))=1,{@assert \
isadmin(%#)=@nspemit %#=announce(INFO)%BERROR: That Info File may not \
be changed by you.}},0,{@break gt(strlen(%q<filename>),18)=@nspemit \
%#=ERROR: Info names are limited to 18 characters or less.;@break \
regmatchi(%q<filename>,\\|)=@nspemit %#=ERROR: Pipe symbols are not \
allowed in info names.;@break regmatchi(%q<filename>,\/)=@nspemit \
%#=ERROR: Slashes symbols are not allowed in info names.;@assert \
strlen(%1)=ERROR: Text field empty. To delete an +info file, use \
+info/delete.};&[strfirstof(%q<attr>,setr(attr,D`INFOFILE`[nextslot(%q<target>,D`INFOFILE)]))] \
%q<target>=%q<filename>;&%q<attr>`CONTENTS %q<target>=%1;th \
setstat(%q<target>/%q<attr>`FLAGS,SetBy,%#);th \
setstat(%q<target>/%q<attr>`FLAGS,SetOn,secs());@switch/inline \
strmatch(%#,%q<target>)=1,{@nspemit %#=announce(INFO)%BYou set your \
%q<filename> Info File},{@nspemit %#=announce(INFO)%BYou set \
[name(%q<target>)]'s %q<filename> Info File!;@nspemit \
%q<target>=announce(INFO)%B%n set your %q<filename> Info File!}
(Note that the softcode is actually all one line, it was split to be
viewable on this wiki). Below is the rough Evennia equivalent
functionality as an Evennia command method, written by the same softcode
author after a week of learning Evennia:
::
def switch_set(self,target,files,rhs,isadmin):
if self.caller is not target and not isadmin:
self.caller.msg("ERROR: You may not set that person's files.")
return
if not self.rhs:
self.caller.msg("ERROR: No info file contents entered to set.")
return
for info in files:
if not re.match('^[\w-]+$', info.lower().strip()):
self.caller.msg("ERROR: File '" + info + \
"' could not be set: may only use alphanumeric characters, -, and spaces in info names.")
elif self.files.get(info.lower().strip(),{}).get("approved",None) is True:
self.caller.msg("ERROR: File '" + info.strip() + "' could not be set: file is approved.")
else:
self.files[info.lower().strip()] = {"contents":rhs, "setby":self.caller,
"seton":"timestamp", "displayname":info.strip()}
if target is self.caller:
self.caller.msg("Info File '" + info.strip() + "' set!")
else:
self.caller.msg("Info File '" + info.strip() + "' set!")
target.caller.msg(self.caller.key + " set your '" + info.strip() + "' info file!")
target.db.infofiles = dict(self.files)
return
The details of the implementation are unimportant, the difference in
readability is the main point here.
Changing Times
--------------

View file

@ -18,6 +18,9 @@ Coding basics
More details about coding with Evennia is found in the `Developer
Central <DeveloperCentral.html>`_.
- `First Steps Coding with Evennia <FirstStepsCoding.html>`_ - this is
partly duplicated in the following two tutorials using different
words.
- `Tutorial: Adding a new default
command <AddingCommandTutorial.html>`_
- `Tutorial: Adding new Object typeclasses and

File diff suppressed because one or more lines are too long

View file

@ -27,23 +27,76 @@ unlimited power to extend the game leveraging the full power of a mature
high level programming language. You can find a more elaborate
discussion about our take on MUX SoftCode `here <SoftCode.html>`_.
Documentation policy
--------------------
All the commands in the default command sets have their doc-strings
formatted on a similar form:
::
"""
Short header
Usage:
key[/switches, if any] <mandatory args> [<optional args or types>]
Switches:
switch1 - description
switch2 - description
Examples:
usage example and output
Longer documentation detailing the command.
"""
The ``Switches`` and ``Examples`` headers can be skipped if not needed.
Here is the ``nick`` command as an example:
::
"""
Define a personal alias/nick
Usage:
nick[/switches] <nickname> = [<string>]
alias ''
Switches:
object - alias an object
player - alias a player
clearall - clear all your aliases
list - show all defined aliases (also "nicks" works)
Examples:
nick hi = say Hello, I'm Sarah!
nick/object tom = the tall man
A 'nick' is a personal shortcut you create for your own use [...]
"""
For commands that *require arguments*, the policy is for it to return a
``Usage`` string if the command is entered without any arguments. So for
such commands, the Command body should contain something to the effect
of
::
if not self.args:
self.caller.msg("Usage: nick[/switches] <nickname> = [<string>]")
return
WWMD - What Would MUX Do?
-------------------------
Our policy for implementing the default commands is as follows - we tend
to look at MUX2's implementation before contriving one of our own. This
comes with a caveat though - there are many cases where this is
impossible without sacrificing the usability and utility of the
codebase. In those cases, differences in implementation as well as
command syntax is to be expected. Evennia is *not* MUX - we handle all
underlying systems very differently and don't use
`SoftCode <SoftCode.html>`_. The WWMD policy is only applied to the
default commands, not to any other programming paradigms in the
codebase.
If you are an Evennia codebase developer, consider activating
``IMPORT_MUX_HELP`` in your ``settings.py`` file. This will import a
copy of the MUX2 help database and might come in handy when it comes to
adding/implementing new default commands. If you must deviate from
MUX2's implementation of something, make sure to document it extensively
in the command's docstring.
Our original policy for implementing the default commands was to look at
MUX2's implementation and base our command syntax on that. This means
that many default commands have roughly similar syntax and switches as
MUX commands. There are however many differences between the systems and
readability and usability has taken priority (frankly, the MUX syntax is
outright arcane in places). So the default command sets can be
considered to implement a "MUX-like" dialect - whereas the overall feel
is familiar, the details may differ considerably.

View file

@ -30,8 +30,36 @@ should be easy to retrieve.
Many MUD codebases hardcode zones as part of the engine and database.
Evennia does no such distinction due to the fact that rooms themselves
are meant to be customized to any level anyway. Below is just *one*
example of how one could add zone-like functionality to a game.
are meant to be customized to any level anyway. Below are two
suggestions for how zones could be implemented.
Zones using Tags
~~~~~~~~~~~~~~~~
*OBS: Placeholder - this section is NOT fully supported by the code at
the moment!*
All objects in Evennia can hold any number of `tags <Tag.html>`_. Tags
are short labels that you attach to objects. They make it very easy to
retrieve groups of objects. An object can have any number of different
tags. So let's attach the relevant tag to our forest:
::
forestobj.tags.add("magicalforest", category="zone")
You could add this manually, or automatically during creation somehow
(you'd need to modify your @dig command for this, most likely).
Henceforth you can then easily retrieve only objects with a given tag:
::
import ev
rooms = ev.managers.Tags.get_objs_with_tag("magicalforest", category="zone") # (error here)
Zones using Aliases
~~~~~~~~~~~~~~~~~~~
All objects have a *key* property, stored in the database. This is the
primary name of the object. But it can also have any number of *Aliases*
@ -41,8 +69,8 @@ alias "door". Aliases are actually separate database entities and are as
such very fast to search for in the database, about as fast as searching
for the object's primary key in fact.
This makes Aliases prime candiates for implementing zones. All you need
to do is to come up with a consistent aliasing scheme. Here's one
This makes Aliases another candidate for implementing zones. All you
need to do is to come up with a consistent aliasing scheme. Here's one
suggestion:
::
@ -130,12 +158,12 @@ zone in the typeclass rather than enforce the ``@dig`` command to do it:
class MagicalForestRoom(Room)
def at_object_creation(self):
...
self.aliases = "#magicforest|%s" % self.key
self.aliases.add("#magicforest|%s" % self.key)
...
class NormalForestRoom(Room)
def at_object_creation(self):
...
self.aliases = "#normalforest|%s" % self.key
self.aliases.add("#normalforest|%s" % self.key)
...
Of course, an alternative way to implement zones themselves is to have