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. but in this example we assume you don't.
#. Edit ``game/settings.py``, adding the following line: #. 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. class of your newly copied module. You only need to do this once.
Creating a custom command Creating a custom command
@ -45,6 +45,7 @@ Creating a custom command
# file game/gamesrc/commands/command.py # file game/gamesrc/commands/command.py
#[...] #[...]
from ev import default_cmds
class CmdEcho(default_cmds.MuxCommand): class CmdEcho(default_cmds.MuxCommand):
""" """
Simple command example Simple command example
@ -65,30 +66,30 @@ Creating a custom command
else: else:
self.caller.msg("You gave the string: '%s'" % self.args) 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. 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 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`` #. Edit your recently copied ``game/gamesrc/commands/cmdset.py``
#. In this copied module you will find the ``DefaultCmdSet`` class #. In this copied module you will find the ``DefaultCmdSet`` class
already imported and prepared for you. Import your new command module already imported and prepared for you. Import your new command module
here with ``from game.gamesrc.commands.command import CmdEcho``. 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 ``at_cmdset_creation`` method (the template tells you where). This is
approximately how it should look at this point: 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 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): 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 See `Commands <Commands.html>`_ for many more details and possibilities
when defining Commands and using Cmdsets in various ways. 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 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 `lock <Locks.html>`_ and `Attribute <Attribute.html>`_ here set in
the typeclass could just as well have been set using commands in-game, 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 # file game/gamesrc/objects/heavy.py
from ev import Object from ev import Object
# let's assume we defined our own cmdset earlier
from game.gamesrc.commands.mycmdsets import HeavySet
class Heavy(Object): class Heavy(Object):
"Heavy object" "Heavy object"
at_object_creation(self): def at_object_creation(self):
"Called whenever a new object is created" "Called whenever a new object is created"
# lock the object down by default # lock the object down by default
self.locks.add("get:false()") 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 # this, you'd have to look at the code of the 'get' command to
# find out). # find out).
self.db.get_err_msg = "This is too heavy for you to pick up." 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 Change Default Rooms, Exits, Character Typeclass
------------------------------------------------ ------------------------------------------------

View file

