Updated ReST documentation.

This commit is contained in:
Griatch 2012-05-01 17:37:37 +02:00
parent 36b15b4ad8
commit a8139feb1a
37 changed files with 963 additions and 910 deletions

View file

@ -37,9 +37,9 @@ mod\_wsgi Setup
Install mod\_wsgi
~~~~~~~~~~~~~~~~~
mod*wsgi is an excellent, secure, and high-performance way to serve
mod\ *wsgi is an excellent, secure, and high-performance way to serve
Python projects. Code reloading is a breeze, Python modules are executed
as a user of your choice (which is a great security win), and mod*wsgi
as a user of your choice (which is a great security win), and mod*\ wsgi
is easy to set up on most distributions.
For the sake of brevity, this guide will refer you to mod\_wsgi's
@ -50,10 +50,10 @@ Ubuntu, you may install the entire stack with the following command:
``sudo aptitude install libapache2-mod-wsgi``
This should install apache2 (if it isn't already), mod*wsgi, and load
This should install apache2 (if it isn't already), mod\ *wsgi, and load
the module. On Fedora or CentOS, you'll do this with ``yum`` and a
similar package name that you'll need to search for. On Windows, you'll
need to download and install apache2 and mod*wsgi binaries.
need to download and install apache2 and mod*\ wsgi binaries.
Copy and modify the VHOST
~~~~~~~~~~~~~~~~~~~~~~~~~
@ -88,12 +88,13 @@ site <http://evennia.com>`_.
A note on code reloading
~~~~~~~~~~~~~~~~~~~~~~~~
If your mod*wsgi is set up to run on daemon mode (as will be the case by
default on Debian and Ubuntu), you may tell mod*wsgi to reload by using
the ``touch`` command on ``evennia/game/web/utils/apache_wsgi.conf``.
When mod\_wsgi sees that the file modification time has changed, it will
force a code reload. Any modifications to the code will not be
propagated to the live instance of your site until reloaded.
If your mod\ *wsgi is set up to run on daemon mode (as will be the case
by default on Debian and Ubuntu), you may tell mod*\ wsgi to reload by
using the ``touch`` command on
``evennia/game/web/utils/apache_wsgi.conf``. When mod\_wsgi sees that
the file modification time has changed, it will force a code reload. Any
modifications to the code will not be propagated to the live instance of
your site until reloaded.
If you are not running in daemon mode or want to force the issue, simply
restart or reload apache2 to apply your changes.

View file

@ -43,7 +43,7 @@ use of the ``run_async()`` function in ``src/utils/utils.py``.
::
from src.utils import utils print "before call ..." utils.run_async(long_running_function) print "after call ..."
from ev import utils print "before call ..." utils.run_async(long_running_function) print "after call ..."
Now, when running this you will find that the program will not wait
around for ``long_running_function`` to finish. Infact you will see
@ -93,7 +93,7 @@ An example of making an asynchronous call from inside a
::
from src.utils import utils from game.gamesrc.commands.basecommand import Command class CmdAsync(Command): key = "asynccommand" def func(self): def long_running_function(): #[... lots of time-consuming code return final_value def at_return(r): self.caller.msg("The final value is %s" % r) def at_err(e): self.caller.msg("There was an error: %s" % e) # do the async call, setting all callbacks utils.run_async(long_running_function, at_return, at_err)
from ev import utils from game.gamesrc.commands.basecommand import Command class CmdAsync(Command): key = "asynccommand" def func(self): def long_running_function(): #[... lots of time-consuming code return final_value def at_return(r): self.caller.msg("The final value is %s" % r) def at_err(e): self.caller.msg("There was an error: %s" % e) # do the async call, setting all callbacks utils.run_async(long_running_function, at_return, at_err)
That's it - from here on we can forget about ``long_running_function``
and go on with what else need to be done. *Whenever* it finishes, the

View file

@ -24,25 +24,25 @@ Saving and Retrieving data
--------------------------
To save persistent data on a Typeclassed object you normally use the
``db`` operator. Let's try to save some data to a *Rose* (an
``db`` (!DataBase) operator. Let's try to save some data to a *Rose* (an
`Object <Objects.html>`_):
::
# saving rose.db.has_thorns = True # getting it back is_ouch = rose.db.has_thorns
# saving rose.db.has_thorns = True # getting it back is_ouch = rose.db.has_thorns
This looks like any normal Python assignment, but that ``db`` makes sure
that an *Attribute* is created behind the scenes and is stored in the
database. Your rose will continue to have thorns throughout the life of
the server now, until you deliberately remove them.
To be sure to save **non-persistently**, i.e. to make sure NOT create a
database entry, you use ``ndb`` (!NonDataBase). It works in the same
To be sure to save **non-persistently**, i.e. to make sure NOT to create
a database entry, you use ``ndb`` (!NonDataBase). It works in the same
way:
::
# saving rose.ndb.has_thorns = True # getting it back is_ouch = rose.ndb.has_thorns
# saving rose.ndb.has_thorns = True # getting it back is_ouch = rose.ndb.has_thorns
Strictly speaking, ``ndb`` has nothing to do with ``Attributes``,
despite how similar they look. No ``Attribute`` object is created behind
@ -56,28 +56,52 @@ will for example delete an ``Attribute``:
del rose.db.has_thorns
Fast assignment
---------------
For quick testing you can most often skip the ``db`` operator and assign
Attributes like you would any normal Python property:
Both ``db`` and ``ndb`` defaults to offering an ``all`` property on
themselves. This returns all associated attributes or non-persistent
properties.
::
# saving rose.has_thorns = True# getting it back is_ouch = rose.has_thorns
list_of_all_rose_attributes = rose.db.all list_of_all_rose_ndb_attrs = rose.ndb.all
If you use ``all`` as the name of an attribute, this will be used
instead. Later deleting your custom ``all`` will return the default
behaviour.
Fast assignment
---------------
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.
``rose.msg()`` is for example an already defined method for sending
messages. Doing ``rose.msg = "Ouch"`` will overload the method with a
string and will create all sorts of trouble down the road (the engine
uses ``msg()`` a lot to send text to you). Using
``rose.db.msg = "Ouch"`` will always do what you expect and is usually
the safer bet. And it also makes it visually clear at all times when you
are saving to the database and not.
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``
@ -97,32 +121,33 @@ is, you don't have to. Most of the time you really want to save as much
as you possibly can. Non-persistent data is potentially useful in a few
situations though.
- You are worried about database performance. Maybe you are
reading/storing data many times a second (for whatever reason) or you
have many players doing things at the same time. Hitting the database
over and over might not be ideal in that case. Non-persistent data
simply writes to memory, it doesn't hit the database at all. It
should be said that with the speed and quality of hardware these
days, this point is less likely to be of any big concern except for
the most extreme of situations. Modern database systems cache data
very efficiently for speed. Our default database even runs completely
in RAM if possible, alleviating much of the need to write to disk
during heavy loads.
- You *want* to loose your state when logging off. Maybe you are
testing a buggy `Script <Scripts.html>`_ that does potentially
harmful stuff to your character object. With non-persistent storage
you can be sure that whatever the script messes up, it's nothing a
server reboot can't clear up.
- You are worried about database performance. Since Evennia caches
Attributes very aggressively, this is not an issue unless you are
reading *and* writing to your Attribute very often (like many times
per second). Reading from an already cached Attribute is as fast as
reading any Python property. But even then this is not likely
something to worry about: Apart from Evennia's own caching, modern
database systems themselves also cache data very efficiently for
speed. Our default database even runs completely in RAM if possible,
alleviating much of the need to write to disk during heavy loads.
- A more valid reason for using non-persistent data is if you *want* to
loose your state when logging off. Maybe you are storing throw-away
data that are re-initialized at server startup. Maybe you are
implementing some caching of your own. Or maybe you are testing a
buggy `Script <Scripts.html>`_ that does potentially harmful stuff to
your character object. With non-persistent storage you can be sure
that whatever is messed up, it's nothing a server reboot can't clear
up.
- You want to implement a fully or partly *non-persistent world*. Who
are we to argue with your grand vision!
What types of data can I save?
------------------------------
What types of data can I save in an Attribute?
----------------------------------------------
If you store a single object (that is, not a iterable list of objects),
If you store a single object (that is, not an iterable list of objects),
you can practically store any Python object that can be
`pickled <http://docs.python.org/library/pickle.html>`_. Evennia uses
the ``pickle`` module to serialize data into the database.
the ``pickle`` module to serialize Attribute data into the database.
There is one notable type of object that cannot be pickled - and that is
a Django database object. These will instead be stored as a wrapper
@ -132,7 +157,7 @@ accessed. Since erroneously trying to save database objects in an
Attribute will lead to errors, Evennia will try to detect database
objects by analyzing the data being stored. This means that Evennia must
recursively traverse all iterables to make sure all database objects in
them are stored safely. So for efficiency, it can be a good idea is to
them are stored safely. So for efficiency, it can be a good idea to
avoid deeply nested lists with objects if you can.
To store several objects, you may only use python *lists*,
@ -146,13 +171,14 @@ usually not a limitation you need to worry about.
custom, non-iterable classes and stored database objects in them. So to
make this clear - saving such an object is **not supported** and will
probably make your game unstable. Store your database objects using
lists, dictionaries or a combination of the two and you should be fine.*
lists, tuples, dictionaries or a combination of the three and you should
be fine.*
Examples of valid attribute data:
::
# a single value obj.db.test1 = 23 obj.db.test1 = False # a database object (will be stored as dbref) obj.db.test2 = myobj # a list of objects obj.db.test3 = [obj1, 45, obj2, 67] # a dictionary obj.db.test4 = 'str':34, 'dex':56, 'agi':22, 'int':77 # a mixed dictionary/list obj.db.test5 = 'members': [obj1,obj2,obj3], 'enemies':[obj4,obj5] # a tuple with a list in it obj.db.test6 = (1,3,4,8, ["test", "test2"], 9) # a set will still be stored and returned as a list [1,2,3,4,5]! obj.db.test7 = set([1,2,3,4,5])
# a single value obj.db.test1 = 23 obj.db.test1 = False # a database object (will be stored as dbref) obj.db.test2 = myobj # a list of objects obj.db.test3 = [obj1, 45, obj2, 67] # a dictionary obj.db.test4 = 'str':34, 'dex':56, 'agi':22, 'int':77 # a mixed dictionary/list obj.db.test5 = 'members': [obj1,obj2,obj3], 'enemies':[obj4,obj5] # a tuple with a list in it obj.db.test6 = (1,3,4,8, ["test", "test2"], 9) # a set will still be stored and returned as a list [1,2,3,4,5]! obj.db.test7 = set([1,2,3,4,5]) # in-situ manipulation obj.db.test8 = [1,2,"test":1] obj.db.test8[0] = 4 obj.db.test8[2]["test"] = 5 # test8 is now [4,2,"test":5]
Example of non-supported save:
@ -164,21 +190,44 @@ Retrieving Mutable objects
--------------------------
A side effect of the way Evennia stores Attributes is that Python Lists
and Dictionaries (only )are handled by custom objects called PackedLists
and !PackedDicts. These have the special property that they save to the
database whenever new data gets assigned to them. This allows you to do
things like self.db.mylist`4 <4.html>`_
val without having to extract the mylist Attribute into a temporary
variable first.
and Dictionaries (only) are handled by custom objects called PackedLists
and !PackedDicts. These behave just like normal lists and dicts except
they have the special property that they save to the database whenever
new data gets assigned to them. This allows you to do things like
``self.db.mylist[4]`` = val without having to extract the mylist
Attribute into a temporary variable first.
There is however an important thing to remember. If you retrieve this
data into another variable, e.g. ``mylist2 = obj.db.mylist``, your new
variable will *still* be a PackedList, and if you assign things to it,
it will save to the database! To "disconnect" it from the database
system, you need to convert it to a normal list with mylist2
variable (``mylist2``) will *still* be a !PackedList! This means it will
continue to save itself to the database whenever it is updated! This is
important to keep in mind so you are not confused by the results.
list(mylist2).
::
obj.db.mylist = [1,2,3,4] mylist = obj.db.mylist mylist[3] = 5 # this will also update database print mylist # this is now [1,2,3,5] print mylist.db.mylist # this is also [1,2,3,5]
To "disconnect" your extracted mutable variable from the database you
simply need to convert the PackedList or PackedDict to a normal Python
list or dictionary. This is done with the builtin ``list()`` and
``dict()`` functions. In the case of "nested" lists and dicts, you only
have to convert the "outermost" list/dict in order to cut the entire
structure's connection to the database.
::
obj.db.mylist = [1,2,3,4] mylist = list(obj.db.mylist) # convert to normal list mylist[3] = 5 print mylist # this is now [1,2,3,5] print obj.db.mylist # this remains [1,2,3,4]
Remember, this is only valid for mutable iterables - lists and dicts and
combinations of the two.
`Immutable <http://en.wikipedia.org/wiki/Immutable>`_ objects (strings,
numbers, tuples etc) are already disconnected from the database from the
onset. So making the outermost iterable into a tuple is also a way to
stop any changes to the structure from updating the database.
::
obj.db.mytup = (1,2,[3,4]) obj.db.mytup[0] = 5 # this fails since tuples are immutable obj.db.mytup[2][1] = 5 # this works but will NOT update database since outermost iterable is a tuple print obj.db.mytup[2][1] # this still returns 4, not 5 mytup1 = obj.db.mytup # mytup1 is already disconnected from database since outermost # iterable is a tuple, so we can edit the internal list as we want # without affecting the database.
Notes
-----

View file

@ -16,7 +16,7 @@ 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
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
@ -61,10 +61,15 @@ Here are the rules of syntax of the batch-command ``*.py`` file.
``obj1, obj2, ...`` parts are optional object labels used by the
processor's *debug* mode in order to auto-delete objects after a test
run.
- A new ``#HEADER`` or ``#CODE`` (or the end of the file) ends the
previous block. Text before the first block are ignored.
- A ``#`` that is not starting a ``#HEADER`` or ``#CODE`` block is
considered a comment.
- ``#INSERT path.filename`` as the first on a line loads the contents
of another batch-code file into this one. Its ``#CODE`` blocks will
be executed as if they were defined in this file, but they will not
share ``#HEADER``\ s with the current file, but only use its own, if
any.
- A new ``#HEADER``, ``#CODE`` or ``#INSERT`` (or the end of the file)
ends a previous block. Text before the first block are ignored.
- A ``#`` that is not starting a ``#HEADER``, ``#CODE`` or ``#INSERT``
instruction is considered a comment.
- Inside a block, normal Python syntax rules apply. For the sake of
indentation, each block acts as a separate python module.
- The variable ``caller`` is always made available to the script,
@ -77,7 +82,7 @@ Below is a version of the example file found in
#
# This is an example batch-code build file for Evennia.
##HEADER# This will be included in all other #CODE blocksfrom src.utils import create, search from game.gamesrc.objects.examples import red_button from game.gamesrc.objects import baseobjectslimbo = search.objects(caller, 'Limbo', global_search=True)[0]#CODE (create red button)red_button = create.create_object(red_button.RedButton, key="Red button", location=limbo, aliases=["button"])# caller points to the one running the script caller.msg("A red button was created.")#CODE (create table and chair) table, chairtable = create.create_object(baseobjects.Object, key="Blue Table", location=limbo) chair = create.create_object(baseobjects.Object, key="Blue Chair", location=limbo)string = "A %s and %s were created. If debug was active, they were deleted again." caller.msg(string % (table, chair))
##HEADER# This will be included in all other #CODE blocksfrom src.utils import create, search from game.gamesrc.objects.examples import red_button from game.gamesrc.objects import baseobjectslimbo = search.objects(caller, 'Limbo', global_search=True)[0]#CODE (create red button)red_button = create.create_object(red_button.RedButton, key="Red button", location=limbo, aliases=["button"])# caller points to the one running the script caller.msg("A red button was created.")# importing more code from another batch-code file #INSERT examples.batch_code_insert#CODE (create table and chair) table, chairtable = create.create_object(baseobjects.Object, key="Blue Table", location=limbo) chair = create.create_object(baseobjects.Object, key="Blue Chair", location=limbo)string = "A %s and %s were created. If debug was active, they were deleted again." caller.msg(string % (table, chair))
This uses Evennia's Python API to create three objects in sequence.

View file

@ -16,7 +16,7 @@ The batch-command processor is a superuser-only function, invoked by
> @batchcommand path.to.batchcmdfile
Where ``path.to.batchcmdfile`` is the path to a *batch-command file*
with the "``.ev``" file ending. This path is given like a python path
with the "``.ev``\ " file ending. This path is given like a python path
relative to a folder you define to hold your batch files, set with
``BATCH_IMPORT_PATH`` in your settings. Default folder is
``game/gamesrc/world``. So if you want to run the example batch file in
@ -52,6 +52,11 @@ really, really simple:
after one another in the file - separate them with a comment, or the
second of the two will be considered an argument to the first one.
Besides, using plenty of comments is good practice anyway.
- A line that starts with the word ``#INSERT`` is a comment line but
also signifies a special instruction. The syntax is
``#INSERT <path.batchfile>`` and tries to import a given batch-cmd
file into this one. The inserted batch file (file ending ``.ev``)
will run normally from the point of the ``#INSERT`` instruction.
- Extra whitespace in a command definition is *ignored*.
- A completely empty line translates in to a line break in texts. Two
empty lines thus means a new paragraph (this is obviously only
@ -59,13 +64,18 @@ really, really simple:
``@desc`` command).
- The very last command in the file is not required to end with a
comment.
- You *cannot* nest another ``@batchcommand`` statement into your batch
file. If you want to link many batch-files together, use the
``#INSERT`` batch instruction instead. You also cannot launch the
``@batchcode`` command from your batch file, the two batch processors
are not compatible.
Below is a version of the example file found in
``game/gamesrc/commands/examples/batch_cmds.ev``.
::
# # This is an example batch build file for Evennia. ## This creates a red button @create button:examples.red_button.RedButton # (This comment ends input for @create) # Next command. Let's create something. @set button/desc = This is a large red button. Now and then it flashes in an evil, yet strangely tantalizing way. A big sign sits next to it. It says:----------- Press me! ----------- ... It really begs to be pressed! You know you want to! # (This ends the @set command). Note that single line breaks # and extra whitespace in the argument are ignored. Empty lines # translate into line breaks in the output. # Now let's place the button where it belongs (let's say limbo #2 is # the evil lair in our example) @teleport #2 # (This comments ends the @teleport command.) # Now we drop it so others can see it. # The very last command in the file needs not be ended with #. drop button
# # This is an example batch build file for Evennia. ## This creates a red button @create button:examples.red_button.RedButton # (This comment ends input for @create) # Next command. Let's create something. @set button/desc = This is a large red button. Now and then it flashes in an evil, yet strangely tantalizing way. A big sign sits next to it. It says:----------- Press me! ----------- ... It really begs to be pressed! You know you want to! # This inserts the commands from another batch-cmd file named # batch_insert_file.ev. #INSERT examples.batch_insert_file # (This ends the @set command). Note that single line breaks # and extra whitespace in the argument are ignored. Empty lines # translate into line breaks in the output. # Now let's place the button where it belongs (let's say limbo #2 is # the evil lair in our example) @teleport #2 # (This comments ends the @teleport command.) # Now we drop it so others can see it. # The very last command in the file needs not be ended with #. drop button
To test this, run ``@batchcommand`` on the file. A button will be
created, described and dropped in Limbo. All commands will be executed

View file

@ -37,17 +37,20 @@ 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.
Log off and choose ``create`` from the login screen. Create a new
account (don't log in). Let's say we call the new account "Anna". Next
log in as your superuser account and give the recently created player
build rights:
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:
::
@perm Anna = Builders
That should do it. Log out again (``@quit``) and finally log back in as
your builder account.
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.
Creating an object
------------------
@ -129,8 +132,8 @@ and try to get the box now:
Think the default error message looks dull? The ``get`` command looks
for an `Attribute <Attributes.html>`_ named ``get_err_msg`` for
returning a nicer error message (we just happen to know this, you would
currently need to peek into the code for the ``get`` command to find
out. You set attributes using the ``@set`` command:
need to peek into the code for the ``get`` command to find out). You set
attributes using the ``@set`` command:
::
@ -185,11 +188,10 @@ object-based `Commands <Commands.html>`_, you could expand it and other
items to be as unique, complex and interactive as you want.
Let's take an example. So far we have only created objects that use the
default object typeclass found in
``game/gamesrc/objects/baseobjects.py``. It is called simply *Object*.
Let's create an object that is a little more interesting. Under
``game/gamesrc/objects/`` there is a directory ``examples`` with a
module ``red_button.py``. It contains the enigmatic RedButton typeclass.
default object typeclass named simply ``Object``. Let's create an object
that is a little more interesting. Under ``game/gamesrc/objects/`` there
is a directory ``examples`` with a module ``red_button.py``. It contains
the enigmatic RedButton typeclass.
Let's make us one of *those*!

View file

@ -22,8 +22,8 @@ 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 be the best choice. This is due to the possibility of
clashes with file-locking when using SQLite from more than one process.
probably not the best choice. This is due to the possibility of clashes
with file-locking when using SQLite from more than one process.
Postgres
--------

View file

@ -37,8 +37,7 @@ Defining a Command
------------------
All commands are implemented as normal Python classes inheriting from
the base class ``Command``
(``game.gamesrc.commands.basecommand.Command``). You will find that this
the base class ``Command`` (``ev.Command``). You will find that this
base class is very "bare". The default commands of Evennia actually
inherit from a child of ``Command`` called ``MuxCommand`` - this is the
class that knows all the mux-like syntax like ``/switches``, splitting
@ -48,7 +47,7 @@ class directly.
::
# basic Command definition
from game.gamesrc.commands.basecommand import Command
from ev import Command
class MyCmd(Command):
"""
This is the help-text for the command
@ -86,18 +85,18 @@ assigns it the following properties:
*Player* object (usually used only when a Player has no character
assigned to them, like when creating a new one).
- ``cmdstring`` - the matched key for the command. This would be
"``look``" in our example.
"``look``\ " in our example.
- ``args`` - this is the rest of the string, except the command name.
So if the string entered was ``look at sword``, ``args`` would simply
be "``at sword``".
be "``at sword``\ ".
- ``obj`` - the game `Object <Objects.html>`_ on which this command is
defined. This need not be the caller, but since ``look`` is a common
(default) command, this is probably defined directly on *!BigGuy* -
so ``obj`` will point to !BigGuy. Otherwise ``obj`` could be any
interactive object with commands defined on it, like in the example
of the "check time" command defined on a "Clock" object or a `red
button <https://code.google.com/p/evennia/source/browse/trunk/game/gamesrc/objects/examples/red%3Ci%3Ebutton.py.html>`_
that you can "``push``".
button <https://code.google.com/p/evennia/source/browse/trunk/game/gamesrc/objects/examples/red<i>button.py.html>`_
that you can "``push``\ ".
- ``cmdset`` - this is a reference to the merged CmdSet (see below)
from which this command was matched. This variable is rarely used,
it's main use is for the `auto-help system <HelpSystem.html>`_
@ -113,9 +112,7 @@ Beyond the properties Evennia always assigns to the command at runtime
- ``key`` (string) - the identifier for the command, like ``look``.
This should (ideally) be unique. it can be more than one word long in
a string, like "press button". Maximum number of space-separated
words that can be part of a command name is given by
``settings.CMD_MAXLEN``.
a string, like "press button" or "pull lever left".
- ``aliases`` (optional list) - a list of alternate names for the
command (``["l", "glance", "see"]``). Same name rules as for ``key``
applies.
@ -131,10 +128,10 @@ Beyond the properties Evennia always assigns to the command at runtime
to it) will be stored by the system and can be accessed by the next
command called by retrieving ``self.caller.ndb.last_cmd``. The next
run command will either clear or replace the storage.
- 'arg*regex' (optional raw string): This should be given as a `raw
- 'arg\ *regex' (optional raw string): This should be given as a `raw
regular expression string <http://docs.python.org/library/re.html>`_.
This will be compiled by the system at runtime. This allows you to
customize how the part*immediately following the command name (or
customize how the part*\ immediately following the command name (or
alias) must look in order for the parser to match for this command.
Normally the parser is highly efficient in picking out the command
name, also as the beginning of a longer word (as long as the longer
@ -147,7 +144,7 @@ Beyond the properties Evennia always assigns to the command at runtime
expected.
- autohelp (optional boolean). Defaults to ``True``. This allows for
turning off the `auto-help
system <HelpSystem#Command%3Ci%3EAuto-help%3C/i%3Esystem.html>`_ on a
system <HelpSystem#Command<i>Auto-help</i>system.html>`_ on a
per-command basis. This could be useful if you either want to write
your help entries manually or hide the existence of a command from
``help``'s generated list.
@ -173,11 +170,11 @@ by the `Help system <HelpSystem.html>`_ to create the help entry for
this command. You should decide on a way to format your help and stick
to that.
Below is how you define a simple alternative "``look at``" command:
Below is how you define a simple alternative "``look at``\ " command:
::
from game.gamesrc.commands.basecommand import Commandclass CmdLookAt(Command): """ An alternative (and silly) look command Usage: look at <what> Where <what> may only be 'here' in this example. This initial string (the __doc__ string) is also used to auto-generate the help for this command ... """ key = "look at" # this is the command name to use aliases = ["la", "look a"] # aliases to the command name locks = "cmd:all()" help_category = "General" def parse(self): "Very trivial parser" self.what = self.args.strip() def func(self): "This actually does things" caller = self.caller if not self.what: caller.msg("Look at what?") elif self.what == 'here': # look at the current location description = caller.location.db.desc caller.msg(description) else: # we don't add any more functionality in this example caller.msg("Sorry, you can only look 'here'...")
from ev import Commandclass CmdLookAt(Command): """ An alternative (and silly) look command Usage: look at <what> Where <what> may only be 'here' in this example. This initial string (the __doc__ string) is also used to auto-generate the help for this command ... """ key = "look at" # this is the command name to use aliases = ["la", "look a"] # aliases to the command name locks = "cmd:all()" help_category = "General" def parse(self): "Very trivial parser" self.what = self.args.strip() def func(self): "This actually does things" caller = self.caller if not self.what: caller.msg("Look at what?") elif self.what == 'here': # look at the current location description = caller.location.db.desc caller.msg(description) else: # we don't add any more functionality in this example caller.msg("Sorry, you can only look 'here'...")
The power of having commands as classes and to separate ``parse()`` and
``func()`` lies in the ability to inherit functionality without having
@ -201,7 +198,7 @@ number of different !CmdSets. CmdSets can be stored on game
When a user issues a command, it is matched against the contents of all
cmdsets available at the time, `merged
together <Commands#Adding%3Ci%3Eand%3C/i%3Emerging%3Ci%3Ecommand%3C/i%3Esets.html>`_.
together <Commands#Adding<i>and</i>merging<i>command</i>sets.html>`_.
The currently valid command sets are collected from the following
sources, in this order:
@ -217,24 +214,25 @@ The default ``CmdSet`` shipping with Evennia is automatically added to
all new characters and contains commands such as ``look``, ``drop``,
``@dig`` etc. You can find it defined in
``src/commands/default/cmdset_default.py``, but it is also referenced by
``game/gamesrc/commands/basecmdset.py``. Players have an
Out-of-character cmdset called ``cmdset_ooc`` that can also be found
from the same place. There is finally an "unloggedin" cmdset that is
used before the Player has authenticated to the game. The path to these
three standard command sets are defined in settings, as
``CMDSET_UNLOGGEDIN``, ``CMDSET_DEFAULT`` and ``CMDSET_OOC``. You can
create any number of command sets besides those to fit your needs.
importing ``ev.default_cmds`` and accessing its property
``DefaultCmdset``. Players have an Out-of-character cmdset called
``cmdset_ooc`` that can also be found from the same place. There is
finally an "unloggedin" cmdset that is used before the Player has
authenticated to the game. The path to these three standard command sets
are defined in settings, as ``CMDSET_UNLOGGEDIN``, ``CMDSET_DEFAULT``
and ``CMDSET_OOC``. You can create any number of command sets besides
those to fit your needs.
A CmdSet is, as most things in Evennia, defined as a Python class
inheriting from the correct parent (``src.commands.cmdset.CmdSet``). The
CmdSet class only needs to define one method, called
``at_cmdset_creation()``. All other class parameters are optional, but
are used for more advanced set manipulation and coding (see the `merge
rules <Commands#Merge_rules.html>`_ section).
inheriting from the correct parent (``ev.CmdSet`` or
``src.commands.cmdset.CmdSet``). The CmdSet class only needs to define
one method, called ``at_cmdset_creation()``. All other class parameters
are optional, but are used for more advanced set manipulation and coding
(see the `merge rules <Commands#Merge_rules.html>`_ section).
::
from src.commands.cmdset import CmdSet from game.gamesrc.commands import mycommandsclass MyCmdSet(CmdSet): def at_cmdset_creation(self): """ The only thing this method should need to do is to add commands to the set. """ self.add(mycommands.MyCommand1()) self.add(mycommands.MyCommand2()) self.add(mycommands.MyCommand3())
from ev import CmdSet from game.gamesrc.commands import mycommands class MyCmdSet(CmdSet): def at_cmdset_creation(self): """ The only thing this method should need to do is to add commands to the set. """ self.add(mycommands.MyCommand1()) self.add(mycommands.MyCommand2()) self.add(mycommands.MyCommand3())
The !CmdSet's ``add()`` method can also take another CmdSet as input. In
this case all the commands from that CmdSet will be appended to this one
@ -271,7 +269,7 @@ server, or you run
@py self.cmdset.delete('game.gamesrc.commands.mycmdset.MyCmdSet')
For more permanent addition, read the `step-by-step
guide <Commands#Adding%3Ci%3Ea%3C/i%3Enew%3Ci%3Ecommand%3C/i%3E-%3Ci%3Ea%3C/i%3Estep%3Ci%3Eby%3C/i%3Estep_guide.html>`_
guide <Commands#Adding<i>a</i>new<i>command</i>-<i>a</i>step<i>by</i>step_guide.html>`_
below. Generally you can customize which command sets are added to your
objects by using ``self.cmdset.add()`` or ``self.cmdset.add_default()``.
@ -283,36 +281,36 @@ assume you have just downloaded Evennia and wants to try to add a new
command to use. This is the way to do it.
#. In ``game/gamesrc/commands``, create a new module. Name it, say,
``mycommand.py``.
#. Import ``game.gamesrc.commands.basecommands.MuxCommand`` (this is a
convenient shortcut so you don't have to import from src/ directly).
The ``MuxCommand`` class handles command line parsing for you, giving
you stuff like /switches, the syntax using '=' etc). In other words,
you don't have to implement ``parse()`` on your own.
``mycommand.py``. Copy from the templates in ``examples/`` if you
like.
#. Import ``ev.default_cmds`` and access ``MuxCommand`` from that (this
is a convenient shortcut so you don't have to import from src/
directly). The ``MuxCommand`` class handles command line parsing for
you, giving you stuff like /switches, the syntax using '=' etc). In
other words, you don't have to implement ``parse()`` on your own.
#. Create a new class in ``mycommand`` that inherits from
``MuxCommand``.
#. Set the class variable ``key`` to the name to call your command with,
say ``mycommand``.
#. Set the ``locks`` property on the command to a suitable
`lockstring <Locks#Defining%3Ci%3Elocks.html>`_. If you are unsure,
use "cmd:all()".
`lockstring <Locks#Defining<i>locks.html>`_. If you are unsure, use
"cmd:all()".
#. Define a class method ``func()`` that does stuff. See below.
#. Give your class a useful *doc*\_ string, this acts as the help entry
for the command.
#. Give your class a useful *doc*\ \_ string, this acts as the help
entry for the command.
Your command definition is now ready. Here's an example of how it could
look:
::
from game.gamesrc.commands.basecommand import MuxCommandclass MyCommand(MuxCommand): """ Simple command example Usage: mycommand <text> This command simply echoes text back to the caller. (this string is also the help text for the command) """ key = "mycommand" locks = "cmd:all()" def func(self): "This actually does things" if not self.args: self.caller.msg("You didn't enter anything!") else: self.caller.msg("You gave the string: '%s'" % self.args)
from ev import default_cmdsclass MyCommand(default_cmds.MuxCommand): """ Simple command example Usage: mycommand <text> This command simply echoes text back to the caller. (this string is also the help text for the command) """ key = "mycommand" locks = "cmd:all()" def func(self): "This actually does things" if not self.args: self.caller.msg("You didn't enter anything!") else: self.caller.msg("You gave the string: '%s'" % self.args)
Next we want to make this command available to us. There are many ways
to do this, but all of them involves putting this command in a *Command
Set*. First, let's try the more involved way.
#. Create a class that inherits from
``game.gamesrc.commands.basecmdset.CmdSet``.
#. Create a class that inherits from ``ev.CmdSet``.
#. (Optionally) set a key to name your command set.
#. Add a method ``at_cmdset_creation()`` and use the ``self.add()``
method to add your command to the command set.
@ -321,7 +319,7 @@ This is what we have now:
::
from game.gamesrc.commands.basecmdset import CmdSet
from ev import CmdSet
from game.gamesrc.commands import mycommandclass MyCmdSet(CmdSet): key = "MyCmdSet" def at_cmdset_creation(self): self.add(mycommand.MyCommand())
This new command set could of course contain any number of commands. We
@ -379,14 +377,16 @@ will be loaded every server start along with all the other default
commands.
The default command set is found in
``src/commands/default/cmdset_default.py`` but there is already a
shortcut to it in ``gamesrc/commands/basecmdset.py`` called
``DefaultCmdSet``. Add your command to the end of the ``DefaultSet``
class and you will in fact append it to the existing command set.
``src/commands/default/cmdset_default.py`` but the template in
``gamesrc/commands/examples/`` already shows how to extend it. Copy that
file to ``game/gamesrc/`` and edit ``settings.CMDSET_DEFAULT`` to point
to this class instead. Next you add your new commands to the end of the
Default Cmdset in that file and you will in fact append it to the
existing command set.
::
# file gamesrc/commands/basecmdset.py ... from game.gamesrc.commands import mycommandclass DefaultSet(BaseDefaultSet): key = DefaultMUX def at_cmdset_creation(self): # this first adds all default commands super(DefaultSet, self).at_cmdset_creation() # all commands added after this point will extend or # overwrite the default commands. self.add(mycommand.MyCommand())
# file gamesrc/commands/examples/cmdset.py ... from game.gamesrc.commands import mycommandclass DefaultSet(BaseDefaultSet): key = DefaultMUX def at_cmdset_creation(self): # this first adds all default commands super(DefaultSet, self).at_cmdset_creation() # all commands added after this point will extend or # overwrite the default commands. self.add(mycommand.MyCommand())
Again, you need to run the ``@reload`` command to make these changes
available.
@ -401,7 +401,7 @@ make sure to set your new command's ``key`` variable to ``look`` as
well.
If you want to expand/build on the original command, just copy&paste its
command class from ``src/commands/default``(the ``look`` class is for
command class from ``src/commands/default``\ (the ``look`` class is for
example found in ``src/commands/default/general.py``) into
``game/gamesrc/commands`` and edit it there.
@ -505,23 +505,24 @@ high-prio one as a template.
Besides ``priority`` and ``mergetype``, a command set also takes a few
other variables to control how they merge:
- *allow*duplicates*(bool) - determines what happens when two sets of
equal priority merge. Default is that the new set in the merger (i.e.
**A** above) automatically takes precedence. But if*allow*duplicates*
is true, the result will be a merger with more than one of each name
match. This will usually lead to the player receiving a
multiple-match error higher up the road, but can be good for things
like cmdsets on non-player objects in a room, to allow the system to
warn that more than one 'ball' in the room has the same 'kick'
command defined on it, so it may offer a chance to select which ball
to kick ... Allowing duplicates only makes sense for *Union* and
*Intersect*, the setting is ignored for the other mergetypes.
- *key*mergetype*(dict) - allows the cmdset to define a unique
- *allow*\ duplicates\ *(bool) - determines what happens when two sets
of equal priority merge. Default is that the new set in the merger
(i.e. **A** above) automatically takes precedence. But
if*\ allow\ *duplicates* is true, the result will be a merger with
more than one of each name match. This will usually lead to the
player receiving a multiple-match error higher up the road, but can
be good for things like cmdsets on non-player objects in a room, to
allow the system to warn that more than one 'ball' in the room has
the same 'kick' command defined on it, so it may offer a chance to
select which ball to kick ... Allowing duplicates only makes sense
for *Union* and *Intersect*, the setting is ignored for the other
mergetypes.
- *key*\ mergetype\ *(dict) - allows the cmdset to define a unique
mergetype for particular cmdsets, identified by their cmdset-key.
Format is ``CmdSetkey:mergetype``. Priorities still apply. Example:
``'Myevilcmdset','Replace'`` which would make sure for this set to
always use 'Replace' on ``Myevilcmdset`` only, no matter
what*mergetype\_ is set to.
what*\ mergetype\_ is set to.
More advanced cmdset example:
@ -548,29 +549,30 @@ are defined at the top of ``src/commands/cmdhandler.py``). You can find
``src/commands/default/system_commands.py``. Since these are not (by
default) included in any ``CmdSet`` they are not actually used, they are
just there for show. When the special situation occurs, Evennia will
look through all valid ``CmdSet``s for your custom system command. Only
after that will it resort to its own, hard-coded implementation.
look through all valid ``CmdSet``\ s for your custom system command.
Only after that will it resort to its own, hard-coded implementation.
Here are the exceptional situations that triggers system commands:
Here are the exceptional situations that triggers system commands. You
can find the command keys they use as properties on ``ev.syscmdkeys``
- No input (``cmdhandler.CMD_NOINPUT``) - the player just pressed
- No input (``syscmdkeys.CMD_NOINPUT``) - the player just pressed
return without any input. Default is to do nothing, but it can be
useful to do something here for certain implementations such as line
editors that interpret non-commands as text input (an empty line in
the editing buffer).
- Command not found (``cmdhandler.CMD_NOMATCH``) - No matching command
- Command not found (``syscmdkeys.CMD_NOMATCH``) - No matching command
was found. Default is to display the "Huh?" error message.
- Several matching commands where found (``cmdhandler.CMD_MULTIMATCH``)
- Several matching commands where found (``syscmdkeys.CMD_MULTIMATCH``)
- Default is to show a list of matches.
- User is not allowed to execute the command
(``cmdhandler.CMD_NOPERM``) - Default is to display the "Huh?" error
(``syscmdkeys.CMD_NOPERM``) - Default is to display the "Huh?" error
message.
- Channel (``cmdhandler.CMD_CHANNEL``) - This is a
- Channel (``syscmdkeys.CMD_CHANNEL``) - This is a
`Channel <Communications.html>`_ name of a channel you are
subscribing to - Default is to relay the command's argument to that
channel. Such commands are created by the Comm system on the fly
depending on your subscriptions.
- New session connection ('cmdhandler.CMD\_LOGINSTART'). This command
- New session connection ('syscmdkeys.CMD\_LOGINSTART'). This command
name should be put in the ``settings.CMDSET_UNLOGGEDIN``. Whenever a
new connection is established, this command is always called on the
server (default is to show the login screen).
@ -581,7 +583,7 @@ command must be added to a cmdset as well before it will work.
::
from src.commands import cmdhandler from game.gamesrc.commands.basecommand import Commandclass MyNoInputCommand(Command): "Usage: Just press return, I dare you" key = cmdhandler.CMD_NOINPUT def func(self): self.caller.msg("Don't just press return like that, talk to me!")
from ev import syscmdkeys, Commandclass MyNoInputCommand(Command): "Usage: Just press return, I dare you" key = syscmdkeys.CMD_NOINPUT def func(self): self.caller.msg("Don't just press return like that, talk to me!")
Exits
-----

View file

@ -80,7 +80,7 @@ send a non-persistent message, also if you send it a ``Msg`` object.
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
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

@ -70,7 +70,7 @@ To help with Evennia development it's recommended to do so using a clone
repository as described above. But for small, well isolated fixes you
are also welcome to submit your suggested Evennia fixes/addendums as
*patches*. You can use normal
`patches <https://secure.wikimedia.org/wikipedia/en/wiki/Patch_(computing).html>`_,
`patches <https://secure.wikimedia.org/wikipedia/en/wiki/Patch_%28computing%29.html>`_,
but it might be easier to use mercurial's own patch mechanism. Make sure
you have committed your latest fixes first, then

File diff suppressed because it is too large Load diff

View file

@ -22,6 +22,7 @@ more links to Evennia resources from the `Links <Links.html>`_ page.
General Evennia development information
---------------------------------------
- `Introduction to coding with Evennia <CodingIntroduction.html>`_
- `Evennia Licensing FAQ <Licensing.html>`_
- `Contributing to Evennia <Contributing.html>`_
- `Evennia Code Style
@ -34,6 +35,8 @@ General Evennia development information
Evennia Component Documentation
-------------------------------
- `ev - the flat API <evAPI.html>`_
`Directory Overview <DirectoryOverview.html>`_
`Portal and Server <PortalAndServer.html>`_

View file

@ -4,6 +4,7 @@ Evennia directory overview
::
evennia/
ev.py
contrib/
docs/
game/
@ -25,6 +26,12 @@ directories. When you have run Evennia at least once you will find that
there will also be ``.pyc`` files appearing, these are pre-compiled
binary versions of the ``.py`` files to speed up execution.
The file ``ev.py`` is important to remember. This is the home of
Evennia's flat API, essentially a set of shortcuts to various important
places in ``src/``. By importing ``ev`` from your code in ``game/`` you
have access to most important Evennia systems without *having* to know
where everything is located, as described in the following sections.
The ``docs/`` directory
-----------------------
@ -94,29 +101,25 @@ Evennia.
^^^^^^^^^^^^^^^^^^^^^
``gamesrc/commands/`` contains modules for defining
`Commands <Commands.html>`_. It contains a file ``basecommand.py`` which
defines the root object from which all your own command classes will
inherit.The file ``basecmdset.py`` is where you'll inherit your `Command
Set <Commands.html>`_ classes from. ``commands/examples`` contains the
main interactive commands and cmdsets of the *Red Button*.
`Commands <Commands.html>`_. In ``commands/examples`` you will find
templates for starting to define your own commands and cmdsets. Copy
these out into the parent ``command`` folder and work from there.
``gamesrc/scripts/``
^^^^^^^^^^^^^^^^^^^^
``gamesrc/scripts/`` holds everything related to
`Scripts <Scripts.html>`_. It has a file ``basescript.py`` that hold the
parent for all scripts and which you should inherit from.
``scripts/examples`` holds the *Red Button*'s scripts.
`Scripts <Scripts.html>`_. ``scripts/examples`` holds templates you can
make copies of and build from to define your own scripts.
``gamesrc/objects/``
^^^^^^^^^^^^^^^^^^^^
``gamesrc/objects/`` should contain the definitions for all your
`Objects <Objects.html>`_. ``baseobjects.py`` contains the parent
classes for the normal *Object* as well as its three basic subclasses
*Character*, *Room* and *Exit*. Your own objects will inherit from the
classes in this file. ``objects/examples`` define the example *Red
Button* object itself.
`Objects <Objects.html>`_. ``objects/examples`` contain templates for
*Object* as well as its three basic subclasses *Character*, *Room* and
*Exit*. Make copies of these templates to have somthing to start from
when defining your own in-game entities.
``gamesrc/world/``
^^^^^^^^^^^^^^^^^^
@ -143,21 +146,23 @@ syntax.
^^^^^^^^^^^^^^^^^
``gamesrc/conf/`` holds optional extension modules for the Evennia
engine. Certain functionality in the server is meant to be extended, and
in order to allow you to do this without modifying the server itself, it
imports files from this directory. Modifying these are optional and you
can usually change a variable in ``game/settings.py`` to change exactly
which module Evennia actually uses. There are dummy example files in
here, read their headers for usage instructions.
engine. It is empty by default, but in ``conf/examples/`` are templates
for the various config files that the server undertands. Each template
file contains instructions for how you should use them; copy out the
ones you want into the ``conf/`` directory and edit them there.
The ``src/`` directory
----------------------
``src/`` contains the main running code of the Evennia server. You will
often need to import modules from here to access the functionality of
Evennia. You should generally not modify anything in this folder
directly since it might be changed when we release updates. If you find
bugs or features missing, file a bug report or send us a message.
``src/`` contains the main running code of the Evennia server. You can
import files directly from here, but normally you will probably find it
easier to use the shortcuts in the top-level ``ev`` module.
You should never modify anything in this folder directly since it might
be changed when we release updates. If you want to use some code as a
base for your own work (such as new commands), copy the relevant code
out into your own modules in ``game/gamesrc`` instead. If you find bugs
or features missing, file a bug report or send us a message.
::
@ -196,7 +201,7 @@ Evennia. It defines basic command function, parsing and command-set
handling.
``commands/default/`` holds a multitude of modules that together form
Evennia's default ('`MUX-like <UsingMUXAsAStandard.html>`_') command
Evennia's default ('`MUX-like <UsingMUXAsAStandard.html>`_\ ') command
set. The files ``game/gamesrc/basecommand.py`` and
``game/gamesrc/basecmdset.py`` both link to their respective parents
here. If you want to edit a default command, copy&paste the respective

View file

@ -52,9 +52,9 @@ function on the database model or if it in fact sat on the script parent
By contrast, a typeclass is a normal python class that inherits from the
*!TypeClass* parent. There are no other required functions to define.
This class uses **getattribute** and **setattr** transparently behind
the scenes to store data onto the persistent django object. Also the
django model is aware of the typeclass in the reverse direction. The
This class uses **\ getattribute\ ** and **\ setattr\ ** transparently
behind the scenes to store data onto the persistent django object. Also
the django model is aware of the typeclass in the reverse direction. The
admin don't really have to worry about this connection, they can usually
consider the two objects (typeclass and django model) to be one.
@ -74,14 +74,15 @@ Command functions + !StateCommands-> Command classes + CmdSets
--------------------------------------------------------------
In trunk, there was one default group of commands in a list
GLOBAL*CMD*TABLE. Every player in game used this. There was a second
dictionary GLOBAL*STATE*TABLE that held commands valid only for certain
*states* the player might end up in - like entering a dark room, a text
editor, or whatever. The problem with this state system, was that it was
limited in its use - every player could ever only be in one state at a
time for example, never two at the same time. The way the system was set
up also explicitly made states something unique to players - an object
could not offer different commands dependent on its state, for example.
GLOBAL\ *CMD*\ TABLE. Every player in game used this. There was a second
dictionary GLOBAL\ *STATE*\ TABLE that held commands valid only for
certain *states* the player might end up in - like entering a dark room,
a text editor, or whatever. The problem with this state system, was that
it was limited in its use - every player could ever only be in one state
at a time for example, never two at the same time. The way the system
was set up also explicitly made states something unique to players - an
object could not offer different commands dependent on its state, for
example.
In devel, *every* command definition is grouped in what's called a
*!CmdSet* (this is, like most things in Devel, defined as a class). A
@ -319,7 +320,7 @@ where it might be unclear if you receive a session or a player object
(especially during login/logout), you can now use simply use ``msg()``
without having to check (however, you *can* still use ``emit_to`` for
legacy code, it's an alias to msg() now). Same is true with
emit*to*contents() -> msg*to*contents().
emit\ *to*\ contents() -> msg\ *to*\ contents().
``source_object`` in default commands are now consistently named
*caller* instead.

View file

@ -6,16 +6,16 @@ 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>`_
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/MU <http://en.wikipedia.org/wiki/Mu%3Cstrong%3E>`_ 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
(`MUD/MUX/MU <http://en.wikipedia.org/wiki/Mu<strong>>`_ 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.
@ -132,24 +132,23 @@ 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!
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.
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/trunk>`_. We also
have a comprehensive `online
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

View file

@ -3,10 +3,10 @@ The ``@py`` command
The ``@py`` command supplied with the default command set of Evennia
allows you to execute Python commands directly from inside the game. An
alias to ``@py`` is simply "``!``". *Access to the ``@py`` command
should be severely restricted only to game admins.* Being able to
execute arbitrary Python code on the server is not something you should
entrust to just anybody.
alias to ``@py`` is simply "``!``\ ". *Access to the ``@py`` command
should be severely restricted*. This is no joke - being able to execute
arbitrary Python code on the server is not something you should entrust
to just anybody.
::
@ -16,27 +16,24 @@ Available variables
-------------------
A few local variables are made available when running ``@py``. These
offer entry into the running system and allows for quick exploration of
the standard objects.
offer entry into the running system.
- **self** / **me** - the calling object (i.e. you)
- **here** - the current caller's location
- **obj** - a dummy `Object <Objects.html>`_ instance
- **script** - a dummy `Script <Scripts.html>`_ instance
- **config** - a dummy ConfigValue instance
- **ObjectDB** - direct reference to the ObjectDB database class
- **ScriptDB** - direct reference to the ScriptDB database class
- **!ConfigValue** - direct reference to the ConfigValue database class
- **ev** - Evennia's flat API - through this you can access all of
Evennia.
Returning output
----------------
This is an example where we import and test one of Evennia's utilities
found in ``src/utils/utils.py``:
found in ``src/utils/utils.py``, but also accessible through
``ev.utils``:
::
@py from src.utils import utils; utils.time_format(33333) <<< Done.
@py from ev import utils; utils.time_format(33333) <<< Done.
Note that we didn't get any return value, all we where told is that the
code finished executing without error. This is often the case in more
@ -46,7 +43,7 @@ system to echo it to us explicitly with ``self.msg()``.
::
@py from src.utils import utils; self.msg(utils.time_format(33333)) 09:15 <<< Done.
@py from ev import utils; self.msg(utils.time_format(33333)) 09:15 <<< Done.
If you were to use Python's standard ``print``, you will see the result
in your current ``stdout`` (your terminal by default), *if* you are
@ -68,31 +65,28 @@ Locating an object is best done using ``self.search()``:
``self.search()`` is by far the most used case, but you can also search
other database tables for other Evennia entities like scripts or
configuration entities. To do this you can use the generic search
entries found in ``src.utils.search``.
entries found in ``ev.search_*``.
::
@py from src.utils import search; self.msg(search.scripts("sys_game_time")) <<< [<src.utils.gametime.GameTime object at 0x852be2c>]
@py ev.search_script("sys_game_time") <<< [<src.utils.gametime.GameTime object at 0x852be2c>]
You can also use the database model managers directly (accessible
through the ``objects`` properties of database models). This is a bit
more flexible since it gives you access to the full range of database
search methods defined in each manager.
(Note that since this becomes a simple statement, we don't have to wrap
it in ``self.msg()`` to get the output). You can also use the database
model managers directly (accessible through the ``objects`` properties
of database models or as ``ev.db_*``). This is a bit more flexible since
it gives you access to the full range of database search methods defined
in each manager.
::
@py ScriptDB.objects.script_search("sys_game_time") <<< [<src.utils.gametime.GameTime object at 0x852be2c>]
@py ev.db_scripts.script_search("sys_game_time") <<< [<src.utils.gametime.GameTime object at 0x852be2c>]
(Note that since this second example becomes a simple statement, we
don't have to wrap it in ``self.msg()`` to get the output). If you want
to see what is available, the managers are found in the ``manager.py``
files throughout the ``src`` directory (e.g.
``src/objects/manager.py``). Through the manager you can also view the
contents of the database using normal Django query operations:
The managers are useful for all sorts of database studies.
::
@py ConfigValue.objects.all() <<< [<ConfigValue: default_home]>, <ConfigValue:site_name>, ...]
@py ev.db_configvalues.all() <<< [<ConfigValue: default_home]>, <ConfigValue:site_name>, ...]
In doing so however, keep in mind the difference between `Typeclasses
and Database Objects <Typeclasses.html>`_: Using the search commands in
@ -104,7 +98,7 @@ most situations.
::
# this uses Evennia's manager method get_id(). # It returns a Character typeclass instance @py ObjectDB.objects.get_id(1).__class__ <<< Character# this uses the standard Django get() query. # It returns a django database model instance. @py ObjectDB.objects.get(id=1).__class__ <<< <class 'src.objects.models.ObjectDB'>
# this uses Evennia's manager method get_id(). # It returns a Character typeclass instance @py ev.db_objects.get_id(1).__class__ <<< Character# this uses the standard Django get() query. # It returns a django database model instance. @py ev.db_objects.get(id=1).__class__ <<< <class 'src.objects.models.ObjectDB'>
Running a Python Parser outside the game
========================================
@ -122,12 +116,13 @@ Go to the ``game`` directory and get into a new terminal.
Your default Python intrepeter will start up, configured to be able to
work with and import all modules of your Evennia installation. From here
you can explore the database and test-run individual modules as desired.
Not only does a fully featured Python interpreter like
Most of the time you can get by with just the ``ev`` module though. A
fully featured Python interpreter like
`iPython <http://ipython.scipy.org/moin/>`_ allow you to work over
several lines, it also has lots of other editing features, usch as
several lines, but also has lots of other editing features, usch as
tab-completion and ``__doc__``-string reading.
::
$ python manage.py shellIPython 0.10 -- An enhanced Interactive Python ...In [1]: from src.objects.models import ObjectDB In [2]: ObjectDB.objects.all() Out[3]: [<ObjectDB: Harry>, <ObjectDB: Limbo>, ...]
$ python manage.py shellIPython 0.10 -- An enhanced Interactive Python ...In [1]: import ev In [2]: ev.db_objects.all() Out[3]: [<ObjectDB: Harry>, <ObjectDB: Limbo>, ...]

View file

@ -96,7 +96,7 @@ Installing pre-requisites
**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
`here <GettingStarted#Optional:%3Ci%3EA%3C/i%3Eseparate%3Ci%3Einstallation%3C/i%3Eenvironment%3Ci%3Ewith%3C/i%3Evirtualenv.html>`_.
`here <GettingStarted#Optional:<i>A</i>separate<i>installation</i>environment<i>with</i>virtualenv.html>`_.
Windows users will probably want to go the ActivePython way instead
though (see below), there are issues with installing certain extensions
in Windows.
@ -113,7 +113,7 @@ Debian-derived systems (such as Ubuntu) you can do something like this
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
`easyinstall <http://packages.python.org/distribute/easy%3Ci%3Einstall.html>`_
`easyinstall <http://packages.python.org/distribute/easy<i>install.html>`_
or the alternative
`pip <http://www.pip-installer.org/en/latest/index.html>`_ to get some
or all of these instead:
@ -126,6 +126,15 @@ or all of these instead:
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. There are however
reports that you might need to get the
@ -136,9 +145,11 @@ installers or python setups. Some users have reported problems compiling
the ``PIL`` library on Mac, it's however not strictly required to use
Django.
**Windows** users may choose to install
**Windows** users may want to install
`ActivePython <http://www.activestate.com/activepython/downloads>`_
instead of the usual Python. If ActivePython is installed, you can use
instead of the usual Python. Get the 32-bit version (it seems the 64-bit
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
@ -156,7 +167,7 @@ Windows users not using ActivePython or virtual environments will have
to manually download and install the packages in turn (including their
own dependencies in the list above). Most have normal Windows
installers, but in some cases you'll need to know how to use the Windows
command prompt to execute python install scripts (usually it's not
command prompt to execute python install scripts (it's usually not
harder than running ``python setup.py install`` from the downloaded
package's folder).
@ -298,8 +309,10 @@ Optional: A separate installation environment with virtualenv
Apart from installing the packages and versions as above, you can also
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`` file from that
page and run it directly in the terminal with ``python virtualenv.py``.
are unsure how to get it, just grab the
`virtualenv.py <https://raw.github.com/pypa/virtualenv/master/virtualenv.py.html>`_
file from that page 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,

View file

@ -80,7 +80,7 @@ A help entry consists of four parts:
- The *text* - the help text itself, of any length.
- locks - a `lock definition <Locks.html>`_. This can be used to limit
access to this help entry, maybe because it's staff-only or otherwise
meant to be restricted. Help commands check for ``access_type``s
meant to be restricted. Help commands check for ``access_type``\ s
``view`` and ``edit``. An example of a lock string would be
``view:perm(Builders)``.

View file

@ -9,7 +9,7 @@ documentation <Index.html>`_, here's what to do:
- If you think the documentation is not clear enough, fill in our quick
little "https://docs.google.com/spreadsheet/viewform?hl
en*US&formkey*
en\ *US&formkey*
dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid
======================================

View file

@ -2,8 +2,8 @@ IRC
===
`IRC (Internet Relay
Chat) <http://en.wikipedia.org/wiki/Internet%3Ci%3ERelay%3C/i%3EChat>`_
is a long standing chat protocol used by many open-source projects for
Chat) <http://en.wikipedia.org/wiki/Internet<i>Relay</i>Chat>`_ is a
long standing chat protocol used by many open-source projects for
communicating in real time. By connecting one of Evennia's
`Channels <Communications.html>`_ to an IRC channel you can communicate
also with people not on an mud themselves. Note that you can use IRC

View file

@ -9,8 +9,7 @@ directory. You can also read the full license file
You should read the full license text to know what it says exactly, but
here are some answers to common questions.
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 licence permit me to do with it?
-------------------------------------------------------------------------------------
**A:** It's your own game world to do with as you please! To summarize,
@ -38,8 +37,7 @@ is referred to as "The Package, Standard version" in the license.
of course, if you plan to add new features to the server, the easiest
way to do so is to simply become an Evennia developer!
Q: Can I re-distribute the Evennia server package along with my custom
game implementation?
Q: Can I re-distribute the Evennia server package along with my custom game implementation?
-------------------------------------------------------------------------------------------
**A:** Sure. This is covered in **§4** - just package the "Standard

View file

@ -49,7 +49,7 @@ General mud/game development ideas and discussions
aggregator following blogs of current MUD development around the
'net.
- Mud Dev mailing list archive
(`mirror1 <http://nilgiri.net/MUD-Dev-archive/>`_),(`mirror2 <http://www.disinterest.org/resource/MUD-Dev/>`_)
(`mirror1 <http://nilgiri.net/MUD-Dev-archive/>`_),(\ `mirror2 <http://www.disinterest.org/resource/MUD-Dev/>`_)
- Influential mailing list active 1996-2004. Advanced game design
discussions.
- `Imaginary

View file

@ -49,8 +49,9 @@ add, delete and check locks.
One can call ``locks.check()`` to perform a lock check, but to hide the
underlying implementation all objects also have a convenience function
called ``access``. This should preferably be used. In the example below,
``accessing_obj`` is the object requesting the 'delete' access. This is
how it would (and do) look from inside the ``@delete`` command:
``accessing_obj`` is the object requesting the 'delete' access whereas
``obj`` is the object that might get deleted. This is how it would (and
do) look from inside the ``@delete`` command:
::
@ -63,7 +64,7 @@ Defining a lock (i.e. an access restriction) in Evennia is done by
adding simple strings of lock definitions to the object's ``locks``
property using ``obj.locks.add()``.
Here are some examples of lock strings:
Here are some examples of lock strings (not including the quotes):
::
@ -79,7 +80,7 @@ where ``[..]`` marks optional parts. AND, OR and NOT are not case
sensitive and excess spaces are ignored. ``func1, func2`` etc are
special *lock functions* available to the lock system.
So, a lockstrings consists of the type of restriction (the
So, a lockstring consists of the type of restriction (the
``access_type``), a colon (``:``) and then a list of function calls that
determine what is needed to pass the lock. Each function returns either
``True`` or ``False``. AND/OR and NOT works like normal Python to
@ -163,7 +164,8 @@ You are not allowed to use just any function in your lock definition;
you are infact only allowed to use those functions defined in one of the
modules given in ``settings.LOCK_FUNC_MODULES``. All functions in any of
those modules will automatically be considered a valid lock function.
The default ones are found in ``src/locks/lockfuncs.py``.
The default ones are found in ``src/locks/lockfuncs.py`` or via
``ev.lockfuncs``.
A lock function must always accept at least two arguments - the
*accessing object* (this is the object wanting to get access) and the
@ -195,7 +197,7 @@ Some useful default lockfuncs (see ``src/locks/lockfuncs.py`` for more):
- ``attr(attrname)`` - checks if a certain
`Attribute <Attributes.html>`_ exists on accessingobject.
- ``attr(attrname, value)`` - checks so an attribute exists on
accessing*object*and has the given value.
accessing\ *object*\ and has the given value.
- ``attr_gt(attrname, value)`` - checks so accessingobject has a value
larger (``>``) than the given value.
- ``attr_ge, attr_lt, attr_le, attr_ne`` - corresponding for ``>=``,
@ -260,9 +262,9 @@ looked for is not in the hierarchy, an exact match is required.
Superusers
----------
There is normally only one *superuser* account and that is the the one
first created when starting Evennia (User #1). This is sometimes known
as the "Owner" or "God" user. A superuser has more than full access - it
There is normally only one *superuser* account and that is the one first
created when starting Evennia (User #1). This is sometimes known as the
"Owner" or "God" user. A superuser has more than full access - it
completely *bypasses* all locks so no checks are even run. This allows
for the superuser to always have access to everything in an emergency.
But it also hides any eventual errors you might have made in your lock
@ -349,7 +351,7 @@ this snippet:
So the ``get`` command looks for a lock with the type *get* (not so
surprising). It also looks for an `Attribute <Attributes.html>`_ on the
checked object called *get*err*msg* in order to return a customized
checked object called *get*\ err\ *msg* in order to return a customized
error message. Sounds good! Let's start by setting that on the box:
::
@ -361,7 +363,7 @@ only be passed if the accessing object has the attribute *strength* of
the right value. For this we would need to create a lock function that
checks if attributes have a value greater than a given value. Luckily
there is already such a one included in evennia (see
``src/permissions/lockfuncs.py``), called``attr_gt``.
``src/permissions/lockfuncs.py``), called ``attr_gt``.
So the lock string will look like this: ``get:attr_gt(strength, 50)``.
We put this on the box now:
@ -379,14 +381,14 @@ like this:
::
from src.utils import create box = create.create_object(None, key="box", locks="get:attr_gt(strength, 50)")# or, if we don't set the locks right awaybox.locks.add("get:attr_gt(strength, 50)")# set the attributesbox.db.desc = "This is a very big and heavy box." box.db.get_err_msg = "You are not strong enough to lift this box."# one heavy box, ready to withstand all but the strongest...
from ev import create_objectbox = create_object(None, key="box") box.locks.add("get:attr_gt(strength, 50)")# or we can assign locks right away box = create_object(None, key="box", locks="get:attr_gt(strength, 50)")# set the attributes box.db.desc = "This is a very big and heavy box." box.db.get_err_msg = "You are not strong enough to lift this box."# one heavy box, ready to withstand all but the strongest...
On Django's permission system
=============================
Django also implements a comprehensive permission/security system out of
the box. The reason we don't use that is because it is app-centric (app
in the Django sense). Its permission strings are of the form
Django also implements a comprehensive permission/security system of its
own. The reason we don't use that is because it is app-centric (app in
the Django sense). Its permission strings are of the form
``appname.permstring`` and it automatically adds three of them for each
database model in the app - for the app src/object this would be for
example 'object.create', 'object.admin' and 'object.edit'. This makes a

View file

@ -46,7 +46,7 @@ commands expecting an object reference, such as
look mycar2
becomes equivalent to "``look The red sports car``".
becomes equivalent to "``look The red sports car``\ ".
::

View file

@ -13,13 +13,13 @@ An Evennia Object is, per definition, a Python class that includes
``src.objects.objects.Object`` among its parents (if you are aware of
how typeclasses work, this is a typeclass linked to the ``ObjectDB``
database model). In your code you can however conveniently refer to
``game.gamesrc.objects.baseobjects.Object`` instead.
``ev.Object`` instead.
Here's how to define a new Object typeclass in code:
::
from game.gamesrc.objects.baseobjects import Objectclass Rose(Object): """ This creates a simple rose object """ def at_object_creation(self): "this is called only once, when object is first created" # add a persistent attribute 'desc' to object. self.db.desc = "This is a pretty rose with thorns."
from ev import Objectclass Rose(Object): """ This creates a simple rose object """ def at_object_creation(self): "this is called only once, when object is first created" # add a persistent attribute 'desc' to object. self.db.desc = "This is a pretty rose with thorns."
Save your class to a module under ``game/gamesrc/objects``, say
``flowers.py``. Now you just need to point to the class *Rose* with the
@ -29,21 +29,21 @@ Save your class to a module under ``game/gamesrc/objects``, say
> @create/drop MyRose:flowers.Rose
To create a new object in code, use the method
``src.utils.create.create_object()``:
To create a new object in code, use the method ``ev.create_object`` (a
shortcut to src.utils.create.create\_object()
::
from src.utils import create new_rose = create.create_object("game.gamesrc.objects.flowers.Rose", key="MyRose")
):from ev import create_object new_rose = create_object("game.gamesrc.objects.flowers.Rose", key="MyRose")
(You have to give the full path to the class in this case -
``create.create_object`` is a powerful function that should be used for
all coded creating, for example if you create your own command that
creates some objects as it runs. Check out the ``src.utils.create``
module for more info on which arguments you can give the function.)
creates some objects as it runs. Check out the ``ev.create_*``
functions.
This particular Rose class doesn't really do much, all it does it make
sure the attribute ``desc``(which is what the ``look`` command looks
sure the attribute ``desc``\ (which is what the ``look`` command looks
for) is pre-set, which is pretty pointless since you will usually want
to change this at build time (using the ``@describe`` command). The
``Object`` typeclass offers many more hooks that is available to use
@ -108,34 +108,34 @@ The last two properties are special:
`scripts <Scripts.html>`_ attached to the object (if any).
The Object also has a host of useful utility functions. See the function
headers in ``src/objects/models.py`` for arguments and more details.
headers in ``src/objects/objects.py`` for their arguments and more
details.
- ``msg`` - this function is used to send messages from the server to a
player connected to this object.
- ``msg_contents`` - calls ``msg`` on all objects inside this object.
- ``search`` - this is a convenient shorthand to search for a specific
object, at a given location or globally. It's mainly useful when
defining commands (in which case the object executing the command is
named ``caller`` and one can do ``caller.search()`` to find objects
in the room to operate on).
- ``execute_cmd`` - Lets the object execute the given string as if it
- ``msg()`` - this function is used to send messages from the server to
a player connected to this object.
- ``msg_contents()`` - calls ``msg`` on all objects inside this object.
- ``search()`` - this is a convenient shorthand to search for a
specific object, at a given location or globally. It's mainly useful
when defining commands (in which case the object executing the
command is named ``caller`` and one can do ``caller.search()`` to
find objects in the room to operate on).
- ``execute_cmd()`` - Lets the object execute the given string as if it
was given on the command line.
- ``move_to`` - perform a full move of this object to a new location.
This is the main move method and will call all relevant hooks, do all
checks etc.
- ``clear_exits`` - will delete all `Exits <Objects#Exits.html>`_ to
- ``clear_exits()`` - will delete all `Exits <Objects#Exits.html>`_ to
*and* from this object.
- ``clear_contents`` - this will not delete anything, but rather move
- ``clear_contents()`` - this will not delete anything, but rather move
all contents (except Exits) to their designated ``Home`` locations.
- ``delete`` - deletes this object, first calling ``clear_exits()`` and
``clear_contents()``.
- ``delete()`` - deletes this object, first calling ``clear_exits()``
and ``clear_contents()``.
The Object Typeclass defines many more *hook methods* beyond
``at_object_creation``. Evennia calls these hooks at various points.
When implementing your custom objects, you will inherit from the base
parent and overload these hooks with your own custom code. See
``game.gamesrc.baseobjects`` for an updated list of all the available
hooks.
``src.objects.objects`` for an updated list of all the available hooks.
Subclasses of *Object*
----------------------
@ -146,8 +146,7 @@ because these particular object types are fundamental, something you
will always need and in some cases requires some extra attention in
order to be recognized by the game engine (there is nothing stopping you
from redefining them though). In practice they are all pretty similar to
the base Object. You will import them all from
``game.gamesrc.objects.baseobjects``.
the base Object.
Characters
~~~~~~~~~~
@ -158,10 +157,10 @@ object is created and the Player object is assigned to the ``player``
attribute. A ``Character`` object must have a `Default
Commandset <Commands#Command_Sets.html>`_ set on itself at creation, or
the player will not be able to issue any commands! If you just inherit
your own class from ``baseobjects.Character`` and make sure the parent
methods are not stopped from running you should not have to worry about
this. You can change the default typeclass assigned to new Players in
your settings with ``BASE_CHARACTER_TYPECLASS``.
your own class from ``ev.Character`` and make sure the parent methods
are not stopped from running you should not have to worry about this.
You can change the default typeclass assigned to new Players in your
settings with ``BASE_CHARACTER_TYPECLASS``.
Rooms
~~~~~
@ -170,8 +169,8 @@ Rooms
really separating a room from any other object is that they have no
``location`` of their own and that default commands like ``@dig``
creates objects of this class - so if you want to expand your rooms with
more functionality, just inherit from ``baseobjects.Room``. Change the
default used by ``@dig`` with ``BASE_ROOM_TYPECLASS``.
more functionality, just inherit from ``ev.Room``. Change the default
used by ``@dig`` with ``BASE_ROOM_TYPECLASS``.
Exits
~~~~~
@ -191,10 +190,10 @@ its own to move around, just as you would expect.
The exit functionality is all defined on the Exit typeclass, so you
could in principle completely change how exits work in your game (it's
not recommended though, unless you really know what you are doing).
Exits are `locked <Locks.html>`_ using an access*type called*traverse\_
and also make use of a few hook methods for giving feedback if the
traversal fails. See ``baseobjects.Exit`` for more info, that is also
what you should inherit from to make custom exit types. Change the
Exits are `locked <Locks.html>`_ using an access\ *type
called*\ traverse\_ and also make use of a few hook methods for giving
feedback if the traversal fails. See ``ev.Exit`` for more info, that is
also what you should inherit from to make custom exit types. Change the
default class used by e.g. ``@dig`` and ``@open`` by editing
``BASE_EXIT_TYPECLASS`` in your settings.

View file

@ -33,23 +33,21 @@ player's typeclass dynamically).
An Evennia Player is, per definition, a Python class that includes
``src.players.player.Player`` among its parents (if you are aware of how
`Typeclasses <Typeclasses.html>`_ work, this is a typeclass linked to
the ``PlayerDB`` database model). There is no equivalence to this in the
``game/gamesrc`` folder, you need to inherit from the base object
directly.
the ``PlayerDB`` database model). You can also inherit from
``ev.Player`` which is a shortcut.
Here's how to define a new Player typeclass in code:
::
from src.players.player import Player class ConfigPlayer(Player): """ This creates a Player with some configuration options """ 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.config_1 = True # default config self.db.config_2 = False # " self.db.config_3 = 1 # " # ... whatever else our game needs to know
from ev import Player class ConfigPlayer(Player): """ This creates a Player with some configuration options """ 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.config_1 = True # default config self.db.config_2 = False # " self.db.config_3 = 1 # " # ... whatever else our game needs to know
There is no pre-made folder in ``game/gamesrc`` to store custom player
typeclasses. Either make your own folder or store it in
``gamesrc/objects`` (remember that if you make your own folder you need
to add an empty ``__init__.py`` file so that you can import the file
later). To change which object becomes the Player object for new
players, set the variable ``BASE_PLAYER_TYPECLASS`` in your
``settings.py`` file.
typeclasses. Make your own folder or store it in ``gamesrc/objects``
(remember that if you make your own folder you need to add an empty
``__init__.py`` file so that you can import the file later). To change
which object becomes the Player object for new players, set the variable
``BASE_PLAYER_TYPECLASS`` in your ``settings.py`` file.
Properties on Players
---------------------
@ -81,8 +79,8 @@ Special handlers:
How it all hangs together
-------------------------
Looking at the above list, it's clear there are more to ``Player``s than
what first meets the eye.
Looking at the above list, it's clear there are more to ``Player``\ s
than what first meets the eye.
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

View file

@ -10,7 +10,7 @@ to have players connect to the Portal but keep the MUD running on the
Server. This way one can restart/reload the game (the Server part)
without Players getting disconnected.
https://2498159658166209538-a-1802744773732722657-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia*server*portal.png
https://2498159658166209538-a-1802744773732722657-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia\ *server*\ portal.png
The Server and Portal are glued together via an AMP (Asynchronous
Messaging Protocol) connection. This allows the two programs to

View file

@ -34,7 +34,7 @@ inheriting from ``game.gamesrc.objects.baseobjecs.Character``.
::
from game.gamesrc.objects.baseobjects import Characterclass ColourableCharacter(Character): at_object_creation(self): # set a colour config value self.db.config_colour = True
from ev import Characterclass ColourableCharacter(Character): at_object_creation(self): # set a colour config value self.db.config_colour = True
Above we set a simple config value as an `attribute <Attributes.html>`_.
@ -50,11 +50,13 @@ everything works - you don't want to render your root user unusable!).
@typeclass/reset/force Bob = mycharacter.ColourableCharacter
The ``/reset`` switch clears all attributes and properties back to the
default for the new typeclass and forces the object to re-run all its
creation hooks (important in this case). ``/force`` might be needed if
you edit the typeclass and want to update the object despite the actual
typeclass name not having changed.
``@typeclass`` changes Bob's typeclass and runs all its creation hooks
all over again. The ``/reset`` switch clears all attributes and
properties back to the default for the new typeclass - this is useful in
this case to avoid ending up with an object having a "mixture" of
properties from the old typeclass and the new one. ``/force`` might be
needed if you edit the typeclass and want to update the object despite
the actual typeclass name not having changed.
Overload the ``msg()`` method
-----------------------------
@ -74,7 +76,7 @@ original. Here's how it could look:
::
from src.utils import ansimsg(self, message, from_obj=None, data=None): "our custom msg()" if not self.db.config_colour: message = ansi.parse_ansi(message, strip_ansi=True) self.dbobj.msg(message, from_obj, data)
from ev import ansimsg(self, message, from_obj=None, data=None): "our custom msg()" if not self.db.config_colour: message = ansi.parse_ansi(message, strip_ansi=True) self.dbobj.msg(message, from_obj, data)
Above we create a custom version of the ``msg()`` method that cleans all
ansi characters if the config value is not set to True. Once that's
@ -106,15 +108,27 @@ for configuration down the line).
::
from game.gamesrc.commands.basecommand import MuxCommandclass ConfigColourCmd(MuxCommand): """ Configures your colour Usage: @setcolour on|off This turns ansii-colours on/off. Default is on. """ key = "@setcolour" aliases = ["@setcolor"] def func(self): "Implements the command" if not self.args or not self.args in ("on", "off"): self.caller.msg("Usage: @setcolour on|off") return if self.args == "on": self.caller.db.config_colour = True else: self.caller.db.config_colour = False self.caller.msg("Colour was turned %s." % self.args)
from ev import default_cmds
class ConfigColourCmd(default_cmds.MuxCommand):
"""
Configures your colour Usage: @setcolour on|off This turns ansii-colours on/off. Default is on. """ key = "@setcolour" aliases = ["@setcolor"] def func(self): "Implements the command" if not self.args or not self.args in ("on", "off"): self.caller.msg("Usage: @setcolour on|off") return if self.args == "on": self.caller.db.config_colour = True else: self.caller.db.config_colour = False self.caller.msg("Colour was turned %s." % self.args)
Lastly, we make this command available to the user by adding it to the
default command set. Easiest is to add it to the end of
``DefaultCmdSet`` class in gamesrc/commands/basecmdset.py:
default command set. Easiest is to add it to copy the template file from
``gamesrc/commands/examples``, set ``settings.CMDSET_DEFAULT`` to point
to, and then add your module to the end of ``DefaultCmdSet`` in that new
module.
::
from game.gamesrc.commands import configcmds class DefaultCmdSet(cmdset_default.DefaultCmdSet): key = "DefaultMUX" def at_cmdset_creation(self): super(DefaultCmdSet, self).at_cmdset_creation() self.add(configcmds.ConfigColourCmd())
from game.gamesrc.commands import configcmds
class DefaultCmdSet(cmdset_default.DefaultCmdSet):
key = "DefaultMUX"
def at_cmdset_creation(self):
super(DefaultCmdSet, self).at_cmdset_creation()
self.add(configcmds.ConfigColourCmd())
When adding a new command to a cmdset like this you need to run the
``@reload`` command (or reboot the server). From here on out, your users

View file

@ -51,8 +51,7 @@ 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 all scripts from
``game.gamesrc.scripts.basescript.Script``.
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
@ -79,12 +78,12 @@ 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.
You can create global scripts with ``src.utils.create.create_script()``.
Just don't supply an object to store it on.
You can create global scripts with
``ev.create_script (a shortcut to``\ src.utils.create.create\_script()
::
# adding a global script from src.utils.create import create_script create_script("game.gamesrc.scripts.globals.MyGlobalEconomy", key="economy", obj=None)
). 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.
@ -119,7 +118,7 @@ There is one special property:
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 ``gamesrc/scripts/basescript.py``.
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
@ -153,7 +152,7 @@ possible to also invoke manually)
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 auomatically. ``at_stop()`` will
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
@ -174,7 +173,7 @@ Example script
::
import random
from game.gamesrc.scripts.basescript import Script
from ev import Script
class Weather(Script):
"Displays weather info. Meant to be attached to a room."
def at_script_creation(self):
@ -212,7 +211,7 @@ locate the room you want:
::
from src.utils.create import create_script create_script('game.gamesrc.scripts.weather.Weather', obj=myroom)
from ev import create_script create_script('game.gamesrc.scripts.weather.Weather', obj=myroom)
Or, from in-game, use the ``@script`` command:

View file

@ -3,7 +3,7 @@ On MUX and Softcode: A brief overview
Evennia was originally created in order to provide a MUX/MUSH-style
development environment without the kludgery of softcode. Although it
has since grown to be adaptable to any style of MU``*`` it still ships
has since grown to be adaptable to any style of MU\ ``*`` it still ships
with 'MUX-like' default commands.
This document will provide a quick overview of what softcode is, why it

View file

@ -73,7 +73,7 @@ Resetting
---------
*Resetting* is the equivalent of a "cold reboot" of the server - it will
restart but will behave as it if was fully shut down. You initiate a
restart but will behave as if it was fully shut down. You initiate a
reset using the ``@reset`` command from inside the game. As with a
reload, no players will be disconnected during a shutdown. It will
however purge all non-persistent scripts and will call

View file

@ -24,16 +24,13 @@ storing data they hide underlying database models ...
... and that's basically all you *really* need to know about how
typeclasses work behind the scenes.
To work with them you should however know that Objects, Scripts and
To *work* with them you should however know that Objects, Scripts and
Players all inherit a lot of helper methods from the typeclass system,
properties you can *always* expect a typeclassed entity to have. In
addition to these, each of the three sub types also offer a host of help
methods and properties you can use. The database handling is hidden, but
it means that typeclasses do some special things with their in-built
class methods that you shouldn't edit.
addition to these, each of the three sub types also offer a host of
additional, subtype-specific helper methods and properties for your use.
Properties available to all typeclassed entities (Players, Objects,
Scripts)
Properties available to all typeclassed entities (Players, Objects, Scripts)
----------------------------------------------------------------------------
- ``key`` - the main identifier for the entity, say 'Rose', 'myscript'
@ -65,7 +62,7 @@ more info.
Things to remember when using TypeClasses
-----------------------------------------
Typeclasses mostly behave like normal Python classes - you can
Typeclasses *mostly* behave like normal Python classes - you can
add/overload custom methods and inherit your own classes from them -
most things you'd expect to be able to do with a Python class. There are
a few things that you need to remember however:
@ -182,6 +179,7 @@ Below is a schematic of the database/typeclass structure.
.. figure:: http://d.imagehost.org/0784/typeclasses1.png
:align: center
:alt:
Let's see how object creation looks like in an example.
#. We have defined a Typeclass called *Rose* in
@ -213,9 +211,8 @@ Let's see how object creation looks like in an example.
Storing properties on the typeclass-instance will in fact transparently
save to the database object. So ``RedRose.thorns = True`` is the same as
``RedRose.dbobj.thorns = True`` (note also that depending on your
``FULL_PERSISTENCE`` setting, this may or may not save ``thorns`` as an
`Attribute <Attributes.html>`_ behind the scenes).
``RedRose.dbobj.thorns = True`` (this will in fact be saved in the
database as an attribute "thorns").
Doing ``ouch = RedRose.thorns`` is however not really as symmetric. The
system will in this case *first* check the Typeclass instance and only
@ -228,13 +225,14 @@ are intended to *overload* the default methods on the database object.
These are thus searched and run first, and you can then safely use
``self.dbobj`` from the typeclass to call the original function if you
want. An example of Typeclass overloading is found
`here <CommandPrompt#Prompt%3Ci%3Eon%3C/i%3Ethe%3Ci%3Esame%3C/i%3Eline.html>`_.
`here <CommandPrompt#Prompt<i>on</i>the<i>same</i>line.html>`_.
Another example:
.. figure:: http://b.imagehost.org/0023/typeclasses2.png
:align: center
:alt:
Caveats of the typeclass system
-------------------------------
@ -261,7 +259,7 @@ Even more important to know for Django affectionados: Evennia's custom
methods return *lists* where you with normal Django methods would expect
``Query`` objects (e.g. from the ``filter()`` method). As long as you
don't confuse what result type you are dealing with (for example you
cannot 'link' ``list``s together the way you can ``Querysets``), you
cannot 'link' ``list``\ s together the way you can ``Querysets``), you
should be fine.
Read the ``manager.py`` files in each relevant folder under ``src/`` to

View file

@ -45,12 +45,12 @@ Inside the ``tests.py`` module you create classes inheriting from
used to test a single aspect or component in various ways. Each test
case contains one ore more *test methods* - these define the actual
tests to run. You can name the test methods anything you want as long as
the name starts with "``test_``". Your ``TestCase`` class can also have
a method !SetUp(). This is run before each test, setting up whatever
preparations the test methods need.
the name starts with "``test_``\ ". Your ``TestCase`` class can also
have a method !SetUp(). This is run before each test, setting up
whatever preparations the test methods need.
To test the results, you use special methods of the ``TestCase`` class.
Many of those start with "``assert``", such as ``assertEqual`` or
Many of those start with "``assert``\ ", such as ``assertEqual`` or
``assertTrue``.
Example of a ``TestCase`` class (inside a file ``tests.py``):

View file

@ -62,7 +62,7 @@ components you need to clear the data from all of them:
::
python manage.py reset objects players scripts comms help web auth
python manage.py reset server objects players scripts comms help web auth
Django also offers an easy way to start the database's own management
should we want more direct control:
@ -93,7 +93,7 @@ using the database's command line. This often means adding/removing new
tables or fields as well as possibly convert existing data to match what
the new Evennia version expects. It should be quite obvious that this
quickly becomes cumbersome and error-prone. If your database doesn't
contain anything critical yet i's probably easiest to simply reset it
contain anything critical yet iẗ́'s probably easiest to simply reset it
and start over rather than to bother converting.
Enter `South <http://south.aeracode.org/>`_. South keeps track of

View file

@ -111,7 +111,7 @@ NO\_AUTOCHUNK
Contents are never sent to the client until the encoding mode changes
(for example, switching from HTML to UNENCODED will send the HTML
buffer) or the buffering mode changes (for example, one could set
NO*AUTOCHUNK, send some text, and set NO*AUTOCHUNK again to force a
NO\ *AUTOCHUNK, send some text, and set NO*\ AUTOCHUNK again to force a
flush.
AUTOCHUNK

View file

@ -50,249 +50,249 @@ SMAUG specifics
Code Availability By Lvl
~~~~~~~~~~~~~~~~~~~~~~~~
+-------+---------------------------+
| Lvl | Code Bit |
+-------+---------------------------+
| 0 | spell*disenchant*weapon |
+-------+---------------------------+
| 1 | spell*cause*light |
+-------+---------------------------+
| 1 | dohide |
+-------+---------------------------+
| 1 | spellventriloquate |
+-------+---------------------------+
| 1 | docook |
+-------+---------------------------+
| 1 | doclimb |
+-------+---------------------------+
| 1 | spellnull |
+-------+---------------------------+
| 1 | dopick |
+-------+---------------------------+
| 1 | dosteal |
+-------+---------------------------+
| 1 | dobackstab |
+-------+---------------------------+
| 1 | spellsmaug |
+-------+---------------------------+
| 1 | dokick |
+-------+---------------------------+
| 2 | dodig |
+-------+---------------------------+
| 2 | domount |
+-------+---------------------------+
| 2 | spell*faerie*fire |
+-------+---------------------------+
| 2 | spell*create*food |
+-------+---------------------------+
| 2 | spell*create*water |
+-------+---------------------------+
| 2 | spellweaken |
+-------+---------------------------+
| 2 | spellblackhand |
+-------+---------------------------+
| 3 | doscan |
+-------+---------------------------+
| 3 | dosearch |
+-------+---------------------------+
| 3 | dofeed |
+-------+---------------------------+
| 3 | spell*chill*touch |
+-------+---------------------------+
| 4 | dorescue |
+-------+---------------------------+
| 4 | spellcureblindness |
+-------+---------------------------+
| 4 | spellinvis |
+-------+---------------------------+
| 4 | doaid |
+-------+---------------------------+
| 4 | spellgalvanicwhip |
+-------+---------------------------+
| 5 | spellblindness |
+-------+---------------------------+
| 5 | spell*cause*serious |
+-------+---------------------------+
| 5 | spell*detect*poison |
+-------+---------------------------+
| 5 | spell*burning*hands |
+-------+---------------------------+
| 5 | spell*know*alignment |
+-------+---------------------------+
| 6 | spell*locate*object |
+-------+---------------------------+
| 6 | dotrack |
+-------+---------------------------+
| 6 | spellremoveinvis |
+-------+---------------------------+
| 6 | spellpoison |
+-------+---------------------------+
| 7 | spellearthquake |
+-------+---------------------------+
| 7 | spellshockinggrasp |
+-------+---------------------------+
| 8 | spellteleport |
+-------+---------------------------+
| 8 | dobashdoor |
+-------+---------------------------+
| 8 | spellsummon |
+-------+---------------------------+
| 8 | spell*cure*poison |
+-------+---------------------------+
| 8 | spelldisruption |
+-------+---------------------------+
| 9 | spellbethsaideantouch |
+-------+---------------------------+
| 9 | spellcausecritical |
+-------+---------------------------+
| 9 | spelllightningbolt |
+-------+---------------------------+
| 10 | spellidentify |
+-------+---------------------------+
| 10 | spell*faerie*fog |
+-------+---------------------------+
| 10 | spell*control*weather |
+-------+---------------------------+
| 10 | spell*dispel*evil |
+-------+---------------------------+
| 10 | dodisarm |
+-------+---------------------------+
| 11 | spellcolourspray |
+-------+---------------------------+
| 11 | dobite |
+-------+---------------------------+
| 11 | spell*dispel*magic |
+-------+---------------------------+
| 11 | dobloodlet |
+-------+---------------------------+
| 12 | spellsleep |
+-------+---------------------------+
| 12 | spellcurse |
+-------+---------------------------+
| 12 | spellcalllightning |
+-------+---------------------------+
| 12 | spellremovecurse |
+-------+---------------------------+
| 12 | spellenchantweapon |
+-------+---------------------------+
| 12 | spellword*of*recall |
+-------+---------------------------+
| 13 | spellharm |
+-------+---------------------------+
| 13 | spellfireball |
+-------+---------------------------+
| 13 | spellexpurgation |
+-------+---------------------------+
| 13 | spellflamestrike |
+-------+---------------------------+
| 13 | spell*midas*touch |
+-------+---------------------------+
| 13 | spell*energy*drain |
+-------+---------------------------+
| 14 | spell*spectral*furor |
+-------+---------------------------+
| 14 | spell*charm*person |
+-------+---------------------------+
| 15 | spell*remove*trap |
+-------+---------------------------+
| 16 | spellfarsight |
+-------+---------------------------+
| 16 | dodetrap |
+-------+---------------------------+
| 17 | spelltransport |
+-------+---------------------------+
| 17 | spelldream |
+-------+---------------------------+
| 18 | spell*sulfurous*spray |
+-------+---------------------------+
| 18 | spell*pass*door |
+-------+---------------------------+
| 19 | spell*sonic*resonance |
+-------+---------------------------+
| 20 | dogouge |
+-------+---------------------------+
| 20 | spellacidblast |
+-------+---------------------------+
| 21 | spellportal |
+-------+---------------------------+
| 23 | spell*black*fist |
+-------+---------------------------+
| 25 | dopunch |
+-------+---------------------------+
| 25 | docircle |
+-------+---------------------------+
| 25 | dobrew |
+-------+---------------------------+
| 27 | spellmagneticthrust |
+-------+---------------------------+
| 27 | dopoisonweapon |
+-------+---------------------------+
| 28 | spellscorchingsurge |
+-------+---------------------------+
| 30 | doscribe |
+-------+---------------------------+
| 30 | dobash |
+-------+---------------------------+
| 30 | spellastralwalk |
+-------+---------------------------+
| 31 | domistwalk |
+-------+---------------------------+
| 32 | spell*ethereal*fist |
+-------+---------------------------+
| 32 | spellknock |
+-------+---------------------------+
| 33 | spellrecharge |
+-------+---------------------------+
| 34 | spell*caustic*fount |
+-------+---------------------------+
| 35 | spell*sacral*divinity |
+-------+---------------------------+
| 35 | spell*plant*pass |
+-------+---------------------------+
| 37 | spell*hand*ofchaos |
+-------+---------------------------+
| 37 | spellacetumprimus |
+-------+---------------------------+
| 39 | spellsolarflight |
+-------+---------------------------+
| 41 | dobroach |
+-------+---------------------------+
| 41 | spell*frost*breath |
+-------+---------------------------+
| 42 | spell*helical*flow |
+-------+---------------------------+
| 42 | spell*animate*dead |
+-------+---------------------------+
| 42 | spell*lightning*breath |
+-------+---------------------------+
| 43 | spell*acid*breath |
+-------+---------------------------+
| 44 | spell*fire*breath |
+-------+---------------------------+
| 45 | spell*gas*breath |
+-------+---------------------------+
| 46 | spell*spiral*blast |
+-------+---------------------------+
| 46 | spell*black*lightning |
+-------+---------------------------+
| 48 | dostun |
+-------+---------------------------+
| 48 | spellquantumspike |
+-------+---------------------------+
| 50 | dohitall |
+-------+---------------------------+
| 51 | spellpossess |
+-------+---------------------------+
| 51 | spellchangesex |
+-------+---------------------------+
| 51 | spellgate |
+-------+---------------------------+
| 51 | doslice |
+-------+---------------------------+
| 51 | spellpolymorph |
+-------+---------------------------+
| 51 | do\_berserk |
+-------+---------------------------+
+-------+-------------------------------+
| Lvl | Code Bit |
+-------+-------------------------------+
| 0 | spell\ *disenchant*\ weapon |
+-------+-------------------------------+
| 1 | spell\ *cause*\ light |
+-------+-------------------------------+
| 1 | dohide |
+-------+-------------------------------+
| 1 | spellventriloquate |
+-------+-------------------------------+
| 1 | docook |
+-------+-------------------------------+
| 1 | doclimb |
+-------+-------------------------------+
| 1 | spellnull |
+-------+-------------------------------+
| 1 | dopick |
+-------+-------------------------------+
| 1 | dosteal |
+-------+-------------------------------+
| 1 | dobackstab |
+-------+-------------------------------+
| 1 | spellsmaug |
+-------+-------------------------------+
| 1 | dokick |
+-------+-------------------------------+
| 2 | dodig |
+-------+-------------------------------+
| 2 | domount |
+-------+-------------------------------+
| 2 | spell\ *faerie*\ fire |
+-------+-------------------------------+
| 2 | spell\ *create*\ food |
+-------+-------------------------------+
| 2 | spell\ *create*\ water |
+-------+-------------------------------+
| 2 | spellweaken |
+-------+-------------------------------+
| 2 | spellblackhand |
+-------+-------------------------------+
| 3 | doscan |
+-------+-------------------------------+
| 3 | dosearch |
+-------+-------------------------------+
| 3 | dofeed |
+-------+-------------------------------+
| 3 | spell\ *chill*\ touch |
+-------+-------------------------------+
| 4 | dorescue |
+-------+-------------------------------+
| 4 | spellcureblindness |
+-------+-------------------------------+
| 4 | spellinvis |
+-------+-------------------------------+
| 4 | doaid |
+-------+-------------------------------+
| 4 | spellgalvanicwhip |
+-------+-------------------------------+
| 5 | spellblindness |
+-------+-------------------------------+
| 5 | spell\ *cause*\ serious |
+-------+-------------------------------+
| 5 | spell\ *detect*\ poison |
+-------+-------------------------------+
| 5 | spell\ *burning*\ hands |
+-------+-------------------------------+
| 5 | spell\ *know*\ alignment |
+-------+-------------------------------+
| 6 | spell\ *locate*\ object |
+-------+-------------------------------+
| 6 | dotrack |
+-------+-------------------------------+
| 6 | spellremoveinvis |
+-------+-------------------------------+
| 6 | spellpoison |
+-------+-------------------------------+
| 7 | spellearthquake |
+-------+-------------------------------+
| 7 | spellshockinggrasp |
+-------+-------------------------------+
| 8 | spellteleport |
+-------+-------------------------------+
| 8 | dobashdoor |
+-------+-------------------------------+
| 8 | spellsummon |
+-------+-------------------------------+
| 8 | spell\ *cure*\ poison |
+-------+-------------------------------+
| 8 | spelldisruption |
+-------+-------------------------------+
| 9 | spellbethsaideantouch |
+-------+-------------------------------+
| 9 | spellcausecritical |
+-------+-------------------------------+
| 9 | spelllightningbolt |
+-------+-------------------------------+
| 10 | spellidentify |
+-------+-------------------------------+
| 10 | spell\ *faerie*\ fog |
+-------+-------------------------------+
| 10 | spell\ *control*\ weather |
+-------+-------------------------------+
| 10 | spell\ *dispel*\ evil |
+-------+-------------------------------+
| 10 | dodisarm |
+-------+-------------------------------+
| 11 | spellcolourspray |
+-------+-------------------------------+
| 11 | dobite |
+-------+-------------------------------+
| 11 | spell\ *dispel*\ magic |
+-------+-------------------------------+
| 11 | dobloodlet |
+-------+-------------------------------+
| 12 | spellsleep |
+-------+-------------------------------+
| 12 | spellcurse |
+-------+-------------------------------+
| 12 | spellcalllightning |
+-------+-------------------------------+
| 12 | spellremovecurse |
+-------+-------------------------------+
| 12 | spellenchantweapon |
+-------+-------------------------------+
| 12 | spellword\ *of*\ recall |
+-------+-------------------------------+
| 13 | spellharm |
+-------+-------------------------------+
| 13 | spellfireball |
+-------+-------------------------------+
| 13 | spellexpurgation |
+-------+-------------------------------+
| 13 | spellflamestrike |
+-------+-------------------------------+
| 13 | spell\ *midas*\ touch |
+-------+-------------------------------+
| 13 | spell\ *energy*\ drain |
+-------+-------------------------------+
| 14 | spell\ *spectral*\ furor |
+-------+-------------------------------+
| 14 | spell\ *charm*\ person |
+-------+-------------------------------+
| 15 | spell\ *remove*\ trap |
+-------+-------------------------------+
| 16 | spellfarsight |
+-------+-------------------------------+
| 16 | dodetrap |
+-------+-------------------------------+
| 17 | spelltransport |
+-------+-------------------------------+
| 17 | spelldream |
+-------+-------------------------------+
| 18 | spell\ *sulfurous*\ spray |
+-------+-------------------------------+
| 18 | spell\ *pass*\ door |
+-------+-------------------------------+
| 19 | spell\ *sonic*\ resonance |
+-------+-------------------------------+
| 20 | dogouge |
+-------+-------------------------------+
| 20 | spellacidblast |
+-------+-------------------------------+
| 21 | spellportal |
+-------+-------------------------------+
| 23 | spell\ *black*\ fist |
+-------+-------------------------------+
| 25 | dopunch |
+-------+-------------------------------+
| 25 | docircle |
+-------+-------------------------------+
| 25 | dobrew |
+-------+-------------------------------+
| 27 | spellmagneticthrust |
+-------+-------------------------------+
| 27 | dopoisonweapon |
+-------+-------------------------------+
| 28 | spellscorchingsurge |
+-------+-------------------------------+
| 30 | doscribe |
+-------+-------------------------------+
| 30 | dobash |
+-------+-------------------------------+
| 30 | spellastralwalk |
+-------+-------------------------------+
| 31 | domistwalk |
+-------+-------------------------------+
| 32 | spell\ *ethereal*\ fist |
+-------+-------------------------------+
| 32 | spellknock |
+-------+-------------------------------+
| 33 | spellrecharge |
+-------+-------------------------------+
| 34 | spell\ *caustic*\ fount |
+-------+-------------------------------+
| 35 | spell\ *sacral*\ divinity |
+-------+-------------------------------+
| 35 | spell\ *plant*\ pass |
+-------+-------------------------------+
| 37 | spell\ *hand*\ ofchaos |
+-------+-------------------------------+
| 37 | spellacetumprimus |
+-------+-------------------------------+
| 39 | spellsolarflight |
+-------+-------------------------------+
| 41 | dobroach |
+-------+-------------------------------+
| 41 | spell\ *frost*\ breath |
+-------+-------------------------------+
| 42 | spell\ *helical*\ flow |
+-------+-------------------------------+
| 42 | spell\ *animate*\ dead |
+-------+-------------------------------+
| 42 | spell\ *lightning*\ breath |
+-------+-------------------------------+
| 43 | spell\ *acid*\ breath |
+-------+-------------------------------+
| 44 | spell\ *fire*\ breath |
+-------+-------------------------------+
| 45 | spell\ *gas*\ breath |
+-------+-------------------------------+
| 46 | spell\ *spiral*\ blast |
+-------+-------------------------------+
| 46 | spell\ *black*\ lightning |
+-------+-------------------------------+
| 48 | dostun |
+-------+-------------------------------+
| 48 | spellquantumspike |
+-------+-------------------------------+
| 50 | dohitall |
+-------+-------------------------------+
| 51 | spellpossess |
+-------+-------------------------------+
| 51 | spellchangesex |
+-------+-------------------------------+
| 51 | spellgate |
+-------+-------------------------------+
| 51 | doslice |
+-------+-------------------------------+
| 51 | spellpolymorph |
+-------+-------------------------------+
| 51 | do\_berserk |
+-------+-------------------------------+
+ the affects they apply float, sneak, hide, detect invisibility, detect
magic, detect evil, invisibility

View file

@ -1,4 +1,3 @@
"""
This package contains all default commands of Evennia, grouped after category.
"""