Added Sphinx (reST-style) conversion of Evennia documentation to docs/. This is an auto-generated conversion directly from the Wiki, so it's not custom-written in any way (will also make it easy to update). You need Sphinx to compile the sources into fancy pages. Supporting sphinx is to make documentation easier to print and view offline. Currently no sphinx src-code viewing is activated by default, it gives too many spurious errors (the converters are in the repo though if you're interested in experimenting). So for offline autodocs, doxygen is still to recommend.

This commit is contained in:
Griatch 2011-09-10 23:44:49 +02:00
parent 5a2b9e27a0
commit bd0079a39d
65 changed files with 9394 additions and 143 deletions

9
.hgignore Normal file
View file

@ -0,0 +1,9 @@
# This specifies file types that mercurial should
# ignore, defined on glob format.
syntax: glob
*.pyc
*.swp
*~
*#

80
README
View file

@ -1,27 +1,10 @@
Evennia README (http://evennia.com)
--------------
-----------------------------------
Evennia README
(http://evennia.com)
Alpha hg (mercurial) version
-----------------------------------
- Aug 2011 - split evennia into portal + server for better reload /Griatch
- May 2011 - all commands implemented, web client, contribs /Griatch
- Aug 2010 - evennia devel merged into trunk /Griatch
- May 2010 - merged ABOUT and README. Added Current status /Griatch
- < 2010 (earlier revisions)
Contents:
---------
- Version
- About Evennia
- Current Status
- Contact, Support and Development
- Directory structure
- Design Objectives
- The Components
Version
-------
Evennia Alpha SVN version
About Evennia
-------------
@ -37,8 +20,7 @@ bare-bones base for developers. Some of our main features are:
(djangoproject.com)
* Powerful an extremely extendable bare-bones base system
The essential points here are the web integration and the SQL backing via
Django. The Django framework has database abstraction abilities that give us
The Django framework has database abstraction abilities that give us
many features free, such as:
* The codebase will run transparently on MySQL, SQLite, or Postgres
@ -90,7 +72,7 @@ will not be backwards compatabile. Changes touch almost all
parts of Evennia's innards, from the way Objects are handled
to Events, Commands and Permissions.
(Earlier revisions, with other maintainer, go back to 2005)
Contact, Support and Development
@ -132,7 +114,7 @@ evennia
The two main directories you will spend most of your time in
are src/ and game/ (probably mostly game/).
Basically src contains everything related to
Basically src/ contains everything related to
running the gritty stuff behind the scenes. Unless you are an
Evennia developer you should normally make sure never to edit
things in src/, since this is where we push new revisions that
@ -156,49 +138,3 @@ and use them.
With this little first orientation, you should head into the online
Evennia wiki documentation to get going with the codebase.
Design Objectives
-----------------
1) To create a barebones MU* server that serves as a great foundation
for capable admins to craft their own respective games. It is not the
intention to provide a full-fledged, ready-to-run base, rather Evennia
is offering the means to make such games.
2) Development of games on Evennia must be easy for anyone with some
degree of Python experience. Building needs to be easy, and per-room,
per-object, and environmental customizations need to be simple to
do. This is handled by use of normal Python classes transparently
abstracting and wrapping the SQL backend. The user should not need to
use SQL or even know Django to any greater extent.
3) The server must utilize SQL as a storage back-end to allow for web->game
integration through Django.
The Components
--------------
Python (Including the SQL driver of your choice)
|-Twisted (http://twistedmatrix.com)
|-SQL (MySQL, SQLite, Postgresql)
|-Django (http://djangoproject.com)
Evennia is built on top of Twisted, a networking engine that handles a lot
of the guts and lower-level socket stuff for us.
Serving as our storage medium, SQL allows for very simple code in many cases, and
can lead to a game being a lot more scalable due to the inherent speed of
most modern SQL servers. Another extremely important benefit is that by
storing everything in SQL, we make the entire game accessible from other
means, such as a website. Which leads us to the next component.
Django is perhaps one of the most interesting introductions to the codebase.
Django is technically a Python web framework, but it also includes a great
data modeling and database abstraction module. This means that things like
Players or Objects can be represented by a very short class, then related to one
another. This allows us to add, remove, delete, and manipulate things in our database
very easily. Another huge benefit is the admin interface that Django more
or less automatically generates for us. Instead of a bunch of clunky admin
commands, you can fire up your web browser and administer pretty much
everything from there, although equivalent in-game commands may be offered.
The possibilities for developing your game's website are nearly endless with
this tandem of MU* server, SQL, and Django.

View file

@ -1 +1 @@
SVN-Alpha
HG-Alpha

View file

@ -1,6 +1,7 @@
===========
DOCS README
-----------
===========
* Evennia docs and manual
@ -17,9 +18,44 @@ DOCS README
#evennia on the Freenode network
* Evennia source auto-docs
------------------------
* Sphinx Manuals
------------------------
The folder docs/sphinx contains a source tree with Evennia's online wiki
formatted into reStructuredText for easy (and good looking!) offline
browsing or printing.
To build the sources you need to install Sphinx. Linux users can get it
through their package managers (in Debian it's called python-sphinx). Or
you can download it here:
http://sphinx.pocoo.org/index.html
Go into docs/sphinx and run
make html
You will see a lot of output (and probably some errors too, Evennia's docs
are not formatted to reST format by default). When done, point your
web browser to docs/sphinx/build/html/index.html to see the nice manual.
In this folder you can build the developer auto-docs
If you don't want html output, you can output to a host of other formats,
use just "make" for a list of options.
Note: In docs/sphinx are two more dirs, wiki2rest and src2rest. These
can be used to create reST-formatted documentation from raw sources.
They depend on a host of external libraries however, so best stay away
from them unless you are an Evennia dev. Read the headers of the
respective *.py files for instructions.
-------------------
* Doxygen auto-docs
-------------------
In docs/doxygen you can build the developer auto-docs
(a fancy searchable index of the entire source tree).
This makes use of doxygen, a doc generator that parses
the source tree and creates docs on the fly.
@ -32,16 +68,16 @@ DOCS README
- Run
> doxygen Doxyfile
> doxygen config.dox
This will create the auto-docs in a folder 'html'.
This will create the auto-docs in a folder 'doxygen/html'.
- Start your web browser and point it to
<evenniadir>/docs/html/index.html
<evenniadir>/docs/doxygen/html/index.html
- If you prefer a pdf version for printing, use LaTeX by
activating the relevant section in Doxyfile. Run the
activating the relevant section in config.dox. Run the
doxygen command again as above and a new folder 'latex'
will be created with the latex sources. With the latex
processing system installed, then run

View file

@ -1,14 +1,14 @@
# Doxyfile 1.7.1
# Doxyfile 1.7.4
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project
# doxygen (www.doxygen.org) for a project.
#
# All text after a hash (#) is considered a comment and will be ignored
# All text after a hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (" ")
# Values that contain spaces should be placed between quotes (" ").
#---------------------------------------------------------------------------
# Project related configuration options
@ -33,6 +33,19 @@ PROJECT_NAME = Evennia
PROJECT_NUMBER = SVN-Alpha
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
# a quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = Python MUD server
# With the PROJECT_LOGO tag one can specify an logo or icon that is
# included in the documentation. The maximum height of the logo should not
# exceed 55 pixels and the maximum width should not exceed 200 pixels.
# Doxygen will copy the logo to the output directory.
PROJECT_LOGO = ../../src/web/media/images/evennia_logo_small.png
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
# If a relative path is entered, it will be relative to the location
@ -57,7 +70,7 @@ CREATE_SUBDIRS = YES
# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
OUTPUT_LANGUAGE = English
@ -86,7 +99,7 @@ REPEAT_BRIEF = YES
# "The $name file" "is" "provides" "specifies" "contains"
# "represents" "a" "an" "the"
ABBREVIATE_BRIEF =
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
@ -114,7 +127,7 @@ FULL_PATH_NAMES = NO
# If left blank the directory from which doxygen is run is used as the
# path to strip.
STRIP_FROM_PATH =
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@ -126,7 +139,7 @@ STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful is your file systems
# (but less readable) file names. This can be useful if your file system
# doesn't support long names like on DOS, Mac, or CD-ROM.
SHORT_NAMES = NO
@ -193,7 +206,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
# Java. For instance, namespaces will be presented as packages, qualified
# scopes will look different, etc.
OPTIMIZE_OUTPUT_JAVA = YES
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources only. Doxygen will then generate output that is more tailored for
@ -223,7 +236,7 @@ EXTENSION_MAPPING =
# to include (a tag file for) the STL sources as input, then you should
# set this tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
# func(std::string) {}). This also make the inheritance and collaboration
# func(std::string) {}). This also makes the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
BUILTIN_STL_SUPPORT = NO
@ -241,7 +254,7 @@ SIP_SUPPORT = NO
# For Microsoft's IDL there are propget and propput attributes to indicate getter
# and setter methods for a property. Setting this option to YES (the default)
# will make doxygen to replace the get and set methods by a property in the
# will make doxygen replace the get and set methods by a property in the
# documentation. This will only work if the methods are indeed getting or
# setting a simple type. If this is not the case, or you want to show the
# methods anyway, you should set this option to NO.
@ -263,6 +276,13 @@ DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
# unions are shown inside the group in which they are included (e.g. using
# @ingroup) instead of on a separate page (for HTML and Man pages) or
# section (for LaTeX and RTF).
INLINE_GROUPED_CLASSES = NO
# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
# is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
@ -279,10 +299,10 @@ TYPEDEF_HIDES_STRUCT = NO
# For small to medium size projects (<1000 input files) the default value is
# probably good enough. For larger projects a too small cache size can cause
# doxygen to be busy swapping symbols to and from disk most of the time
# causing a significant performance penality.
# causing a significant performance penalty.
# If the system has enough physical memory increasing the cache will improve the
# performance by keeping more symbols in memory. Note that the value works on
# a logarithmic scale so increasing the size by one will rougly double the
# a logarithmic scale so increasing the size by one will roughly double the
# memory usage. The cache size is given by this formula:
# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
# corresponding to a cache size of 2^16 = 65536 symbols
@ -327,7 +347,7 @@ EXTRACT_LOCAL_METHODS = NO
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base
# name of the file that contains the anonymous namespace. By default
# anonymous namespace are hidden.
# anonymous namespaces are hidden.
EXTRACT_ANON_NSPACES = NO
@ -337,14 +357,14 @@ EXTRACT_ANON_NSPACES = NO
# various overviews, but no documentation section is generated.
# This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy.
# If set to NO (the default) these classes will be included in the various
# overviews. This option has no effect if EXTRACT_ALL is enabled.
HIDE_UNDOC_CLASSES = YES
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
# friend (class|struct|union) declarations.
@ -403,7 +423,7 @@ INLINE_INFO = YES
# alphabetically by member name. If set to NO the members will appear in
# declaration order.
SORT_MEMBER_DOCS = NO
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
# brief documentation of file, namespace and class members alphabetically
@ -438,6 +458,15 @@ SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
# do proper type resolution of all parameters of a function it will reject a
# match between the prototype and the implementation of a member function even
# if there is only one candidate or it is obvious which candidate to choose
# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
# will still accept a match between prototype and implementation in such cases.
STRICT_PROTO_MATCHING = NO
# The GENERATE_TODOLIST tag can be used to enable (YES) or
# disable (NO) the todo list. This list is created by putting \todo
# commands in the documentation.
@ -468,10 +497,10 @@ GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
# the initial value of a variable or define consists of for it to appear in
# the initial value of a variable or macro consists of for it to appear in
# the documentation. If the initializer consists of more lines than specified
# here it will be hidden. Use a value of 0 to hide initializers completely.
# The appearance of the initializer of individual variables and defines in the
# The appearance of the initializer of individual variables and macros in the
# documentation can be controlled using \showinitializer or \hideinitializer
# command in the documentation regardless of this setting.
@ -487,7 +516,7 @@ SHOW_USED_FILES = YES
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
# in the documentation. The default is NO.
SHOW_DIRECTORIES = YES
SHOW_DIRECTORIES = NO
# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
# This will remove the Files entry from the Quick Index and from the
@ -549,7 +578,7 @@ WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be abled to get warnings for
# The WARN_NO_PARAMDOC option can be enabled to get warnings for
# functions that are documented, but have no documentation for their parameters
# or return value. If set to NO (the default) doxygen will only warn about
# wrong or incomplete parameter documentation, but not about the absence of
@ -581,7 +610,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = ../
INPUT = ../../
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@ -595,10 +624,11 @@ INPUT_ENCODING = UTF-8
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
# and *.h) to filter out the source-files in the directories. If left
# blank the following patterns are tested:
# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
FILE_PATTERNS =
FILE_PATTERNS = *.py
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@ -610,10 +640,10 @@ RECURSIVE = YES
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = docs
EXCLUDE = docs */migrate/
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
EXCLUDE_SYMLINKS = NO
@ -624,7 +654,7 @@ EXCLUDE_SYMLINKS = NO
# against the file with absolute path, so to exclude all test directories
# for example use the pattern */test/*
EXCLUDE_PATTERNS =
EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
@ -677,8 +707,8 @@ INPUT_FILTER =
# filter if there is a match.
# The filters are a list of the form:
# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
# is applied to all files.
# info on how filters are used. If FILTER_PATTERNS is empty or if
# non of the patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
@ -688,6 +718,14 @@ FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
# and it is also possible to disable source filtering for a specific pattern
# using *.ext= (so without naming a filter). This option only has effect when
# FILTER_SOURCE_FILES is enabled.
FILTER_SOURCE_PATTERNS =
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
@ -697,12 +735,12 @@ FILTER_SOURCE_FILES = NO
# Note: To get rid of all source code in the generated output, make sure also
# VERBATIM_HEADERS is set to NO.
SOURCE_BROWSER = YES
SOURCE_BROWSER = NO
# Setting the INLINE_SOURCES tag to YES will include the body
# of functions and classes directly in the documentation.
INLINE_SOURCES = YES
INLINE_SOURCES = NO
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
# doxygen to hide any special comment blocks from generated source code
@ -714,13 +752,13 @@ STRIP_CODE_COMMENTS = YES
# then for each documented function all documented
# functions referencing it will be listed.
REFERENCED_BY_RELATION = YES
REFERENCED_BY_RELATION = NO
# If the REFERENCES_RELATION tag is set to YES
# then for each documented function all documented entities
# called/used by that function will be listed.
REFERENCES_RELATION = YES
REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
@ -790,7 +828,13 @@ HTML_FILE_EXTENSION = .html
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
# standard header.
# standard header. Note that when using a custom header you are responsible
# for the proper inclusion of any scripts and style sheets that doxygen
# needs, which is dependent on the configuration options used.
# It is adviced to generate a default header using "doxygen -w html
# header.html footer.html stylesheet.css YourConfigFile" and then modify
# that header. Note that the header is subject to change so you typically
# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW!
HTML_HEADER =
@ -809,6 +853,15 @@ HTML_FOOTER =
HTML_STYLESHEET =
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that
# the files will be copied as-is; there are no commands or markers available.
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
# Doxygen will adjust the colors in the stylesheet and background images
# according to this color. Hue is specified as an angle on a colorwheel,
@ -852,7 +905,7 @@ HTML_ALIGN_MEMBERS = YES
# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
HTML_DYNAMIC_SECTIONS = YES
HTML_DYNAMIC_SECTIONS = NO
# If the GENERATE_DOCSET tag is set to YES, additional index files
# will be generated that can be used as input for Apple's Xcode 3
@ -889,7 +942,7 @@ DOCSET_PUBLISHER_ID = org.doxygen.Publisher
# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
DOCSET_PUBLISHER_NAME = Evennia development team
DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
# will be generated that can be used as input for tools like the
@ -1011,8 +1064,10 @@ ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
# This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
# (range [0,1..20]) that doxygen will group on one line in the generated HTML
# documentation. Note that a value of 0 will completely suppress the enum
# values from appearing in the overview section.
ENUM_VALUES_PER_LINE = 4
@ -1029,7 +1084,7 @@ GENERATE_TREEVIEW = NO
# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
# and Class Hierarchy pages using a tree view instead of an ordered list.
USE_INLINE_TREES = YES
USE_INLINE_TREES = NO
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
# used to set the initial width (in pixels) of the frame in which the tree
@ -1058,6 +1113,26 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
# (see http://www.mathjax.org) which uses client side Javascript for the
# rendering instead of using prerendered bitmaps. Use this if you do not
# have LaTeX installed or if you want to formulas look prettier in the HTML
# output. When enabled you also need to install MathJax separately and
# configure the path to it using the MATHJAX_RELPATH option.
USE_MATHJAX = NO
# When MathJax is enabled you need to specify the location relative to the
# HTML output directory using the MATHJAX_RELPATH option. The destination
# directory should contain the MathJax.js script. For instance, if the mathjax
# directory is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to the
# mathjax.org site, so you can quickly see the result without installing
# MathJax, but it is strongly recommended to install a local copy of MathJax
# before deployment.
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
# When the SEARCHENGINE tag is enabled doxygen will generate a search box
# for the HTML output. The underlying search engine uses javascript
# and DHTML and should work on any modern browser. Note that when using
@ -1073,7 +1148,7 @@ SEARCHENGINE = YES
# using Javascript. Doxygen will generate the search PHP script and index
# file to put on the web server. The advantage of the server
# based approach is that it scales better to large projects and allows
# full text search. The disadvances is that it is more difficult to setup
# full text search. The disadvantages are that it is more difficult to setup
# and does not have live searching capabilities.
SERVER_BASED_SEARCH = NO
@ -1114,10 +1189,10 @@ MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper type that is used
# by the printer. Possible values are: a4, a4wide, letter, legal and
# by the printer. Possible values are: a4, letter, legal and
# executive. If left blank a4wide will be used.
PAPER_TYPE = a4wide
PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
# packages that should be included in the LaTeX output.
@ -1131,6 +1206,13 @@ EXTRA_PACKAGES =
LATEX_HEADER =
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
# the generated latex document. The footer should contain everything after
# the last chapter. If it is left blank doxygen will generate a
# standard footer. Notice: only use this tag if you know what you are doing!
LATEX_FOOTER =
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
# contain links (just like the HTML output) instead of page references
@ -1340,7 +1422,7 @@ MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
# in the INCLUDE_PATH (see below) will be search if a #include is found.
# pointed to by INCLUDE_PATH will be searched when a #include is found.
SEARCH_INCLUDES = YES
@ -1370,15 +1452,15 @@ PREDEFINED =
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
# Use the PREDEFINED tag if you want to use a different macro definition.
# Use the PREDEFINED tag if you want to use a different macro definition that
# overrules the definition found in the source code.
EXPAND_AS_DEFINED =
# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
# doxygen's preprocessor will remove all function-like macros that are alone
# on a line, have an all uppercase name, and do not end with a semicolon. Such
# function macros are typically used for boiler-plate code, and will confuse
# the parser if not removed.
# doxygen's preprocessor will remove all references to function-like macros
# that are alone on a line, have an all uppercase name, and do not end with a
# semicolon, because these will confuse the parser if not removed.
SKIP_FUNCTION_MACROS = YES
@ -1434,9 +1516,8 @@ PERL_PATH = /usr/bin/perl
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
# or super classes. Setting the tag to NO turns the diagrams off. Note that
# this option is superseded by the HAVE_DOT option below. This is only a
# fallback. It is recommended to install and use dot, since it yields more
# powerful graphs.
# this option also works with HAVE_DOT disabled, but it is recommended to
# install and use dot, since it yields more powerful graphs.
CLASS_DIAGRAMS = YES
@ -1470,16 +1551,15 @@ HAVE_DOT = NO
DOT_NUM_THREADS = 0
# By default doxygen will write a font called FreeSans.ttf to the output
# directory and reference it in all dot files that doxygen generates. This
# font does not include all possible unicode characters however, so when you need
# these (or just want a differently looking font) you can specify the font name
# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
# By default doxygen will write a font called Helvetica to the output
# directory and reference it in all dot files that doxygen generates.
# When you want a differently looking font you can specify the font name
# using DOT_FONTNAME. You need to make sure dot is able to find the font,
# which can be done by putting it in a standard location or by setting the
# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
# containing the font.
DOT_FONTNAME = FreeSans.ttf
DOT_FONTNAME = Helvetica
# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
# The default size is 10pt.
@ -1554,7 +1634,7 @@ CALL_GRAPH = NO
CALLER_GRAPH = NO
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
# will graphical hierarchy of all classes instead of a textual one.
# will generate a graphical hierarchy of all classes instead of a textual one.
GRAPHICAL_HIERARCHY = YES
@ -1566,7 +1646,7 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. Possible values are png, jpg, or gif
# generated by dot. Possible values are svg, png, jpg, or gif.
# If left blank png will be used.
DOT_IMAGE_FORMAT = png
@ -1582,6 +1662,12 @@ DOT_PATH =
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the
# \mscfile command).
MSCFILE_DIRS =
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
# nodes that will be shown in the graph. If the number of nodes in a graph
# becomes larger than this value, doxygen will truncate the graph, which is

View file

@ -1,3 +0,0 @@
twisted>=10.0
django>=1.2.1
PIL

130
docs/sphinx/Makefile Normal file
View file

@ -0,0 +1,130 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Evennia.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Evennia.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Evennia"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Evennia"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

170
docs/sphinx/make.bat Normal file
View file

@ -0,0 +1,170 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Evennia.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Evennia.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

220
docs/sphinx/source/conf.py Normal file
View file

@ -0,0 +1,220 @@
# -*- coding: utf-8 -*-
#
# Evennia documentation build configuration file, created by
# sphinx-quickstart on Sat Sep 10 14:19:20 2011.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
EVENNIA_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
sys.path.insert(0, EVENNIA_ROOT)
sys.path.insert(0, os.path.dirname(EVENNIA_ROOT)) # also import top container
os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings'
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['.templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Evennia'
copyright = u'2011, Evennia-development team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = 'Alpha'
# The full version, including alpha/beta/rc tags.
release = 'Alpha'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['.static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'Evenniadoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'Evennia.tex', u'Evennia Documentation',
u'Evennia-devs', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'evennia', u'Evennia Documentation',
[u'Evennia-devs'], 1)
]

View file

@ -0,0 +1,84 @@
.. Evennia documentation master file, created by
sphinx-quickstart on Sat Sep 10 14:19:20 2011.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Evennia's documentation!
===================================
This is `Evennia <http://www.evennia.com>`_'s sphinx-based
documentation. It is built from the `online wiki <http://code.google.com/p/evennia/wiki/Index?tm=6>`_ at regular
intervals.
Text documentation
-------------------
.. toctree::
:titlesonly:
Manual <wiki/Index>
How to give and get help <wiki/HowToGetAndGiveHelp>
Evennia Links <wiki/Links>
.. Code
.. -----
.. .. toctree::
.. :titlesonly:
.. Browse Code <code/modules>
.. toctree::
:hidden:
wiki/Index
wiki/EvenniaIntroduction
wiki/SoftCode
wiki/GettingStarted
wiki/AdminDocs
wiki/ChoosingAnSQLServer
wiki/StartStopReload
wiki/UpdatingYourGame
wiki/Internationalization
wiki/StaffVersionControl
wiki/ApacheConfig
wiki/TextEncodings
wiki/IRC
wiki/IMC2
wiki/BuilderDocs
wiki/DefaultCommandHelp
wiki/BuildingQuickstart
wiki/BuildingPermissions
wiki/Colours
wiki/ConnectionScreen
wiki/BatchProcessors
wiki/BatchCommandProcessor
wiki/BatchCodeProcessor
wiki/TutorialWorldIntroduction
wiki/DeveloperCentral
wiki/Licensing
wiki/Contributing
wiki/UsingMUXAsAStandard
wiki/BazaarDevel
wiki/DirectoryOverview
wiki/PortalAndServer
wiki/Commands
wiki/Typeclasses
wiki/Objects
wiki/Scripts
wiki/Players
wiki/Attributes
wiki/Locks
wiki/Communications
wiki/HelpSystem
wiki/Nicks
wiki/SessionProtocols
wiki/WebFeatures
wiki/ExecutePythonCode
wiki/UnitTesting
wiki/RemovingColour
wiki/CommandPrompt
wiki/AsyncProcess
wiki/WorkshopDefaultGame
wiki/Workshop
wiki/EvenniaDevel

View file

@ -0,0 +1,30 @@
Administrative Documentation
============================
The following pages are aimed at game administrators. These are defined
as the higher-ups that possess shell access and/or are responsible for
the game.
Installation and Early Life
---------------------------
- `Choosing an SQL Server <ChoosingAnSQLServer.html>`_
- `Getting Started - Installing Evennia <GettingStarted.html>`_
- `Starting, stopping, restarting and resetting
Evennia <StartStopReload.html>`_
- `Keeping your game up to date <UpdatingYourGame.html>`_
- `Change Evennia's language <Internationalization.html>`_
<wiki:comment>
- `Collaborate with others using version
control <StaffVersionControl.html>`_
</wiki:comment>
- `Apache Configuration <ApacheConfig.html>`_ (optional)
- `Text encodings <TextEncodings.html>`_ used when connecting to
Evennia
- `How to connect Evennia to IRC channels <IRC.html>`_
- `How to connect Evennia to an IMC2 network <IMC2.html>`_

View file

@ -0,0 +1,117 @@
Apache Configuration
====================
*OBS: Evennia has a powerful in-built Twisted-based web server for
handling all web features. This works out of the box without any special
setup. This page is only of interest if you really want/need to run
Apache instead Evennia's in-built server. Note that the ajax web client
is not guaranteed to work (at least not without tweaking) on a
third-party server.*
The suggested third-party stack for running Evennia's web front end is
`apache2 <http://httpd.apache.org/>`_ and
`mod\_wsgi <http://code.google.com/p/modwsgi/>`_. However, the codebase
may run just fine on other servers and modules (apache2/nginx/lighttpd +
gunicorn, Tornado, uwsgi, etc.) Below are instructions on how to set
things up with various apache2 Python modules. If you get things working
using a different setup, please feel free to provide details below.
--------------
SQLite Note
-----------
It's important to note that on Windows, you will be unable to run the
game and your web presence at the same time due to evennia.db3 being
locked while one has it opened. While Linux/Unix will let you run both
concurrently, there **may** be issues with simultaneous read/writes by
the game and the web front-end. The best bet to any game wishing to
power their web presence with Evennia is to use Postgres, MySQL, Oracle,
or any other supported full-blown relational database.
--------------
mod\_wsgi Setup
---------------
Install mod\_wsgi
~~~~~~~~~~~~~~~~~
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
is easy to set up on most distributions.
For the sake of brevity, this guide will refer you to mod\_wsgi's
`installation
instructions <http://code.google.com/p/modwsgi/wiki/InstallationInstructions>`_
page, as their guides are great. For those that are running Debian or
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
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.
Copy and modify the VHOST
~~~~~~~~~~~~~~~~~~~~~~~~~
After mod\_wsgi is installed, copy the
``evennia/game/web/utils/evennia_wsgi_apache.conf`` file to your apache2
vhosts/sites folder. On Debian/Ubuntu, this is
``/etc/apache2/sites-enabled/``. Make your modifications **after**
copying the file there.
Read the comments and change the paths to point to the appropriate
locations within your setup.
Restart/Reload Apache
~~~~~~~~~~~~~~~~~~~~~
You'll then want to reload or restart apache2. On Debian/Ubuntu, this
may be done via:
``sudo /etc/init.d/apache2 restart`` or
``sudo /etc/init.d/apache2 reload``
Enjoy
~~~~~
With any luck, you'll be able to point your browser at your domain or
subdomain that you set up in your vhost and see the nifty default
Evennia webpage. If not, read the hopefully informative error message
and work from there. Questions may be directed to our `Evennia Community
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 you are not running in daemon mode or want to force the issue, simply
restart or reload apache2 to apply your changes.
Further notes and hints:
~~~~~~~~~~~~~~~~~~~~~~~~
If you get strange (and usually uninformative) ``Permission denied``
errors from Apache, make sure that your ``evennia`` directory is located
in a place the webserver may actually access. For example, some Linux
distributions may default to very restrictive access permissions on a
user's ``/home`` directory.
One user commented that they had to add the following to their Apache
config to get things to work. Not confirmed, but worth trying if there
are trouble.
::
<Directory "/home/<yourname>/evennia/game/web"> Options +ExecCGI Allow from all </Directory>

View file

@ -0,0 +1,130 @@
Asynchronous code
=================
*This is considered an advanced topic, probably not useful for most
users.*
Synchronous versus Asynchronous
-------------------------------
Most code operate *synchronously*. This means that each statement in
your code gets processed and finishes before the next can begin. This
makes for easy-to-understand code. It is also a *requirement* in many
cases - a subsequent piece of code often depend on something calculated
or defined in a previous statement.
Consider this piece of code:
::
print "before call ..." long_running_function() print "after call ..."
When run, this will print ``"before call ..."``, after which the
``long_running_function`` gets to work for however long time. Only once
that is done, the system prints ``"after call ..."``. Easy and logical
to follow. Most of Evennia work in this way. Most of the time we want to
make sure that commands get executed in strict order after when they
where entered.
The main problem is that Evennia is a multi-user server. It swiftly
switches between dealing with player input in the order it is sent to
it. So if one user, say, run a command containing that
``long_running_function``, *all* other players are effectively forced to
wait until it finishes ... hardly an ideal solution.
Now, it should be said that on a modern computer system this is rarely
an issue. Very few commands run so long that other users notice it. And
as mentioned, most of the time you *want* to enforce all commands to
occur in strict sequence.
When delays do become noticeable and you don't care which order the
command actually completes, you can run it *asynchronously*. This makes
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 ..."
Now, when running this you will find that the program will not wait
around for ``long_running_function`` to finish. Infact you will see
``"before call ..."`` and ``"after call ..."`` printed out right away.
The long-running function will run in the background and you (and other
users) can go on as normal.
Customizing asynchronous operation
----------------------------------
A complication with using asynchronous calls is what to do with the
result from that call. What if ``long_running_function`` returns a value
that you need? It makes no real sense to put any lines of code after the
call to try to deal with the result from ``long_running_function`` above
- as we saw the ``"after call ..."`` got printed long before
``long_running_function`` was finished, making that line quite pointless
for processing any data from the function. Instead one has to use
*callbacks*.
``utils.run_async`` takes two optional arguments, ``at_return`` and
``at_err``. Both of these should be function defitions. Each will be
called automatically.
- ``at_return(r)`` (the *callback*) is called when the asynchronous
function (``long_running_function`` above) finishes successfully. The
argument ``r`` will then be the return value of that function (or
``None``). Example:
::
def at_return(r): print r
- ``at_err(e)`` (the *errback*) is called if the asynchronous function
fails and raises an exception. This exception is passed to the
errback wrapped in a *Failure* object ``e``. If you do not supply an
errback of your own, Evennia will automatically add one that silently
writes errors to the evennia log. An example of an errback is found
below:
::
def at_err(e):
print "There was an error:", str(e)
An example of making an asynchronous call from inside a
`Command <Commands.html>`_ definition:
::
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)
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
``at_return`` function will be called and the final value will pop up
for us to see. If not we will see an error message.
Assorted notes
--------------
Be careful with choosing when to use asynchronous calls. It is mainly
useful for large administration operations that has no direct influence
on the game world (imports and backup operations come to mind). Since
there is no telling exactly when an asynchronous call actually ends,
using them for in-game commands is to potentially invite confusion and
inconsistencies (and very hard-to-reproduce bugs).
The very first synchronous example above is not *really* correct in the
case of Twisted, which is inherently an asynchronous server. Notably you
might find that you will *not* see the first ``before call ...`` text
being printed out right away. Instead all texts could end up being
delayed until after the long-running process finishes. So all commands
will retain their relative order as expected, but they may appear with
delays or in groups.
Further reading
---------------
Technically, ``run_async`` is just a very thin and simplified wrapper
around a `Twisted
Deferred <http://twistedmatrix.com/documents/9.0.0/core/howto/defer.html>`_
object; the wrapper sets up a separate thread and assigns a default
errback also if none is supplied. If you know what you are doing there
is nothing stopping you from bypassing the utility function, building a
more sophisticated callback chain after your own liking.

View file

@ -0,0 +1,166 @@
Attributes
==========
When performing actions in Evennia it is often important that you store
data for later. If you write a menu system, you have to keep track of
the current location in the menu tree so that the player can give
correct subsequent commands. If you are writing a combat system, you
might have a combattant's next roll get easier dependent on if their
opponent failed. Your characters will probably need to store
roleplaying-attributes like strength and agility. And so on.
`Typeclassed <Typeclasses.html>`_ game entities
(`Players <Players.html>`_, `Objects <Objects.html>`_ and
`Scripts <Scripts.html>`_) always have *Attributes* associated with
them. Attributes are used to store any type of data 'on' such entities.
This is different from storing data in properties already defined on
entities (such as ``key`` or ``location``) - these have very specific
names and require very specific types of data (for example you couldn't
assign a python *list* to the ``key`` property no matter how hard you
tried). ``Attributes`` come into play when you want to assign arbitrary
data to arbitrary names.
Saving and Retrieving data
--------------------------
The **default** way of storing data on Typeclassed objects is simply to
assign data to it. Let's try to save some data to a *Rose* (an
`Object <Objects.html>`_):
::
# saving rose.has_thorns = True# getting it back is_ouch = rose.has_thorns
Whether this data is saved *persistently* to the database or not (i.e.
if it survives a server reboot) depends on the setting of the variable
``FULL_PERSISTENCE`` in the settings (it's described in more detail
later on this page).
To be **sure** to save your data persistently, regardless of the setting
of ``FULL_PERSISTENCE``, use the ``db`` (!DataBase) interface.
::
# saving rose.db.has_thorns = True # getting it back is_ouch = rose.db.has_thorns
This creates a new ``Attribute`` object and links it uniquely to
``rose``. Using ``db`` ``will`` always save data to the database.
To be sure to save **non-persistently**, 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
(Using ``ndb`` like this will **NEVER** use the database.)
Strictly speaking, ``ndb`` has nothing to do with ``Attributes``,
despite how similar they look. No ``Attribute`` object is created behind
the scenes when using ``ndb``. In fact the database is not invoked at
all since we are not interested in persistence.
You can also ``del`` properties on ``db`` and ``ndb`` as normal. This
will for example delete an ``Attribute``:
::
del rose.db.has_thorns
Persistent vs non-persistent
----------------------------
So *persistent* data means that your data will survive a server reboot,
whereas with *non-persistent* data it will not ...
... So why would you ever want to use non-persistent data? The answer
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 an over might not be ideal in that case. Non-persistent data
simply writes to memory, it doesn't hit the database at all. With the
speed and quality of hardware these days, this point is probably less
likely to be of any big concern except for the most extreme of
situations.
- 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 want to implement a fully or partly *non-persistent world*.
Whereas this sounds to us like something of an under-use of the
codebase's potential, who are we to argue with your grand vision!
FULL\_PERSISTENCE
-----------------
As mentioned above, Evennia allows you to change the default operation
when storing attributes by using ``FULL_PERSISTENCE`` in
``settings.py``.
With ``FULL_PERSISTENCE`` on, you can completely ignore ``db`` and
assign properties to your object as you would any python object. This is
the 'default' method shown at the top). Behind the scenes an
``Attribute`` will be created and your data will be saved to the
database. Only thing you have to do explicitly is if you *don't* want
persistence, where you have to use ``ndb``.
With ``FULL_PERSISTENCE`` off, the inverse is true. You then have to
specify ``db`` if you want to save, whereas normal assignment means
non-persistence.
Regardless of the setting you can always use ``db`` and ``ndb``
explicitly to get the result you want. This means writing a little bit
more, but has the advantage of clarity and portability: If you plan to
distribute your code to others, it's recommended you use explicit
assignment. This avoids weird errors when your users don't happen to use
the save persistence setting as you.
What types of data can I save?
------------------------------
If you store a single object (that is, not a 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.
There is one notable type of object that cannot be pickled - and that is
a Django database object. These will instead be stored as wrapper object
containing the ID and its database model. It will be read back to a new
instantiated `typeclass <Typeclasses.html>`_ when the Attribute is
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 efficiently, it can be a good idea is to
avoid deeply nested lists with objects if you can.
To store several objects, you may only use python *lists* or
*dictionaries* to store them. If you try to save any other form of
iterable (like a ``set`` or a home-made class), the Attribute will
convert, store and retrieve it as a list instead. Since you can nest
dictionaries and lists together in any combination, this is usually not
a limitation you need to worry about.
*Note that you could fool the safety check if you for example created
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.*
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 will stored and returned as a list [1,2,3,4,5]! obj.db.test6 = (1,2,3,4,5)
Notes
-----
There are several other ways to assign Attributes to be found on the
typeclassed objects, all being more 'low-level' underpinnings to
``db``/``ndb``. Read their descriptions in the respective modules.

View file

@ -0,0 +1,200 @@
: Using the Evennia batch code processor
The Batch-Code processor
========================
For an introduction and motivation to using batch processors, see
`here <BatchProcessors.html>`_. This page describes the Batch-*code*
processor. The Batch-*command* one is covered
`here <BatchCommandProcessor.html>`_.
Basic Usage
-----------
The batch-command processor is a superuser-only function, invoked by
::
> @batchcode path.to.batchcodefile
Where ``path.to.batchcodefile`` is the path to a *batch-code file* with
the "``.py``" file ending. This path is given like a python path
relative to a folder you define to hold your batch files, set by
``BATCH_IMPORT_PATH`` in your settings. Default folder is
``game/gamesrc/world``. So if you want to run the example batch file in
``game/gamesrc/world/examples/batch_code.py``, you could simply use
::
> @batchcommand examples.batch_code
This will try to run through the entire batch file in one go. For more
gradual, *interactive* control you can use the ``/interactive`` switch.
The switch ``/debug`` will put the processor in *debug* mode. Read below
for more info.
The batch file
--------------
A batch-code file is mostly a normal Python source file. The only thing
separating a batch file from any Python module is that the code are
wrapped into *blocks* using a special syntax. These blocks allow the
batch processor more control over execution, especially when using the
processor's *interactive* mode, where they allow the default
``@batchcommand`` to pause and only execute certain blocks at a time.
Here are the rules of syntax of the batch-command ``*.py`` file.
- ``#HEADER`` as the first on a line marks the start of a *header*
block. This is intended to hold imports and variables that might be
of use for for other blocks. All python code defined in a header
block will always be inserted at the top of all ``#CODE`` blocks in
the file. You may have more than one ``#HEADER`` block, but that is
equivalent to having just one big one. Comments in ``#HEADER`` blocks
are stripped out before merging.
- ``#CODE`` as the first on a line marks the start of a *code* block.
Code blocks contain functional python code. ``#HEADER`` blocks are
added to the top of code blocks at runtime.
- ``#CODE (info) obj1, obj2, ...`` is an optional form of the code
block header. The ``(info)`` field gives extra info about what's
going on in the block and is displayed by the batch processor. The
``obj1, obj2, ...`` parts are optional object labels used by the
processors *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.
- 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,
pointing to the object executing the batchcommand.
Below is a version of the example file found in
``game/gamesrc/commands/examples/batch_code.py``.
::
#
# 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))
This uses Evennia's Python API to create three objects in sequence.
Debug mode
----------
Try to run the example script with
::
> @batchcode/debug examples.batch_code
The batch script will run to the end and tell you it completed. You will
also get messages that the button and the two pieces of furniture where
created. Look around and you should see the button there. But you won't
see any chair nor a table! This is because we ran this with the
``/debug`` switch. The debug mode of the processor is intended to be
used when you test out a script. Maybe you are looking for bugs in your
code or try to see if things behave as they should. Running the script
over and over would then create an ever-growing stack of buttons, chairs
and tables, all with the same name. You would have to go back and
painstakingly delete them later. The debug mode simply tries to
automatically delete the objects that where created so as to not crowd
the room with unwanted objects.
The second ``#CODE`` block supplies the variable names ``table`` and
``chair``, which match the actual variables we later assign our new
ojects to. In debug mode the batch-code processor will look for these
references and simply run ``delete()`` on them. Since the
button-creating block does not define any such variables the processor
can't help us there - meaning the button stays also in debug mode.
Interactive mode
----------------
Interactive mode works very similar to the `batch-command processor
counterpart <BatchCommandProcessor.html>`_. It allows you more step-wise
control over how the batch file is executed. This is useful for
debugging or for picking and choosing only particular blocks to run. Use
``@batchcommand`` with the ``/interactive`` flag to enter interactive
mode.
::
> @batchcode/interactive examples.batch_code
You should see the following:
::
01/02: #CODE (create red button) [...] (hh for help)
This shows that you are on the first ``#CODE`` block, the first of only
two commands in this batch file. Observe that the block has *not*
actually been executed at this point!
To take a look at the full command you are about to run, use ``ll`` (a
batch-processor version of ``look``).
::
from 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]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.")
Compare with the example code given earlier. Notice how the content of
``#HEADER`` has been pasted at the top of the ``#CODE`` block. Use
``pp`` to actually execute this block (this will create the button and
give you a message). Use ``nn`` (next) to go to the next command. Use
``hh`` for a list of commands.
If there are tracebacks, fix them in the batch file, then use ``rr`` to
reload the file. You will still be at the same code block and can rerun
it easily with ``pp`` as needed. This makes for a simple debug cycle. It
also allows you to rerun individual troublesome blocks - as mentioned,
in a large batch file this can be very useful (don't forget the
``/debug`` mode either).
Use ``nn`` and ``bb`` (next and back) to step through the file; e.g.
``nn 12`` will jump 12 steps forward (without processing any blocks in
between). All normal commands of Evennia should work too while working
in interactive mode.
Limitations and Caveats
-----------------------
The batch-code processor is by far the most flexible way to build a
world in Evennia. There are however some caveats you need to keep in
mind.
- *Safety*. Or rather the lack of it. There is a reason only
*superusers* are allowed to run the batch-code processor by default.
The code-processor runs *without any Evennia security checks* and
allows full access to Python. If an untrusted party could run the
code-processor they could execute arbitrary python code on your
machine, which is potentially a very dangerous thing. If you want to
allow other users to access the batch-code processor you should make
sure to run Evennia as a separate and very limited-access user on
your machine (i.e. in a 'jail'). By comparison, the batch-command
processor is much safer since the user running it is still 'inside'
the game and can't really do anything outside what the game commands
allow them to.
- *You cannot communicate between code blocks*. Global variables won't
work in code batch files, each block is executed as stand-alone
environments. Similarly you cannot in one ``#CODE`` block assign to
variables from the ``#HEADER`` block and expect to be able to read
the changes from another ``#CODE`` block (whereas a python execution
limitation, allowing this would also lead to very hard-to-debug code
when using the interactive mode). The main issue with this is when
building e.g. a room in one code block and later want to connect that
room with a room you built in another block. To do this, you must
perform a database search for the name of the room you created (since
you cannot know in advance which dbref it got assigned). This sounds
iffy, but there is an easy way to handler this - use object aliases.
You can assign any number of aliases to any object. Make sure that
one of those aliases is unique (like "room56") and you will
henceforth be able to always find it later by searching for it from
other code blocks regardless of if the main name is shared with
hundreds of other rooms in your world (coincidentally, this is also
one way of implementing "zones", should you want to group rooms
together).

View file

@ -0,0 +1,164 @@
: Using the Evennia command batch processors
The Batch-Command processor
===========================
For an introduction and motivation to using batch processors, see
`here <BatchProcessors.html>`_. This page describes the Batch-*command*
processor. The Batch-*code* one is covered
`here <BatchCodeProcessor.html>`_.
Basic Usage
-----------
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
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
``game/gamesrc/world/examples/batch_cmds.ev``, you could use
::
> @batchcommand examples.batch_cmds
A batch-command file contains a list of Evennia commands that you have
previously entered. The processor will run the batch file from beginning
to end. Note that *it will not stop if commands in it fail* (there is no
universal way for the processor to know what a failure looks like for
all different commands). So keep a close watch on the output, or use
*Interactive mode* (see below) to run the file in a more controlled,
gradual manner.
The batch file
--------------
The batch file is a simple plain-text file containing Evennia commands.
Just like you would write them in-game, except you have more freedom
with line breaks.
Here's the rules of syntax of an ``*.ev`` file. You'll find it's really,
really simple:
- All lines having the # (hash)-symbol *as the first one on the line*
are considered *comments*.
- Comments also have an actual function -- they mark the *end of the
previous command definition*. So never put two commands directly
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
(regardless, using plenty of comments is a good practice anyway).
- Extra whitespace in a command definition are ignored. If you want a
line break in texts, leave an empty line. Two empty lines thus means
a new paragraph (for commands accepting formatting, that is).
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 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
To test this, run ``@batchcommand`` on the file. A button will be
created, described and dropped in Limbo. All commands will be executed
by the user calling the command. *Note that if you interact with the
button, you might find that its description changes, loosing your
custom-set description above. This is just the way this particular
object works.*
Interactive mode
----------------
Interactive mode allows you to more step-wise control over how the batch
file is executed. This is useful for debugging and also if you have a
large batch file and is only updating a small part of it -- running the
entire file again would be a waste of time (and in the case of
``@create``-ing objects you would to end up with multiple copies of
same-named objects, for example). Use ``@batchcommand`` with the
``/interactive`` flag to enter interactive mode.
::
> @batchcommand/interactive examples.batch_cmds
You will see this:
::
01/04: @create button:examples.red_button.RedButton (hh for help)
This shows that you are on the ``@create`` command, the first out of
only four commands in this batch file. Observe that the command
``@create`` has *not* been actually processed at this point!
To take a look at the full command you are about to run, use ``ll`` (a
batch-processor version of ``look``). Use ``pp`` to actually process the
current command (this will actually ``@create`` the button) -- and make
sure it worked as planned. Use ``nn`` (next) to go to the next command.
Use ``hh`` for a list of commands.
If there are errors, fix them in the batch file, then use ``rr`` to
reload the file. You will still be at the same command and can rerun it
easily with ``pp`` as needed. This makes for a simple debug cycle. It
also allows you to rerun individual troublesome commands - as mentioned,
in a large batch file this can be very useful. Do note that in many
cases, commands depend on the previous ones (e.g. if ``@create`` in the
example above had failed, the following commands would have had nothing
to operate on).
Use ``nn`` and ``bb`` (next and back) to step through the file; e.g.
``nn 12`` will jump 12 steps forward (without processing any command in
between). All normal commands of Evennia should work too while working
in interactive mode.
Limitations and Caveats
-----------------------
The batch-command processor is great for automating smaller builds or
for testing new commands and objects repeatedly without having to write
so much. There are several caveats you have to be aware of when using
the batch-command processor for building larger, complex worlds though.
The main issue is that when you run a batch-command script you (*you*,
as in your superuser character) are actually moving around in the game
creating and building rooms in sequence, just as if you had been
entering those commands manually, one by one. You have to take this into
account when creating the file, so that you can 'walk' (or teleport) to
the right places in order.
This also means there are several pitfalls when designing and adding
certain types of objects. Here are some examples:
- *Rooms that changes your `cmdset <Commands.html>`_*: Imagine that you
build a 'dark' room, which severely limits the cmdsets of those
entering it (maybe you have to find the light switch to proceed). In
your batch script you would create this room, then teleport to it -
and promptly be shifted into the dark state where none of your normal
build commands work ...
- *Auto-teleportation*: Rooms that automatically teleport those that
enter them to another place (like a trap room, for example). You
would be teleported away too.
- *Mobiles*: If you add aggressive mobs, they might attack you, drawing
you into combat. If they have AI they might even follow you around
when building - or they might move away from you before you've had
time to finish describing and equipping them!
The solution to all these is to plan ahead. Make sure that superusers
are never affected by whatever effects are in play. Add an on/off switch
to objects and make sure it's always set to *off* upon creation. It's
all doable, one just needs to keep it in mind.
Assorted notes
--------------
The fact that you build as 'yourself' can also be considered an
advantage however, should you ever decide to change the default command
to allow others than superusers to call the processor. Since normal
access-checks are still performed, a malevolent builder with access to
the processor should not be able to do all that much damage (this is the
main drawback of the `batch-code processor <BatchCodeProcessor.html>`_)

View file

@ -0,0 +1,103 @@
Batch Processors - overview
===========================
Building a game world is a lot of work, especially when starting out.
Rooms should be created, descriptions have to be written, objects must
be detailed and placed in their proper places. In many traditional MUD
setups you had to do all this online, line by line, over a telnet
session.
Evennia already moves away from much of this by shifting the main coding
work to external Python modules. But also building would be helped if
one could do some or all of it externally. Enter Evennia's *batch
command processors* (there are two of them). The processors allows you,
as a game admin, to build your game completely offline in normal text
files (*batch files*) that the processors understands. Then, when you
are ready, you use the processors to read it all into Evennia (and into
the database) in one go.
You can of course still build completely online should you want to -
this is certainly the easiest way to go when learning and for small
build projects. But for major building work, the advantages of using the
batch-processors are many:
- It's hard to compete with the comfort of a modern desktop text
editor; Compared to a traditional MUD line input, you can get much
better overview and many more features. Also, accidentally pressing
Return won't immediately commit things to the database.
- You might run external spell checkers on your batch files. In the
case of one of the batch-processors (the one that deals with Python
code), you could also run external debuggers and code analyzers on
your file to catch problems before feeding it to Evennia.
- The batch files (as long as you keep them) are records of your work.
They make a natural starting point for quickly re-building your world
should you ever decide to start over.
- If you are an Evennia developer, using a batch file is a fast way to
setup a test-game after having reset the database.
- The batch files might come in useful should you ever decide to
distribute all or part of your world to others.
There are two batch processors, the Batch-*command* processor and the
Batch-*code* processor. The first one is the simpler of the two. It has
the advantage of you not needing to know any programming - you basically
just list game commands in a text file. The code-processor on the other
hand is much more powerful but also more complex - it lets you to use
Evennia's API to code your world in full-fledged Python code.
- The `Batch-command processor <BatchCommandProcessor.html>`_
- The `Batch-code processor <BatchCodeProcessor.html>`_
If you plan to use international characters in your batchfiles you are
wise to read about *file encodings* below.
A note on File Encodings
------------------------
As mentioned, both the processors take text files as input and then
proceeds to process them. As long as you stick to the standard
`ASCII <http://en.wikipedia.org/wiki/Ascii>`_ character set (which means
the normal English characters, basically) you should not have to worry
much about this section.
Many languages however use characters outside the simple ``ASCII``
table. Common examples are various apostrophes and umlauts but also
completely different symbols like those of the greek or cyrillic
alphabets.
First, we should make it clear that Evennia itself handles international
characters just fine. It (and Django) uses
`unicode <http://en.wikipedia.org/wiki/Unicode>`_ strings internally.
The problem is that when reading a text file like the batchfile, we need
to know how to decode the byte-data stored therein to universal unicode.
That means we need an *encoding* (a mapping) for how the file stores its
data. There are many, many byte-encodings used around the world, with
opaque names such as ``Latin-1``, ``ISO-8859-3`` or ``ARMSCII-8`` to
pick just a few examples. Problem is that it's practially impossible to
determine which encoding was used to save a file just by looking at it
(it's just a bunch of bytes!). You have to *know*.
With this little introduction it should be clear that Evennia can't
guess but has to *assume* an encoding when trying to load a batchfile.
The text editor and Evennia must speak the same "language" so to speak.
Evennia will by default first try the international ``UTF-8`` encoding,
but you can have Evennia try any sequence of different encodings by
customizing the ``ENCODINGS`` list in your settings file. Evennia will
use the first encoding in the list that do not raise any errors. Only if
none work will the server give up and return an error message.
You can often change the text editor encoding (this depends on your
editor though), otherwise you need to add the editor's encoding to
Evennia's ``ENCODINGS`` list. If you are unsure, write a test file with
lots of non-ASCII letters in the editor of your choice, then import to
make sure it works as it should.
More help with encodings can be found in the entry `Text
Encodings <TextEncodings.html>`_ and also in the Wikipedia article
`here <http://en.wikipedia.org/wiki/Text_encodings>`_.
**A footnote for the batch-code processor**: Just because *Evennia* can
parse your file and your fancy special characters, doesn't mean that
*Python* allows their use. Python syntax only allows international
characters inside *strings*. In all other source code only ``ASCII`` set
characters are allowed.

View file

@ -0,0 +1,176 @@
Setting up a solo coding environment with version control
=========================================================
*This page deals with working as a lone coder. See also how to use
version control to collaborate with many people on a game
`here <StaffVersionControl.html>`_.*
Version control software allows you to easily backtrack changes to your
code, help to share your development efforts and more. Even if you are
not contributing to Evennia itself, but is "just" developing your own
game using Evennia, having a version control system in place is a good
idea. If you want more info, start with the wikipedia article about it
`here <http://en.wikipedia.org/wiki/Version_control>`_. Note that this
page deals with commands in the Linux operating system. Details may vary
for other systems.
Bazaar and SVN
--------------
Evennia itself uses the *Subversion* (SVN)version control system. This
relatively old version control system lacks some of the more modern
features of later systems, but is universally recognized and easy to
use. Just because we use SVN centrally does not mean that you have to
use it when working with Evennia on your local machine however.
`Bazaar <http://bazaar.canonical.com>`_ (bzr) is a version control
system written entirely in Python. It's available for all major
platforms. It's a more modern system than SVN and is generally easy to
use, also for newbies (other commonly seen systems similar to Bazaar are
GIT and Mercurial). We won't go into the details of what makes Bazaar
different from SVN, there are many texts about this on the internet.
What is important though is that Bazaar interfaces very well with SVN,
by use of a plugin called, *bzr-svn*.
Prerequisites
-------------
Bazaar and bzr-svn are both available from the normal Linux package
managers (see the homepage for how to download for other systems).
Install those first, then give the command ``bzr`` in a terminal to make
sure it's available.
First, identify to bazaar by giving the command
``bzr whoami name <email>``
``bzr whoami Harry Olsson <harry@gmail.com>``
You can put a nickname here too if you want. This is just so the system
knows what to put to identify new revisions.
Setting up for a single developer
---------------------------------
We will here assume you are downloading Evennia for the first time. We
will set up a simple environment for hacking your game in.
Make a new folder on your hard drive, for example named *evennia*.
Outside this folder, give the command
``bzr init-repo evennia``
This sets the ``evennia`` folder up as a Bazaar repository, ready to
use. Enter this folder now. Next we obtain the Evennia server, except we
now use Bazaar to do it and not SVN.
``bzr checkout http://evennia.googlecode.com/svn/trunk/ evennia-trunk``
(Contributors use the contributor URL instead). A new folder
``evennia-trunk`` has appeared in your repository! In it you will find
the entire Evennia source. Working with this folder works almost
identically to how it would work with SVN - you use ``bzr update`` to
get the latest version, contributors use ``bzr commit`` to enter their
changes to the server. Actually coding away in this folder is not ideal
however. As mentioned, doing ``bzr commit`` will (attempt to) push your
changes to the main Evennia repository, which is most often not what you
want when developing your own game. This is where Bazaar kicks in. We
will leave ``evennia-trunk`` be and create a separate *branch* to do our
work in. Change your directory to the root ``evennia`` one, then copy to
a new branch, let's call it ``evennia-mygame``:
``bzr branch evennia-trunk evennia-mygame``
A new folder appeared, containing a copy of the code. ``evennia-mygame``
is where you do all your work. If you do commits in here, they will be
committed locally, not to Evennia central. You now have full version
control on your machine. Updating your work code becomes a simple
two-step process of updating ``evennia-trunk`` and then *merging* those
changes into ``evennia-mygame``. Read on.
Example work process for single developer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
First we make sure our copy of Evennia is up-to-date. Go to
``evennia-trunk``
``bzr update``
Bazaar goes online and gets the latest Evennia revision from the central
repository, merging it automatically into the branch.
So ``evennia-trunk`` is now up-to-date. Go to ``evennia-mygame``.
``bzr merge ../evennia-trunk``
The changes in ``evennia-trunk`` are pulled in and merged with
``evennia-mygame``. You can now continue to hack away in
``evennia-mygame``. Maybe you define new commands, fix bugs, create
batchfiles or what have you. If you create any new files, you must tell
Bazaar to handle them too, using the ``add`` command:
``bzr add <filenames>``
Check the current status of the version control with
``bzr status``
If you don't get any return value, you haven't made any changes since
last commit. Otherwise you will get a list of modified files. "Unknown"
files need to be added with ``add`` before Bazaar can track them.
It's usually a good idea to commit your changes often. This gives you a
snapshot of your work that you can get back to.
``bzr commit``
This will open a text editor where you can add a message detailing your
changes. These are the messages you see in the Evennia update list. If
you don't want to use the editor you can set the message right away with
the ``-m`` flag:
``bzr commit -m "This should fix the bug Sarah talked about."``
If you did changes that you wish you hadn't, you can easily get rid of
everything since your latest commit:
``bzr revert``
You can view the full log of committed changes with
``bzr log``
See the Bazaar manuals for learning more about useful day-to-day
commands, and special situations such as dealing with text collisions
etc.
Evennia Contributor
~~~~~~~~~~~~~~~~~~~
If you are an Evennia contributor, you can also have use of the Bazaar
setup above. The only difference is that you then also have commit
permission to the Evennia main repository.
You can have any number of work branches in your ``evennia`` folder.
Let's say your work branch for fixing Evennia bugs and features is
``evennia-work``. You update and work with this the same way as
``evennia-mygame`` above.
After having committed your latest changes, move to the
``evennia-trunk`` folder.
``bzr update``
This makes sure your local trunk is up-to-date.
``bzr merge ../evennia-work``
This merges your updates into the ``evennia-trunk`` branch.
``bzr commit``
Give the commit message and your changes will be pushed to the central
repository. Done!
.. figure:: http://d.imagehost.org/0452/bazaar_repo1.png
:align: center
:alt:

View file

@ -0,0 +1,27 @@
Builder Documentation
=====================
This section contains information useful to world builders.
Building basics
---------------
- `Default in-game commands <DefaultCommandHelp.html>`_
- `Building Quick-start <BuildingQuickstart.html>`_
- `Giving build permissions to others <BuildingPermissions.html>`_
- `Adding colour <Colours.html>`_
- `Customizing the connection screen <ConnectionScreen.html>`_
World creation
--------------
`Overview of batch processors <BatchProcessors.html>`_
- `Batch-command processor <BatchCommandProcessor.html>`_
- `Batch-code processor <BatchCodeProcessor.html>`_
The Tutorial world
------------------
- `Introduction and setup <TutorialWorldIntroduction.html>`_

View file

@ -0,0 +1,54 @@
Giving permissions to your staff
================================
*OBS: This gives only a brief introduction to the access system. Locks
and permissions are fully detailed `here <Locks.html>`_.*
The super user
--------------
There are strictly speaking two types of users in Evennia, the *super
user* and everyone else. The superuser is the first user you create,
object #1. This is the all-powerful server-owner account. A superuser
account has access to everything and no locks affect them. Technically
the superuser not only has all access, it even bypasses the permission
checks entirely. This makes the superuser impossible to lock out, but
makes it unsuitable to actually play-test the game's locks and
restrictions with. Usually there is no need to have but one superuser.
Assigning permissions
---------------------
Whereas permissions can be used for anything, those put in
settings.PERMISSION\_HIERARCHY will have a ranking relative each other
as well. By default Evennia creates the following hierarchy:
#. *Immortals* - these basically have all the same access as superusers
(except that they do not sidestep the Permission system). Assign only
to really trusted server-admin staff.
#. *Wizards* can do everything except affecting the server functions
itself. So a wizard couldn't reload or shutdown the server for
example. They also cannot execute arbitrary Python code on the
console or import files from the hard drive.
#. *Builders* has all the build commands, but cannot affect other
players or mess with the server.
#. *!PlayerHelpers* are almost like a normal *Player*, but they can also
add help files to the database.
#. *Players* is the default group that new players end up in. A new
player have permission to use tells, to use and create new channels.
A user having a higher-level permission also automatically have access
to locks requiring only lower-level access.
To assign a new permission from inside the game, you need to be able to
use the ``@perm`` command. This is an *Immortal*-level command, but it
could in principle be made lower-access since it only allows assignments
equal or lower to your current level (so you cannot use it to escalate
your own permission level). So, assuming you yourself have *Immortal*
access (or is superuser), you assign a new player "Tommy" to your core
staff with the command
::
@perm/add Tommy = Immortals

View file

@ -0,0 +1,301 @@
A quick-start guide to in-game building in Evennia.
Building Quick-start
====================
The default `command <Commands.html>`_ definitions coming with Evennia
follows a style `similar <UsingMUXAsAStandard.html>`_ to that of MUX, so
the commands should be familiar if you used any such code bases before.
If you haven't, you might be confused by the use of ``@`` all over. This
is just a naming convention - commands related to out-of-character or
admin-related actions tend to start with ``@``, the symbol has no
meaning of its own.
The default commands have the following style (where ``[...]`` marks
optional parts):
::
command[/switch/switch...] [arguments ...]
A *switch* is a special, optional flag to the command to make it behave
differently. It is always put directly after the command name, and
begins with a forward slash (``/``). The *arguments* are one or more
inputs to the commands. It's common to use an equal sign (``=``) when
assigning something to an object.
Below are some examples of commands. Use ``help <command>`` for learning
more about each command and their detailed options.
Creating an object
------------------
Basic objects can be anything -- swords, flowers and non-player
characters. They are created using the ``@create`` command:
::
> @create box
This created a new 'box' (of the default object type) in your inventory.
Use the command ``inventory`` (or ``i``) to see it. Now, 'box' is a
rather short name, let's is give a few aliases.
::
> @name box = very large box;box;very;bo;crate
We now actually renamed the box to *very large box* (and this is what we
will see when looking at the room), but we will also recognize it by any
of the other names we give - like *crate* or simply *box* as before. We
could have given these aliases directly after the name in the
``@create`` command, this is true for all creation commands - you can
always tag on a list of ;-separated aliases to the name of your new
object. If you had wanted to not change the name itself, but to only add
aliases, you could have used the ``@alias`` command.
We are currently carrying the box, which you can see if you give the
command ``inventory`` (or ``i``). Let's drop it.
::
> drop box
Hey presto - there it is on the ground, in all its normality (you can
also create & drop in one go using the ``/drop`` switch, like this:
``@create/drop box``).
::
> examine box
This will show some technical details about the box object (you can
normally just write ``ex`` as a short for ``examine``).
Try to ``look`` at the box to see the (default) description.
::
> look box
Let's add some flavor.
::
> @describe box = This is a large and very heavy box.
If you try the ``get`` command we will pick up the box. So far so good,
but if we really want this to be a large and heavy box, people should
*not* be able to run off with it that easily. To prevent this we need to
lock it down. This is done by assigning a *Lock* to it. Make sure the
box was dropped in the room, then try this:
::
> @lock box = get:false()
Locks are a rather `big topic <Locks.html>`_, but for now that will do
what we want. This will lock the box so noone can lift it (except
superusers, they override all locks and pick it up anyway). Make sure
you log in as another user than #1 and try to get the box now:
::
> get box You can't get that.
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 (if you logged in as
another user, you need to have build permissions again for this):
::
> @set box/get_err_msg = The box is way too heavy for you to lift.
Try to get it now and you should see a nicer error message echoed back
to you.
Get a personality
-----------------
`Scripts <Scripts.html>`_ are powerful things that allows time-dependent
effects on objects. To try out a first script, let's put one on
ourselves. There is an example script in
``game/gamesrc/scripts/examples/bodyfunctions.py`` that is called
``BodyFunctions``. To add this to us we will use the ``@script``
command:
::
> @script self = examples.bodyfunctions.BodyFunctions
(note that you don't have to give the full path as long as you are
pointing to a place inside the ``gamesrc/scripts`` directory). Wait a
while and you will notice yourself starting making random observations.
::
> examine self
This will show details about yourself. You will also see the script and
how long it is until it "fires" next (a randomizer determines if it will
say something, so you will not see any output every time it fires).
When you are tired of this, kill the script with
::
> @script/stop self = examples.bodyfunctions.BodyFunctions
Pushing your buttons
--------------------
If we get back to the box we made, there is only so much fun you can do
with it at this point. It's just a dumb generic object. If you renamed
it ``carpet`` and changed its description noone would be the wiser.
However, with the combined use of custom
`Typeclasses <Typeclasses.html>`_, `Scripts <Scripts.html>`_ and
object-based `Commands <Commands.html>`_, you could expand it and other
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.
Let's make us one of *those*!
::
> @create/drop button:examples.red_button.RedButton
With the ``/drop`` switch we make sure to drop the button right away
without having to use the ``drop`` command later. We import the
*!RedButton* python class the same way you would import it in Python
except Evennia defaults to looking in ``game/gamesrc/objects/`` so you
don't have to write the full path every time. There you go - one red
button.
The *!RedButton* is an example object intended to show off many of
Evennia's features. You will find that the `Scripts <Scripts.html>`_ and
`Commands <Commands.html>`_ controlling it are scattered in
``examples``-folders all across ``game/gamesrc/``.
If you wait for a while (make sure you dropped it!) the button will
blink invitingly. Why don't you try to push it ...? Surely a big red
button is meant to be pushed. You know you want to.
Creating a room called 'house'
------------------------------
The main command for shaping the game world is ``@dig``. If you for
example are standing in Limbo, you can in one go dig a route 'north' to
your new house location like this:
::
> @dig house = large red door;door;in, to the outside;out
This will create a new room named 'house'. It will also directly create
an exit from your current location named 'large red door' and a
corresponding exit named 'to the outside' in the house room leading back
to Limbo. We also define a few aliases to those exits, so people don't
have to write the full thing all the time.
If you wanted to use normal compass directions (north, west, southwest
etc), you could do that with ``@dig`` too. But Evennia also has a
limited version of ``@dig`` that helps for compass directions (and also
up/down and in/out). It's called ``@tunnel``:
::
> @tunnel sw = cliff
This will create a new room "cliff" with an exit "southwest" leading
there and a path "northeast" leading back from the cliff to your current
location.
You can create exits from anywhere at any time using the ``@open``
command:
::
> @open north;n = house
This opens an exit ``north`` to the previously created room ``house``.
If you have many rooms named ``house`` you will get a list of matches
and have to select which one you want to link to. You can also give its
database ref number, which is unique to every object. This can be found
with the ``examine`` command or by looking at the latest constructions
with ``@objects``.
Follow the north exit to your 'house' or ``@teleport`` to it:
::
> north
or:
::
> @teleport house
To manually open an exit back to Limbo (if you didn't do so with the
``@dig`` command):
::
> @open door = limbo
(or give limbo's dbref which is #2)
Finding and manipulating existing objects
-----------------------------------------
To re-point an exit at another room or object, you can use
::
> @link <room name> = <new_target name>
To find something, use
::
> @find <name>
This will return a list of dbrefs that have a similar name.
To teleport something somewhere, one uses
::
> @teleport <object> = <destination>
To destroy something existing, use
::
> @destroy <object>
You can destroy many objects in one go by giving a comma-separated list
of objects to the command.
Adding a help entry
-------------------
An important part of building is keeping the help files updated. You can
add, delete and append to existing help entries using the ``@sethelp``
command.
::
> @sethelp/add MyTopic = This help topic is about ...

View file

@ -0,0 +1,60 @@
Choosing an SQL Server
======================
Since Evennia uses `Django <http://djangoproject.com>`_, most of our
notes are based off of what we know from the community and their
documentation. While the information below may be useful, you can always
find the most up-to-date and "correct" information at Django's `Notes
about supported
Databases <http://docs.djangoproject.com/en/dev/ref/databases/#ref-databases>`_
page.
SQLite
------
This is the default database used, and for the vast majority of sites
out there, will probably be more than adequate. No server process is
needed, the administrative overhead is tiny (as is resource
consumption). The database will appear as a simple file
(``game/evennia.db`` by default). Purging your database is just a matter
of deleting this file and re-running the database creation commands in
GettingStarted.
It is not tested how well Evennia performs with SQLite under a heavier
load, but it should probably be fine given the relative simplicity of
our applications.
**Note:** If you run Windows and 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 of the database file under
Windows.
Postgres
--------
This is Django's recommended DB engine, and the one that we recommend
for all sites aspiring to grow to a larger size. While not as fast as
SQLite for simple purposes, it will scale infinitely better than SQLite,
especially if your game has an extensive web presence.
MySQL
-----
While perfectly reasonable to deploy under, the MySQL driver for Django
has some very slight oddities (at the time of this document's writing)
that probably don't affect our usage case that much (if at all). Make
sure you look at the aforementioned `Notes about supported
Databases <http://docs.djangoproject.com/en/dev/ref/databases/#ref-databases>`_
page for the latest on this.
MySQL **may** be slightly faster than Postgres depending on your setup
and software versions involved.
Others
------
No testing has been performed with Oracle, but it is also supported.
There are community maintained drivers for `MS
SQL <http://code.google.com/p/django-mssql/>`_ and possibly a few others
(found via our friend, Google).

View file

@ -0,0 +1,59 @@
Putting Colour to your game
===========================
<wiki:comment> </wiki:comment>
*Note that the Wiki does not display colour the way it would look on the
screen.*
Evennia supports the ``ANSI`` standard for displaying text. This means
that you can put markers in your text and if the user's
client/console/display supports those markers, they will see the text in
the specified colour. Remember that whereas there is, for example, one
special marker meaning "yellow", which colour (hue) of yellow is
*actually* displayed on the user's screen depends on the settings of
their particular mud client/viewer. They could even swap around the
colours displayed if they wanted to. or turn them off altogether. Some
clients don't support colour from the onset - text games are also played
with special reading equipment by people who are blind or have otherwise
diminished eyesight. So a good rule of thumb is to use colour to enhance
your game, but don't *rely* on it to display critical information. If
you are coding the game, you can add functionality to let users disable
colours as they please, as described `here <RemovingColour.html>`_.
Adding colour to in-game text is easy. You just put in special markers
in your text that tell Evennia when a certain colour begins and when it
ends. There are two markup styles. The traditional(?) one use ``%c#`` to
mark colour:
::
This is a %crRed text%cn This is normal text again. %cRThis text has red background%cn this is normal text.
``%c#`` - markup works like a switch that is on until you actively turn
it off with ``%cn`` (this returns the text to your default setting).
Capital letters mean background colour, lower-case means letter-colour.
So ``%cR`` means a red area behind your normal-colour text. If you
combine red background with red foreground text - ``%cR%cr``, you get a
solid red block with no characters visible! Similarly, ``%cR%cx`` gives
red background with black text. ``%ch`` 'hilights' your current text, so
grey becomes white, dark yellow becomes bright yellow etc.
The drawback of the ``%cs`` style has to do with how Python formats
strings - the ``%`` is used in Python to create special text formatting,
and combining that with colour codes easily leads to messy and
unreadable code. It is thus often easier to use ``#`` style codes:
::
This is a rBright red textn This is normal text again
The ``x`` format don't include background colour, it only colours the
foreground text. The basic rule is that lower-case letter means bright
(hilighted) colour, whereas the upper-case one is for darker colour. So
``g`` means bright green and ``G`` means dark green. ``n`` returns to
normal text colour. The equivalent in ``%c``-style markup is ``%cg%ch``
for bright green and ``%cg`` for dark green.
You can find a list of all the parsed ``ANSI``-colour codes in
``src/utils/ansi.py``.

View file

@ -0,0 +1,85 @@
Adding a command prompt
=======================
A *prompt* is quite common in MUDs. The prompt display useful details
about your character that you are likely to want to keep tabs on at all
times, such as health, magical power etc. It might also show things like
in-game time, weather and so on.
Prompt after the command
------------------------
The easiest form of prompt is one that is sent after every command you
send. So, say you enter the look command; you would then get the result
of the look command, followed by the prompt. As an example:
::
> look You see nothing special. HP:10, SP:20, MP: 5
MUD clients can be set to detect prompts like this and display them in
various client-specific ways.
To add this kind of "after-every-command-prompt", you can use the
``at_post_cmd()`` hook. This is to be defined on the Command class and
Evennia will always call it right after ``func()`` has finished
executing. For this to appear after every command you enter, it's best
to put this in the parent for your commands (for the default commands
this would be ``MuxCommand``), but you could also put it only in certain
commands (might not be too useful to show it if you are doing game
administration for example).
::
class MyCommand(Command): [...] def at_post_cmd(self): # we assume health/stamina/magic are just stored # as simple attributes on the character. hp = self.caller.db.hp sp = self.caller.db.sp mp = self.caller.db.mp self.caller.msg("HP: %i, SP: %i, MP: %i" % (hp, sp, mp))
Prompt on the same line
-----------------------
Another, more advanced type of prompt is one that appears before the
return of every command, on the same line:
::
> look HP: 10, SP:20, MP:5 -- You see nothing special.
Now, there is an ``at_pre_cmd()`` hook analogous to the hook from last
section except called just *before* parsing of the command. But putting
prompt code in that would just have the prompt appear on the *line
before* the function return:
::
> look HP:10, SP:20, MP: 5 You see nothing special.
... which might be cool too, but not what we wanted. To have the prompt
appear on the same line as the return this, we need to change how
messages are returned to the player. This means a slight modification to
our *Character class* (see `here <Objects#Characters.html>`_ on how to
change the default Character class to your custom one). Now, all
commands use the ``object.msg()`` method for communicating with the
player. This is defined in ``src/objects/models.py``, on the
``ObjectDB`` base class. This is how the ``msg()`` method is defined:
::
def msg(self, outgoing_message, from_obj=None, data=None): ...
The only argument we are interested in here is the ``outgoing_message``,
which contains the text that is about to be passed on to the player. We
want to make sure that ``msg()`` always tack our prompt in front of the
``outgoing_message`` before sending it on. This is done by simply
overloading the ``msg()`` method in our custom Character class. On your
custom Character typeclass add this:
::
def msg(self, outgoing_message, from_obj=None, data=None): # prepend the prompt in front of the message hp = self.db.hp sp = self.db.sp mp = self.db.mp prompt = "%i, %i, %i -- " % (hp, sp, mp) outgoing_message = prompt + outgoing_message # pass this on to the original msg() method on the database object self.dbobj.msg(outgoing_message, from_obj=from_obj, data=data)
Note that this solution will *always* give you the prompt, also if you
use admin commands, which could get annoying. You might want to have
some attribute defined on your character for turning on/off the prompt
(the msg() method could look for it to determine if it should add the
prompt or not). You can of course also name the above method
``msg_prompt()`` and make sure that only commands that *should* return a
prompt call this version.

View file

@ -0,0 +1,608 @@
Details on how to use and extend the command system.
Command system
==============
The basic way for users to communicate with the game is through
*Commands*. These can be commands directly related to the game world
such as *look*, *get*, *drop* and so on, or administrative commands such
as *examine* or *@dig*.
The `default commands <DefaultCommandHelp.html>`_ coming with Evennia
are 'MUX-like' in that they use @ for admin commands, support things
like switches, syntax with the '=' symbol etc, but there is nothing that
prevents you from implementing a completely different command scheme for
your game. You can find the default commands in
``src/commands/default``. You should not edit these directly - they will
be updated by the Evennia team as new features are added. Rather you
should look to them for inspiration and inherit your own designs from
them.
There are two components to having a command running - the *Command*
class and the *Command Set* you want to store that command in.
A *Command* is a python class containing all the functioning code for
what a command does - for example, a *look* command would contain code
for describing other objects.
A *Command Set* (often referred to as a !CmdSet) is a python class
holding any number of Command class instances, and one Command can go
into many different command sets. By storing the command set on a
character object you will make all the commands therein available to use
by that character. You can also store command sets on normal objects if
you want users to be able to use the object in various ways. Consider a
"Tree" object with a cmdset defining the commands *climb* and *shop
down*. Or a "Clock" with a cmdset containing the single command *check
time*.
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
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
by "=" etc. Below we'll avoid mux-specifics and use the base ``Command``
class directly.
You define a new command by assigning a few class-global properties on
your inherited class and overloading one or two hook functions. The full
gritty mechanic behind how commands work are found towards the end of
this page; for now you only need to know that the command handler
creates an instance of this class when you call that command, then
assigns the new object a few useful properties that you can assume to
always be available.
Properties assigned to the command instance at run-time
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's say player *Bob* with a character *!BigGuy* enters the command
``look at sword``. After the system having successfully identified this
a the "look" command and determined that *!BigGuy* really has access to
a command named ``look``, it chugs the ``look`` command class out of
storage and creates a new instance of it. After some more checks it then
assigns it the following properties:
- ``caller`` - a reference to the object executing the command - this
is normally *!BigGuy*, not *Bob*! The command system usually deals
with things on the character level. If you want to do something to
the player in your command, do so through ``caller.player``. The only
exception to this is if you stored your cmdset directly on the
*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.
- ``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``".
- ``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``".
- ``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>`_
(Advanced note: the merged cmdset need NOT be the same as
!BigGuy.cmdset. The merged set can be a combination of the cmdsets
from other objects in the room, for example\_).
Defining your own command classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Beyond the properties Evennia always assigns to the command at runtime
(listed above), your job is to define the following class properties:
- ``key`` - 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``.
- ``aliases`` (optional) - a list of alternate names for the command
(``["l", "glance", "see"]``). Same name rules as for ``key`` applies.
- ``locks`` - a `lock definition <Locks.html>`_, usually on the form
``cmd:<lockfuncs>``. Locks is a rather big topic, so until you learn
more about locks, stick to giving the lockstring ``"cmd:all()"`` to
make the command available to everyone.
- ``help_category`` (optional) - setting this helps to structure the
auto-help into categories. If none is set, this will be set to
*General*.
You should also implement at least two methods, ``parse()`` and
``func()`` (You could also implement ``perm()``, but that's not needed
unless you want to fundamentally change how access checks work).
``parse()`` is intended to parse the arguments (``self.args``) of the
function. You can do this in any way you like, then store the result(s)
in variable(s) on the command object itself (i.e. on ``self``). The
default mux-like system uses this method to detect "command switches",
to take one example.
``func()`` is called right after ``parse()`` and should make use of the
pre-parsed input to actually do whatever the command is supposed to do.
This is the main body of the command.
Finally, you should always make an informative ```__doc__``
string <http://www.python.org/dev/peps/pep-0257/#what-is-a-docstring>`_
at the top of your class. This string is dynamically read 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:
::
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'...")
The power of having commands as classes and to separate ``parse()`` and
``func()`` lies in the ability to inherit functionality without having
to parse every command individually. For example, as mentioned the
default commands all inherit from ``MuxCommand``. ``MuxCommand``
implements its own version of ``parse()`` that understands all the
specifics of MUX-like commands. Almost none of the default commands thus
need to implement ``parse()`` at all, but can assume the incoming string
is already split up and parsed in suitable ways by its parent.
So we have created our own first command! But Evennia doesn't know about
it yet. To tell it we have to add it to a *Command Set*.
Command Sets
------------
All commands in Evennia are always grouped together into *Command Sets*
(!CmdSets). A particular ``Command`` class definition can be part of any
number of different !CmdSets. CmdSets can be stored on game
`objects <Objects.html>`_ and on `Players <Players.html>`_ respectively.
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>`_.
The currently valid command sets are collected from the following
sources, in this order:
- The active cmdset on the character object
- The cmdsets of objects carried by the character
- The cmdset of the current location
- The cmdset of objects in the currrent location (this includes exits)
- The channel commandset
- The cmdset defined on the Player object controlling the character
(OOC cmdset)
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.
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).
::
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())
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
as if you added them line by line:
::
at_cmdset_creation(): ... self.add(AdditionalCmdSet) # adds all command from this set ...
If you added your command to an existing cmdset (like to the default
cmdset), that set is already loaded into memory. You need to make the
server aware of the code changes:
::
@reload
You should now be able to use the command.
If you created a new, fresh cmdset, this must be added to an object in
order to make the commands within available. A simple way to temporarily
test a cmdset on yourself is use the ``@py`` command to execute a python
snippet:
::
@py self.cmdset.add('game.gamesrc.commands.mycmdset.MyCmdSet')
This will stay with you until you shut down the server or 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>`_
below. Generally you can customize which command sets are added to your
objects by using ``self.cmdset.add()`` or ``self.cmdset.add_default()``.
Adding a new command - a step by step guide
-------------------------------------------
This is a summary of the information from the previous sections. Let's
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.
#. 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()".
#. 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.
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)
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``.
#. (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.
This is what we have now:
::
from game.gamesrc.commands.basecmdset 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
will now temporarily *merge* this command set to your current set. This
is a convenient way to test cmdsets without messing with your default
setup - if you reset those extra comands will be gone again.
Log into your game (as user #1) and add the cmdset to yourself like
this:
::
@py self.cmdset.add('game.gamesrc.commands.mycmdset.MyCmdSet')
There, you should now be able to run the ``mycommand`` command.
To remove a cmdset, use ``self.cmdset.delete()``. This will remove the
latest set (you can also name the set to remove, this where the cmdset's
key comes in handy).
You can replace an object's default command set with this command:
::
@py self.search("myobject").cmdset.add_default('game.gamesrc.commands.mycmdset.MyCmdSet')
If you want to this to survive a server shutdown, use the ``permanent``
keyword:
::
@py self.search("myobject").cmdset.add_default('game.gamesrc.commands.mycmdset.MyCmdSet', permanent=True)
The default cmdset is never affected by ``cmdset.add()`` or
``cmdset.delete()``, you have to use ``cmdset.add_default()`` to set it
explicitly (use ``remove_default()`` to remove it). Be careful to
replace or remove the default cmdset on yourself unless you really know
what you are doing - you will loose all the default Evennia commands and
might not be able to get them back ...
And finally,
::
@reload
to update the server to your changes.
Appending a new command to the default command set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Instead of manually appending your custom cmdset you can choose to
extend Evennia's default command set directly. That way your new command
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.
::
# 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())
Again, you need to run the ``@reload`` command to make these changes
available.
Editing/replacing an existing default command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This works the same way as in the previous section. Just set your new
command class' ``key`` variable to be the same as that of the command to
replace. So if you want to replace the default ``look`` command, just
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
example found in ``src/commands/default/general.py``) into
``game/gamesrc/commands`` and edit it there.
Adding and merging command sets
-------------------------------
*Note: This is an advanced topic. It's useful to know about, but you
might want to skip it if this is your first time learning about
commands.*
CmdSets have the special ability that they can be *merged* together into
new sets. This would happen if you, for example, did
``object.cmdset.add(MyCmdSet)`` on an object that already had a command
set defined on it. The two sets will be evaluated and a temporary,
*merged set* will be created out of the commands in both sets. Only the
commands in this merged set is from that point available to use. Which
of the ingoing commands end up in the merged set is defined by the
*merge rule* and the relative *priorities* of the two sets. Removing the
latest added set will restore things back to the way it was before the
addition.
CmdSets are non-destructively stored in a stack inside the cmdset
handler on the object. This stack is parsed to create the "combined"
cmdset active at the moment. The very first cmdset in this stack is
called the *Default cmdset* and is protected from accidental deletion.
Running ``obj.cmdset.delete()`` will never delete the default set.
Instead one should add new cmdsets on top of the default to "hide" it,
as described below. Use the special ``obj.cmdset.delete_default()`` only
if you really know what you are doing.
CmdSet merging is an advanced feature useful for implementing powerful
game effects. Imagine for example a player entering a dark room. You
don't want the player to be able to find everything in the room at a
glance - maybe you even want them to have a hard time to find stuff in
their backpack! You can then define a different CmdSet with commands
that override the normal ones. While they are in the dark room, maybe
the ``look`` and ``inv`` commands now just tell the player they cannot
see anything! Another example would be to offer special combat commands
only when the player is in combat. Or when being on a boat. Or when
having taken the super power-up. All this can be done on the fly by
merging command sets.
Merge rules
^^^^^^^^^^^
To understand how sets merge, we need to define a little lingo. Let's
call the first command set **A** and the second **B**. We will merge
**A** onto **B**, so in code terms the command would be
``object.cdmset.add(A)``, where we assume **B** was already the active
cmdset on ``object`` since earlier.
We let the **A** set have higher priority than **B**. A priority is
simply an integer number. Default is 0, Evennia's in-built high-prio
commands (intended to overrule others) have values of 9 or 10.
Both sets contain a number of commands named by numbers, like ``A1, A2``
for set **A** and ``B1, B2, B3, B4`` for **B**. So for that example both
sets contain commands with the same keys 1 and 2, whereas commands 3 and
4 are unique to **B**. To describe a merge between these sets, we would
write ``A1,A2 + B1,B2,B3,B4 = ?`` where ``?`` is a list of commands that
depend on which merge type **A** has, and which relative priorities the
two sets have. By convention, we read this statement as "New command set
**A** is merged onto the old command set **B** to form **?**".
Below are the available merge types and how they work. Names are partly
borrowed from `Set theory <http://en.wikipedia.org/wiki/Set_theory>`_.
**Union** (default) - The two cmdsets are merged so that as many
commands as possible from each cmdset ends up in the merged cmdset.
Same-key commands are merged by priority.
::
# Union A1,A2 + B1,B2,B3,B4 = A1,A2,B3,B4
**Intersect** - Only commands found in *both* cmdsets (i.e. which have
the same keys) end up in the merged cmdset, with the higher-priority
cmdset replacing the lower one's commands.
::
# Intersect A1,A3,A5 + B1,B2,B4,B5 = A1,A5
**Replace** - The commands of the higher-prio cmdset completely replaces
the lower-priority cmdset's commands, regardless of if same-key commands
exist or not.
::
# Replace A1,A3 + B1,B2,B4,B5 = A1,A3
**Remove** - The high-priority command sets removes same-key commands
from the lower-priority cmdset. They are not replaced with anything, so
this is a sort of filter that prunes the low-prio set using the
high-prio one as a template.
::
# Remove A1,A3 + B1,B2,B3,B4,B5 = B2,B4,B5
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
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.
More advanced cmdset example:
::
class MyCmdSet(CmdSet): key = "MyCmdSet" priority = 4 mergetype = "Replace" key_mergetype = 'MyOtherCmdSet':'Union' 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())
System commands
---------------
*Note: This is an advanced topic. Skip it if this is your first time
learning about commands.*
There are several command-situations that are exceptional in the eyes of
the server. What happens if the player enters an empty string? What if
the 'command' given is infact the name of a channel the user wants to
send a message to? Or maybe the name of an exit they want to traverse?
Such 'special cases' are handled by what's called *system commands*. A
system command is defined in the same way as other commands, except that
their name (key) must be set to one reserved by the engine (the names
are defined at the top of ``src/commands/cmdhandler.py``). You can find
(unused) implementations of the system commands in
``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.
Here are the exceptional situations that triggers system commands:
- No input (``cmdhandler.CMD_NOINPUT``) - the player just pressed
return without any input. Default is to do nothing, but it can be
useful for certain implementations such as line editors that interpret
non-commands as text input.
- Command not found (``cmdhandler.CMD_NOMATCH``) - No matching command
was found. Default is to display the "Huh?" error message.
- Several matching commands where found (``cmdhandler.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
message.
- Channel (``cmdhandler.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.
Below is an example of redefining what happens when the player don't
give any input (e.g. just presses return). Of course the new system
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!")
How commands actually work
--------------------------
*Note: This is an advanced topic mainly of interest to server
developers.*
Any time the user sends text to Evennia, the server tries to figure out
if the text entered corresponds to a known command. This is how the
command handler sequence looks for a logged-in user:
A user (the *caller*) enters a string of text and presses enter.
- If input is an empty string, resend command as ``CMD_NOINPUT``. If no
such command is found in cmdset, ignore.
- If command.key matches ``settings.IDLE_COMMAND``, update timers but
don't do anything more.
Evennia's *commandhandler* gathers the CmdSets available to *caller* at
the time:
- The caller's own currently active !CmdSet.
- The active CmdSets of eventual objects in the same location (if any).
This includes commands on `Exits <Objects#Exits.html>`_.
- Sets of dynamically created *System commands* representing available
`Channels <Communications.html>`_.
- !CmdSet defined on the *caller.player* (OOC cmdset).
All the CmdSets are *merged* into one combined CmdSet according to each
set's merge rules.
Evennia's *command parser* takes the merged cmdset and matches each of
its commands (using its key and aliases) against the beginning of the
string entered by *caller*. This produces a set of candidates.
The *cmd parser* next rates the matches by how many characters they have
and how many percent matches the respective known command. Only if
candidates cannot be separated will it return multiple matches.
- If multiple matches were returned, resend as ``CMD_MULTIMATCH``. If
no such command is found in cmdset, return hard-coded list of
matches.
- If no match was found, resend as ``CMD_NOMATCH``. If no such command
is found in cmdset, give hard-coded error message.
If a single command was found by the parser, the correct command class
is plucked out of storage and instantiated.
It is checked that the caller actually has access to the command by
validating the *lockstring* of the command. If not, it is not considered
as a suitable match it is resent as ``CMD_NOPERM`` is created. If no
such command is found in cmdset, use hard-coded error message.
If the new command is tagged as a channel-command, resend as
``CMD_CHANNEL``. If no such command is found in cmdset, use hard-coded
implementation.
Assign several useful variables to the command instance.
Call ``at_pre_command()`` on the command instance.
Call ``parse()`` on the command instance. This is is fed the remainder
of the string, after the name of the command. It's intended to pre-parse
the string int a form useful for the ``func()`` method.
Call ``func()`` on the command instance. This is the functional body of
the command, actually doing useful things.
Call ``at_post_command()`` on the command instance.

View file

@ -0,0 +1,130 @@
<wiki:toc max*depth*
"3" />
======
Communications
Apart from moving around in the game world and talking, players might
need other forms of communication. This is offered by Evennia's ``Comm``
system. Stock evennia implements a 'MUX-like
::
system of channels, but there is nothing stopping you from changing things to better suit your taste. Comms rely on two main database objects -
Msg``and``Channel
::
. == Msg ==The
Msg
::
object is the basic unit of communication in Evennia. A message works a little like an e-mail; it always has a sender (a [Players Player]) and one or more recipients. The recipients may be either other Players, or a _Channel_ (see below). You can mix recipients to send the message to both Channels and Players if you like.Once created, a
Msg
::
is normally not changed. It is peristently saved in the database. This allows for comprehensive logging of communications, both in channels, but also for allowing senders/receivers to have 'mailboxes' with the messages they want to keep. === Properties defined on
Msg
::
=== *
sender
::
- this is a reference to a unique [Players Player] object sending the message. *
receivers
::
- a list of target [Players] to send to. *
channels
::
- a list of target Channels to send to. *
message
::
- the actual text being sent *
datesent
::
- when message was sent. *
locks
::
- a [Locks lock definition]. The following is currently unimplemented in Evennia (stay tuned): * hide_from_sender - bool if message should be hidden from sender * hide_from_receivers - list of receiver objects to hide message from * hide_from_channels - list of channels objects to hide message fromYou create new messages in code using
src.utils.create.create*message.*
::
===!TempMsg===
src.objects.models``contains a class called``TempMsg``that mimics a``Msg``but does not get saved to the database and do not require a sender object of a certain type. It's not used by default, but you could use it in code to send one-off messages to systems expecting a``Msg
::
.== Channels == Channels act as generic distributors of messages. Players _subscribe_ to channels and can then send and receive message from it. Channels have [Locks] to limit who may join them. There are three default channels created in stock Evennia -
MUDinfo``,``MUDconnections``and``Public
::
. Two first ones are server-related messages meant for Admins, the last one is open to everyone to chat on (all new players are automatically joined to it when logging in, useful for asking questions). You create new channels with
src.utils.create.createchannel()
::
.In code, messages are sent to a channel using the
msg(message, fromobj
None)``method. The argument``message``can either be a previously constructed``Msg``object or a message string. If you send a text string, you should usually also define``fromobj``; a``Msg``object will then be created for you behind the scenes. If you don't supply``from\_obj``, just the string will be sent to the channel and nothing will be stored in the database (could be useful for certain spammy error messages). You can also use``channel.tempmsg()``to always send a non-persistent message, also if you send it a``Msg
::
object.# assume we have a 'sender' object and a channel named 'mychan'# send and store in database from src.utils import create mymsg = create.create_message(sender, "Hello!", channels=[mychan]) mychan.msg(mymsg)# send a one-time message mychan.msg("Hello!")# send a one-time message created from a Msg object mychan.tempmsg(mymsg)
As a more advanced note, sending text to channels is a "special
exception" as far as commands are concerned, and you may completely
customize how this works by defining a *system*command\_ with your own
code. See `Commands <Commands.html>`_ for more details.
Properties defined on ``Channel``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``key`` - main name for channel
- ``aliases`` - alternative native names for channels
- ``desc`` - optional description of channel (seen in listings)
- ``keep_log`` (bool) - if the channel should store messages (default)
- ``locks`` - A `lock definition <Locks.html>`_. Channels normally use
the access\_types ``send, admin`` and ``listen``.
External Connections
====================
Channels may also communicate through what is called an *External
Connection*. Whereas normal users send messages through in-game Evennia
commands, an external connection instead takes data from a remote
location. `IMC2 <IMC2.html>`_ and `IRC <IRC.html>`_ connections make use
of this.

View file

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

View file

@ -0,0 +1,58 @@
Wanna help out? Great! Here's how.
Contributing with Documentation
===============================
Evennia depends heavily on good documentation and we are always looking
for extra eyes and hands to improve it. Even a small thing such as
fixing typos is a great help.
Contributing with Code
======================
Code sharing with Clone repository
----------------------------------
The most elegant way to contribute code to Evennia is to use Mercurial
to create an online *clone* of the Evennia repository and make your
changes to that. .
#. Go to the
`Checkout <http://code.google.com/p/evennia/source/checkout>`_ page.
#. If you are logged in, you should see a button named *Create a Clone*.
Click that.
#. You are asked to fill in a few fields. Name your clone repository
something snazzy. Give a brief summary, like "my repo for messing
around with Evennia". Accept.
#. Your new repo is created. This is actually your own mini-version of
the Evennia page! Go to your checkout page and use the command there
to get a local copy of your clone to your computer.
#. Code away on your computer, fixing bugs or whatnot (you can be
offline for this). Commit your code to your local clone as you work,
as often as you like.
#. When you have something you feel is worthwhile (or just want to ask
people's opinions or make an online backup), *push* your local code
up to your online repository with Mercurial.
#. Let people know what you did, talk discuss. If you think your changes
should be merged into main Evennia (maybe you have made bugfixes,
added new features etc), make a new
`Issue <http://code.google.com/p/evennia/issues/list>`_ using the
"Merge Request" template. Try to separate features with different
commits, so it's possible to pick individual features.
From your online repo, Evennia devs can then, assuming the change is
deemed good, pick and merge your work into Evennia proper.
Patches
-------
It's recommended to use a clone repository as described above. Otherwise
you are also welcome to submit your suggested Evennia fixes/addendums as
`patches <https://secure.wikimedia.org/wikipedia/en/wiki/Patch_(computing).html>`_
if you like. Depending on what fits best, post your patch to the `issue
tracker <https://code.google.com/p/evennia/issues/list.html>`_ or to the
`discussion
forum <https://groups.google.com/forum/#!forum/evennia.html>`_. Please
avoid pasting the full patch text directly in your post though, best is
to use a site like `Pastebin <http://pastebin.com/>`_ and just supply
the link.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,79 @@
Developer Central
=================
This page serves as a central nexus for useful information regarding
coding using the Evennia codebase, and also for development of the
codebase itself. Everyone is welcome to help out! If you have any
questions, please feel free to ask them in the `Forum/Discussion
Group <http://www.evennia.com/discussions>`_. Bugs should be reported to
the `Issue tracker <http://code.google.com/p/evennia/issues/list>`_. You
can find more links to Evennia resources from the `Links <Links.html>`_
page.
General Evennia development information
---------------------------------------
- `Evennia Licensing FAQ <Licensing.html>`_
- `Contributing code to Evennia <Contributing.html>`_
- `Evennia Code Style
Guide <http://evennia.googlecode.com/svn/trunk/CODING_STYLE>`_
(Important!)
- `Policy for 'MUX-like' default commands <UsingMUXAsAStandard.html>`_
<wiki:comment>
- `Setting up a Bazaar environment for coding <BazaarDevel.html>`_
</wiki:comment>
Evennia Component Documentation
-------------------------------
`Directory Overview <DirectoryOverview.html>`_
`Portal and Server <PortalAndServer.html>`_
`Commands <Commands.html>`_
`Typeclass system <Typeclasses.html>`_
- `Objects <Objects.html>`_
- `Scripts <Scripts.html>`_
- `Players <Players.html>`_
- `Attributes <Attributes.html>`_
`Locks and Permissions <Locks.html>`_
`Communications <Communications.html>`_
`Help System <HelpSystem.html>`_
`Nicks <Nicks.html>`_
`Sessions and Protocols <SessionProtocols.html>`_
`Web features <WebFeatures.html>`_
Programming Evennia
-------------------
- `Running and Testing Python code from inside the
game <ExecutePythonCode.html>`_
- `Running and writing unit tests for Evennia <UnitTesting.html>`_
- `Removing Colour from your game - tutorial on redefining typeclass
methods <RemovingColour.html>`_
- `Adding a Command prompt <CommandPrompt.html>`_
- `Running processes asynchronously <AsyncProcess.html>`_
Work in Progress - Developer brainstorms and whitepages
-------------------------------------------------------
*In this section, contributors may suggest, discuss and plan out new
features and ideas. Items here may or may not make it into Evennia down
the road.*
- `Basic game system implementation <WorkshopDefaultGame.html>`_
- `Rtclient protocol <Workshop.html>`_
- `Summary of changes <EvenniaDevel.html>`_ of latest version vs old
Evennia (pre aug2010)

View file

@ -0,0 +1,274 @@
Evennia directory overview
==========================
Evennia's main directory (``evennia``) is divided into four sub
directories - ``src/``, ``game/``, ``contrib/``, ``locale`` and
``doc/``. The first two are the most important ones. ``game/`` is the
place where you will create your own game, whereas ``src/`` is the home
of the Evennia server itself. Your code should usually just import
resources from ``src/`` and not change anything in there.
All directories contain files ending in ``.py``. These are Python
*modules* and are the basic units of Python code. The roots of
directories also have empty files named ``__init__.py``. These are
required by Python so as to be able to find and import modules in other
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 ``docs/`` directory
-----------------------
You may have noticed that ``docs/`` is pretty empty. This is because you
are in fact reading the docs right now - this wiki *is* the
documentation.
You can create the *autodocs* of Evennia by following the instructions
in ``docs/README``. This will make use of the source code itself to
create a nice browsable web-index of all the sources and comments. In
the same way you could in theory also create nice ``LaTeX``-formatted
PDFs of the Evennia source (all 300+ pages of it ...).
The ``locale`` directory
------------------------
This contains internationalization strings for translating the Evennia
core server to different languages. See
`Internationalization <Internationalization.html>`_ for more
information.
The ``contrib/`` ("contributions") directory
--------------------------------------------
This directory contains various stand-alone code snippets that are
potentially useful but which are deemed too game-specific to be a
regular part of the server. Modules in ``contrib/`` are not used unless
you explicitly import and use them. The contrib folder also contains the
`Tutorial World <TutorialWorldIntroduction.html>`_ game example. See
``contrib/README`` for more information.
The ``game/`` directory
-----------------------
``game/`` contains everything related to a particular game world. If you
ever wanted to start over with a new game implementation you could
replace the ``game`` directory and start from scratch. The root of this
directory contains the all-important ``manage.py`` and ``evennia.py``
which you need in order to `get started <GettingStarted.html>`_ and run
the server.
::
game/
evennia.py
manage.py gamesrc/ commands/ basecommand.py basecmdset.py examples/ cmdset_red_button.py scripts/ basescript.py examples/ red_button_sripts.py objects/ baseobjects.py examples/ red_button.py world/ examples/ batch_cmds.ev batch_code.py
``game/gamesrc/``
~~~~~~~~~~~~~~~~~
``game/gamesrc`` is where you will be spending most of your time. All
the things going into your own dream game should be put here, by adding
Python modules. Throughout the ``gamesrc`` directories are ``examples``
folders that all define different aspects of an example
`object <Objects.html>`_ called *Red Button*. This is a button that
blinks and does interesting stuff when pressed. It's designed to combine
many different systems and to show off several advanced features of
Evennia.
``gamesrc/commands/``
^^^^^^^^^^^^^^^^^^^^^
``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*.
``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.
``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.
``gamesrc/world/``
^^^^^^^^^^^^^^^^^^
``gamesrc/world/``, finally, contains all the rest that make up your
world. This is where you would put your own custom economic system,
combat mechanic, emote-parser or what have you; organized in whatever
way you like. Just remember that if you create new folders under
``world``, they must contain an empty file ``__init__.py``, or Python
will not know how to import modules from them. The ``world`` folder is
also where Evennia's `batch processors <BatchProcessors.html>`_ by
default look for their input files. These allow you to build your world
offline using your favourite text editor rather than have to do it
online over a command line. The `Batch-Command
processor <BatchCommandProcessor.html>`_ expects files ending with
``.ev``, whereas the more advanced `Batch-Code
processor <BatchCodeProcessor.html>`_ takes ``.py`` with some special
formatting.
``world/examples/`` contains one batch file for each processor. Each
creates a *Red Button* object in *Limbo* using their respective special
syntax.
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/
settings_defaults.py commands/ comms/ help/ objects/ locks/ players/ scripts/ server/ typeclasses/ utils/ web/
Most of the folders in ``src/`` are technically "Django apps",
identified by containing a file ``models.py`` and usually
``managers.py``. A Django *model* is a template for how to save data to
the database. In order to offer full-persistence, Evennia uses models
extensively. The *manager* is used to conveniently access objects in the
database. Even if you don't know Django, you can easily use the methods
in the respective managers by accessing them through the *objects*
property of each corresponding model. Example: in
``src/objects/models.py`` there is a model named ``ObjectDB``. In the
same folder, there is also a manager found in
``src/objects/managers.py``. To access one of the manager's methods,
such as ``object_search()``, you would need to do
``ObjectDB.objects.object_search(...)``.
All Django app folders also have a file ``admin.py``. This tells
Django's web features to automatically build a nice web-based admin
interface to the database. This means that you can add/edit/delete
objects through your browser.
In the root of the ``src`` directory lies the ``settings_defaults.py``
file. This is the main configuration file of Evennia. You should
copy&paste entries from this file to your ``game/settings.py`` file if
you want to customize any setting.
``src/commands/``
~~~~~~~~~~~~~~~~~
This directory contains the `command system <Commands.html>`_ of
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
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
module to ``game/gamesrc/commands/`` and edit the default cmdset to
point to your copy.
``src/comms/``
~~~~~~~~~~~~~~
``src/comms/`` defines all aspects of OOC
`communication <Communications.html>`_, notably *channels* and the basic
operations for storing listeners to channels.
``src/help/``
~~~~~~~~~~~~~
This defines the `help system <HelpSystem.html>`_ of Evennia, the
command auto-help as well as the database-centric storage of in-game
help files.
``src/objects/``
~~~~~~~~~~~~~~~~
``src/objects/`` defines how the in-game `objects <Objects.html>`_ are
stored, found and handled in the database.
``src/locks/``
~~~~~~~~~~~~~~
This directory defines the powerful `lock system <Locks.html>`_ of
Evennia, a system that serves to restrict access to objects. The default
lock functions are found here.
``src/players/``
~~~~~~~~~~~~~~~~
The `Player <Players.html>`_ is the OOC-represention of the person
behind the game character. This directory defines the database handling
and methods acting on the Player object.
``src/scripts/``
~~~~~~~~~~~~~~~~
``src/scripts/`` defines all aspects of `Scripts <Scripts.html>`_ - how
they are activated, repeated and stored in-memory or in-database. The
main engine scripts (e.g. for keeping track of game-time, uptime and
connection timeouts) are also defined here.
``src/server/``
~~~~~~~~~~~~~~~
This directory is the heart of Evennia. It holds the server process
itself (started from ``game/evennia.py``) and all `sessions and
protocols <SessionProtocols.html>`_ that allow users to connect to it.
It also knows how to store dynamic server info in the database.
``src/typeclasses/``
~~~~~~~~~~~~~~~~~~~~
``src/typeclasses/`` defines the `Typeclass system <Typeclasses.html>`_
that permeates Evennia, allowing coders to interact with normal Python
classes instead of caring about the underlying database implementation.
This directory is rarely accessed directly, rather both Objects, Scripts
and Players all inherit from its core classes. Also
`attributes <Attributes.html>`_ are defined here, being an vital part of
the typeclass system.
``src/utils/``
~~~~~~~~~~~~~~
``src/utils/`` is a useful directory that contains helper functions for
the MUD coder. The ``utils/create.py`` module for example gathers
methods for creating all sorts of database models (objects, scripts,
help entries etc) without having to go into the respective database
managers directly. ``utils/search.py`` search a similar function for
searching the database. This directory also contains many helper modules
for parsing and converting data in various ways.
``src/web/``
~~~~~~~~~~~~
This directory contains features related to running Evennia's `web site
and ajax web client <WebFeatures.html>`_. It will be customizable by the
user, but it's currently not established how to conveniently hook into
this from game/, so for the moment the suggested way is to make a copy
of this directory in ``game/gamesrc``, re-link the right settings in
your settings file and edit things from there.
Assorted notes
==============
Whereas ``game/gamesrc/`` contains a set of directories already, you
might find that another structure suits your development better. For
example, it could sometimes easier to put all the commands and scripts a
certain object needs in the same module as that object, rather than
slavishly split them out into their respective directories and import.
Don't be shy to define your own directory structure as needed. A basic
rule of thumb should nevertheless be to avoid code-duplication. So if a
certain script or command could be useful for other objects, break it
out into its own module and import from it.

View file

@ -0,0 +1,372 @@
Summary of changes in devel-branch
<wiki:toc max\_depth
"3" />
*Note: The devel branch merged with trunk as of r970. So if you are new
to Evennia, this page is of no real interest to you.*
Introduction
The Evennia that has been growing in trunk for the last few years is a
wonderful piece of software, with which you can do very nice coding
work. It has however grown 'organically', adding features here and there
by different coders at different times, and some features (such as my
State system) were bolted onto an underlying structure for which it was
never originally intended. Meanwhile Evennia is still in an alpha stage
and not yet largely used. If one needs to do a cleanup/refactoring and
homogenization of the code, now is the time time to do it. So I set out
to do just that.
The "devel-branch" of Evennia is a clean rework of Evennia based on
trunk. I should point out that the main goal has been to make system
names consistent, to add all features in a fully integrated way, and to
give all subsystems a more common API for the admin to work against.
This means that in the choice between a cleaner implementation and
backwards-compatability with trunk, the latter has had to stand back.
However, you'll hopefully find that converting old codes shouldn't be
too hard. Another goal is to further push Evennia as a full-fledged
barebones system for *any* type of mud, not just MUX. So you'll find far
more are now user-configurability now than ever before (MUX remains the
default though).
Devel is now almost ready for merging with the main trunk, but it needs
some more eyes to look at it first. If you are brave and want to help
report bugs, you can get it from the *griatch* branch with
``svn checkout http://evennia.googlecode.com/svn/branches/griatch evennia-devel``
Concepts changed from trunk to devel=
Script parent -> Typeclasses
----------------------------
The biggest change is probably that script parents have been replaced by
*typeclasses*. Both handle the abstraction of in-game objects without
having to create a separate database model for each (i.e. it allows
objects to be anything from players to apples, rooms and swords all with
the same django database model). A script parent in trunk was a class
stored in a separate module together with a 'factory' function that the
engine called. The admin had to always remember if they were calling a
function on the database model or if it in fact sat on the script parent
(the call was made through something called the "scriptlink").
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
admin don't really have to worry about this connection, they can usually
consider the two objects (typeclass and django model) to be one.
So if you have your 'apple' typeclass, accessing, say the 'location',
which is stored as a persistent field on the django model, you can now
just do ``loc = apple.location`` without caring where it is stored.
The main drawback with any typeclass/parent system is that it adds an
overhead to all calls, and this overhead might be slightly larger with
typeclasses than with trunk's script parents although I've not done any
testing. You also need to use Evennia's supplied ``create`` methods to
create the objects rather than to create objects with plain Django by
instantiating the model class; this so that the rather complex
relationships can be instantiated safely behind the scenes.
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.
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
command can exist in any number of cmdsets at the same time. Also the
'default' group of commands belong to a cmdset. These command sets are
no longer stored globally, but instead locally on each object capable of
launching commands. You can add and new cmdsets to an object in a
stack-like way. The cmdsets support set operations (Union, Difference
etc) and will merge together into one cmdset with a unique set of
commands. Removing a cmdset will re-calculate those available commands.
This allows you to do things like the following (impossible in trunk): A
player is walking down a corridor. The 'default' cmdset is in play. Now
he meets an enemy. The 'combat' cmdset is merged onto (and maybe
replacing part of) the default cmdset, giving him new combat-related
commands only available during combat. The enemy hits him over the head,
dazing him. The "Dazed" cmdset is now added on top of the previous ones
- maybe he now can't use certain commands, or might even get a garbled
message if trying to use 'look'. After a few moments the dazed state is
over, and the 'Dazed' cmdset is removed, returning us to the combat mode
we were in before. And so on.
Command definitions used to be functions, but are now classes. Instead
of relying on input arguments, all relevant variables are stored
directly on the command object at run-time. Also parsing and function
execution have been split into two methods that are very suitable for
subclassing (an example is all the commands in the default set which
inherits from the MuxCommand class - that's the one knowing about MUX's
special syntax with /switches, '=' and so on, Evennia's core don't deal
with this at all!).
Example of new command definition:
::
class CmdTest(Command): def func(self): self.caller.msg("This is the test!")
Events + States -> Scripts
--------------------------
The Event system of Evennia used to be a non-persistent affair; python
objects that needed to be explicitly called from code when starting.
States allowed for mapping different groups of commands to a certain
situations (see CmdSets above for how commands are now always grouped).
*Scripts* (warning: Not to be confused with the old *script parents*!)
are persistent database objects now and are only deleted on a server
restart if explicitly marked as non-persistent.
A script can have a time-component, like Events used to have, but it can
also work like an 'Action' or a 'State' since a script constantly checks
if it is still 'valid' and if not will delete itself. A script handles
everything that changes with time in Evennia. For example, all players
have a script attached to them that assigns them the default cmdset when
logging in.
Oh, and Scripts have typeclasses too, just like Objects, and carries all
the same flexibility of the Typeclass system.
User + player -> User + Player + character
------------------------------------------
In trunk there is no clear separation between the User (which is the
django model representing the player connecting to the mud) and the
player object. They are both forced to the same dbref and are
essentially the same for most purposes. This has its advantages, but the
problem is configurability for different game types - the in-game player
object becomes the place to store also OOC info, and allowing a player
to have many characters is a hassle (although doable, I have coded such
a system for trunk privately). Devel-branch instead separate a "player
character" into three tiers:
- The User (Django object)
- The PlayerDB (User profile + Player typeclass)
- The ObjectDB (+ Character typeclass)
User is not something we can get out of without changing Django; this is
a permission/password sensitive object through which all Django users
connect. It is not configurable to any great extent except through it's
*profile*, a django feature that allows you to have a separate model
that configures the User. We call this profile 'PlayerDB', and for
almost all situations we deal with this rather than User. PlayerDB can
hold attributes and is typeclassed just like Objects and Scripts
(normally with a typeclass named simply *Player*) allowing very big
configurability options (although you can probably get away with just
the default setup and use attributes for all but the most exotic
designs). The Player is an OOC entity, it is what chats on channels but
is not visible in a room. The last stage is the in-game ObjectDB model,
typeclassed with a class called 'Character' by default. This is the
in-game object that the player controls.
The neat thing with this separation is that the Player object can easily
switch its Character object if desired - the two are just linking to
each other through attributes. This makes implementing multi-character
game types much easier and less contrived than in the old system.
Help database -> command help + help database
---------------------------------------------
Trunk stores all help entries in the database, including those created
dynamically from the command's doc strings. This forced a system where
the auto-help creation could be turned off so as to not overwrite later
changes made by hand. There was also a mini-language that allowed for
creating multiple help entries from the ``__doc__`` string.
Devel-branch is simpler in this regard. All commands are *always* using
``__doc__`` on the fly at run time without hitting the database (this
makes use of cmdsets to only show help for commands actually available
to you). The help database is stand-alone and you can add entries to it
as you like, the help command will look through both sources of help
entries to match your query.
django-perms + locks -> permission/locks
----------------------------------------
Trunk relies on Django's user-permissions. These are powerful but have
the disadvantage of being 'app-centric' in a way that makes sense for a
web app, not so much for a mud. The devel-branch thus implements a
completely stand-alone permission system that incoorperate both
permissions and locks into one go - the system uses a mini-language that
has a permission string work as a keystring in one situation and as a
complex lock (calling python lock functions you can define yourself) in
another.
The permission system is working on a fundamental level, but the default
setup probably needs some refinements still.
Mux-like comms -> Generic comms
-------------------------------
The trunk comm system is decidedly MUX-like. This is fine, but the
problem is that much of that mux-likeness is hard-coded in the engine.
Devel just defines three objects, Channel and Msg and an object to track
connections between players and channels (this is needed to easily
delete/break connections). How they interact with each other is up to
the commands that use them, making the system completely configurable by
the admin.
All ooc messages - to channels or to players or both at the same time,
are sent through use of the Msg object. This means a full log of all
communications become possible to keep. Other uses could be an e-mail
like in/out box for every player. The default setup is still mux-like
though.
Hard-coded parsing -> user customized parsing
---------------------------------------------
Essentially all parts of parsing a command from the command line can be
customized. The main parser can be replaced, as well as error messages
for multiple-search matches. There is also a considerable difference in
handling exits and channels - they are handled as commands with their
separate cmdsets and searched with the same mechanisms as any command
(almost any, anyway).
Aliases -> Nicks
----------------
Aliases (that is, you choosing to for yourself rename something without
actually changing the object itself) used to be a separate database
table. It is now a dictionary 'nicks' on the Character object - that
replace input commands, object names and channel names on the fly. And
due to the separation between Player and Character, it means each
character can have its own aliases (making this a suitable start for a
recog system too, coincidentally).
Attributes -> properties
------------------------
To store data persistently in trunk requires you to call the methods
``get_attribute_value(attr)`` and ``set_attribute(attr, value)``. This
is available for in-game Objects only (which is really the only data
type that makes sense anyway in Trunk).
Devel allows attribute storage on both Objects, Scripts and Player
objects. The attribute system works the same but now offers the option
of using the ``db`` (for database) directly. So in devel you could now
just do:
::
obj.db.attr = value value = obj.db.attr
And for storing something non-persistently (stored only until the server
reboots) you can just do
::
obj.attr = value value = obj.attr
The last example may sound trivial, but it's actually impossible to do
in trunk since django objects are not guaranteed to remain the same
between calls (only stuff stored to the database is guaranteed to
remain). Devel makes use of the third-party ``idmapper`` functionality
to offer this functionality. This used to be a very confusing thing to
new Evennia admins.
*All* database fields in Devel are now accessed through properties that
handle in/out data storage. There is no need to save() explicitly
anymore; indeed you should ideally not need to know the actual Field
names.
Always full persistence -> Semi/Full persistence
------------------------------------------------
In Evennia trunk, everything has to be saved back/from the database at
all times, also if you just need a temporary storage that you'll use
only once, one second from now. This enforced full persistency is a good
thing for most cases - especially for web-integration, where you want
the world to be consistent regardless of from where you are accessing
it. Devel offer the ability to yourself decide this; since
semi-persistent variables can be stored on objects (see previous
section). What actually happens is that such variables are stored on a
normal python object called ``ndb`` (non-database), which is
transparently accessed. This does not touch the database at all.
Evennia-devel offers a setting ``FULL_PERSISTENCE`` that switches how
the server operates. With this off, you have to explicitly assign
attributes to database storage with e.g. ``obj.db.attr = value``,
whereas normal assignment (``obj.attr = value``) will be stored
non-persistent. With ``FULL_PERSISTENT`` on however, the roles are
reversed. Doing ``obj.attr = value`` will now actually be saving to
database, and you have to explicitly do ``obj.ndb.attr = value`` if you
want non-persistence. In the end it's a matter of taste and of what kind
of game/features you are implementing. Default is to use full
persistence (but all of the engine explicitly put out ``db`` and ``ndb``
making it work the same with both).
Commonly used functions/concept that changed names
==================================================
There used to be that sending data to a player object used a method
``emit_to()``, whereas sending data to a session used a method
``msg()``. Both are now called ``msg()``. Since there are situations
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().
``source_object`` in default commands are now consistently named
*caller* instead.
``obj.get_attribute_value(attr)`` is now just
``obj.get_attribute(attr)`` (but see the section on Attributes above,
you should just use ``obj.db.attr`` to access your attribute).
How hard is it to convert from trunk to devel?
==============================================
It depends. Any game logic game modules you have written (AI codes,
whatever) should ideally not do much more than take input/output from
evennia. These can usually be used straight off.
Commands and Script parents take more work but translate over quite
cleanly since the idea is the same. For commands, you need to make the
function into a class and add the parse(self) and func(self) methods
(parse should be moved into a parent class so you don't have to use as
much double code), as well as learn what variable names is made
available (see the commands in ``gamesrc/commands/default`` for
guidance). You can make States into CmdSets very easy - just listing the
commands needed for the state in a new !CmdSet.
Script parents are made into Typeclasses by deleting the factory
function and making them inherit from a TypeClassed object (such as
Object or Player) like the ones in ``gamesrc/typeclasses/basetypes.py``,
and then removing all code explicitly dealing with script parents.
Converting to the new Scripts (again, don't confuse with the old *script
parents*!) is probably the trickiest, since they are a more powerful
incarnation of what used to be two separate things; States and Events.
See the examples in the ``gamesrc/scripts/`` for some ideas.
Better docs on all of this will be forthcoming.
Things not working/not implemented in devel (Aug 2010)
======================================================
All features planned to go into Devel are finished. There are a few
features available in Trunk that is not going to work in Devel until
after it merges with Trunk:
- IMC2/IRC support is not implemented.
- Attribute-level permissions are not formalized in the default cmdset.
- Some of the more esoteric commands are not converted.
Please play with it and report bugs to our bug tracker!

View file

@ -0,0 +1,139 @@
"*A MUD (originally Multi-User Dungeon, with later variants Multi-User
Dimension and Multi-User Domain), pronounced /ˈmʌd/, is a multiplayer
real-time virtual world described primarily in text. MUDs combine
elements of role-playing games, hack and slash, player versus player,
interactive fiction, and online chat. Players can read or view
descriptions of rooms, objects, other players, non-player characters,
and actions performed in the virtual world. Players typically interact
with each other and the world by typing commands that resemble a natural
language.*" - `Wikipedia <http://en.wikipedia.org/wiki/MUD>`_
Evennia introduction
====================
If you are reading this, it's quite likely you are dreaming of creating
and running a text-based massively-multiplayer game
(`MUD/MUX/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
reality. We know how you feel. That is, after all why Evennia came to
be.
Evennia is in principle a MUD-building system: a bare-bones Python
codebase and server intended to be highly extendable for any style of
game. "Bare-bones" in this context means that we try to impose as few
game-specific things on you as possible. So whereas we for convenience
offer basic building blocks like objects, characters, rooms, default
commands for building and administration etc, we don't prescribe any
combat rules, mob AI, races, skills, character classes or other things
that will be different from game to game anyway. It is possible that we
will offer some such systems as contributions in the future, but these
will in that case all be optional.
What we *do* however, is to provide a solid foundation for all the
boring database, networking, and behind-the-scenes administration stuff
that all online games need whether they like it or not. Evennia is by
default *fully persistent*, that means things you drop on the ground
somewhere will still be there a dozen server reboots later. Through
Django, we support a large variety of different database systems (the
default of which is created for you automatically).
Using the full power of Python throughout the server offers some
distinct advantages. All your coding, from object definitions and custom
commands to AI scripts and economic systems are done in normal Python
modules rather than some ad-hoc scripting language. The fact that you
script the game in the same high-level language that you code it in
allows for very powerful and custom game implementations indeed.
The server ships with a default set of player commands that are similar
to the MUX command set. We *do not* aim specifically to be a MUX server,
but we had to pick some default to go with (see `this <SoftCode.html>`_
for more about our original motivations). It's easy to remove or add
commands, or to have the command syntax mimic other systems, like Diku,
LP, MOO and so on. Or why not create a new and better command system of
your own design.
There is already a default django website as well as an ajax web client
shipping with Evennia. You can also edit the database from the browser
using the admin interface. Apart from telnet, SSH, SSL and web
connections, you can connect e.g. IRC and IMC2 channels to evennia's
in-game channels so that your players can chat with people "outside" the
game. If you didn't see it before, there is a
`screenshot <Screenshot.html>`_ of Evennia running that shows some of
the connections in action.
What you need to know to work with Evennia
==========================================
Assuming you have Evennia working (see the `quick start
instructions <GettingStarted.html>`_) and have gotten as far as to start
the server and connect to it with the client of your choice, here's what
you need to know depending on your skills and needs.
I don't know (or don't want to do) any programming - I just want to run
a game!
-------------------------------------------------------------------------------
Evennia comes with a default set of commands for the Python newbies and
for those who need to get a game running *now*. Stock Evennia is enough
for running a simple 'Talker'-type game - you can build and describe
rooms and basic objects, have chat channels, do emotes and other things
suitable for a social or free-form MU``*``. Combat, mobs and other game
elements are not included, so you'll have a very basic game indeed if
you are not willing to do at least *some* coding.
I know basic Python, or am willing to learn
-------------------------------------------
Evennia's source code is extensively documented and `viewable
online <http://code.google.com/p/evennia/source/browse/trunk>`_. We also
have a comprehensive `online
manual <http://code.google.com/p/evennia/wiki/Index>`_ with lots of
examples. But while Python is a relatively easy programming language, it
still represents a learning curve if you are new to programming. You
should probably sit down with a Python beginner's
`tutorial <http://docs.python.org/tutorial/tutorial>`_ (there are plenty
of them on the web if you look around) so you at least know know what
you are seeing. To efficiently code your dream game in Evennia you don't
need to be a Python guru, but you do need to be able to read example
code containing at least these basic Python features:
- Importing python modules
- Using variables, `conditional
statements <http://docs.python.org/tutorial/controlflow.html#if-statements>`_,
`loops <http://docs.python.org/tutorial/controlflow.html#for-statements>`_
and
`functions <http://docs.python.org/tutorial/controlflow.html#defining-functions>`_
- Using `lists, dictionaries and list
comprehensions <http://docs.python.org/tutorial/datastructures.html>`_
- Doing `string handling and
formatting <http://docs.python.org/tutorial/introduction.html#strings>`_
- Using `Classes <http://docs.python.org/tutorial/classes.html>`_,
their methods and properties
Obviously, the more things you feel comfortable with, the easier time
you'll have to find your way. With just basic knowledge you should be
able to define your own `Commands <Commands.html>`_, create custom
`Objects <Objects.html>`_ as well as make your world come alive with
basic `Scripts <Scripts.html>`_. You can definitely build a whole
advanced and customized game from extending Evennia's examples only.
I know my Python stuff and am willing to use it!
------------------------------------------------
Even if you started out as a Python beginner, you will likely get to
this point after working on your game for a while. With more general
knowledge in Python the full power of Evennia opens up for you. Apart
from modifying commands, objects and scripts, you can develop everything
from advanced mob AI and economic systems, through sophisticated combat
and social minigames, to redefining how commands, players, rooms or
channels themselves work. Since you code your game by importing normal
Python modules, there are few limits to what you can accomplish.
If you *also* happen to know some web programming (HTML, CSS,
Javascript) there is also a web presence (a website and an mud web
client) to play around with ...
From here you can continue to the `Index <Index.html>`_ to find more
info about Evennia.

View file

@ -0,0 +1,137 @@
<wiki:toc max\_depth
"3" />
======
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.
::
@py 1+2 <<< 3
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.
- **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
Returning output
----------------
This is an example where we import and test one of Evennia's utilities
found in ``src/utils/utils.py``:
::
@py from src.utils 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
complex pieces of code which has no single obvious return value. To see
the output from the ``time_format()`` function we need to tell the
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.
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
running Evennia in *interactive mode* (with the ``-i`` flag).
Finding objects
---------------
A common use for ``@py`` is to explore objects in the database, for
debugging and performing specific operations that are not covered by a
particular command.
Locating an object is best done using ``self.search()``:
::
@py self.search("red_ball") <<< Ball @py self.search("red_ball").db.color = "red" <<< Done. @py self.search("red_ball").db.color <<< red
``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``.
::
@py from src.utils import search; self.msg(search.scripts("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.
::
@py ScriptDB.objects.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:
::
@py ConfigValue.objects.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
the managers will return *!TypeClasses*. Using Django's default search
methods (``get``, ``filter`` etc) will return *Database objects*. This
distinction can often be disregarded, but as a convention you should try
to stick with the manager search functions and work with TypeClasses in
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'>
Running a Python Parser outside the game
========================================
``@py`` has the advantage of operating inside a running server, where
you can test things in real time. Much of this *can* be done from the
outside too though.
Go to the ``game`` directory and get into a new terminal.
::
python manage.py shell
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
`iPython <http://ipython.scipy.org/moin/>`_ allow you to work over
several lines, it 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>, ...]

View file

@ -0,0 +1,313 @@
Getting Started
===============
This will help you download, install and start Evennia for the first
time.
Quick start
-----------
For you who are extremely impatient, here's the gist of getting a
vanilla Evennia install running.
#. *Get the pre-requisites (mainly Python, Django, Twisted and
Mercurial)*.
#. *Start a command terminal/dos prompt and change directory to where
you want to have your 'evennia' folder appear*.
#. ``hg clone https://code.google.com/p/evennia/ evennia``
#. *Change directory to evennia/game*.
#. ``python manage.py``
#. ``python manage.py syncdb``
#. ``python evennia.py -i start``
Evennia should now be running and you can connect to it by pointing a
web browser to ``http://localhost:8000`` or a MUD telnet client to
``localhost:4000``.
Read on for more detailed instructions and configurations.
Pre-Requesites
--------------
As far as operating systems go, any system with Python support should
work.
- Linux/Unix
- Windows (2000, XP, Vista, Win7)
- Mac OSX (>=10.5 recommended)
If you run into problems, or have success running Evennia on another
platform, please let us know.
You'll need the following packages and minimum versions in order to run
Evennia:
**Python** (http://www.python.org)
- Version 2.5+ strongly recommended, although 2.3 or 2.4 **may** work.
Obs- Python3.x is not supported yet.
- The default database system SQLite3 only comes as part of Python2.5
and later.
- Python is available in all modern operating systems (Linux, Mac,
etc).
- Windows users are recommended to use ActivePython
(http://www.activestate.com/activepython)
**Twisted** (http://twistedmatrix.com)
Version 10.0+
Twisted also requires:
- !ZopeInterface 3.0+ (http://www.zope.org/Products/ZopeInterface)
- For Windows only: pywin32 (http://sourceforge.net/projects/pywin32)
**Django** (http://www.djangoproject.com)
- Version 1.2.1+ or latest subversion trunk highly recommended.
- PIL library (http://www.pythonware.com/products/pil)
To download/update Evennia:
**Mercurial** (http://mercurial.selenic.com/)
- This is needed to download and update Evennia itself.
Optional packages:
**South** (http://south.aeracode.org/)
- Version 0.7+
- Optional. Used for database migrations.
**Apache2** (http://httpd.apache.org)
- Optional. Most likely you'll not need to bother with this since
Evennia runs its own threaded web server based on Twisted. Other
equivalent web servers with a Python interpreter module can also be
used.
*Note: You don't need to make anything visible to the 'net in order to
run and test out Evennia. Apart from downloading/updating Evennia itself
you don't even need to have an internet connection. Of course you'll
probably want that as your game matures, but until then it works nicely
to develop and play around completely in the sanctity and isolation of
your local machine.*
Installing pre-requisites
~~~~~~~~~~~~~~~~~~~~~~~~~
**Linux** package managers should usually handle all this for you.
Python itself is definitely available through all distributions. On
Debian-derived systems you can do something like this (as root) to get
all you need:
``apt-get install python python-django python-twisted mercurial``
If some or all dependencies are not readily available (for example,
running some flavors of !RedHat/CentOS or an older Debian version) you
can still retrieve them easily by using Python's
`easyinstall <http://packages.python.org/distribute/easy%3Ci%3Einstall.html>`_
or the alternative
`pip <http://www.pip-installer.org/en/latest/index.html>`_:
``easy_install django twisted pil mercurial``
``pip install django twisted pil mercurial``
**Windows** users may choose to install
`ActivePython <http://www.activestate.com/activepython>`_ instead of the
usual Python. 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:
``pypm install Django Twisted PIL Mercurial``
Another simple alternative (for all platforms) is to set up a *virtual
Python environment* and install to that. This is covered
`here <GettingStarted#Optional:%3Ci%3EA%3C/i%3Eseparate%3Ci%3Einstallation%3C/i%3Eenvironment%3Ci%3Ewith%3C/i%3Evirtualenv.html>`_.
Windows users not using ActivePython or virtual environments will have
to manually download and install the packages in turn - most have normal
Windows installers, but in some cases you'll need to know how to use the
Windows command prompt to execute some python install scripts.
Step 1: Obtaining the Server
----------------------------
To download Evennia you need the Mercurial client to grab a copy of the
source.
For command-line Mercurial client users, something like this will do the
trick (first place yourself in a directory where you want a new folder
``evennia`` to be created):
``hg clone https://code.google.com/p/evennia/ evennia``
(``hg`` is the chemical abbreviation of mercury, hence the use of ``hg``
for ``mercurial``)
In the future, you just do
``hg pull``
from your ``evennia/`` directory to obtain the latest updates.
If you use a graphical Mercurial client, use the equivalent buttons to
perform the above operations.
Step 2: Setting up the Server
-----------------------------
From within the Evennia ``game`` directory (``evennia/game/``, if you
followed the Subversion instructions above) type the following to
trigger the automatic creation of an empty ``settings.py`` file.
``python manage.py``
Your new ``settings.py`` file will just be an empty template initially.
In ``evennia/src/settings_default.py`` you will find the settings that
may be copied/pasted into your ``settings.py`` to override the defaults.
This will be the case if you want to adjust paths or use something other
than the default SQLite3 database engine. You *never* want to modify
``settings_default.py`` directly - as the server is developed, this file
might be overwritten with new versions and features.
If you would like to use something other than the default SQLite setup
(which works "out of the box"), you'll need to copy the ``DATABASE_*``
variables from ``settings_defaults.py`` and paste them to
``settings.py``, making your modifications there.
*Note that the settings.py file is in fact a normal python module which
imports the default settings. This means that all variables have been
set to default values by the time you get to change things. So to
customize a particular variable you have to copy&paste it to your
settings file - and you have to do so also for variables that depend on
that variable (if any), or the dependent variables will remain at the
default values.*
Finally, enter the following command in a terminal or shell to create
the database file (in the case of SQLite) and populate the database with
the standard tables and values:
``python manage.py syncdb``
You should be asked for a superuser username, email, and password. Make
**sure** you create a superuser here when asked, this becomes your login
name for the superuser account ``#1`` in game. After this you will see a
lot of spammy install messages. If all goes well, you're ready to
continue to the next step. If not, look at the error messages and
double-check your ``settings.py`` file.
If you installed ``South`` for database schema migrations, you will then
need to do this:
``python manage.py migrate``
This will migrate the server to the latest version. If you don't use
``South``, migrations will not be used and your server will already be
at the latest version (but your existing database might have to be
manually edited to match future server changes).
Step 3: Starting and Stopping the Server
----------------------------------------
To start the server, make sure you're in the ``evennia/game`` directory
and execute ``evennia.py`` like this:
``python evennia.py -i start``
This starts the server and portal. The ``-i`` flag means that the server
starts in *interactive mode*, as a foreground process. You will see
debug/log messages directly in the terminal window instead of logging
them to a file.
Running the server in interactive mode is very useful for development
and debugging but is not recommended for production environments. For
the latter you'll want to run it as a *daemon* by skipping the ``-i``
flag:
``python evennia.py start``
This will start the server as a background process. Server messages will
be logged to a file you specify in your configuration file (default is a
file in ``game/logs``).
To stop Evennia, do:
``python evennia.py stop``
Step 4: Connecting to the server
--------------------------------
The Evennia server is now up and running. You should now be able to
login with any mud client or telnet client using the email address and
password you specified when syncing the database. If you are just
testing the server out on your local machine, the server name will most
likely be ``localhost`` whereas the port used by default is ``4000``.
If the defaults are not changed, Evennia will also start its own
Twisted-based web server on port 8000. Point your web browser to
``http://localhost:8000/``. The *admin interface* allows you to edit the
game database online and you can connect directly to the game by use of
the ajax web client.
Welcome to Evennia! Why not try `building
something <BuildingQuickstart.html>`_ next?
Optional: Database migrations with South
========================================
Evennia supports database migrations using
`South <http://south.aeracode.org/>`_, a Django database schema
migration tool. Installing South is optional, but if it is installed,
Evennia *will* use it automatically, meaning this section comes into
play. You can install South from
`http://south.aeracode.org/. <http://south.aeracode.org/.>`_ It is also
available through the normal package distributions, easy\_install, pip,
or pypm (see above notes).
Whenever you see a commit or mailing list message instructing you to run
migrations to update your DB schema, simply do the following from within
the ``evennia/game`` directory: ``python manage.py migrate``
You should see migrations being applied, and should be left with an
updated DB schema afterwards.
Optional: A separate installation environment with virtualenv
=============================================================
Apart from installing the packages and versions as above, you can also
set up a very fast self-contained Evennia install using the
`virtualenv <http://pypi.python.org/pypi/virtualenv>`_ program.
Virtualenv sets aside a folder on your harddrive as a stand-alone Python
environment. It should work both on Linux and Windows. First, install
Python as normal, then get virtualenv and install it so you can run it
from the command line. This is an example for setting up Evennia in an
isolated new folder *mudenv*:
::
python virtualenv mudenv --no-site-packages cd mudenv
Now we should be in our new directory *mudenv*. Next we activate the
virtual environment in here.
::
# for Linux: source bin/activate # for Windows: <path_to_this_place>\bin\activate.bat
In here you can play around and install python packages of any version
without affecting your normal system installation at all. Next we get
all the requirements with *pip*, which comes with virtualenv. This is
the cool bit.
::
pip install django twisted pil
You can now refer to **Step 1** above and continue on from there to
install Evennia into *mudenv* (you need to get ``subversion`` manually
still, it's not a python program). In the future, just go into the
folder and activate it to make this separate virtual environment
available to Evennia.

View file

@ -0,0 +1,114 @@
*How to use Evennia's help system*
Help system
===========
An important part of Evennia is the online help system. This allows the
players and staff alike to learn how to use the game's commands as well
as other information pertinent to the game. The help system has many
different aspects, from the normal editing of help entries from inside
the game, to auto-generated help entries during code development using
the *auto-help* system.
Viewing the help database
-------------------------
The main command is ``help``.
::
help [searchstring]
This will show a list of help entries, ordered after categories. You
will find two sections, *Command help entries* and *Other help entries*
(initially you will only have the first one). You can use help to get
more info about an entry; you can also give partial matches to get
suggestions. If you give category names you will only be shown the
topics in that category.
Command Auto-help system
------------------------
One important use of the help system is to teach the use of in-game
commands. Evennia offers a dynamically updated help system for all your
commands, new and old, known simply as the *auto-help* system. Only
commands that you can actually use are picked up by the auto-help
system. That means an admin will see a considerably larger mass of help
topics when using the ``help`` command than a normal player.
The auto-help system uses the ``__doc__`` strings of your command
definitions and formats this to a nice-looking help entry. This makes
for a very easy way to keep the help updated - just document your
commands well - updating the help system is just a ``@reload`` away.
There is no need to manually create help database entries for commands;
as long as you keep the docstrings updated your help will be dynamically
updated for you as well.
Example (from a module with command definitions):
::
class CmdMyCmd(Command): """ mycmd - my very own command Usage: mycmd[/switches] <args> Switches: test - test the command run - do something else This is my own command that does things to you when you supply it with arguments. """ ... help_category = "Building" ...
So the text at the very top of the command class definition is the
class' ``__doc__``-string and what will be shown to users looking for
help. Try to use a consistent formatting between your help strings (for
example, all default commands have ``__doc__``-strings formatted in the
way seen above). You should also supply the ``help_category`` class
property if you can; this helps to group help entries together for
easier finding (if you don't supply a help\_category, "General" will be
assumed).
Other help entries (entries stored in database)
-----------------------------------------------
The *Other help* section you see when using the ``help`` command shows
all help entries that has been manually added to the database by staff.
Instead of being generated from the code by Evennia, these are stored in
the database using a model called *!HelpEntry*. HelpEntry topics are
intended for world-game-info, tutorials and other types of useful
information not directly tied to a command and covered by auto-help.
A help entry consists of four parts:
- The *topic*. This is the name of the help entry. This is what players
search for when they are looking for help. The topic can contain
spaces.
- The *help category*. Examples are *Administration*, *Building*,
*Comms* or *General*. This is an overall grouping of similar help
topics, used by the engine to give a better overview.
- The *text* - the help text itself, of any length. This can also
include *markup*, see below.
- locks - a `lock definition <Locks.html>`_. Help commands check for
access\_types ``examine`` and ``edit``.
You can create new help entries in code by using
``src.utils.create.create_help_entry()``:
::
from src.utils import create entry = create.create_help_entry("emote", "Emoting is important because ...", category="Roleplaying", locks="view:all()"):
From inside the game those with the right permissions can use the
``@sethelp`` command to add and modify help entries.
::
> @sethelp/add emote = The emote command is ...
Using ``@sethelp`` you can add, delete and append text to existing
entries. By default new entries will go in the *General* help category.
You can change this using a different form of the ``@sethelp`` command:
::
> @sethelp/add emote, Roleplaying = Emoting is important because ...
If the category *Roleplaying* did not exist it is created and will
appear in the help index. You can, finally, define a lock for the help
entry by following the category with a `lock definition <Locks.html>`_:
::
> @sethelp/add emote, Roleplaying, view:all() = The emote command ...

View file

@ -0,0 +1,61 @@
Getting and giving Evennia-help
How to *get* Help
=================
If you cannot find what you are looking for in the `online
documentation <Index.html>`_, here's what to do:
- If you have trouble with a missing feature or a problem you think is
a bug, go to the `issue
tracker <http://code.google.com/p/evennia/issues/list>`_. If you
can't find the issue already reported, file a new one by filling in
the handy form.
- If you need help, want to start a discussion or get input on
something, make a post in our `forum <http://evennia.com>`_. This is
technically a 'mailing list', but you don't need to use e-mail; you
can post and read all messages just as easily from your browser via
the online interface.
- If you want more direct discussions with developers and other users,
consider dropping into our IRC chat channel
"http://webchat.freenode.net/?channels
evennia">#evennia on the *Freenode* network. Please note however that
you have to be patient if you don't get any response immediately; we
are all in very different time zones and many have busy personal
lives. So you might have to lurk about for a while - you'll get
noticed eventually!
How to *give* Help
==================
Evennia is a completely non-funded project. It relies on the time
donated by its users and developers in order to progress.
The first and easiest way you as a user can help us out is by taking
part in `community
discussions <http://groups.google.com/group/evennia/>`_ and by giving
feedback on what is good or bad. Report bugs you find and features you
lack to our `issue
tracker <http://code.google.com/p/evennia/issues/list>`_. Just the
simple act of letting developers know you are out there using their
program is worth a lot.
If you'd like to help develop Evennia more hands-on, here are some ways
to get going:
- Look through our `online documentation wiki <Index.html>`_ and see if
you can help improve or expand the documentation (even small things
like fixing typos!).
- Send a message to our
`forum <http://groups.google.com/group/evennia/>`_ and/or our
"http://webchat.freenode.net/?channels
evennia">IRC chat asking about what needs doing, along with what your
interests and skills are.
- Take a look at our `issue
tracker <http://code.google.com/p/evennia/issues/list>`_ and see if
there's something you feel like taking on.
- Check out the `Contributing <Contributing.html>`_ page on how to
contribute with code in practice.
In either case, you may find documentation useful to developers in the
`Developer Central <DeveloperCentral.html>`_.

View file

@ -0,0 +1,123 @@
Introduction to and configuration for IMC2.
IMC2
====
`IMC2 <http://en.wikipedia.org/wiki/InterMUD>`_, *!InterMud
Communications, protocol version 2*, is a protocol that allows
individual mud games (Evennia-powered or not) to connect to a remote
server for the purpose of IRC-like communication with other games. By
connecting your MUD to IMC, you and your admins/players will be able to
communicate with players on other muds connected to the network! Note
that you can use IMC2 also if your Evennia install is only running
locally on your computer -all you need is an internet connection.
Evennia's IMC implementation is special in that it integrates Evennia's
normal channel system with IMC. The basic principle is that you
"connect" an IMC channel to an existing Evennia channel. Users on the
IMC network will then see what is said on the channel and vice versa.
Joining the IMC network
-----------------------
To configure IMC, you first need to activate it by setting
``IMC2_ENABLED=True`` in your settings file. This will make several new
IMC-related commands available to a privileged user. Since the IMC
network will need to know your mud's name, make sure you have also set
``settings.SERVERNAME`` to the mud name you want.
Next you need to register your mud at a IMC2 network. We suggest the
`MudBytes IMC2 network <http://www.mudbytes.net/intermud>`_. You can
join for free
`here <http://www.mudbytes.net/imc2-intermud-join-network>`_. On that
page, follow the following steps:
#. From the drop-down list, select "Other unsupported IMC2 version",
then click Submit
#. You will get to a form. In "Short Mud name" you need to enter the
name of your mud as defined by ``settings.SERVERNAME``.
#. Give client- and server passwords to anything you want, but remember
them.
#. Give an admin e-mail. This shouldn't be too critical.
#. Choose a server. It shouldn't really matter which you choose, as long
as you remember what you picked (Evennia's development channel
``ievennia`` is found on ``Server01``). Click "Join".
You have now created an account on the Mudbytes IMC network and are
ready to go on.
Now fill in the rest of the IMC2 information in your settings file -
give the network name and port, as well as the client- and server
passwords you used when registering on mudbytes.
For testing, you can connect your mud client to the IMC mini-mud called
*Talon* on ``talon.mudbytes.net:2000``. This works pretty much like an
IRC client.
Creating an Evennia channel
---------------------------
Evennia maps in-game channels to remote IMC channels. This means that
you get all of the features of the local comm system for remote IMC
channels as well (channel history, permissions-based channel entry,
etc.)
Let's create a dedicated Evennia channel to host imc communications (you
could also use an existing channel like ``ooc`` if you wanted):
::
@ccreate imc2 = This is connected to an IMC2 channel!
You should join the channel automatically.
Setting up a Channel ``<->`` IMC2 binding
-----------------------------------------
=
Evennia developers have an open-access IMC channel called ``ievennia``
on ``Server01`` of the Mudbytes network. For Evennia development we
recommend you connect to this for sharing evennia anecdotes!
Activating IMC2 have made new commands available, the one you need is
``@imc2chan``. You use this to create a permanent link between an IMC
channel and an existing Evennia channel of your choice. You can use the
``imcchanlist`` to see which IMC channels are available on the network.
Let's connect our new ``imc2`` channel to the ``ievennia`` channel on
Server01.
::
@imc2chan imc2 = ievennia
To test, use the IMC mud *Talon*, make sure you "listen" to
``ievennia``, then write something to the channel. You should see the
text appear in Evennia's ``imc2`` channel and vice versa.
Administration and notes
------------------------
You can view all your IMC-to-Evennia mappings using ``@imc2chan/list``.
To permanently remove a connection, use ``@imc2chan`` with the
``/delete`` switch like this:
::
@imc2chan/delete imc2 = ievennia
A single Evennia channel may *listen* to any number of remote IMC
channels. Just use ``@imc2chan`` to add more connections. Your channel
can however only ever *send* to one IMC2 channel and that is the first
one you link to it (``ievennia`` in this example).
The ``@imclist`` command will list all other MUDs connected to the
network (not including yourself).
Talk between IRC and IMC
------------------------
This is easy - just bind IMC to the same evennia channel that IRC binds
to. The process of binding IRC channels is described in more detail
`here <IRC.html>`_.

View file

@ -0,0 +1,115 @@
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
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
also if you are only running your Evennia MUD locally on your computer
(your game don't need to be open to the public)! All you need is an
internet connection. For IRC operation you also need
`twisted.words <http://twistedmatrix.com/trac/wiki/TwistedWords>`_. This
is available simply as a package *python-twisted-words* in many Linux
distros, or directly downloadable from the link.
<wiki:toc max\_depth
"3" />
======
Configuring IRC =
To configure IRC, you'll need to activate it in your settings file. You
do this by copying the ``IRC_ENABLED`` flag from
``evennia/src/config_defaults.py`` into your
``evennia/game/settings.py`` and setting it to ``True``.
Start Evennia and log in as a privileged user. You should now have a new
command availabele: ``@irc2chan``. This command is called like this:
::
@irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>
If you already know how IRC works, this should be pretty self-evident to
use. Read the help entry for more features.
Setting up IRC, step by step
----------------------------
You can connect IRC to any Evennia channel, but for testing, let's set
up a new channel ``irc``.
::
@ccreate irc = This is connected to an irc channel!
You will automatically join the new channel.
Next we will create a connection to an external IRC network and channel.
There are many, many IRC nets.
`Here <http://www.irchelp.org/irchelp/networks/popular.html>`_ is a list
of some of the biggest ones, the one you choose is not really very
important unless you want to connect to a particular channel (also make
sure that the network allows for "bots" to connect).
For testing, we choose the *Freenode* network, ``irc.freenode.net``. We
will connect to a test channel, let's call it *#myevennia-test* (an IRC
channel always begins with ``#``). It's best if you pick an obscure
channel name that didn't exist previously - if it didn't exist it will
be created for you. *Don't* connect to ``#evennia``, that is Evennia's
official chat channel!
A *port* needed depends on the network. For Freenode this is ``6667``.
What will happen is that your Evennia server will connect to this IRC
channel as a normal user. This "user" (or "bot") needs a name, which you
must also supply. Let's call it "mud-bot".
To test that the bot connects correctly you also want to log onto this
channel with a separate, third-party IRC client. There are hundreds of
such clients available. If you use Firefox, the *Chatzilla* plugin is
good and easy. There are also web-based clients like *Mibbit* that you
can try. Once you have connected to a network, the command to join is
usually ``/join channelname`` (don't forget the #).
Next we connect Evennia with the IRC channel.
::
@irc2chan irc = irc.freenode.net 6667 #myevennia-test mud-bot
Evennia will now create a new IRC bot ``mud-bot`` and connect it to the
IRC network and the channel #myevennia. If you are connected to the IRC
channel you will soon see the user *mud-bot* connect.
Write something in the Evennia channel *irc*.
::
irc Hello, World! [irc] Anna: Hello, World!
If you are viewing your IRC channel with a separate IRC client you
should see your text appearing there, spoken by the bot:
::
mud-bot> [irc] Anna: Hello, World!
Write ``Hello!`` in your IRC client window and it will appear in your
normal channel, marked with the name of the IRC channel you used
(#evennia here).
::
[irc] Anna@#myevennia-test: Hello!
Your Evennia gamers can now chat with users on external IRC channels!
Talking between IRC and IMC
---------------------------
You can easily connect IRC and IMC by simply connecting them to the same
Evennia channel. IMC connections are described `here <IMC2.html>`_.

View file

@ -0,0 +1,28 @@
Evennia Documentation
=====================
This is Evennia's manual. You should hopefully find all you need to know
about coding with, extending and using the codebase among these pages.
The documentation is divided into several main categories, selectable
below or from the left sidebar. If you are new, it might be an idea to
browse the sections in the order they are listed. For more help, see the
`how to get and give help <HowToGetAndGiveHelp.html>`_ page.
Sections
--------
- A `Lengthier introduction <EvenniaIntroduction.html>`_ to what
Evennia is.
- The `Getting Started <GettingStarted.html>`_ page helps with
downloading, installing and setting up Evennia for the first time.
- The `Administrative Documentation <AdminDocs.html>`_ covers the
practicalities of running and maintaining an Evennia game once it is
in place.
- The `Builder Docs <BuilderDocs.html>`_ section contains instructions
for starting to build a game world using Evennia.
- The `Developer Central <DeveloperCentral.html>`_ covers
implementation details and guides of interest for game-world coders
as well as for current and prospective Evennia developers.

View file

@ -0,0 +1,68 @@
Internationalization
====================
*Internationalization* (often abbreviated *i18n* since there are 18
characters between the first "i" and the last "n" in that word) allows
Evennia's core server to return texts in other languages than English -
without anyone having to go in and add it manually. Take a look at the
``locale`` directory of the Evennia installation. there you will find
which languages are currently supported.
Note, what is translated in this way are hard-coded strings from the
server, things like "Connection closed" or "Server restarted".
Basically, the things users are not supposed to change on their own.
This means that the default command set is *not* translated. The reason
for this is that commands are *intended* to be modified by users. .
Changing server language
------------------------
Change language by copy&pasting the following from the default file to
your ``game/settings.py`` file:
::
USE_I18N = True LANGUAGE_CODE = 'en'
Here ``'en'`` should be changed to the abbreviation for one of the
supported languages found in ``locale/``. Restart the server to activate
i18n.
Translating Evennia
-------------------
If you cannot find your language in ``locale/`` it's because noone has
translated it yet. Alternatively you might find the language but find
the translation bad ... You are welcome to help improve the situation!
To start a new translation, place yourself in Evennia's root directory
and run
::
django-admin makemessages -l <language-code>
where ``<language-code`` is the two-letter locale code for the language
you want, like 'sv' for Swedish or 'es' for Spanish.
Next head to ``locale/<language-code>/LC_MESSAGES`` and edit the
``*.po`` file you find there. There is no need to edit this file using a
normal text editor -- best is to use a po-file editor from the web
(search the web for "po editor" for many free alternatives).
The concept of translating is simple, it's just a matter of taking the
english strings you find in the ``*.po`` file and add your language's
translation best you can. When you are done, send the ``*.po`` file to
the Evennia developer list so we can integrate your translation it into
Evennia!
Finally, you need to compile your translation into a more efficient
form.
::
django-admin.py compilemessages
This will go through all languages and create/update compiled files
(``*.mo``) for them. This needs to be done whenever a ``*.po`` file is
updated.

View file

@ -0,0 +1,50 @@
Evennia Licence
===============
Evennia is licensed under the very friendly *Modified Clarified Artistic
License*. You can find the license as ``LICENCE`` in the Evennia root
directory. You can also read the full license file
`here <http://code.google.com/p/evennia/source/browse/trunk/LICENSE>`_.
Licence FAQ
-----------
You should read the full license file to know what it says exactly, but
here are some answers to common questions.
Q: I have created a game using Evennia, what does the license allow me
to do with it?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**A:** It's your own world to do with what you please! In summary, a
MU``*`` world you create using Evennia (i.e. the files you create in
``game``) falls under **§6** of the license (it's a sort of "library").
So your game world and all its contents belongs to you (as it should
be). Keep it to yourself or re-distribute it under any license of your
choice - or sell it and become filthy rich for all we care.
Q: I have modified Evennia itself, what does the license say about that?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**A:** The Evennia package itself (i.e. the stuff you download from us)
is referred to as "The Package", "Standard version" in the license.
- If you just fixed a typo or bug, that falls under **§2** - that is,
you don't *have* to do anything to appease the license. Regardless,
we'd of course appreciate it if you submitted bugs/fixes to us so
Evennia becomes more complete!.
- If you made other modifications or added new features to the server,
that's also ok, but falls under **§3** - you must make a clear note
of the changes as well as put the changes into the public domain or
make separate arrangements with us (since it's then no longer a
"Standard version"). 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 Evennia along with my custom game implementation?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**A:** Sure. This is covered in **§4** - just package the "Standard
version" (that is, the one you download from us) with your package. Make
sure to include the original license and disclaimers and note where
users may get it if they want to download it of their own.

View file

@ -0,0 +1,60 @@
External links and resources
============================
This is a list of resources that may be useful for Evennia users and
developers.
Evennia links
-------------
- `Evennia's main portal page <http://www.evennia.com>`_ (RSS feeds to
updates)
- `Evennia forums <http://www.evennia.com/discussions>`_
- `Evennia Commit
Log <http://groups.google.com/group/evennia-commits>`_ (SVN commit
notification)
- `Sequential source update
list <http://code.google.com/p/evennia/source/list>`_ (easily see
what was changed in each update)
- `Evennia mailing list <http://groups.google.com/group/evennia>`_
(better web interface can be found from the portal)
Third-party Evennia links
-------------------------
- `Hosting Evennia on
Webfaction <http://lotek.heavy.ch/evennia#Hosting>`_
- `Evennia on Ohloh <http://www.ohloh.net/projects/6906>`_
- `Evennia on OpenHatch <http://openhatch.org/+projects/Evennia>`_
- `Evennia on
PyPi <http://pypi.python.org/pypi/Evennia%20MUD%20Server/Alpha>`_
Frameworks
----------
`Django's homepage <http://www.djangoproject.com/>`_
- `Documentation <http://docs.djangoproject.com/en>`_
- `Code <http://code.djangoproject.com/>`_
`Twisted homepage <http://twistedmatrix.com/>`_
- `Documentation <http://twistedmatrix.com/documents/current/core/howto/index.html>`_
- `Code <http://twistedmatrix.com/trac/browser>`_
Tools
-----
- `Subversion Manual <http://svnbook.red-bean.com/>`_
- `Doxygen <http://www.stack.nl/~dimitri/doxygen/>`_ (build auto-docs)
Python Info
-----------
`Python Website <http://www.python.org/>`_
- `Documentation <http://www.python.org/doc/>`_
- `Tutorial <http://docs.python.org/tut/tut.html>`_
- `Library Reference <http://docs.python.org/lib/lib.html>`_
- `Language Reference <http://docs.python.org/ref/ref.html>`_

View file

@ -0,0 +1,411 @@
<wiki:toc max\_depth
"3" />
======
Locks =
For most games it is a good idea to restrict what people can do. In
Evennia such restrictions are applied and checked by something called
*locks*. All Evennia entities (`commands <Commands.html>`_,
`objects <Objects.html>`_, `scripts <Scripts.html>`_,
`players <Players.html>`_, `help system <HelpSystem.html>`_,
`messages <Communications#Msg.html>`_ and
`channels <Communications#Channels.html>`_) are accessed through locks.
A lock can be thought of as an "access rule" restricting a particular
use of an Evennia entity. Whenever another entity wants that kind of
access the lock will analyze that entity in different ways to determine
if access should be granted or not. Evennia implements a "lockdown"
philosophy - all entities are inaccessible unless you explicitly define
a lock that allows some or full access.
Let's take an example: An object has a lock on itself that restricts how
people may "delete" that object. Apart from knowing that it restricts
deletion, the lock also knows that only players with the specific ID of,
say, '34' are allowed to delete it. So whenever a player tries to run
@delete on the object, the @delete command makes sure to check if this
player is really allowed to do so. It calls the lock, which in turn
checks if the player's id is 34. Only then will it allow @delete to go
on with its job.
Setting and checking a lock
---------------------------
The in-game command for setting locks on objects is ``@lock``:
::
> @lock obj = <lockstring>
The ``<lockstring>`` is a string on a certain form that defines the
behaviour of the lock. We will go into more detail on how
``<lockstring>`` should look in the next section.
Code-wise, Evennia handles locks through what is usually called
``locks`` on all relevant entities. This is a handler that allows you to
add, delete and check locks.
::
myobj.locks.add(<lockstring>)
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:
::
if not obj.access(accessing_obj, 'delete'): accessing_obj.msg("Sorry, you may not delete that.") return
Defining locks
--------------
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()``. Such a *lockstring* formally looks
like this:
::
access_type:[NOT] func1([arg1,..])[[AND|OR][ NOT] func2([arg1,...])[...]]
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.
This form of writing may look complicated, so let's immediately give
some much nicer examples:
::
delete:id(34) # only allow obj #34 to delete edit:all() # let everyone edit get: not attr(very_weak) or perm(Wizard) # only those who are not "very_weak" or are Wizards may pick this up
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
combine several function checks. If the total result is True, the lock
is passed.
You can create several lock types one after the other by separating them
with a semicolon (``;``) in the lockstring. The string below is
identical to the first two rows of the previous example:
::
delete:id(34);edit:all()
Valid access\_types
~~~~~~~~~~~~~~~~~~~
An ``access_type``, the first part of a lockstring, defines what kind of
capability a lock controls, such as "delete" or "edit". You may in
principle name your ``access_type`` anything as long as it is unique for
the particular object. Access\_types are not case-sensitive.
If you want to make sure the lock is used however, you should pick
``access_type`` names that you (or the default command set) actually
tries, as in the example of ``@delete`` above that uses the 'delete'
``access_type``.
Below are the access\_types checked by the default commandset.
`Commands <Commands.html>`_: ``cmd`` - this defines who may call this
command at all.
`Objects <Objects.html>`_:
- ``control`` - who is the "owner" of the object. Can set locks, delete
it etc. Defaults to the creator of the object.
- ``call`` - who may call object-commands on this object.
- ``examine`` - who may examine this object's properties.
- ``delete`` - who may delete the object.
- ``edit`` - who may edit properties and attributes of the object.
- ``get``- who may pick up the object and carry it around.
- ``puppet`` - who may "become" this object and control it as their
"character".
`Characters <Objects#Characters.html>`_: ``<Same as Objects>``
`Exits <Objects#Exits.html>`_: ``<Same as Objects>`` + ``traverse`` -
who may pass the exit.
`Players <Players.html>`_:
- ``examine`` - who may examine the player's properties.
- ``delete`` - who may delete the player.
- ``edit`` - who may edit the player's attributes and properties.
- ``msg`` - who may send messages to the player.
- ``boot`` - who may boot the player.
`Attributes <Attributes.html>`_: ``<None>``
`Channels <Communications#Channels.html>`_:
- ``control`` - who is administrating the channel. This means the
ability to delete the channel, boot listeners etc.
- ``send`` - who may send to the channel.
- ``listen`` - who may subscribe and listen to the channel.
`HelpEntry <HelpSystem.html>`_:
- ``examine`` - who may view this help entry (usually everyone)
- ``edit`` - who may edit this help entry.
So to take an example, whenever an exit is to be traversed, a lock of
the type *traverse* will be checked. Defining a suitable lock type for
an exit object would thus involve a lockstring
``traverse: <lock functions>``.
Lock functions
~~~~~~~~~~~~~~
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.
A lock function must always accept at least two arguments - the
*accessing object* (this is the object wanting to get access) and the
*accessed object* (this is the object with the lock). Those two are fed
automatically as the first two arguments the function when the lock is
checked. Any arguments explicitly given in the lock definition will
appear as extra arguments.
::
# A simple example lock function. Called with e.g. id(34)def id(accessing_obj, accessed_obj, *args, **kwargs): if args: wanted_id = args[0] return accessing_obj.id == wanted_id return False
(Using the ``*`` and ``**`` syntax causes Python to magically put all
extra arguments into a list ``args``and all keyword arguments into a
dictionary ``kwargs`` respectively. If you are unfamiliar with how
``*args`` and ``**kwargs`` work, see the Python manuals).
Some useful default lockfuncs (see lockfuncs.py for a full list):
- ``true()/all()`` - give access to everyone
- ``false()/none()/superuser()`` - give access to noone. Superusers
bypass the check entirely.
- ``perm(perm)`` - this tries to match a given ``permission`` property.
See `below <Locks#Permissions.html>`_.
- ``perm_above(perm)`` - requres a "higher" permission level than the
one given.
- ``id(num)/dbref(num)`` - checks so the accessobject has a certain
dbref/id.
- ``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.
- ``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 >
, <, <
======
and !=.
- ``holds(objid)`` - checks so the accessing objects contains an object
of given name or dbref.
- ``pperm(perm)``, ``pid(num)/pdbref(num)`` - same as ``perm``,
``id/dbref`` but always looks for permissions and dbrefs of
*Players*, not on Characters.
Default locks
-------------
Evennia sets up a few basic locks on all new objects and players (if we
didn't, noone would have any access to anything from the start). This is
all defined in the root `Typeclasses <Typeclass.html>`_ of the
respective entity, in the hook method ``basetype_setup()`` (which you
usually don't want to edit unless you want to change how basic stuff
like rooms and exits store their internal variables). This is called
once, before ``at_object_creation``, so just put them in the latter
method on your child object to change the default. Also creation
commands like ``@create`` changes the locks of objects you create - for
example it sets the ``control`` lock\_type allow youm, its creator to
control and delete the object.
Permissions
===========
A *permission* is simply a list of text strings stored on the property
``permissions`` on ``Objects`` and ``Players``. Permissions can be used
as a convenient way to structure access levels and hierarchies. It is
set by the ``@perm`` command.
::
@perm Tommy = Builders
All new players/character are given a default set of permissions defined
by ``settings.PERMISSION_PLAYER_DEFAULT``.
Selected permission strings can be organized in a *permission hierarchy*
by editing the tuple ``settings.PERMISSION_HIERARCHY``. Evennia's
default permission hierarchy is as follows:
::
Immortals Wizards Builders PlayerHelpers Players # this is what all new Players start with by default
The main use of this is that if you use the lock function ``perm()``
mentioned above, a lock check for a particular permission in the
hierarchy will *also* grant access to those with *higher* hierarchy
acces. So if you have the permission "Wizards" you will also pass a lock
defined as ``perm(Builders)`` or any of those levels below "Wizards".
The lock function ``perm_above(Players)`` require you to have a
permission level higher than ``Players`` and so on. If the permission
looked for is not in the hierarchy, an exact match is required.
::
obj1.permissions = ["Builders", "cool_guy"] obj2.locks.add("enter:perm_above(Players) and perm(cool_guy)")obj2.access(obj1, "enter") # this returns True!
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
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
definitions. So when trying out game systems you should use a secondary
character rather than #1 so your locks get tested correctly.
More Lock definition examples
=============================
::
examine: attr(eyesight, excellent) or perm(Builders)
You are only allowed to do *examine* on this object if you have
'excellent' eyesight or is a Builder.
::
# lock for the tell command
cmd: perm(Builders) and not perm(no_tell)
Locks can be used to implement highly specific bans. Set this on e.g.
the ``tell`` command, then give a player the "permission" ``no_tell`` to
disable their use of this particular command henceforth.
::
open: holds('the green key') or perm(Builder)
This could be called by the ``open`` command on a "door" object. The
check is passed if you are a Builder or has the right key in your
inventory.
::
# this limits what commands are visible to the user
cmd: perm(Builders)
Evennia's command handler looks for a lock of type ``cmd`` to determine
if a user is allowed to even call upon a particular command or not. When
you define a command, this is the kind of lock you must set. See the
default command set for lots of examples.
::
dbref = caller.id
lockstring = "control:id(%s);examine:perm(Builders);delete:id(%s) or perm(Wizards);get:all()" % (dbref, dbref)
new_obj.locks.add(lockstring)
This is how the ``@create`` command sets up new objects. In sequence,
this permission string sets the owner of this object be the creator (the
one running ``@create``). Builders may examine the object whereas only
Wizards and the creator may delete it. Everyone can pick it up.
A complete example of setting locks on an object
================================================
Assume we have two objects - one is ourselves (not superuser) and the
other is an `Object <Objects.html>`_ called ``box``.
::
> @create/drop box > @desc box = "This is a very big and heavy box."
We want to limit which objects can pick up this heavy box. Let's say
that to do that we require the would-be lifter to to have an attribute
*strength* on themselves, with a value greater than 50. We assign it to
ourselves to begin with.
::
> @set self/strength = 45
Ok, so for testing we made ourselves strong, but not strong enough. Now
we need to look at what happens when someone tries to pick up the the
box - they use the ``get`` command (in the default set). This is defined
in ``game/gamesrc/commands/default/general.py``. In its code we find
this snippet:
::
if not obj.access(caller, 'get'): if obj.db.get_err_msg: caller.msg(obj.db.get_err_msg) else: caller.msg("You can't get that.") return
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
error message. Sounds good! Let's start by setting that on the box:
::
> @set box/get_err_msg = You are not strong enough to lift this box.
Next we need to craft a Lock of type *get* on our box. We want it to
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``.
So the lock string will look like this: "``get:attr_gt(strength, 50)``".
We put this on the box now:
::
@lock box = get:attr_gt(strength, 50)
Try to ``get`` the object and you should get the message that we are not
strong enough. Increase your strength above 50 however and you'll pick
it up no problem. Done! A very heavy box!
If you wanted to set this up in python code, it would look something
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...
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
``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
lot of sense for a web application, not so much for a MUD, especially
when we try to hide away as much of the underlying architecture as
possible.
The django permissions are not completely gone however. We use it for
logging in users (the ``User`` object tied to `Players <Players.html>`_
is a part of Djangos's auth system). It is also used exclusively for
managing Evennia's web-based admin site, which is a graphical front-end
for the database of Evennia. You edit and assign such permissions
directly from the web interface. It's stand-alone from the permissions
described above.

View file

@ -0,0 +1,94 @@
Nicks
=====
*Nicks*, short for *Nicknames* is a system allowing an object (usually a
`Player Character <Players.html>`_) to assign custom replacement names
for other game entities.
Nicks are not to be confused with *Aliases*. Setting an Alias on a game
entity actually changes an inherent attribute on that entity, and
everyone in the game will be able to use that alias to address the
entity thereafter. A *Nick* on the other hand, is an alternate name *you
alone* can use to refer to that entity. The nicknamed entitity is not
changed in any way. The principle is very simple - Evennia simply scans
your input looking for a defined nick and replaces it with the full,
"real" name before passing it on. In the default system nicks are
controlled with the simple ``nick`` command, but the system can be
expanded for other uses too.
Default Evennia use Nicks in three flavours that determine when Evennia
actually tries to do the substitution.
- inputline - replacement is attempted whenever you write anything on
the command line. This is the default.
- objects - replacement is only attempted when referring an object
- players - replacement is only attempted when referring a player
Here's how to use it in the default command set (using the ``nick``
command):
::
nick ls = look
This is a good one for unix/linux users who are accustomed to using the
``ls`` command in their daily life. It is equivalent to
``nick/inputline ls = look``.
::
nick/object mycar2 = The red sports car
With this example, substitutions will only be done specifically for
commands expecting an object reference, such as
::
look mycar2
becomes equivalent to "``look The red sports car``".
::
nick/players tom = TommyBoy
This is useful for commands searching for players explicitly:
::
@find *tom
One can use nicks to speed up input. Below we add ourselves a quicker
way to build red buttons. In the future just writing *rb* will be enough
to execute that whole long string.
::
nick rb = @create button:examples.red_button.RedButton
Nicks could also be used as the start for building a "recog" system
suitable for an RP mud.
::
nick/player Arnold = The mysterious hooded man
Coding with nicks
-----------------
Nicks are are stored as the ``Nick`` database model and are referred
from the normal Evennia `object <Objects.html>`_ through the ``nicks``
property. ``nicks`` is a special handler that offers effective error
checking, searches and conversion.
::
# A command/channel nick: object.nicks.add("greetjack", "tell Jack = Hello pal!")# An object nick: object.nicks.add("rose", "The red flower", nick_type="object")# An player nick: object.nicks("tom", "Tommy Hill", nick_type="player")# My own custom nick type (handled by my own game code somehow): object.nicks.add("hood", "The hooded man", nick_type="my_identsystem")# get back the translated nick: full_name = object.nicks.get("rose", nick_type="object")# delete a previous set nick object.nicks.del("rose", nick_type="object")
In a command definition you can reach the nick handler through
``self.caller.nicks``. See the ``nick`` command in
``game/gamesrc/commands/default/general.py`` for more examples.
As a last note, The Evennia `channel <Communications.html>`_ alias
systems are using nicks with the ``nick_type="channel"`` in order to
allow users to create their own custom aliases to channels.

View file

@ -0,0 +1,192 @@
Objects
=======
All in-game objects in Evennia, be it characters, chairs, monsters,
rooms or hand grenades are represented by an Evennia *Object*. Objects
form the core of Evennia and is probably what you'll spend most time
working with. Objects are `TypeClassed <Typeclasses.html>`_ entities.
How to create your own object types
-----------------------------------
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.
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 """ 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
``@create`` command to make a new rose:
::
> @create/drop MyRose:flowers.Rose
To create a new object in code, use the method
``src.utils.create.create_object()``:
::
from src.utils import create new_rose = create.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. Check out the module for more info on which
arguments you can give the function.)
This particular class doesn't really do much, all it does it make sure
the attribute ``desc``(which is what the ``look`` command looks for) is
pre-set. You could just as well do the same with the ``@describe``
command. The ``Object`` typeclass offers many more hooks that is
available to use though. Look at the ``Object`` class in
``game/gamesrc/objects/baseobjects.py`` to orient yourself. If you
define a new Object class (inheriting from the base one), and wants that
to be the default instead, set ``BASE_OBJECT_TYPECLASS`` in
``settings.py`` to point to your new class.
Properties and functions on Objects
-----------------------------------
Beyond those properties assigned to all
`typeclassed <Typeclasses.html>`_ objects, the Object also has the
following custom properties:
- ``aliases`` - a list of alternative names for the object. Aliases are
stored database objects, but the ``aliases`` property receives and
returns lists - so assign to it like normal, e.g.
``obj.aliases=['flower', 'red blossom']``
- ``location`` - a reference to the object currently storing this
object.
- ``home`` is a backup location. The main motivation is to have a safe
place to move the object to if its ``location`` is destroyed. All
objects should usually have a home location for this reason.
- ``destination`` - this holds a reference to another object this
object links to in some way. Its main use is for
`Exits <Objects#Exits.html>`_, it's otherwise usually unset.
- ``nicks`` - as opposed to aliases, a `Nick <Nicks.html>`_ holds a
convenient nickname replacement for a real name, word or sequence,
only valid for this object. Nicks are stored in the database and are
a bit more complex than aliases since they have a *type* that defines
where Evennia tries to do the substituion. Use nicks.get(alias, type)
to get a nick, or nicks.add(alias, realname) to add a new one.
- ``player`` - this holds a reference to a connected
`Player <Players.html>`_ controlling this object (if any). Note that
this is set also if the controlling player is *not* currently online
- to test if a server is online, use ``has_player`` instead.
- ``sessions`` - if ``player`` field is set *and the player is online*,
this is a list of all active sessions (server connections) to contact
them through.
- ``permissions`` - a list of `permission strings <Locks.html>`_ for
defining access rights.
- ``has_player`` - a shorthand for checking if an online player is
currently connected to this object.
- ``contents`` - this is a list referencing all objects 'inside' this
object, that is which has this object set as their ``location``.
- ``exits`` - this returns all objects inside this object that are
*Exits*, that is, has the ``destination`` property set.
The last two properties are special:
- ``cmdset`` - this is a handler that stores all `command
sets <Commands#Command_Sets.html>`_ defined on the object (if any).
- ``scripts`` - this is a handler that manages
`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.
- ``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 way to search for a specific
object, at a given location or globally.
- ``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
*and* from this object.
- ``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()``.
Objects also define a host of *hook methods* beyond
``at_object_creation``. 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.
Subclasses of *Object*
----------------------
There are three special subclasses of *Object* in default Evennia -
*Characters*, *Rooms* and *Exits*. The reason they are separated is
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. In practice they are all
pretty similar to the base Object. You will import them all from
``game.gamesrc.objects.baseobjects``.
Characters
~~~~~~~~~~
Characters are objects controlled by `Players <Players.html>`_. When a
new Player logs in to Evennia for the first time, a new ``Character``
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 run 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
~~~~~
*Rooms* are the root containers of all other objects. The only thing
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``.
Exits
~~~~~
*Exits* are objects connecting other objects (usually *Rooms*) together.
An object named *North* or *in* might be an exit, as well as *door*,
*portal* or *jump out the window*. An exit has two things that separate
them from other objects. Firstly, their *destination* property is set
and points to a valid object. This fact makes it easy and fast to locate
exits in the database. Secondly, exits define a special `Transit
Command <Commands.html>`_ on themselves when they are created. This
command is named the same as the exit object and will, when called,
handle the practicalities of moving the character to the Exits's
*destination* - this allows you to just enter the name of the exit on
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
default class used by e.g. ``@dig`` and ``@open`` by editing
``BASE_EXIT_TYPECLASS`` in your settings.
Further notes
-------------
For a more advanced example of a customized object class, see
``game/gamesrc/objects/examples/red_button.py``.

View file

@ -0,0 +1,121 @@
<wiki:toc max\_depth
"3" />
======
Players=
All users (in the sense of actual people) connecting to Evennia are
doing so through an object called *Player*. The Player object has no
in-game representation; rather it is the out-of-character representation
of the user. The Player object is what is chatting on
`Channels <Communications.html>`_. It is also a good place to store
`Permissions <Locks.html>`_ to be consistent between different in-game
characters, configuration options, account info and other things related
to the user. Players are `TypeClassed <Typeclasses.html>`_ entities and
can store a `CmdSet <Commands.html>`_ of their own for OOC-type
commands.
If you are logged in into default Evennia, you can use the ``@ooc``
command to leave your current `Character <Objects.html>`_ and go into
OOC mode. You are quite limited in this mode, basically it works like a
simple chat program. It acts as a staging area for switching between
Characters (if your game supports that) or as a safety mode if your
Character gets deleted. . Use ``@ic`` to switch back "into" your
character. Also note that the Player object can have a different set of
`Permissions <Locks#Permissions.html>`_ from the Character they control
(in the first character you create permissions for Player and Character
are the same, however).
How to create your own Player types
-----------------------------------
You will usually not want more than one Player typeclass for all new
players (but you could in principle create a system that changes a
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.
Here's how to define a new Player typeclass in code:
::
from src.players.player import Playerclass 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 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.
Properties on Players
---------------------
Beyond those properties assigned to all typeclassed objects (see
`Typeclasses <Typeclasses.html>`_), the Player also has the following
custom properties:
- ``user`` - a unique link to a ``User`` Django object, representing
the logged-in user.
- ``character`` - a reference to an associated *Character*-type
`Object <Objects.html>`_.
- ``obj`` - an alias for ``character``.
- ``name`` - an alias for ``user.username``
- ``sessions`` - a list of all connected Sessions (physical
connections) this object listens to.
- ``is_superuser`` (bool: True/False) - if this player is a superuser.
Special handlers:
- ``cmdset`` - This holds all the current `Commands <Commands.html>`_
of this Player. By default these are the commands found in the cmdset
defined by ``settings.CMDSET_OOC``.
- ``nicks`` - This stores and handles `Nicks <Nicks.html>`_, in the
same way as nicks it works on Objects. For Players, nicks are
primarily used to store custom aliases for
`Channels <Communications#Channels.html>`_.
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.
What happens when a person connects to Evennia and logs in is that they
log in as a ``User`` object. This is a Django object that knows all
about keeping track of authentication - it stores the login name
(``username``), password, e-mail etc.
We can't change ``User`` very much unless we want to start digging down
into Django source code (and we don't). Django however allows another
model (technically called a *profile*) to reference the User for
customization. This is our ``Player`` object. There is a one-to-one
relationship between ``User`` and Player, so we have tried to completely
hide the ``User`` interface throughout Evennia and left you to only have
to deal with ``Player``.
So for all purposes, ``Player`` represents the OOC existence of a person
logged into Evennia. You e.g. connect to
`Channels <Communications.html>`_ using your Player identity. The Player
object may store configurations and follows you wherever you go. You
will however never see the Player object in-game. This is handled by a
*Character*, a type of `Object <Objects.html>`_ connected to the
``character`` property in the list above.
So why don't we just use ``Player`` to walk around with too? The main
reason for this is flexibility. Your Player object won't change, but
your character *might*. By separating the two you could easily implement
a game where you can ``swap`` between different *Character* objects. All
you'd need to do is change the ``character`` property to point to
another suitable object (and change the values of the ``player``
property on the affected objects).
So the structure looks like ``User - Player - Character``, where the
last two are typeclassed, customizable objects.

View file

@ -0,0 +1,61 @@
Portal and Server layout
========================
Evennia consists of two processes, known as *Portal* and *Server*. They
can be controlled from inside the game or from the command line as
described `here <StartStopReload.html>`_.
https://2498159658166209538-a-1802744773732722657-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia*server*portal.png
As seen above, the Server and Portal are glued together via an AMP
(Asynchronous Messaging Protocol) connection. This allows the two
programs to communicate.
Portal and Server Sessions
--------------------------
*note: This is not really necessary to understand if you are new to
Evennia.*
New Player connections are listened for and handled by the Portal using
the `protocols <SessionProtocols.html>`_ it understands (such as telnet,
ssh, webclient etc). When a new connection is established, a *Portal
Session* is created on the Portal side. This session object looks
different depending on which protocol is used to connect, but all still
have a minimum set of attributes that are generic to all sessions.
These common properties are piped through AMP to the Server, who is now
informed a new connection has been established. On the Server side, a
*Server Session* object is created to represent this. There is only one
type of Server Session. It looks the same regardless of how the Player
connects, it leaves such details up to the Portal.
From now on, there is a one-to-one match between the Server Session on
one side and the Portal Session on the other. Data arriving to the
Portal Session is sent on to its mirror Server session and vice versa.
During certain situations, the portal- and server-side sessions are
"synced" with each other:
- The Player closes their client, killing the Portal Session. The
Portal syncs with the Server to make sure the corresponding Server
Session is also deleted.
- The Player quits from inside the game, killing the Server Session.
The Server then syncs with the Portal to make sure to close the
Portal connection cleanly.
- The Server is rebooted/reset/shutdown - The Server Sessions are then
copied over ("saved") to the Portal side. When the Server comes back
up, this data is returned by the Portal so the two are again in sync.
This way a Player's login status and other connection-critical things
can survive a server reboot (assuming the Portal is also not stopped,
obviously).
Sessionhandlers
---------------
Both the Portal and Server each have a *sessionhandler* to manage the
connections. These handlers contain all methods for relaying data across
the AMP bridge. All types of Sessions hold a reference to their
respective Sessionhandler (the property is called ``sessionhandler``) so
they can relay data. See `protocols <SessionProtocols.html>`_ for more
info on building new protocols.

View file

@ -0,0 +1,115 @@
Tutorial: Removing colour from your game
========================================
This is a small tutorial for customizing your character objects, using
the example of letting users turn on and off ansii colour parsing.
In the Building guide's `Colours <Colours.html>`_ page you can learn how
to add Colour to your game by using special markup. Colours enhance the
gaming experience, but not all users want colour. Examples would be
users working from clients that don't support colour, or people with
various seeing disabilities that rely on screen readers to play your
game.
So here's how to allow those users to remove colour. It basically means
you implementing a simple configuration system for your characters. This
is the basic sequence:
#. Define your own default character typeclass, inheriting from
Evennia's default.
#. Set an attribute on the character to control markup on/off.
#. Set your custom character class to be the default for new players.
#. Overload the ``msg()`` method on the typeclass and change how it uses
markup.
#. Create a custom command to allow users to change their setting.
Setting up a custom Typeclass
-----------------------------
Create a new module in ``game/gamesrc/objects`` named, for example,
``mycharacter.py``.
In your new module, create a new `typeclass <Typeclasses.html>`_
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
Above we set a simple config value as an `attribute <Attributes.html>`_.
Let's make sure that new characters are created of this type. Edit your
``game/settings.py`` file and change ``BASE_CHARACTER_TYPECLASS`` to
point to your new character class. Observe that this will only affect
*new* characters, not those already created. You have to convert already
created characters to the new typeclass by using the ``@typeclass``
command (try on a secondary character first though, to test that
everything works - you don't want to render your root user unusable!).
::
@typeclass/reset/force 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.
Overload the ``msg()`` method
-----------------------------
Next we need to overload the ``msg()`` method. What we want is to check
the configuration value before calling the main function. The original
``msg`` method is found on ``src.objects.models.ObjectDB`` and is called
like this:
::
msg(message, from_obj=None, data=None)
As long as we define a method on our custom object with the same name
and keep the same number of arguments/keywords we will overload the
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)
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
done, we pass it all on to the normal ``msg()`` on the database object
(``ObjectDB``) to do its thing.
Since we put this custom ``msg()`` in our typeclass
``ColourableCharacter``, it will be searched for and called rather than
the default method on ``ObjectDB`` (which we now instead call manually).
There we go! Just flip the attribute ``config_colour`` to False and your
users will not see any colour.
Custom colour config command
----------------------------
For completeness, let's add a custom command so users can turn off their
colour display themselves if they want.
In game/gamesrc/commands, create a new file, call it for example
``configcmds.py`` (it's likely that you'll want to add other commands
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)
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:
::
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
should be able to turn on or off their colour as they please.

View file

@ -0,0 +1,160 @@
Scripts
=======
*Scripts* are the way to implement everything in Evennia that may change
with time.
The most obvious use of Scripts may be to use them as *timers* or
*Events*. Consider a script running on the object ``Grandfather Clock``.
The script has a timer that tells it to fire every hour. This allows the
clock to chime regularly. The script might even regulate how often the
clock must be rewound so it won't stop.
Scripts may act as changeable *States*. Consider for example creating a
'dark' room. It has two scripts assigned on it - one ``DarkState``
script, and one ``BrightState`` script. When characters enters the dark
room, it assigns a custom `Cmdset <Commands.html>`_ to them - this
command set (say) limits their actions because of the darkness. After
the characters have stumbled around for a while, someone brings up a
torch. As a light source is now in the room, ``DarkState`` reacts to
this by shutting down itself and handing over control to the
``BrightState`` script that restores normal commands. Finally, when the
character with the torch leaves the room, the ``BrightState`` script
detects this and obediently hands control back to the ``DarkState``,
leaving the remaining poor characters in darkness once again.
By combining state-changes with timers one can make a room look
different during nighttime than it does during the day. Weather and
seasons might come and go. But one can also achieve more complex things
such as state-AI systems that make mobs move around and possibly persue
characters between rooms.
... In short, Scripts make the game world *tick*. Scripts are
database-persistent objects and are `TypeClassed <Typeclasses.html>`_
entities, with all the advantages that this entails.
How to create your own Script types
-----------------------------------
An Evennia Script is, per definition, a Python class that includes
``src.scripts.scripts.Script`` among its parents (if you are aware of
how typeclasses work, this is a typeclass linked to the ``ScriptDB``
database model). Scripts have no in-game representation and you cannot
define them with any default commands. They have to be created in python
code modules and imported from there into the game.
The vast majority of scripts are always run 'on'
`Objects <Objects.html>`_ affecting that object and maybe its
surroundings or contents. Scripts unrelated to objects are called
*Global* scripts and could handle things like game-time, weather and
other tickers.
Custom script modules are usually stored in ``game/gamesrc/scripts``. As
a convenience you can inherit all scripts from
``game.gamesrc.scripts.basescript.Script``.
You can try out scripts an add them to objects by use of the ``@script``
command (not to the confused with ``@scripts`` which lists scripts). You
can try it out with an example script:
::
> @script self = examples.bodyfunctions.BodyFunctions
This should cause some random messages. The ``/stop`` switch will kill
the script again.
In code, you add scripts to `Objects <Objects.html>`_ and the script can
then manipulate the object as desired. The script is added to the
object's *script handler*, called simply ``scripts``. The handler takes
care of all initialization and startup of the script for you.
::
# adding a script to an existing object 'myobj'myobj.scripts.add("game.gamesrc.scripts.myscripts.CoolScript")
The ``myobj.scripts.add()`` method also takes an argument *key* that
allows you to name your script uniquely before adding it. This is not
necessary, but is useful if you add many scripts of the same class and
later plan to use ``myobj.scripts.delete`` to remove individual scripts.
Properties and functions defined on Scripts
-------------------------------------------
It's important to know the variables controlling the script before one
can create one. Beyond those properties assigned to all typeclassed
objects (see `Typeclasses <Typeclasses.html>`_), such as ``key``,
``db``, ``ndb`` etc, all Scripts also has the following properties:
- ``desc`` - an optional description of the script's function. Seen in
listings.
- ``interval`` - how often the script should run. If ``interval == 0``
(default), it runs forever (it will not accept a negative value).
- ``start_delay`` - (bool), if we should wait ``interval`` seconds
before firing for the first time or not.
- ``repeats`` - How many times we should repeat, assuming
``interval > 0``. If repeats is set to ``<= 0``, the script will
repeat indefinitely.
- ``persistent``- if this script should survive a server reboot.
There is one special property:
- ``obj`` - the `Object <Objects.html>`_ this script is attached to (if
any). You should not need to set this manually. If you add the script
to the Object with ``myobj.scripts.add(myscriptpath)``, the ``obj``
property will be set to ``myobj`` for you.
It's also imperative to know the hook functions. Normally, overriding
these are all the customization you'll need to do in Scripts. You can
find longer descriptions of these in ``gamesrc/scripts/basescript.py``.
- ``at_script_creation()`` - this is usually where the script class
sets things like ``interval`` and ``repeats``; things that control
how the script runs. It is only called once - when the script is
first created.
- ``is_valid()`` - determines if the script should still be running or
not. This is called when running ``obj.scripts.validate()``, which
you can run manually, but which also Evennia calls during certain
situations such as reloads. This is also useful for using scripts as
state managers. If the method returns ``False``, the script is
stopped and cleanly removed.
- ``at_start()`` - this is called when the script first starts. For
persistent scripts this is at least once ever server startup. Note
that this will *always* be called right away, also if ``start_delay``
is ``True``.
- ``at_repeat()`` - this is called every ``interval`` seconds, or not
at all. It is called right away at startup, unless ``start_delay`` is
``True``, in which case the system will wait ``interval`` seconds
before calling.
- ``at_stop()`` - this is called when the script stops for whatever
reason. It's a good place to do custom cleanup.
::
import random
from game.gamesrc.scripts.basescript import Scriptclass Weather(Script): "Displays weather info. Meant to be attached to a room." def at_script_creation(self): "Called once, during initial creation" self.key = "weather_script" self.desc = "Gives random weather messages." self.interval = 60 * 5 # every 5 minutes self.persistent = True self.at_repeat(self): "called every self.interval seconds." rand = random.random() if rand < 0.5: weather = "A faint breeze is felt." elif rand < 0.7: weather = "Clouds sweep across the sky." else: weather = "There is a light drizzle of rain." # send this message to everyone inside the object this # script is attached to (likely a room) self.obj.msg_contents(weather)
This is a simple weather script that we can put on an object. Every 5
minutes it will tell everyone inside that object how the weather is.
To activate it, just add it to the script handler (``scripts``) on an
`Room <Objects.html>`_. That object becomes ``self.obj`` in the example
above. Here we put it on a room called ``myroom``:
::
# Assuming Script is found in game/gamesrc/scripts/weather.pymyroom.scripts.add(weather.Weather)
Or, from in-game, use the ``@script`` command:
::
@script here = weather.Weather
Further notes
-------------
Should you *really* need to create a script unrelated to a particular
Object (this is called a *Global* script), you can create it with
``src.utils.create.create_script()`` and refrain from supplying an
object to store it on. See that module for more info.

View file

@ -0,0 +1,103 @@
Portal Sessions and Protocols
=============================
*Note: This is considered an advanced topic and not relevant to most
users.*
A *Portal Session* is the basic data object representing an external
connection to the Evennia `Portal <PortalAndServer.html>`_ -- usually a
human player running a mud client of some kind. The way they connect -
the language the player's client and Evennia use to talk to each other -
is called the connection *Protocol*. The most common such protocol for
MUD:s is the *Telnet* protocol. All Portal Sessions are stored and
managed by the Portal's *sessionhandler*.
It's technically sometimes hard to separate the concept of *Session*
from the concept of *Protocol* since both depend heavily on the other.
Protocols and Sessions both belong in ``src/server/``, so adding new
protocols is one of the rare situations where development needs to
happen in ``src/`` (in fact, if you do add a new useful protocol,
consider contacting Evennia devs so we can include it in the main
Evennia distribution!).
Protocols
---------
Writing a stable communication protocol from scratch is not something
we'll cover here, it's no trivial task. The good news is that Twisted
offers implementations of many common protocols, ready for adapting.
Writing a protocol implementation in Twisted usually involves creating a
class inheriting from a suitable Twisted parent, then overloading the
methods that particular protocol requires so that it talks to Evennia.
Whenever a new connection is made via this protocol, an instance of this
class will be called. As various states change, specific-named methods
on the class will be called (what they are named depends on the Twisted
implementation).
A straight-forward protocol (like Telnet) is assumed to at least have
the following components (although the actual method names might vary):
- ``connectionMade`` - called when a new connection is made. This must
call ``self.init_session()`` with three arguments: an identifier for
the protocol type (e.g. the string 'telnet'), the IP address
connecting, and a reference to the sessionhandler.
- ``connectionLost`` - called when connection is dropped for whatever
reason. This must call 'self.sessionhandler.disconnect(self)' so the
handler can make sure the disconnect is reported to the rest of the
system.
- ``getData`` - data arriving from the player to Evennia. This should
apply whatever custom formatting this protocol needs, then relay the
data to ``self.sessionhandler.data_in(self, msg, data)``.
- sendLine - data from server to Player. This is called by hook
``data_out()`` below.
See an example of this in
`server/telnet.py <http://code.google.com/p/evennia/source/browse/trunk/src/server/telnet.py>`_.
These might not be as clear-cut in all protocols, but the principle is
there. These four basic components - however they are accessed - links
to the *Session*, which is the actual common interface between the
different low-level protocols and Evennia.
Portal Sessions
---------------
A *Portal Session* is an Evennia-specific thing. It must be a class
inheriting from ``src.server.session.Session``. If you read the Telnet
example above, the Protocol and Session are infact sometimes
conveniently implemented in the same class through multiple inheritance.
At startup the Portal creates and adds the Portal Session to its
*sessionhandler*. While doing so, the session also gets assigned a
property ``sessionhandler`` that refers to that very handler. This is
important since the handler holds all methods relevant for sending and
receiving data to and from the Server.
Whereas we don't know the method names of a Twisted Protocol (this can
vary from protocol to protocol), the Session has a strict naming scheme
that may not change; it is the glue that connects the Protocol to
Evennia (along with some other convenient features).
The Session class must implement the following method hooks (which must
be named exactly like this):
- ``disconnect()`` - called when manually disconnecting. Must call the
protocol-specific disconnect method (e.g. ``connectionLost`` above)
- ``data_out(string="", data=None)`` - data from Evennia to player.
``string`` is normally a raw text string with formatting. ``data``
can be a collection of any extra information the server want to give
to the protocol; it's completely up to the Protocol to handle this
(e.g. telnet completely ignores the ``data`` variable). From inside
Evennia, this if often called with the alias ``msg`` instead. This
method should call the protocol-specific send method, such as
``self.sendLine()``, directly.
Assorted notes
--------------
To take two examples, Evennia supports the *telnet* protocol as well as
*webclient*, a custom ajax protocol. You'll find that whereas telnet is
a textbook example of a Twisted protocol as seen above, the ajax client
protocol looks quite different due to how it interacts with the
webserver through long-polling (comet) style requests.

View file

@ -0,0 +1,123 @@
A brief explanation of what MUSH softcode is and why we use Python
instead.
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
with 'MUX-like' default commands.
This document will provide a quick overview of what softcode is, why it
drove us to write Evennia, and why we instead use Python.
Softcode is a very simple programming language that was created for
in-game development on TinyMUD derivatives such as MUX, PennMUSH,
TinyMUSH, and RhostMUSH. The idea is that by providing a stripped down,
minimalistic language for in-game use, you can allow quick and easy
building and game development to happen without having to learn C/C++.
There is an added benefit of not having to have to hand out shell access
to all developers, and permissions can be used to alleviate many
security problems.
Writing and installing softcode is done through a MUD client. As is
such, it is not a formatted language. Each softcode function is a single
line of varying size. Some functions can be a half of a page long due to
this, which is obviously not very readable. The lack of formatting is
one of the big reasons Evennia exists today. Bigger projects tend to
choke under their own weight after time unless your entire staff has a
good understanding of functional programming practices.
Examples of Softcode
--------------------
Here is a simple 'Hello World!' command:
::
@set me=HELLO_WORLD.C:$hello:@pemit %#=Hello World!
Pasting this into a MUX/MUSH and typing 'hello' will theoretically yield
'Hello World!', assuming certain flags are not set on your player
object.
Setting attributes is done via ``@set``. Softcode also allows the use of
the ampersand (``&``) symbol. This shorter version looks like this:
::
&HELLO_WORLD.C me=$hello:@pemit %#=Hello World!
Perhaps I want to break the Hello World into an attribute which is
retrieved when emitting:
::
&HELLO_VALUE.D me=Hello World &HELLO_WORLD.C me=$hello:@pemit %#=[v(HELLO_VALUE.D)]
The v() function returns the HELLO\_VALUE.D attribute on the object that
the command resides (``me``, which is yourself in this case). This
should yield the same output as the first example.
If you are still curious about how Softcode works, take a look at some
external resources:
- http://www.tinymux.com/wiki/index.php/Softcode
- http://www.duh.com/discordia/mushman/man2x1
Problems with Softcode
----------------------
Softcode is excellent at what it was intended for: simple things. It is
an incredible tool if used for its intended purposes - an interactive
object, a room with ambiance, simple global commands, simple economies
and coded systems. However, once you start to try to write something
like a complex combat system or a higher end economy, you're likely to
find yourself buried under a mountain of functions that span various
objects and are of various length.
Not to mention, softcode is not an inherently fast language. It is not
compiled, it is parsed with each calling of a function. While MUX and
MUSH parsers have jumped light years ahead of where they were even seven
or eight years ago, they can still stutter under the weight of the more
complex systems if not designed properly.
Changing Times
--------------
Now that starting text-based games is easy and an option for even the
most technically inarticulate, new projects are a dime a dozen. People
are starting new MUDs every day with varying levels of commitment and
ability. Because of this shift from fewer, larger, well-staffed games to
a bunch of small, one or two developer games, some of the benefit of
softcode fades.
Softcode is great in that it allows a mid to large sized staff all work
on the same game without stepping on one another's toes. As mentioned
before, shell access is not necessary to develop a MUX or a MUSH.
However, now that we are seeing a lot more small, one or two-man shops,
the issue of shell access and stepping on each other's toes is a lot
less.
Our Solution
============
For the hobbyist who would like the option to use a full-featured
language, we created Evennia. We are no longer bound to single lines of
softcode. Game developers now have access to the entire library of
Python modules out there in the wild. Our complex systems may be
organized neatly into modules, sub-modules, or even broken out into
entire Python packages.
So what is *not* included in Evennia is a MUX/MOO-like online player
building system. Advanced coding and building in Evennia is primarily
intended to be done outside the game, in full-fledged Python modules. We
feel that with a small development team you are better off using a
professional source-control system (svn, git, bazaar, mercurial etc)
anyway.
There is of course nothing stopping you from adding very advanced online
building commands to Evennia (or even re-implement MUX' softcode in
Python should you be very ambitious), but at this time this is not
something planned to come with he core distribution.

View file

@ -0,0 +1,155 @@
Using Version Control to collaboratively manage and develop a game
==================================================================
*TODO: This page does not yet deal much with the specifics of access
control and protocols used when allowing access to a remove repository.
The example commands also lack proper testing!*
Using modern `version control
software <http://en.wikipedia.org/wiki/Version_control>`_ is a powerful
way for a small development team to collaborate on a MUD project. Not
only will it help you keep track of your changes (and undo bad things
you do), it will also help combine the efforts of many people into one
joint place.
Evennia uses version control in the form of the program Subversion (SVN)
to manage the entire project. It allows multiple coders to contribute
without getting in each other's way. The same mechanic would work just
as well on the next level - with several people collaborating to build
and code a MUD.
This page uses the Python-based
`Bazaar <http://bazaar.canonical.com/en/>`_ version control system as an
example of how to manage your MUD project. There are many other options
though, notably *GIT* or *Mercurial* are worth checking out if Bazaar is
not your thing. We use Bazaar's command-line interface, but Bazaar also
has a full graphical GUI called *Bazaar Explorer* that might make it
easier for newbies to get their head around the concept of version
control. We also cannot go into much detail here, please refer to the
very good Bazaar manuals for more help.
Premise
-------
Let's say you are the admin/owner of a new MUD initiative, based on
Evennia. The whole project will primarily be hosted on your computer.
You are doing this with a few good friends that will help you implement
the actual game system. You also have a few Builders/Coders of varying
skill to help with creating the game world. Apart from building through
their MUD clients, you also want them to be able to submit
build-batchfiles, small code snippets, custom typeclasses and scripts --
without giving them full access to your custom-coded game source.
First you need to set up a `development environment for a single
developer <BazaarDevel.html>`_. That link will also teach you the basics
of using Bazaar. Return here when you are done.
You should by this point have a Bazaar repository *evennia* containing
two branches, ``evennia-trunk`` and ``evennia-mygame``.
Collaborating with trusted coders
---------------------------------
There are many ways to make your code base available to your fellow
administrators/coders.
Branching remotely
~~~~~~~~~~~~~~~~~~
The absolutely easiest way is to have them use Bazaar to simply branch
your ``evennia-mygame`` branch as if it was any other branch. To do this
they need to set up their own repository first with
``bzr init-repo``
Then they branch normally, but over the net:
``bzr branch sftp://url.to.your.computer/evennia-mygame myworkcopy``
(This example uses sftp, but which protocol is used need to be setup and
agreed on. You also need to check so you don't have a firewall blocking
that protocol. The `Bazaar branching
manual <http://doc.bazaar.canonical.com/bzr.2.2/en/user-guide/branching%3Ci%3Ea%3C/i%3Eproject.html>`_
gives a lot more info.)
This will create their very own copy of the branch named ``myworkcopy``,
which they can work on as if it was their own. They can commit changes
to it etc without affecting you. To keep their branches up-to-date
against your branch they need to do a *pull*:
``bzr pull sftp://url.to.your.computer/evennia-mygame``
When they are ready to merge back their changes into your branch, they
need to do a *push*:
``bzr push sftp://url.to.your.computer/evennia-mygame``
SVN-like checkout
~~~~~~~~~~~~~~~~~
Another variant is to make a separate branch for your development
effort, and make this a *checkin branch*. Let's call this branch
*evennia-share*:
``bzr branch evennia-mygame evennia-share``
So far this is the same as ``evennia-mygame``. With the *bind* command
you make this branch act as a centralized, SVN-like repository:
``bzr bind evennia-share``
From now on, people now use ``commit`` and ``update`` from this branch,
and use ``checkout`` to retrieve their personal copy. In fact, users and
contributors can relate to this in the same way you deal with the main
Evennia repository, by setting up equivalents to ``evennia-trunk`` and
``evennia-mygame``. You merge to and from it as usual.
Collaborating with limited access
---------------------------------
Not everyone should (or need) to download your entire customized
codebase (the contents of ``evennia-mygame``) just because they
volunteered to build a region of your game, or is scripting a new
object. And whereas some building can surely happen on-line through MUD
commands, the power of Evennia lies in its Python scripting abilities.
This means them sending you files of code one way or another. Using
e-mail or other communication methods works, but can quickly be a hassle
with many files of different versions.
There are many ways to resolve this with version control, the easiest
might be to simply set aside an isolated place for them to upload their
data to you.
You could have one branch for all builders (so they could collaborate
amongst themselves), or create a completely independent branch for each
builder:
``bzr init anna-builds``
``bzr init peter-builds``
You could for example copy example files / builder instructions etc in
there as needed (``cp`` is a Linux/Unix command, use whatever method is
suitable in your OS): ``cp instructions.txt anna-builds``
``bzr add anna-builds/instructions.txt``
``bzr commit``
You could also *bind* this branch
``bzr bind anna-builds``
so the builder in the future can simply use ``commit`` and ``update`` to
get things in and out of their respective upload area (they'd probably
not mind that they upload to your machine every time they make a
commit).
You can in this way manually inspect submitted files before copying them
into the main branch as desired, using ``bzr add`` to have Bazaar track
them.
.. figure:: http://b.imagehost.org/0824/bazaar_repo2.png
:align: center
:alt:

View file

@ -0,0 +1,102 @@
Running Evennia
===============
You control Evennia from ``game/`` using the ``evennia.py`` program.
Below are described the various management options. You can also start
the program without any arguments or use the *menu* option to get a
multiple-choice menu instead.
::
python evennia.py menu
Starting Evennia
----------------
Evennia consists of two components, the Evennia `Server and
Portal <ServerAndPortal.html>`_. Briefly, the *Server* is what is
running the mud. It handles all game-specific things but don't care
exactly how players connect, only that they have. The *Portal* is a
gateway to which players connect. It knows everything about telnet, ssh,
webclient protocols etc but very little about the game. Both are
required for a functioning mud.
::
python evennia.py start
The above command automatically starts both Portal and Server at the
same time, logging to the log files in ``game/log``.
If you rather see error messages etc directly in the terminal (useful
for quickly debugging your code), you use the -i (interactive) flag:
::
python evennia.py -i start
This will start the *Server* in interactive mode. The Portal will
continue to log to its log file. This is normally what you want unless
you are debugging the Portal.
You can also start the two components one at a time.
::
python evennia.py start server python evennia.py start portal
Adding -i to either of these explicit commands will start that component
in interactive mode so it logs to the terminal rather than to log file.
Reloading
---------
The act of *reloading* means the *Server* program is shut down and then
restarted again. In the default cmdset you initiate a reload by using
the ``@reload`` command from inside the game. The game will be briefly
paused for all players as the server comes back up (since they are all
connected to the *Portal*, their connections are not lost).
Reloading is as close to a "warm reboot" you can get. It reinitializes
all code of Evennia, but doesn't kill "persistent" scripts. It also
calls ``at_server_reload()`` hooks on all objects so you can save
eventual temporary properties you want.
You can also reload the server from outside the game (not available in
Windows):
::
python evennia.py reload
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
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
``at_server_shutdown()`` hooks. It can be a good way to clean unsafe
scripts during development, for example.
A reset is equivalent to
::
python evennia.py stop server python evennia.py start server
Shutting down
-------------
A full shutdown closes Evennia completely, both Server and Portal. All
players will be booted and systems saved and turned off cleanly. From
inside the game you initiate a shutdown with the ``@shutdown`` command.
From command line you do
::
python.py evennia.py stop
You will see messages of both Server and Portal closing down.

View file

@ -0,0 +1,61 @@
Introduction
============
Text *byte encodings* describe how a string of text is actually stored
in the computer - that is, the particular sequence of bytes used to
represent the letters of your particular alphabet. A common encoding
used in English-speaking languages is the *ASCII* encoding. This
describes the letters in the English alphabet (Aa-Zz) as well as a bunch
of special characters. For describing other character sets (such as that
of other languages with other letters than English), sets with names
such as *Latin-1*, *ISO-8859-3* and *ARMSCII-8* are used. There are
hundreds of different byte encodings in use around the world.
In contrast to the byte encoding is the *unicode representation*. The
unicode is an internationally agreed-upon table describing essentially
all available letters you could ever want to print. Everything from
English to Chinese alphabets and all in between. So what Evennia (as
well as Python and Django) does is to store everything in Unicode
internally, but then converts the data to one of the encodings whenever
outputting data to the user.
The problem is that when receiving a string of bytes from a user it's
impossible for Evennia to guess which encoding was used - it's just a
bunch of bytes! Evennia must know the encoding in order to convert back
and from the correct unicode representation.
How to customize encodings
==========================
As long as you stick to the standard ASCII character set (which means
the normal English characters, basically) you should not have to worry
much about this section.
If you want to build your game in another language however, or expect
your users to want to use special characters not in ASCII, you need to
consider which encodings you want to support.
As mentioned, there are many, many byte-encodings used around the world.
It should be clear at this point that Evennia can't guess but has to
assume or somehow be told which encoding you want to use to communicate
with the server. Basically the encoding used by your client must be the
same encoding used by the server. This can be customized in two
complementary ways.
#. Point users to the default ``@encoding`` command. This allows them to
themselves set which encoding they (and their client of choice) uses.
Whereas data will remain stored as unicode internally in Evennia, all
data received from and sent to this particular player will be
converted to the given format before transmitting.
#. As a back-up, in case the user-set encoding translation is erroneous
or fails in some other way, Evennia will fall back to trying with the
names defined in the settings variable ``ENCODINGS``. This is a list
of encoding names Evennia will try, in order, before giving up and
giving an encoding error message.
Note that having to try several different encodings every input/output
adds unneccesary overhead. Try to guess the most common encodings you
players will use and make sure these are tried first. The International
*UTF-8* encoding is what Evennia assumes by default (and also what
Python/Django use normally). See the Wikipedia article
`here <http://en.wikipedia.org/wiki/Text_encodings>`_ for more help.

View file

@ -0,0 +1,71 @@
Tutorial World Introduction
===========================
The *Tutorial World* is, quite simply, a small example of Evennia usage
for you to learn from. It's also a functioning (if small) game - a small
single-player quest area with some 20 rooms that you can explore on your
quest to find a mythical weapon.
The source code is fully documented and you can find the whole thing in
``contrib/tutorial_world``.
Some features exemplified by the tutorial world:
- Tutorial command, giving "behind-the-scenes" help for every room and
some of the special objects
- Hidden exits
- Objects with multiple custom interactions
- Large-area rooms
- Outdoor weather rooms
- Dark room, needing light source
- Puzzle object
- Multi-room puzzle
- Aggressive mobile with roam, pursue and battle state-engine AI
- Weapons, also used by mobs
- Simple combat system with attack/defend commands
- Object spawn
- Teleporter trap rooms
Install
-------
The tutorial world consists of a a few modules in
``contrib/tutorial_world/`` containing custom
`Typeclasses <Typeclasses.html>`_ for `rooms and
objects <Objects.html>`_, associated `commands <Commands.html>`_ and a
few custom `scripts <Scripts.html>`_ to make things tick.
These reusable bits and pieces are then put together into a functioning
game area ("world" is maybe too big a word for such a small zone) using
a `batch script <BatchProcessors.html>`_ called ``build.ev``. To
install, log into the server as the superuser (user #1) and run:
::
@batchcommand contrib.tutorial_world.build
The world will be built (there will be a lot of text output) and you
will end up back in Limbo with a new exit called ``tutorial``. You can
also use the ``/interactive`` switch of ``@batchcommand`` to be able to
slowly go through each step of building the world in detail.
To play the tutorial "correctly", you should *not* do so as superuser.
The reason for this is that many game systems ignore the presence of a
superuser and will thus not work as normal. Create a new, non-superuser
character instead (as superuser you can of course examine things "under
the hood" later if you want).
Notes
-----
When reading and learning from the code, keep in mind that *Tutorial
World* was created with a very specific goal: to install easily and to
not permanently modify the rest of the server. It therefore goes to some
length to use only temporary solutions and to clean up after itself.
None of the basic typeclasses are modified more than temporarily. This
means the tutorial sometimes needs to solve things in a more complex
fashion than really needed.
When coding your own game you'd of course not have such considerations -
you'd just customize the base typeclasses to always work just the way
you want and be done with it.

View file

@ -0,0 +1,251 @@
Typeclassed objects
===================
Several of the the main game 'entities' in Evennia, namely
`Players <Players.html>`_, `Objects <Objects.html>`_ and
`Scripts <Scripts.html>`_ - are what we call *typeclassed*. This
basically means that they are almost normal Python classes that 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 know
that all the listed game entities inherit a common interface from the
typeclass system, properties you can *always* expect a typeclassed
entity to have *beyond* the more specialized properties unique to each
sub-type. Typeclasses also do some special things with their in-built
class methods that you shouldn't edit.
Properties available to all typeclassed entities (Players, Objects,
Scripts)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ``key`` - the main identifier for the entity, say 'Rose', 'myscript'
or 'Paul'. ``name`` is an alias that can also be used.
- ``date_created`` - time stamp when this object was created.
- ``locks`` - the `lockhandler <Locks.html>`_ that manages access
restrictsions. Use locks.add(), locks.get() etc.
- ``dbref`` - the database id (database ref) of the object. This is a
unique integer. You can usually also use ``id``.
There are three further properties that warrant special mention:
- ``db`` (!DataBase) - this is the interface to the `Attribute
system <Attributes.html>`_, allowing for *persistently* storing your
own custom data on the entity (i.e. data that will survive a server
restart).
- ``ndb`` (!NotDataBase) - this is equivalent to the functionality of
``db`` but is used to store *non-peristent* data (i.e. data that will
be lost on server restart).
- ``dbobj`` - this is a reference to the *Database object* connected to
this typeclass (reversely, ``dbobj.typeclass`` is a reference back to
this very typeclass).
Each of the typeclassed entities then extend this list with their own
properties. Go to the pages for `Objects <Objects.html>`_,
`Scripts <Scripts.html>`_ and `Players <Players.html>`_ respectively for
more info.
Things to remember when using TypeClasses
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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:
- Evennia will look for and call especially named *hook methods* on the
typeclass in different situations. Just define a new method on the
class named correctly and Evennia will call it appropriately. Hooks
are your main way to interact with the server. Available hook methods
are listed in the resepective base modules in ``game/gamesrc/``.
- Don't use the normal ``__init__()`` to set up your typeclass. It is
used by Evennia to set up the mechanics of the Typeclass system. Use
the designated hook method instead, such as ``at_object_creation()``,
``at_player_creation()`` or ``at_script_creation()``.
- Don't re-implement the python special class methods
``__setattr__()``, ``__getattribute__()`` and ``__delattr__()``.
These are used extensively by the Typeclass system.
- Some property names cannot be assigned to a Typeclassed entity due to
being used for internal Typeclass operations. If you try, you will
get an error. These property names are *id*, *dbobj*, *db*, *ndb*,
*objects*, *typeclass*, *attr*, *save* and *delete*.
- Even if they are not explicitly protected, you should not redefine
the "type" of the default typeclass properties listed above and on
each typeclassed entity (such as trying to store an integer in the
``key`` property). These properties are often called by the engine
expecting a certain type of return, and some are even tied directly
to the database and will thus return errors if given a value of the
wrong type.
- *Advanced note*: If you are doing advanced coding you might (very
rarely) find that overloading ``__init__``, ``_setattr__`` etc allows
for some functionality not possible with hooks alone. You *can* do it
if you know what you are doing, but you *must* then remember to use
Python's built-in function ``super()`` to call the parent method too,
or you *will* crash the server! You have been warned.
How typeclasses actually work
-----------------------------
\_You don't need to read this section to use typeclassed entities, but
it might be useful if you want to do advanced things or are interested
in knowing how Evennia actually does things behind the scenes.\_
All typeclassed entities actually consist of two (three) parts:
#. The *Typeclass* (a normal Python class with customized get/set
behaviour)
#. The *Database model* (Django model)
#. (`Attributes <Attributes.html>`_)
The *Typeclass* is an almost normal Python class, and holds all the
flexibility of such a class. This is what makes the class special, some
of which was already mentioned above:
- It inherits from ``src.typeclasses.typeclass.TypeClass``.
- ``__init__()`` is reserved for various custom startup procedures.
- It always initiates a property ``dbobj`` that points to a *Database
model*.
- It redefines python's normal ``__getattribute__()``,
``__setattr__()`` and ``__delattr__`` on itself to relay all data on
itself to/from ``dbobj`` (i.e. to/from the database model).
The related *Database model* in turn communicates data in and out of the
the database. The Database model holds the following (typeclass-related)
features:
- It inherits from ``src.typeclasses.models.TypedObject`` (this
actually implements a
`idmapper <http://github.com/dcramer/django-idmapper>`_-type model.
If that doesn't mean anything to you, never mind).
- It has a field ``typelclass_path`` that gives the python path to the
*Typeclass* associated with this particular model instance.
- It has a property *typeclass* that dynamically imports and loads the
*Typeclass* from ``typeclass_path``, and assigns itself to the
Typeclass' ``dbobj`` property.
- It redefines ``__getattribute__()`` to search its typeclass too,
while avoiding loops. This means you can search either object and
find also data stored on the other.
The *Attributes* are not really part of the typeclass scheme, but are
very important for saving data without having to change the database
object itself. They are covered in a separate entry
`here <Attributes.html>`_.
Why split it like this?
~~~~~~~~~~~~~~~~~~~~~~~
The *Database model* (Django model) allows for saving data to the
database and is a great place for storing persistent data an object
might need during and between sessions. But it is not suitable for
representing all the various objects a game needs. You *don't* want to
have to redefine a new database representation just because a
``CarObject`` needs to look and behave differently than a
``ChairObject``. So instead we keep the database model pretty "generic",
and only put database Fields on it that we know that *all* objects would
need (or that require fast and regular database searches). Examples of
such fields are "key" and "location".
Enter the *Typeclass*. For lack of a better word, a typeclass
"decorates" a Django database model. Through the re-definition of the
class' get/set methods, the typeclass constantly communicates behind the
scenes with the Django model. The beauty of it is that this is all
hidden from you, the coder. As long as you don't overwrite the few magic
methods listed above you can deal with the typeclass almost as you would
any normal Python class. You can extend it, inherit from it, and so on,
mostly without caring that it is infact hiding a full persistent
database representation. So you can now create a typeclass-class
*Flowers* and then inherit a bunch of other typeclass-classes from that
one, like *Rose*, *Tulip*, *Sunflower*. As your classes are instantiated
they will each secretly carry a reference to a database model to which
all data *actually* goes. We, however, can treat the two as if they
where one.
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
``game.gamesrc.objects.flower.Rose``. It inherits from
``game.gamesrc.objects.baseobjects.Object``, which is a grandchild of
``src.typeclasses.typeclass.TypeClass``. So the rose a typeclassed
object, just as it should be.
#. Using a command we create a new *Rose* instance *!RedRose* (e.g. with
``@create redrose:flowers.Rose``).
#. A new database model is created and given the key *!RedRose*. Since
this is an `Object <Objects.html>`_ typeclass (rather than a Script
or Player), the database model used is
``src.objects.models.ObjectDB``, which inherits directly from
``src.typeclasses.models.TypedObject``).
#. This new Django-model instance receives the python-path to the *Rose*
typeclass and stores it as a string on itself (in a database field
``typeclass_path``). When the server restarts in the future, the
database model will restart from this point.
#. The database model next *imports* the Typeclass from its stored path
and creates a new instance of it in memory. It stores a reference to
this instance of *Rose* (*!RedRose*)in a property called
``typeclass``.
#. As *Rose* is instantiated, its ``__init__()`` method is called. What
this does it to make sure to store the back-reference to the Django
model on our new *Rose* instance. This back-reference is called
``dbobj``.
#. The creation method next runs the relevant startup hooks on the
typeclass, such as ``at_object_creation()``.
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).
Doing ``ouch = RedRose.thorns`` is however not really as symmetric. The
system will in this case *first* check the Typeclass instance and only
if no property *thorns* was found will go on to examine the database
object. So ``ouch = RedRose.thorns`` is not necessarily the same as
``ouch = RedRose.dbobj.thorns`` in this case. The reason we don't assume
everything to be on the database object is that you are likely to
customize your *Rose* typeclass with custom parameters and methods that
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>`_.
Another example:
.. figure:: http://b.imagehost.org/0023/typeclasses2.png
:align: center
:alt:
Caveats of the typeclass system
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
While there are many advantages to the typeclass system over working
with Django models directly, there are also some caveats to remember.
Be careful when not using Evennia's search and create methods. Almost
all code in evennia (including default commands) assume that what is
returned from searches or creates are Typeclasses, not Django models
(i.e. the first of the two in the pair). This is what you get if you use
any of the model manager methods, and also the create/search functions
in ``src.utils.create`` and ``src.utils.search``. Old Django-gurus will
find it tempting to use Django's in-build database query methods, such
as ``ObjectDB.objects.filter()`` to get data. This works, but the result
will then of course *not* be a typeclass but a Django model object (a
query). You can easily convert between them with ``dbobj.typeclass`` and
``typeclass.dbobj``, but you should be aware of this distinction.
::
obj = ObjectDB.objects.get_id(1) # custom evennia manager method. This returns the typeclass. obj = ObjectDB.objects.get(1) # standard Django. Returns a Django model object.
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
should be fine.
Read the ``manager.py`` files in each relevant folder under ``src/`` to
see which database access methods are available.

View file

@ -0,0 +1,103 @@
Using and writing unit tests for Evennia.
Unit Testing
============
*This topic is mainly of interest to people interested in helping to
develop Evennia itself.*
Unit testing means testing components of a program in isolation from
each other to make sure every part works on its own before using it with
others. Extensive testing helps avoid new updates causing unexpected
side effects as well as alleviates general code rot (a more
comprehensive wikipedia article on unit testing can be found
`here <http://en.wikipedia.org/wiki/Unit_test>`_).
A typical unit test calls some component of Evennia with a given input,
looks at the result and makes sure that this result looks as expected.
Rather than having lots of stand-alone test programs, Evennia makes use
of a central *test runner*. This is a program that gathers all available
tests all over the Evennia source code (called *test suites*) and runs
them all in one go. Errors and tracebacks are reported.
Running the test suite
----------------------
To run the Evennia test suite, go to the ``game/`` folder and issue the
command
``python manage.py test``
A temporary database will be instantiated to manage the tests. If
everything works out you will see how many tests were run and how long
it took. If something went wrong you will get error messages.
Writing new tests
-----------------
Evennia's test suite makes use of Django unit test system, which in turn
relies on Python's *unittest* module. Evennia's test modules are always
named ``tests.py`` and should be located in different sub folders of
``src/`` depending on which system they are testing. You can find an
example of a testing module in ``src/objects/tests.py``.
Inside the ``tests.py`` module you create classes inheriting from
``django.test.TestCase`` (later versions of Django will use
``django.utils.unittest.TestCase`` instead). A ``TestCase`` class is
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.
To test the results, you use special methods of the ``TestCase`` class.
Many of those start with "``assert``", such as ``assertEqual`` or
``assertTrue``.
Example of a ``TestCase`` class (inside a file ``tests.py``):
::
# testing a simple funciontry: # this is an optimized version only available in later Django versions from django.utils.unittest import TestCase except ImportError: # if the first fail, we use the old version from django.test import TestCase# the function we want to test from mypath import myfuncTestObj(unittest.TestCase): "This tests a function myfunc." def test_return_value(self): "test method. Makes sure return value is as expected." expected_return = "This is me being nice." actual_return = myfunc() # test self.assertEqual(expected_return, actual_return) def test_alternative_call(self): "test method. Calls with a keyword argument." expected_return = "This is me being baaaad." actual_return = myfunc(bad=True) # test self.assertEqual(expected_return, actual_return)
The above example is very simplistic, but you should get the idea. Look
at ``src/objects/tests.py`` for more realistic examples of tests. You
might also want to read the `documentation for the unittest
module <http://docs.python.org/library/unittest.html>`_.
Testing in-game Commands
------------------------
In-game Commands are a special case. Tests for the default commands are
put in ``src/commands/default/tests.py``. This test suite is executed as
part of running the ``objects`` test suite (since it lies outside
Django's normal "app" structure). It also supplies a few convenience
functions for executing commands (notably creating a "fake" player
session so as to mimic an actual command call). It also makes several
test characters and objects available. For example ``char1`` is a
"logged in" Character object that acts as the one calling the command.
Each command tested should have its own ``TestCase`` class. Inherit this
class from the ``CommandTest`` class in the same module to get access to
the command-specific utilities mentioned.
::
class TestSet(CommandTest):
"tests the @set command by simple call"
def test_call(self):
self.execute_command("@set self/testval = mytestvalue")
# knowing what @set does, our test character (char1) should
# by now have a new attribute 'testval' with the value 'mytestvalue'.
self.assertEqual("mytestvalue", self.char1.db.testval)
A note on adding new tests
--------------------------
Having an extensive tests suite is very important for avoiding code
degradation as Evennia is developed. Only a small fraction of the
Evennia codebase is covered by test suites at this point. Writing new
tests is not hard, it's more a matter of finding the time to do so. So
adding new tests is really an area where everyone can contribute, also
with only limited Python skills.

View file

@ -0,0 +1,61 @@
Updating your Game
==================
Fortunately, it's extremely easy to keep your Evennia server up-to-date
via Subversion. If you haven't already, see the `Getting Started
guide <GettingStarted.html>`_ and get your installation up. You'll then
want to join the `Evennia Commit
Log <http://groups.google.com/group/evennia-commits/>`_ group. This will
notify you via email whenever updates are made to the source in the
Subversion repository, letting you know you need to update. You can also
subscribe to the RSS feed or check up on the feeds from
`http://www.evennia.com. <http://www.evennia.com.>`_ When you're wanting
to apply updates, simply ``cd`` to your ``evennia`` root directory and
type:
``svn update``
Assuming you've got the command line client. If you're using a graphical
client, you will probably want to navigate to the ``evennia`` directory
and either right click and find your client's update function, or use
one of the menus (if applicable).
You can review the latest changes with
``svn log``
or the equivalent in the graphical client. You can also see the latest
changes online `here <http://code.google.com/p/evennia/source/list>`_.
A Note on Schema Migration
--------------------------
Database migration becomes an issue when/if the database models of
Evennia changes in an update (this should be gradually more and more
rare as Evennia matures). If you already have a database, this then has
to be updated to match the latest server version or you are likely to
run into trouble down the line.
One way to solve this is to manually add/remove the new tables or fields
to your existing database (or simply reset your database if you don't
have anything important in it yet). Enter
`South <http://south.aeracode.org/>`_. South is a Django database schema
migration tool. It keep tracks of changes in the database schema and
applies those changes to the database for you.
Using South is optional, but if you install South, Evennia will use it
automatically. See correct section of
`GettingStarted <GettingStarted.html>`_ on how to install South and the
slightly changed way to start a clean database server when South is used
(you have to give the ``mange.py migrate`` command as well as
``manage.py syncdb``).
Once you have a database ready to use South, you work as normal.
Whenever a new Evennia update tells you that the database schema has
changed (check ``svn log`` or the online list), you go to ``game/`` and
run this command:
``python manage.py migrate``
This will convert your database to the new schema and you should be set
to go.

View file

@ -0,0 +1,48 @@
The 'MUX-like' default of Evennia
=================================
Evennia is a highly customizable codebase. Among many things, its
command structure and indeed the very way that commands look can all be
changed by you. If you like the way, say, DikuMUDs handle things, you
could emulate that with Evennia. Or LPMuds, or MOOs. Or if you are
ambitious you could design a whole new style, perfectly fitting your own
dreams of the ideal MUD.
We do offer a default however. The default Evennia setup tend to
resemble `MUX2 <http://www.tinymux.org/>`_, and its cousins
`PennMUSH <http://www.pennmush.org>`_,
`TinyMUSH <http://tinymush.sourceforge.net/>`_, and
`RhostMUSH <http://www.rhostmush.org/>`_. By default we emulate these
Tiny derivatives (MUX2, Penn, etc) in the user interface and building
commands. We believe these codebases have found a good way to do things
in terms of building and administration. We hope this will also make it
more familiar for new users coming from those communities to start using
Evennia.
However, Evennia has taken a completely different stance on how admins
extend and improve their games. Instead of implementing a special
in-game language (!SoftCode), all game extension is done through Python
modules, like the rest of Evennia. This gives the admin practically
unlimited power to extend the game leveraging the full power of a mature
high level programming language. You can find a more elaborate
discussion about our take on MUX SoftCode `here <SoftCode.html>`_.
WWMD - What Would MUX Do?
-------------------------
Our policy for implementing the default commands is as follows - we tend
to look at MUX2's implementation before contriving one of our own. This
comes with a caveat though - there are many cases where this is
impossible without sacrificing the usability and utility of the
codebase. In those cases, differences in implementation as well as
command syntax is to be expected. Evennia is *not* MUX - we handle all
underlying systems very differently and don't use SoftCode. The WWMD
policy is only applied to the default commands, not to any other
programming paradigms in the codebase.
If you are an Evennia codebase developer, consider activating
``IMPORT_MUX_HELP`` in your ``settings.py`` file. This will import a
copy of the MUX2 help database and might come in handy when it comes to
adding/implementing new default commands. If you must deviate from
MUX2's implementation of something, make sure to document it extensively
in the command's docstring.

View file

@ -0,0 +1,64 @@
Web Features
============
Evennia is its own webserver and hosts a default website and browser
webclient.
Editing the Web site
--------------------
The Evennia website is a Django application that ties in with the MUD
database. It allows you to, for example, tell website visitors how many
players are logged into the game at the moment, how long the server has
been up and any other database information you may want. The dynamic
website application is located in ``src/web/website`` whereas you will
find the html files in ``src/web/templates/prosimii``. Static media such
as images, css and javascript files are served from ``src/web/media``.
You can access the website during development by going to
``http://localhost:8000``.
Since it's not recommended to edit files in ``src/`` directly, we need
to devise a way to allow website customization from ``game/gamesrc``.
This is not really finalized at the current time (it will be easier to
share media directories in Django 1.3) so for now, your easiest course
of action is probably to copy the entire ``src/web`` directory into
``game/gamesrc/`` and modify the copy. Make sure to retain permissions
so the server can access the directory.
You also need to modify the settings file. Set ``ROOT_URLCONF`` to your
new ``game.gamesrc.web.urls`` and add an entry
``os.path.join(GAME_DIR, "web", "templates", ACTIVE_TEMPLATE)`` to the
``TEMPLATE_DIRS`` tuple. You should now have a separate website setup
you can edit as you like. Be aware that updates we do to ``src/web``
will not transfer automatically to your copy, so you'll need to apply
updates manually.
Web client
----------
Evennia comes with a MUD client accessible from a normal web browser. It
is technically a javascript client polling an asynchronous webserver
through long-polling (this is also known as a *COMET* setup). The
webclient server is defined in ``src/server/webclient`` and is not
something that should normally need to be edited unless you are creating
a custom client. The client javascript, html and css files are located
under the respective folders of ``src/web/``.
The webclient uses the `jQuery <http://jquery.com/>`_ javascript
library. This is imported automatically over the internet when running
the server. If you want to run the client without an internet
connection, you need to download the library from the jQuery homepage
and put it in ``src/web/media/javascript``. Then edit
``src/web/templates/prosimii/webclient.html`` and uncomment the line:
::
<script src="/media/javascript/jquery-1.4.4.js" type="text/javascript" charset="utf-8"></script>
(edit it to match the name of the ``*.js`` for the jQuery version you
downloaded).
The webclient requires the webserver to be running and is then found on
``http://localhost:8000/webclient``. For now it's best to follow the
procedure suggested in the previous section if you want to customize it.

View file

@ -0,0 +1,127 @@
rtclient protocol
=================
*Note: Most functionality of a webcliebnt implementation is already
added to trunk as of Nov 2010. That implementation does however not use
a custom protocol as suggested below. Rather it parses telnet-formatted
ansi text and converts it to html. Custom client operations (such as
opening windows or other features not relevant to telnet or other
protocols) should instead eb handled by a second "data" object being
passed to the server through the msg() method.*
rtclient is an extended and bastardized telnet protocol that processes
html and javascript embedded in the telnet session.
rtclient is implemented by the Teltola client, a web-based html/js
telnet client that is being integrated with Evennia and is written in
twisted/python.
There are two principle aspects to the rtclient protocol, mode control
and buffering.
modes
-----
Unencoded Mode
~~~~~~~~~~~~~~
All output is buffered until ascii char 10, 13, or 255 is encountered or
the mode changes or no output has been added to the buffer in the last
1/10th second and the buffer is not blank. When this occurs, the client
interprets the entire buffer as plain text and flushes the buffer.
HTML Mode
~~~~~~~~~
All output is buffered. When the mode changes, the client then parses
the entire buffer as HTML.
Javascript Mode
~~~~~~~~~~~~~~~
All output is buffered. When the mode changes, the client then parses
the entire buffer as Javascript.
Sample Sessions
---------------
# start html mode, send html, force buffer flush
::
session.msg(chr(240) + "<h1>Test</h1>" + chr(242) + chr(244))
# same as above, but realize that msg sends end-of-line # automatically
thus sending the buffer via AUTO\_CHNK
::
session.msg(chr(240) + "<h1>Test</h1>" + chr(242))
# more elaborate example sending javascript, html, and unbuffered text #
note we are using the tokens imported instead of the constants
::
from game.gamesrc.teltola.RTClient import HTML_TOKEN, JAVASCRIPT_TOKEN, UNENCODED_TOKEN
hello_world_js = "alert('hello world');"
welcome_html = "<h1>Hello World</h1>"
session.msg("".join([JAVASCRIPT_TOKEN, hello_world_js, HTML_TOKEN, welcome_html, UNENCODED_TOKEN,"Hello there."]))
::
session.msg(chr(243))
session.msg(my_text_with_line_breaks)
session.msg(chr(244))
Values of Tokens
----------------
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| chr() value \| name \| function |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 240 \| HTMLTOKEN \| lets client know it is about to receive HTML |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 241 \| JAVASCRIPTTOKEN \| lets client know it is about to receive javascript |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 242 \| UNENCODEDTOKEN \| lets client know it is about to receive plain telnet text |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 243 \| NOAUTOCHUNKTOKEN \| applies to unencoded mode only, prevents the chunking of text at end-of-line characters so that only mode changes force the buffer to be sent to the client |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 244 \| AUTOCHUNKTOKEN \| applies to unencoded mode only, enables automatic chunking of text by end-of-line characters and by non-blank buffers not having been written to in the last 1/10th second |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
identifying as an rtclient
--------------------------
rtclients send the text rtclient\\n immediately after connection so that
the server may enable rtclient extensions
Buffering Control
-----------------
Unbuffered output is not supported. There are two different buffering
methods supported. The default method is called AUTOCHUNK and applies
only to unencoded data (see data encoding section below). JAVASCRIPT and
HTML data is always treated as NO\_AUTOCHUNK.
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
flush.
AUTOCHUNK
~~~~~~~~~
It sends the buffer to the client as unencoded text whenever one of two
things happen: \* the buffer is non-blank but hasn't had anything added
to it very recently (about 1/10th of a second) \* the buffer ends with
an end-of-line character (10, 13, 255)
Autochunking strips end-of-line characters and the client adds in its
own EOL! If you would like to preserve them, send them from within
NO\_AUTOCHUNK.

View file

@ -0,0 +1,294 @@
Workshop: Default-game whitepage
<wiki:toc max\_depth
"3" />
======
Introduction =
This is an initiative to create a "base" game system to be shipped with
Evennia in a "contrib" folder. The game is an independent
re-implementation of the basic stuff of the
`SMAUG <http://www.smaug.org>`_ system. No code from the original will
be used, and no licensed content will be included in the release. For
easy testing of content, rcaskey's SMAUG importer will be used.
TODO, first prototype
=====================
The first stage serves to establish a prototype implementation -
something that shows the parts hanging together, but with only a subset
of the functionality.
Create custom `TypeClasses <Objects.html>`_ supporting the SMAUG system:
- Object->!SmaugObject->!SmaugBeing->!SmaugCharacter,Character
- Object->!SmaugObject->!SmaugBeing->!SmaugMob-> ...
- Object->!SmaugObject->!SmaugThing-> ...
Create limited subclasses or attributes on objects
- Limited classes/races (1-2?)
- Skills (<lvl 5?) - not too many!
Behind-the-scenes SMAUG engine
- Contest resolution
- Mobs moving around, "AI"
- Base combat system
Import of small data set, testing.
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 |
+-------+---------------------------+
+ the affects they apply float, sneak, hide, detect invisibility, detect
magic, detect evil, invisibility

View file

@ -0,0 +1,64 @@
#! /usr/bin/python
#
# Auto-generate reST documentation for Sphinx from Evennia source
# code.
#
# Uses etinenned's sphinx autopackage script. Install it to folder
# "autogen" in this same directory:
#
# hg clone https://bitbucket.org/etienned/sphinx-autopackage-script autogen
#
# Create a directory tree "code/" containing one directory for every
# package in the PACKAGE dictionary below. Make sure EVENNIA_DIR
# points to an Evennia root dir. Then just run this script. A new
# folder sphinx/source/code will be created with the reST sources.
#
# Note - this is not working very well at the moment, not all sources
# seems to be properly detected and you get lots of errors when
# compiling. To nevertheless make a link to the code from the doc
# front page, edit docs/sphinx/sources/index.rst to reference
# code/modules.
#
import os, subprocess, shutil
EVENNIA_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
SPHINX_DIR = os.path.join(os.path.join(EVENNIA_DIR, "docs"), "sphinx")
SPHINX_SRC_DIR = os.path.join(SPHINX_DIR, "source")
SPHINX_CODE_DIR = os.path.join(SPHINX_SRC_DIR, "code")
CONVERT_DIR = os.path.join(SPHINX_DIR, 'src2rest')
AUTOGEN_EXE = os.path.join(CONVERT_DIR, os.path.join("autogen", "generate_modules.py"))
def src2rest():
"""
Run import
"""
try:
shutil.rmtree(SPHINX_CODE_DIR)
print "Emptied old %s." % SPHINX_CODE_DIR
except OSError:
pass
os.mkdir(SPHINX_CODE_DIR)
inpath = EVENNIA_DIR
outpath = SPHINX_CODE_DIR
excludes = [r".*/migrations/.*", r"evennia\.py$", r"manage\.py$",
r"runner\.py$", r"server.py$", r"portal.py$"]
subprocess.call(["python", AUTOGEN_EXE,
"-n", "Evennia",
"-d", outpath,
"-s", "rst",
"-f",
inpath] + excludes)
if __name__ == '__main__':
try:
src2rest()
except Exception, e:
print e
print "Make sure to read the header of this file so that it's properly set up."

View file

@ -0,0 +1,109 @@
#! /usr/bin/python
#
# Converts Evennia's google-style wiki pages to reST documents
#
# Setting up to run:
#
# 1) From this directory, use SVN to download wiki2html converter by Chris Roos. Make sure
# to download into a directory "wiki2html" like this:
#
# svn co http://chrisroos.googlecode.com/svn/trunk/google-wiki-syntax wiki2html
#
# This is a ruby program! Sorry, it was the best match I could find to do this.
# So if you don't have ruby, you need that too.
#
# 2) Install pandoc:
#
# apt-get install pandoc (debian)
# or download from
# http://johnmacfarlane.net/pandoc/
#
# 3) Retrieve wiki files (*.wiki) from Google code by mercurial. Make sure
# to retrieve them into a directory wikiconvert/wiki:
#
# hg clone https://code.google.com/p/evennia/wiki wiki
#
# 4) Check so that you have the following file structure:
#
# wiki/ (containing google code wiki files)
# wiki2html/ (containing the wiki_converter.rb ruby program.)
# html/ (empty)
# rest/ (empty)
# (this file)
#
# Usage:
#
# 1) Pull the wiki files into wiki/ so you have the latest.
# 2) Run wiki2rest.py. Folders html and rest will end up containing the conversions and the contents
# of rest/ will automatically be copied over to docs/sphinx/source/wiki.
#
import sys, os, subprocess, re
# Setup
EVENNIA_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
SPHINX_DIR = os.path.join(os.path.join(EVENNIA_DIR, "docs"), "sphinx")
SPHINX_SRC_DIR = os.path.join(SPHINX_DIR, "source")
SPHINX_WIKI_DIR = os.path.join(SPHINX_SRC_DIR, "wiki")
CONVERT_DIR = os.path.join(SPHINX_DIR, "wiki2rest")
WIKI_DIR = os.path.join(CONVERT_DIR, "wiki")
HTML_DIR = os.path.join(CONVERT_DIR, "html")
REST_DIR = os.path.join(CONVERT_DIR, "rest")
WIKI2HTML_DIR = os.path.join(CONVERT_DIR, "wiki2html")
PANDOC_EXE = "pandoc"
RUBY_EXE = "ruby"
# files to not convert (no file ending)
NO_CONVERT = ["SideBar", "Screenshot"]
def wiki2rest():
"""
Convert from wikifile to rst file, going through html
"""
# convert from wikifile to html with wiki2html
subprocess.call([RUBY_EXE, "wiki_convertor.rb", WIKI_DIR, HTML_DIR], cwd=WIKI2HTML_DIR)
# convert from html to rest with pandoc
htmlfilenames = [fn for fn in os.listdir(HTML_DIR)
if fn.endswith(".html") and not re.sub(r".html", "", fn) in NO_CONVERT]
for filename in htmlfilenames:
htmlfilename = os.path.join(HTML_DIR, filename)
string = "".join(open(htmlfilename, 'r').readlines())
string = re.sub(r'<p class="summary">[A-Za-z0-9 ]*</p>', "", string)
string = re.sub(r"&lt;wiki:toc max_depth=&quot;[0-9]&quot; /&gt;", "", string)
string = re.sub(r"<p>#settings Featured</p>", "", string)
#string = re.sub(r'&lt;wiki:comment&gt;[<>;a-zA\/\n-&Z0-9 ]*&lt;/wiki:comment&gt;', "", string)
f = open(htmlfilename, 'w')
f.write(string)
f.close()
rstfilename = os.path.join(REST_DIR, re.sub(r".html$", ".rst", filename))
print "pandoc: converting %s -> %s" % (htmlfilename, rstfilename)
subprocess.call([PANDOC_EXE, "--from=html", "--to=rst", "-o", rstfilename, htmlfilename])
if __name__ == "__main__":
try:
wiki2rest()
except Exception, e:
print e
print "Make sure to read this file's header to make sure everything is correctly set up. "
sys.exit()
import shutil
try:
shutil.rmtree(SPHINX_WIKI_DIR)
print "Deleted old %s." % SPHINX_WIKI_DIR
except OSError:
pass
print "Copying %s -> %s" % (REST_DIR, SPHINX_WIKI_DIR)
shutil.copytree(REST_DIR, SPHINX_WIKI_DIR)