Updated the ReST documentation.

This commit is contained in:
Griatch 2013-05-15 23:49:38 +02:00
parent d30a79386f
commit cc12dc36fa
34 changed files with 935 additions and 759 deletions

18
docs/sphinx/README.txt Normal file
View file

@ -0,0 +1,18 @@
Wiki convertion and autodocs
----------------------------
The source/ directory contains Evennia's wiki documentation converted
to ReST form. This can be built to a html document by installing
python-sphinx (sphinx-doc.org) and running 'make html' from this
directory. The output will appear in under build/ - point your browser
to the index.html file.
If you want to (re-)build the documentation yourself, wiki2rest/
contains programs for converting Evennia's wiki documentation to ReST
files. Read the header of wiki2rest.py for setting up the converter.
The src2rest folder contains a reprecated program for building
documented ReST source code from Evennia's documentation. You can
arguably get as good autodocs using doxygen.

View file

@ -11,10 +11,10 @@ Evennia comes with a few very basic classes of in-game entities:
Room
Exit
So the more specific object-types are just children of the basic
``Object`` class (technically these are all
`Typeclasses <Typeclassed.html>`_ entities, but for this tutorial, just
treat them as normal Python classes).
The more specific object-types are just children of the basic ``Object``
class (technically these are all `Typeclassed <Typeclasses.html>`_
entities, but for this tutorial, just treat them as normal Python
classes).
For your own game you will most likely want to expand on these very
simple beginnings. It's normal to want your Characters to have various
@ -54,14 +54,14 @@ that characters should not have the ability to pick up.
#. Create a new module here, named ``heavy.py``. Alternatively you can
copy ``examples/object.py`` up one level and rename that file to
``heavy.py`` instead - you will then have a template to start from.
#. Code away in the ``heavy.py`` module, implementing the chair
#. Code away in the ``heavy.py`` module, implementing the heavy
functionality. See `Objects <Objects.html>`_ for more details and the
example class below. Let's call the typeclass simply ``Heavy``.
example class below. Let's call the typeclass simply "``Heavy``\ ".
#. Once you are done, log into the game with a build-capable account and
do ``@create/drop rock:heavy.Heavy`` to drop a new heavy "rock"
object in your location. Note that you have to log in as a
non-superuser (i.e. not as User #1) when trying to get the rock in
order to see its heavy effects.
object in your location. Next try to pick it up. *Note - the
superuser (User #1) will ignore all locks. Always test functionality
like this with a non-superuser character.*
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
@ -80,7 +80,7 @@ so this is a *very* simple example.
# lock the object down by default
self.locks.add("get:false()")
# the default "get" command looks for this Attribute in order
# return a customized error message (we just happen to know
# to return a customized error message (we just happen to know
# 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."
@ -114,8 +114,8 @@ Change the default Object Typeclass
Changing the root ``Object`` class works identically to changing the
``Character``, ``Room`` or ``Exit`` typeclass. After having created your
new typeclass, set ``settings.BASE_EXIT_TYPECLASS`` to point to your new
class. Let's say you call your new default ``Object`` class
new typeclass, set ``settings.BASE_OBJECT_TYPECLASS`` to point to your
new class. Let's say you call your new default ``Object`` class
``MyObject``.
There however one important further thing to remember: ``Characters``,
@ -154,6 +154,42 @@ example of a new ``myroom.py``:
"My own expandable room class"
pass
Updating existing objects
=========================
Let's say you have already created a slew of objects (Characters, Rooms,
what have you). Now you change the default typeclass for that type of
object (as described above). Unfortunately those old objects will not
know about this yet. If you want to update them you have to do this
manually. Luckily you only have to do this once, but it's a good case
for planning your game and its base typeclasses *before* starting to
build stuff.
Typeclassed objects have a useful method called ``swap_typeclass``. All
you need to do is to flip through all existing objects, calling this.
Here is an example of how to do it using some Django magic:
::
from django.conf import settings
import ev
old_default = "src.objects.objects.Object"
new_default = "game.gamesrc.objects.myobj.MyObject"
# use Django to query the database for all objects with the
# old typeclass path (typeclass path is stored in a database
# field 'db_typeclass_path)'
for obj in ev.managers.objects.filter(db_typeclass_path=old_default):
obj.swap_typeclass(new_default)
Above we use one of the Django database managers to query the database.
We are looking for the main thing typeclasses store in the database,
namely the full python path to the typeclass. We find all objects still
using the old typeclass and swap them to the new on. For more on Django
database access, see the Django manual and/or peruse ``ev.managers``.
Notes
=====

View file

@ -1,22 +1,22 @@
Apache Configuration
====================
*OBS: Evennia has a powerful in-built Twisted-based web server for
handling all web features. This works out of the box without any special
setup. This page is only of interest if you really want/need to run
Apache instead Evennia's in-built server. Note that the ajax web client
is not guaranteed to work (at least not without tweaking) on a
third-party server.*
This is an optional section only relevant for advanced users preferring
to use a third-party web server to power Evennia's front-end. For most
users the in-built Twisted web server should be enough. The in-built
server works out of the box without any extra configuration. Note that
the ajax web client will probably *not* work (at least not without
tweaking) on a third-party web server.
The suggested third-party stack for running Evennia's web front end is
You can run Evennia's web front end with
`apache2 <http://httpd.apache.org/>`_ and
`mod\_wsgi <http://code.google.com/p/modwsgi/>`_. However, the codebase
may run just fine on other servers and modules (apache2/nginx/lighttpd +
gunicorn, Tornado, uwsgi, etc.) Below are instructions on how to set
things up with various apache2 Python modules. If you get things working
using a different setup, please feel free to provide details below.
`mod\_wsgi <http://code.google.com/p/modwsgi/>`_. However, there seems
to be no reason why the codebase should not also work with other modern
web servers like nginx/lighttpd + gunicorn, Tornado, uwsgi, etc.
----
Note that the Apache instructions below might be slightly outdated. If
something is not working right, or you use Evennia with a different
server, please let us know.
SQLite Note
-----------
@ -29,8 +29,6 @@ the game and the web front-end. The best bet to any game wishing to
power their web presence with Evennia is to use Postgres, MySQL, Oracle,
or any other supported full-blown relational database.
----
mod\_wsgi Setup
---------------

View file

@ -205,6 +205,25 @@ not be available to unprivileged users. Try
version of Python for untrusted users. This will use ``run_async`` under
the hood.
delay
-----
The ``delay`` function is a much simpler sibling to ``run_async``. It is
in fact just a way to delay the execution of a command until a future
time. This is equivalent to something like ``time.sleep()`` except delay
is asynchronous while ``sleep`` would lock the entire server for the
duration of the sleep.
::
def callback(obj):
obj.msg("Returning!")
delay(10, caller, callback=callback)
This will delay the execution of the callback for 10 seconds. This
function is explored much more in `Command Duration
Tutorial <CommandDuration.html>`_.
Assorted notes
--------------

View file

@ -75,58 +75,6 @@ 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.
Fast assignment
---------------
*Depracation Warning: Fast assigment is deprecated and should not be
used - it will be removed in the future. Use the ``db`` operator
explicitly when saving to the database.*
For quick testing you can in principle skip the ``db`` operator and
assign Attributes like you would any normal Python property:
::
# saving
rose.has_thorns = True
# getting it back
is_ouch = rose.has_thorns
This looks like any normal Python assignment, but calls ``db`` behind
the scenes for you.
Note however that this form stands the chance of overloading already
existing properties on typeclasses and their database objects. Unless
you know what you are doing, this can cause lots of trouble.
::
rose.msg("hello") # this uses the in-built msg() method
rose.msg = "Ouch!" # this OVERLOADS the msg() method with a string
rose.msg("hello") # this now a gives traceback!
Overloading ``msg()`` with a string is a very bad idea since Evennia
uses this method all the time to send text to you. There are of course
situations when you *want* to overload default methods with your own
implementations - but then you'll hopefully do so intentionally and with
something that works.
::
rose.db.msg = "Ouch" # this stands no risk of overloading msg()
rose.msg("hello") # this works as it should
So using ``db``/``ndb`` will always do what you expect and is usually
the safer bet. It also makes it visually clear at all times when you are
saving to the database and not.
Another drawback of this shorter form is that it will handle a non-found
Attribute as it would any non-found property on the object. The ``db``
operator will instead return ``None`` if no matching Attribute is found.
So if an object has no attribute (or property) named ``test``, doing
``obj.test`` will raise an ``AttributeException`` error, whereas
``obj.db.test`` will return ``None``.
Persistent vs non-persistent
----------------------------
@ -325,13 +273,12 @@ commands/code wherever it fits (such as before setting an Attribute).
# 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 case by default). 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:
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:
::

View file

@ -15,12 +15,14 @@ The batch-command processor is a superuser-only function, invoked by
> @batchcode path.to.batchcodefile
Where ``path.to.batchcodefile`` is the path to a *batch-code file* with
the "``.py``\ " file ending. This path is given like a python path
relative to a folder you define to hold your batch files, set by
``BATCH_IMPORT_PATH`` in your settings. Default folder is
``game/gamesrc/world``. So if you want to run the example batch file in
``game/gamesrc/world/examples/batch_code.py``, you could simply use
Where ``path.to.batchcodefile`` is the path to a *batch-code file*. Such
a file should have a name ending in "``.py``\ " (but you shouldn't
include that when you batch-run the file from the game below). The path
is given like a python path relative to a folder you define to hold your
batch files, set by ``BATCH_IMPORT_PATH`` in your settings. Default
folder is ``game/gamesrc/world``. So if you want to run the example
batch file in ``game/gamesrc/world/examples/batch_code.py``, you could
simply use
::
@ -76,7 +78,7 @@ Here are the rules of syntax of the batch-command ``*.py`` file.
pointing to the object executing the batchcommand.
Below is a version of the example file found in
``game/gamesrc/commands/examples/batch_code.py``.
``game/gamesrc/world/examples/batch_code.py``.
::

View file

@ -37,8 +37,8 @@ as well. By default Evennia creates the following hierarchy:
#. *Players* is the default group that new players end up in. A new
player have permission to use tells, to use and create new channels.
A user having a higher-level permission also automatically have access
to locks requiring only lower-level access.
A user having a certain level of permission automatically have access to
locks specifying access of a lower level.
To assign a new permission from inside the game, you need to be able to
use the ``@perm`` command. This is an *Immortal*-level command, but it
@ -50,5 +50,32 @@ staff with the command
::
@perm/add Tommy = Immortals
@perm/add *Tommy = Immortals
The ``*`` makes sure to put the permission on the *Player* and not on
any eventual *Character* that may also be named Tommy. This is usually
what you want since the Player will then remain an Immortal regardless
of which Character they are currently controlling. To limit permission
to a per-Character level you should instead use *quelling* (see below).
Quelling your permissions
-------------------------
When developing it can be useful to check just how things would look had
your permission-level been lower. For this you can use *quelling*.
Normally, when you puppet a Character you are using your Player-level
permission. So even if your Character only has *Players* level
permissions, your *Immortals*-level Player will take precedence. With
the ``@quell`` command you can change so that the Character's permission
takes precedence instead:
::
@quell
This will allow you to test out the game using the current Character's
permission level. A developer or builder can thus in principle maintain
several test characters, all using different permission levels. Note
that you cannot escalate your permissions this way; If the Character
happens to have a *higher* permission level than the Player, the
Player's permission will still be used.

View file

@ -25,30 +25,28 @@ assigning something to an object.
Below are some examples of commands. Use ``help <command>`` for learning
more about each command and their detailed options.
Making a Builder
----------------
Stepping down from godhood
--------------------------
If you just installed Evennia, your very first player account is called
user #1, also known as the *superuser* or *god user*. This user is very
powerful, so powerful that it will override many game restrictions such
as locks. This can be useful, but it also hides some functionality that
you might want to test. Let's create a more "normal" Builder player
account instead.
you might want to test.
Get to Evennia's login screen (log off with ``@quit`` if you are already
connected) and choose ``create`` from the login screen. Create a new
account (don't log in yet). You can use any e-mail address, it doesn't
have to be an existing one. Let's say we call the new account "Anna".
Next log in *on your superuser account* and give the recently created
player build rights:
To temporarily step down from your superuser position you can use the
``@quell`` command:
::
@perm Anna = Builders
@quell
You could give the permission "Immortals" instead, if you want to assign
full admin privileges. Log out of your superuser account (``@quit``) and
finally log back in again as your new builder account.
This will make you start using the permission of your current
`Character <Objects.html>`_ instead of your superuser level. If you
didn't change any settings your game Character should have an *Immortal*
level permission - high as can be without bypassing locks like the
superuser does. This will work fine for the examples on this page. Use
``@unquell`` to get back to superuser status again afterwards.
Creating an object
------------------
@ -335,5 +333,5 @@ 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
``contrib/tutorial_world/build.ev`` to see exactly how it's built, step
by step.

View file

@ -23,6 +23,10 @@ place. Most users should not have to worry about them, but if you ever
try to "bang the metal" with Evennia, you should know what you are
seeing.
All caching schemes except Idmapper is centralized in
``src/server.caches/py``. You can turn off all caches handled by that
module by use of the ``GAME_CACHE_TYPE`` setting.
The default ``@server`` command will give a brief listing of the memory
usage of most relevant caches.
@ -68,16 +72,14 @@ All database fields on all objects in Evennia are cached by use of
properties <http://docs.python.org/library/functions.html#property>`_.
So when you do ``name = obj.key``, you are actually *not* directly
accessing a database field "key" on the object. What you are doing is
actually to access a handler. This handler looks for hidden variable
named ``_cached_db_key``. If that can be found, it is what is returned.
If not, the actual database field, named ``db_key`` are accessed. The
result is returned and cached for next time.
actually to access a handler. This handler reads the field ``db_key``
and caches its value for next time it using a call to the the
``server.caches`` module.
The naming scheme is consistent, so a given property ``obj.foo`` is a
handler with a cache named ``obj._cached_db_foo`` and a database field
``obj.db_key.`` The handler methods for the property are always named
``obj.foo_get()``, ``obj.foo_set()`` and ``obj.foo_del()`` (all are not
always needed).
The naming scheme is consistent, so a given field property ``obj.foo``
is always a handler for a database field ``obj.db_key.`` The handler
methods for the property are always named ``obj.foo_get()``,
``obj.foo_set()`` and ``obj.foo_del()`` (all are not always needed).
Apart from caching, property handlers also serves another function -
they hide away Django administration. So doing ``obj.key = "Peter"``
@ -154,16 +156,12 @@ reloading the typeclass also next try, until it is fixed.
On-object Attribute cache
-------------------------
`Attribute <Attributes.html>`_ lookups are cached by use of hidden
dictionaries on all `Typeclassed <Typeclasses.html>`_ objects - 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.
`Attribute <Attributes.html>`_ lookups on objects are also cached. This
means that after the first access or assignment, ``obj.db.attrname`` is
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.
Attribute value cache
---------------------
Each Attribute object also caches the values stored in it. Whenever
retrieving an attribute value, it is also cached for future accesses. In
effect this means that (after the first time) accessing an attribute is
equivalent to accessing any normal property.
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.

View file

@ -13,17 +13,19 @@ SQLite3
-------
This is the default database used, and for the vast majority of Evennia
installs it will probably be more than adequate or even the best choice.
No server process is needed, the administrative overhead is tiny (as is
resource consumption). The database will appear as a simple file
(``game/evennia.db3``) and since we run SQLite as an in-memory process
without any socket overhead, it might well be faster than Postgres/MySQL
unless your database is huge.
installs it will probably be more than adequate. It's definitely
recommended for most of your development. No server process is needed,
the administrative overhead is tiny (as is resource consumption). The
database will appear as a simple file (``game/evennia.db3``) and since
we run SQLite as an in-memory process without any socket overhead, it
might well be faster than Postgres/MySQL unless your database is huge.
**Note:** If you for some reason need to use a third-party web server
like Apache rather than Evennia's internal web server, SQLite is
probably not the best choice. This is due to the possibility of clashes
with file-locking when using SQLite from more than one process.
The drawback with SQLite3 is that it does not work very well will
multiple concurrent threads or processes. This has to do with
file-locking clashes of the database file. So for a production server
making heavy use of process- or threadpools (or when using a third-party
webserver like Apache), a more full-featured database may be the better
choice.
Postgres
--------
@ -54,3 +56,24 @@ No testing has been performed with Oracle, but it is also supported.
There are community maintained drivers for `MS
SQL <http://code.google.com/p/django-mssql/>`_ and possibly a few others
(found via our friend, Google).
Inspecting database data
========================
If you know SQL you can easily get command line access to your database
like this:
::
python game/gamesrc.py dbshell
This will drop you into the command line interface for your respective
database.
There are also a host of easier graphical interfaces for the various
databases. For SQLite3 we recommend `SQLite
manager <https://addons.mozilla.org/En-us/firefox/addon/sqlite-manager/>`_.
This is a plugin for the
`Firefox <http://www.mozilla.org/en-US/firefox/new/>`_ web browser
making it usable across all operating systems. Just use it to open the
game/evennia.db3 file.

View file

@ -32,7 +32,7 @@ Learn the `ev interface <evAPI.html>`_. This is a great way to explore
what Evennia has to offer. For example, start an interactive python
shell, import ``ev`` and just look around.
You can compliment your exploration by peeking at the sections of the
You can complement your exploration by peeking at the sections of the
much more detailed `Developer Central <DeveloperCentral.html>`_. The
`Tutorials <Tutorials.html>`_ section also contains a growing collection
of system- or implementation-specific help.

View file

@ -104,18 +104,18 @@ inherits\_from()
This useful function takes two arguments - an object to check and a
parent. It returns ``True`` if object inherits from parent *at any
distance* (as opposed to Python's ``is_instance()`` that will only catch
immediate dependence. This function also accepts any combination of
classes, instances or python paths to classes as inputs.
distance* (as opposed to Python's in-built ``is_instance()`` that will
only catch immediate dependence). This function also accepts as input
any combination of classes, instances or python-paths-to-classes.
Note that Python code should usually work with `duck
typing <http://en.wikipedia.org/wiki/Duck_typing>`_. But in Evennia's
case it can sometimes be useful to check if an object inherits from a
given `Typeclass <Typelasses.html>`_ as a way of identification. Say for
example that we have a typeclass *Animal*. This has a subclass *Felines*
which in turns is a parent to *HouseCat*. Maybe there are a bunch of
other animal types too, like horses and dogs. Using ``inherits_from``
will allow you to check for all animals in one go:
given `Typeclass <Typeclasses.html>`_ as a way of identification. Say
for example that we have a typeclass *Animal*. This has a subclass
*Felines* which in turns is a parent to *HouseCat*. Maybe there are a
bunch of other animal types too, like horses and dogs. Using
``inherits_from`` will allow you to check for all animals in one go:
::
@ -123,6 +123,17 @@ will allow you to check for all animals in one go:
if (utils.inherits_from(obj, "game.gamesrc.objects.animals.Animal"):
obj.msg("The bouncer stops you in the door. He says: 'No talking animals allowed.'")
delay()
-------
This is a thin wrapper around a Twisted construct called a *deferred*.
It simply won't return until a given number of seconds have passed, at
which time it will trigger a given callback with whatever argument. This
is a small and lightweight (non-persistent) alternative to a full
`Script <Scripts.html>`_. Contrary to a Script it can also handle
sub-second timing precision (although this is not something you should
normally need to worry about).
Some text utilities
-------------------
@ -168,7 +179,7 @@ string to the left edge.
::
#python code is at this indentation
#python code is entered at a given indentation
intxt = """
This is an example text that will end
up with a lot of whitespace on the left.
@ -178,8 +189,8 @@ string to the left edge.
# outtxt will now retain all internal indentation
# but be shifted all the way to the left.
Normally you do the dedent in the display code (this is the way the help
system homogenizes help entries).
Normally you do the dedent in the display code (this is for example how
the help system homogenizes help entries).
time\_format()
~~~~~~~~~~~~~~

View file

@ -9,9 +9,9 @@ in-game time, weather and so on.
Prompt after the command
------------------------
The easiest form of prompt is one that is sent after every command you
send. So, say you enter the look command; you would then get the result
of the look command, followed by the prompt. As an example: 
One common form of prompt appears after every command you send. So, say
you enter the look command; you would then get the result of the look
command, followed by the prompt. As an example: 
::
@ -26,10 +26,9 @@ To add this kind of "after-every-command-prompt", you can use the
``at_post_cmd()`` hook. This is to be defined on the Command class and
Evennia will always call it right after ``func()`` has finished
executing. For this to appear after every command you enter, it's best
to put this in the parent for your commands (for the default commands
this would be ``MuxCommand``), but you could also put it only in certain
commands (might not be too useful to show it if you are doing game
administration for example).
to put this in the parent for your own commands. You can also put it
only in certain commands (might not be too useful to show it if you are
doing game administration for example).
::
@ -48,6 +47,32 @@ administration for example).
self.caller.msg("HP: %i, SP: %i, MP: %i" % (hp, sp, mp))
Note that if you are using the default commands, they will *not* display
a command prompt after this change - they are inheriting from
``src.commands.default.muxcommand.MuxCommand``. If you want to modify
default commands you need to copy&paste the default command definitions
to ``game/gamesrc/commands`` and modify them so they inherit from your
new parent (and re-point Evennia to use your custom versions as
described `here <AddingCommandTutorial.html>`_). If you only want to add
the hook and don't need to change anything else you can just create
stubs in modules in ``game/gamesrc/commands`` on this form:
::
from ev import default_cmds
from game.gamesrc.commands.basecommand import MyCommand
class CmdLook(MyCommand, default_cmds.CmdLook):
pass
class CmdGet(MyCommand, default_cmds.CmdGet):
pass
This multiple inheritance should make use of your custom ``at_post_cmd``
hook while otherwise using the default command's code. This type of
overload is useful not only for adding prompts but for many different
forms of overloading default functionality.
Prompt on the same line
-----------------------
@ -70,14 +95,17 @@ before* the function return:
HP:10, SP:20, MP: 5
You see nothing special.
... which might be cool too, but not what we wanted. To have the prompt
appear on the same line as the return this, we need to change how
... which might be cool too, but is not what we wanted. To have the
prompt appear on the same line as the return, we need to change how
messages are returned to the player. This means a slight modification to
our *Character class* (see [Objects#Characters here] on how to change
the default Character class to your custom one). Now, all commands use
the ``object.msg()`` method for communicating with the player. This is
defined in ``src/objects/models.py``, on the ``ObjectDB`` base class.
This is how the ``msg()`` method is defined:
our *Character typeclass* (see [Objects#Characters here] on how to
change the default Character class to your custom one).
All in-game commands use the ``object.msg()`` method for communicating
with the player (this is usually called as ``self.caller.msg()`` inside
command classes). This method is defined in ``src/objects/models.py``,
on the ``ObjectDB`` base class. This is the signature of ``msg()``
method:
::
@ -113,4 +141,4 @@ some attribute defined on your character for turning on/off the prompt
(the msg() method could look for it to determine if it should add the
prompt or not). You can of course also name the above method
``msg_prompt()`` and make sure that only commands that *should* return a
prompt call this version.
prompt call that method.

View file

@ -106,6 +106,8 @@ properties:
(*Advanced note: the merged cmdset need NOT be the same as
BigGuy.cmdset. The merged set can be a combination of the cmdsets
from other objects in the room, for example*).
- ``sessid`` - this is an integer identifier for the Session triggering
this command, if any. This is seldomly needed directly.
- ``raw_string`` - this is the raw input coming from the user, without
stripping any surrounding whitespace. The only thing that is stripped
is the ending newline marker.
@ -149,8 +151,14 @@ Beyond the properties Evennia always assigns to the command at runtime
for this would be ``r"\s.*?|$"``). In that case, only ``"look me"``
will work whereas ``"lookme"`` will lead to an "command not found"
error.
- auto\_help (optional boolean). Defaults to ``True``. This allows for
turning off the
- ``func_parts`` (optional list of methods). Not defined by default,
used if it exists. This list of methods will be called in sequence,
each given a chance to yield execution. This allows for multi-part
long-running commands. See `Commands with a
Duration <CommandDuration.html>`_ for a practial presentation of how
to use this.
- ``auto_help`` (optional boolean). Defaults to ``True``. This allows
for turning off the
[`HelpSystem <HelpSystem.html>`_\ #Command\_Auto-help\_system
auto-help system] on a per-command basis. This could be useful if you
either want to write your help entries manually or hide the existence
@ -221,9 +229,9 @@ Below is how you define a simple alternative "``smile``\ " command:
caller.location.msg_contents(string, exclude=caller)
caller.msg("You smile.")
else:
target = self.search(self.target)
target = caller.search(self.target)
if not target:
# self.search handles error messages
# caller.search handles error messages
return
string = "%s smiles to you." % caller.name
target.msg(string)

View file

@ -27,32 +27,52 @@ keep.
Properties defined on \`Msg\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``sender`` - this is a reference to a unique `Player <Players.html>`_
object sending the message.
- ``receivers`` - a list of target `Players <Players.html>`_ to send
to.
- ``channels`` - a list of target Channels to send to.
- ``message`` - the actual text being sent
- ``senders`` - this is a reference to one or many
`Player <Players.html>`_ or `Objects <Objects.html>`_ (normally
*Characters*) sending the message. This could also be an *External
Connection* such as a message coming in over IRC/IMC2 (see below).
There is usually only one sender, but the types can also be mixed in
any combination.
- ``receivers`` - a list of target `Players <Players.html>`_,
`Objects <Objects.html>`_ (usually *Characters*) or *Channels* to
send the message to. The types of receivers can be mixed in any
combination.
- ``header`` - this has a max-length of 128 characters. This could be
used to store mime-type information for this type of message (such as
if it's a mail or a page), but depending on your game it could also
instead be used for the subject line or other types of header info
you want to track. Being an indexed field it can be used for quick
look-ups in the database.
- ``message`` - the actual text being sent.
- ``date_sent`` - when message was sent (auto-created).
- ``locks`` - a `lock definition <Locks.html>`_.
- ``hide_from`` - this can optionally hold a list of objects, players
or channels to hide this ``Msg`` from. This relationship is stored in
the database primarily for optimization reasons, allowing for quickly
post-filter out messages not intended for a given target. There is no
in-game methods for setting this, it's intended to be done in code.
You create new messages in code using ``ev.create_message`` (or
``src.utils.create.create_message.``)
!TempMsg
~~~~~~~~
--------
``src.objects.models`` contains a class called ``TempMsg`` that mimics a
``Msg`` but does not get saved to the database and do not require a
sender object of a certain type. It's not used by default, but you could
use it in code to send one-off messages to systems expecting a ``Msg``.
``src.comms.models`` contains a class called ``TempMsg`` which mimics
the API of ``Msg`` but is not connected to the database. It's not used
by default but you could use it in code to send non-persistent messages
to systems expecting a ``Msg`` (like *Channels*, see the example in the
next section).
Channels
--------
Channels act as generic distributors of messages. Players *subscribe* to
channels and can then send and receive message from it. Channels have
`Locks <Locks.html>`_ to limit who may join them.
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
`Locks <Locks.html>`_ to limit who may listen and/or send messages
through them.
There are three default channels created in stock Evennia - ``MUDinfo``,
``MUDconnections`` and ``Public``. Two first ones are server-related
@ -62,38 +82,50 @@ for asking questions). The default channels created are defined by
``settings.CHANNEL_PUBLIC``, ``settings.CHANNEL_MUDINFO`` and
``settings.CHANNEL_CONNECTINFO``.
You create new channels with ``ev.create_message`` (or
You create new channels with ``ev.create_channel`` (or
``src.utils.create.create_channel``).
In code, messages are sent to a channel using the
``msg(message, from_obj=None)`` method. The argument ``message`` can
either be a previously constructed ``Msg`` object or a message string.
If you send a text string, you should usually also define ``from_obj``;
a ``Msg`` object will then be created for you behind the scenes. If you
don't supply ``from_obj``, just the string will be sent to the channel
and nothing will be stored in the database (could be useful for certain
spammy error messages). You can also use ``channel.tempmsg()`` to always
send a non-persistent message, also if you send it a ``Msg`` object.
In code, messages are sent to a channel using the ``msg`` or ``tempmsg``
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.
::
# assume we have a 'sender' object and a channel named 'mychan'
# send and store in database
# send and store Msg in database
from src.utils import create
mymsg = create.create_message(sender, "Hello!", channels=[mychan])
# use the Msg object directly, no other keywords are needed
mychan.msg(mymsg)
# send a one-time message
mychan.msg("Hello!")
# create a Msg automatically behind the scenes
mychan.msg("Hello!", senders=[sender])
# send a one-time message created from a Msg object
# 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)
As a more advanced note, sending text to channels is a "special
exception" as far as commands are concerned, and you may completely
customize how this works by defining a *system\_command* with your own
code. See `Commands <Commands.html>`_ for more details.
On a more advanced note, when a player enters something like
``ooc Hello!`` (where ``ooc`` is the name/alias of a channel), this is
treated as a `System Command <Commands.html>`_ by Evennia. You may
completely customize how this works by defining a system command with
your own code. See `Commands <Commands.html>`_ for more details.
Properties defined on \`Channel\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -24,24 +24,27 @@ Effective, but not very exciting. You will most likely want to change
this to be more unique for your game.
You can customize the connection screen easily. If you look in
``game/gamesrc/world`` you will find a module named
``connection_screens.py``. Evennia looks into this module for globally
defined strings (only). These strings are used as connection screens and
shown to the user at startup. If more than one screen is defined in the
module, a random screen will be picked from among those available.
``game/gamesrc/conf/examples/`` you will find a module named
``connection_screens.py``. Copy this module up one level (to
``game/gamesrc/conf/``) and set ``settings.CONNECTION_SCREEN_MODULE`` to
point to your new module.
Evennia looks into this module for globally defined strings (only).
These strings are used as connection screens and shown to the user at
startup. If more than one screen is defined in the module, a random
screen will be picked from among those available.
Evennia's default screen is imported as ``DEFAULT_SCREEN`` from
``src.commands.connection_screen``. Remove the import or redefine
``DEFAULT_SCREEN`` to get rid of the default. There is a commented-out
example screen in the module that you can start from. You can define and
import things as normal into the module, but remember that *all* global
strings will be picked up and potentially used as a connection screen.
You can change which module Evennia uses by changing
``settings.CONNECTION_SCREEN_MODULE``.
``src.commands.connection_screen``. Remove the import at the top or
redefine ``DEFAULT_SCREEN`` to get rid of the default. There is a
commented-out example screen in the module that you can start from. You
can define and import things as normal into the module, but remember
that *all* global strings will be picked up and potentially used as a
connection screen.
You can also customize the `commands <Commands.html>`_ available during
the connection screen (``connect``, ``create`` etc). These commands are
a bit special since when the screen is running the player is not yet
identified. A command is made available at the login screen by adding
logged in. A command is made available at the login screen by adding
them to the command set specified by settings.CMDSET\_UNLOGGEDIN. The
default commands are found in ``src/commands/default/unloggedin.py``.

View file

@ -3,6 +3,16 @@ Contributing to Evennia
Wanna help out? Great! Here's how.
Contributing by spreading the word
----------------------------------
Even if you are not keen on working on the server code yourself, just
spreading the word is a big help - it will help attract more people
which leads to more feedback, motivation and interest. Rating and
writing a review on places like
`ohloh <http://www.ohloh.net/p/evennia>`_, talk about what you do in a
blog post or in mud forums, that kind of thing.
Contributing with Documentation
-------------------------------

View file

@ -27,7 +27,7 @@ defined on.
DefaultCmdset and available in the game.
The full set of available commands (all three sub-sets above) currently
contains 86 commands in 6 categories. More information about how
contains 85 commands in 6 categories. More information about how
commands work can be found in the `Command <Commands.html>`_
documentation.
@ -137,7 +137,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/adm
~~~~~
- ``key`` = ``@emit``
- ``aliases`` = ``@remit, @pemit``
- ``aliases`` = ``@pemit, @remit``
- `locks <Locks.html>`_ = ``cmd:perm(emit) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``Admin``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -319,7 +319,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
~~~~~~~~~~~~~~
- ``key`` = ``@batchcommands``
- ``aliases`` = ``@batchcmd, @batchcommand``
- ``aliases`` = ``@batchcommand, @batchcmd``
- `locks <Locks.html>`_ = ``cmd:perm(batchcommands) or superuser()``
- `help\_category <HelpSystem.html>`_ = ``Building``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -510,7 +510,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
~~~~~~~~
- ``key`` = ``@destroy``
- ``aliases`` = ``@del, @delete``
- ``aliases`` = ``@delete, @del``
- `locks <Locks.html>`_ = ``cmd:perm(destroy) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``Building``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -570,7 +570,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
~~~~~~~~
- ``key`` = ``@examine``
- ``aliases`` = ``examine, @ex, ex, exam``
- ``aliases`` = ``@ex, ex, exam, examine``
- `locks <Locks.html>`_ = ``cmd:perm(examine) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``Building``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -600,7 +600,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
~~~~~
- ``key`` = ``@find``
- ``aliases`` = ``locate, @locate, search, @search, find``
- ``aliases`` = ``find, @search, search, @locate, locate``
- `locks <Locks.html>`_ = ``cmd:perm(find) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``Building``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -666,7 +666,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
~~~~~
- ``key`` = ``@home``
- ``aliases`` = ``@sethome``
- ``aliases`` = ``<None>``
- `locks <Locks.html>`_ = ``cmd:perm(@home) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``Building``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -721,7 +721,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
~~~~~
- ``key`` = ``@lock``
- ``aliases`` = ``lock, @locks, locks``
- ``aliases`` = ``@locks, lock, locks``
- `locks <Locks.html>`_ = ``cmd: perm(@locks) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``Building``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -910,29 +910,19 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
::
teleport object to another location
teleport
Usage:
@tel/switch [<object> =] <target location>
Examples:
@tel Limbo
@tel/quiet box Limbo
@tel/tonone box
@tel/switch [<object> =] <location>
Switches:
quiet - don't echo leave/arrive messages to the source/target
locations for the move.
intoexit - if target is an exit, teleport INTO
the exit object instead of to its destination
tonone - if set, teleport the object to a None-location. If this
switch is set, <target location> is ignored.
Note that the only way to retrieve
an object from a None location is by direct #dbref
reference.
Teleports an object somewhere. If no object is given, you yourself
is teleported to the target location.
Teleports an object or yourself somewhere.
@tunnel
~~~~~~~
@ -1183,7 +1173,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/com
- ``key`` = ``@channels``
- ``aliases`` =
``comlist, channellist, all channels, channels, @clist, chanlist``
``@clist, channels, comlist, chanlist, channellist, all channels``
- `locks <Locks.html>`_ = ``cmd: not pperm(channel_banned)``
- `help\_category <HelpSystem.html>`_ = ``Comms``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -1280,7 +1270,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/com
~~~~~~~~~~~~~~~~~~~~~~
- ``key`` = ``@imcinfo``
- ``aliases`` = ``@imcchanlist, @imcwhois, @imclist``
- ``aliases`` = ``@imcchanlist, @imclist, @imcwhois``
- `locks <Locks.html>`_ =
``cmd: serversetting(IMC2_ENABLED) and pperm(Wizards)``
- `help\_category <HelpSystem.html>`_ = ``Comms``
@ -1446,7 +1436,7 @@ imctell (OOC command)
~~~~~~~~~~~~~~~~~~~~~
- ``key`` = ``imctell``
- ``aliases`` = ``imc2tell, imc2page, imcpage``
- ``aliases`` = ``imcpage, imc2tell, imc2page``
- `locks <Locks.html>`_ = ``cmd: serversetting(IMC2_ENABLED)``
- `help\_category <HelpSystem.html>`_ = ``Comms``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -1497,29 +1487,6 @@ General
`Link to Python
module <https://code.google.com/p/evennia/source/browse/src/commands/default/general.py>`_
@color
~~~~~~
- ``key`` = ``@color``
- ``aliases`` = ``<None>``
- `locks <Locks.html>`_ = ``cmd:all()``
- `help\_category <HelpSystem.html>`_ = ``General``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
(``__doc__ string``) =
::
testing colors
Usage:
@color ansi|xterm256
Print a color map along with in-mud color codes, while testing what is supported in your client.
Choices are 16-color ansi (supported in most muds) or the 256-color xterm256 standard.
No checking is done to determine your client supports color - if not you will
see rubbish appear.
@encoding (OOC command)
~~~~~~~~~~~~~~~~~~~~~~~
@ -1642,7 +1609,7 @@ access
~~~~~~
- ``key`` = ``access``
- ``aliases`` = ``hierarchy, groups``
- ``aliases`` = ``groups, hierarchy``
- `locks <Locks.html>`_ = ``cmd:all()``
- `help\_category <HelpSystem.html>`_ = ``General``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -1771,7 +1738,7 @@ inventory
~~~~~~~~~
- ``key`` = ``inventory``
- ``aliases`` = ``i, inv``
- ``aliases`` = ``inv, i``
- `locks <Locks.html>`_ = ``cmd:all()``
- `help\_category <HelpSystem.html>`_ = ``General``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -1838,7 +1805,7 @@ nick
~~~~
- ``key`` = ``nick``
- ``aliases`` = ``@nick, nicks, nickname, alias``
- ``aliases`` = ``nickname, nicks, @nick, alias``
- `locks <Locks.html>`_ = ``cmd:all()``
- `help\_category <HelpSystem.html>`_ = ``General``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -1975,7 +1942,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/sys
~~~~~~~~
- ``key`` = ``@objects``
- ``aliases`` = ``@listobjects, @stats, @db, @listobjs``
- ``aliases`` = ``@listobjects, @listobjs, @stats, @db``
- `locks <Locks.html>`_ = ``cmd:perm(listobjects) or perm(Builders)``
- `help\_category <HelpSystem.html>`_ = ``System``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -2074,7 +2041,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/sys
~~~~~~~~
- ``key`` = ``@scripts``
- ``aliases`` = ``@listscripts, @globalscript``
- ``aliases`` = ``@globalscript, @listscripts``
- `locks <Locks.html>`_ = ``cmd:perm(listscripts) or perm(Wizards)``
- `help\_category <HelpSystem.html>`_ = ``System``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -2236,7 +2203,7 @@ connect (Unloggedin command)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``key`` = ``connect``
- ``aliases`` = ``co, conn, con``
- ``aliases`` = ``conn, con, co``
- `locks <Locks.html>`_ = ``cmd:all()``
- `help\_category <HelpSystem.html>`_ = ``Unloggedin``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -2247,19 +2214,16 @@ connect (Unloggedin command)
Connect to the game.
Usage (at login screen):
connect playername password
connect "player name" "pass word"
connect <email> <password>
Use the create command to first create an account before logging in.
If you have spaces in your name, enclose it in quotes.
create (Unloggedin command)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``key`` = ``create``
- ``aliases`` = ``cr, cre``
- ``aliases`` = ``cre, cr``
- `locks <Locks.html>`_ = ``cmd:all()``
- `help\_category <HelpSystem.html>`_ = ``Unloggedin``
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
@ -2270,12 +2234,10 @@ create (Unloggedin command)
Create a new account.
Usage (at login screen):
create <playername> <password>
create "player name" "pass word"
create "playername" <email> <password>
This creates a new player account.
If you have spaces in your name, enclose it in quotes.
help (Unloggedin command)

View file

@ -1,200 +0,0 @@
"*A MUD (originally Multi-User Dungeon, with later variants
Multi-User Dimension and Multi-User Domain), pronounced 'mud', is a
multiplayer real-time virtual world described primarily in text.
MUDs combine elements of role-playing games, hack and slash, player
versus player, interactive fiction, and online chat. Players can
read or view descriptions of rooms, objects, other players,
non-player characters, and actions performed in the virtual world.
Players typically interact with each other and the world by typing
commands that resemble a natural language.*\ " -
`Wikipedia <http://en.wikipedia.org/wiki/MUD>`_
Evennia introduction
====================
If you are reading this, it's quite likely you are dreaming of creating
and running a text-based massively-multiplayer game
(`MUD/MUX/MUSH <http://tinyurl.com/c5sc4bm>`_ etc) of your very own. You
might just be starting to think about it, or you might have lugged
around that *perfect* game in your mind for years ... you know *just*
how good it would be, if you could only make it come to reality. We know
how you feel. That is, after all, why Evennia came to be.
Evennia is in principle a MUD-building system: a bare-bones Python
codebase and server intended to be highly extendable for any style of
game. "Bare-bones" in this context means that we try to impose as few
game-specific things on you as possible. So whereas we for convenience
offer basic building blocks like objects, characters, rooms, default
commands for building and administration etc, we don't prescribe any
combat rules, mob AI, races, skills, character classes or other things
that will be different from game to game anyway. It is possible that we
will offer some such systems as contributions in the future, but these
will in that case all be optional.
What we *do* however, is to provide a solid foundation for all the
boring database, networking, and behind-the-scenes administration stuff
that all online games need whether they like it or not. Evennia is
*fully persistent*, that means things you drop on the ground somewhere
will still be there a dozen server reboots later. Through Django we
support a large variety of different database systems (a database is
created for you automatically if you use the defaults).
Using the full power of Python throughout the server offers some
distinct advantages. All your coding, from object definitions and custom
commands to AI scripts and economic systems is done in normal Python
modules rather than some ad-hoc scripting language. The fact that you
script the game in the same high-level language that you code it in
allows for very powerful and custom game implementations indeed.
The server ships with a default set of player commands that are similar
to the MUX command set. We *do not* aim specifically to be a MUX server,
but we had to pick some default to go with (see `this <SoftCode.html>`_
for more about our original motivations). It's easy to remove or add
commands, or to have the command syntax mimic other systems, like Diku,
LP, MOO and so on. Or why not create a new and better command system of
your own design.
Can I test it somewhere?
------------------------
There are Evennia-based muds under development but they are still not
publicly available. If you do try to install Evennia (it's not hard), it
comes with its own tutorial though - this shows off some of the
possibilities *and* gives you a small single-player quest to play. The
tutorial takes only one single in-game command to install as explained
`here <TutorialWorldIntroduction.html>`_.
If you didn't see it before, here is also a
`screenshot <Screenshot.html>`_ of Evennia running.
Brief summary of features
=========================
Technical
---------
- Game development is done by the server importing your normal Python
modules. Specific server features are implemented by overloading
hooks that the engine calls appropriately.
- All game entities are simply Python classes that handles database
negotiations behind the scenes without you needing to worry.
- Command sets are stored on individual objects (including characters)
to offer unique functionality and object-specific commands. Sets can
be updated and modified on the fly to expand/limit player input
options during play.
- Scripts are used to offer asynchronous/timed execution abilities.
Scripts can also be persistent. There are easy mechanisms to thread
particularly long-running processes.
- In-game communication channels are modular and can be modified to any
functionality, including mailing systems and full logging of all
messages.
- Server can be fully rebooted/reloaded without users disconnecting.
- A session (player) can freely connect/disconnect from game-objects,
offering an easy way to implement multi-character systems and
puppeting.
- All source code is extensively documented.
- Unit-testing suite, including tests of default commands and plugins
Default content
---------------
- Basic classes for Objects, Characers, Rooms and Exits
- Basic login system, using the Player's login name as their in-game
Character's name for simplicity
- "MUX-like" command set with administration, building, puppeting,
channels and social commands
- In-game Tutorial
- Contributions folder with working, but optional, code such as
alternative login, menus, character generation and more
Standards/Protocols supported
-----------------------------
- Telnet with mud-specific extensions (MCCP, MSSP, TTYPE)
- SSH
- SSL
- TCP/Comet, JavaScript browser webclient included
- HTTP - Website served by in-built webserver and connected to same
database as game.
- IRC/IMC2 - external IRC and/or IMC2 channels can be connected to
in-game chat channels
- RSS feeds can be echoed to in-game channels
- ANSI, xterm256 colours
- Several different databases supported (SQLite3, MySQL, ...)
For more extensive feature information, see
`here <http://code.google.com/p/evennia/wiki/DeveloperCentral>`_.
What you need to know to work with Evennia
==========================================
Assuming you have Evennia working (see the `quick start
instructions <GettingStarted.html>`_) and have gotten as far as to start
the server and connect to it with the client of your choice, here's what
you need to know depending on your skills and needs.
I don't know (or don't want to do) any programming - I just want to run a game!
-------------------------------------------------------------------------------
Evennia comes with a default set of commands for the Python newbies and
for those who need to get a game running *now*. Stock Evennia is enough
for running a simple 'Talker'-type game - you can build and describe
rooms and basic objects, have chat channels, do emotes and other things
suitable for a social or free-form MU\ ``*``. Combat, mobs and other
game elements are not included, so you'll have a very basic game indeed
if you are not willing to do at least *some* coding.
I know basic Python, or am willing to learn
-------------------------------------------
Evennia's source code is extensively documented and `viewable
online <http://code.google.com/p/evennia/source/browse/>`_. We also have
a comprehensive `online
manual <http://code.google.com/p/evennia/wiki/Index>`_ with lots of
examples. But while Python is a relatively easy programming language, it
still represents a learning curve if you are new to programming. You
should probably sit down with a Python beginner's
`tutorial <http://docs.python.org/tutorial/>`_ (there are plenty of them
on the web if you look around) so you at least know what you are seeing.
To efficiently code your dream game in Evennia you don't need to be a
Python guru, but you do need to be able to read example code containing
at least these basic Python features:
- Importing python modules
- Using variables, `conditional
statements <http://docs.python.org/tutorial/controlflow.html#if-statements>`_,
`loops <http://docs.python.org/tutorial/controlflow.html#for-statements>`_
and
`functions <http://docs.python.org/tutorial/controlflow.html#defining-functions>`_
- Using `lists, dictionaries and list
comprehensions <http://docs.python.org/tutorial/datastructures.html>`_
- Doing `string handling and
formatting <http://docs.python.org/tutorial/introduction.html#strings>`_
- Using `Classes <http://docs.python.org/tutorial/classes.html>`_,
their methods and properties
Obviously, the more things you feel comfortable with, the easier time
you'll have to find your way. With just basic knowledge you should be
able to define your own `Commands <Commands.html>`_, create custom
`Objects <Objects.html>`_ as well as make your world come alive with
basic `Scripts <Scripts.html>`_. You can definitely build a whole
advanced and customized game from extending Evennia's examples only.
I know my Python stuff and am willing to use it!
------------------------------------------------
Even if you started out as a Python beginner, you will likely get to
this point after working on your game for a while. With more general
knowledge in Python the full power of Evennia opens up for you. Apart
from modifying commands, objects and scripts, you can develop everything
from advanced mob AI and economic systems, through sophisticated combat
and social minigames, to redefining how commands, players, rooms or
channels themselves work. Since you code your game by importing normal
Python modules, there are few limits to what you can accomplish.
If you *also* happen to know some web programming (HTML, CSS,
Javascript) there is also a web presence (a website and an mud web
client) to play around with ...
From here you can continue to the `Index <Index.html>`_ to find more
info about Evennia.

View file

@ -49,7 +49,7 @@ platform, please let us know.
You'll need the following packages and minimum versions in order to run
Evennia:
- **`Python <http://www.python.org>`_** (v2.6+, not supporting v3.x)
- **`Python <http://www.python.org>`_** (v2.6+, not supporting v3.x).
- Windows users are recommended to use
`ActivePython <http://www.activestate.com/activepython/downloads>`_
@ -62,95 +62,97 @@ Evennia:
- Windows users might also need
`pywin32 <http://sourceforge.net/projects/pywin32>`_.
- **`Django <http://www.djangoproject.com>`_** (v1.3+ or latest dev
build recommended)
- **`Django <http://www.djangoproject.com>`_** (v1.4+)
- `PIL <http://www.pythonware.com/products/pil>`_ (Python Image
Library) - often distributed with Django.
- **`South <http://south.aeracode.org/>`_** (v0.7+)
- South is used to track and apply changes to the database's
structure.
To download/update Evennia:
- **`Mercurial <http://mercurial.selenic.com/>`_**
Optional packages:
Optional:
- **`South <http://south.aeracode.org/>`_** (v0.7+)
- **`PyPy <http://pypy.org>`_** (v1.7+)
- Optional, but highly recommended. Makes it easy to keep up with
Evennia updates to the database schema.
- Optional faster implementation of Python. See
[`GettingStarted <GettingStarted.html>`_\ #Optional:\ *Running\_under\_PyPy
here] for how to run Evennia under PyPy.*
- **`Apache2 <http://httpd.apache.org>`_**
Installing pre-requisites
-------------------------
- Optional. Only use if you don't want to use Evennia's own threaded
webserver. Other equivalent web servers with a Python interpreter
module can also be used.
**All platforms** can set up an \_virtual Python environment and
install Evennia to that. All you need pre-installed is Python.
Setup is described in detail
[`GettingStarted <GettingStarted.html>`_\ #Optional:\ *A\_separate\_installation\_environment\_with\_virtualenv
here]. Windows users will probably want to go the ActivePython
route instead (see below) since there are issues with installing
certain extensions under Windows.*
Installing pre-requisites
~~~~~~~~~~~~~~~~~~~~~~~~~
**Linux** package managers should usually handle all this for you.
Python itself is definitely available through all distributions.
On Debian-derived systems (such as Ubuntu) you can do something
like this (as root) to get all you need:
**All platforms** can set up an *virtual Python environment* and install
Evennia to that. All you need pre-installed is Python. Setup is
described in detail
[`GettingStarted <GettingStarted.html>`_\ #Optional:\ *A\_separate\_installation\_environment\_with\_virtualenv
here]. Windows users will probably want to go the ActivePython way
instead though (see below), there are issues with installing certain
extensions in Windows.*
::
**Linux** package managers should usually handle all this for you.
Python itself is definitely available through all distributions. On
Debian-derived systems (such as Ubuntu) you can do something like this
(as root) to get all you need:
apt-get install python python-django python-twisted mercurial python-django-south
::
(Gentoo note: Gentoo (and maybe other distros?) seems to
distribute Twisted in multiple packages. Beyond the main twisted
package you will also need to get at least twisted-conch and
twisted-web too).\ **
apt-get install python python-django python-twisted mercurial python-django-south
Distributions can usually not keep fully up-to-date with the
latest security fixes. So for an online server it is highly
recommended to use Python's
`easy\_install <http://packages.python.org/distribute/easy_install.html>`_
or the newer
`pip <http://www.pip-installer.org/en/latest/index.html>`_ to get
some or all of the dependencies instead:
(Gentoo note: Gentoo (and maybe other distros?) seems to distribute
Twisted in multiple packages. Beyond the main twisted package you will
also need to get at least twisted-conch and twisted-web too).\ **
::
Few distros actually keep the latest updated security updates (notably
django and twisted) in their repos though. So it might be worth to use
Python's
`easy\_install <http://packages.python.org/distribute/easy_install.html>`_
or the alternative
`pip <http://www.pip-installer.org/en/latest/index.html>`_ to get some
or all of these instead:
easy_install django twisted pil mercurial south
::
::
easy_install django twisted pil mercurial south
pip install django twisted pil mercurial south
::
If you already have Python and have downloaded Evennia, the
package comes with a ``requirements.txt`` file. This can be used
with ``pip`` to install the remaining dependencies. This is useful
for automated build systems:
pip install django twisted pil mercurial south
::
If you already have Python and mercurial, and have downloaded Evennia,
the package comes with a ``requirements.txt`` file. This can be used
with ``pip`` to install the remaining dependencies (possibly useful for
automated build systems):
pip install -r requirements.txt
::
**Mac** users should be able to get most dependencies through
``easy_install`` or ``pip`` like Linux users do. All interaction
is done from a terminal window. There are some reports that you
might need to get the
`Xcode <https://developer.apple.com/xcode/>`_ development system
to install the packages that requires extension compiling. You can
also retrieve the dependencies directly and install them through
their native installers or python setups. Some users have reported
problems compiling the ``PIL`` library on Mac, it's however not
strictly required in order to use Django (it's used for images).
pip install -r requirements.txt
**Mac** users should be able to get most dependencies through
``easy_install`` or ``pip`` like Linux users do. All interaction is done
from a terminal window. There are some reports that you might need to
get the `Xcode <https://developer.apple.com/xcode/>`_ development system
to install the packages that requires extension compiling. You can also
retrieve the dependencies directly and install them through their native
installers or python setups. Some users have reported 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.
\_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
@ -167,8 +169,8 @@ 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 since that platform is by default missing
many of the sane developer systems that Linux users take for granted.
getting started on Windows - that platform defaults to missing many of
the sane developer tools that Linux users take for granted.
After installing ActivePython you may need to restart the terminal/DOS
window to make the pypm command available on the command line:
@ -328,8 +330,7 @@ set up a very easy self-contained Evennia install using the
`virtualenv <http://pypi.python.org/pypi/virtualenv>`_ program. If you
are unsure how to get it, just grab the
`virtualenv.py <https://raw.github.com/pypa/virtualenv/master/virtualenv.py>`_
file from that page and run it directly in the terminal with
``python virtualenv.py``.
file and run it directly in the terminal with ``python virtualenv.py``.
Virtualenv sets aside a folder on your harddrive as a stand-alone Python
environment. It should work both on Linux/Unix and Windows. First,
@ -339,13 +340,13 @@ in an isolated new folder *mudenv*:
::
python virtualenv mudenv --no-site-packages
virtualenv mudenv
Or, if you grabbed ``virtualenv.py`` and is running it directly:
::
python virtualenv.py mudenv --no-site-packages
python virtualenv.py mudenv
Followed by
@ -363,22 +364,71 @@ virtual environment in here.
# for Windows:
<path_to_this_place>\Scripts\activate.bat
The virtual environment within our *mudenv* folder is now active. Next
we get all the requirements with *pip*, which is included with
The virtual environment within our *mudenv* folder is now active. Things
will not seem to have changed very much, and indeed they haven't - the
only difference is that python programs will now look to the python
installation in this folder instead of the system-centric ones.
Next we get all the requirements with *pip*, which is included with
virtualenv:
::
pip install django twisted pil mercurial south
The difference from the normal install described earlier is that these
installed packages are *only* localized to the virtual environment, they
do not affect the normal versions of programs you run in the rest of
your system. So you could for example experiment with bleeding-edge,
unstable libraries or go back to older versions without having to worry
about messing up other things. It's also very easy to uninstall the
whole thing in one go - just delete your ``mudenv`` folder.
These newly installed packages are *only* localized to the virtual
environment, they do not affect the normal versions of programs you run
in the rest of your system. So you could for example experiment with
bleeding-edge, unstable libraries or go back to older versions without
having to worry about messing up other things. It's also very easy to
uninstall the whole thing in one go - just delete your ``mudenv``
folder.
You can now refer to **Step 1** above and continue on from there to
install Evennia into *mudenv*. In the future, just go into the folder
and activate it before starting or working with Evennia.
Optional: Running under !PyPy
=============================
Evennia can also be run under `PyPy <http://pypy.org>`_, a fast
alternative implementation of standard Python. Evennia under PyPy
generally takes longer to start but may run faster (just how much is
currently untested so feel free to report your findings).
You first need to download and install PyPy. See the
`PyPy <http://pypy.org>`_ homepage for instructions. This may be the
most tricky step depending on your operating system.
The easiest way to set up Evennia for running under pypy is to do so in
a separate *virtualenv*. First get the virtualenv program as described
in the previous section and create your virtual environment like this:
::
virtualenv mudenv --python=/usr/bin/pypy
Replace ``/usr/bin/pypy`` with the full path to your PyPy binary on your
system.
Next you activate and set up the virtual environment as normal. Make
sure to install all dependencies to the virtual environment. If ``pip``
aborts with a message about "dependence is already satisfied", use the
--upgrade option. This way PyPy-enhanced versions of the dependencies
will be installed wherever applicable.
Download and configure Evennia as usual. Then just start it like this:
::
pypy evennia.py -i start
Inside the game you can do the following (as superuser) to test that
PyPy is working:
::
@py import __pypy__
If this works Evennia is running under pypy. If you get an ImportError
there was some problem and normal Python is still being used.

View file

@ -1,12 +1,14 @@
Evennia Licence FAQ
Evennia License FAQ
===================
Evennia is licensed under the very friendly BSD License. You can find
the license as ``LICENCE.txt`` in the Evennia root directory. You can
also read the full license file
`here <http://code.google.com/p/evennia/source/browse/LICENSE.txt>`_.
Evennia is licensed under the very friendly
`BSD <http://en.wikipedia.org/wiki/BSD_license>`_ (3-clause) license.
You can find the license as ``LICENSE.txt`` in the Evennia root
directory. You can also read the full license file
`here <http://code.google.com/p/evennia/source/browse/LICENSE.txt>`_
(it's not long).
Q: When creating a game using Evennia, what does the licence permit me to do with it?
Q: When creating a game using Evennia, what does the license permit me to do with it?
-------------------------------------------------------------------------------------
**A:** It's your own game world to do with as you please! Keep it to
@ -16,14 +18,14 @@ it and become filthy rich for all we care.
Q: I have modified Evennia itself, what does the license say about that?
------------------------------------------------------------------------
**A:** The License allows you to do whatever you want with your modified
Evennia, including re-distributing or selling it, as long as you include
our license and copyright info in the ``LICENSE.txt`` file along with
your distribution.
**A:** The BSD license allows you to do whatever you want with your
modified Evennia, including re-distributing or selling it, as long as
you include our license and copyright info in the ``LICENSE.txt`` file
along with your distribution.
... Of course, if you add bug fixes or add some new snazzy features we
still *softly nudge* you to make those changes available upstream so
they could be added to the core Evennia package. The license don't
... Of course, if you make bug fixes or add some new snazzy feature we
*softly nudge* you to make those changes available so they can be added
to the core Evennia package for everyone's benefit. The license don't
require you to do it, but that doesn't mean we can't still greatly
appreciate it if you do!
@ -31,3 +33,10 @@ Q: Can I re-distribute the Evennia server package along with my custom game impl
-------------------------------------------------------------------------------------------
**A:** Sure. As long as the text in LICENSE.txt is included.
Q: What about Contributions?
----------------------------
The contributions in ``evennia/contrib`` are considered to be released
under the same license as Evennia itself unless the individual
contributor has specifically defined otherwise.

View file

@ -18,6 +18,7 @@ Evennia links
what was changed in each update)
- `Evennia mailing list <http://groups.google.com/group/evennia>`_
(better web interface can be found from the portal)
- `Evennia development blog <http://evennia.blogspot.se/>`_
Third-party Evennia links
-------------------------
@ -45,13 +46,13 @@ General mud/game development ideas and discussions
- `MudLab <http://mudlab.org/>`_ mud design discussion forum
- `MudConnector <http://www.mudconnect.com/>`_ mud listing and forums
- `MudBytes <http://www.mudbytes.net/>`_ mud listing and forums
- `Top Mud bytes <http://www.topmudsites.com/>`_ mud listing and forums
- `Top Mud Sites <http://www.topmudsites.com/>`_ mud listing and forums
- `MudStandards wiki <http://www.mudstandards.org/MudStandards_Wiki>`_
is an attempt at gathering protocol standards for MUD servers.
- `Planet Mud-Dev <http://planet-muddev.disinterest.org/>`_ is a blog
aggregator following blogs of current MUD development around the
'net.
aggregator following blogs of current MUD development (including
Evennia) around the 'net.
- Mud Dev mailing list archive
(`mirror1 <http://nilgiri.net/MUD-Dev-archive/>`_),(\ `mirror2 <http://www.disinterest.org/resource/MUD-Dev/>`_)
- Influential mailing list active 1996-2004. Advanced game design

View file

@ -126,8 +126,8 @@ Below are the access\_types checked by the default commandset.
- ``get``- who may pick up the object and carry it around.
- ``puppet`` - who may "become" this object and control it as their
"character".
- ``attrcreate`` - allows to create new objects on object (default
True)
- ``attrcreate`` - who may create new attributes on the object
(default True)
- [Objects#Characters Characters]: ``<Same as Objects>``
- [Objects#Exits Exits]: ``<Same as Objects>`` + ``traverse`` - who may
@ -200,10 +200,11 @@ Some useful default lockfuncs (see ``src/locks/lockfuncs.py`` for more):
- ``true()/all()`` - give access to everyone
- ``false()/none()/superuser()`` - give access to noone. Superusers
bypass the check entirely.
- ``perm(perm)`` - this tries to match a given ``permission`` property.
See [Locks#Permissions below].
- ``perm_above(perm)`` - requres a "higher" permission level than the
one given.
- ``perm(perm)`` - this tries to match a given ``permission`` property,
on a Player firsthand, on a Character second. See [Locks#Permissions
below].
- ``perm_above(perm)`` - like ``perm`` but requires a "higher"
permission level than the one given.
- ``id(num)/dbref(num)`` - checks so the access\_object has a certain
dbref/id.
- ``attr(attrname)`` - checks if a certain
@ -225,7 +226,7 @@ Default locks
Evennia sets up a few basic locks on all new objects and players (if we
didn't, noone would have any access to anything from the start). This is
all defined in the root `Typeclasses <Typeclass.html>`_ of the
all defined in the root `Typeclasses <Typeclasses.html>`_ of the
respective entity, in the hook method ``basetype_setup()`` (which you
usually don't want to edit unless you want to change how basic stuff
like rooms and exits store their internal variables). This is called
@ -245,10 +246,16 @@ set by the ``@perm`` command.
::
@perm Tommy = Builders
@perm *Tommy = Builders
All new players/character are given a default set of permissions defined
by ``settings.PERMISSION_PLAYER_DEFAULT``.
Note the use of the asterisk ``*`` above. For the ``@perm`` command it
means assigning to the `Player <Players.html>`_ Tommy instead of any
`Character <Objects.html>`_ that also happens to be named Tommy. Putting
permissions on the Player guarantees that they are kept regardless of
which Character they are currently puppeting.
All new players are given a default set of permissions defined by
``settings.PERMISSION_PLAYER_DEFAULT``.
Selected permission strings can be organized in a *permission hierarchy*
by editing the tuple ``settings.PERMISSION_HIERARCHY``. Evennia's
@ -265,11 +272,19 @@ default permission hierarchy is as follows:
The main use of this is that if you use the lock function ``perm()``
mentioned above, a lock check for a particular permission in the
hierarchy will *also* grant access to those with *higher* hierarchy
acces. So if you have the permission "Wizards" you will also pass a lock
defined as ``perm(Builders)`` or any of those levels below "Wizards".
The lock function ``perm_above(Players)`` require you to have a
permission level higher than ``Players`` and so on. If the permission
looked for is not in the hierarchy, an exact match is required.
access. So if you have the permission "Wizards" you will also pass a
lock defined as ``perm(Builders)`` or any of those levels below
"Wizards". When doing an access check from an `Object <Objects.html>`_
or Character, the ``perm()`` lock function will always first use the
permissions of any Player connected to that Object before checking for
permissions on the Object. In the case of hierarchical permissions
(Wizards, Builders etc), the Player permission will always be used (this
stops a Player from escalating their permission by puppeting a
high-level Character). If the permission looked for is not in the
hierarchy, an exact match is required, first on the Player and if not
found there (or if no Player is connected), then on the Object itself.
Below is an example of an object without any connected player
::
@ -278,6 +293,16 @@ looked for is not in the hierarchy, an exact match is required.
obj2.access(obj1, "enter") # this returns True!
And one example of a puppet with a connected player:
::
player.permissions = ["Players"]
puppet.permissions = ["Builders", "cool_guy"]
obj2.locks.add("enter:perm_above(Players) and perm(cool_guy)")
obj2.access(puppet, "enter") # this returns False!
Superusers
----------
@ -290,6 +315,18 @@ But it also hides any eventual errors you might have made in your lock
definitions. So when trying out game systems you should use a secondary
character rather than #1 so your locks get tested correctly.
Quelling
--------
The ``@quell`` command can be used to enforce the ``perm()`` lockfunc to
ignore permissions on the Player and instead use the permissions on the
Character only. This can be used e.g. by staff to test out things with a
lower permission level. Return to the normal operation with
``@unquell``. Note that quelling will use the smallest of any
hierarchical permission on the Player or Character, so one cannot
escalate one's Player permission by quelling to a high-permission
Character. Also, the superuser cannot be quelled.
More Lock definition examples
=============================

View file

@ -1,29 +1,57 @@
Players
=======
All users (in the sense of actual people) connecting to Evennia are
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; rather it is the out-of-character representation
of the user. The Player object is what is chatting on
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
the diagram below:
|image0|
From left to right, these show ``MULTISESSION_MODE`` 0, 1 and 2. In all
cases the gamer connects to the `Portal <PortalAndServer.html>`_ with
one or more sessions - this could be a telnet connection, webclient, ssh
or some of the other protocols Evennia supports.
- In mode 0 (leftmost), each Player can only hold one session at a
time. This is the normal mode for many legacy muds.
- In mode 1 (middle), each Player can hold any number of sessions but
they are all treated equal. This means all giving a command in one
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
they are kept separate from one another. This allows a single player
to puppet any number of Characters and Objects.
Apart from storing login information and other account-specific data,
the Player object is what is chatting on
`Channels <Communications.html>`_. It is also a good place to store
`Permissions <Locks.html>`_ to be consistent between different in-game
characters, configuration options, account info and other things related
to the user. Players are `TypeClassed <Typeclasses.html>`_ entities and
can store a `CmdSet <Commands.html>`_ of their own for OOC-type
commands.
characters as well as configuration options. Players are
`TypeClassed <Typeclasses.html>`_ entities defaulting to use
``settings.BASE_PLAYER_TYPECLASS``. They also hold a
`CmdSet <Commands.html>`_ defaulting to the set defined by
``settings.CMDSET_PLAYER``.
If you are logged in 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 switch back "into" your
character.
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.
Also note that the Player object can have a different set of
[Locks#Permissions Permissions] from the Character they control (in the
first character you create permissions for Player and Character are the
same, however).
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.
How to create your own Player types
-----------------------------------
@ -50,7 +78,7 @@ Here's how to define a new Player typeclass in code:
at_player_creation(self):
"this is called only once, when player is first created"
self.db.real_name = None # this is set later
self.db.real_address = None # ''
self.db.real_address = None # "
self.db.config_1 = True # default config
self.db.config_2 = False # "
self.db.config_3 = 1 # "
@ -72,58 +100,32 @@ custom properties:
- ``user`` - a unique link to a ``User`` Django object, representing
the logged-in user.
- ``character`` - a reference to an associated *Character*-type
`Object <Objects.html>`_.
- ``obj`` - an alias for ``character``.
- ``name`` - an alias for ``user.username``
- ``sessions`` - a list of all connected Sessions (physical
connections) this object listens to.
connections) this object listens to. The so-called session-id (used
in many places) is found as a property ``sessid`` on each Session
instance.
- ``is_superuser`` (bool: True/False) - if this player is a superuser.
Special handlers:
- ``cmdset`` - This holds all the current `Commands <Commands.html>`_
of this Player. By default these are the commands found in the cmdset
defined by ``settings.CMDSET_OOC``.
defined by ``settings.CMDSET_PLAYER``.
- ``nicks`` - This stores and handles `Nicks <Nicks.html>`_, in the
same way as nicks it works on Objects. For Players, nicks are
primarily used to store custom aliases for [Communications#Channels
Channels].
How it all hangs together
-------------------------
Selection of special methods (see ``src.player.models`` for details):
Looking at the above list, it's clear there are more to ``Player``\ s
than what first meets the eye.
- ``get_puppet`` - get a currently puppeted object connected to the
Player and a given given session id, if any.
- ``puppet_object`` - connect a session to a puppetable Object.
- ``unpuppet_object`` - disconnect a session from a puppetable Object.
- ``msg`` - send text to the Player
- ``execute_cmd`` - runs a command as if this Player did it.
- ``search`` - search for Players.
What happens when a person connects to Evennia and logs in is that they
log in as a ``User`` object. This is a Django object that knows all
about keeping track of authentication - it stores the login name
(``username``), password, e-mail etc.
We can't change ``User`` very much unless we want to start digging down
into Django source code (and we don't). Django however allows another
model (technically called a *profile*) to reference the User for
customization. This is our ``Player`` object. There is a one-to-one
relationship between ``User`` and Player, so we have tried to completely
hide the ``User`` interface throughout Evennia and left you to only have
to deal with ``Player``.
So for all purposes, ``Player`` represents the OOC existence of a person
logged into Evennia. You e.g. connect to
`Channels <Communications.html>`_ using your Player identity. The Player
object may store configurations and follows you wherever you go. You
will however never see the Player object in-game. This is handled by a
*Character*, a type of `Object <Objects.html>`_ connected to the
``character`` property in the list above.
So why don't we just use ``Player`` to walk around with too? The main
reason for this is flexibility. Your Player object won't change, but
your character *might*. By separating the two you could easily implement
a game where you can ``swap`` between different *Character* objects. All
you'd need to do is change the ``character`` property to point to
another suitable object (and change the values of the ``player``
property on the affected objects).
So the structure looks like ``User - Player - Character``, where the
last two are typeclassed, customizable objects.
.. |image0| image:: https://lh5.googleusercontent.com/-9XuiTr2UAbo/UZDxNLFUobI/AAAAAAAAB3I/1wArg9P-KnQ/w898-h293-no/evennia_player_sessions2.png

View file

@ -17,8 +17,9 @@ Scripts can be used for many different things in Evennia:
Time. But they can also have no time dependence at all.
- They can describe State changes.
- They can act as data stores for storing game data persistently in the
database
- They can be used to shared data between groups of objects
database.
- They can be used as OOC stores for sharing data between groups of
objects.
The most obvious use of Scripts may be to use them as *timers* or
*Events*. Consider a script running on the object ``Grandfather Clock``.
@ -52,62 +53,182 @@ references to.
In short, Scripts can be used for a lot of things.
How to create your own Script types
-----------------------------------
How to create and test your own Script types
--------------------------------------------
An Evennia Script is, per definition, a Python class that includes
``src.scripts.scripts.Script`` among its parents (if you are aware of
how typeclasses work, this is a typeclass linked to the ``ScriptDB``
database model). Scripts have no in-game representation and you cannot
define them with any default commands. They have to be created in python
code modules and imported from there into the game.
Scripts may run directly 'on' `Objects <Objects.html>`_, affecting that
object and maybe its surroundings or contents. An alternative way to
affect many objects (rather than one script per object) is to create one
Script and have it call all objects that "subscribe" to it at regular
intervals (a *ticker*). Scripts not defined directly 'on' objects are
called *Global* scripts.
Custom script modules are usually stored in ``game/gamesrc/scripts``. As
a convenience you can inherit sripts from ``ev.Script``.
You can try out scripts an add them to objects by use of the ``@script``
command (not to the confused with ``@scripts`` which lists scripts). You
can try it out with an example script:
In-game you can try out scripts using the ``@script`` command. Try the
following:
::
> @script self = examples.bodyfunctions.BodyFunctions
This should cause some random messages. The ``/stop`` switch will kill
the script again.
This should cause some random messages. Add the ``/stop`` switch to the
above command to kill the script again. You can use the ``@scripts``
command to list all active scripts in the game. Evennia creates a few
default ones.
In code, if you add scripts to `Objects <Objects.html>`_ the script can
then manipulate the object as desired. The script is added to the
object's *script handler*, called simply ``scripts``. The handler takes
care of all initialization and startup of the script for you.
Custom script modules are usually stored in ``game/gamesrc/scripts``. As
a convenience you can inherit sripts from ``ev.Script``.
If you add scripts to `Objects <Objects.html>`_ the script can then
manipulate the object as desired. The script is added to the object's
*script handler*, called simply ``scripts``. The handler takes care of
all initialization and startup of the script for you.
::
# adding a script to an existing object 'myobj'
# add script to myobj's scripthandler
myobj.scripts.add("game.gamesrc.scripts.myscripts.CoolScript")
# alternative way
from src.utils.create import create_script
from ev import create_script
create_script("game.gamesrc.scripts.myscripts.CoolScript", obj=myobj)
The creation method(s) takes an optional argument *key* that allows you
to name your script uniquely before adding it. This can be useful if you
add many scripts of the same type and later plan to use
``myobj.scripts.delete`` to remove individual scripts.
A script does not have to be connected to an in-game object. Such
scripts are called *Global scripts*. You can create global scripts by
simply not supplying an object to store it on:
You can create global scripts with
``ev.create_script (a shortcut to ``\ src.utils.create.create\_script()\ ``). Just don't supply an object to store it on. {{{ # adding a global script from ev import create_script create_script("game.gamesrc.scripts.globals.MyGlobalEconomy", key="economy", obj=None) }}} Assuming the Script ``\ game.gamesrc.scripts.globals.MyGlobalEconomy\ `` exists, this will create and start it as a global script. == Properties and functions defined on Scripts == It's important to know the variables controlling the script before one can create one. Beyond those properties assigned to all typeclassed objects (see [Typeclasses]), such as ``\ key\ ``, ``\ db\ ``, ``\ ndb\ `` etc, all Scripts also have the following properties: * ``\ desc\ `` - an optional description of the script's function. Seen in script listings. * ``\ interval\ `` - how often the script should run. If ``\ interval
==
0\ `` (default), it runs forever, without any repeating (it will not accept a negative value). * ``\ start\_delay\ `` - (bool), if we should wait ``\ interval\ `` seconds before firing for the first time or not. * ``\ repeats\ `` - How many times we should repeat, assuming ``\ interval
> 0\ ``. If repeats is set to ``\ <=
0\ ``, the script will repeat indefinitely. * ``\ persistent\ ``- if this script should survive a server reboot. There is one special property: * ``\ obj\ `` - the [Objects Object] this script is attached to (if any). You should not need to set this manually. If you add the script to the Object with ``\ myobj.scripts.add(myscriptpath)\ `` or give ``\ myobj\ `` as an argument to the ``\ utils.create.create\_script\ `` function, the ``\ obj\ `` property will be set to ``\ myobj\ `` for you. It's also imperative to know the hook functions. Normally, overriding these are all the customization you'll need to do in Scripts. You can find longer descriptions of these in ``\ src/scripts/scripts.py\ ``. * ``\ at\_script\_creation()\ `` - this is usually where the script class sets things like ``\ interval\ `` and ``\ repeats\ ``; things that control how the script runs. It is only called once - when the script is first created. * ``\ is\_valid()\ `` - determines if the script should still be running or not. This is called when running ``\ obj.scripts.validate()\ ``, which you can run manually, but which also Evennia calls during certain 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\_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 before calling. * ``\ at\_stop()\ `` - this is called when the script stops for whatever reason. It's a good place to do custom cleanup. * ``\ at\_server\_reload()\ `` - this is called whenever the server is warm-rebooted (e.g. with the ``\ @reload\ `` command). It's a good place to save non-persistent data you might want to survive a reload. * ``\ at\_server\_shutdown()\ `` - this is called on a full systems shutdown. Running methods (usually called automatically by the engine, but possible to also invoke manually) * ``\ start()\ `` - this will start the script. This is called automatically whenever you add a new script to a handler. ``\ at\_start()\ `` will be called. * ``\ stop()\ `` - this will stop the script and delete it. Removing a script from a handler will stop it automatically. ``\ at\_stop()\ `` will be called. * ``\ pause()\ `` - this pauses a running script, rendering it inactive, but not deleting it. All properties are saved and timers can be 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. * ``\ time\_until\_next\_repeat()\ `` - for timed scripts, this returns the time in seconds until it next fires. Returns ``\ None\ `` if ``\ interval==0\ ``. == Example script == {{{ import random from ev import Script class Weather(Script): "Displays weather info. Meant to be attached to a room." def at_script_creation(self): "Called once, during initial creation" self.key = "weather_script" self.desc = "Gives random weather messages." self.interval = 60 * 5 # every 5 minutes self.persistent = True self.at_repeat(self): "called every self.interval seconds." rand = random.random() if rand < 0.5: weather = "A faint breeze is felt." elif rand < 0.7: weather = "Clouds sweep across the sky." else: weather = "There is a light drizzle of rain." # send this message to everyone inside the object this # script is attached to (likely a room) self.obj.msg_contents(weather) }}} This is a simple weather script that we can put on an object. Every 5 minutes it will tell everyone inside that object how the weather is. To activate it, just add it to the script handler (``\ scripts\ ``) on an [Objects Room]. That object becomes ``\ self.obj\ `` in the example above. Here we put it on a room called ``\ myroom\ ``: {{{ myroom.scripts.add(weather.Weather) }}} In code you can also use the create function directly if you know how to locate the room you want: {{{ from ev import create_script create_script('game.gamesrc.scripts.weather.Weather', obj=myroom) }}} Or, from in-game, use the ``\ @script\ ````
command:
::
# adding a global script
from ev import create_script
create_script("game.gamesrc.scripts.globals.MyGlobalEconomy", key="economy", obj=None)
Assuming the Script ``game.gamesrc.scripts.globals.MyGlobalEconomy``
exists, this will create and start it as a global script.
Properties and functions defined on Scripts
-------------------------------------------
A Script has all the properties of a typeclassed object, such as ``db``
and ``ndb``\ (see `Typeclasses <Typeclasses.html>`_). Setting ``key`` is
useful in order to manage scripts (delete them by name etc). These are
usually set up in the Script's typeclass, but can also be assigned on
the fly as keyword arguments to ``ev.create_script``.
- ``desc`` - an optional description of the script's function. Seen in
script listings.
- ``interval`` - how often the script should run. If ``interval == 0``
(default), it runs forever, without any repeating (it will not accept
a negative value).
- ``start_delay`` - (bool), if we should wait ``interval`` seconds
before firing for the first time or not.
- ``repeats`` - How many times we should repeat, assuming
``interval > 0``. If repeats is set to ``<= 0``, the script will
repeat indefinitely.
- ``persistent``- if this script should survive a server *reset* or
server *shutdown*. (You don't need to set this for it to survive a
normal reload - the script will be paused and seamlessly restart
after the reload is complete).
There is one special property:
- ``obj`` - the `Object <Objects.html>`_ this script is attached to (if
any). You should not need to set this manually. If you add the script
to the Object with ``myobj.scripts.add(myscriptpath)`` or give
``myobj`` as an argument to the ``utils.create.create_script``
function, the ``obj`` property will be set to ``myobj`` for you.
It's also imperative to know the hook functions. Normally, overriding
these are all the customization you'll need to do in Scripts. You can
find longer descriptions of these in ``src/scripts/scripts.py``.
- ``at_script_creation()`` - this is usually where the script class
sets things like ``interval`` and ``repeats``; things that control
how the script runs. It is only called once - when the script is
first created.
- ``is_valid()`` - determines if the script should still be running or
not. This is called when running ``obj.scripts.validate()``, which
you can run manually, but which also Evennia calls during certain
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_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
before calling.
- ``at_stop()`` - this is called when the script stops for whatever
reason. It's a good place to do custom cleanup.
- ``at_server_reload()`` - this is called whenever the server is
warm-rebooted (e.g. with the ``@reload`` command). It's a good place
to save non-persistent data you might want to survive a reload.
- ``at_server_shutdown()`` - this is called when a system reset or
systems shutdown is invoked.
Running methods (usually called automatically by the engine, but
possible to also invoke manually)
- ``start()`` - this will start the script. This is called
automatically whenever you add a new script to a handler.
``at_start()`` will be called.
- ``stop()`` - this will stop the script and delete it. Removing a
script from a handler will stop it automatically. ``at_stop()`` will
be called.
- ``pause()`` - this pauses a running script, rendering it inactive,
but not deleting it. All properties are saved and timers can be
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.
- ``time_until_next_repeat()`` - for timed scripts, this returns the
time in seconds until it next fires. Returns ``None`` if
``interval==0``.
Example script
--------------
::
import random
from ev import Script
class Weather(Script):
"Displays weather info. Meant to be attached to a room."
def at_script_creation(self):
"Called once, during initial creation"
self.key = "weather_script"
self.desc = "Gives random weather messages."
self.interval = 60 * 5 # every 5 minutes
self.persistent = True
def at_repeat(self):
"called every self.interval seconds."
rand = random.random()
if rand < 0.5:
weather = "A faint breeze is felt."
elif rand < 0.7:
weather = "Clouds sweep across the sky."
else:
weather = "There is a light drizzle of rain."
# send this message to everyone inside the object this
# script is attached to (likely a room)
self.obj.msg_contents(weather)
This is a simple weather script that we can put on an object. Every 5
minutes it will tell everyone inside that object how the weather is.
To activate it, just add it to the script handler (``scripts``) on an
`Room <Objects.html>`_. That object becomes ``self.obj`` in the example
above. Here we put it on a room called ``myroom``:
::
myroom.scripts.add(weather.Weather)
In code you can also use the create function directly if you know how to
locate the room you want:
::
from ev import create_script
create_script('game.gamesrc.scripts.weather.Weather', obj=myroom)
Or, from in-game, use the ``@script`` command:
::

View file

@ -2,38 +2,44 @@ Ticker Scripts ("Heartbeats")
=============================
A common way to implement a dynamic MUD is by using "tickers", also
known as "heartbeats". Tickers are very common or even unavoidable in
other mud code bases, where many systems are hard coded to rely on the
concept of the global 'tick'. In Evennia this is very much up to your
game and which requirements you have. `Scripts <Scripts.html>`_ are
powerful enough to act as any type of counter you want.
known as "heartbeats". A ticker is a timer that fires ("ticks" at a
given interval. The tick triggers updates in various game systems.
Tickers are very common or even unavoidable in other mud code bases,
where many systems are hard coded to rely on the concept of the global
'tick'. Evennia has no such notion - the use of tickers (or not) is very
much up to your game and which requirements you have.
`Scripts <Scripts.html>`_ are powerful enough to act as any type of
counter you want and the "ticker recipe" is just one convenient (and
occationally effective) way of cranking the wheels.
When \_not\_ to use tickers
---------------------------
Even if you are used to habitually relying on tickers in other code
bases, stop and think about what you really need them for. Notably you
should think very, *very* hard before implementing a ticker to *catch
changes in something that rarely changes*. Think about it - you might
have to run the ticker every second to react to changes fast enough.
This means that most of the time *nothing* will have changed. You are
doing pointless calls (since skipping the call gives the same result as
doing it). Making sure nothing's changed might even be a tad expensive
depending on the complexity of your system. Not to mention that you
might need to run the check on every object in the database. Every
second. Just to maintain status quo.
First, let's consider when *not* to use tickers. Even if you are used to
habitually relying on tickers for everything in other code bases, stop
and think about what you really need them for. Notably you should
*never* try implement a ticker to *catch changes*. Think about it - you
might have to run the ticker every second to react to the change fast
enough. Most likely nothing will have changed most of the time. So you
are doing pointless calls (since skipping the call gives the same result
as doing it). Making sure nothing's changed might even be
computationally expensive depending on the complexity of your system.
Not to mention that you might need to run the check on every object in
the database. Every second. Just to maintain status quo.
Rather than checking over and over on the off-chance that something
changed, consider a more proactive approach. Can you maybe implement
your rarely changing system to *itself* report its change *whenever* it
happens? It's almost always much cheaper/efficient if you can do things
"on demand". Evennia itself uses hook methods all over for this very
reason. The only real "ticker"-like thing in the default set is the one
that saves the uptime (which of course *always* changes every call).
"on demand". Evennia itself uses hook methods for this very reason. The
only real "ticker"-like thing in the default set is the one that saves
the uptime (which of course *always* changes every call).
So, in summary, if you consider a ticker script that will fire very
often but which you expect to do nothing 99% of the time, ponder if you
can handle things some other way.
can handle things some other way. A self-reporting solution is usually
cheaper also for fast-updating properties. The main reason you do need a
ticker is rather when the timing itself is important.
Ticker example - night/day system
=================================
@ -91,24 +97,26 @@ list and calls a given method on the subscribed object.
This depends on your subscribing weather rooms defining the
``echo_daynight()`` method (presumably outputting some sort of message).
It's worth noting that this simple recipe can be used for all sorts of
tickers objects. Rooms are maybe not likely to unsubscribe very often,
but consider a mob that "deactivates" when Characters are not around for
It's worth noting that the simple recipe above can be used for all sorts
of tickers. Rooms are maybe not likely to unsubscribe very often, but
consider a mob that "deactivates" when Characters are not around for
example.
The above TimeTicker-example could be further optimized. All subscribed
rooms are after all likely to echo the same time related text. So this
text can be pre-set already at the Script level and echoed to each room
directly. This way the subscribed objects won't need a custom
``echo_daynight()`` method at all.
This particular TimeTicker-example could be further optimized. All
subscribed rooms are after all likely to echo the same time related
text. So this text can be pre-set already at the Script level and echoed
to each room directly. This way the subscribed objects won't need a
custom ``echo_daynight()`` method at all.
Here's the more efficient example (only showing the new stuff).
::
...
ECHOES = ["The sun rises in the east.", "It's mid-morning",
"It's mid-day", ...]
ECHOES = ["The sun rises in the east.",
"It's mid-morning",
"It's mid-day", ...]
class TimerTicker(Script):
...
def at_script_creation(self):

View file

@ -36,6 +36,8 @@ the `Developer Central <DeveloperCentral.html>`_.
- `Tutorial: Adding a Command prompt <CommandPrompt.html>`_
- `Tutorial: Creating a Zoning system <Zones.html>`_
- `Hints: Implementing cooldowns for commands <CommandCooldown.html>`_
- `Hints: Designing commands that take time to
finish <CommandDuration.html>`_
- `Hints: Ticker Scripts <TickerScripts.html>`_
Examples

File diff suppressed because one or more lines are too long

View file

@ -52,6 +52,8 @@ clear your database. Once you are done, you just rebuild it from scratch
as described in step 2 of the `Getting Started
guide <GettingStarted.html>`_.
First stop a running server with ``game/python evennia.py stop``.
If you run the default ``SQlite3`` database (to change this you need to
edit your ``settings.py`` file), the database is actually just a normal
file in ``game/`` called ``evennia.db3``. Simply delete that file -

View file

@ -22,17 +22,27 @@ Since it's not recommended to edit files in ``src/`` directly, we need
to devise a way to allow website customization from ``game/gamesrc``.
This is not really finalized at the current time (it will be easier to
share media directories in Django 1.3) so for now, your easiest course
of action is probably to copy the entire ``src/web`` directory into
``game/gamesrc/`` and modify the copy. Make sure to retain permissions
so the server can access the directory.
of action is as follows:
You also need to modify the settings file. Set ``ROOT_URLCONF`` to your
new ``game.gamesrc.web.urls`` and add an entry
`` os.path.join(GAME_DIR, "web", "templates", ACTIVE_TEMPLATE)`` to the
``TEMPLATE_DIRS`` tuple. You should now have a separate website setup
you can edit as you like. Be aware that updates we do to ``src/web``
will not transfer automatically to your copy, so you'll need to apply
updates manually.
#. Copy the entire ``src/web`` directory into ``game/gamesrc/`` and do
your modifications to the copy. Make sure to retain permissions so
the server can access the directory (in linux you can do this with
something like ``cp -ra src/web game/gamesrc/``)
#. Re-link all relevant path variables to the new location. In settings
add the following lines:
::
ROOT_URLCONF = "game.gamesrc.web.urls"
TEMPLATE_DIRS = (os.path.join(GAME_DIR, "gamesrc", "web", "templates", ACTIVE_TEMPLATE),)
MEDIA_ROOT = os.path.join(GAME_DIR, "gamesrc", "web", "media"`).
#. Reload the server (you want to also restart the Portal at this point
to make sure it picks up the new web location).
You should now have a separate website you can edit as you like. Be
aware that updates we do to ``src/web`` will not transfer automatically
to your copy, so you'll need to apply updates manually.
Web client
----------

View file

@ -49,9 +49,14 @@ suggestion:
#zonename|key
So say we (arbitrarily) divide our forest example into the zones
``magicforest`` and ``normalforest``. These are the added aliases we use
for the respective *Meadow* 's:
There is nothing special about this format; it's just a string we store
- a way to clump the zone-name and the room-key together in a "tag" we
can easily find and match against later. We could have used a format
like ``"zonename.key"`` or ``"ZONE:zonename,ROOMNAME:key"`` or some
other combination if we liked that better. So, using our suggested
format we assume we (arbitrarily) divide our forest example into the
zones ``magicforest`` and ``normalforest``. These are the added aliases
we use for the respective *Meadow* 's:
::
@ -67,8 +72,8 @@ with ``#zonename|``.
Enforcing zones
---------------
Maybe you feel that this usage of aliases for zones is somehow loose and
ad-hoc. It is, and there is no guarantee that a builder would follow the
Maybe you feel that this usage of aliases for zones is loose and ad-hoc.
It is indeed, and there is no guarantee that a builder would follow the
naming convention - unless you force them. And you can do that easily by
changing for example the ``@dig`` `Command <Commands.html>`_ to require
the zone to be given:
@ -112,13 +117,13 @@ group and organize only rooms with this scheme.
Using typeclasses and inheritance for zoning
--------------------------------------------
The above alias scheme is basically a way to easily find and group
objects together at run-time - a way to label, if you will. It doesn't
instill any sort of functional difference between a magical forest room
and a normal one. For this you will need to use Typeclasses. If you know
that a certain typeclass of room will always be in a certain zone you
could even hard-code the zone in the typeclass rather than enforce the
``@dig`` command to do it:
The aliasing system above doesn't instill any sort of functional
difference between a magical forest room and a normal one - it's just an
abitrary way to attach tags to objects for quick retrieval later. To
enforce differences you will need to use
`Typeclasses <Typeclasses.html>`_. If you know that a certain typeclass
of room will always be in a certain zone you could even hard-code the
zone in the typeclass rather than enforce the ``@dig`` command to do it:
::

View file

@ -1,8 +1,8 @@
#! /usr/bin/python
# /usr/bin/python
#
# Auto-generate reST documentation for Sphinx from Evennia source
# code.
#
#
# Uses etinenned's sphinx autopackage script. Install it to folder
# "autogen" in this same directory:
#
@ -34,21 +34,21 @@ AUTOGEN_EXE = os.path.join(CONVERT_DIR, os.path.join("autogen", "generate_module
def src2rest():
"""
Run import
Run import
"""
try:
shutil.rmtree(SPHINX_CODE_DIR)
print "Emptied old %s." % SPHINX_CODE_DIR
except OSError:
pass
pass
os.mkdir(SPHINX_CODE_DIR)
inpath = EVENNIA_DIR
outpath = SPHINX_CODE_DIR
excludes = [r".*/migrations/.*", r"evennia\.py$", r"manage\.py$",
excludes = [r".*/migrations/.*", r"evennia\.py$", r"manage\.py$",
r"runner\.py$", r"server.py$", r"portal.py$"]
subprocess.call(["python", AUTOGEN_EXE,
subprocess.call(["python", AUTOGEN_EXE,
"-n", "Evennia",
"-d", outpath,
"-s", "rst",

View file

@ -290,9 +290,9 @@ def GoogleCode_PrettyLink(wikifier, lookaheadRegExp=None, **kwargs):
lookMatch = lookaheadRegExp.search(wikifier.source, wikifier.matchStart)
if lookMatch and lookMatch.start() == wikifier.matchStart:
text = lookMatch.group(1)
link = text
if lookMatch.group(2):
# Pretty bracketted link
link = text
text = lookMatch.group(2)
if GoogleCode_IsExternalLink(wikifier, link):
# External link