diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst index 767861fccc..3309593025 100644 --- a/docs/sphinx/source/index.rst +++ b/docs/sphinx/source/index.rst @@ -46,7 +46,6 @@ intervals. wiki/StartStopReload wiki/UpdatingYourGame wiki/Internationalization - wiki/StaffVersionControl wiki/ApacheConfig wiki/TextEncodings wiki/IRC @@ -65,7 +64,6 @@ intervals. wiki/Licensing wiki/Contributing wiki/UsingMUXAsAStandard - wiki/BazaarDevel wiki/DirectoryOverview wiki/PortalAndServer wiki/Commands @@ -88,3 +86,19 @@ intervals. wiki/WorkshopDefaultGame wiki/Workshop wiki/EvenniaDevel + wiki/Banning + wiki/CodingIntroduction + wiki/CodingUtils + wiki/CommandCooldown + wiki/GamePlanning + wiki/GettingHelp + wiki/OnlineSetup + wiki/Quirks + wiki/RSS + wiki/ServerConf + wiki/TickerScripts + wiki/Tutorials + wiki/VersionControl + wiki/Zones + wiki/evAPI + wiki/AddingCommandTutorial diff --git a/docs/sphinx/source/wiki/AdminDocs.rst b/docs/sphinx/source/wiki/AdminDocs.rst index fe33ed8261..dbaa82dd73 100644 --- a/docs/sphinx/source/wiki/AdminDocs.rst +++ b/docs/sphinx/source/wiki/AdminDocs.rst @@ -27,7 +27,7 @@ Customizing the server Administrating the running game ------------------------------- -- `Banning `_ Banning and deleting users +- `Banning `_ and deleting users Working with Evennia -------------------- diff --git a/docs/sphinx/source/wiki/ApacheConfig.rst b/docs/sphinx/source/wiki/ApacheConfig.rst index c2bbef66cd..c634a8c4a5 100644 --- a/docs/sphinx/source/wiki/ApacheConfig.rst +++ b/docs/sphinx/source/wiki/ApacheConfig.rst @@ -16,7 +16,7 @@ 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 ----------- @@ -29,7 +29,7 @@ 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 --------------- @@ -37,9 +37,9 @@ mod\_wsgi Setup Install mod\_wsgi ~~~~~~~~~~~~~~~~~ -mod\ *wsgi is an excellent, secure, and high-performance way to serve +mod\_wsgi is an excellent, secure, and high-performance way to serve Python projects. Code reloading is a breeze, Python modules are executed -as a user of your choice (which is a great security win), and mod*\ wsgi +as a user of your choice (which is a great security win), and mod\_wsgi is easy to set up on most distributions. For the sake of brevity, this guide will refer you to mod\_wsgi's @@ -50,10 +50,10 @@ Ubuntu, you may install the entire stack with the following command: ``sudo aptitude install libapache2-mod-wsgi`` -This should install apache2 (if it isn't already), mod\ *wsgi, and load +This should install apache2 (if it isn't already), mod\_wsgi, and load the module. On Fedora or CentOS, you'll do this with ``yum`` and a similar package name that you'll need to search for. On Windows, you'll -need to download and install apache2 and mod*\ wsgi binaries. +need to download and install apache2 and mod\_wsgi binaries. Copy and modify the VHOST ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -88,8 +88,8 @@ site `_. 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 +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 @@ -114,5 +114,8 @@ are trouble. :: - /evennia/game/web"> Options +ExecCGI Allow from all + /evennia/game/web"> + Options +ExecCGI + Allow from all + diff --git a/docs/sphinx/source/wiki/AsyncProcess.rst b/docs/sphinx/source/wiki/AsyncProcess.rst index dd1e5ba6af..8c5fc859ce 100644 --- a/docs/sphinx/source/wiki/AsyncProcess.rst +++ b/docs/sphinx/source/wiki/AsyncProcess.rst @@ -1,3 +1,5 @@ +Running code asynchronously + Asynchronous code ================= @@ -17,7 +19,9 @@ Consider this piece of code: :: - print "before call ..." long_running_function() print "after call ..." + 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 @@ -43,7 +47,10 @@ use of the ``run_async()`` function in ``src/utils/utils.py``. :: - from ev import utils print "before call ..." utils.run_async(long_running_function) print "after call ..." + from ev import utils + print "before call ..." + utils.run_async(long_running_function) + print "after call ..." Now, when running this you will find that the program will not wait around for ``long_running_function`` to finish. Infact you will see @@ -72,9 +79,10 @@ called automatically. argument ``r`` will then be the return value of that function (or ``None``). Example: -:: + :: - def at_return(r): print r + 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 @@ -83,17 +91,37 @@ called automatically. 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) + def at_err(e): + print "There was an error:", str(e) An example of making an asynchronous call from inside a `Command `_ definition: :: - from ev import utils from game.gamesrc.commands.basecommand import Command class CmdAsync(Command): key = "asynccommand" def func(self): def long_running_function(): #[... lots of time-consuming code return final_value def at_return(r): self.caller.msg("The final value is %s" % r) def at_err(e): self.caller.msg("There was an error: %s" % e) # do the async call, setting all callbacks utils.run_async(long_running_function, at_return, at_err) + from ev import utils + from game.gamesrc.commands.basecommand import Command + + class CmdAsync(Command): + + key = "asynccommand" + + def func(self): + + def long_running_function(): + #[... lots of time-consuming code + return final_value + + def at_return(r): + self.caller.msg("The final value is %s" % r) + + def at_err(e): + self.caller.msg("There was an error: %s" % e) + + # do the async call, setting all callbacks + utils.run_async(long_running_function, at_return, at_err) That's it - from here on we can forget about ``long_running_function`` and go on with what else need to be done. *Whenever* it finishes, the diff --git a/docs/sphinx/source/wiki/Attributes.rst b/docs/sphinx/source/wiki/Attributes.rst index 452a5e997f..3f3646a1f9 100644 --- a/docs/sphinx/source/wiki/Attributes.rst +++ b/docs/sphinx/source/wiki/Attributes.rst @@ -1,3 +1,5 @@ +Using attributes to store data + Attributes ========== @@ -24,12 +26,15 @@ Saving and Retrieving data -------------------------- To save persistent data on a Typeclassed object you normally use the -``db`` (!DataBase) operator. Let's try to save some data to a *Rose* (an +``db`` (DataBase) operator. Let's try to save some data to a *Rose* (an `Object `_): :: - # saving rose.db.has_thorns = True # getting it back is_ouch = rose.db.has_thorns + # saving + rose.db.has_thorns = True + # getting it back + is_ouch = rose.db.has_thorns This looks like any normal Python assignment, but that ``db`` makes sure that an *Attribute* is created behind the scenes and is stored in the @@ -37,12 +42,15 @@ database. Your rose will continue to have thorns throughout the life of the server now, until you deliberately remove them. To be sure to save **non-persistently**, i.e. to make sure NOT to create -a database entry, you use ``ndb`` (!NonDataBase). It works in the same +a database entry, you use ``ndb`` (NonDataBase). It works in the same way: :: - # saving rose.ndb.has_thorns = True # getting it back is_ouch = rose.ndb.has_thorns + # saving + rose.ndb.has_thorns = True + # getting it back + is_ouch = rose.ndb.has_thorns Strictly speaking, ``ndb`` has nothing to do with ``Attributes``, despite how similar they look. No ``Attribute`` object is created behind @@ -62,7 +70,8 @@ properties. :: - list_of_all_rose_attributes = rose.db.all list_of_all_rose_ndb_attrs = rose.ndb.all + list_of_all_rose_attributes = rose.db.all + list_of_all_rose_ndb_attrs = rose.ndb.all If you use ``all`` as the name of an attribute, this will be used instead. Later deleting your custom ``all`` will return the default @@ -76,7 +85,10 @@ assign Attributes like you would any normal Python property: :: - # saving rose.has_thorns = True # getting it back is_ouch = rose.has_thorns + # saving + rose.has_thorns = True + # getting it back + is_ouch = rose.has_thorns This looks like any normal Python assignment, but calls ``db`` behind the scenes for you. @@ -87,7 +99,9 @@ you know what you are doing, this can cause lots of trouble. :: - rose.msg("hello") # this uses the in-built msg() method rose.msg = "Ouch!" # this OVERLOADS the msg() method with a string rose.msg("hello") # this now a gives traceback! + rose.msg("hello") # this uses the in-built msg() method + rose.msg = "Ouch!" # this OVERLOADS the msg() method with a string + rose.msg("hello") # this now a gives traceback! Overloading ``msg()`` with a string is a very bad idea since Evennia uses this method all the time to send text to you. There are of course @@ -97,7 +111,8 @@ something that works. :: - rose.db.msg = "Ouch" # this stands no risk of overloading msg() rose.msg("hello") # this works as it should + rose.db.msg = "Ouch" # this stands no risk of overloading msg() + rose.msg("hello") # this works as it should So using ``db``/``ndb`` will always do what you expect and is usually the safer bet. It also makes it visually clear at all times when you are @@ -178,20 +193,46 @@ Examples of valid attribute data: :: - # a single value obj.db.test1 = 23 obj.db.test1 = False # a database object (will be stored as dbref) obj.db.test2 = myobj # a list of objects obj.db.test3 = [obj1, 45, obj2, 67] # a dictionary obj.db.test4 = 'str':34, 'dex':56, 'agi':22, 'int':77 # a mixed dictionary/list obj.db.test5 = 'members': [obj1,obj2,obj3], 'enemies':[obj4,obj5] # a tuple with a list in it obj.db.test6 = (1,3,4,8, ["test", "test2"], 9) # a set will still be stored and returned as a list [1,2,3,4,5]! obj.db.test7 = set([1,2,3,4,5]) # in-situ manipulation obj.db.test8 = [1,2,"test":1] obj.db.test8[0] = 4 obj.db.test8[2]["test"] = 5 # test8 is now [4,2,"test":5] + # a single value + obj.db.test1 = 23 + obj.db.test1 = False + # a database object (will be stored as dbref) + obj.db.test2 = myobj + # a list of objects + obj.db.test3 = [obj1, 45, obj2, 67] + # a dictionary + obj.db.test4 = {'str':34, 'dex':56, 'agi':22, 'int':77} + # a mixed dictionary/list + obj.db.test5 = {'members': [obj1,obj2,obj3], 'enemies':[obj4,obj5]} + # a tuple with a list in it + obj.db.test6 = (1,3,4,8, ["test", "test2"], 9) + # a set will still be stored and returned as a list [1,2,3,4,5]! + obj.db.test7 = set([1,2,3,4,5]) + # in-situ manipulation + obj.db.test8 = [1,2,{"test":1}] + obj.db.test8[0] = 4 + obj.db.test8[2]["test"] = 5 + # test8 is now [4,2,{"test":5}] Example of non-supported save: :: - # this will fool the dbobj-check since myobj (a database object) is "hidden" # inside a custom object. This is unsupported and will lead to unexpected # results! class BadStorage(object): pass bad = BadStorage() bad.dbobj = myobj obj.db.test8 = bad # this will likely lead to a traceback + # this will fool the dbobj-check since myobj (a database object) is "hidden" + # inside a custom object. This is unsupported and will lead to unexpected + # results! + class BadStorage(object): + pass + bad = BadStorage() + bad.dbobj = myobj + obj.db.test8 = bad # this will likely lead to a traceback Retrieving Mutable objects -------------------------- A side effect of the way Evennia stores Attributes is that Python Lists and Dictionaries (only) are handled by custom objects called PackedLists -and !PackedDicts. These behave just like normal lists and dicts except +and PackedDicts. These behave just like normal lists and dicts except they have the special property that they save to the database whenever new data gets assigned to them. This allows you to do things like ``self.db.mylist[4]`` = val without having to extract the mylist @@ -199,13 +240,17 @@ Attribute into a temporary variable first. There is however an important thing to remember. If you retrieve this data into another variable, e.g. ``mylist2 = obj.db.mylist``, your new -variable (``mylist2``) will *still* be a !PackedList! This means it will +variable (``mylist2``) will *still* be a PackedList! This means it will continue to save itself to the database whenever it is updated! This is important to keep in mind so you are not confused by the results. :: - obj.db.mylist = [1,2,3,4] mylist = obj.db.mylist mylist[3] = 5 # this will also update database print mylist # this is now [1,2,3,5] print mylist.db.mylist # this is also [1,2,3,5] + obj.db.mylist = [1,2,3,4] + mylist = obj.db.mylist + mylist[3] = 5 # this will also update database + print mylist # this is now [1,2,3,5] + print mylist.db.mylist # this is also [1,2,3,5] To "disconnect" your extracted mutable variable from the database you simply need to convert the PackedList or PackedDict to a normal Python @@ -216,7 +261,11 @@ structure's connection to the database. :: - obj.db.mylist = [1,2,3,4] mylist = list(obj.db.mylist) # convert to normal list mylist[3] = 5 print mylist # this is now [1,2,3,5] print obj.db.mylist # this remains [1,2,3,4] + obj.db.mylist = [1,2,3,4] + mylist = list(obj.db.mylist) # convert to normal list + mylist[3] = 5 + print mylist # this is now [1,2,3,5] + print obj.db.mylist # this remains [1,2,3,4] Remember, this is only valid for mutable iterables - lists and dicts and combinations of the two. @@ -227,7 +276,14 @@ stop any changes to the structure from updating the database. :: - obj.db.mytup = (1,2,[3,4]) obj.db.mytup[0] = 5 # this fails since tuples are immutable obj.db.mytup[2][1] = 5 # this works but will NOT update database since outermost iterable is a tuple print obj.db.mytup[2][1] # this still returns 4, not 5 mytup1 = obj.db.mytup # mytup1 is already disconnected from database since outermost # iterable is a tuple, so we can edit the internal list as we want # without affecting the database. + obj.db.mytup = (1,2,[3,4]) + obj.db.mytup[0] = 5 # this fails since tuples are immutable + obj.db.mytup[2][1] = 5 # this works but will NOT update database since outermost iterable is a tuple + print obj.db.mytup[2][1] # this still returns 4, not 5 + mytup1 = obj.db.mytup + # mytup1 is already disconnected from database since outermost + # iterable is a tuple, so we can edit the internal list as we want + # without affecting the database. Notes ----- diff --git a/docs/sphinx/source/wiki/BatchCodeProcessor.rst b/docs/sphinx/source/wiki/BatchCodeProcessor.rst index 2cf46c58e5..55f9f6d3fb 100644 --- a/docs/sphinx/source/wiki/BatchCodeProcessor.rst +++ b/docs/sphinx/source/wiki/BatchCodeProcessor.rst @@ -1,3 +1,5 @@ +Using the Evennia batch code processor + The Batch-Code processor ======================== @@ -13,7 +15,7 @@ The batch-command processor is a superuser-only function, invoked by :: - > @batchcode path.to.batchcodefile + > @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 @@ -24,7 +26,7 @@ relative to a folder you define to hold your batch files, set by :: - > @batchcommand examples.batch_code + > @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. @@ -82,7 +84,37 @@ Below is a version of the example file found in # # This is an example batch-code build file for Evennia. - ##HEADER# This will be included in all other #CODE blocksfrom src.utils import create, search from game.gamesrc.objects.examples import red_button from game.gamesrc.objects import baseobjectslimbo = search.objects(caller, 'Limbo', global_search=True)[0]#CODE (create red button)red_button = create.create_object(red_button.RedButton, key="Red button", location=limbo, aliases=["button"])# caller points to the one running the script caller.msg("A red button was created.")# importing more code from another batch-code file #INSERT examples.batch_code_insert#CODE (create table and chair) table, chairtable = create.create_object(baseobjects.Object, key="Blue Table", location=limbo) chair = create.create_object(baseobjects.Object, key="Blue Chair", location=limbo)string = "A %s and %s were created. If debug was active, they were deleted again." caller.msg(string % (table, chair)) + # + + #HEADER + + # This will be included in all other #CODE blocks + + from src.utils import create, search + from game.gamesrc.objects.examples import red_button + from game.gamesrc.objects import baseobjects + + limbo = search.objects(caller, 'Limbo', global_search=True)[0] + + + #CODE (create red button) + + red_button = create.create_object(red_button.RedButton, key="Red button", + location=limbo, aliases=["button"]) + + # caller points to the one running the script + caller.msg("A red button was created.") + + # importing more code from another batch-code file + #INSERT examples.batch_code_insert + + #CODE (create table and chair) table, chair + + table = 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. @@ -93,7 +125,7 @@ Try to run the example script with :: - > @batchcode/debug examples.batch_code + > @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 @@ -127,13 +159,13 @@ mode. :: - > @batchcode/interactive examples.batch_code + > @batchcode/interactive examples.batch_code You should see the following: :: - 01/02: #CODE (create red button) [...] (hh for help) + 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* @@ -144,7 +176,17 @@ To take a look at the full code snippet you are about to run, use ``ll`` :: - 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.") + from src.utils import create, search + from game.gamesrc.objects.examples import red_button + from game.gamesrc.objects import baseobjects + + limbo = 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 diff --git a/docs/sphinx/source/wiki/BatchCommandProcessor.rst b/docs/sphinx/source/wiki/BatchCommandProcessor.rst index 570f0b55de..5b532097b7 100644 --- a/docs/sphinx/source/wiki/BatchCommandProcessor.rst +++ b/docs/sphinx/source/wiki/BatchCommandProcessor.rst @@ -1,3 +1,5 @@ +Using the Evennia command batch processors + The Batch-Command processor =========================== @@ -13,7 +15,7 @@ The batch-command processor is a superuser-only function, invoked by :: - > @batchcommand path.to.batchcmdfile + > @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 @@ -24,7 +26,7 @@ relative to a folder you define to hold your batch files, set with :: - > @batchcommand examples.batch_cmds + > @batchcommand examples.batch_cmds A batch-command file contains a list of Evennia in-game commands separated by comments. The processor will run the batch file from @@ -75,7 +77,46 @@ Below is a version of the example file found in :: - # # This is an example batch build file for Evennia. ## This creates a red button @create button:examples.red_button.RedButton # (This comment ends input for @create) # Next command. Let's create something. @set button/desc = This is a large red button. Now and then it flashes in an evil, yet strangely tantalizing way. A big sign sits next to it. It says:----------- Press me! ----------- ... It really begs to be pressed! You know you want to! # This inserts the commands from another batch-cmd file named # batch_insert_file.ev. #INSERT examples.batch_insert_file # (This ends the @set command). Note that single line breaks # and extra whitespace in the argument are ignored. Empty lines # translate into line breaks in the output. # Now let's place the button where it belongs (let's say limbo #2 is # the evil lair in our example) @teleport #2 # (This comments ends the @teleport command.) # Now we drop it so others can see it. # The very last command in the file needs not be ended with #. drop button + # + # This is an example batch build file for Evennia. + # + + # This creates a red button + @create button:examples.red_button.RedButton + # (This comment ends input for @create) + # Next command. Let's create something. + @set button/desc = + This is a large red button. Now and then + it flashes in an evil, yet strangely tantalizing way. + + A big sign sits next to it. It says: + + + ----------- + + Press me! + + ----------- + + + ... It really begs to be pressed! You + know you want to! + + # This inserts the commands from another batch-cmd file named + # batch_insert_file.ev. + #INSERT examples.batch_insert_file + + + # (This ends the @set command). Note that single line breaks + # and extra whitespace in the argument are ignored. Empty lines + # translate into line breaks in the output. + # Now let's place the button where it belongs (let's say limbo #2 is + # the evil lair in our example) + @teleport #2 + # (This comments ends the @teleport command.) + # Now we drop it so others can see it. + # The very last command in the file needs not be ended with #. + drop button To test this, run ``@batchcommand`` on the file. A button will be created, described and dropped in Limbo. All commands will be executed @@ -97,13 +138,13 @@ same-named objects, for example). Use ``@batchcommand`` with the :: - > @batchcommand/interactive examples.batch_cmds + > @batchcommand/interactive examples.batch_cmds You will see this: :: - 01/04: @create button:examples.red_button.RedButton (hh for help) + 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 diff --git a/docs/sphinx/source/wiki/BatchProcessors.rst b/docs/sphinx/source/wiki/BatchProcessors.rst index 2698b56e4b..cb41a9e5e4 100644 --- a/docs/sphinx/source/wiki/BatchProcessors.rst +++ b/docs/sphinx/source/wiki/BatchProcessors.rst @@ -1,3 +1,5 @@ +Introduction to batch processors + Batch Processors - overview =========================== diff --git a/docs/sphinx/source/wiki/BuilderDocs.rst b/docs/sphinx/source/wiki/BuilderDocs.rst index 3ce6cd3c80..3ed748bf42 100644 --- a/docs/sphinx/source/wiki/BuilderDocs.rst +++ b/docs/sphinx/source/wiki/BuilderDocs.rst @@ -15,12 +15,12 @@ Building basics Advanced building and World building ------------------------------------ -`Overview of batch processors `_ +- `Overview of batch processors `_ -- `Batch-command processor `_ -- `Batch-code processor `_ + - `Batch-command processor `_ + - `Batch-code processor `_ -`Adding zones `_ +- `Adding zones `_ The Tutorial world ------------------ diff --git a/docs/sphinx/source/wiki/BuildingPermissions.rst b/docs/sphinx/source/wiki/BuildingPermissions.rst index 98b3626973..0b1c8565eb 100644 --- a/docs/sphinx/source/wiki/BuildingPermissions.rst +++ b/docs/sphinx/source/wiki/BuildingPermissions.rst @@ -1,3 +1,5 @@ +Introduction to setting permissions + Giving permissions to your staff ================================ @@ -32,7 +34,7 @@ as well. By default Evennia creates the following hierarchy: 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 +#. *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. diff --git a/docs/sphinx/source/wiki/BuildingQuickstart.rst b/docs/sphinx/source/wiki/BuildingQuickstart.rst index 8fea9fe55b..94a1fa7539 100644 --- a/docs/sphinx/source/wiki/BuildingQuickstart.rst +++ b/docs/sphinx/source/wiki/BuildingQuickstart.rst @@ -16,7 +16,7 @@ optional parts): :: - command[/switch/switch...] [arguments ...] + 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 @@ -46,7 +46,7 @@ player build rights: :: - @perm Anna = Builders + @perm Anna = Builders You could give the permission "Immortals" instead, if you want to assign full admin privileges. Log out of your superuser account (``@quit``) and @@ -127,7 +127,8 @@ and try to get the box now: :: - > get box You can't get that. + > get box + You can't get that. Think the default error message looks dull? The ``get`` command looks for an `Attribute `_ named ``get_err_msg`` for @@ -137,7 +138,7 @@ attributes using the ``@set`` command: :: - > @set box/get_err_msg = The box is way too heavy for you to lift. + > @set box/get_err_msg = 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. @@ -162,7 +163,7 @@ while and you will notice yourself starting making random observations. :: - > @script self + > @script self This will show details about scripts on yourself (also ``examine`` works). You will see how long it is until it "fires" next. Don't be @@ -320,7 +321,7 @@ command. :: - > @sethelp/add MyTopic = This help topic is about ... + > @sethelp/add MyTopic = This help topic is about ... Adding a World -------------- @@ -330,7 +331,7 @@ need to log back in as *superuser*. Place yourself in Limbo and do: :: - @batchcommand contrib.tutorial_world.build + @batchcommand contrib.tutorial_world.build This will take a while, but you will see a lot of messages as the world is built for you. You will end up with a new exit from Limbo named diff --git a/docs/sphinx/source/wiki/ChoosingAnSQLServer.rst b/docs/sphinx/source/wiki/ChoosingAnSQLServer.rst index ac3f34352c..2fc1993dc9 100644 --- a/docs/sphinx/source/wiki/ChoosingAnSQLServer.rst +++ b/docs/sphinx/source/wiki/ChoosingAnSQLServer.rst @@ -34,9 +34,9 @@ your game has an very large database and/or extensive web presence through a separate server process. **Warning:** Postgres has issues with Evennia on some installs at the -moment. "http://code.google.com/p/evennia/issues/detail?id - -151">Issue 151 outlines this. If unsure, avoid Postgres for now. +moment. `Issue +151 `_ outlines +this. If unsure, avoid Postgres for now. MySQL ----- diff --git a/docs/sphinx/source/wiki/Colours.rst b/docs/sphinx/source/wiki/Colours.rst index 460b6c0af4..a27d1fcd5b 100644 --- a/docs/sphinx/source/wiki/Colours.rst +++ b/docs/sphinx/source/wiki/Colours.rst @@ -1,3 +1,5 @@ +Adding colour + Adding Colour to your game ========================== @@ -26,7 +28,8 @@ mark colour: :: - This is a %crRed text%cn This is normal text again. %cRThis text has red background%cn this is normal text. + 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). @@ -40,16 +43,16 @@ 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: +unreadable code. It is thus often easier to use ``{#`` style codes: :: - This is a rBright red textn This is normal text again + This is a {rBright red text{n This is normal text again -The ``x`` format don't include background colour, it only colours the +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 +``{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. diff --git a/docs/sphinx/source/wiki/CommandPrompt.rst b/docs/sphinx/source/wiki/CommandPrompt.rst index 74e6d274ed..c968022e45 100644 --- a/docs/sphinx/source/wiki/CommandPrompt.rst +++ b/docs/sphinx/source/wiki/CommandPrompt.rst @@ -1,3 +1,5 @@ +Adding a command prompt to your game + Adding a command prompt ======================= @@ -11,11 +13,13 @@ 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: +of the look command, followed by the prompt. As an example:  :: - > look You see nothing special. HP:10, SP:20, MP: 5 + > 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. @@ -31,7 +35,20 @@ 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)) + 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 ----------------------- @@ -41,7 +58,8 @@ return of every command, on the same line: :: - > look HP: 10, SP:20, MP:5 -- You see nothing special. + > 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 @@ -50,20 +68,23 @@ before* the function return: :: - > look HP:10, SP:20, MP: 5 You see nothing special. + > 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 `_ on how to -change the default Character class to your custom one). Now, all -commands use the ``object.msg()`` method for communicating with the -player. This is defined in ``src/objects/models.py``, on the -``ObjectDB`` base class. This is how the ``msg()`` method is defined: +our *Character class* (see [Objects#Characters here] on how to change +the default Character class to your custom one). Now, all commands use +the ``object.msg()`` method for communicating with the player. This is +defined in ``src/objects/models.py``, on the ``ObjectDB`` base class. +This is how the ``msg()`` method is defined: :: - def msg(self, outgoing_message, from_obj=None, data=None): ... + 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 @@ -74,7 +95,19 @@ 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) + 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 diff --git a/docs/sphinx/source/wiki/Commands.rst b/docs/sphinx/source/wiki/Commands.rst index 81fecc6db6..64c8c7cb45 100644 --- a/docs/sphinx/source/wiki/Commands.rst +++ b/docs/sphinx/source/wiki/Commands.rst @@ -1,3 +1,5 @@ +Details on how to use and extend the command system. + Command system ============== @@ -17,21 +19,24 @@ 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. +class and the *Command Set*. 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. +what a command does - for example, a *get* command would contain code +for picking up 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 *chop -down*. Or a "Clock" with a cmdset containing the single command *check -time*. +A *Command Set* (often referred to as a CmdSet) is like a container for +one or more Commands. A given Command can go into any number of +different command sets. By putting 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 *chop down*. Or a +"Clock" with a cmdset containing the single command *check time*. + +This page goes into full detail about how to use Commands. There is also +a step-by-step `beginner's tutorial `_ that +will get you started quickly without the explanations. Defining a Command ------------------ @@ -53,56 +58,59 @@ class directly. This is the help-text for the command """ key = "mycommand" - locks = "cmd:all()" # this lock means cmd is available to all def parse(self): # parsing the command line here def func(self): - # executing the command here + # executing the command here 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. +creates an instance of this class and uses that instance whenever you +use this command - it also dynamically assigns the new command instance +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: +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 either loads an existing Command instance from cache or +creates one. 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. + is normally the Character\_BigGuy\_, not his Player *Bob* ! If you + want to do something to the player (*Bob*) in your command, do so + through ``caller.player``. (Since cmdsets can be put directly on + Players, caller *can* be a Player object as well, such commands are + usually quite specific though). +- ``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``\ ". + So if the string entered was *look at sword*, ``args`` would be "*at + sword*\ ". - ``obj`` - the game `Object `_ 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 button.py.html>`_ + (default) command, this is probably defined directly on *BigGuy* - so + ``obj`` will point to BigGuy. Otherwise ``obj`` could be a Player or + 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 `_ 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 `_ - (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\_). + (*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*). +- ``raw_string`` - this is the raw input coming from the user, without + stripping any surrounding whitespace. The only thing that is stripped + is the ending newline marker. Defining your own command classes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -111,43 +119,44 @@ Beyond the properties Evennia always assigns to the command at runtime (listed above), your job is to define the following class properties: - ``key`` (string) - the identifier for the command, like ``look``. - This should (ideally) be unique. it can be more than one word long in - a string, like "press button" or "pull lever left". + This should (ideally) be unique. A key can consist of more than one + word, like "press button" or "pull left lever". - ``aliases`` (optional list) - a list of alternate names for the command (``["l", "glance", "see"]``). Same name rules as for ``key`` applies. - ``locks`` (string) - a `lock definition `_, usually on the form ``cmd:``. 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. + ``"cmd:all()"`` to make the command available to everyone (if you + don't put a lock string, this will be assigned for you). - ``help_category`` (optional string) - setting this helps to structure the auto-help into categories. If none is set, this will be set to *General*. - ``save_for_next`` (optional boolean). This defaults to ``False``. If - ``True``, this command object (along with any changes you have done - to it) will be stored by the system and can be accessed by the next - command called by retrieving ``self.caller.ndb.last_cmd``. The next + ``True``, a copy of this command object (along with any changes you + have done to it) will be stored by the system and can be accessed by + the next command by retrieving ``self.caller.ndb.last_cmd``. The next run command will either clear or replace the storage. -- 'arg\ *regex' (optional raw string): This should be given as a `raw +- 'arg\_regex' (optional raw string): This should be given as a `raw regular expression string `_. - This will be compiled by the system at runtime. This allows you to - customize how the part*\ immediately following the command name (or - alias) must look in order for the parser to match for this command. - Normally the parser is highly efficient in picking out the command - name, also as the beginning of a longer word (as long as the longer - word is not a command name in it self). So ``"lookme"`` will be - parsed as the command ``"look"`` followed by the argument ``"me"``. - By using ``arg_regex`` you could for example force the parser to - require an optional space following the command name (regex string - for this would be ``r"\s.*?|$"``). In that case, ``"lookme"`` will - lead to an "command not found" error while ``"look me"`` will work as - expected. -- autohelp (optional boolean). Defaults to ``True``. This allows for - turning off the `auto-help - system Auto-helpsystem.html>`_ on a - per-command basis. This could be useful if you either want to write - your help entries manually or hide the existence of a command from - ``help``'s generated list. + The regex will be compiled by the system at runtime. This allows you + to customize how the part *immediately following* the command name + (or alias) must look in order for the parser to match for this + command. Normally the parser is highly efficient in picking out the + command name, also as the beginning of a longer word (as long as the + longer word is not a command name in it self). So ``"lookme"`` will + be parsed as the command ``"look"`` followed by the argument + ``"me"``. By using ``arg_regex`` you could for example force the + parser to require a space to follow the command name (regex string + for this would be ``r"\s.*?|$"``). In that case, only ``"look me"`` + will work whereas ``"lookme"`` will lead to an "command not found" + error. +- auto\_help (optional boolean). Defaults to ``True``. This allows for + turning off the + [`HelpSystem `_\ #Command\_Auto-help\_system + auto-help system] on a per-command basis. This could be useful if you + either want to write your help entries manually or hide the existence + of a command from ``help``'s generated list. You should also implement at least two methods, ``parse()`` and ``func()`` (You could also implement ``perm()``, but that's not needed @@ -155,9 +164,14 @@ 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. +in variable(s) on the command object itself (i.e. on ``self``). To take +an example, the default mux-like system uses this method to detect +"command switches" and store them as a list in ``self.switches``. Since +the parsing is usually quite similar inside a command scheme you should +make ``parse()`` as generic as possible and then inherit from it rather +than re-implementing it over and over. In this way, the default +``MuxCommand`` class implements a ``parse()`` for all child commands to +use. ``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. @@ -170,11 +184,55 @@ by the `Help system `_ to create the help entry for this command. You should decide on a way to format your help and stick to that. -Below is how you define a simple alternative "``look at``\ " command: +Below is how you define a simple alternative "``smile``\ " command: :: - from ev import Commandclass CmdLookAt(Command): """ An alternative (and silly) look command Usage: look at Where may only be 'here' in this example. This initial string (the __doc__ string) is also used to auto-generate the help for this command ... """ key = "look at" # this is the command name to use aliases = ["la", "look a"] # aliases to the command name locks = "cmd:all()" help_category = "General" def parse(self): "Very trivial parser" self.what = self.args.strip() def func(self): "This actually does things" caller = self.caller if not self.what: caller.msg("Look at what?") elif self.what == 'here': # look at the current location description = caller.location.db.desc caller.msg(description) else: # we don't add any more functionality in this example caller.msg("Sorry, you can only look 'here'...") + from ev import Command + + class CmdSmile(Command): + """ + A smile command + + Usage: + smile [at] [] + grin [at] [] + + Smiles to someone in your vicinity or to the room + in general. + + (This initial string (the __doc__ string) + is also used to auto-generate the help + for this command) + """ + + key = "smile" + aliases = ["smile at", "grin", "grin at"] + locks = "cmd:all()" + help_category = "General" + + def parse(self): + "Very trivial parser" + self.target = self.args.strip() + + def func(self): + "This actually does things" + caller = self.caller + if not self.target or self.target == "here": + string = "%s smiles." % caller.name + caller.location.msg_contents(string, exclude=caller) + caller.msg("You smile.") + else: + target = self.search(self.target) + if not target: + # self.search handles error messages + return + string = "%s smiles to you." % caller.name + target.msg(string) + string = "You smile to %s." % target.name + caller.msg(string) + string = "%s smiles to %s." % (caller.name, target.name) + caller.location.msg_contents(string, exclude=[caller,target]) The power of having commands as classes and to separate ``parse()`` and ``func()`` lies in the ability to inherit functionality without having @@ -185,27 +243,25 @@ 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 `_ and on `Players `_ respectively. +(CmdSets). A particular ``Command`` class definition can be part of any +number of different CmdSets. CmdSets can be stored either on game +`Objects `_ or on `Players `_. When a user issues a command, it is matched against the contents of all -cmdsets available at the time, `merged -together andmergingcommandsets.html>`_. -The currently valid command sets are collected from the following -sources, in this order: +cmdsets available to the user at the moment, +[Commands#Adding\_and\_merging\_command\_sets merged together]. 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 cmdset(s) of objects in the current location (this includes + exits) - The channel commandset - The cmdset defined on the Player object controlling the character (OOC cmdset) @@ -228,19 +284,32 @@ inheriting from the correct parent (``ev.CmdSet`` or ``src.commands.cmdset.CmdSet``). The CmdSet class only needs to define one method, called ``at_cmdset_creation()``. All other class parameters are optional, but are used for more advanced set manipulation and coding -(see the `merge rules `_ section). +(see the [Commands#Merge\_rules merge rules] section). :: - from ev import CmdSet from game.gamesrc.commands import mycommands class MyCmdSet(CmdSet): def at_cmdset_creation(self): """ The only thing this method should need to do is to add commands to the set. """ self.add(mycommands.MyCommand1()) self.add(mycommands.MyCommand2()) self.add(mycommands.MyCommand3()) + from ev import CmdSet + from game.gamesrc.commands import mycommands + class MyCmdSet(CmdSet): + def at_cmdset_creation(self): + """ + The only thing this method should need + to do is to add commands to the set. + """ + self.add(mycommands.MyCommand1()) + self.add(mycommands.MyCommand2()) + self.add(mycommands.MyCommand3()) -The !CmdSet's ``add()`` method can also take another CmdSet as input. In +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 ... + 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 @@ -248,7 +317,7 @@ server aware of the code changes: :: - @reload + @reload You should now be able to use the command. @@ -268,149 +337,18 @@ server, or you run @py self.cmdset.delete('game.gamesrc.commands.mycmdset.MyCmdSet') -For more permanent addition, read the `step-by-step -guide anewcommand-astepbystep_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``. Copy from the templates in ``examples/`` if you - like. -#. Import ``ev.default_cmds`` and access ``MuxCommand`` from that (this - is a convenient shortcut so you don't have to import from src/ - directly). The ``MuxCommand`` class handles command line parsing for - you, giving you stuff like /switches, the syntax using '=' etc). In - other words, you don't have to implement ``parse()`` on your own. -#. Create a new class in ``mycommand`` that inherits from - ``MuxCommand``. -#. Set the class variable ``key`` to the name to call your command with, - say ``mycommand``. -#. Set the ``locks`` property on the command to a suitable - `lockstring locks.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 ev import default_cmdsclass MyCommand(default_cmds.MuxCommand): """ Simple command example Usage: mycommand 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 ``ev.CmdSet``. -#. (Optionally) set a key to name your command set. -#. Add a method ``at_cmdset_creation()`` and use the ``self.add()`` - method to add your command to the command set. - -This is what we have now: - -:: - - from ev import CmdSet - from game.gamesrc.commands import mycommandclass MyCmdSet(CmdSet): key = "MyCmdSet" def at_cmdset_creation(self): self.add(mycommand.MyCommand()) - -This new command set could of course contain any number of commands. We -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 the template in -``gamesrc/commands/examples/`` already shows how to extend it. Copy that -file to ``game/gamesrc/`` and edit ``settings.CMDSET_DEFAULT`` to point -to this class instead. Next you add your new commands to the end of the -Default Cmdset in that file and you will in fact append it to the -existing command set. - -:: - - # file gamesrc/commands/examples/cmdset.py ... from game.gamesrc.commands import mycommandclass DefaultSet(BaseDefaultSet): key = DefaultMUX def at_cmdset_creation(self): # this first adds all default commands super(DefaultSet, self).at_cmdset_creation() # all commands added after this point will extend or # overwrite the default commands. self.add(mycommand.MyCommand()) - -Again, you need to run the ``@reload`` command to make these changes -available. - -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. +For more permanent addition, read the +[Commands#Adding\_a\_new\_command\_-*a\_step\_by\_step\_guide +step-by-step guide] below. Generally you can customize which command +sets are added to your objects by using ``self.cmdset.add()`` or +``self.cmdset.add_default()``.* Adding and merging command sets ------------------------------- -*Note: This is an advanced topic. It's useful to know about, but you +\_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.* +commands. CmdSets have the special ability that they can be *merged* together into new sets. This would happen if you, for example, did @@ -445,7 +383,7 @@ 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 @@ -475,7 +413,8 @@ Same-key commands are merged by priority. :: - # Union A1,A2 + B1,B2,B3,B4 = A1,A2,B3,B4 + # 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 @@ -483,7 +422,8 @@ cmdset replacing the lower one's commands. :: - # Intersect A1,A3,A5 + B1,B2,B4,B5 = A1,A5 + # 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 @@ -491,7 +431,8 @@ exist or not. :: - # Replace A1,A3 + B1,B2,B4,B5 = A1,A3 + # 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 @@ -500,35 +441,50 @@ high-prio one as a template. :: - # Remove A1,A3 + B1,B2,B3,B4,B5 = B2,B4,B5 + # 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 +- *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 +- *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. + 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()) + 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 --------------- @@ -539,7 +495,7 @@ 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? +send a message to? Or if there are multiple command possibilities? 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 @@ -583,7 +539,13 @@ command must be added to a cmdset as well before it will work. :: - from ev import syscmdkeys, Commandclass MyNoInputCommand(Command): "Usage: Just press return, I dare you" key = syscmdkeys.CMD_NOINPUT def func(self): self.caller.msg("Don't just press return like that, talk to me!") + from ev import syscmdkeys, Command + + class MyNoInputCommand(Command): + "Usage: Just press return, I dare you" + key = syscmdkeys.CMD_NOINPUT + def func(self): + self.caller.msg("Don't just press return like that, talk to me!") Exits ----- @@ -618,75 +580,76 @@ 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. +#. 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. + - 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: +#. 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 `_. -- Sets of dynamically created *System commands* representing available - `Channels `_. -- !CmdSet defined on the *caller.player* (OOC cmdset). + - The caller's own currently active CmdSet. + - The active CmdSets of eventual objects in the same location (if + any). This includes commands on [Objects#Exits Exits]. + - Sets of dynamically created *System commands* representing + available `Channels `_. + - CmdSet defined on the *caller.player* (OOC cmdset). -All the CmdSets are *merged* into one combined CmdSet according to each -set's merge rules. +#. 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. -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. + - 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. -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. +#. 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. Assorted notes -------------- -The return value of ``Command.func()`` *is* safely passed on should one -have some very specific use case in mind. So one could in principle do -``value = obj.execute_cmd(cmdname)``. Evennia does not use this -functionality at all by default (all default commands simply returns -``None``) and it's probably not relevant to any but the most -advanced/exotic designs (one might use it to create a "nested" command -structure for example). +The return value of ``Command.func()`` is a Twisted +`deferred `_. +Evennia does not use this return value at all by default. If you do, you +must thus do so asychronously, using callbacks. + +:: + + # in command class func() + def callback(ret, caller): + caller.msg("Returned is %s" % ret) + deferred = self.execute_command("longrunning") + deferred.addCallback(callback, self.caller) + +This is probably not relevant to any but the most advanced/exotic +designs (one might use it to create a "nested" command structure for +example). The ``save_for_next`` class variable can be used to implement state-persistent commands. For example it can make a command operate on diff --git a/docs/sphinx/source/wiki/Communications.rst b/docs/sphinx/source/wiki/Communications.rst index f5504b04fe..974ce04281 100644 --- a/docs/sphinx/source/wiki/Communications.rst +++ b/docs/sphinx/source/wiki/Communications.rst @@ -1,3 +1,5 @@ +Handling of ooc communications in game + Communications ============== @@ -24,7 +26,7 @@ communications, both in channels, but also for allowing senders/receivers to have 'mailboxes' with the messages they want to keep. -Properties defined on ``Msg`` +Properties defined on \`Msg\` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ``sender`` - this is a reference to a unique `Player `_ @@ -36,8 +38,8 @@ Properties defined on ``Msg`` - ``date_sent`` - when message was sent (auto-created). - ``locks`` - a `lock definition `_. -You create new messages in code using -``src.utils.create.create_message.`` +You create new messages in code using ``ev.create_message`` (or +``src.utils.create.create_message.``) !TempMsg ~~~~~~~~ @@ -62,7 +64,8 @@ for asking questions). The default channels created are defined by ``settings.CHANNEL_PUBLIC``, ``settings.CHANNEL_MUDINFO`` and ``settings.CHANNEL_CONNECTINFO``. -You create new channels with ``src.utils.create.create_channel()``. +You create new channels with ``ev.create_message`` (or +``src.utils.create.create_channel``). In code, messages are sent to a channel using the ``msg(message, from_obj=None)`` method. The argument ``message`` can @@ -76,14 +79,25 @@ 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) + # 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 +customize how this works by defining a *system\_command* with your own code. See `Commands `_ for more details. -Properties defined on ``Channel`` +Properties defined on \`Channel\` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ``key`` - main name for channel diff --git a/docs/sphinx/source/wiki/ConnectionScreen.rst b/docs/sphinx/source/wiki/ConnectionScreen.rst index 2bf1ea3bda..5d46bceebb 100644 --- a/docs/sphinx/source/wiki/ConnectionScreen.rst +++ b/docs/sphinx/source/wiki/ConnectionScreen.rst @@ -1,3 +1,5 @@ +Customizing the connection screen + The Connection Screen ===================== @@ -8,7 +10,15 @@ tells you how to connect. :: ============================================================== - Welcome to Evennia, version HG-Alpha! If you have an existing account, connect to it by typing: connect If you need to create an account, type (without the <>'s): create "" Enter help for more info. look will re-show this screen. ============================================================== + Welcome to Evennia, version HG-Beta! + + If you have an existing account, connect to it by typing: + connect + If you need to create an account, type (without the <>'s): + create "" + + Enter help for more info. look will re-show this screen. + ============================================================== Effective, but not very exciting. You will most likely want to change this to be more unique for your game. diff --git a/docs/sphinx/source/wiki/Contributing.rst b/docs/sphinx/source/wiki/Contributing.rst index 243e8cc67d..8b80555996 100644 --- a/docs/sphinx/source/wiki/Contributing.rst +++ b/docs/sphinx/source/wiki/Contributing.rst @@ -1,3 +1,5 @@ +Contributing + Contributing to Evennia ======================= @@ -12,9 +14,8 @@ typos is a great help. To edit the wiki yourself you need contributor access. Otherwise, it goes a long way just pointing out wiki errors so devs can fix them (in an Issue or just over chat/forum). You can also commit wiki changes over Mercurial - just go to the wiki repository -"http://code.google.com/p/evennia/source/checkout?repo - -wiki">here and then continue from point ``2`` below. +`here `_ and +then continue from point ``2`` below. Contributing with Code through a clone repository ------------------------------------------------- @@ -37,8 +38,8 @@ do this once): something useful, like "Johns-evennia-fixes". Give a brief summary, like "my repo for contributing to Evennia". Accept. #. Your new repo is created. You should see it appear in the `clone-repo - list `_. This - is actually your own mini-version of the Evennia page! + list `_. This is + actually your own mini-version of the Evennia page! #. Choose your repo and you will find it has its own Checkout page. Use the command shown there to get a local copy of your clone to your computer. @@ -61,7 +62,9 @@ Once you have an online clone and a local copy of it: 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. +deemed good, pick and merge your work into Evennia proper. Mercurial +will automatically make sure you get proper credit for your contribution +in the source code history. Contributing with Patches ------------------------- @@ -69,21 +72,20 @@ Contributing with Patches To help with Evennia development it's recommended to do so using a clone repository as described above. But for small, well isolated fixes you are also welcome to submit your suggested Evennia fixes/addendums as -*patches*. You can use normal -`patches `_, +*patches*. You can use `normal +patches `_, but it might be easier to use mercurial's own patch mechanism. Make sure you have committed your latest fixes first, then :: - hg export tip > mypatch.patch + hg export tip > mypatch.patch This will create a patch file ``mypatch.patch`` that can be imported by others with ``hg import mypatch.patch``. Depending on what fits best, post your patch to the `issue -tracker `_ or to the -`discussion -forum `_. Please -avoid pasting the full patch text directly in your post though, best is -to use a site like `Pastebin `_ and just supply -the link. +tracker `_ or to the +`discussion forum `_. +Please avoid pasting the full patch text directly in your post though, +best is to use a site like `Pastebin `_ and just +supply the link. diff --git a/docs/sphinx/source/wiki/DefaultCommandHelp.rst b/docs/sphinx/source/wiki/DefaultCommandHelp.rst index e547956ff9..afe84794f6 100644 --- a/docs/sphinx/source/wiki/DefaultCommandHelp.rst +++ b/docs/sphinx/source/wiki/DefaultCommandHelp.rst @@ -11,9 +11,9 @@ usually match a module in ``src/commands/default``. So for example, the code for a command in the "General" category is most likely to be found in ``src/commands/default/general.py``. -The commands that make up the default `command -set `_ are divided into three sub-sets after -which objects they are defined on. +The commands that make up the default [Commands#Command\_Sets command +set] are divided into three sub-sets after which objects they are +defined on. - An *OOC Command* is a command in the OOCCmdset, available only on Players, not on Objects/Characters. Since Players control Characters, @@ -23,7 +23,7 @@ which objects they are defined on. Same-keyed command on the Character has higher priority than its OOC equivalent, allowing to overload the OOC commands on a per-Character basis. -- An *Unloggedin Command* sits in !UnloggedinCmdset. They are specific +- An *Unloggedin Command* sits in UnloggedinCmdset. They are specific to the login screen, before the session (User) has authenticated. - All other commands are *On-Character* commands, commands defined in DefaultCmdset and available in the game. @@ -37,7 +37,7 @@ Admin ----- `Link to Python -module `_ +module `_ @ban ~~~~ @@ -45,13 +45,45 @@ module `_ = ``cmd:perm(ban) or perm(Immortals)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - ban a player from the server Usage: @ban [ [: reason]] Without any arguments, shows numbered list of active bans. This command bans a user from accessing the game. Supply an optional reason to be able to later remember why the ban was put in place It is often to prefer over deleting a player with @delplayer. If banned by name, that player account can no longer be logged into. IP (Internet Protocol) address banning allows to block all access from a specific address or subnet. Use the asterisk (*) as a wildcard. Examples: @ban thomas - ban account 'thomas' @ban/ip 134.233.2.111 - ban specific ip address @ban/ip 134.233.2.* - ban all in a subnet @ban/ip 134.233.*.* - even wider ban A single IP filter is easy to circumvent by changing the computer (also, some ISPs assign only temporary IPs to their users in the first placer. Widening the IP block filter with wildcards might be tempting, but remember that blocking too much may accidentally also block innocent users connecting from the same country and region. + ban a player from the server + + Usage: + @ban [ [: reason]] + + Without any arguments, shows numbered list of active bans. + + This command bans a user from accessing the game. Supply an + optional reason to be able to later remember why the ban was put in + place + + It is often to + prefer over deleting a player with @delplayer. If banned by name, + that player account can no longer be logged into. + + IP (Internet Protocol) address banning allows to block all access + from a specific address or subnet. Use the asterisk (*) as a + wildcard. + + Examples: + @ban thomas - ban account 'thomas' + @ban/ip 134.233.2.111 - ban specific ip address + @ban/ip 134.233.2.* - ban all in a subnet + @ban/ip 134.233.*.* - even wider ban + + A single IP filter is easy to circumvent by changing the computer + (also, some ISPs assign only temporary IPs to their users in the + first placer. Widening the IP block filter with wildcards might be + tempting, but remember that blocking too much may accidentally + also block innocent users connecting from the same country and + region. + + @boot ~~~~~ @@ -59,13 +91,24 @@ module `` - `locks `_ = ``cmd:perm(boot) or perm(Wizards)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @boot Usage @boot[/switches] [: reason] Switches: quiet - Silently boot without informing player port - boot by port number instead of name or dbref Boot a player object from the server. If a reason is supplied it will be echoed to the user unless /quiet is set. + @boot + + Usage + @boot[/switches] [: reason] + + Switches: + quiet - Silently boot without informing player + port - boot by port number instead of name or dbref + + Boot a player object from the server. If a reason is + supplied it will be echoed to the user unless /quiet is set. + @delplayer (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -73,13 +116,24 @@ module `` - `locks `_ = ``cmd:perm(delplayer) or perm(Immortals)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - delplayer - delete player from server Usage: @delplayer[/switch] [: reason] Switch: delobj - also delete the player's currently assigned in-game object. Completely deletes a user from the server database, making their nick and e-mail again available. + delplayer - delete player from server + + Usage: + @delplayer[/switch] [: reason] + + Switch: + delobj - also delete the player's currently + assigned in-game object. + + Completely deletes a user from the server database, + making their nick and e-mail again available. + @emit ~~~~~ @@ -87,13 +141,30 @@ module `_ = ``cmd:perm(emit) or perm(Builders)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @emit Usage: @emit[/switches] [, , ... =] @remit [, , ... =] @pemit [, , ... =] Switches: room : limit emits to rooms only (default) players : limit emits to players only contents : send to the contents of matched objects too Emits a message to the selected objects or to your immediate surroundings. If the object is a room, send to its contents. @remit and @pemit are just limited forms of @emit, for sending to rooms and to players respectively. + @emit + + Usage: + @emit[/switches] [, , ... =] + @remit [, , ... =] + @pemit [, , ... =] + + Switches: + room : limit emits to rooms only (default) + players : limit emits to players only + contents : send to the contents of matched objects too + + Emits a message to the selected objects or to + your immediate surroundings. If the object is a room, + send to its contents. @remit and @pemit are just + limited forms of @emit, for sending to rooms and + to players respectively. + @perm ~~~~~ @@ -101,13 +172,25 @@ module `_ = ``cmd:perm(perm) or perm(Immortals)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @perm - set permissions Usage: @perm[/switch] [= [,,...]] @perm[/switch] * [= [,,...]] Switches: del : delete the given permission from or . player : set permission on a player (same as adding * to name) This command sets/clears individual permission strings on an object or player. If no permission is given, list all permissions on . + @perm - set permissions + + Usage: + @perm[/switch] [= [,,...]] + @perm[/switch] * [= [,,...]] + + Switches: + del : delete the given permission from or . + player : set permission on a player (same as adding * to name) + + This command sets/clears individual permission strings on an object + or player. If no permission is given, list all permissions on . + @unban ~~~~~~ @@ -115,13 +198,23 @@ module `` - `locks `_ = ``cmd:perm(unban) or perm(Immortals)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - remove a ban Usage: @unban This will clear a player name/ip ban previously set with the @ban command. Use this command without an argument to view a numbered list of bans. Use the numbers in this list to select which one to unban. + remove a ban + + Usage: + @unban + + This will clear a player name/ip ban previously set with the @ban + command. Use this command without an argument to view a numbered + list of bans. Use the numbers in this list to select which one to + unban. + + @userpassword (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -129,13 +222,19 @@ module `` - `locks `_ = ``cmd:perm(newpassword) or perm(Wizards)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @setpassword Usage: @userpassword = Set a player's password. + @setpassword + + Usage: + @userpassword = + + Set a player's password. + @wall ~~~~~ @@ -143,19 +242,25 @@ module `` - `locks `_ = ``cmd:perm(wall) or perm(Wizards)`` -- `helpcategory `_ = ``Admin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Admin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @wall Usage: @wall Announces a message to all connected players. + @wall + + Usage: + @wall + + Announces a message to all connected players. + Building -------- `Link to Python -module `_ +module `_ @alias ~~~~~~ @@ -163,13 +268,24 @@ module `_ = ``cmd:perm(setobjalias) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Adding permanent aliases Usage: @alias [= [alias[,alias,alias,...]]] Assigns aliases to an object so it can be referenced by more than one name. Assign empty to remove all aliases from object. Observe that this is not the same thing as aliases created with the 'alias' command! Aliases set with @alias are changing the object in question, making those aliases usable by everyone. + Adding permanent aliases + + Usage: + @alias [= [alias[,alias,alias,...]]] + + Assigns aliases to an object so it can be referenced by more + than one name. Assign empty to remove all aliases from object. + Observe that this is not the same thing as aliases + created with the 'alias' command! Aliases set with @alias are + changing the object in question, making those aliases usable + by everyone. + @batchcode ~~~~~~~~~~ @@ -177,13 +293,29 @@ module `_ = ``cmd:superuser()`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Build from batch-code file Usage: @batchcode[/interactive] Switch: interactive - this mode will offer more control when executing the batch file, like stepping, skipping, reloading etc. debug - auto-delete all objects that has been marked as deletable in the script file (see example files for syntax). This is useful so as to to not leave multiple object copies behind when testing out the script. Runs batches of commands from a batch-code text file (*.py). + Build from batch-code file + + Usage: + @batchcode[/interactive] + + Switch: + interactive - this mode will offer more control when + executing the batch file, like stepping, + skipping, reloading etc. + debug - auto-delete all objects that has been marked as + deletable in the script file (see example files for + syntax). This is useful so as to to not leave multiple + object copies behind when testing out the script. + + Runs batches of commands from a batch-code text file (*.py). + + @batchcommands ~~~~~~~~~~~~~~ @@ -191,13 +323,25 @@ module `_ = ``cmd:perm(batchcommands) or superuser()`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Build from batch-command file Usage: @batchcommands[/interactive] Switch: interactive - this mode will offer more control when executing the batch file, like stepping, skipping, reloading etc. Runs batches of commands from a batch-cmd text file (*.ev). + Build from batch-command file + + Usage: + @batchcommands[/interactive] + + Switch: + interactive - this mode will offer more control when + executing the batch file, like stepping, + skipping, reloading etc. + + Runs batches of commands from a batch-cmd text file (*.ev). + + @cmdsets ~~~~~~~~ @@ -205,13 +349,20 @@ module `_ = ``cmd:perm(listcmdsets) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - list command sets on an object Usage: @cmdsets [obj] This displays all cmdsets assigned to a user. Defaults to yourself. + list command sets on an object + + Usage: + @cmdsets [obj] + + This displays all cmdsets assigned + to a user. Defaults to yourself. + @copy ~~~~~ @@ -219,13 +370,25 @@ module `` - `locks `_ = ``cmd:perm(copy) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @copy - copy objects Usage: @copy[/reset] [= new_name][;alias;alias..][:new_location] [,new_name2 ...] switch: reset - make a 'clean' copy off the object, thus removing any changes that might have been made to the original since it was first created. Create one or more copies of an object. If you don't supply any targets, one exact copy of the original object will be created with the name *_copy. + @copy - copy objects + + Usage: + @copy[/reset] [= new_name][;alias;alias..][:new_location] [,new_name2 ...] + + switch: + reset - make a 'clean' copy off the object, thus + removing any changes that might have been made to the original + since it was first created. + + Create one or more copies of an object. If you don't supply any targets, one exact copy + of the original object will be created with the name *_copy. + @cpattr ~~~~~~~ @@ -233,13 +396,32 @@ module `` - `locks `_ = ``cmd:perm(cpattr) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cpattr - copy attributes Usage: @cpattr[/switch] / = / [,/,/,...] @cpattr[/switch] / = [,,,...] @cpattr[/switch] = / [,/,/,...] @cpattr[/switch] = [,,,...] Switches: move - delete the attribute from the source object after copying. Example: @cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety -> copies the coolness attribute (defined on yourself), to attributes on Anna and Tom. Copy the attribute one object to one or more attributes on another object. If you don't supply a source object, yourself is used. + @cpattr - copy attributes + + Usage: + @cpattr[/switch] / = / [,/,/,...] + @cpattr[/switch] / = [,,,...] + @cpattr[/switch] = / [,/,/,...] + @cpattr[/switch] = [,,,...] + + Switches: + move - delete the attribute from the source object after copying. + + Example: + @cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety + -> + copies the coolness attribute (defined on yourself), to attributes + on Anna and Tom. + + Copy the attribute one object to one or more attributes on another object. If + you don't supply a source object, yourself is used. + @create ~~~~~~~ @@ -247,13 +429,32 @@ module `` - `locks `_ = ``cmd:perm(create) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @create - create new objects Usage: @create[/drop] objname[;alias;alias...][:typeclass], objname... switch: drop - automatically drop the new object into your current location (this is not echoed) this also sets the new object's home to the current location rather than to you. Creates one or more new objects. If typeclass is given, the object is created as a child of this typeclass. The typeclass script is assumed to be located under game/gamesrc/types and any further directory structure is given in Python notation. So if you have a correct typeclass object defined in game/gamesrc/types/examples/red_button.py, you could create a new object of this type like this: @create button;red : examples.red_button.RedButton + @create - create new objects + + Usage: + @create[/drop] objname[;alias;alias...][:typeclass], objname... + + switch: + drop - automatically drop the new object into your current location (this is not echoed) + this also sets the new object's home to the current location rather than to you. + + Creates one or more new objects. If typeclass is given, the object + is created as a child of this typeclass. The typeclass script is + assumed to be located under game/gamesrc/types and any further + directory structure is given in Python notation. So if you have a + correct typeclass object defined in + game/gamesrc/types/examples/red_button.py, you could create a new + object of this type like this: + + @create button;red : examples.red_button.RedButton + + @debug ~~~~~~ @@ -261,13 +462,29 @@ module `` - `locks `_ = ``cmd:perm(debug) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Debug game entities Usage: @debug[/switch] Switches: obj - debug an object script - debug a script Examples: @debug/script game.gamesrc.scripts.myscript.MyScript @debug/script myscript.MyScript @debug/obj examples.red_button.RedButton This command helps when debugging the codes of objects and scripts. It creates the given object and runs tests on its hooks. + Debug game entities + + Usage: + @debug[/switch] + + Switches: + obj - debug an object + script - debug a script + + Examples: + @debug/script game.gamesrc.scripts.myscript.MyScript + @debug/script myscript.MyScript + @debug/obj examples.red_button.RedButton + + This command helps when debugging the codes of objects and scripts. + It creates the given object and runs tests on its hooks. + @desc ~~~~~ @@ -275,13 +492,21 @@ module `_ = ``cmd:perm(desc) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @desc - describe an object or room Usage: @desc [ =] >description> Setts the "desc" attribute on an object. If an object is not given, describe the current room. + @desc - describe an object or room + + Usage: + @desc [ =] >description> + + Setts the "desc" attribute on an + object. If an object is not given, + describe the current room. + @destroy ~~~~~~~~ @@ -289,13 +514,27 @@ module `_ = ``cmd:perm(destroy) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @destroy - remove objects from the game Usage: @destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...] switches: override - The @destroy command will usually avoid accidentally destroying player objects. This switch overrides this safety. examples: @destroy house, roof, door, 44-78 @destroy 5-10, flower, 45 Destroys one or many objects. If dbrefs are used, a range to delete can be given, e.g. 4-10. Also the end points will be deleted. + @destroy - remove objects from the game + + Usage: + @destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...] + + switches: + override - The @destroy command will usually avoid accidentally destroying + player objects. This switch overrides this safety. + examples: + @destroy house, roof, door, 44-78 + @destroy 5-10, flower, 45 + + Destroys one or many objects. If dbrefs are used, a range to delete can be + given, e.g. 4-10. Also the end points will be deleted. + @dig ~~~~ @@ -303,13 +542,31 @@ module `` - `locks `_ = ``cmd:perm(dig) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @dig - build and connect new rooms to the current one Usage: @dig[/switches] roomname[;alias;alias...][:typeclass] [= exit_to_there[;alias][:typeclass]] [, exit_to_here[;alias][:typeclass]] Switches: tel or teleport - move yourself to the new room Examples: @dig kitchen = north;n, south;s @dig house:myrooms.MyHouseTypeclass @dig sheer cliff;cliff;sheer = climb up, climb down This command is a convenient way to build rooms quickly; it creates the new room and you can optionally set up exits back and forth between your current room and the new one. You can add as many aliases as you like to the name of the room and the exits in question; an example would be 'north;no;n'. + @dig - build and connect new rooms to the current one + + Usage: + @dig[/switches] roomname[;alias;alias...][:typeclass] + [= exit_to_there[;alias][:typeclass]] + [, exit_to_here[;alias][:typeclass]] + + Switches: + tel or teleport - move yourself to the new room + + Examples: + @dig kitchen = north;n, south;s + @dig house:myrooms.MyHouseTypeclass + @dig sheer cliff;cliff;sheer = climb up, climb down + + This command is a convenient way to build rooms quickly; it creates the new room and you can optionally + set up exits back and forth between your current room and the new one. You can add as many aliases as you + like to the name of the room and the exits in question; an example would be 'north;no;n'. + @examine ~~~~~~~~ @@ -317,13 +574,29 @@ module `_ = ``cmd:perm(examine) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - examine - detailed info on objects Usage: examine [[/attrname]] examine [*[/attrname]] Switch: player - examine a Player (same as adding *) raw - don't parse escape codes for data. The examine command shows detailed game info about an object and optionally a specific attribute on it. If object is not specified, the current location is examined. Append a * before the search string to examine a player. + examine - detailed info on objects + + Usage: + examine [[/attrname]] + examine [*[/attrname]] + + Switch: + player - examine a Player (same as adding *) + raw - don't parse escape codes for data. + + The examine command shows detailed game info about an + object and optionally a specific attribute on it. + If object is not specified, the current location is examined. + + Append a * before the search string to examine a player. + + @find ~~~~~ @@ -331,13 +604,27 @@ module `_ = ``cmd:perm(find) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - find objects Usage: @find[/switches] [= dbrefmin[-dbrefmax]] Switches: room - only look for rooms (location=None) exit - only look for exits (destination!=None) char - only look for characters (BASE_CHARACTER_TYPECLASS) Searches the database for an object of a particular name or dbref. Use *playername to search for a player. The switches allows for limiting object matches to certain game entities. Dbrefmin and dbrefmax limits matches to within the given dbrefs, or above/below if only one is given. + find objects + + Usage: + @find[/switches] [= dbrefmin[-dbrefmax]] + + Switches: + room - only look for rooms (location=None) + exit - only look for exits (destination!=None) + char - only look for characters (BASE_CHARACTER_TYPECLASS) + + Searches the database for an object of a particular name or dbref. + Use *playername to search for a player. The switches allows for + limiting object matches to certain game entities. Dbrefmin and dbrefmax + limits matches to within the given dbrefs, or above/below if only one is given. + @help ~~~~~ @@ -345,13 +632,37 @@ module `_ = ``cmd:perm(PlayerHelpers)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @help - edit the help database Usage: @help[/switches] [,category[,locks]] = Switches: add - add or replace a new topic with text. append - add text to the end of topic with a newline between. merge - As append, but don't add a newline between the old text and the appended text. delete - remove help topic. force - (used with add) create help topic also if the topic already exists. Examples: @sethelp/add throw = This throws something at ... @sethelp/append pickpocketing,Thievery = This steals ... @sethelp/append pickpocketing, ,attr(is_thief) = This steals ... This command manipulates the help database. A help entry can be created, appended/merged to and deleted. If you don't assign a category, the "General" category will be used. If no lockstring is specified, default is to let everyone read the help file. + @help - edit the help database + + Usage: + @help[/switches] [,category[,locks]] = + + Switches: + add - add or replace a new topic with text. + append - add text to the end of topic with a newline between. + merge - As append, but don't add a newline between the old + text and the appended text. + delete - remove help topic. + force - (used with add) create help topic also if the topic + already exists. + + Examples: + @sethelp/add throw = This throws something at ... + @sethelp/append pickpocketing,Thievery = This steals ... + @sethelp/append pickpocketing, ,attr(is_thief) = This steals ... + + This command manipulates the help database. A help entry can be created, + appended/merged to and deleted. If you don't assign a category, the "General" + category will be used. If no lockstring is specified, default is to let everyone read + the help file. + + @home ~~~~~ @@ -359,13 +670,24 @@ module `` - `locks `_ = ``cmd:perm(@home) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @home - control an object's home location Usage: @home [= home_location] The "home" location is a "safety" location for objects; they will be moved there if their current location ceases to exist. All objects should always have a home location for this reason. It is also a convenient target of the "home" command. If no location is given, just view the object's home location. + @home - control an object's home location + + Usage: + @home [= home_location] + + The "home" location is a "safety" location for objects; they + will be moved there if their current location ceases to exist. All + objects should always have a home location for this reason. + It is also a convenient target of the "home" command. + + If no location is given, just view the object's home location. + @link ~~~~~ @@ -373,13 +695,29 @@ module `` - `locks `_ = ``cmd:perm(link) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @link - connect objects Usage: @link[/switches] = @link[/switches] = @link[/switches] Switch: twoway - connect two exits. For this to work, BOTH and must be exit objects. If is an exit, set its destination to . Two-way operation instead sets the destination to the *locations* of the respective given arguments. The second form (a lone =) sets the destination to None (same as the @unlink command) and the third form (without =) just shows the currently set destination. + @link - connect objects + + Usage: + @link[/switches] = + @link[/switches] = + @link[/switches] + + Switch: + twoway - connect two exits. For this to work, BOTH + and must be exit objects. + + If is an exit, set its destination to . Two-way operation + instead sets the destination to the *locations* of the respective given + arguments. + The second form (a lone =) sets the destination to None (same as the @unlink command) + and the third form (without =) just shows the currently set destination. + @lock ~~~~~ @@ -387,13 +725,41 @@ module `_ = ``cmd: perm(@locks) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - lock - assign a lock definition to an object Usage: @lock [ = ] or @lock[/switch] object/ Switch: del - delete given access type view - view lock associated with given access type (default) If no lockstring is given, shows all locks on object. Lockstring is on the form 'access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...] Where func1, func2 ... valid lockfuncs with or without arguments. Separator expressions need not be capitalized. For example: 'get: id(25) or perm(Wizards)' The 'get' access_type is checked by the get command and will an object locked with this string will only be possible to pick up by Wizards or by object with id 25. You can add several access_types after oneanother by separating them by ';', i.e: 'get:id(25);delete:perm(Builders)' + lock - assign a lock definition to an object + + Usage: + @lock [ = ] + or + @lock[/switch] object/ + + Switch: + del - delete given access type + view - view lock associated with given access type (default) + + If no lockstring is given, shows all locks on + object. + + Lockstring is on the form + 'access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...] + Where func1, func2 ... valid lockfuncs with or without arguments. + Separator expressions need not be capitalized. + + For example: + 'get: id(25) or perm(Wizards)' + The 'get' access_type is checked by the get command and will + an object locked with this string will only be possible to + pick up by Wizards or by object with id 25. + + You can add several access_types after oneanother by separating + them by ';', i.e: + 'get:id(25);delete:perm(Builders)' + @mvattr ~~~~~~~ @@ -401,13 +767,26 @@ module `` - `locks `_ = ``cmd:perm(mvattr) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @mvattr - move attributes Usage: @mvattr[/switch] / = / [,/,/,...] @mvattr[/switch] / = [,,,...] @mvattr[/switch] = / [,/,/,...] @mvattr[/switch] = [,,,...] Switches: copy - Don't delete the original after moving. Move an attribute from one object to one or more attributes on another object. If you don't supply a source object, yourself is used. + @mvattr - move attributes + + Usage: + @mvattr[/switch] / = / [,/,/,...] + @mvattr[/switch] / = [,,,...] + @mvattr[/switch] = / [,/,/,...] + @mvattr[/switch] = [,,,...] + + Switches: + copy - Don't delete the original after moving. + + Move an attribute from one object to one or more attributes on another object. If + you don't supply a source object, yourself is used. + @name ~~~~~ @@ -415,13 +794,20 @@ module `_ = ``cmd:perm(rename) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - cname - change the name and/or aliases of an object Usage: @name obj = name;alias1;alias2 Rename an object to something new. + cname - change the name and/or aliases of an object + + Usage: + @name obj = name;alias1;alias2 + + Rename an object to something new. + + @open ~~~~~ @@ -429,13 +815,24 @@ module `` - `locks `_ = ``cmd:perm(open) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @open - create new exit Usage: @open [;alias;alias..][:typeclass] [,[;alias;..][:typeclass]]] = Handles the creation of exits. If a destination is given, the exit will point there. The argument sets up an exit at the destination leading back to the current room. Destination name can be given both as a #dbref and a name, if that name is globally unique. + @open - create new exit + + Usage: + @open [;alias;alias..][:typeclass] [,[;alias;..][:typeclass]]] = + + Handles the creation of exits. If a destination is given, the exit + will point there. The argument sets up an exit at the + destination leading back to the current room. Destination name + can be given both as a #dbref and a name, if that name is globally + unique. + + @script ~~~~~~~ @@ -443,13 +840,28 @@ module `_ = ``cmd:perm(script) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - attach scripts Usage: @script[/switch] [= ] Switches: start - start all non-running scripts on object, or a given script only stop - stop all scripts on objects, or a given script only If no script path/key is given, lists all scripts active on the given object. Script path can be given from the base location for scripts as given in settings. If adding a new script, it will be started automatically (no /start switch is needed). Using the /start or /stop switches on an object without specifying a script key/path will start/stop ALL scripts on the object. + attach scripts + + Usage: + @script[/switch] [= ] + + Switches: + start - start all non-running scripts on object, or a given script only + stop - stop all scripts on objects, or a given script only + + If no script path/key is given, lists all scripts active on the given + object. + Script path can be given from the base location for scripts as given in + settings. If adding a new script, it will be started automatically (no /start + switch is needed). Using the /start or /stop switches on an object without + specifying a script key/path will start/stop ALL scripts on the object. + @set ~~~~ @@ -457,13 +869,36 @@ module `` - `locks `_ = ``cmd:perm(set) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @set - set attributes Usage: @set / = @set / = @set / Sets attributes on objects. The second form clears a previously set attribute while the last form inspects the current value of the attribute (if any). The most common data to save with this command are strings and numbers. You can however also set Python primities such as lists, dictionaries and tuples on objects (this might be important for the functionality of certain custom objects). This is indicated by you starting your value with one of c'n, c"n, c(n, c[n or c n. Note that you should leave a space after starting a dictionary (' ') so as to not confuse the dictionary start with a colour code like \g. Remember that if you use Python primitives like this, you must write proper Python syntax too - notably you must include quotes around your strings or you will get an error. + @set - set attributes + + Usage: + @set / = + @set / = + @set / + + Sets attributes on objects. The second form clears + a previously set attribute while the last form + inspects the current value of the attribute + (if any). + + The most common data to save with this command are strings and + numbers. You can however also set Python primities such as lists, + dictionaries and tuples on objects (this might be important for + the functionality of certain custom objects). This is indicated + by you starting your value with one of {c'{n, {c"{n, {c({n, {c[{n or {c{ {n. + Note that you should leave a space after starting a dictionary ('{ ') + so as to not confuse the dictionary start with a colour code like \{g. + Remember that if you use Python primitives like this, you must + write proper Python syntax too - notably you must include quotes + around your strings or you will get an error. + + @tel ~~~~ @@ -471,13 +906,25 @@ module `_ = ``cmd:perm(teleport) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - teleport Usage: @tel/switch [ =] Switches: quiet - don't echo leave/arrive messages to the source/target locations for the move. intoexit - if target is an exit, teleport INTO the exit object instead of to its destination Teleports an object or yourself somewhere. + teleport + + Usage: + @tel/switch [ =] + + Switches: + quiet - don't echo leave/arrive messages to the source/target + locations for the move. + intoexit - if target is an exit, teleport INTO + the exit object instead of to its destination + + Teleports an object or yourself somewhere. + @tunnel ~~~~~~~ @@ -485,13 +932,36 @@ module `_ = ``cmd: perm(tunnel) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - dig in often-used directions Usage: @tunnel[/switch] [= roomname[;alias;alias;...][:typeclass]] Switches: oneway - do not create an exit back to the current location tel - teleport to the newly created room Example: @tunnel n @tunnel n = house;mike's place;green building This is a simple way to build using pre-defined directions: wn,ne,e,se,s,sw,w,nwn (north, northeast etc) wu,dn (up and down) wi,on (in and out) The full names (north, in, southwest, etc) will always be put as main name for the exit, using the abbreviation as an alias (so an exit will always be able to be used with both "north" as well as "n" for example). Opposite directions will automatically be created back from the new room unless the /oneway switch is given. For more flexibility and power in creating rooms, use @dig. + dig in often-used directions + + Usage: + @tunnel[/switch] [= roomname[;alias;alias;...][:typeclass]] + + Switches: + oneway - do not create an exit back to the current location + tel - teleport to the newly created room + + Example: + @tunnel n + @tunnel n = house;mike's place;green building + + This is a simple way to build using pre-defined directions: + {wn,ne,e,se,s,sw,w,nw{n (north, northeast etc) + {wu,d{n (up and down) + {wi,o{n (in and out) + The full names (north, in, southwest, etc) will always be put as + main name for the exit, using the abbreviation as an alias (so an + exit will always be able to be used with both "north" as well as + "n" for example). Opposite directions will automatically be + created back from the new room unless the /oneway switch is given. + For more flexibility and power in creating rooms, use @dig. + @typeclass ~~~~~~~~~~ @@ -499,13 +969,41 @@ module `_ = ``cmd:perm(typeclass) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @typeclass - set object typeclass Usage: @typclass[/switch] [= ] @type '' @parent '' Switch: reset - clean out *all* the attributes on the object - basically making this a new clean object. force - change to the typeclass also if the object already has a typeclass of the same name. Example: @type button = examples.red_button.RedButton View or set an object's typeclass. If setting, the creation hooks of the new typeclass will be run on the object. If you have clashing properties on the old class, use /reset. By default you are protected from changing to a typeclass of the same name as the one you already have, use /force to override this protection. The given typeclass must be identified by its location using python dot-notation pointing to the correct module and class. If no typeclass is given (or a wrong typeclass is given). Errors in the path or new typeclass will lead to the old typeclass being kept. The location of the typeclass module is searched from the default typeclass directory, as defined in the server settings. + @typeclass - set object typeclass + + Usage: + @typclass[/switch] [= ] + @type '' + @parent '' + + Switch: + reset - clean out *all* the attributes on the object - + basically making this a new clean object. + force - change to the typeclass also if the object + already has a typeclass of the same name. + Example: + @type button = examples.red_button.RedButton + + View or set an object's typeclass. If setting, the creation hooks + of the new typeclass will be run on the object. If you have + clashing properties on the old class, use /reset. By default you + are protected from changing to a typeclass of the same name as the + one you already have, use /force to override this protection. + + The given typeclass must be identified by its location using + python dot-notation pointing to the correct module and class. If + no typeclass is given (or a wrong typeclass is given). Errors in + the path or new typeclass will lead to the old typeclass being + kept. The location of the typeclass module is searched from the + default typeclass directory, as defined in the server settings. + + @unlink ~~~~~~~ @@ -513,13 +1011,20 @@ module `` - `locks `_ = ``cmd:perm(unlink) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @unlink - unconnect objects Usage: @unlink Unlinks an object, for example an exit, disconnecting it from whatever it was connected to. + @unlink - unconnect objects + + Usage: + @unlink + + Unlinks an object, for example an exit, disconnecting + it from whatever it was connected to. + @wipe ~~~~~ @@ -527,19 +1032,30 @@ module `` - `locks `_ = ``cmd:perm(wipe) or perm(Builders)`` -- `helpcategory `_ = ``Building`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Building`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @wipe - clears attributes Usage: @wipe [/attribute[/attribute...]] Example: @wipe box @wipe box/colour Wipes all of an object's attributes, or optionally only those matching the given attribute-wildcard search string. + @wipe - clears attributes + + Usage: + @wipe [/attribute[/attribute...]] + + Example: + @wipe box + @wipe box/colour + + Wipes all of an object's attributes, or optionally only those + matching the given attribute-wildcard search string. + Comms ----- `Link to Python -module `_ +module `_ @cboot (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -547,13 +1063,23 @@ module `` - `locks `_ = ``cmd: not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cboot Usage: @cboot[/quiet] = [:reason] Switches: quiet - don't notify the channel Kicks a player or object from a channel you control. + @cboot + + Usage: + @cboot[/quiet] = [:reason] + + Switches: + quiet - don't notify the channel + + Kicks a player or object from a channel you control. + + @ccreate (OOC command) ~~~~~~~~~~~~~~~~~~~~~~ @@ -561,13 +1087,19 @@ module `_ = ``cmd:not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @ccreate channelcreate Usage: @ccreate [;alias;alias...] = description Creates a new channel owned by you. + @ccreate + channelcreate + Usage: + @ccreate [;alias;alias...] = description + + Creates a new channel owned by you. + @cdesc (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -575,13 +1107,20 @@ module `` - `locks `_ = ``cmd:not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cdesc - set channel description Usage: @cdesc = Changes the description of the channel as shown in channel lists. + @cdesc - set channel description + + Usage: + @cdesc = + + Changes the description of the channel as shown in + channel lists. + @cdestroy (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -589,13 +1128,19 @@ module `` - `locks `_ = ``cmd: not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cdestroy Usage: @cdestroy Destroys a channel that you control. + @cdestroy + + Usage: + @cdestroy + + Destroys a channel that you control. + @cemit (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -603,13 +1148,27 @@ module `_ = ``cmd: not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cemit - send a message to channel Usage: @cemit[/switches] = Switches: noheader - don't show the [channel] header before the message sendername - attach the sender's name before the message quiet - don't echo the message back to sender Allows the user to broadcast a message over a channel as long as they control it. It does not show the user's name unless they provide the /sendername switch. + @cemit - send a message to channel + + Usage: + @cemit[/switches] = + + Switches: + noheader - don't show the [channel] header before the message + sendername - attach the sender's name before the message + quiet - don't echo the message back to sender + + Allows the user to broadcast a message over a channel as long as + they control it. It does not show the user's name unless they + provide the /sendername switch. + + @channels (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -618,13 +1177,22 @@ module `_ = ``cmd: not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @clist Usage: @channels @clist comlist Lists all channels available to you, wether you listen to them or not. Use 'comlist" to only view your current channel subscriptions. + @clist + + Usage: + @channels + @clist + comlist + + Lists all channels available to you, wether you listen to them or not. + Use 'comlist" to only view your current channel subscriptions. + @cset (OOC command) ~~~~~~~~~~~~~~~~~~~ @@ -632,13 +1200,20 @@ module `_ = ``cmd:not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cset - changes channel access restrictions Usage: @cset [= ] Changes the lock access restrictions of a channel. If no lockstring was given, view the current lock definitions. + @cset - changes channel access restrictions + + Usage: + @cset [= ] + + Changes the lock access restrictions of a channel. If no + lockstring was given, view the current lock definitions. + @cwho (OOC command) ~~~~~~~~~~~~~~~~~~~ @@ -646,13 +1221,19 @@ module `` - `locks `_ = ``cmd: not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @cwho Usage: @cwho List who is connected to a given channel you have access to. + @cwho + + Usage: + @cwho + + List who is connected to a given channel you have access to. + @imc2chan (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -661,13 +1242,31 @@ module `` - `locks `_ = ``cmd:serversetting(IMC2_ENABLED) and pperm(Immortals)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - imc2chan - link an evennia channel to imc2 Usage: @imc2chan[/switches] = Switches: /disconnect - this clear the imc2 connection to the channel. /remove - " /list - show all imc2<->evennia mappings Example: @imc2chan myimcchan = ievennia Connect an existing evennia channel to a channel on an IMC2 network. The network contact information is defined in settings and should already be accessed at this point. Use @imcchanlist to see available IMC channels. + imc2chan - link an evennia channel to imc2 + + Usage: + @imc2chan[/switches] = + + Switches: + /disconnect - this clear the imc2 connection to the channel. + /remove - " + /list - show all imc2<->evennia mappings + + Example: + @imc2chan myimcchan = ievennia + + Connect an existing evennia channel to a channel on an IMC2 + network. The network contact information is defined in settings and + should already be accessed at this point. Use @imcchanlist to see + available IMC channels. + + @imcinfo (OOC command) ~~~~~~~~~~~~~~~~~~~~~~ @@ -676,13 +1275,28 @@ module `_ = ``cmd: serversetting(IMC2_ENABLED) and pperm(Wizards)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - imcinfo - package of imc info commands Usage: @imcinfo[/switches] @imcchanlist - list imc2 channels @imclist - list connected muds @imcwhois - whois info about a remote player Switches for @imcinfo: channels - as @imcchanlist (default) games or muds - as @imclist whois - as @imcwhois (requires an additional argument) update - force an update of all lists Shows lists of games or channels on the IMC2 network. + imcinfo - package of imc info commands + + Usage: + @imcinfo[/switches] + @imcchanlist - list imc2 channels + @imclist - list connected muds + @imcwhois - whois info about a remote player + + Switches for @imcinfo: + channels - as @imcchanlist (default) + games or muds - as @imclist + whois - as @imcwhois (requires an additional argument) + update - force an update of all lists + + Shows lists of games or channels on the IMC2 network. + @irc2chan (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -691,13 +1305,31 @@ module `` - `locks `_ = ``cmd:serversetting(IRC_ENABLED) and pperm(Immortals)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @irc2chan - link evennia channel to an IRC channel Usage: @irc2chan[/switches] = <#irchannel> Switches: /disconnect - this will delete the bot and remove the irc connection to the channel. /remove - " /list - show all irc<->evennia mappings Example: @irc2chan myircchan = irc.dalnet.net 6667 myevennia-channel evennia-bot This creates an IRC bot that connects to a given IRC network and channel. It will relay everything said in the evennia channel to the IRC channel and vice versa. The bot will automatically connect at server start, so this comman need only be given once. The /disconnect switch will permanently delete the bot. To only temporarily deactivate it, use the @services command instead. + @irc2chan - link evennia channel to an IRC channel + + Usage: + @irc2chan[/switches] = <#irchannel> + + Switches: + /disconnect - this will delete the bot and remove the irc connection to the channel. + /remove - " + /list - show all irc<->evennia mappings + + Example: + @irc2chan myircchan = irc.dalnet.net 6667 myevennia-channel evennia-bot + + This creates an IRC bot that connects to a given IRC network and channel. It will + relay everything said in the evennia channel to the IRC channel and vice versa. The + bot will automatically connect at server start, so this comman need only be given once. + The /disconnect switch will permanently delete the bot. To only temporarily deactivate it, + use the @services command instead. + @rss2chan (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -706,13 +1338,32 @@ module `` - `locks `_ = ``cmd:serversetting(RSS_ENABLED) and pperm(Immortals)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @rss2chan - link evennia channel to an RSS feed Usage: @rss2chan[/switches] = Switches: /disconnect - this will stop the feed and remove the connection to the channel. /remove - " /list - show all rss->evennia mappings Example: @rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic This creates an RSS reader that connects to a given RSS feed url. Updates will be echoed as a title and news link to the given channel. The rate of updating is set with the RSS_UPDATE_INTERVAL variable in settings (default is every 10 minutes). When disconnecting you need to supply both the channel and url again so as to identify the connection uniquely. + @rss2chan - link evennia channel to an RSS feed + + Usage: + @rss2chan[/switches] = + + Switches: + /disconnect - this will stop the feed and remove the connection to the channel. + /remove - " + /list - show all rss->evennia mappings + + Example: + @rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic + + This creates an RSS reader that connects to a given RSS feed url. Updates will be + echoed as a title and news link to the given channel. The rate of updating is set + with the RSS_UPDATE_INTERVAL variable in settings (default is every 10 minutes). + + When disconnecting you need to supply both the channel and url again so as to identify + the connection uniquely. + addcom (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -720,13 +1371,22 @@ addcom (OOC command) - ``key`` = ``addcom`` - ``aliases`` = ``aliaschan, chanalias`` - `locks `_ = ``cmd:not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - addcom - subscribe to a channel with optional alias Usage: addcom [alias=] Joins a given channel. If alias is given, this will allow you to refer to the channel by this alias rather than the full channel name. Subsequent calls of this command can be used to add multiple aliases to an already joined channel. + addcom - subscribe to a channel with optional alias + + Usage: + addcom [alias=] + + Joins a given channel. If alias is given, this will allow you to + refer to the channel by this alias rather than the full channel + name. Subsequent calls of this command can be used to add multiple + aliases to an already joined channel. + allcom (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -734,13 +1394,23 @@ allcom (OOC command) - ``key`` = ``allcom`` - ``aliases`` = ```` - `locks `_ = ``cmd: not pperm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - allcom - operate on all channels Usage: allcom [on | off | who | destroy] Allows the user to universally turn off or on all channels they are on, as well as perform a 'who' for all channels they are on. Destroy deletes all channels that you control. Without argument, works like comlist. + allcom - operate on all channels + + Usage: + allcom [on | off | who | destroy] + + Allows the user to universally turn off or on all channels they are on, + as well as perform a 'who' for all channels they are on. Destroy deletes + all channels that you control. + + Without argument, works like comlist. + delcom (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -748,13 +1418,21 @@ delcom (OOC command) - ``key`` = ``delcom`` - ``aliases`` = ``delaliaschan, delchanalias`` - `locks `_ = ``cmd:not perm(channel_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - delcom - unsubscribe from channel or remove channel alias Usage: delcom If the full channel name is given, unsubscribe from the channel. If an alias is given, remove the alias but don't unsubscribe. + delcom - unsubscribe from channel or remove channel alias + + Usage: + delcom + + If the full channel name is given, unsubscribe from the + channel. If an alias is given, remove the alias but don't + unsubscribe. + imctell (OOC command) ~~~~~~~~~~~~~~~~~~~~~ @@ -762,13 +1440,21 @@ imctell (OOC command) - ``key`` = ``imctell`` - ``aliases`` = ``imcpage, imc2tell, imc2page`` - `locks `_ = ``cmd: serversetting(IMC2_ENABLED)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - imctell - send a page to a remote IMC player Usage: imctell User@MUD = imcpage " Sends a page to a user on a remote MUD, connected over IMC2. + imctell - send a page to a remote IMC player + + Usage: + imctell User@MUD = + imcpage " + + Sends a page to a user on a remote MUD, connected + over IMC2. + page (OOC command) ~~~~~~~~~~~~~~~~~~ @@ -776,19 +1462,32 @@ page (OOC command) - ``key`` = ``page`` - ``aliases`` = ``tell`` - `locks `_ = ``cmd:not pperm(page_banned)`` -- `helpcategory `_ = ``Comms`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Comms`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - page - send private message Usage: page[/switches] [,,... = ] tell '' page Switch: last - shows who you last messaged list - show your last of tells/pages (default) Send a message to target user (if online). If no argument is given, you will get a list of your latest messages. + page - send private message + + Usage: + page[/switches] [,,... = ] + tell '' + page + + Switch: + last - shows who you last messaged + list - show your last of tells/pages (default) + + Send a message to target user (if online). If no + argument is given, you will get a list of your latest messages. + General ------- `Link to Python -module `_ +module `_ @encoding (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -796,13 +1495,30 @@ module `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - encoding - set a custom text encoding Usage: @encoding/switches [] Switches: clear - clear your custom encoding This sets the text encoding for communicating with Evennia. This is mostly an issue only if you want to use non-ASCII characters (i.e. letters/symbols not found in English). If you see that your characters look strange (or you get encoding errors), you should use this command to set the server encoding to be the same used in your client program. Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc. If you don't submit an encoding, the current encoding will be displayed instead. + encoding - set a custom text encoding + + Usage: + @encoding/switches [] + + Switches: + clear - clear your custom encoding + + + This sets the text encoding for communicating with Evennia. This is mostly an issue only if + you want to use non-ASCII characters (i.e. letters/symbols not found in English). If you see + that your characters look strange (or you get encoding errors), you should use this command + to set the server encoding to be the same used in your client program. + + Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc. + + If you don't submit an encoding, the current encoding will be displayed instead. + @ic (OOC command) ~~~~~~~~~~~~~~~~~ @@ -810,13 +1526,24 @@ module `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Switch control to an object Usage: @ic Go in-character (IC) as a given Character. This will attempt to "become" a different object assuming you have the right to do so. You cannot become an object that is already controlled by another player. In principle can be any in-game object as long as you have access right to puppet it. + Switch control to an object + + Usage: + @ic + + Go in-character (IC) as a given Character. + + This will attempt to "become" a different object assuming you have + the right to do so. You cannot become an object that is already + controlled by another player. In principle can be + any in-game object as long as you have access right to puppet it. + @ooc (OOC command) ~~~~~~~~~~~~~~~~~~ @@ -824,13 +1551,21 @@ module `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @ooc - go ooc Usage: @ooc Go out-of-character (OOC). This will leave your current character and put you in a incorporeal OOC state. + @ooc - go ooc + + Usage: + @ooc + + Go out-of-character (OOC). + + This will leave your current character and put you in a incorporeal OOC state. + @password (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -838,13 +1573,19 @@ module `` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @password - set your password Usage: @password = Changes your password. Make sure to pick a safe one. + @password - set your password + + Usage: + @password = + + Changes your password. Make sure to pick a safe one. + @quit (OOC command) ~~~~~~~~~~~~~~~~~~~ @@ -852,13 +1593,19 @@ module `` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - quit Usage: @quit Gracefully disconnect from the game. + quit + + Usage: + @quit + + Gracefully disconnect from the game. + access ~~~~~~ @@ -866,13 +1613,20 @@ access - ``key`` = ``access`` - ``aliases`` = ``groups, hierarchy`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - access - show access groups Usage: access This command shows you the permission hierarchy and which permission groups you are a member of. + access - show access groups + + Usage: + access + + This command shows you the permission hierarchy and + which permission groups you are a member of. + drop ~~~~ @@ -880,13 +1634,20 @@ drop - ``key`` = ``drop`` - ``aliases`` = ```` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - drop Usage: drop Lets you drop an object from your inventory into the location you are currently in. + drop + + Usage: + drop + + Lets you drop an object from your inventory into the + location you are currently in. + get ~~~ @@ -894,13 +1655,20 @@ get - ``key`` = ``get`` - ``aliases`` = ``grab`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - get Usage: get Picks up an object from your location and puts it in your inventory. + get + + Usage: + get + + Picks up an object from your location and puts it in + your inventory. + help ~~~~ @@ -908,13 +1676,22 @@ help - ``key`` = ``help`` - ``aliases`` = ```` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - The main help command Usage: help help list help all This will search for help on commands and other topics related to the game. + The main help command + + Usage: + help + help list + help all + + This will search for help on commands and other + topics related to the game. + help (OOC command) ~~~~~~~~~~~~~~~~~~ @@ -922,13 +1699,22 @@ help (OOC command) - ``key`` = ``help`` - ``aliases`` = ```` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - The main help command Usage: help help list help all This will search for help on commands and other topics related to the game. + The main help command + + Usage: + help + help list + help all + + This will search for help on commands and other + topics related to the game. + home ~~~~ @@ -936,13 +1722,19 @@ home - ``key`` = ``home`` - ``aliases`` = ```` - `locks `_ = ``cmd:perm(home) or perm(Builders)`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - home Usage: home Teleports you to your home location. + home + + Usage: + home + + Teleports you to your home location. + inventory ~~~~~~~~~ @@ -950,13 +1742,20 @@ inventory - ``key`` = ``inventory`` - ``aliases`` = ``inv, i`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - inventory Usage: inventory inv Shows your inventory. + inventory + + Usage: + inventory + inv + + Shows your inventory. + look ~~~~ @@ -964,13 +1763,21 @@ look - ``key`` = ``look`` - ``aliases`` = ``l, ls`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - look Usage: look look look * Observes your location or objects in your vicinity. + look + + Usage: + look + look + look * + + Observes your location or objects in your vicinity. + look (OOC command) ~~~~~~~~~~~~~~~~~~ @@ -978,13 +1785,23 @@ look (OOC command) - ``key`` = ``look`` - ``aliases`` = ``l, ls`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - ooc look Usage: look This is an OOC version of the look command. Since a Player doesn't have an in-game existence, there is no concept of location or "self". If we are controlling a character, pass control over to normal look. + ooc look + + Usage: + look + + This is an OOC version of the look command. Since a + Player doesn't have an in-game existence, there is no + concept of location or "self". If we are controlling + a character, pass control over to normal look. + + nick ~~~~ @@ -992,13 +1809,41 @@ nick - ``key`` = ``nick`` - ``aliases`` = ``nickname, nicks, @nick, alias`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Define a personal alias/nick Usage: nick[/switches] = [] alias '' Switches: object - alias an object player - alias a player clearall - clear all your aliases list - show all defined aliases (also "nicks" works) Examples: nick hi = say Hello, I'm Sarah! nick/object tom = the tall man A 'nick' is a personal shortcut you create for your own use. When you enter the nick, the alternative string will be sent instead. The switches control in which situations the substitution will happen. The default is that it will happen when you enter a command. The 'object' and 'player' nick-types kick in only when you use commands that requires an object or player as a target - you can then use the nick to refer to them. Note that no objects are actually renamed or changed by this command - the nick is only available to you. If you want to permanently add keywords to an object for everyone to use, you need build privileges and to use the @alias command. + Define a personal alias/nick + + Usage: + nick[/switches] = [] + alias '' + + Switches: + object - alias an object + player - alias a player + clearall - clear all your aliases + list - show all defined aliases (also "nicks" works) + + Examples: + nick hi = say Hello, I'm Sarah! + nick/object tom = the tall man + + A 'nick' is a personal shortcut you create for your own use. When + you enter the nick, the alternative string will be sent instead. + The switches control in which situations the substitution will + happen. The default is that it will happen when you enter a + command. The 'object' and 'player' nick-types kick in only when + you use commands that requires an object or player as a target - + you can then use the nick to refer to them. + + Note that no objects are actually renamed or changed by this + command - the nick is only available to you. If you want to + permanently add keywords to an object for everyone to use, you + need build privileges and to use the @alias command. + pose ~~~~ @@ -1006,13 +1851,26 @@ pose - ``key`` = ``pose`` - ``aliases`` = ``:, emote`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - pose - strike a pose Usage: pose pose's Example: pose is standing by the wall, smiling. -> others will see: Tom is standing by the wall, smiling. Describe an action being taken. The pose text will automatically begin with your name. + pose - strike a pose + + Usage: + pose + pose's + + Example: + pose is standing by the wall, smiling. + -> others will see: + Tom is standing by the wall, smiling. + + Describe an action being taken. The pose text will + automatically begin with your name. + say ~~~ @@ -1020,13 +1878,19 @@ say - ``key`` = ``say`` - ``aliases`` = ``", '`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - say Usage: say Talk to those in your current location. + say + + Usage: + say + + Talk to those in your current location. + who ~~~ @@ -1034,19 +1898,27 @@ who - ``key`` = ``who`` - ``aliases`` = ``doing`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``General`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - who Usage: who doing Shows who is currently online. Doing is an alias that limits info also for those with all permissions. + who + + Usage: + who + doing + + Shows who is currently online. Doing is an alias that limits info + also for those with all permissions. + System ------ `Link to Python -module `_ +module `_ @about ~~~~~~ @@ -1054,13 +1926,19 @@ module `_ = ``cmd:all()`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @about - game engine info Usage: @about Display info about the game engine. + @about - game engine info + + Usage: + @about + + Display info about the game engine. + @objects ~~~~~~~~ @@ -1068,13 +1946,21 @@ module `_ = ``cmd:perm(listobjects) or perm(Builders)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Give a summary of object types in database Usage: @objects [] Gives statictics on objects in database as well as a list of latest objects in database. If not given, defaults to 10. + Give a summary of object types in database + + Usage: + @objects [] + + Gives statictics on objects in database as well as + a list of latest objects in database. If not + given, defaults to 10. + @py ~~~ @@ -1082,13 +1968,31 @@ module `_ = ``cmd:perm(py) or perm(Immortals)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Execute a snippet of python code Usage: @py Separate multiple commands by ';'. A few variables are made available for convenience in order to offer access to the system (you can import more at execution time). Available variables in @py environment: self, me : caller here : caller.location ev : the evennia API inherits_from(obj, parent) : check object inheritance rNote: In the wrong hands this command is a severe security risk. It should only be accessible by trusted server admins/superusers.n + Execute a snippet of python code + + Usage: + @py + + Separate multiple commands by ';'. A few variables are made + available for convenience in order to offer access to the system + (you can import more at execution time). + + Available variables in @py environment: + self, me : caller + here : caller.location + ev : the evennia API + inherits_from(obj, parent) : check object inheritance + + {rNote: In the wrong hands this command is a severe security risk. + It should only be accessible by trusted server admins/superusers.{n + + @reload (OOC command) ~~~~~~~~~~~~~~~~~~~~~ @@ -1096,13 +2000,21 @@ module `` - `locks `_ = ``cmd:perm(reload) or perm(Immortals)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Reload the system Usage: @reload This restarts the server. The Portal is not affected. Non-persistent scripts will survive a @reload (use @reset to purge) and at_reload() hooks will be called. + Reload the system + + Usage: + @reload + + This restarts the server. The Portal is not + affected. Non-persistent scripts will survive a @reload (use + @reset to purge) and at_reload() hooks will be called. + @reset (OOC command) ~~~~~~~~~~~~~~~~~~~~ @@ -1110,13 +2022,22 @@ module `_ = ``cmd:perm(reload) or perm(Immortals)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Reset and reboot the system Usage: @reset A cold reboot. This works like a mixture of @reload and @shutdown, - all shutdown hooks will be called and non-persistent scrips will be purged. But the Portal will not be affected and the server will automatically restart again. + Reset and reboot the system + + Usage: + @reset + + A cold reboot. This works like a mixture of @reload and @shutdown, + - all shutdown hooks will be called and non-persistent scrips will + be purged. But the Portal will not be affected and the server will + automatically restart again. + @scripts ~~~~~~~~ @@ -1124,13 +2045,31 @@ module `_ = ``cmd:perm(listscripts) or perm(Wizards)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Operate and list global scripts, list all scrips. Usage: @scripts[/switches] [] Switches: start - start a script (must supply a script path) stop - stops an existing script kill - kills a script - without running its cleanup hooks validate - run a validation on the script(s) If no switches are given, this command just views all active scripts. The argument can be either an object, at which point it will be searched for all scripts defined on it, or an script name or dbref. For using the /stop switch, a unique script dbref is required since whole classes of scripts often have the same name. Use @script for managing commands on objects. + Operate and list global scripts, list all scrips. + + Usage: + @scripts[/switches] [] + + Switches: + start - start a script (must supply a script path) + stop - stops an existing script + kill - kills a script - without running its cleanup hooks + validate - run a validation on the script(s) + + If no switches are given, this command just views all active + scripts. The argument can be either an object, at which point it + will be searched for all scripts defined on it, or an script name + or dbref. For using the /stop switch, a unique script dbref is + required since whole classes of scripts often have the same name. + + Use @script for managing commands on objects. + @server ~~~~~~~ @@ -1138,13 +2077,38 @@ module `_ = ``cmd:perm(list) or perm(Immortals)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - server load and memory statistics Usage: @serverload This command shows server load statistics and dynamic memory usage. Some Important statistics in the table: wServer loadn is an average of processor usage. It's usually between 0 (no usage) and 1 (100% usage), but may also be temporarily higher if your computer has multiple CPU cores. The wResident/Virtual memoryn displays the total memory used by the server process. Evennia wcachesn all retrieved database entities when they are loaded by use of the idmapper functionality. This allows Evennia to maintain the same instances of an entity and allowing non-persistent storage schemes. The total amount of cached objects are displayed plus a breakdown of database object types. Finally, wAttributesn are cached on-demand for speed. The total amount of memory used for this type of cache is also displayed. + server load and memory statistics + + Usage: + @serverload + + This command shows server load statistics and dynamic memory + usage. + + Some Important statistics in the table: + + {wServer load{n is an average of processor usage. It's usually + between 0 (no usage) and 1 (100% usage), but may also be + temporarily higher if your computer has multiple CPU cores. + + The {wResident/Virtual memory{n displays the total memory used by + the server process. + + Evennia {wcaches{n all retrieved database entities when they are + loaded by use of the idmapper functionality. This allows Evennia + to maintain the same instances of an entity and allowing + non-persistent storage schemes. The total amount of cached objects + are displayed plus a breakdown of database object types. Finally, + {wAttributes{n are cached on-demand for speed. The total amount of + memory used for this type of cache is also displayed. + + @service ~~~~~~~~ @@ -1152,13 +2116,26 @@ module `_ = ``cmd:perm(service) or perm(Immortals)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @service - manage services Usage: @service[/switch] Switches: list - shows all available services (default) start - activates a service stop - stops a service Service management system. Allows for the listing, starting, and stopping of services. If no switches are given, services will be listed. + @service - manage services + + Usage: + @service[/switch] + + Switches: + list - shows all available services (default) + start - activates a service + stop - stops a service + + Service management system. Allows for the listing, + starting, and stopping of services. If no switches + are given, services will be listed. + @shutdown (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1166,13 +2143,19 @@ module `` - `locks `_ = ``cmd:perm(shutdown) or perm(Immortals)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @shutdown Usage: @shutdown [announcement] Gracefully shut down both Server and Portal. + @shutdown + + Usage: + @shutdown [announcement] + + Gracefully shut down both Server and Portal. + @time ~~~~~ @@ -1180,33 +2163,43 @@ module `_ = ``cmd:perm(time) or perm(Players)`` -- `helpcategory `_ = ``System`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``System`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - @time Usage: @time Server local time. + @time + + Usage: + @time + + Server local time. + Unloggedin ---------- `Link to Python -module `_ +module `_ -**\ unloggedin\ *look*\ command (Unloggedin command) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\_\_unloggedin\_look\_command (Unloggedin command) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - ``key`` = ``__unloggedin_look_command`` - ``aliases`` = ``look, l`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``Unloggedin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Unloggedin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - This is an unconnected version of the look command for simplicity. This is called by the server and kicks everything in gear. All it does is display the connect screen. + This is an unconnected version of the look command for simplicity. + + This is called by the server and kicks everything in gear. + All it does is display the connect screen. + connect (Unloggedin command) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1214,13 +2207,19 @@ connect (Unloggedin command) - ``key`` = ``connect`` - ``aliases`` = ``conn, con, co`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``Unloggedin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Unloggedin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Connect to the game. Usage (at login screen): connect Use the create command to first create an account before logging in. + Connect to the game. + + Usage (at login screen): + connect + + Use the create command to first create an account before logging in. + create (Unloggedin command) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1228,13 +2227,20 @@ create (Unloggedin command) - ``key`` = ``create`` - ``aliases`` = ``cre, cr`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``Unloggedin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Unloggedin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - Create a new account. Usage (at login screen): create "playername" This creates a new player account. + Create a new account. + + Usage (at login screen): + create "playername" + + This creates a new player account. + + help (Unloggedin command) ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1242,13 +2248,15 @@ help (Unloggedin command) - ``key`` = ``help`` - ``aliases`` = ``h, ?`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``Unloggedin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Unloggedin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - This is an unconnected version of the help command, for simplicity. It shows a pane of info. + This is an unconnected version of the help command, + for simplicity. It shows a pane of info. + quit (Unloggedin command) ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1256,11 +2264,14 @@ quit (Unloggedin command) - ``key`` = ``quit`` - ``aliases`` = ``q, qu`` - `locks `_ = ``cmd:all()`` -- `helpcategory `_ = ``Unloggedin`` -- `Auto-help system.html>`_ +- `help\_category `_ = ``Unloggedin`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] (``__doc__ string``) = :: - We maintain a different version of the quit command here for unconnected players for the sake of simplicity. The logged in version is a bit more complicated. + We maintain a different version of the quit command + here for unconnected players for the sake of simplicity. The logged in + version is a bit more complicated. + diff --git a/docs/sphinx/source/wiki/DeveloperCentral.rst b/docs/sphinx/source/wiki/DeveloperCentral.rst index 0f331c3454..a7a611985e 100644 --- a/docs/sphinx/source/wiki/DeveloperCentral.rst +++ b/docs/sphinx/source/wiki/DeveloperCentral.rst @@ -7,15 +7,9 @@ codebase itself. Everyone is welcome to `help out `_! If you have any questions, please feel free to ask them in the `Forum/Discussion Group `_. If you want more docs on a -particular issue, consider filling out our -"https://docs.google.com/spreadsheet/viewform?hl - -en\_US&formkey - -dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid -====================================== - -0.html">online form and tell us! Bugs should be reported to the `Issue +particular issue, consider filling out our `online +form `_ +and tell us! Bugs should be reported to the `Issue tracker `_. You can find more links to Evennia resources from the `Links `_ page. @@ -31,36 +25,30 @@ General Evennia development information - `Policy for 'MUX-like' default commands `_ - `Setting up a Mercurial environment for coding `_ +- `Planning your own Evennia game `_ Evennia Component Documentation ------------------------------- - `ev - the flat API `_ -`Directory Overview `_ +- `Directory Overview `_ +- `Portal and Server `_ +- `Commands `_ +- `Typeclass system `_ -`Portal and Server `_ + - `Objects `_ + - `Scripts `_ + - `Players `_ + - `Attributes `_ -`Commands `_ - -`Typeclass system `_ - -- `Objects `_ -- `Scripts `_ -- `Players `_ -- `Attributes `_ - -`Locks and Permissions `_ - -`Communications `_ - -`Help System `_ - -`Nicks `_ - -`Sessions and Protocols `_ - -`Web features `_ +- `Locks and Permissions `_ +- `Communications `_ +- `Help System `_ +- `Nicks `_ +- `Sessions and Protocols `_ +- `Web features `_ +- `Configuration and module plugins `_ Programming Evennia ------------------- @@ -69,18 +57,8 @@ Programming Evennia game `_ - `Useful coding utilities `_ - `Running and writing unit tests for Evennia `_ -- `Removing Colour from your game - tutorial on redefining typeclass - methods `_ -- `Adding a Command prompt `_ - `Running processes asynchronously `_ -Game implementation hints -------------------------- - -- `Planning your own Evennia game `_ -- `Creating a Zoning system `_ -- `Implementing cooldowns for commands `_ - Work in Progress - Developer brainstorms and whitepages ------------------------------------------------------- diff --git a/docs/sphinx/source/wiki/DirectoryOverview.rst b/docs/sphinx/source/wiki/DirectoryOverview.rst index 74d34d16b7..5d7b6d699a 100644 --- a/docs/sphinx/source/wiki/DirectoryOverview.rst +++ b/docs/sphinx/source/wiki/DirectoryOverview.rst @@ -1,3 +1,5 @@ +The layout of the evennia package + Evennia directory overview ========================== @@ -9,7 +11,7 @@ Evennia directory overview docs/ game/ locale/ - src/ + src/ Evennia's main directory (``evennia``) is divided into five sub directories - ``src/``, ``game/``, ``contrib/`` , ``locale`` and @@ -32,7 +34,7 @@ places in ``src/``. By importing ``ev`` from your code in ``game/`` you have access to most important Evennia systems without *having* to know where everything is located, as described in the following sections. -The ``docs/`` directory +The \`docs/\` directory ----------------------- This contains Evennia's offline documentation. The main source of @@ -51,7 +53,7 @@ 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 400+ pages of it ...). -The ``locale/`` directory +The \`locale/\` directory ------------------------- This contains internationalization strings for translating the Evennia @@ -59,7 +61,7 @@ core server to different languages. See `Internationalization `_ for more information. -The ``contrib/`` ("contributions") directory +The \`contrib/\` ("contributions") directory -------------------------------------------- This directory contains various stand-alone code snippets that are @@ -69,7 +71,7 @@ you explicitly import and use them. The contrib folder also contains the `Tutorial World `_ game example. See ``contrib/README`` for more information. -The ``game/`` directory +The \`game/\` directory ----------------------- ``game/`` contains everything related to a particular game world. If you @@ -83,9 +85,20 @@ the server. game/ evennia.py - manage.py gamesrc/ commands/ examples/ scripts/ examples/ objects/ examples/ world/ examples/ conf/ + manage.py -``game/gamesrc/`` + gamesrc/ + commands/ + examples/ + scripts/ + examples/ + objects/ + examples/ + world/ + examples/ + conf/ + +\`game/gamesrc/\` ~~~~~~~~~~~~~~~~~ ``game/gamesrc`` is where you will be spending most of your time. All @@ -97,7 +110,7 @@ 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/\` ^^^^^^^^^^^^^^^^^^^^^ ``gamesrc/commands/`` contains modules for defining @@ -105,14 +118,14 @@ Evennia. templates for starting to define your own commands and cmdsets. Copy these out into the parent ``command`` folder and work from there. -``gamesrc/scripts/`` +\`gamesrc/scripts/\` ^^^^^^^^^^^^^^^^^^^^ ``gamesrc/scripts/`` holds everything related to `Scripts `_. ``scripts/examples`` holds templates you can make copies of and build from to define your own scripts. -``gamesrc/objects/`` +\`gamesrc/objects/\` ^^^^^^^^^^^^^^^^^^^^ ``gamesrc/objects/`` should contain the definitions for all your @@ -121,7 +134,7 @@ make copies of and build from to define your own scripts. *Exit*. Make copies of these templates to have somthing to start from when defining your own in-game entities. -``gamesrc/world/`` +\`gamesrc/world/\` ^^^^^^^^^^^^^^^^^^ ``gamesrc/world/``, contains all the rest that make up your world. This @@ -142,7 +155,7 @@ formatting. creates a *Red Button* object in *Limbo* using their respective special syntax. -``gamesrc/conf/`` +\`gamesrc/conf/\` ^^^^^^^^^^^^^^^^^ ``gamesrc/conf/`` holds optional extension modules for the Evennia @@ -151,7 +164,7 @@ for the various config files that the server undertands. Each template file contains instructions for how you should use them; copy out the ones you want into the ``conf/`` directory and edit them there. -The ``src/`` directory +The \`src/\` directory ---------------------- ``src/`` contains the main running code of the Evennia server. You can @@ -167,7 +180,19 @@ 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/ + 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 @@ -193,7 +218,7 @@ 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/`` +\`src/commands/\` ~~~~~~~~~~~~~~~~~ This directory contains the `command system `_ of @@ -208,41 +233,41 @@ 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/\` ~~~~~~~~~~~~~~ ``src/comms/`` defines all aspects of OOC `communication `_, notably *channels*, *messages* and the basic operators for connecting external listeners to channels. -``src/help/`` +\`src/help/\` ~~~~~~~~~~~~~ This defines the `help system `_ of Evennia, the command auto-help as well as the database-centric storage of in-game help files. -``src/objects/`` +\`src/objects/\` ~~~~~~~~~~~~~~~~ ``src/objects/`` defines how the in-game `objects `_ are stored, found and handled in the database. -``src/locks/`` +\`src/locks/\` ~~~~~~~~~~~~~~ This directory defines the powerful `lock system `_ of Evennia, a system that serves to restrict access to objects. The default lock functions are found here. -``src/players/`` +\`src/players/\` ~~~~~~~~~~~~~~~~ The `Player `_ is the OOC-represention of the person connected to the game. This directory defines the database handling and methods acting on the Player object. -``src/scripts/`` +\`src/scripts/\` ~~~~~~~~~~~~~~~~ ``src/scripts/`` defines all aspects of `Scripts `_ - how @@ -250,7 +275,7 @@ 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/`` +\`src/server/\` ~~~~~~~~~~~~~~~ This directory is the heart of Evennia. It holds the server process @@ -259,7 +284,7 @@ and protocols `_ that allow users to connect to the game. It also knows how to store dynamic server info in the database. -``src/typeclasses/`` +\`src/typeclasses/\` ~~~~~~~~~~~~~~~~~~~~ ``src/typeclasses/`` defines the `Typeclass system `_ @@ -270,7 +295,7 @@ and Players all inherit from its core classes. Also `attributes `_ are defined here, being an vital part of the typeclass system. -``src/utils/`` +\`src/utils/\` ~~~~~~~~~~~~~~ ``src/utils/`` is a useful directory that contains helper functions for @@ -281,7 +306,7 @@ 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/`` +\`src/web/\` ~~~~~~~~~~~~ This directory contains features related to running Evennia's `web site diff --git a/docs/sphinx/source/wiki/EvenniaDevel.rst b/docs/sphinx/source/wiki/EvenniaDevel.rst index 0ce8f17532..5f35e7a363 100644 --- a/docs/sphinx/source/wiki/EvenniaDevel.rst +++ b/docs/sphinx/source/wiki/EvenniaDevel.rst @@ -51,8 +51,8 @@ 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 +*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 @@ -70,12 +70,12 @@ 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 --------------------------------------------------------------- +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 +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 @@ -85,7 +85,7 @@ 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 +*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 @@ -117,7 +117,9 @@ Example of new command definition: :: - class CmdTest(Command): def func(self): self.caller.msg("This is the test!") + class CmdTest(Command): + def func(self): + self.caller.msg("This is the test!") Events + States -> Scripts -------------------------- @@ -263,14 +265,16 @@ just do: :: - obj.db.attr = value value = obj.db.attr + 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 + 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 @@ -320,7 +324,7 @@ where it might be unclear if you receive a session or a player object (especially during login/logout), you can now use simply use ``msg()`` without having to check (however, you *can* still use ``emit_to`` for legacy code, it's an alias to msg() now). Same is true with -emit\ *to*\ contents() -> msg\ *to*\ contents(). +emit\_to\_contents() -> msg\_to\_contents(). ``source_object`` in default commands are now consistently named *caller* instead. @@ -343,7 +347,7 @@ function into a class and add the parse(self) and func(self) methods 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. +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 diff --git a/docs/sphinx/source/wiki/EvenniaIntroduction.rst b/docs/sphinx/source/wiki/EvenniaIntroduction.rst index c28a1d2217..43e3a732ea 100644 --- a/docs/sphinx/source/wiki/EvenniaIntroduction.rst +++ b/docs/sphinx/source/wiki/EvenniaIntroduction.rst @@ -1,23 +1,26 @@ -"*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 `_ +Introduction -Evennia introduction= + "*A MUD (originally Multi-User Dungeon, with later variants + Multi-User Dimension and Multi-User Domain), pronounced 'mud', is a + multiplayer real-time virtual world described primarily in text. + MUDs combine elements of role-playing games, hack and slash, player + versus player, interactive fiction, and online chat. Players can + read or view descriptions of rooms, objects, other players, + non-player characters, and actions performed in the virtual world. + Players typically interact with each other and the world by typing + commands that resemble a natural language.*\ " - + `Wikipedia `_ + +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 >`_ 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. +(`MUD/MUX/MUSH `_ 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 @@ -54,7 +57,7 @@ LP, MOO and so on. Or why not create a new and better command system of your own design. Can I test it somewhere? -~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------ There are Evennia-based muds under development but they are still not publicly available. If you do try to install Evennia (it's not hard), it @@ -70,7 +73,7 @@ Brief summary of features ========================= Technical -~~~~~~~~~ +--------- - Game development is done by the server importing your normal Python modules. Specific server features are implemented by overloading @@ -95,7 +98,7 @@ Technical - Unit-testing suite, including tests of default commands and plugins Default content -~~~~~~~~~~~~~~~ +--------------- - Basic classes for Objects, Characers, Rooms and Exits - Basic login system, using the Player's login name as their in-game @@ -107,7 +110,7 @@ Default content alternative login, menus, character generation and more Standards/Protocols supported -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------------------- - Telnet with mud-specific extensions (MCCP, MSSP, TTYPE) - SSH diff --git a/docs/sphinx/source/wiki/ExecutePythonCode.rst b/docs/sphinx/source/wiki/ExecutePythonCode.rst index cd49f94434..f79ec7d69d 100644 --- a/docs/sphinx/source/wiki/ExecutePythonCode.rst +++ b/docs/sphinx/source/wiki/ExecutePythonCode.rst @@ -1,4 +1,6 @@ -The ``@py`` command +Running python code parsers for testing and debugging + +The \`@py\` command =================== The ``@py`` command supplied with the default command set of Evennia @@ -10,7 +12,8 @@ to just anybody. :: - @py 1+2 <<< 3 + @py 1+2 + <<< 3 Available variables ------------------- @@ -33,7 +36,8 @@ found in ``src/utils/utils.py``, but also accessible through :: - @py from ev import utils; utils.time_format(33333) <<< Done. + @py from ev import utils; utils.time_format(33333) + <<< Done. Note that we didn't get any return value, all we where told is that the code finished executing without error. This is often the case in more @@ -43,7 +47,9 @@ system to echo it to us explicitly with ``self.msg()``. :: - @py from ev import utils; self.msg(utils.time_format(33333)) 09:15 <<< Done. + @py from ev import utils; self.msg(utils.time_format(33333)) + 09:15 + <<< Done. If you were to use Python's standard ``print``, you will see the result in your current ``stdout`` (your terminal by default), *if* you are @@ -60,7 +66,14 @@ 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 + @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 @@ -69,7 +82,8 @@ entries found in ``ev.search_*``. :: - @py ev.search_script("sys_game_time") <<< [] + @py ev.search_script("sys_game_time") + <<< [] (Note that since this becomes a simple statement, we don't have to wrap it in ``self.msg()`` to get the output). You can also use the database @@ -80,17 +94,19 @@ in each manager. :: - @py ev.db_scripts.script_search("sys_game_time") <<< [] + @py ev.db_scripts.script_search("sys_game_time") + <<< [] The managers are useful for all sorts of database studies. :: - @py ev.db_configvalues.all() <<< [, , ...] + @py ev.db_configvalues.all() + <<< [, , ...] In doing so however, keep in mind the difference between `Typeclasses and Database Objects `_: Using the search commands in -the managers will return *!TypeClasses*. Using Django's default search +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 @@ -98,7 +114,15 @@ most situations. :: - # this uses Evennia's manager method get_id(). # It returns a Character typeclass instance @py ev.db_objects.get_id(1).__class__ <<< Character# this uses the standard Django get() query. # It returns a django database model instance. @py ev.db_objects.get(id=1).__class__ <<< + # this uses Evennia's manager method get_id(). + # It returns a Character typeclass instance + @py ev.db_objects.get_id(1).__class__ + <<< Character + + # this uses the standard Django get() query. + # It returns a django database model instance. + @py ev.db_objects.get(id=1).__class__ + <<< Running a Python Parser outside the game ======================================== @@ -124,5 +148,12 @@ tab-completion and ``__doc__``-string reading. :: - $ python manage.py shellIPython 0.10 -- An enhanced Interactive Python ...In [1]: import ev In [2]: ev.db_objects.all() Out[3]: [, , ...] + $ python manage.py shell + + IPython 0.10 -- An enhanced Interactive Python + ... + + In [1]: import ev + In [2]: ev.db_objects.all() + Out[3]: [, , ...] diff --git a/docs/sphinx/source/wiki/GettingStarted.rst b/docs/sphinx/source/wiki/GettingStarted.rst index d08825b13d..3ea68494c1 100644 --- a/docs/sphinx/source/wiki/GettingStarted.rst +++ b/docs/sphinx/source/wiki/GettingStarted.rst @@ -49,46 +49,51 @@ platform, please let us know. You'll need the following packages and minimum versions in order to run Evennia: -**Python** (http://www.python.org) +- **Python** (`http://www.python.org `_) -- Version 2.5+. Obs- Python3.x is not supported. -- Windows users are recommended to use ActivePython - (http://www.activestate.com/activepython/downloads) + - Version 2.6+. Obs- Python3.x is not supported. + - Windows users are recommended to use ActivePython + (`http://www.activestate.com/activepython/downloads `_) -**Twisted** (http://twistedmatrix.com) +- **Twisted** (`http://twistedmatrix.com `_) -Version 10.0+ + - Version 10.0+ + - Twisted also requires: -Twisted also requires: + - ZopeInterface 3.0+ + (`http://www.zope.org/Products/ZopeInterface `_) + - For Windows only: pywin32 + (`http://sourceforge.net/projects/pywin32 `_) -- !ZopeInterface 3.0+ (http://www.zope.org/Products/ZopeInterface) -- For Windows only: pywin32 (http://sourceforge.net/projects/pywin32) +- **Django** + (`http://www.djangoproject.com `_) -**Django** (http://www.djangoproject.com) - -- Version 1.2.5+ or latest development versions highly recommended. -- PIL (Python Imaging Library) (http://www.pythonware.com/products/pil) - - not strictly required unless you use images in Django. + - Version 1.3+ or latest development versions highly recommended. + - PIL (Python Imaging Library) + (`http://www.pythonware.com/products/pil `_) + - not strictly required unless you use images in Django. To download/update Evennia: -**Mercurial** (http://mercurial.selenic.com/) +- **Mercurial** + (`http://mercurial.selenic.com/ `_) -- This is needed to download and update Evennia itself. + - This is needed to download and update Evennia itself. Optional packages: -**South** (http://south.aeracode.org/) +- **South** + (`http://south.aeracode.org/ `_) -- Version 0.7+ -- Optional, but highly recommended. Used for database migrations. + - Version 0.7+ + - Optional, but highly recommended. Used for database migrations. -**Apache2** (http://httpd.apache.org) +- **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. + - 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. Installing pre-requisites ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -96,10 +101,10 @@ Installing pre-requisites **All platforms** can set up an *virtual Python environment* and install Evennia to that. All you need pre-installed is Python. Setup is described in detail -`here Aseparateinstallationenvironmentwithvirtualenv.html>`_. -Windows users will probably want to go the ActivePython way instead -though (see below), there are issues with installing certain extensions -in Windows. +[`GettingStarted `_\ #Optional:\ *A\_separate\_installation\_environment\_with\_virtualenv +here]. Windows users will probably want to go the ActivePython way +instead though (see below), there are issues with installing certain +extensions in Windows.* **Linux** package managers should usually handle all this for you. Python itself is definitely available through all distributions. On @@ -108,23 +113,23 @@ Debian-derived systems (such as Ubuntu) you can do something like this :: - apt-get install python python-django python-twisted mercurial python-django-south + apt-get install python python-django python-twisted mercurial python-django-south Few distros actually keep the latest updated security updates (notably django and twisted) in their repos though. So it might be worth to use Python's -`easyinstall install.html>`_ +`easy\_install `_ or the alternative `pip `_ to get some or all of these instead: :: - easy_install django twisted pil mercurial south + easy_install django twisted pil mercurial south :: - pip install django twisted pil mercurial south + pip install django twisted pil mercurial south If you already have Python and mercurial, and have downloaded Evennia, the package comes with a ``requirements.txt`` file. This can be used @@ -133,19 +138,35 @@ automated build systems): :: - pip install -r requirements.txt + pip install -r requirements.txt **Mac** users should be able to get most dependencies through -``easy_install`` or ``pip`` like Linux users do. There are however -reports that you might need to get the -`Xcode `_ development system to -install the packages that requires extension compiling. You can also +``easy_install`` or ``pip`` like Linux users do. All interaction is done +from a terminal window. There are some reports that you might need to +get the `Xcode `_ development system +to install the packages that requires extension compiling. You can also retrieve the dependencies directly and install them through their native installers or python setups. Some users have reported problems compiling -the ``PIL`` library on Mac, it's however not strictly required to use -Django. +the ``PIL`` library on Mac, it's however not strictly required in order +to use Django (it's used for images). -**Windows** users may want to install +\_Note (June 2012): Some versions of MacOSX does not seem to have a +locale setting out of the box, and this causes a traceback during +database creation. This is a known upstream bug in Django 1.4, described +`here `_. +In the bug comments is also described how to add the locale and +circumvent this bug for now. This affects also Unix/Linux systems, but +those usually have the locale set out of the box. + +**Windows** users should first and foremost recognize that the Evennia +server is run from the command line, something which they might not be +familiar with. In the Windows launch menu, just start *All Programs -> +Accessories -> command prompt* and you will get the Windows command line +interface. There are plenty of online tutorials on using the Windows +command line, one example is found +`here `_. + +Windows users may want to install `ActivePython `_ instead of the usual Python. Get the 32-bit version (it seems the 64-bit one won't let you download any packages without paying for a "Business" @@ -154,12 +175,13 @@ license). If ActivePython is installed, you can use same manner as ``easy_install``/``pip`` above. This *greatly* simplifies getting started on Windows since that platform is by default missing many of the sane developer systems that Linux users take for granted. -After installing ActivePython you may need to open a new DOS window to -make this new command available on the command line: + +After installing ActivePython you may need to restart the terminal/DOS +window to make the pypm command available on the command line: :: - pypm install Django Twisted PIL Mercurial South + pypm install Django Twisted PIL Mercurial South This installs everything you need in one go. @@ -183,7 +205,7 @@ trick (first place yourself in a directory where you want a new folder :: - hg clone https://code.google.com/p/evennia/ evennia + hg clone https://code.google.com/p/evennia/ evennia (Mercurial is abbreviated ``hg`` since this is the chemical symbol for mercury). @@ -192,7 +214,8 @@ In the future, you just do :: - hg pull hg update + hg pull + hg update from your ``evennia/`` directory to obtain the latest updates. @@ -210,7 +233,7 @@ the automatic creation of an empty ``settings.py`` file. :: - python manage.py + 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 @@ -239,7 +262,7 @@ with the standard tables and values: :: - python manage.py syncdb + python manage.py syncdb You should be asked for a superuser username, email, and password. Make **sure** you create a superuser here when asked, this becomes your login @@ -253,7 +276,7 @@ need to do this: :: - python manage.py migrate + python manage.py migrate This will migrate the server to the latest version. If you don't use ``South``, migrations will not be used and your server will already be @@ -268,7 +291,7 @@ and execute ``evennia.py`` like this: :: - python evennia.py -i start + python evennia.py -i start This starts the server and portal. The ``-i`` flag means that the server starts in *interactive mode*, as a foreground process. You will see @@ -279,11 +302,11 @@ To stop Evennia, do: :: - python evennia.py stop + python evennia.py stop See `Running -Evennia `_ -for more advanced options on controlling Evennia's processes. +Evennia `_ for +more advanced options on controlling Evennia's processes. Step 4: Connecting to the server -------------------------------- @@ -310,7 +333,7 @@ Apart from installing the packages and versions as above, you can also set up a very easy self-contained Evennia install using the `virtualenv `_ program. If you are unsure how to get it, just grab the -`virtualenv.py `_ +`virtualenv.py `_ file from that page and run it directly in the terminal with ``python virtualenv.py``. @@ -341,7 +364,10 @@ virtual environment in here. :: - # for Linux/Unix: source bin/activate # for Windows: \Scripts\activate.bat + # for Linux/Unix: + source bin/activate + # for Windows: + \Scripts\activate.bat The virtual environment within our *mudenv* folder is now active. Next we get all the requirements with *pip*, which is included with diff --git a/docs/sphinx/source/wiki/HelpSystem.rst b/docs/sphinx/source/wiki/HelpSystem.rst index 875c376117..1e0519b438 100644 --- a/docs/sphinx/source/wiki/HelpSystem.rst +++ b/docs/sphinx/source/wiki/HelpSystem.rst @@ -1,4 +1,4 @@ -*How to use Evennia's help system* +Evennia's help system Help system =========== @@ -17,7 +17,7 @@ The main command is ``help``. :: - help [searchstring] + 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* @@ -49,7 +49,24 @@ Example (from a module with command definitions): :: - class CmdMyCmd(Command): """ mycmd - my very own command Usage: mycmd[/switches] 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" ... + class CmdMyCmd(Command): + """ + mycmd - my very own command + + Usage: + mycmd[/switches] + + 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" + ... The text at the very top of the command class definition is the class' ``__doc__``-string and will be shown to users looking for help. Try to @@ -89,7 +106,10 @@ You can create new help entries in code by using :: - from src.utils import create entry = create.create_help_entry("emote", "Emoting is important because ...", category="Roleplaying", locks="view:all()"): + 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. diff --git a/docs/sphinx/source/wiki/HowToGetAndGiveHelp.rst b/docs/sphinx/source/wiki/HowToGetAndGiveHelp.rst index 96034b72a4..87fc2e8f65 100644 --- a/docs/sphinx/source/wiki/HowToGetAndGiveHelp.rst +++ b/docs/sphinx/source/wiki/HowToGetAndGiveHelp.rst @@ -1,24 +1,18 @@ Getting and giving Evennia-help -How to *get* Help -================= +How to \_get\_ Help +=================== If you cannot find what you are looking for in the `online documentation `_, here's what to do: - If you think the documentation is not clear enough, fill in our quick - little "https://docs.google.com/spreadsheet/viewform?hl - - en\ *US&formkey* - - dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid - ====================================== - - 0.html">online form and say so (no login required). Maybe the docs - need to be improved or a new tutorial added! Note that this form will - help you by helping us improve documentation, but you cannot get - direct, specific answers back from it. - + little `online + form `_ + and say so (no login required). Maybe the docs need to be improved or + a new tutorial added! Note that this form will help you by helping us + improve documentation, but you cannot get direct, specific answers + back from it. - If you have trouble with a missing feature or a problem you think is a bug, go to the `issue tracker `_. If you @@ -31,15 +25,14 @@ documentation `_, here's what to do: 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! + `#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 -================== +How to \_give\_ Help +==================== Evennia is a completely un-funded project. It relies on the time donated by its users and developers in order to progress. @@ -60,10 +53,9 @@ to get going: you can help improve or expand the documentation (even small things like fixing typos!). - Send a message to our - `forum `_ and/or our - "http://webchat.freenode.net/?channels - evennia">IRC chat asking about what needs doing, along with what your - interests and skills are. + `forum `_ and/or our `IRC + chat `_ asking about + what needs doing, along with what your interests and skills are. - Take a look at our `issue tracker `_ and see if there's something you feel like taking on. diff --git a/docs/sphinx/source/wiki/IMC2.rst b/docs/sphinx/source/wiki/IMC2.rst index 3c7e5474d6..baf648b2a5 100644 --- a/docs/sphinx/source/wiki/IMC2.rst +++ b/docs/sphinx/source/wiki/IMC2.rst @@ -1,7 +1,9 @@ +Introduction to and configuration for IMC2. + IMC2 ==== -`IMC2 `_, *!InterMud +`IMC2 `_, *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 @@ -65,11 +67,11 @@ could also use an existing channel like ``ooc`` if you wanted): :: - @ccreate imc2 = This is connected to an IMC2 channel! + @ccreate imc2 = This is connected to an IMC2 channel! You should join the channel automatically. -Setting up a Channel ``<->`` IMC2 binding +Setting up a Channel \`<->\` IMC2 binding ----------------------------------------- Evennia developers have an open-access IMC channel called ``ievennia`` @@ -81,12 +83,12 @@ Activating IMC2 have made new commands available, the one you need is 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. + Let's connect our new ``imc2`` channel to the ``ievennia`` channel + on Server01. :: - @imc2chan imc2 = ievennia + @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 @@ -101,7 +103,7 @@ To permanently remove a connection, use ``@imc2chan`` with the :: - @imc2chan/delete imc2 = ievennia + @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 diff --git a/docs/sphinx/source/wiki/IRC.rst b/docs/sphinx/source/wiki/IRC.rst index e20f6a632b..7dc773a5a3 100644 --- a/docs/sphinx/source/wiki/IRC.rst +++ b/docs/sphinx/source/wiki/IRC.rst @@ -1,9 +1,11 @@ +Configuring IRC connectivity + IRC === `IRC (Internet Relay -Chat) RelayChat>`_ is a -long standing chat protocol used by many open-source projects for +Chat) `_ is a long +standing chat protocol used by many open-source projects for communicating in real time. By connecting one of Evennia's `Channels `_ to an IRC channel you can communicate also with people not on an mud themselves. Note that you can use IRC @@ -27,7 +29,7 @@ command availabele: ``@irc2chan``. This command is called like this: :: - @irc2chan[/switches] = <#irchannel> + @irc2chan[/switches] = <#irchannel> If you already know how IRC works, this should be pretty self-evident to use. Read the help entry for more features. @@ -40,7 +42,7 @@ up a new channel ``irc``. :: - @ccreate irc = This is connected to an irc channel! + @ccreate irc = This is connected to an irc channel! You will automatically join the new channel. @@ -75,7 +77,7 @@ Next we connect Evennia with the IRC channel. :: - @irc2chan irc = irc.freenode.net 6667 #myevennia-test mud-bot + @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 @@ -85,7 +87,8 @@ Write something in the Evennia channel *irc*. :: - irc Hello, World! [irc] Anna: Hello, World! + 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: @@ -100,6 +103,7 @@ normal channel, marked with the name of the IRC channel you used :: + [irc] Anna@#myevennia-test: Hello! Your Evennia gamers can now chat with users on external IRC channels! diff --git a/docs/sphinx/source/wiki/Index.rst b/docs/sphinx/source/wiki/Index.rst index 261e6b0fe7..0b76ef7ebd 100644 --- a/docs/sphinx/source/wiki/Index.rst +++ b/docs/sphinx/source/wiki/Index.rst @@ -4,15 +4,8 @@ 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. If you have trouble with unclear documentation, fill in our quick -"https://docs.google.com/spreadsheet/viewform?hl - -en\_US&formkey - -dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid -====================================== - -0.html">online form and tell us so - maybe more details or a new -tutorial is needed! +`online form `_ and tell us so - maybe more +details or a new tutorial is needed! The documentation is divided into several main categories. If you are new, it might be an idea to browse the sections in the order they are @@ -35,4 +28,7 @@ Sections - The `Developer Central `_ covers implementation details and guides of interest for game-world coders as well as for current and prospective Evennia developers. +- The `Tutorials & Examples `_ section summarizes help + pages on a step-by-step or tutorial format. Some of these are + reachable from their respective sections as well. diff --git a/docs/sphinx/source/wiki/Internationalization.rst b/docs/sphinx/source/wiki/Internationalization.rst index 33785a8c04..3e1eab5837 100644 --- a/docs/sphinx/source/wiki/Internationalization.rst +++ b/docs/sphinx/source/wiki/Internationalization.rst @@ -1,3 +1,5 @@ +changing and creating new translations + Internationalization ==================== @@ -9,23 +11,25 @@ without anyone having to go in and add it manually. Take a look at the 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. Adding -*i18n* code to commands tend to add complexity to code that will be -changed anyway. One of the goals of Evennia is to keep the -user-changeable code as clean and easy-to-read as possible. +server, things like "Connection closed" or "Server restarted" - things +that Players will see and which game devs are not supposed to change on +their own. So stuff seen in the log file or on stdout will not be +translated. It also means that the default command set is *not* +translated. The reason for this is that commands are *intended* to be +modified by users. Adding *i18n* code to commands tend to add complexity +to code that will be changed anyway. One of the goals of Evennia is to +keep the user-changeable code as clean and easy-to-read as possible. Changing server language ------------------------ -Change language by copy&pasting the following from the default file to -your ``game/settings.py`` file: +Change language by adding the following to your ``game/settings.py`` +file: :: - USE_I18N = True LANGUAGE_CODE = 'en' + 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 @@ -43,7 +47,7 @@ and run :: - django-admin makemessages -l + django-admin makemessages -l where ```` is the two-letter locale code for the language you want, like 'sv' for Swedish or 'es' for Spanish. @@ -55,7 +59,11 @@ normal text editor -- best is to use a po-file editor from the web 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. +translation best you can. The ``*.po`` format (and many supporting +editors) allow you to mark translations as "fuzzy". This tells the +system (and future translators) that you are unsure about the +translation, or that you couldn't find a translation that exactly +matched the intention of the original text. Finally, you need to compile your translation into a more efficient form. diff --git a/docs/sphinx/source/wiki/Licensing.rst b/docs/sphinx/source/wiki/Licensing.rst index 290debcc38..23701f63af 100644 --- a/docs/sphinx/source/wiki/Licensing.rst +++ b/docs/sphinx/source/wiki/Licensing.rst @@ -1,3 +1,5 @@ +The Licensing of Evennia + Evennia Licence FAQ =================== @@ -14,7 +16,7 @@ Q: When creating a game using Evennia, what does the licence permit me to do wit **A:** It's your own game world to do with as you please! To summarize, a MUD world you create using Evennia (i.e. the files you create in -``/game/``) falls under **§6** of the license (it's a sort of +``/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. @@ -25,12 +27,12 @@ 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, +- 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 bigger modifications or added new features to the server, - that's also ok, but falls under **§3** - you must make a clear note + that's also ok, but falls under **§3** - you must make a clear note of the changes you did and put those changes into public domain (since it's then no longer a "Standard version"). You could also contact the Evennia developers to make separate arrangements ... but @@ -40,7 +42,7 @@ is referred to as "The Package, Standard version" in the license. Q: Can I re-distribute the Evennia server package along with my custom game implementation? ------------------------------------------------------------------------------------------- -**A:** Sure. This is covered in **§4** - just package the "Standard +**A:** Sure. This is covered in **§4** - just package the "Standard version" (that is, the one you download from us) with your game files. Also make sure to include the original license and disclaimers and note where users may get "plain" Evennia should they want to download it of diff --git a/docs/sphinx/source/wiki/Links.rst b/docs/sphinx/source/wiki/Links.rst index 58bdfe07ef..ae2464503e 100644 --- a/docs/sphinx/source/wiki/Links.rst +++ b/docs/sphinx/source/wiki/Links.rst @@ -1,3 +1,5 @@ +External links + External links and resources ============================ @@ -61,19 +63,23 @@ General mud/game development ideas and discussions blog with long and interesting articles (not MUD-specific) - `What Games Are `_ is a blog about general game design (not MUD-specific) +- `The Alexandrian `_ is a blog about + tabletop roleplaying and board games, but with lots of general + discussion about rule systems and game balance that could be + applicable also for MUDs. Frameworks ---------- -`Django's homepage `_ +- `Django's homepage `_ -- `Documentation `_ -- `Code `_ + - `Documentation `_ + - `Code `_ -`Twisted homepage `_ +- `Twisted homepage `_ -- `Documentation `_ -- `Code `_ + - `Documentation `_ + - `Code `_ Tools ----- @@ -87,10 +93,11 @@ Tools Python Info ----------- -`Python Website `_ +- `Python Website `_ + + - `Documentation `_ + - `Tutorial `_ + - `Library Reference `_ + - `Language Reference `_ -- `Documentation `_ -- `Tutorial `_ -- `Library Reference `_ -- `Language Reference `_ diff --git a/docs/sphinx/source/wiki/Locks.rst b/docs/sphinx/source/wiki/Locks.rst index ba66ddc68d..208bd27534 100644 --- a/docs/sphinx/source/wiki/Locks.rst +++ b/docs/sphinx/source/wiki/Locks.rst @@ -1,3 +1,5 @@ +Locks and Permissions + Locks ===== @@ -6,8 +8,8 @@ Evennia such restrictions are applied and checked by something called *locks*. All Evennia entities (`commands `_, `objects `_, `scripts `_, `players `_, `help system `_, -`messages `_ and -`channels `_) are accessed through locks. +[Communications#Msg messages] and [Communications#Channels channels]) +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 @@ -32,7 +34,7 @@ The in-game command for setting locks on objects is ``@lock``: :: - > @lock obj = + > @lock obj = The ```` is a string on a certain form that defines the behaviour of the lock. We will go into more detail on how @@ -44,7 +46,7 @@ add, delete and check locks. :: - myobj.locks.add() + myobj.locks.add() One can call ``locks.check()`` to perform a lock check, but to hide the underlying implementation all objects also have a convenience function @@ -55,7 +57,9 @@ do) look from inside the ``@delete`` command: :: - if not obj.access(accessing_obj, 'delete'): accessing_obj.msg("Sorry, you may not delete that.") return + if not obj.access(accessing_obj, 'delete'): + accessing_obj.msg("Sorry, you may not delete that.") + return Defining locks -------------- @@ -68,13 +72,15 @@ Here are some examples of lock strings (not including the quotes): :: - 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 + 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 Formally, a lockstring has the following syntax: :: - access_type:[not] func1([arg1,..])[[and|or][ not] func2([arg1,...])[...]] + 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 @@ -110,47 +116,50 @@ tries, as in the example of ``@delete`` above that uses the 'delete' Below are the access\_types checked by the default commandset. -`Commands `_: ``cmd`` - this defines who may call this -command at all. +- `Commands `_: ``cmd`` - this defines who may call this + command at all. +- `Objects `_: -`Objects `_: + - ``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". + - ``attrcreate`` - allows to create new objects on object (default + True) -- ``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". +- [Objects#Characters Characters]: ```` +- [Objects#Exits Exits]: ```` + ``traverse`` - who may + pass the exit. +- `Players `_: -`Characters `_: ```` + - ``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. -`Exits `_: ```` + ``traverse`` - -who may pass the exit. +- `Attributes `_: (*only checked by + ``obj.secure_attr``*) -`Players `_: + - ``attrread`` - see/access attribute + - ``attredit`` - change/delete attribute -- ``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. +- [Communications#Channels Channels]: -`Attributes `_: ```` + - ``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. -`Channels `_: +- `HelpEntry `_: -- ``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 `_: - -- ``examine`` - who may view this help entry (usually everyone) -- ``edit`` - who may edit this help entry. + - ``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 @@ -176,7 +185,13 @@ 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 + # 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 @@ -189,17 +204,17 @@ Some useful default lockfuncs (see ``src/locks/lockfuncs.py`` for more): - ``false()/none()/superuser()`` - give access to noone. Superusers bypass the check entirely. - ``perm(perm)`` - this tries to match a given ``permission`` property. - See `below `_. + See [Locks#Permissions below]. - ``perm_above(perm)`` - requres a "higher" permission level than the one given. -- ``id(num)/dbref(num)`` - checks so the accessobject has a certain +- ``id(num)/dbref(num)`` - checks so the access\_object has a certain dbref/id. - ``attr(attrname)`` - checks if a certain - `Attribute `_ exists on accessingobject. + `Attribute `_ exists on accessing\_object. - ``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. + accessing\_object *and* has the given value. +- ``attr_gt(attrname, value)`` - checks so accessing\_object 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 @@ -233,7 +248,7 @@ set by the ``@perm`` command. :: - @perm Tommy = Builders + @perm Tommy = Builders All new players/character are given a default set of permissions defined by ``settings.PERMISSION_PLAYER_DEFAULT``. @@ -244,7 +259,11 @@ default permission hierarchy is as follows: :: - Immortals Wizards Builders PlayerHelpers Players # this is what all new Players start with by default + 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 @@ -257,7 +276,10 @@ 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! + obj1.permissions = ["Builders", "cool_guy"] + obj2.locks.add("enter:perm_above(Players) and perm(cool_guy)") + + obj2.access(obj1, "enter") # this returns True! Superusers ---------- @@ -293,7 +315,7 @@ their use of this particular command henceforth. :: - open: holds('the green key') or perm(Builder) + 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 @@ -328,7 +350,8 @@ other is an `Object `_ called ``box``. :: - > @create/drop box > @desc box = "This is a very big and heavy 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 @@ -337,7 +360,7 @@ ourselves to begin with. :: - > @set self/strength = 45 + > @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 @@ -347,16 +370,21 @@ 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 + 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 `_ on the -checked object called *get*\ err\ *msg* in order to return a customized +checked object called *get\_err\_msg* in order to return a customized error message. Sounds good! Let's start by setting that on the box: :: - > @set box/get_err_msg = You are not strong enough to lift this 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 @@ -370,7 +398,7 @@ We put this on the box now: :: - @lock box = get:attr_gt(strength, 50) + @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 @@ -381,7 +409,19 @@ like this: :: - from ev import create_objectbox = create_object(None, key="box") box.locks.add("get:attr_gt(strength, 50)")# or we can assign locks right away box = create_object(None, key="box", locks="get:attr_gt(strength, 50)")# set the attributes box.db.desc = "This is a very big and heavy box." box.db.get_err_msg = "You are not strong enough to lift this box."# one heavy box, ready to withstand all but the strongest... + from ev import create_object + + box = create_object(None, key="box") + box.locks.add("get:attr_gt(strength, 50)") + + # or we can assign locks right away + box = create_object(None, key="box", locks="get:attr_gt(strength, 50)") + + # set the attributes + box.db.desc = "This is a very big and heavy box." + box.db.get_err_msg = "You are not strong enough to lift this box." + + # one heavy box, ready to withstand all but the strongest... On Django's permission system ============================= diff --git a/docs/sphinx/source/wiki/Nicks.rst b/docs/sphinx/source/wiki/Nicks.rst index 5bf67b21db..46e14c6f80 100644 --- a/docs/sphinx/source/wiki/Nicks.rst +++ b/docs/sphinx/source/wiki/Nicks.rst @@ -1,3 +1,5 @@ +Using nicknames + Nicks ===== @@ -29,7 +31,7 @@ command): :: - nick ls = look + 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 @@ -37,26 +39,26 @@ This is a good one for unix/linux users who are accustomed to using the :: - nick/object mycar2 = The red sports car + 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 + look mycar2 becomes equivalent to "``look The red sports car``\ ". :: - nick/players tom = Thomas Johnsson + nick/players tom = Thomas Johnsson This is useful for commands searching for players explicitly: :: - @find *tom + @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 @@ -64,26 +66,42 @@ to execute that whole long string. :: - nick rb = @create button:examples.red_button.RedButton + 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 + 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 `_ through the ``nicks`` -property. ``nicks`` is a special handler that offers effective error +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") + # 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 diff --git a/docs/sphinx/source/wiki/Objects.rst b/docs/sphinx/source/wiki/Objects.rst index 305ef3a9c1..3a9e993fb3 100644 --- a/docs/sphinx/source/wiki/Objects.rst +++ b/docs/sphinx/source/wiki/Objects.rst @@ -1,3 +1,5 @@ +Object typeclass + Objects ======= @@ -19,7 +21,16 @@ Here's how to define a new Object typeclass in code: :: - from ev import Objectclass Rose(Object): """ This creates a simple rose object """ def at_object_creation(self): "this is called only once, when object is first created" # add a persistent attribute 'desc' to object. self.db.desc = "This is a pretty rose with thorns." + from ev import Object + + class Rose(Object): + """ + This creates a simple rose object + """ + def at_object_creation(self): + "this is called only once, when object is first created" + # add a persistent attribute 'desc' to object. + self.db.desc = "This is a pretty rose with thorns." Save your class to a module under ``game/gamesrc/objects``, say ``flowers.py``. Now you just need to point to the class *Rose* with the @@ -27,178 +38,10 @@ Save your class to a module under ``game/gamesrc/objects``, say :: - > @create/drop MyRose:flowers.Rose + > @create/drop MyRose:flowers.Rose To create a new object in code, use the method ``ev.create_object`` (a -shortcut to src.utils.create.create\_object() - -:: - - ):from ev import create_object new_rose = create_object("game.gamesrc.objects.flowers.Rose", key="MyRose") - -(You have to give the full path to the class in this case - -``create.create_object`` is a powerful function that should be used for -all coded creating, for example if you create your own command that -creates some objects as it runs. Check out the ``ev.create_*`` -functions. - -This particular Rose class doesn't really do much, all it does it make -sure the attribute ``desc``\ (which is what the ``look`` command looks -for) is pre-set, which is pretty pointless since you will usually want -to change this at build time (using the ``@describe`` command). The -``Object`` typeclass offers many more hooks that is available to use -though - see next section. - -If you define a new Object class (inheriting from the base one), and -wants the default create command (``@create``) to default to that -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 `_ objects, the Object also has the -following custom properties: - -- ``aliases`` - a list of alternative names for the object. Aliases are - stored in the database and can be searched for very fast. 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 containing 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 safety. -- ``destination`` - this holds a reference to another object this - object links to in some way. Its main use is for - `Exits `_, it's otherwise usually unset. -- ``nicks`` - as opposed to aliases, a `Nick `_ holds a - convenient nickname replacement for a real name, word or sequence, - only valid for this object. This mainly makes sense if the Object is - used as a game character - it can then store briefer shorts, example - so as to quickly reference game commands or other characters. 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. In code, 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 `_ controlling this object (if any). Note that - this is set also if the controlling player is *not* currently online - - to test if a player is online, use the ``has_player`` property - 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 (it may be more than one if multiple connections are - allowed in settings). -- ``permissions`` - a list of `permission strings `_ for - defining access rights for this Object. -- ``has_player`` - a shorthand for checking if an *online* player is - currently connected to this object. -- ``contents`` - this returns a list referencing all objects 'inside' - this object (i,e. 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 `_ defined on the object (if any). -- ``scripts`` - this is a handler that manages - `scripts `_ attached to the object (if any). - -The Object also has a host of useful utility functions. See the function -headers in ``src/objects/objects.py`` for their arguments and more -details. - -- ``msg()`` - this function is used to send messages from the server to - a player connected to this object. -- ``msg_contents()`` - calls ``msg`` on all objects inside this object. -- ``search()`` - this is a convenient shorthand to search for a - specific object, at a given location or globally. It's mainly useful - when defining commands (in which case the object executing the - command is named ``caller`` and one can do ``caller.search()`` to - find objects in the room to operate on). -- ``execute_cmd()`` - Lets the object execute the given string as if it - 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 `_ 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()``. - -The Object Typeclass defines many more *hook methods* beyond -``at_object_creation``. Evennia calls these hooks at various points. -When implementing your custom objects, you will inherit from the base -parent and overload these hooks with your own custom code. See -``src.objects.objects`` 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 (there is nothing stopping you -from redefining them though). In practice they are all pretty similar to -the base Object. - -Characters -~~~~~~~~~~ - -Characters are objects controlled by `Players `_. 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 `_ set on itself at creation, or -the player will not be able to issue any commands! If you just inherit -your own class from ``ev.Character`` and make sure the parent methods -are not stopped from running you should not have to worry about this. -You can change the default typeclass assigned to new Players in your -settings with ``BASE_CHARACTER_TYPECLASS``. - -Rooms -~~~~~ - -*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 ``ev.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 `_ 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 `_ using an access\ *type -called*\ traverse\_ and also make use of a few hook methods for giving -feedback if the traversal fails. See ``ev.Exit`` for more info, that is -also what you should inherit from to make custom exit types. Change the -default class used by e.g. ``@dig`` and ``@open`` by editing -``BASE_EXIT_TYPECLASS`` in your settings. - -Further notes -------------- - -For a more advanced example of a customized object class, see -``game/gamesrc/objects/examples/red_button.py``. +shortcut to +src.utils.create.create\_object()\ ``): {{{ from ev import create_object new_rose = create_object("game.gamesrc.objects.flowers.Rose", key="MyRose") }}} (You have to give the full path to the class in this case - ``\ create.create\_object\ `` is a powerful function that should be used for all coded creating, for example if you create your own command that creates some objects as it runs. Check out the ``\ ev.create\_\ **`` functions. This particular Rose class doesn't really do much, all it does it make sure the attribute ``\ desc\ ``(which is what the ``\ look\ `` command looks for) is pre-set, which is pretty pointless since you will usually want to change this at build time (using the ``\ @describe\ `` command). The ``\ Object\ `` typeclass offers many more hooks that is available to use though - see next section. If you define a new Object class (inheriting from the base one), and wants the default create command (``\ @create\ ``) to default to that 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 [Typeclasses typeclassed] objects, the Object also has the following custom properties: * ``\ aliases\ `` - a list of alternative names for the object. Aliases are stored in the database and can be searched for very fast. 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 containing 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 safety. * ``\ destination\ `` - this holds a reference to another object this object links to in some way. Its main use is for [Objects#Exits Exits], it's otherwise usually unset. * ``\ nicks\ `` - as opposed to aliases, a [Nicks Nick] holds a convenient nickname replacement for a real name, word or sequence, only valid for this object. This mainly makes sense if the Object is used as a game character - it can then store briefer shorts, example so as to quickly reference game commands or other characters. 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. In code, 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 [Players Player] controlling this object (if any). Note that this is set also if the controlling player is _not_ currently online - to test if a player is online, use the ``\ has\_player\ `` property 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 (it may be more than one if multiple connections are allowed in settings). * ``\ permissions\ `` - a list of [Locks permission strings] for defining access rights for this Object. * ``\ has\_player\ `` - a shorthand for checking if an _online_ player is currently connected to this object. * ``\ contents\ `` - this returns a list referencing all objects 'inside' this object (i,e. 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 [Commands#Command_Sets command sets] defined on the object (if any). * ``\ scripts\ `` - this is a handler that manages [Scripts scripts] attached to the object (if any). The Object also has a host of useful utility functions. See the function headers in ``\ src/objects/objects.py\ `` for their arguments and more details. * ``\ msg()\ `` - this function is used to send messages from the server to a player connected to this object. * ``\ msg\_contents()\ `` - calls ``\ msg\ `` on all objects inside this object. * ``\ search()\ `` - this is a convenient shorthand to search for a specific object, at a given location or globally. It's mainly useful when defining commands (in which case the object executing the command is named ``\ caller\ `` and one can do ``\ caller.search()\ `` to find objects in the room to operate on). * ``\ execute\_cmd()\ `` - Lets the object execute the given string as if it 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 [Objects#Exits Exits] 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()\ ``. The Object Typeclass defines many more _hook methods_ beyond ``\ at\_object\_creation\ ``. Evennia calls these hooks at various points. When implementing your custom objects, you will inherit from the base parent and overload these hooks with your own custom code. See ``\ src.objects.objects\ `` 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 (there is nothing stopping you from redefining them though). In practice they are all pretty similar to the base Object. === Characters === Characters are objects controlled by [Players]. 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 [Commands#Command_Sets Default Commandset] set on itself at creation, or the player will not be able to issue any commands! If you just inherit your own class from ``\ ev.Character\ `` and make sure the parent methods are not stopped from running you should not have to worry about this. You can change the default typeclass assigned to new Players in your settings with ``\ BASE\_CHARACTER\_TYPECLASS\ ``. === Rooms === _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 ``\ ev.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 [Commands Transit Command] 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 [Locks locked] using an access_type called _traverse_ and also make use of a few hook methods for giving feedback if the traversal fails. See ``\ ev.Exit\ `` for more info, that is also what you should inherit from to make custom exit types. Change the default class used by e.g. ``\ @dig\ `` and ``\ @open\ `` by editing ``\ BASE\_EXIT\_TYPECLASS\ `` in your settings. == Further notes == For a more advanced example of a customized object class, see ``\ game/gamesrc/objects/examples/red\_button.py\ ````.** diff --git a/docs/sphinx/source/wiki/Players.rst b/docs/sphinx/source/wiki/Players.rst index a21f61fee9..ebbf72e3b1 100644 --- a/docs/sphinx/source/wiki/Players.rst +++ b/docs/sphinx/source/wiki/Players.rst @@ -1,3 +1,5 @@ +Player typeclass + Players ======= @@ -18,10 +20,12 @@ 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 `_ from the Character they control -(in the first character you create permissions for Player and Character -are the same, however). +character. + +Also note that the Player object can have a different set of +[Locks#Permissions Permissions] from the Character they control (in the +first character you create permissions for Player and Character are the +same, however). How to create your own Player types ----------------------------------- @@ -40,7 +44,19 @@ Here's how to define a new Player typeclass in code: :: - from ev import Player class ConfigPlayer(Player): """ This creates a Player with some configuration options """ at_player_creation(self): "this is called only once, when player is first created" self.db.real_name = None # this is set later self.db.real_address = None # '' self.db.config_1 = True # default config self.db.config_2 = False # " self.db.config_3 = 1 # " # ... whatever else our game needs to know + from ev import Player + class ConfigPlayer(Player): + """ + This creates a Player with some configuration options + """ + at_player_creation(self): + "this is called only once, when player is first created" + self.db.real_name = None # this is set later + self.db.real_address = None # '' + self.db.config_1 = True # default config + self.db.config_2 = False # " + self.db.config_3 = 1 # " + # ... whatever else our game needs to know There is no pre-made folder in ``game/gamesrc`` to store custom player typeclasses. Make your own folder or store it in ``gamesrc/objects`` @@ -73,8 +89,8 @@ Special handlers: defined by ``settings.CMDSET_OOC``. - ``nicks`` - This stores and handles `Nicks `_, in the same way as nicks it works on Objects. For Players, nicks are - primarily used to store custom aliases for - `Channels `_. + primarily used to store custom aliases for [Communications#Channels + Channels]. How it all hangs together ------------------------- diff --git a/docs/sphinx/source/wiki/PortalAndServer.rst b/docs/sphinx/source/wiki/PortalAndServer.rst index 0704431b80..d7c29f9ce9 100644 --- a/docs/sphinx/source/wiki/PortalAndServer.rst +++ b/docs/sphinx/source/wiki/PortalAndServer.rst @@ -1,3 +1,5 @@ +Portal and Server + Portal and Server layout ======================== @@ -10,7 +12,7 @@ to have players connect to the Portal but keep the MUD running on the Server. This way one can restart/reload the game (the Server part) without Players getting disconnected. -https://2498159658166209538-a-1802744773732722657-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia\ *server*\ portal.png +|image0| The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection. This allows the two programs to @@ -65,3 +67,5 @@ 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 `_ for more info on building new protocols. + +.. |image0| image:: https://2498159658166209538-a-1802744773732722657-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png diff --git a/docs/sphinx/source/wiki/RemovingColour.rst b/docs/sphinx/source/wiki/RemovingColour.rst index 1b33d7df8a..7d49a55217 100644 --- a/docs/sphinx/source/wiki/RemovingColour.rst +++ b/docs/sphinx/source/wiki/RemovingColour.rst @@ -1,3 +1,5 @@ +Tutorial for adding configuration + Tutorial: Removing colour from your game ======================================== @@ -34,7 +36,12 @@ inheriting from ``game.gamesrc.objects.baseobjecs.Character``. :: - from ev import Characterclass ColourableCharacter(Character): at_object_creation(self): # set a colour config value self.db.config_colour = True + from ev import Character + + class 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 `_. @@ -48,7 +55,7 @@ everything works - you don't want to render your root user unusable!). :: - @typeclass/reset/force Bob = mycharacter.ColourableCharacter + @typeclass/reset/force Bob = mycharacter.ColourableCharacter ``@typeclass`` changes Bob's typeclass and runs all its creation hooks all over again. The ``/reset`` switch clears all attributes and @@ -58,7 +65,7 @@ properties from the old typeclass and the new one. ``/force`` might be needed if you edit the typeclass and want to update the object despite the actual typeclass name not having changed. -Overload the ``msg()`` method +Overload the \`msg()\` method ----------------------------- Next we need to overload the ``msg()`` method. What we want is to check @@ -76,7 +83,13 @@ original. Here's how it could look: :: - from ev import ansimsg(self, message, from_obj=None, data=None): "our custom msg()" if not self.db.config_colour: message = ansi.parse_ansi(message, strip_ansi=True) self.dbobj.msg(message, from_obj, data) + from ev import ansi + + msg(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 @@ -94,7 +107,7 @@ command: :: - @py self.db.config_colour = False + @py self.db.config_colour = False Custom colour config command ---------------------------- @@ -111,7 +124,28 @@ for configuration down the line). from ev import default_cmds class ConfigColourCmd(default_cmds.MuxCommand): """ - Configures your colour Usage: @setcolour on|off This turns ansii-colours on/off. Default is on. """ key = "@setcolour" aliases = ["@setcolor"] def func(self): "Implements the command" if not self.args or not self.args in ("on", "off"): self.caller.msg("Usage: @setcolour on|off") return if self.args == "on": self.caller.db.config_colour = True else: self.caller.db.config_colour = False self.caller.msg("Colour was turned %s." % self.args) + 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 copy the template file from @@ -128,7 +162,7 @@ module. def at_cmdset_creation(self): super(DefaultCmdSet, self).at_cmdset_creation() - self.add(configcmds.ConfigColourCmd()) + 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 diff --git a/docs/sphinx/source/wiki/Scripts.rst b/docs/sphinx/source/wiki/Scripts.rst index 013619cf28..9e51f372f1 100644 --- a/docs/sphinx/source/wiki/Scripts.rst +++ b/docs/sphinx/source/wiki/Scripts.rst @@ -1,3 +1,5 @@ +Script typeclass + Scripts ======= @@ -59,7 +61,7 @@ can try it out with an example script: :: - > @script self = examples.bodyfunctions.BodyFunctions + > @script self = examples.bodyfunctions.BodyFunctions This should cause some random messages. The ``/stop`` switch will kill the script again. @@ -71,7 +73,11 @@ 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") # alternative way from src.utils.create import create_script create_script("game.gamesrc.scripts.myscripts.CoolScript", obj=myobj) + # adding a script to an existing object 'myobj' + myobj.scripts.add("game.gamesrc.scripts.myscripts.CoolScript") + # alternative way + from src.utils.create import create_script + create_script("game.gamesrc.scripts.myscripts.CoolScript", obj=myobj) The creation method(s) takes an optional argument *key* that allows you to name your script uniquely before adding it. This can be useful if you @@ -79,143 +85,14 @@ add many scripts of the same type and later plan to use ``myobj.scripts.delete`` to remove individual scripts. You can create global scripts with -``ev.create_script (a shortcut to``\ src.utils.create.create\_script() +``ev.create_script (a shortcut to ``\ src.utils.create.create\_script()\ ``). Just don't supply an object to store it on. {{{ # adding a global script from ev import create_script create_script("game.gamesrc.scripts.globals.MyGlobalEconomy", key="economy", obj=None) }}} Assuming the Script ``\ game.gamesrc.scripts.globals.MyGlobalEconomy\ `` exists, this will create and start it as a global script. == Properties and functions defined on Scripts == It's important to know the variables controlling the script before one can create one. Beyond those properties assigned to all typeclassed objects (see [Typeclasses]), such as ``\ key\ ``, ``\ db\ ``, ``\ ndb\ `` etc, all Scripts also have the following properties: * ``\ desc\ `` - an optional description of the script's function. Seen in script listings. * ``\ interval\ `` - how often the script should run. If ``\ interval +== +0\ `` (default), it runs forever, without any repeating (it will not accept a negative value). * ``\ start\_delay\ `` - (bool), if we should wait ``\ interval\ `` seconds before firing for the first time or not. * ``\ repeats\ `` - How many times we should repeat, assuming ``\ interval +> 0\ ``. If repeats is set to ``\ <= +0\ ``, the script will repeat indefinitely. * ``\ persistent\ ``- if this script should survive a server reboot. There is one special property: * ``\ obj\ `` - the [Objects Object] this script is attached to (if any). You should not need to set this manually. If you add the script to the Object with ``\ myobj.scripts.add(myscriptpath)\ `` or give ``\ myobj\ `` as an argument to the ``\ utils.create.create\_script\ `` function, the ``\ obj\ `` property will be set to ``\ myobj\ `` for you. It's also imperative to know the hook functions. Normally, overriding these are all the customization you'll need to do in Scripts. You can find longer descriptions of these in ``\ src/scripts/scripts.py\ ``. * ``\ at\_script\_creation()\ `` - this is usually where the script class sets things like ``\ interval\ `` and ``\ repeats\ ``; things that control how the script runs. It is only called once - when the script is first created. * ``\ is\_valid()\ `` - determines if the script should still be running or not. This is called when running ``\ obj.scripts.validate()\ ``, which you can run manually, but which also Evennia calls during certain situations such as reloads. This is also useful for using scripts as state managers. If the method returns ``\ False\ ``, the script is stopped and cleanly removed. * ``\ at\_start()\ `` - this is called when the script first starts. For persistent scripts this is at least once ever server startup. Note that this will _always_ be called right away, also if ``\ start\_delay\ `` is ``\ True\ ``. * ``\ at\_repeat()\ `` - this is called every ``\ interval\ `` seconds, or not at all. It is called right away at startup, unless ``\ start\_delay\ `` is ``\ True\ ``, in which case the system will wait ``\ interval\ `` seconds before calling. * ``\ at\_stop()\ `` - this is called when the script stops for whatever reason. It's a good place to do custom cleanup. * ``\ at\_server\_reload()\ `` - this is called whenever the server is warm-rebooted (e.g. with the ``\ @reload\ `` command). It's a good place to save non-persistent data you might want to survive a reload. * ``\ at\_server\_shutdown()\ `` - this is called on a full systems shutdown. Running methods (usually called automatically by the engine, but possible to also invoke manually) * ``\ start()\ `` - this will start the script. This is called automatically whenever you add a new script to a handler. ``\ at\_start()\ `` will be called. * ``\ stop()\ `` - this will stop the script and delete it. Removing a script from a handler will stop it automatically. ``\ at\_stop()\ `` will be called. * ``\ pause()\ `` - this pauses a running script, rendering it inactive, but not deleting it. All properties are saved and timers can be resumed. This is called automatically when the server reloads. No hooks are called - as far as the script knows, it never stopped - this is a suspension of the script, not a change of state. * ``\ unpause()\ `` - resumes a previously paused script. Timers etc are restored to what they were before pause. The server unpauses all paused scripts after a server reload. No hooks are called - as far as the script is concerned, it never stopped running. * ``\ time\_until\_next\_repeat()\ `` - for timed scripts, this returns the time in seconds until it next fires. Returns ``\ None\ `` if ``\ interval==0\ ``. == Example script == {{{ import random from ev import Script class Weather(Script): "Displays weather info. Meant to be attached to a room." def at_script_creation(self): "Called once, during initial creation" self.key = "weather_script" self.desc = "Gives random weather messages." self.interval = 60 * 5 # every 5 minutes self.persistent = True self.at_repeat(self): "called every self.interval seconds." rand = random.random() if rand < 0.5: weather = "A faint breeze is felt." elif rand < 0.7: weather = "Clouds sweep across the sky." else: weather = "There is a light drizzle of rain." # send this message to everyone inside the object this # script is attached to (likely a room) self.obj.msg_contents(weather) }}} This is a simple weather script that we can put on an object. Every 5 minutes it will tell everyone inside that object how the weather is. To activate it, just add it to the script handler (``\ scripts\ ``) on an [Objects Room]. That object becomes ``\ self.obj\ `` in the example above. Here we put it on a room called ``\ myroom\ ``: {{{ myroom.scripts.add(weather.Weather) }}} In code you can also use the create function directly if you know how to locate the room you want: {{{ from ev import create_script create_script('game.gamesrc.scripts.weather.Weather', obj=myroom) }}} Or, from in-game, use the ``\ @script\ ```` +command: :: - ). Just don't supply an object to store it on. # adding a global script from ev import create_script create_script("game.gamesrc.scripts.globals.MyGlobalEconomy", key="economy", obj=None) - -Assuming the Script ``game.gamesrc.scripts.globals.MyGlobalEconomy`` -exists, this will create and start it as a global script. - -Properties and functions defined on Scripts -------------------------------------------- - -It's important to know the variables controlling the script before one -can create one. Beyond those properties assigned to all typeclassed -objects (see `Typeclasses `_), such as ``key``, -``db``, ``ndb`` etc, all Scripts also have the following properties: - -- ``desc`` - an optional description of the script's function. Seen in - script listings. -- ``interval`` - how often the script should run. If ``interval == 0`` - (default), it runs forever, without any repeating (it will not accept - a negative value). -- ``start_delay`` - (bool), if we should wait ``interval`` seconds - before firing for the first time or not. -- ``repeats`` - How many times we should repeat, assuming - ``interval > 0``. If repeats is set to ``<= 0``, the script will - repeat indefinitely. -- ``persistent``- if this script should survive a server reboot. - -There is one special property: - -- ``obj`` - the `Object `_ this script is attached to (if - any). You should not need to set this manually. If you add the script - to the Object with ``myobj.scripts.add(myscriptpath)`` or give - ``myobj`` as an argument to the ``utils.create.create_script`` - function, the ``obj`` property will be set to ``myobj`` for you. - -It's also imperative to know the hook functions. Normally, overriding -these are all the customization you'll need to do in Scripts. You can -find longer descriptions of these in ``src/scripts/scripts.py``. - -- ``at_script_creation()`` - this is usually where the script class - sets things like ``interval`` and ``repeats``; things that control - how the script runs. It is only called once - when the script is - first created. -- ``is_valid()`` - determines if the script should still be running or - not. This is called when running ``obj.scripts.validate()``, which - you can run manually, but which also Evennia calls during certain - situations such as reloads. This is also useful for using scripts as - state managers. If the method returns ``False``, the script is - stopped and cleanly removed. -- ``at_start()`` - this is called when the script first starts. For - persistent scripts this is at least once ever server startup. Note - that this will *always* be called right away, also if ``start_delay`` - is ``True``. -- ``at_repeat()`` - this is called every ``interval`` seconds, or not - at all. It is called right away at startup, unless ``start_delay`` is - ``True``, in which case the system will wait ``interval`` seconds - before calling. -- ``at_stop()`` - this is called when the script stops for whatever - reason. It's a good place to do custom cleanup. -- ``at_server_reload()`` - this is called whenever the server is - warm-rebooted (e.g. with the ``@reload`` command). It's a good place - to save non-persistent data you might want to survive a reload. -- ``at_server_shutdown()`` - this is called on a full systems shutdown. - -Running methods (usually called automatically by the engine, but -possible to also invoke manually) - -- ``start()`` - this will start the script. This is called - automatically whenever you add a new script to a handler. - ``at_start()`` will be called. -- ``stop()`` - this will stop the script and delete it. Removing a - script from a handler will stop it automatically. ``at_stop()`` will - be called. -- ``pause()`` - this pauses a running script, rendering it inactive, - but not deleting it. All properties are saved and timers can be - resumed. This is called automatically when the server reloads. No - hooks are called - as far as the script knows, it never stopped - - this is a suspension of the script, not a change of state. -- ``unpause()`` - resumes a previously paused script. Timers etc are - restored to what they were before pause. The server unpauses all - paused scripts after a server reload. No hooks are called - as far as - the script is concerned, it never stopped running. -- ``time_until_next_repeat()`` - for timed scripts, this returns the - time in seconds until it next fires. Returns ``None`` if - ``interval==0``. - -Example script --------------- - -:: - - import random - from ev import Script - class Weather(Script): - "Displays weather info. Meant to be attached to a room." - def at_script_creation(self): - "Called once, during initial creation" - self.key = "weather_script" - self.desc = "Gives random weather messages." - self.interval = 60 * 5 # every 5 minutes - self.persistent = True - self.at_repeat(self): - "called every self.interval seconds." - rand = random.random() - if rand < 0.5: - weather = "A faint breeze is felt." - elif rand < 0.7: - weather = "Clouds sweep across the sky." - else: - weather = "There is a light drizzle of rain." - # send this message to everyone inside the object this - # script is attached to (likely a room) - self.obj.msg_contents(weather) - -This is a simple weather script that we can put on an object. Every 5 -minutes it will tell everyone inside that object how the weather is. - -To activate it, just add it to the script handler (``scripts``) on an -`Room `_. That object becomes ``self.obj`` in the example -above. Here we put it on a room called ``myroom``: - -:: - - myroom.scripts.add(weather.Weather) - -In code you can also use the create function directly if you know how to -locate the room you want: - -:: - - from ev import create_script create_script('game.gamesrc.scripts.weather.Weather', obj=myroom) - -Or, from in-game, use the ``@script`` command: - -:: - - @script here = weather.Weather + @script here = weather.Weather diff --git a/docs/sphinx/source/wiki/SessionProtocols.rst b/docs/sphinx/source/wiki/SessionProtocols.rst index 7b44f4ba97..43104ecc91 100644 --- a/docs/sphinx/source/wiki/SessionProtocols.rst +++ b/docs/sphinx/source/wiki/SessionProtocols.rst @@ -1,3 +1,5 @@ +Describing the Portal Session and Protocol system + Portal Sessions and Protocols ============================= @@ -160,7 +162,20 @@ create a module there with the following functions: :: - # the caller is automatically added as first argument def get_health(character): "Get health, stored as simple attribute" return character.db.health def get_stamina(character): "Get stamina level, stored as simple attribute" return character.db.stamina def get_skill(character, skillname, master=False): """we assume skills are stored as a dictionary stored in an attribute. Master skills are stored separately (for whatever reason)""" if master: return character.db.skills_master.get(skillname, "NoSkill") return character.db.skills.get(skillname, "NoSkill") + # the caller is automatically added as first argument + def get_health(character): + "Get health, stored as simple attribute" + return character.db.health + def get_stamina(character): + "Get stamina level, stored as simple attribute" + return character.db.stamina + def get_skill(character, skillname, master=False): + """we assume skills are stored as a dictionary + stored in an attribute. Master skills are + stored separately (for whatever reason)""" + if master: + return character.db.skills_master.get(skillname, "NoSkill") + return character.db.skills.get(skillname, "NoSkill") Done, the functions will return what we want assuming Characters do store this information in our game. Let's finish up the first part of @@ -168,7 +183,25 @@ the portal protocol: :: - # this method could be named differently depending on the # protocol you are using (this is telnet) def lineReceived(self, string): # (does stuff to analyze the incoming string) # ... outdict = if GET_HEALTH: # call get_health(char) outdict["get_health"] = ([], ) elif GET_STAMINA: # call get_mana(char) outdict["get_stamina"] = ([], ) elif GET_MASTER_SKILL_SMITH: # call get_skill(char, "smithing", master=True) outdict["get_skill"] = (["smithing"], 'master':True) [...] self.sessionhandler.oob_data_out(outdict) + # this method could be named differently depending on the + # protocol you are using (this is telnet) + def lineReceived(self, string): + # (does stuff to analyze the incoming string) + # ... + outdict = {} + if GET_HEALTH: + # call get_health(char) + outdict["get_health"] = ([], {}) + elif GET_STAMINA: + # call get_mana(char) + outdict["get_stamina"] = ([], {}) + elif GET_MASTER_SKILL_SMITH: + # call get_skill(char, "smithing", master=True) + outdict["get_skill"] = (["smithing"], {'master':True}) + + [...] + + self.sessionhandler.oob_data_out(outdict) The Server will properly accept this and call the relevant functions to get their return values for the health, stamina and skill. The return @@ -178,7 +211,17 @@ being passed back to the Portal. We need to define :: - def oob_data_out(self, data): # the indata is a dictionary funcname:retval outstring = "" for funcname, retval in data.items(): if funcname == 'get_health': # convert to the right format for sending back to client, store # in outstring ... [...] # send off using the protocols send method (this is telnet) sendLine(outstring) + def oob_data_out(self, data): + # the indata is a dictionary {funcname:retval} + + outstring = "" + for funcname, retval in data.items(): + if funcname == 'get_health': + # convert to the right format for sending back to client, store + # in outstring ... + [...] + # send off using the protocols send method (this is telnet) + sendLine(outstring) As seen, ``oob_data`` takes the values and formats into a form the protocol understands before sending it off. @@ -196,7 +239,7 @@ Portal call and data will be sent back to be handled by the portal as normal. 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 diff --git a/docs/sphinx/source/wiki/SoftCode.rst b/docs/sphinx/source/wiki/SoftCode.rst index 3535b3ca7a..2c26bb57b9 100644 --- a/docs/sphinx/source/wiki/SoftCode.rst +++ b/docs/sphinx/source/wiki/SoftCode.rst @@ -1,3 +1,6 @@ +A brief explanation of what MUSH softcode is and why we use Python +instead. + On MUX and Softcode: A brief overview ===================================== @@ -51,7 +54,8 @@ retrieved when emitting: :: - &HELLO_VALUE.D me=Hello World &HELLO_WORLD.C me=$hello:@pemit %#=[v(HELLO_VALUE.D)] + &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 @@ -60,8 +64,8 @@ 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 +- `http://www.tinymux.com/wiki/index.php/Softcode `_ +- `http://www.duh.com/discordia/mushman/man2x1 `_ Problems with Softcode ---------------------- @@ -107,14 +111,25 @@ 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. +So what is *not* included in Evennia proper 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. +Your Solution +============= + +Adding very advanced and flexible building commands to your game will +probably often be enough to satisfy most creative builders. However, if +you really, *really* want to offer online coding there is of course +nothing stopping you from adding that to Evennia, no matter our +recommendations. You could even re-implement MUX' softcode in Python +should you be very ambitious. + +There is an experimental restricted python environment named *Evlang* to +be found in our *contrib* folder. Being in this folder means it's not a +part of the core server and is completely optional to use. Evlang could +serve as a starting point if you want to go down the route of simple +online player coding. diff --git a/docs/sphinx/source/wiki/StartStopReload.rst b/docs/sphinx/source/wiki/StartStopReload.rst index 5f2d397c35..c8f349e88c 100644 --- a/docs/sphinx/source/wiki/StartStopReload.rst +++ b/docs/sphinx/source/wiki/StartStopReload.rst @@ -1,3 +1,5 @@ +Controlling Evennia processes + Running Evennia =============== @@ -8,13 +10,13 @@ multiple-choice menu instead. :: - python evennia.py menu + python evennia.py menu Starting Evennia ---------------- Evennia consists of two components, the Evennia `Server and -Portal `_. Briefly, the *Server* is what is +Portal `_. 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, @@ -23,7 +25,7 @@ required for a functioning mud. :: - python evennia.py start + 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``. @@ -33,7 +35,7 @@ for quickly debugging your code), you use the -i (interactive) flag: :: - python evennia.py -i start + 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 @@ -43,7 +45,8 @@ You can also start the two components one at a time. :: - python evennia.py start server python evennia.py start portal + 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. @@ -67,7 +70,7 @@ Windows): :: - python evennia.py reload + python evennia.py reload Resetting --------- @@ -84,7 +87,8 @@ A reset is equivalent to :: - python evennia.py stop server python evennia.py start server + python evennia.py stop server + python evennia.py start server Shutting down ------------- @@ -97,6 +101,6 @@ From command line you do :: - python.py evennia.py stop + python.py evennia.py stop You will see messages of both Server and Portal closing down. diff --git a/docs/sphinx/source/wiki/TextEncodings.rst b/docs/sphinx/source/wiki/TextEncodings.rst index fc2dfc2b35..a2ccd87cfd 100644 --- a/docs/sphinx/source/wiki/TextEncodings.rst +++ b/docs/sphinx/source/wiki/TextEncodings.rst @@ -1,3 +1,5 @@ +Text encodings + Notes on text encodings ======================= diff --git a/docs/sphinx/source/wiki/TutorialWorldIntroduction.rst b/docs/sphinx/source/wiki/TutorialWorldIntroduction.rst index cb327e131c..3d0bb0c4c8 100644 --- a/docs/sphinx/source/wiki/TutorialWorldIntroduction.rst +++ b/docs/sphinx/source/wiki/TutorialWorldIntroduction.rst @@ -1,3 +1,5 @@ +Introducing the Tutorial world area + Tutorial World Introduction =========================== @@ -47,12 +49,14 @@ install, log into the server as the superuser (user #1) and run: 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``. +An alternative is + :: @batchcommand/interactive contrib.tutorial_world.build -will allow you to step through the building process at your own pace to -see what happens in detail. +with the /interactive switch you are able to step through the building +process at your own pace to see what happens 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 @@ -75,25 +79,22 @@ down!* and rain screaming in your face you stand where the moor meets the sea along a high, rocky coast ...* -Look at everything. +- Look at everything. +- Some objects are interactive in more than one way. Use the normal + ``help`` command to get a feel for which commands are available at + any given time. (use the command ``tutorial`` to get insight behind + the scenes of the tutorial). +- In order to fight, you need to first find some type of weapon. -Some objects are interactive in more than one way. Use the normal -``help`` command to get a feel for which commands are available at any -given time. (use the command ``tutorial`` to get insight behind the -scenes of the tutorial). + - *slash* is a normal attack + - *stab* launches an attack that makes more damage but has a lower + chance to hit. + - *defend* will lower the chance to taking damage on your enemy's + next attack. -In order to fight, you need to first find some type of weapon. - -- *slash* is a normal attack -- *stab* launches an attack that makes more damage but has a lower - chance to hit. -- *defend* will lower the chance to taking damage on your enemy's next - attack. - -You *can* run from a fight that feels too deadly. Expect to be chased -though. - -Being defeated is a part of the experience ... +- You *can* run from a fight that feels too deadly. Expect to be chased + though. +- Being defeated is a part of the experience ... Uninstall --------- @@ -103,7 +104,8 @@ and objects it consists of. First, move out of the tutorial area. :: - @find tut#01 @find tut#17 + @find tut#01 + @find tut#17 This should locate the first and last rooms created by ``build.ev`` - *Intro* and *Outro*. If you installed normally, everything created @@ -113,7 +115,7 @@ that range: :: - @del 5-80 + @del 5-80 You will see some errors since some objects are auto-deleted and so cannot be found when the delete mechanism gets to them. That's fine. You diff --git a/docs/sphinx/source/wiki/Typeclasses.rst b/docs/sphinx/source/wiki/Typeclasses.rst index 60ae015de6..047a074149 100644 --- a/docs/sphinx/source/wiki/Typeclasses.rst +++ b/docs/sphinx/source/wiki/Typeclasses.rst @@ -1,10 +1,13 @@ -Typeclassed objects -=================== +Descibing how Objects and Typeclasses work + +Typeclassed entities +==================== How do you represent different objects in a game? What makes a bear -different from a stone, or a character different from a house? How do -you store such differences in the database? One way would be to create -new database tables for each type. So a bear would have a database field +different from a stone, a character different from a house or a AI +script different from a script handling light and darkness? How do you +store such differences in the database? One way would be to create new +database tables for each type. So a bear would have a database field "claws" and the stone would have fields specifying its weight and colour ... and you'd soon go crazy with making custom database manipulations for all infinite combinations. @@ -18,17 +21,15 @@ There are three main game 'entities' in Evennia that are what we call *typeclassed*. They are `Players `_, `Objects `_ and `Scripts `_. This means that they are *almost* normal Python classes - they behave and can be -inherited from etc just like normal Python classes except that for -storing data they hide underlying database models ... +inherited from etc just like normal Python classes. But whenever they +store data they are infact transparently storing this data into the +database. -... and that's basically all you *really* need to know about how -typeclasses work behind the scenes. +All typeclassed entities share a few very useful properties and methods. +These are described in the next section. -To *work* with them you should however know that Objects, Scripts and -Players all inherit a lot of helper methods from the typeclass system, -properties you can *always* expect a typeclassed entity to have. In -addition to these, each of the three sub types also offer a host of -additional, subtype-specific helper methods and properties for your use. +See the pages for `Players `_, `Objects `_ +and `Scripts `_ for more specific usage examples. Properties available to all typeclassed entities (Players, Objects, Scripts) ---------------------------------------------------------------------------- @@ -43,24 +44,24 @@ Properties available to all typeclassed entities (Players, Objects, Scripts) There are three further properties that warrant special mention: -- ``db`` (!DataBase) - this is the interface to the `Attribute +- ``db`` (DataBase) - this is the interface to the `Attribute system `_, 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 +- ``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 `_, +As said, each of the typeclassed entities then extend this list with +their own properties. Go to the pages for `Objects `_, `Scripts `_ and `Players `_ respectively for more info. -Things to remember when using TypeClasses ------------------------------------------ +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 - @@ -100,9 +101,9 @@ a few things that you need to remember however: 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.\_ +*This is considered an advanced section. Skip it on your first +read-through unless you are really interested in what's going on under +the hood.* All typeclassed entities actually consist of two (three) parts: @@ -176,9 +177,7 @@ where one. Below is a schematic of the database/typeclass structure. -.. figure:: http://d.imagehost.org/0784/typeclasses1.png - :align: center - :alt: +|image0| Let's see how object creation looks like in an example. @@ -187,9 +186,9 @@ Let's see how object creation looks like in an example. ``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 +#. 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 +#. A new database model is created and given the key *RedRose*. Since this is an `Object `_ typeclass (rather than a Script or Player), the database model used is ``src.objects.models.ObjectDB``, which inherits directly from @@ -200,7 +199,7 @@ Let's see how object creation looks like in an example. 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 + 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 @@ -225,13 +224,12 @@ 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 onthesameline.html>`_. +[`CommandPrompt `_\ #Prompt\_on\_the\_same\_line +here]. Another example: -.. figure:: http://b.imagehost.org/0023/typeclasses2.png - :align: center - :alt: +|image1| Caveats of the typeclass system ------------------------------- @@ -253,7 +251,8 @@ query). You can easily convert between them with ``dbobj.typeclass`` and :: - 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. + 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 @@ -264,3 +263,6 @@ should be fine. Read the ``manager.py`` files in each relevant folder under ``src/`` to see which database access methods are available. + +.. |image0| image:: http://d.imagehost.org/0784/typeclasses1.png +.. |image1| image:: http://b.imagehost.org/0023/typeclasses2.png diff --git a/docs/sphinx/source/wiki/UnitTesting.rst b/docs/sphinx/source/wiki/UnitTesting.rst index 4c62342d1f..5204ced263 100644 --- a/docs/sphinx/source/wiki/UnitTesting.rst +++ b/docs/sphinx/source/wiki/UnitTesting.rst @@ -1,3 +1,5 @@ +Using and writing unit tests for Evennia. + Unit Testing ============ @@ -24,7 +26,7 @@ Running the test suite To run the Evennia test suite, go to the ``game/`` folder and issue the command -``python manage.py test`` + ``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 @@ -46,8 +48,8 @@ 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. +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 @@ -57,7 +59,34 @@ 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) + + # testing a simple funcion + + try: + # 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 myfunc + + TestObj(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 diff --git a/docs/sphinx/source/wiki/UpdatingYourGame.rst b/docs/sphinx/source/wiki/UpdatingYourGame.rst index 52d0783d30..6aacc93d91 100644 --- a/docs/sphinx/source/wiki/UpdatingYourGame.rst +++ b/docs/sphinx/source/wiki/UpdatingYourGame.rst @@ -6,7 +6,7 @@ via Mercurial. If you haven't already, see the `Getting Started guide `_ and get everything running. There are many ways to get told when to update: You can subscribe to the RSS feed or manually check up on the feeds from -`http://www.evennia.com. `_ You can also join +`http://www.evennia.com `_. You can also join the `Evennia Commit Log `_ group, which will send you an email when the server repository changes. @@ -16,7 +16,8 @@ root directory and type: :: - hg pull hg update + hg pull + hg 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 @@ -27,7 +28,7 @@ You can review the latest changes with :: - hg log + hg log or the equivalent in the graphical client. The log tends to scroll past quite quickly, so if you are in linux it might be an idea to *pipe* the @@ -37,7 +38,7 @@ permanent solution): :: - hg log | less + hg log | less You can also see the latest changes online `here `_. @@ -62,21 +63,22 @@ components you need to clear the data from all of them: :: - python manage.py reset server objects players scripts comms help web auth + python manage.py reset server objects players scripts comms help web auth Django also offers an easy way to start the database's own management should we want more direct control: :: - python manage.py dbshell + python manage.py dbshell In e.g. MySQL you can then do something like this (assuming your MySQL database is named "Evennia": :: - mysql> DROP DATABASE Evennia; mysql> exit + mysql> DROP DATABASE Evennia; + mysql> exit A Note on Schema Migration -------------------------- @@ -93,7 +95,7 @@ using the database's command line. This often means adding/removing new tables or fields as well as possibly convert existing data to match what the new Evennia version expects. It should be quite obvious that this quickly becomes cumbersome and error-prone. If your database doesn't -contain anything critical yet iẗ́'s probably easiest to simply reset it +contain anything critical yet it's probably easiest to simply reset it and start over rather than to bother converting. Enter `South `_. South keeps track of @@ -116,7 +118,7 @@ online list), you go to ``game/`` and run this command: :: - python manage.py migrate + python manage.py migrate This will convert your database to the new schema and you should be set to go. diff --git a/docs/sphinx/source/wiki/UsingMUXAsAStandard.rst b/docs/sphinx/source/wiki/UsingMUXAsAStandard.rst index 692d0b388e..ef24aa53f5 100644 --- a/docs/sphinx/source/wiki/UsingMUXAsAStandard.rst +++ b/docs/sphinx/source/wiki/UsingMUXAsAStandard.rst @@ -1,3 +1,5 @@ +Our policy on default commands + The 'MUX-like' default of Evennia ================================= @@ -21,7 +23,7 @@ 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 +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 @@ -36,9 +38,10 @@ 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. +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 diff --git a/docs/sphinx/source/wiki/WebFeatures.rst b/docs/sphinx/source/wiki/WebFeatures.rst index f66bb26c5c..41c5113310 100644 --- a/docs/sphinx/source/wiki/WebFeatures.rst +++ b/docs/sphinx/source/wiki/WebFeatures.rst @@ -1,3 +1,5 @@ +Summarizes the web feautures of Evennia + Web Features ============ @@ -28,7 +30,7 @@ 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 +`` 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 diff --git a/docs/sphinx/source/wiki/Workshop.rst b/docs/sphinx/source/wiki/Workshop.rst index f2d64581f3..18ccba908d 100644 --- a/docs/sphinx/source/wiki/Workshop.rst +++ b/docs/sphinx/source/wiki/Workshop.rst @@ -1,3 +1,5 @@ +Devel workshop + rtclient protocol ================= @@ -19,11 +21,11 @@ twisted/python. There are two principle aspects to the rtclient protocol, mode control and buffering. -modes ------ +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 @@ -31,19 +33,19 @@ the mode changes or no output has been added to the buffer in the last 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 @@ -75,21 +77,21 @@ note we are using the tokens imported instead of the constants 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 | -+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| chr() value \| name \| function | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 240 \| HTML\_TOKEN \| lets client know it is about to receive HTML | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 241 \| JAVASCRIPT\_TOKEN \| lets client know it is about to receive javascript | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 242 \| UNENCODED\_TOKEN \| lets client know it is about to receive plain telnet text | ++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 243 \| NO\_AUTOCHUNK\_TOKEN \| 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 \| AUTOCHUNK\_TOKEN \| 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 -------------------------- @@ -111,16 +113,18 @@ NO\_AUTOCHUNK Contents are never sent to the client until the encoding mode changes (for example, switching from HTML to UNENCODED will send the HTML buffer) or the buffering mode changes (for example, one could set -NO\ *AUTOCHUNK, send some text, and set NO*\ AUTOCHUNK again to force a +NO\_AUTOCHUNK, send some text, and set NO\_AUTOCHUNK again to force a flush. AUTOCHUNK ~~~~~~~~~ -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) + 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 diff --git a/docs/sphinx/source/wiki/WorkshopDefaultGame.rst b/docs/sphinx/source/wiki/WorkshopDefaultGame.rst index 91f383a069..ae68711958 100644 --- a/docs/sphinx/source/wiki/WorkshopDefaultGame.rst +++ b/docs/sphinx/source/wiki/WorkshopDefaultGame.rst @@ -25,24 +25,25 @@ 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 `_ supporting the SMAUG system: +#. Create custom `TypeClasses `_ supporting the SMAUG + system: -- Object->!SmaugObject->!SmaugBeing->!SmaugCharacter,Character -- Object->!SmaugObject->!SmaugBeing->!SmaugMob-> ... -- Object->!SmaugObject->!SmaugThing-> ... + - Object->SmaugObject->SmaugBeing->SmaugCharacter,Character + - Object->SmaugObject->SmaugBeing->SmaugMob-> ... + - Object->SmaugObject->SmaugThing-> ... -Create limited subclasses or attributes on objects +#. Create limited subclasses or attributes on objects -- Limited classes/races (1-2?) -- Skills (" + block.gsub(/\n/, ' ') + "

" -+ #"

" + block.gsub(/\n/, ' ') + "

" -+ "

" + block + "

" - end - end.join - end diff --git a/docs/sphinx/wiki2rest/wiki2rest.py b/docs/sphinx/wiki2rest/wiki2rest.py index dd835b4bea..4ad3991975 100755 --- a/docs/sphinx/wiki2rest/wiki2rest.py +++ b/docs/sphinx/wiki2rest/wiki2rest.py @@ -1,49 +1,30 @@ -#! /usr/bin/python +#! /usr/bin/python # # Converts Evennia's google-style wiki pages to reST documents # -# Setting up to run: +# 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, couldn't find a Python lib to do this. So if you -# don't have Ruby, you need to install that too. -# -# You also need to patch a bug in above program to make multiline code snippets work. -# From the same folder as the patch file, apply the patch like this: -# -# patch -p0 -i wiki2html.patch -# -# 2) Install pandoc (converts from html to reST): +# 1) Install pandoc (converts from html to reST): # # apt-get install pandoc (debian) -# or download from +# 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: +# 2) Retrieve wiki files (*.wiki) from Google code by mercurial. Make sure +# to retrieve them into a subdirectory wiki here: # # hg clone https://code.google.com/p/evennia.wiki wiki # -# 4) Check so that you have the following file structure: +# Regular Usage: # -# wiki/ (containing google code wiki files) -# wiki2html/ (containing the wiki_converter.rb ruby program (patch applied).) -# 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. +# 1) Make sure to pull/update the wiki files into wiki/ so you have the latest. +# 2) Run wiki2rest.py. Temporary work folders html and rest will be created, so make sure you +# have the rights to create directories here. The contents +# of rest/ will automatically be copied over to docs/sphinx/source/wiki. +# 3) From docs/sphinx, run e.g. "make html" to build the documentation from the reST sources. # -import sys, os, subprocess, re, urllib +import sys, os, subprocess, re, urllib, shutil # Setup @@ -69,7 +50,7 @@ WIKI_CRUMB_URL = "/p/evennia/wiki/" NO_CONVERT = ["SideBar", "Screenshot"] -#------------------------------------------------------------ +#------------------------------------------------------------ # This is a version of the importer that imports Google html pages # directly instead of going through the ruby converter. Alas, while # being a lot cleaner in implementation, this seems to produce worse @@ -81,11 +62,11 @@ NO_CONVERT = ["SideBar", "Screenshot"] def fetch_google_wiki_html_files(): """ - Acquire wiki html pages from google code + Acquire wiki html pages from google code """ # use wiki repo to find html filenames html_urls = dict([(re.sub(r"\.wiki", "", fn), WIKI_ROOT_URL + re.sub(r"\.wiki", "?show=content", fn)) - for fn in os.listdir(WIKI_DIR) if fn.endswith(".wiki")]) + for fn in os.listdir(WIKI_DIR) if fn.endswith(".wiki")]) #html_urls = {"Index":html_urls["Index"]} #SR! @@ -102,30 +83,30 @@ def fetch_google_wiki_html_files(): f = open(os.path.join(HTML_DIR, "%s.html" % name), 'w') f.write(s) f.close() - - return html_pages + + return html_pages def clean_html(htmlstring): """ - Clean up html properties special to google code and not known by pandoc + Clean up html properties special to google code and not known by pandoc """ - # remove wikiheader tag (searches over many lines). Unfortunately python <2.7 don't support - # DOTALL flag in re.sub ... + # remove wikiheader tag (searches over many lines). Unfortunately python <2.7 don't support + # DOTALL flag in re.sub ... matches = re.findall(r'
.*?
.*?.*?', htmlstring, re.DOTALL) - for match in matches: + for match in matches: htmlstring = htmlstring.replace(match, "") #htmlstring = re.sub(r'
.*?
.*?.*?', "", htmlstring, re.DOTALL) - # remove prefix from urls + # remove prefix from urls htmlstring = re.sub('href="' + WIKI_CRUMB_URL, 'href="', htmlstring) - # remove #links from headers - htmlstring = re.sub(r'(.*?)(.*?)( html ..." + subprocess.call(["python", "wikify.py", "-e", "-m", "-c", "-a", "-s", "wiki", "-d", "html"]) # convert from html to rest with pandoc - htmlfilenames = [fn for fn in os.listdir(HTML_DIR) + 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: + print " pandoc: converting html -> ReST ..." + for filename in htmlfilenames: htmlfilename = os.path.join(HTML_DIR, filename) - # cleanup of code - string = "".join(open(htmlfilename, 'r').readlines()) + # cleanup of code + string = "".join(open(htmlfilename, 'r').readlines()) string = re.sub(r'

[A-Za-z0-9 .-\:]*

', "", string) - string = re.sub(r"<wiki:toc max_depth="[0-9]*" />", "", string) - string = re.sub(r"<wiki:toc max_depth

"[0-9]*" />

", "", string) + string = re.sub(r"<wiki:toc max_depth="[0-9]*" />", "", string) + string = re.sub(r"<wiki:toc max_depth

"[0-9]*" />

", "", string) string = re.sub(r"

#settings Featured

", "", string) string = re.sub(r'

Featured

', "", string) string = re.sub(r'<wiki:comment>', "", string) string = re.sub(r'</wiki:comment>', "", string) - #string = re.sub(r'<wiki:comment>[<>;a-zA\/\n-&Z0-9 ]*</wiki:comment>', "", string) + string = re.sub(r'<wiki:comment>[<>;a-zA\/\n-&Z0-9 ]*</wiki:comment>', "", 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) + #print "pandoc: converting %s -> %s" % (htmlfilename, rstfilename) subprocess.call([PANDOC_EXE, "--from=html", "--to=rst", "-o", rstfilename, htmlfilename]) - -# main program +# main program if __name__ == "__main__": + print "creating/cleaning output dirs ...", try: - wiki2rest() + shutil.rmtree(REST_DIR) + os.mkdir(REST_DIR) + except OSError: + os.mkdir(REST_DIR) + try: + shutil.rmtree(HTML_DIR) + os.mkdir(HTML_DIR) + except Exception: + os.mkdir(HTML_DIR) + try: + shutil.rmtree(SPHINX_WIKI_DIR) + except Exception: + # this is created by copy mechanism. + pass + print "done." + print "running conversions ..." + + 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) + print "... conversions finished (make sure there are no error messages above)." + print "copying rest data to %s ..." % SPHINX_WIKI_DIR shutil.copytree(REST_DIR, SPHINX_WIKI_DIR) - + print "... done. You can now build the docs from the sphinx directory with e.g. 'make html'." diff --git a/docs/sphinx/wiki2rest/wikify.py b/docs/sphinx/wiki2rest/wikify.py new file mode 100644 index 0000000000..3bcc164e34 --- /dev/null +++ b/docs/sphinx/wiki2rest/wikify.py @@ -0,0 +1,962 @@ +#!/usr/bin/python +# +# wikify.py - Convert from wikitext to HTML +# Based on large portions of JeremyRuston's TiddlyWiki JS Wikifier +# Changed to GoogleCode wiki syntax, python by Michael Crawford +""" Convert wikitext to HTML """ + +# Jeremy's license: +# Copyright (c) UnaMesa Association 2004-2007 +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# Neither the name of the UnaMesa Association nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# My license: +# Copyright (c) Data Unity 2007 +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# Neither the name of the Data Unity nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import re, os, os.path, htmlentitydefs, urllib + + +class _HTML: + """ An HTML node factory factory. """ + + class Node: + """ An HTML element. """ + def __init__(self, parent, tagname, text="", attribs={}, empty=False, **kwargs): + self.tagname = tagname + self.attribs = dict(attribs) + self.children = list() + self.empty = empty + if text != "": + self.appendText(text) + if parent is not None: + parent.children.append(self) + self.parent = parent + + def appendText(self, text): + if text == "": return + _HTML.Text(self, text) + + def __str__(self): + attrs = " ".join([ '%s="%s"' % i for i in self.attribs.iteritems() ]) + if attrs: attrs = " " + attrs + if self.empty: + return "<%s%s/>" % (self.tagname, attrs) + + children = "".join([str(c) for c in self.children]) + return "<%s%s>%s" % (self.tagname, attrs, children, self.tagname) + + def isInside(self, tagname): + k = self + while k is not None: + if k.tagname == tagname: + return True + k = k.parent + return False + + class Text: + """ Simple text node. """ + entities = [ (k,v) + for k,v in htmlentitydefs.entitydefs.iteritems() + if k != "amp" and k[0] != "#" ] + + def __init__(self, parent, text=""): + self.text = self._clean(text) + if parent is not None: + parent.children.append(self) + + def _clean(self, text): + text = text.replace("&", "&") + for k,v in self.entities: + text = text.replace(v, "&%s;" % k) + return text + + def __str__(self): + return self.text + + + def __getattr__(self, attr): + """ Return an element constructor using the attribute as the tagname """ + def factory(parent=None, **kwargs): + return self.Node(parent, attr, **kwargs) + return factory + +HTML = _HTML() + +URLSTR = r"(?:file|http|https|mailto|ftp|irc|news|data):[^\s'\"]+(?:/|\b)" +URL = re.compile(URLSTR, re.M) +IMGURLSTR = r".+((\.[Pp][Nn][Gg])|(\.[Gg][Ii][Ff])|(\.[Jj][Pp][Ee]?[Gg]))" +IMGURL = re.compile(IMGURLSTR, re.M) +YOUTUBESTR = r"http://www.youtube.com/watch\?v=([A-Za-z0-9_-]+)" +YOUTUBEURL = re.compile(YOUTUBESTR, re.M) +YOUTUBEREPL = r'' +VIDEOURLSTR = r".+((\.[Aa][Vv][Ii])|(\.[Mm][Oo][Vv])|(\.[Mm][Pp][Ee]?[Gg]))" +VIDEOURL = re.compile(VIDEOURLSTR, re.M) +VIDEOREPL = r'' +CODEURLSTR = r"http://([^\.]+).googlecode.com/svn/trunk/([^#]+)#((?:(?:(?:[\d]+)?\-)?[\d]+)|(?:[\d]+\-?))((?:\:(?:[\:]|[^\W])+))?" +CODEURL = re.compile(CODEURLSTR, re.M) +CODEREPL = r'
svn://%(site)s/trunk/%(file)s
%(lines)s
' + +def GoogleCode_ReadSVNFile(wikifier, domain, path, start, end): + """ Try to read a file from subversion for inclusion in the wiki. """ + + gcurl = "http://%s.googlecode.com/svn/trunk/%s" % (domain,path) + fdata = urllib.urlopen(gcurl).readlines() + return gcurl, fdata[start-1:end] + + +def GoogleCode_IsExternalLink(wikifier, link): + """ See if the link points outside of the wiki. """ + + if GoogleCode_Exists(wikifier, link): + return False; + + if URL.match(link): + return True + + if '.' in link or '\\' in link or '/' in link or '#' in link: + return True + + return False + +def GoogleCode_Exists(wikifier, wikipage): + """ See if a wiki page exists inside this wiki. """ + path = os.path.join(wikifier.srcdir, "%s.wiki" % wikipage) + if os.path.exists(path): + return True + return False + + +def GoogleCode_Heading(wikifier, termRegExp=None, **kwargs): + termMatch = termRegExp.search(wikifier.source, wikifier.nextMatch) + if termMatch is None: return + if (len(wikifier.output.children) and + "br" == getattr(wikifier.output.children[-1], 'tagname', '')): + wikifier.output.children.pop(-1) + if (len(wikifier.output.children) and + "br" == getattr(wikifier.output.children[-1], 'tagname', '')): + wikifier.output.children.pop(-1) + output = HTML.Node(wikifier.output, "h%i" % wikifier.matchLength) + wikifier.outputText(output, wikifier.nextMatch, termMatch.start()) + wikifier.nextMatch = termMatch.end() + +def GoogleCode_SimpleElement(wikifier, termRegExp=None, tagName=None, **kwargs): + if wikifier.output.isInside(tagName): + wikifier.outputText(wikifier.output, wikifier.matchStart, wikifier.nextMatch) + return + elif wikifier.source[wikifier.nextMatch-1] == "_": + wikifier.outputText(wikifier.output, wikifier.matchStart, wikifier.nextMatch-1) + + if termRegExp.search(wikifier.source, wikifier.nextMatch) is None: return + output = HTML.Node(wikifier.output, tagName, **kwargs) + wikifier.subWikifyTerm(output, termRegExp) + #if wikifier.source[wikifer.nextMatch-2] == "_": + # wikifier.nextMatch -= 1 + +def GoogleCode_Blockquote(wikifier, termRegExp=None, **kwargs): + sibs = wikifier.output.children + if len(sibs) and getattr(sibs[-1], 'tagname', None) == "blockquote": + wikifier.subWikifyTerm(sibs[-1], termRegExp) + else: + output = HTML.blockquote(wikifier.output, **kwargs) + wikifier.subWikifyTerm(output, termRegExp) + +def GoogleCode_Codeblock(wikifier, tagName=None, termRegExp=None, initRegExp=None, **kwargs): + if 'attribs' not in kwargs: + kwargs['attribs'] = {} + + kwargs['attribs']['name'] = 'code' + if 'class' not in kwargs['attribs']: + kwargs['attribs']['class'] = wikifier.defaultHiLang.lower() + else: + kwargs['attribs']['class'] += " " + wikifier.defaultHiLang.lower() + + output = HTML.Node(wikifier.output, tagName, **kwargs) + tcount = 1 + matchStart = wikifier.nextMatch + # Find the matching terminator + while tcount > 0: + nextTermMatch = termRegExp.search(wikifier.source, wikifier.nextMatch) + nextInitMatch = initRegExp.search(wikifier.source, wikifier.nextMatch) + + if not nextTermMatch: + # No terminator. Syntax error, just ignore it. + matchEnd = matchStart + tcount = 0 + break + elif not nextInitMatch or nextTermMatch.start() <= nextInitMatch.start(): + # Terminator goes first. + nextMatch = nextTermMatch + tcount -= 1 + if tcount > 0: + matchEnd = nextMatch.end() + else: + matchEnd = nextMatch.start() + else: + nextMatch = nextInitMatch + tcount += 1 + matchEnd = nextMatch.end() + + wikifier.nextMatch = nextMatch.end() + + # Copy the content + wikifier.outputText(output, matchStart, matchEnd) + + if "\n" not in wikifier.source[matchStart:matchEnd]: + output.tagname = "code" + +def GoogleCode_WikiWord(wikifier, **kwargs): + if wikifier.matchStart > 0: + # Make sure we're at the start of a word? + preRegExp = re.compile("[!A-Za-z0-9]", re.M) + preMatch = preRegExp.search(wikifier.source, wikifier.matchStart-1) + if (preMatch is not None and + preMatch.start() == wikifier.matchStart-1): + wikifier.outputText(wikifier.output,wikifier.matchStart,wikifier.nextMatch) + return + + if wikifier.source[wikifier.matchStart] == "!": + wikifier.outputText(wikifier.output,wikifier.matchStart+1,wikifier.nextMatch) + elif GoogleCode_Exists(wikifier, wikifier.matchText): + # Full link, everybody sees it + HTML.a(wikifier.output, text=wikifier.matchText, attribs={"href": wikifier.matchText + wikifier.suffix}) + elif wikifier.autolink: + # Partial link - only authorized users + wikifier.outputText(wikifier.output,wikifier.matchStart,wikifier.nextMatch) + link = HTML.a(wikifier.output, text="?", attribs={"href": wikifier.matchText + wikifier.suffix}) + else: + wikifier.outputText(wikifier.output,wikifier.matchStart,wikifier.nextMatch) + +def GoogleCode_LineBreak(wikifier, **kwargs): + sibs = wikifier.output.children + if wikifier.multibreak: + HTML.p(wikifier.output, **kwargs) + elif len(sibs) and (not hasattr(sibs[-1], 'tagname') or + sibs[-1].tagname == "img"): + # Only after an inline or header block. + HTML.p(wikifier.output, **kwargs) + HTML.p(wikifier.output, **kwargs) + +def GoogleCode_PrettyLink(wikifier, lookaheadRegExp=None, **kwargs): + lookMatch = lookaheadRegExp.search(wikifier.source, wikifier.matchStart) + if lookMatch and lookMatch.start() == wikifier.matchStart: + text = lookMatch.group(1) + if lookMatch.group(2): + # Pretty bracketted link + link = text + text = lookMatch.group(2) + if GoogleCode_IsExternalLink(wikifier, link): + # External link + attribs={"href":link, "target": "_blank" } + else: + # Internal link + attribs={"href":link + wikifier.suffix} + + e = HTML.a(wikifier.output, attribs=attribs) + + if URL.match(text): + HTML.img(e, attribs={'src':text, + 'border': '0'}) + HTML.br(wikifier.output) + else: + HTML.Text(e, text) + else: + if GoogleCode_IsExternalLink(wikifier, text): + # External link + attribs={"href":link, "target": "_blank" } + else: + # Internal link + attribs={"href":text + wikifier.suffix} + + # Simple bracketted link + e = HTML.a(wikifier.output, text=text, attribs=attribs) + wikifier.nextMatch = lookMatch.end() + +def GoogleCode_UrlLink(wikifier, **kwargs): + attribs = {"href": wikifier.matchText} + if GoogleCode_IsExternalLink(wikifier, wikifier.matchText): + attribs["target"] = "_blank" + + if IMGURL.match(wikifier.matchText): + HTML.img(wikifier.output, attribs={'src':wikifier.matchText}) + HTML.br(wikifier.output) + elif YOUTUBEURL.match(wikifier.matchText): + match = YOUTUBEURL.match(wikifier.matchText) + # Raw html ;) + wikifier.output.children.append(YOUTUBEREPL % match.group(1)) + elif VIDEOURL.match(wikifier.matchText): + # Raw html ;) + wikifier.output.children.append(VIDEOREPL % wikifier.matchText) + elif CODEURL.match(wikifier.matchText): + # Raw html ;) + # http://([^\.]+).googlecode.com/svn/trunk/([^\#]+)#([^\:]+)(?:\:([^\W]+))? + + codeMatch = CODEURL.match(wikifier.matchText) + parts = { "class": (codeMatch.group(4) or "").lower()[1:], + "file": codeMatch.group(2), + "site": codeMatch.group(1)} + + lines = codeMatch.group(3) + if '-' in lines: + lines = lines.split('-') + lines[0] = int(lines[0]) + lines[1] = int(lines[1]) + else: + lines = [int(lines), int(lines)] + + parts['class'] += ":firstline[%i]" % lines[0] + url, parts['lines'] = GoogleCode_ReadSVNFile(wikifier, parts['site'], + parts['file'], *lines) + parts['url'] = url + parts['lines'] = "".join(parts['lines']) + + wikifier.output.children.append(CODEREPL % parts) + else: + HTML.a(wikifier.output, text=wikifier.matchText, attribs=attribs) + + +def GoogleCode_Table(wikifier, sepRegExp=None, termRegExp=None, **kwargs): + sibs = wikifier.output.children + if len(sibs) and getattr(sibs[-1], 'tagname', None) == "table": + table = sibs[-1] + else: + table = HTML.table(wikifier.output) + row = HTML.tr(table) + + termMatch = termRegExp.search(wikifier.source, wikifier.matchStart) + if termMatch is None: + termEnd = termStart = len(wikifier.source) + else: + termStart, termEnd = termMatch.start(), termMatch.end() + + # Skip over the leading separator + sepMatch = sepRegExp.search(wikifier.source, wikifier.matchStart) + wikifier.nextMatch = wikifier.matchStart = sepMatch.end() + sepMatch = sepRegExp.search(wikifier.source, wikifier.matchStart) + attribs = { "style": "border: 1px solid #aaa; padding: 5px;" } + + while sepMatch and sepMatch.end() <= termStart: + cell = HTML.td(row, attribs=attribs) + wikifier.subWikifyTerm(cell, sepRegExp) + wikifier.nextMatch = sepMatch.end() + sepMatch = sepRegExp.search(wikifier.source, wikifier.nextMatch) + + wikifier.nextMatch = termEnd + + +def GoogleCode_List(wikifier, lookaheadRegExp=None, termRegExp=None, **kwargs): + currLevel = 0 + currType = None + stack = [wikifier.output] + indents = [currLevel] + wikifier.nextMatch = wikifier.matchStart + + lookMatch = lookaheadRegExp.search(wikifier.source, wikifier.nextMatch) + while lookMatch and lookMatch.start() == wikifier.nextMatch: + # See what kind of list it is + if lookMatch.group(1): + listType = "ul" + itemType = "li" + elif lookMatch.group(2): + listType = "ol" + itemType = "li" + + listLevel = len(lookMatch.group(0)) + wikifier.nextMatch += len(lookMatch.group(0)) + + # Check for any changes in list type or indentation + if listLevel > currLevel: + # Indent further + indents.append(listLevel) + if currLevel == 0: + target = stack[-1] + else: + target = stack[-1].children[-1] + + stack.append(HTML.Node(target, listType)) + + elif listLevel < currLevel: + # Indent less + while indents[-1] > listLevel: + stack.pop(-1) + indents.pop(-1) + + elif listLevel == currLevel and listType != currType: + # Same level, different kind of list + stack.pop(-1) + stack.append(HTML.Node(stack[-1].children[-1], listType)) + + currLevel = listLevel + currType = listType + + # Output the item + output = HTML.Node(stack[-1],itemType) + wikifier.subWikifyTerm(output,termRegExp) + + # Roll again + lookMatch = lookaheadRegExp.search(wikifier.source, wikifier.nextMatch) + + + +GoogleCodeWikiFormat = [ + { + "name": "tablerow", + "match": r"^(?:\|\|.+\|\|)", + "termRegExp": re.compile(r"(\n)", re.M), + "sepRegExp": re.compile(r"(\|\|)", re.M), + "handler": GoogleCode_Table + }, + + { "name": "heading", + "match": r"^={1,6}", + "termRegExp": re.compile(r"([=]+)", re.M), + "handler": GoogleCode_Heading + }, + + { "name": "list", + "match": r"^(?:[ ]+)(?:[\*#])", + "lookaheadRegExp": re.compile(r"^(?:[ ]+)(?:(\*)|(#))",re.M), + "termRegExp": re.compile(r"(\n)", re.M), + "handler": GoogleCode_List + }, + + + + { "name": "blockquote", + "match": r"^(?:[ ]+)", + "termRegExp": re.compile(r"(\n)", re.M), + "handler": GoogleCode_Blockquote, + "tagName": "blockquote" + }, + + { "name": "codeword", + "match": r"\`", + "initRegExp": re.compile(r"(\`)", re.M), + "termRegExp": re.compile(r"(\`)", re.M), + "handler": GoogleCode_Codeblock, + "tagName": "code" + }, + + { "name": "codeblock", + "match": r"\{\{\{", + "initRegExp": re.compile(r"(\{\{\{)", re.M), + "termRegExp": re.compile(r"(\}\}\})", re.M), + "handler": GoogleCode_Codeblock, + "tagName": "pre", + "attribs": { "class": "codeblock" } + }, + + { "name": "bold", + "match": r"[\*]", + "termRegExp": re.compile(r"([\*])", re.M), + "handler": GoogleCode_SimpleElement, + "tagName": "b" + }, + + { "name": "italic", + "match": r"(?:[^\w\b]|^)[\_]", + "termRegExp": re.compile(r"([\_])[^\w\b]", re.M), + "handler": GoogleCode_SimpleElement, + "tagName": "i" + }, + + { "name": "strike", + "match": r"\~\~", + "termRegExp": re.compile(r"(\~\~)", re.M), + "handler": GoogleCode_SimpleElement, + "tagName": "strike" + }, + + { "name": "superscript", + "match": r"\^", + "termRegExp": re.compile(r"(\^)", re.M), + "handler": GoogleCode_SimpleElement, + "tagName": "sup" + }, + + { "name": "subscript", + "match": r",,", + "termRegExp": re.compile(r"(,,)", re.M), + "handler": GoogleCode_SimpleElement, + "tagName": "sub" + }, + + { "name": "prettyLink", + "match": r"\[(?:(?:[A-Za-z][A-Za-z0-9\_\-]+)|(?:(?:file|http|https|mailto|ftp|irc|news|data):[^\s'\"]+(?:/|\b)))(?: .*?)?\]", + "lookaheadRegExp": re.compile(r'\[(.*?)(?: (.*?))?\]', re.M), + "handler": GoogleCode_PrettyLink + }, + + { "name": "wikiword", + "match": r"(?:\!?(?:[A-Z]+[a-z]+[A-Z][A-Za-z]*)|(?:[A-Z]{2,}[a-z]+))", + "handler": GoogleCode_WikiWord + }, + + { "name": "urlLink", + "match": URLSTR, + "handler": GoogleCode_UrlLink + }, + + { "name": "linebreak", + "match": r"\n\n", + "handler": GoogleCode_LineBreak, + "empty": True + }, + +] + + + +class Wikifier: + + def __init__(self, formatters, autolink=False, srcdir=os.getcwd(), + multibreak=False, tabwidth=8, suffix=".html", + hiLang="Python"): + # Create the master regex + forms = [ "(%s)" % r['match'] for r in formatters ] + self.formatterRegExp = re.compile("|".join(forms), re.M) + # Save the individual format handlers + self.formatters = formatters + self.autolink = autolink + self.srcdir = srcdir + self.multibreak = multibreak and True or False + self.tabwidth = tabwidth + self.suffix = suffix + self.defaultHiLang = hiLang + + def _clean(self, text): + text = text.replace("\r\n", "\n") + + # Out, out, damned tabs + text = text.replace("\t", " " * self.tabwidth) + + if not self.multibreak: + # Remove redundant line breaks + tlen = len(text) + 1 + while tlen > len(text): + tlen = len(text) + text = text.replace("\n\n\n", "\n\n") + + while text.startswith("#"): + # Process any wiki-headers + line, text = text.split("\n", 1) + self._header(line) + + return text + + def _header(self, line): + tagname, content = line.split(" ", 1) + if tagname == "#summary": + self.summary = content + elif tagname == "#labels": + self.labels = tuple(content.split(",")) + + def wikify(self, source, labels=None, summary=None): + self.labels = labels + self.summary = summary + # Clean up the content + self.source = self._clean(source) + self.nextMatch = 0 + # Do it + self.output = HTML.div(None) + self.subWikifyUnterm() + + return "".join([str(c) for c in self.output.children]) + + def findMatch(self, source, start): + return self.formatterRegExp.search(source, start) + + def subWikifyUnterm(self, output=None): + oldOutput = self.output + if output is not None: + self.output = output + + match = self.findMatch(self.source, self.nextMatch) + while match: + # Output any text before the match + if match.start() > self.nextMatch: + self.outputText(self.output, self.nextMatch, match.start()) + + # Set the match parameters for the handler + self.matchStart = match.start() + self.matchLength = len(match.group(0)) + self.matchText = match.group(0) + self.nextMatch = match.end() + + # Figure out which sub-group matched (zero-indexed) + t,submatch = [ (t,s) for t, s in enumerate(match.groups()) if s ][0] + + # Handle it + self.formatters[t]['handler'](self, **self.formatters[t]) + + # Go back for more matches + match = self.findMatch(self.source, self.nextMatch) + + if self.nextMatch < len(self.source): + self.outputText(self.output, self.nextMatch, len(self.source)) + self.nextMatch = len(self.source) + + # Restore the destination node + self.output = oldOutput + + def subWikifyTerm(self, output, termRegExp): + oldOutput = self.output + if output is not None: + self.output = output + + # Get the first matches for the formatter and terminator RegExps + termMatch = termRegExp.search(self.source, self.nextMatch) + if termMatch: + match = self.findMatch(self.source[:termMatch.start()], self.nextMatch) + else: + match = self.findMatch(self.source, self.nextMatch) + + while termMatch or match: + # If the terminator comes before the next formatter match, we're done + if termMatch and (not match or termMatch.start() <= match.start()): + if termMatch.start() > self.nextMatch: + self.outputText(self.output,self.nextMatch,termMatch.start()) + self.matchText = termMatch.group(1) + self.matchLength = len(self.matchText) + self.matchStart = termMatch.start() + self.nextMatch = self.matchStart + self.matchLength + self.output = oldOutput + return + + # Output any text before the match + if match.start() > self.nextMatch: + self.outputText(self.output, self.nextMatch, match.start()) + + # Set the match parameters for the handler + self.matchStart = match.start() + self.matchLength = len(match.group(0)) + self.matchText = match.group(0) + self.nextMatch = match.end() + + # Figure out which sub-group matched (zero-indexed) + t,submatch = [ (t,s) for t, s in enumerate(match.groups()) if s ][0] + + # Handle it + self.formatters[t]['handler'](self, **self.formatters[t]) + + termMatch = termRegExp.search(self.source, self.nextMatch) + if termMatch: + match = self.findMatch(self.source[:termMatch.start()], self.nextMatch) + else: + match = self.findMatch(self.source, self.nextMatch) + + if self.nextMatch < len(self.source): + self.outputText(self.output, self.nextMatch,len(self.source)) + self.nextMatch = len(self.source) + + self.output = oldOutput + + + def outputText(self, output, startPos, endPos): + HTML.Text(output, self.source[startPos:endPos]) + + +DEFAULT_TEMPLATE = ''' + + + + + +
+ + + +
+
+ +%(toc)s +
+ + %(title)s + +
+ %(summary)s +
+ +
+ %(wiki)s +
+ +
+
+ + +''' + +DEFAULT_TEMPLATE = ''' + + + + + +
+ %(summary)s +
+
+ %(wiki)s +
+ + +''' + + +def wikify(pages, options=None): + # See options definition below. + # Pass any object with those (potential) attributes + srcdir = getattr(options, 'srcdir', os.getcwd()) + destdir = getattr(options, 'destdir', None) + + # Find all requested files + onlyStale = False + if getattr(options, 'all', False): + pages = [ k for k in os.listdir(srcdir) + if k.endswith(".wiki") ] + onlyStale = True + if destdir is None: + destdir = os.getcwd() + + # Create the magic 8-ball + w = Wikifier(GoogleCodeWikiFormat, + autolink=getattr(options, 'autolink', False), + tabwidth=getattr(options, 'tabwidth', 8), + multibreak=getattr(options, 'multibreak', False), + srcdir=srcdir, + suffix=".html") + + rets = [] + for wikiname in pages: + # Clean up the page name + if wikiname.endswith(".wiki"): + wikiname = wikiname[:-5] + + wikifilename = os.path.join(srcdir, "%s.wiki" % wikiname) + if onlyStale: + # See if the output is fresh, and if so, skip it + wikidestname = os.path.join(destdir, "%s.html" % wikiname) + try: + sstat = os.stat(wikifilename) + except: + continue + try: + dstat = os.stat(wikidestname) + except: + pass + else: + if dstat.st_mtime > sstat.st_mtime: + continue + + # Load the wiki content + wikifilename = os.path.join(srcdir, "%s.wiki" % wikiname) + wikisrc = file(wikifilename).read() + + # Ask a question + wikified = w.wikify(wikisrc) + + reFind = re.compile(r'\s*([^\<]*[\S])\s*') + strRepl = r'>\g<2>>' + + # Number the sections + if getattr(options, 'number', True): + sectstack = [] + matches = [] + curLevel = 0 + match = reFind.search(wikified) + while match is not None: + level = int(match.group(1)) + + while level > len(sectstack): + sectstack.append(1) + + while len(sectstack) > level: + sectstack.pop(-1) + + if curLevel >= level: + sectstack[-1] += 1 + curLevel = len(sectstack) + + sectnum = ".".join([str(n) for n in sectstack]) + "." + matches.append((sectnum, match)) + match = reFind.search(wikified, match.end()) + + matches.reverse() + for sectnum, match in matches: + wikified = wikified[:match.start()+4] + sectnum + " " + wikified[match.start()+4:] + + + # Generate the TOC + if getattr(options, 'toc', True): + matches = [ '%s: Contents' % wikiname ] + for match in reFind.findall(wikified): + if int(match[0]) > getattr(options, 'levels', 3): continue + indent = " " * ((int(match[0])) * 2) + + href = "#" + match[1] + anchor = '%s%s' % (indent, href, match[1]) + matches.append(anchor) + toc = "
".join(matches) + else: + toc = "" #-e -d /home/adam/src/CSpaceWiki/ + + # Generate the body links + if getattr(options, 'links', True): + wikified = reFind.sub(strRepl, wikified) + + # Find a summary + summary = "" + if w.summary is not None: + summary = w.summary + + if not getattr(options, 'raw', False): + # Fill the template + wikified = options.template % { + "toc": toc, + "title": wikiname, + "wiki": wikified, + "summary": summary } + + # Save it or write it + if destdir is not None: + outputname = os.path.join(destdir, "%s.html" % wikiname) + file(outputname,"w").write(wikified) + + mainpage = getattr(options, 'mainpage', 'MainPage') + if wikiname == mainpage: + rets.append((wikiname, outputname)) + outputname = os.path.join(destdir, "index.html") + file(outputname,"w").write(wikified) + + wikified = outputname + rets.append((wikiname, wikified)) + return rets + +if __name__ == "__main__": + from optparse import OptionParser + import sys + + parser = OptionParser() + + # Output format options + parser.add_option("-t", "--template", dest="template", + help="use TPLTFILE to wrap wiki output", metavar="TPLTFILE") + parser.add_option("-n", "--number", dest="number", metavar="NUMSTART", + help="number the headings in the body and table of contents starting with level NUMSTART") + parser.add_option("-l", "--levels", dest="levels", type="int", + help="create toc to depth LEVELS", metavar="LEVELS") + parser.add_option("-c", "--skiptoc", dest="toc", action="store_false", + help="leave toc out, even if template has slot") + parser.add_option("-u", "--unlink", dest="links", action="store_false", + help="don't create named anchors for toc links") + parser.add_option("-a", "--autolink", dest="autolink", action="store_false", + help="autolink wiki words that don't exist") + parser.add_option("-w", "--tabwidth", dest="tabwidth", type="int", + help="replace tabs by WIDTH spaces", metavar="WIDTH") + parser.add_option("-m", "--multibreak", dest="multibreak", action="store_true", + help="don't collapse multiple line breaks") + parser.add_option("-r", "--raw", dest="raw", action="store_true", + help="raw wiki translation -- no wrapping, no toc, no links") + parser.add_option("-p", "--mainpage", dest="mainpage", metavar="PAGENAME", + help="set main page to PAGENAME") + + # Batch / Location options + parser.add_option("-s", "--srcdir", dest="srcdir", + help="wiki format sources in SRCDIR", metavar="SRCDIR") + parser.add_option("-d", "--destdir", dest="destdir", + help="write html output into DESTDIR", metavar="DESTDIR") + parser.add_option("-e", "--stale", dest="all", action="store_true", + help="convert all wiki files that are stale or missing from DESTDIR") + + + parser.set_default('toc', True) + parser.set_default('links', True) + parser.set_default('template', None) + parser.set_default('number', False) + parser.set_default('levels', 3) + parser.set_default('tabwidth', 8) + parser.set_default('multibreak', False) + parser.set_default('mainpage', "MainPage") # Identity of index + + parser.set_default('srcdir', os.getcwd()) + parser.set_default('destdir', None) + parser.set_default('all', False) + + # Parse the command line + (options, args) = parser.parse_args() + + if options.template is None: + options.template = DEFAULT_TEMPLATE + elif os.path.exists(options.template): + options.template = file(options.template).read() + else: + print "Template not found: %s" % options.template + parser.print_usage() + sys.exit() + #sys.exit() + for wikiname, htmldata in wikify(args, options): + if options.destdir: + #print wikiname + ":", + if htmldata is not None: + pass + #print htmldata + else: + print "Complete." + elif htmldata is not None: + print htmldata + + +