@ -17,6 +17,7 @@ Installation and Early Life
Customizing the server Customizing the server
---------------------- ----------------------
- `Changing the Settings <SettingsDefault.html>`_
- `Change Evennia's language <Internationalization.html>`_ - `Change Evennia's language <Internationalization.html>`_
- `Apache webserver configuration <ApacheConfig.html>`_ (optional) - `Apache webserver configuration <ApacheConfig.html>`_ (optional)
- `Changing text encodings used by the server <TextEncodings.html>`_ - `Changing text encodings used by the server <TextEncodings.html>`_
@ -34,4 +35,5 @@ Working with Evennia
- `Setting up your work environment with version - `Setting up your work environment with version
control <VersionControl.html>`_ 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 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 themselves. This returns all associated attributes or non-persistent
properties. properties.
:: ::
list_of_all_rose_attributes = rose.db.all list_of_all_rose_attributes = rose.db.all()
list_of_all_rose_ndb_attrs = rose.ndb.all list_of_all_rose_ndb_attrs = rose.ndb.all()
If you use ``all`` as the name of an attribute, this will be used If you use ``all`` as the name of an attribute, this will be used
instead. Later deleting your custom ``all`` will return the default instead. Later deleting your custom ``all`` will return the default
behaviour. 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 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 - *attrread* - limits who may read the value of the Attribute
- *attredit* - limits who may set/change this Attribute - *attredit* - limits who may set/change this Attribute
You cannot use e.g. ``obj.db.attrname`` handler to modify Attribute You cannot use the ``db`` handler to modify Attribute object (such as
objects (such as setting a lock on them - you will only get the setting a lock on them) - The ``db`` handler will return the Attribute's
Attribute *value* that way, not the actual Attribute *object*. You get *value*, not the Attribute object itself. Instead you use
the latter with ``get_attribute_obj`` (see next section) which allows ``get_attribute_obj`` (see next section) which allows you to set the
you to set the lock something like this: 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 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 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 # in some command code where we want to limit
# setting of a given attribute name on an object # setting of a given attribute name on an object
attr = obj.get_attribute_obj(attrname, default=None) attr = obj.attributes.get(attrname, return_obj=True, accessing_obj=caller, default=None, default_access=False)
if not (attr and attr.locks.check(caller, 'attredit', default=True)): if not attr:
caller.msg("You cannot edit that Attribute!") caller.msg("You cannot edit that Attribute!")
return return
# edit the Attribute here # edit the Attribute here
Note that in this example this lock check will default to ``True`` if no The same keywords are available to use with ``obj.attributes.set()`` and
lock was defined on the Attribute (which is the normal case). You can ``obj.attributes.remove()``, those will check for the *attredit* lock
set this to False if you know all your Attributes always check access in type.
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.

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 This will make you start using the permission of your current
`Character <Objects.html>`_ instead of your superuser level. If you `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 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 will see when looking at it), but we will also recognize it by any of
of the other names we give - like *crate* or simply *box* as before. We the other names we give - like *crate* or simply *box* as before. We
could have given these aliases directly after the name in the could have given these aliases directly after the name in the
``@create`` command, this is true for all creation commands - you can ``@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 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 object. If you had wanted to not change the name itself, but to only add
aliases, you could have used the ``@alias`` command. aliases, you could have used the ``@alias`` command.
We are currently carrying the box, which you can see if you give the We are currently carrying the box. Let's drop it.
command ``inventory`` (or ``i``). 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 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 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 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 sure you are quelling your superuser powers and try to get the box now:
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 Try to get it now and you should see a nicer error message echoed back
to you. 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 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 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 However, with the combined use of custom
`Typeclasses <Typeclasses.html>`_, `Scripts <Scripts.html>`_ and `Typeclasses <Typeclasses.html>`_, `Scripts <Scripts.html>`_ and
object-based `Commands <Commands.html>`_, you could expand it and other 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 so you don't have to write the full path every time. There you go - one
red button. 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 Evennia's features. You will find that the `Scripts <Scripts.html>`_ and
`Commands <Commands.html>`_ controlling it are scattered in `Commands <Commands.html>`_ controlling it are scattered in
``examples``-folders all across ``game/gamesrc/``. ``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 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. 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 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 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 there and a path "northeast" leading back from the cliff to your current
location. location.
You can create exits from anywhere at any time using the ``@open`` You can create new exits from where you are using the ``@open`` command:
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 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 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 database (#dbref) number, which is unique to every object. This can be
with the ``examine`` command or by looking at the latest constructions found with the ``examine`` command or by looking at the latest
with ``@objects``. constructions with ``@objects``.
Follow the north exit to your 'house' or ``@teleport`` to it: 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) (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. 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:
To teleport something somewhere, one uses
:: ::
> @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 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 Adding a help entry
------------------- -------------------
@ -322,16 +328,27 @@ command.
Adding a World Adding a World
-------------- --------------
Evennia comes with a tutorial world for you to build. To build this you After this brief introduction to building you may be ready to see a more
need to log back in as *superuser*. Place yourself in Limbo and do: 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 This will take a while (be patient and don't re-run the command). You
is built for you. You will end up with a new exit from Limbo named will see all the commands used to build the world scroll by as the world
*tutorial*. See more info about the tutorial world is built for you.
`here <TutorialWorldIntroduction.html>`_. Read
``contrib/tutorial_world/build.ev`` to see exactly how it's built, step You will end up with a new exit from Limbo named *tutorial*. Apart from
by step. 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). the server (via e.g. the ``@reload`` command).
Most developers will not need to care with the idmapper cache - it just 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 makes models work intuitively. It is visible mostly in that many
models in Evennia inherits from database models in Evennia inherit from
``src.utils.idmapper.models.SharedMemoryModel``. ``src.utils.idmapper.models.SharedMemoryModel``.
On-object variable cache 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 methods you don't need to worry about this, they look for the right
things behind the scenes for you. 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 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 necessity for subsequent database look-ups in order to retrieve
attributes. Both ``db`` and ``ndn`` work the same way in this regard. attributes. Both ``db`` and ``ndn`` work the same way in this regard.
Apart from the lookup, each Attribute object itself caches the values Due to the possibility of storing objects in Attributes, the system
stored in it. Again this means that (after the first time) accessing an cannot cache the value of data stored in the Attribute (this would allow
attribute is equivalent to accessing any normal Python property. 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 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 there is nothing stopping you from changing things to better suit your
taste. 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 Msg
--- ---
@ -67,10 +69,15 @@ next section).
Channels 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 Channels act as generic distributors of messages. Think of them as
"switch boards" redistributing ``Msg`` objects. Internally they hold a "switch boards" redistributing ``Msg`` objects. Internally they hold a
list of "listening" objects and any ``Msg`` sent to the channel will be list of "listening" objects and any ``Msg`` (or ``TempMsg`` sent to the
distributed out to all channel listeners. Channels have channel will be distributed out to all channel listeners. Channels have
`Locks <Locks.html>`_ to limit who may listen and/or send messages `Locks <Locks.html>`_ to limit who may listen and/or send messages
through them. through them.
@ -92,11 +99,12 @@ methods of channels:
channel.msg(msgobj, header=None, senders=None, persistent=True) channel.msg(msgobj, header=None, senders=None, persistent=True)
The argument ``msgobj`` can be a previously constructed ``Msg`` or The argument ``msgobj`` can be either a string, a previously constructed
``TempMsg`` - in that case all the following keywords are ignored. If ``Msg`` or a ``TempMsg`` - in the latter cases all the following
``msgobj`` is a string, the other keywords are used for creating a new keywords are ignored. If ``msgobj`` is a string, the other keywords are
``Msg`` or ``TempMsg`` on the fly, depending on if ``persistent`` is set used for creating a new ``Msg`` or ``TempMsg`` on the fly, depending on
or not. 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 # use the Msg object directly, no other keywords are needed
mychan.msg(mymsg) mychan.msg(mymsg)
# create a Msg automatically behind the scenes # Send a non-persistent message to a channel
mychan.msg("Hello!", senders=[sender]) mychan.msg("Hello!", senders=[sender])
# send a non-persistent TempMsg (note that the senders # send a message to list, save it to the database
# keyword can also be used without a list if there is # (note how the senders keyword can also be used
# only one sender) # without a list if there is only one sender)
mychan.msg("Hello!", senders=sender, persistent=False) mychan.msg("Hello!", senders=sender, persistent=True)
# 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)
On a more advanced note, when a player enters something like On a more advanced note, when a player enters something like
``ooc Hello!`` (where ``ooc`` is the name/alias of a channel), this is ``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: 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 #. 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, 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 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 - `Setting up a Mercurial environment for
coding <VersionControl.html>`_ coding <VersionControl.html>`_
- `Planning your own Evennia game <GamePlanning.html>`_ - `Planning your own Evennia game <GamePlanning.html>`_
- `First steps coding Evennia <FirstStepsCoding.html>`_
Evennia Component Documentation Evennia Component Documentation
------------------------------- -------------------------------
@ -34,21 +35,25 @@ Evennia Component Documentation
- `Directory Overview <DirectoryOverview.html>`_ - `Directory Overview <DirectoryOverview.html>`_
- `Portal and Server <PortalAndServer.html>`_ - `Portal and Server <PortalAndServer.html>`_
- `Session <Session.html>`_
- `Commands <Commands.html>`_ - `Commands <Commands.html>`_
- `Typeclass system <Typeclasses.html>`_ - `Typeclass system <Typeclasses.html>`_
- `Objects <Objects.html>`_ - `Objects <Objects.html>`_
- `Scripts <Scripts.html>`_ - `Scripts <Scripts.html>`_
- `Players <Players.html>`_ - `Players <Players.html>`_
- [Communications#Channels Channels]
- `Attributes <Attributes.html>`_ - `Attributes <Attributes.html>`_
- `Locks and Permissions <Locks.html>`_ - `Locks and Permissions <Locks.html>`_
- `Communications <Communications.html>`_ - `Communications <Communications.html>`_
- `Help System <HelpSystem.html>`_ - `Help System <HelpSystem.html>`_
- `Nicks <Nicks.html>`_ - `Nicks <Nicks.html>`_
- `Tags <Tags.html>`_
- `Sessions and Protocols <SessionProtocols.html>`_ - `Sessions and Protocols <SessionProtocols.html>`_
- `Caches <Caches.html>`_ - `Caches <Caches.html>`_
- `Web features <WebFeatures.html>`_ - `Web features <WebFeatures.html>`_
- `Out-of-band communication <OOB.html>`_
- `Configuration and module plugins <ServerConf.html>`_ - `Configuration and module plugins <ServerConf.html>`_
Programming Evennia Programming Evennia
@ -59,6 +64,7 @@ Programming Evennia
- `Useful coding utilities <CodingUtils.html>`_ - `Useful coding utilities <CodingUtils.html>`_
- `Running and writing unit tests for Evennia <UnitTesting.html>`_ - `Running and writing unit tests for Evennia <UnitTesting.html>`_
- `Running processes asynchronously <AsyncProcess.html>`_ - `Running processes asynchronously <AsyncProcess.html>`_
- `Expanding Evennia with new database models <NewModels.html>`_
Work in Progress - Developer brainstorms and whitepages Work in Progress - Developer brainstorms and whitepages
------------------------------------------------------- -------------------------------------------------------
@ -70,6 +76,5 @@ the road.*
- `Basic game system implementation <WorkshopDefaultGame.html>`_ - `Basic game system implementation <WorkshopDefaultGame.html>`_
(inactive) (inactive)
- `Rtclient protocol <Workshop.html>`_ (deprecated) - `Rtclient protocol <Workshop.html>`_ (deprecated)
- `Summary of changes <EvenniaDevel.html>`_ of latest version vs old - `Change log <EvenniaDevel.html>`_ of big Evennia updates over time
Evennia (implemented in aug2010)

View file

@ -188,6 +188,7 @@ or features missing, file a bug report or send us a message.
players/ players/
scripts/ scripts/
server/ server/
portal/
typeclasses/ typeclasses/
utils/ utils/
web/ web/
@ -277,10 +278,10 @@ connection timeouts) are also defined here.
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
This directory is the heart of Evennia. It holds the server process This directory is the heart of Evennia. It holds the server process
itself (started from ``game/evennia.py``), the portal and all `sessions itself (started from ``game/evennia.py``). Its subfolder ``portal/``
and protocols <SessionProtocols.html>`_ that allow users to connect to holds the portal and all `sessions and
the game. It also knows how to store dynamic server info in the protocols <SessionProtocols.html>`_ that allow users to connect to the
database. game.
\`src/typeclasses/\` \`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 For you who are extremely impatient, here's the gist of getting a
vanilla Evennia install running. 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 #. *Start a command terminal/dos prompt and change directory to where
you want to have your 'evennia' folder appear*. you want to have your 'evennia' folder appear*.
#. ``hg clone https://code.google.com/p/evennia/ evennia`` #. ``hg clone https://code.google.com/p/evennia/ evennia``
#. *Change directory to evennia/game*. #. *Change directory to evennia/game*.
#. ``python manage.py`` #. ``python manage.py``
#. ``python manage.py syncdb`` #. ``python manage.py syncdb``
#. ``python manage.py migrate`` (only if using South) #. ``python manage.py migrate``
#. ``python evennia.py -i start`` #. ``python evennia.py -i start``
Evennia should now be running and you can connect to it by pointing a 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. work.
- Linux/Unix - Linux/Unix
- Windows (2000, XP, Vista, Win7) - Windows (2000, XP, Vista, Win7, Win8)
- Mac OSX (>=10.5 recommended) - Mac OSX (>=10.5 recommended)
If you run into problems, or have success running Evennia on another If you run into problems, or have success running Evennia on another
@ -55,19 +56,19 @@ Evennia:
`ActivePython <http://www.activestate.com/activepython/downloads>`_ `ActivePython <http://www.activestate.com/activepython/downloads>`_
instead. instead.
- **`Twisted <http://twistedmatrix.com>`_** (v10.0+) - **`Twisted <http://twistedmatrix.com>`_** (v11.0+)
- `ZopeInterface <http://www.zope.org/Products/ZopeInterface>`_ - `ZopeInterface <http://www.zope.org/Products/ZopeInterface>`_
(v3.0+) - usually included in Twisted packages (v3.0+) - usually included in Twisted packages
- Windows users might also need - Windows users might also need
`pywin32 <http://sourceforge.net/projects/pywin32>`_. `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 - `PIL <http://www.pythonware.com/products/pil>`_ (Python Image
Library) - often distributed with Django. 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 - South is used to track and apply changes to the database's
structure. structure.
@ -145,21 +146,13 @@ Optional:
problems compiling the ``PIL`` library on Mac, it's however not problems compiling the ``PIL`` library on Mac, it's however not
strictly required in order to use Django (it's used for images). strictly required in order to use Django (it's used for images).
\_Note (June 2012): Some versions of MacOSX does not seem to have **Windows** users should first and foremost recognize that the
a locale setting out of the box, and this causes a traceback Evennia server is run from the command line, something which some
during database creation. This is a known upstream bug in Django might not be familiar with (based on the questions we have
1.4, described received). In the Windows launch menu, just start \_All Programs
`here <http://code.google.com/p/evennia/wiki/Quirks#Known_upstream_bugs>`_. -> Accessories -> command prompt and you will get the Windows
In the bug comments is also described how to add the locale and command line interface. There are plenty of online tutorials on
circumvent this bug for now. This affects also Unix/Linux systems, using the Windows command line, one example is found
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/>`_. `here <http://www.bleepingcomputer.com/tutorials/windows-command-prompt-introduction/>`_.
Windows users may want to install Windows users may want to install
@ -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 license). If ActivePython is installed, you can use
`pypm <http://docs.activestate.com/activepython/2.6/pypm.html>`_ in the `pypm <http://docs.activestate.com/activepython/2.6/pypm.html>`_ in the
same manner as ``easy_install``/``pip`` above. This *greatly* simplifies same manner as ``easy_install``/``pip`` above. This *greatly* simplifies
getting started on Windows - that platform defaults to missing many of getting started on Windows - this platform defaults to lacking sane
the sane developer tools that Linux users take for granted. developer tools and package management.
After installing ActivePython you may need to restart the terminal/DOS 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 python manage.py syncdb
You should be asked for a superuser username, email, and password. Make You will see a lot of spammy install messages. If all goes well, you're
**sure** you create a superuser here when asked, this becomes your login ready to continue to the next step. If not, look at the error messages
name for the superuser account ``#1`` in game. After this you will see a and double-check your ``settings.py`` file.
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 Next you migrate the database to the current revision:
need to do this:
:: ::
python manage.py migrate python manage.py migrate
This will migrate the server to the latest version. If you don't use This can take a while. When we make changes to the database schema in
``South``, migrations will not be used and your server will already be the future (we announce this on the homepage) you just need to re-run
at the latest version (but your existing database might have to be this command to have your existing database converted for you.
manually edited to match eventual future schema changes that we do).
Step 3: Starting and Stopping the Server Step 3: Starting and Stopping the Server
---------------------------------------- ----------------------------------------
@ -289,10 +278,18 @@ and execute ``evennia.py`` like this:
python evennia.py -i start python evennia.py -i start
This starts the server and portal. The ``-i`` flag means that the server (The ``-i`` flag means that the server starts in *interactive mode*, as
starts in *interactive mode*, as a foreground process. You will see a foreground process. You will see debug/log messages directly in the
debug/log messages directly in the terminal window instead of logging terminal window instead of logging them to a file.)
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: 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 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 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 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 be created for you. *Don't* connect to ``#evennia`` for testing and
official chat channel! 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 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 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 - `Latitude <https://github.com/dbenoy/latitude>`_ (MUCK under
development, using Evennia) 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 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 discussion about rule systems and game balance that could be
applicable also for MUDs. 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 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 ``id/dbref`` but always looks for permissions and dbrefs of
*Players*, not on Characters. *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 Default locks
------------- -------------

View file

@ -78,8 +78,8 @@ Coding with nicks
Nicks are are stored as the ``Nick`` database model and are referred Nicks are are stored as the ``Nick`` database model and are referred
from the normal Evennia `object <Objects.html>`_ through the ``nicks`` from the normal Evennia `object <Objects.html>`_ through the ``nicks``
property. `` nicks`` is a special handler that offers effective error property - this is known as the NickHandler. The NickHandler offers
checking, searches and conversion. effective error checking, searches and conversion.
:: ::
@ -87,16 +87,16 @@ checking, searches and conversion.
object.nicks.add("greetjack", "tell Jack = Hello pal!") object.nicks.add("greetjack", "tell Jack = Hello pal!")
# An object nick: # 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: # 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): # 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: # 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 # delete a previous set nick
object.nicks.del("rose", nick_type="object") 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 Players
======= =======
All gamers (real people) that opens a game *Session* on Evennia are All *gamers* (real people) that opens a game `Session <Session.html>`_
doing so through an object called *Player*. The Player object has no on Evennia are doing so through an object called *Player*. The Player
in-game representation, it represents the account the gamer has on the object has no in-game representation, it represents the account the
game. In order to actually get on the game the Player must *puppet* an gamer has on the game. In order to actually get on the game the Player
`Object <Objects.html>`_ (normally a Character). must *puppet* an `Object <Objects.html>`_ (normally a Character).
Just how this works depends on the configuration option Just how this works depends on the configuration option
``MULTISESSION_MODE``. There are three multisession modes, described in ``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 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. connected client. All sessions will see the same output and e.g.
giving the @quit command will kill all sessions. 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 they are kept separate from one another. This allows a single player
to puppet any number of Characters and Objects. 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 `CmdSet <Commands.html>`_ defaulting to the set defined by
``settings.CMDSET_PLAYER``. ``settings.CMDSET_PLAYER``.
If you are logged in into default Evennia under any multisession mode, Logged into default Evennia, you can use the ``@ooc`` command to leave
you can use the ``@ooc`` command to leave your current your current `Character <Objects.html>`_ and go into OOC mode. You are
`Character <Objects.html>`_ and go into OOC mode. You are quite limited quite limited in this mode, basically it works like a simple chat
in this mode, basically it works like a simple chat program. It acts as program. It acts as a staging area for switching between Characters (if
a staging area for switching between Characters (if your game supports your game supports that) or as a safety mode if your Character gets
that) or as a safety mode if your Character gets deleted. . Use ``@ic`` deleted. Use ``@ic`` to attempt to puppet a Character.
attempt to puppet a Character.
Note that the Player object can and often do have a different set of Note that the Player object can and often do have a different set of
[Locks#Permissions Permissions] from the Character they control. [Locks#Permissions Permissions] from the Character they control.
Normally you should put your permissions on the Player level - only if Normally you should put your permissions on the Player level - this will
your Player does not have a given permission will the permissions on the overrule permissions set on the Character level (unless ``@quell``-ing
Character be checked. is used).
How to create your own Player types 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 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 ask about or report when using (or trying to use) Evennia. These are
common stumbling blocks, non-intuitive behaviour and common newbie 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 Actual Evennia bugs should be reported in
`Issues <https://code.google.com/p/evennia/issues/list>`_. `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 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 to create a new Player account, you need to consider which
default login system *requires* the Player object to already have a MULTIPLAYER\_MODE you are in. If you are in MULTIPLAYER\_MODE 0 or 1,
connected Character object - there is no character creation screen by 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 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 name is automatically created and connected to your Player. From the web
interface you must do this manually. 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 point to each other. You must also set the lockstring of the Character
to allow the Player to "puppet" this particular 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 Mutable attributes and their connection to the database
------------------------------------------------------- -------------------------------------------------------
@ -117,22 +111,4 @@ appreciate getting more input and help.
Known upstream bugs Known upstream bugs
=================== ===================
These are known bugs in in the libraries Evennia uses, i.e. things out There are no known upstream bugs at this time.
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.

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

View file

@ -43,11 +43,11 @@ code. The only way to change an Evennia setting is to edit
\`game/gamesrc/conf\` directory \`game/gamesrc/conf\` directory
------------------------------- -------------------------------
The ``game/gamesrc/conf/`` directory contains module templates for The ``game/gamesrc/conf/examples/`` directory contains module templates
customizing Evennia. Common for all these is that you should *copy* the for customizing Evennia. Common for all these is that you should *copy*
template up one level (to ``game/gamesrc/conf/``) and edit the copy, not the template up one level (to ``game/gamesrc/conf/``) and edit the copy,
the original. You then need to change your settings file to point the not the original. You then need to change your settings file to point
right variable at your new module. Each template header describes the right variable at your new module. Each template header describes
exactly how to use it and which settings variable needs to be changed exactly how to use it and which settings variable needs to be changed
for Evennia to be able to locate it. 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 or eight years ago, they can still stutter under the weight of the more
complex systems if not designed properly. 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 Changing Times
-------------- --------------

View file

@ -18,6 +18,9 @@ Coding basics
More details about coding with Evennia is found in the `Developer More details about coding with Evennia is found in the `Developer
Central <DeveloperCentral.html>`_. 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 - `Tutorial: Adding a new default
command <AddingCommandTutorial.html>`_ command <AddingCommandTutorial.html>`_
- `Tutorial: Adding new Object typeclasses and - `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 high level programming language. You can find a more elaborate
discussion about our take on MUX SoftCode `here <SoftCode.html>`_. 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? WWMD - What Would MUX Do?
------------------------- -------------------------
Our policy for implementing the default commands is as follows - we tend Our original policy for implementing the default commands was to look at
to look at MUX2's implementation before contriving one of our own. This MUX2's implementation and base our command syntax on that. This means
comes with a caveat though - there are many cases where this is that many default commands have roughly similar syntax and switches as
impossible without sacrificing the usability and utility of the MUX commands. There are however many differences between the systems and
codebase. In those cases, differences in implementation as well as readability and usability has taken priority (frankly, the MUX syntax is
command syntax is to be expected. Evennia is *not* MUX - we handle all outright arcane in places). So the default command sets can be
underlying systems very differently and don't use considered to implement a "MUX-like" dialect - whereas the overall feel
`SoftCode <SoftCode.html>`_. The WWMD policy is only applied to the is familiar, the details may differ considerably.
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.

View file

@ -30,8 +30,36 @@ should be easy to retrieve.
Many MUD codebases hardcode zones as part of the engine and database. Many MUD codebases hardcode zones as part of the engine and database.
Evennia does no such distinction due to the fact that rooms themselves 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* are meant to be customized to any level anyway. Below are two
example of how one could add zone-like functionality to a game. 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 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* 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 such very fast to search for in the database, about as fast as searching
for the object's primary key in fact. for the object's primary key in fact.
This makes Aliases prime candiates for implementing zones. All you need This makes Aliases another candidate for implementing zones. All you
to do is to come up with a consistent aliasing scheme. Here's one need to do is to come up with a consistent aliasing scheme. Here's one
suggestion: suggestion:
:: ::
@ -130,12 +158,12 @@ zone in the typeclass rather than enforce the ``@dig`` command to do it:
class MagicalForestRoom(Room) class MagicalForestRoom(Room)
def at_object_creation(self): def at_object_creation(self):
... ...
self.aliases = "#magicforest|%s" % self.key self.aliases.add("#magicforest|%s" % self.key)
... ...
class NormalForestRoom(Room) class NormalForestRoom(Room)
def at_object_creation(self): 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 Of course, an alternative way to implement zones themselves is to have