mirror of
https://github.com/evennia/evennia.git
synced 2026-04-01 05:27:17 +02:00
Updated ReST documentation.
This commit is contained in:
parent
36b15b4ad8
commit
a8139feb1a
37 changed files with 963 additions and 910 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-----
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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*!
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
--------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-----
|
||||
|
|
|
|||
|
|
@ -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``
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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>`_
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>, ...]
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)``.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
======================================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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``\ ".
|
||||
|
||||
::
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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``):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
"""
|
||||
This package contains all default commands of Evennia, grouped after category.
|
||||
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue