mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
Start to fix references
This commit is contained in:
parent
ef1531c405
commit
7f79c61bb9
31 changed files with 74 additions and 470 deletions
|
|
@ -19,10 +19,24 @@ _NO_REMAP_STARTSWITH = ["http://", "https://", "github:", "api:",
|
|||
"feature-request", "report-bug", "issue", "bug-report"]
|
||||
|
||||
TXT_REMAPS = {
|
||||
"Developer Central": "Evennia Component overview"
|
||||
"Developer Central": "Evennia Component overview",
|
||||
"Getting Started": "Setup Quickstart",
|
||||
}
|
||||
URL_REMAPS = {
|
||||
"Developer-Central": "Component/Component-Overview",
|
||||
"Tutorials": "Howto/Howto-Overview",
|
||||
"../Howto/Starting/Directory-Overview": "Gamedir-Overview",
|
||||
"Howto/Starting/Directory-Overview": "Gamedir-Overview",
|
||||
"Starting/Directory-Overview": "Gamedir-Overview",
|
||||
"Directory-Overview": "Gamedir-Overview",
|
||||
"../Setup/Getting-Started": "Setup-Quickstart",
|
||||
"Setup/Getting-Started": "Setup-Quickstart",
|
||||
"Getting-Started": "Setup-Quickstart",
|
||||
"First-Steps-Coding": "Starting-Part1",
|
||||
"../Howto/Starting/Adding-Command-Tutorial": "Adding-Commands",
|
||||
"Howto/Starting/Adding-Command-Tutorial": "Adding-Commands",
|
||||
"Starting/Adding-Command-Tutorial": "Adding-Commands",
|
||||
"Adding-Command-Tutorial": "Adding-Commands",
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -86,7 +100,7 @@ def create_toctree():
|
|||
ref_doc_regex = re.compile(r"\[(?P<txt>[\w -]+?)\]:\s+?(?P<url>.+?)(?=$|\n)", re.I + re.S + re.U)
|
||||
|
||||
def _sub(match):
|
||||
# inline reference links
|
||||
# inline reference links
|
||||
grpdict = match.groupdict()
|
||||
txt, url = grpdict['txt'], grpdict['url']
|
||||
|
||||
|
|
@ -112,7 +126,7 @@ def create_toctree():
|
|||
return f"[{txt}]({urlout})"
|
||||
|
||||
def _sub_doc(match):
|
||||
# reference links set at the bottom of the page
|
||||
# reference links set at the bottom of the page
|
||||
grpdict = match.groupdict()
|
||||
txt, url = grpdict['txt'], grpdict['url']
|
||||
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ That is, enter `evennia.` and press the `<TAB>` key. This will show you all the
|
|||
available at the top level of Evennia's "flat API". See the [flat API](../Evennia-API) page for more
|
||||
info on how to explore it efficiently.
|
||||
|
||||
You can complement your exploration by peeking at the sections of the much more detailed [Developer
|
||||
Central](Developer-Central). The [Tutorials](Tutorials) section also contains a growing collection
|
||||
You can complement your exploration by peeking at the sections of the much more detailed
|
||||
[Evennia Component overview](../Component/Component-Overview). The [Tutorials](../Howto/Howto-Overview) section also contains a growing collection
|
||||
of system- or implementation-specific help.
|
||||
|
||||
### Use a python syntax checker
|
||||
|
|
@ -67,7 +67,7 @@ from us, really). You import useful functionality from here and if you see code
|
|||
it out into your game folder and edit it there.
|
||||
|
||||
If you find that Evennia doesn't support some functionality you need, make a [Feature
|
||||
Request](feature-request) about it. Same goes for [bugs][bug]. If you add features or fix bugs
|
||||
Request](github:issue) about it. Same goes for [bugs][bug]. If you add features or fix bugs
|
||||
yourself, please consider [Contributing](../Contributing) your changes upstream!
|
||||
|
||||
### Learn to read tracebacks
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ to you, but some things may still be useful.
|
|||
|
||||
## Find your way
|
||||
|
||||
- [Directory-Overview](../Howto/Starting/Directory-Overview)
|
||||
- [Directory-Overview](../Howto/Starting/Part1/Gamedir-Overview)
|
||||
- [Quirks of Evennia](Quirks)
|
||||
|
||||
## Setting up a workflow
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
# Execute Python Code
|
||||
|
||||
|
||||
The `@py` command supplied with the default command set of Evennia allows you to execute Python
|
||||
commands directly from inside the game. An alias to `@py` is simply "`!`". *Access to the `@py`
|
||||
command should be severely restricted*. This is no joke - being able to execute arbitrary Python
|
||||
code on the server is not something you should entrust to just anybody.
|
||||
|
||||
@py 1+2
|
||||
<<< 3
|
||||
|
||||
## Available variables
|
||||
|
||||
A few local variables are made available when running `@py`. These offer entry into the running
|
||||
system.
|
||||
|
||||
- **self** / **me** - the calling object (i.e. you)
|
||||
- **here** - the current caller's location
|
||||
- **obj** - a dummy [Object](../Component/Objects) instance
|
||||
- **evennia** - Evennia's [flat API](../Evennia-API) - through this you can access all of Evennia.
|
||||
|
||||
For accessing other objects in the same room you need to use `self.search(name)`. For objects in
|
||||
other locations, use one of the `evennia.search_*` methods. See [below](Execute-Python-Code#finding-
|
||||
objects).
|
||||
|
||||
## Returning output
|
||||
|
||||
This is an example where we import and test one of Evennia's utilities found in
|
||||
`src/utils/utils.py`, but also accessible through `ev.utils`:
|
||||
|
||||
@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 complex pieces of code which has no single obvious
|
||||
return value. To see the output from the `time_format()` function we need to tell the system to
|
||||
echo it to us explicitly with `self.msg()`.
|
||||
|
||||
@py from ev import utils; self.msg(str(utils.time_format(33333)))
|
||||
09:15
|
||||
<<< Done.
|
||||
|
||||
> Warning: When using the `msg` function wrap our argument in `str()` to convert it into a string
|
||||
above. This is not strictly necessary for most types of data (Evennia will usually convert to a
|
||||
string behind the scenes for you). But for *lists* and *tuples* you will be confused by the output
|
||||
if you don't wrap them in `str()`: only the first item of the iterable will be returned. This is
|
||||
because doing `msg(text)` is actually just a convenience shortcut; the full argument that `msg`
|
||||
accepts is something called an *outputfunc* on the form `(cmdname, (args), {kwargs})` (see [the
|
||||
message path](Messagepath) for more info). Sending a list/tuple confuses Evennia to think you are
|
||||
sending such a structure. Converting it to a string however makes it clear it should just be
|
||||
displayed as-is.
|
||||
|
||||
If you were to use Python's standard `print`, you will see the result in your current `stdout` (your
|
||||
terminal by default, otherwise your log file).
|
||||
|
||||
## Finding objects
|
||||
|
||||
A common use for `@py` is to explore objects in the database, for debugging and performing specific
|
||||
operations that are not covered by a particular command.
|
||||
|
||||
Locating an object is best done using `self.search()`:
|
||||
|
||||
@py self.search("red_ball")
|
||||
<<< Ball
|
||||
|
||||
@py self.search("red_ball").db.color = "red"
|
||||
<<< Done.
|
||||
|
||||
@py self.search("red_ball").db.color
|
||||
<<< red
|
||||
|
||||
`self.search()` is by far the most used case, but you can also search other database tables for
|
||||
other Evennia entities like scripts or configuration entities. To do this you can use the generic
|
||||
search entries found in `ev.search_*`.
|
||||
|
||||
@py evennia.search_script("sys_game_time")
|
||||
<<< [<src.utils.gametime.GameTime object at 0x852be2c>]
|
||||
|
||||
(Note that since this becomes a simple statement, we don't have to wrap it in `self.msg()` to get
|
||||
the output). You can also use the database model managers directly (accessible through the `objects`
|
||||
properties of database models or as `evennia.managers.*`). This is a bit more flexible since it
|
||||
gives you access to the full range of database search methods defined in each manager.
|
||||
|
||||
@py evennia.managers.scripts.script_search("sys_game_time")
|
||||
<<< [<src.utils.gametime.GameTime object at 0x852be2c>]
|
||||
|
||||
The managers are useful for all sorts of database studies.
|
||||
|
||||
@py ev.managers.configvalues.all()
|
||||
<<< [<ConfigValue: default_home]>, <ConfigValue:site_name>, ...]
|
||||
|
||||
## Testing code outside the game
|
||||
|
||||
`@py` has the advantage of operating inside a running server (sharing the same process), where you
|
||||
can test things in real time. Much of this *can* be done from the outside too though.
|
||||
|
||||
In a terminal, cd to the top of your game directory (this bit is important since we need access to
|
||||
your config file) and run
|
||||
|
||||
evennia shell
|
||||
|
||||
Your default Python interpreter will start up, configured to be able to work with and import all
|
||||
modules of your Evennia installation. From here you can explore the database and test-run individual
|
||||
modules as desired.
|
||||
|
||||
It's recommended that you get a more fully featured Python interpreter like
|
||||
[iPython](http://ipython.scipy.org/moin/). If you use a virtual environment, you can just get it
|
||||
with `pip install ipython`. IPython allows you to better work over several lines, and also has a lot
|
||||
of other editing features, such as tab-completion and `__doc__`-string reading.
|
||||
|
||||
$ evennia shell
|
||||
|
||||
IPython 0.10 -- An enhanced Interactive Python
|
||||
...
|
||||
|
||||
In [1]: import evennia
|
||||
In [2]: evennia.managers.objects.all()
|
||||
Out[3]: [<ObjectDB: Harry>, <ObjectDB: Limbo>, ...]
|
||||
|
||||
See the page about the [Evennia-API](../Evennia-API) for more things to explore.
|
||||
|
|
@ -110,7 +110,7 @@ Try to avoid doing so.
|
|||
distributions (notably Ubuntu 16.04 LTS). Zope is a dependency of Twisted. The error manifests in
|
||||
the server not starting with an error that `zope.interface` is not found even though `pip list`
|
||||
shows it's installed. The reason is a missing empty `__init__.py` file at the root of the zope
|
||||
package. If the virtualenv is named "evenv" as suggested in the [Getting Started](../Setup/Getting-Started)
|
||||
package. If the virtualenv is named "evenv" as suggested in the [Setup Quickstart](../Setup/Setup-Quickstart)
|
||||
instructions, use the following command to fix it:
|
||||
|
||||
```shell
|
||||
|
|
|
|||
|
|
@ -330,9 +330,11 @@ to see how it looks when it fails.
|
|||
|
||||
### Testing commands
|
||||
|
||||
This section will test the proper execution of the 'abilities' command, as described in the [First
|
||||
Steps Coding](First-Steps-Coding) page. Follow this tutorial to create the 'abilities' command, we
|
||||
will need it to test it.
|
||||
```warning:: This is not correct anymore.
|
||||
```
|
||||
|
||||
This section will test the proper execution of the 'abilities' command, as described in the DELETED
|
||||
tutorial to create the 'abilities' command, we will need it to test it.
|
||||
|
||||
Testing commands in Evennia is a bit more complex than the simple testing example we have seen.
|
||||
Luckily, Evennia supplies a special test class to do just that ... we just need to inherit from it
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
Fortunately, it's extremely easy to keep your Evennia server up-to-date. If you haven't already, see
|
||||
the [Getting Started guide](../Setup/Getting-Started) and get everything running.
|
||||
the [Getting Started guide](../Setup/Setup-Quickstart) and get everything running.
|
||||
|
||||
### Updating with the latest Evennia code changes
|
||||
|
||||
|
|
@ -78,10 +78,11 @@ When the database schema changes, you just go to your game folder and run
|
|||
|
||||
Should you ever want to start over completely from scratch, there is no need to re-download Evennia
|
||||
or anything like that. You just need to clear your database. Once you are done, you just rebuild it
|
||||
from scratch as described in [step 2](../Setup/Getting-Started#step-2-setting-up-your-game) of the [Getting
|
||||
Started guide](Getting-Started).
|
||||
from scratch by running
|
||||
|
||||
First stop a running server with
|
||||
evennia migrate
|
||||
|
||||
The first step in wiping your database is to stop Evennia completely with
|
||||
|
||||
evennia stop
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
Bootstrap provides many utilities and components you can use when customizing Evennia's web
|
||||
presence. We'll go over a few examples here that you might find useful.
|
||||
> Please take a look at either [the basic web tutorial](../Howto/Starting/Add-a-simple-new-web-page) or [the web
|
||||
character view tutorial](Web-Character-View-Tutorial)
|
||||
> Please take a look at either [the basic web tutorial](../Howto/Starting/Add-a-simple-new-web-page) or
|
||||
>[the web character view tutorial](../Howto/Web-Character-View-Tutorial)
|
||||
> to get a feel for how to add pages to Evennia's website to test these examples.
|
||||
|
||||
## General Styling
|
||||
|
|
@ -11,15 +11,13 @@ Bootstrap provides base styles for your site. These can be customized through CS
|
|||
styles are intended to provide a consistent, clean look for sites.
|
||||
|
||||
### Color
|
||||
Most elements can be styled with default colors. [Take a look at the
|
||||
documentation](https://getbootstrap.com/docs/4.0/utilities/colors/) to learn more about these colors
|
||||
Most elements can be styled with default colors. [Take a look at the documentation](https://getbootstrap.com/docs/4.0/utilities/colors/) to learn more about these colors
|
||||
- suffice to say, adding a class of text-* or bg-*, for instance, text-primary, sets the text color
|
||||
or background color.
|
||||
|
||||
### Borders
|
||||
Simply adding a class of 'border' to an element adds a border to the element. For more in-depth
|
||||
info, please [read the documentation on
|
||||
borders.](https://getbootstrap.com/docs/4.0/utilities/borders/).
|
||||
info, please [read the documentation on borders.](https://getbootstrap.com/docs/4.0/utilities/borders/).
|
||||
```
|
||||
<span class="border border-dark"></span>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ on. The tutorial world included with Evennia showcases a dark room that replaces
|
|||
commands with its own versions because the Character cannot see.
|
||||
|
||||
If you want a quick start into defining your first commands and using them with command sets, you
|
||||
can head over to the [Adding Command Tutorial](../Howto/Starting/Adding-Command-Tutorial) which steps through things
|
||||
can head over to the [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands) which steps through things
|
||||
without the explanations.
|
||||
|
||||
## Defining Command Sets
|
||||
|
|
@ -112,7 +112,7 @@ back even if all other cmdsets fail or are removed. It is always persistent and
|
|||
by `cmdset.delete()`. To remove a default cmdset you must explicitly call `cmdset.remove_default()`.
|
||||
|
||||
Command sets are often added to an object in its `at_object_creation` method. For more examples of
|
||||
adding commands, read the [Step by step tutorial](../Howto/Starting/Adding-Command-Tutorial). Generally you can
|
||||
adding commands, read the [Step by step tutorial](../Howto/Starting/Part1/Adding-Commands). Generally you can
|
||||
customize which command sets are added to your objects by using `self.cmdset.add()` or
|
||||
`self.cmdset.add_default()`.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ can find the default commands in `evennia/commands/default`. You should not edit
|
|||
they will be updated by the Evennia team as new features are added. Rather you should look to them
|
||||
for inspiration and inherit your own designs from them.
|
||||
|
||||
There are two components to having a command running - the *Command* class and the [Command
|
||||
Set](Command-Sets) (command sets were split into a separate wiki page for ease of reading).
|
||||
There are two components to having a command running - the *Command* class and the
|
||||
[Command Set](Command-Sets) (command sets were split into a separate wiki page for ease of reading).
|
||||
|
||||
1. A *Command* is a python class containing all the functioning code for what a command does - for
|
||||
example, a *get* command would contain code for picking up objects.
|
||||
|
|
@ -28,8 +28,9 @@ object in various ways. Consider a "Tree" object with a cmdset defining the comm
|
|||
*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. To fully use them you must also read the
|
||||
page detailing [Command Sets](Command-Sets). There is also a step-by-step [Adding Command
|
||||
Tutorial](Adding-Command-Tutorial) that will get you started quickly without the extra explanations.
|
||||
page detailing [Command Sets](Command-Sets). There is also a step-by-step
|
||||
[Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands) that will get you started quickly without the
|
||||
extra explanations.
|
||||
|
||||
## Defining Commands
|
||||
|
||||
|
|
@ -181,8 +182,8 @@ or replace the storage.
|
|||
- `arg_regex` (optional raw string): Used to force the parser to limit itself and tell it when the
|
||||
command-name ends and arguments begin (such as requiring this to be a space or a /switch). This is
|
||||
done with a regular expression. [See the arg_regex section](Commands#on-arg_regex) for the details.
|
||||
- `auto_help` (optional boolean). Defaults to `True`. This allows for turning off the [auto-help
|
||||
system](Help-System#command-auto-help-system) on a per-command basis. This could be useful if you
|
||||
- `auto_help` (optional boolean). Defaults to `True`. This allows for turning off the
|
||||
[auto-help system](Help-System#command-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.
|
||||
- `is_exit` (bool) - this marks the command as being used for an in-game exit. This is, by default,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ ways to customize the server and expand it with your own plugins.
|
|||
|
||||
The "Settings" file referenced throughout the documentation is the file
|
||||
`mygame/server/conf/settings.py`. This is automatically created on the first run of `evennia --init`
|
||||
(see the [Getting Started](../Setup/Getting-Started) page).
|
||||
(see the [Setup Quickstart](../Setup/Setup-Quickstart) page).
|
||||
|
||||
Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is actually
|
||||
[evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default.py)
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@
|
|||
|
||||
See also:
|
||||
- [Default Command Help](../Component/Default-Command-Help)
|
||||
- [Adding Command Tutorial](../Howto/Starting/Adding-Command-Tutorial)
|
||||
- [Adding Command Tutorial](../Howto/Starting/Part1/Adding-Commands)
|
||||
|
|
@ -43,7 +43,7 @@ Alternatively you might have the language but find the translation bad ... You a
|
|||
improve the situation!
|
||||
|
||||
To start a new translation you need to first have cloned the Evennia repositry with GIT and
|
||||
activated a python virtualenv as described on the [Getting Started](../Setup/Getting-Started) page. You now
|
||||
activated a python virtualenv as described on the [Setup Quickstart](../Setup/Setup-Quickstart) page. You now
|
||||
need to `cd` to the `evennia/` directory. This is *not* your created game folder but the main
|
||||
Evennia library folder. If you see a folder `locale/` then you are in the right place. From here you
|
||||
run:
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ Here is how you add your own database table/models:
|
|||
|
||||
1. In Django lingo, we will create a new "application" - a subsystem under the main Evennia program.
|
||||
For this example we'll call it "myapp". Run the following (you need to have a working Evennia
|
||||
running before you do this, so make sure you have run the steps in [Getting Started](Getting-
|
||||
running before you do this, so make sure you have run the steps in [Setup Quickstart](Getting-
|
||||
Started) first):
|
||||
|
||||
cd mygame/world
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ you will know there are a multitude of other characters around to use. When crea
|
|||
Evennia you have access to the [UTF-8 character encoding](https://en.wikipedia.org/wiki/UTF-8) which
|
||||
put at your disposal [thousands of letters, number and geometric shapes](http://mcdlr.com/utf-8/#1).
|
||||
|
||||
For this exercise, we've copy-and-pasted from the pallet of special characters used over at [Dwarf
|
||||
Fortress](http://dwarffortresswiki.org/index.php/Character_table) to create what is hopefully a
|
||||
For this exercise, we've copy-and-pasted from the pallet of special characters used over at
|
||||
[Dwarf Fortress](http://dwarffortresswiki.org/index.php/Character_table) to create what is hopefully a
|
||||
pleasing and easy to understood landscape:
|
||||
|
||||
```
|
||||
|
|
@ -83,8 +83,8 @@ planning at this stage can solve many problems before they happen.
|
|||
In this section we will try to create an actual "map" object that an account can pick up and look
|
||||
at.
|
||||
|
||||
Evennia offers a range of [default commands](../Component/Default-Command-Help) for [creating objects and rooms
|
||||
in-game](Building-Quickstart). While readily accessible, these commands are made to do very
|
||||
Evennia offers a range of [default commands](../Component/Default-Command-Help) for
|
||||
[creating objects and rooms in-game](../Howto/Starting/Part1/Building-Quickstart). While readily accessible, these commands are made to do very
|
||||
specific, restricted things and will thus not offer as much flexibility to experiment (for an
|
||||
advanced exception see [in-line functions](../Concept/TextTags#new-inlinefuncs)). Additionally, entering long
|
||||
descriptions and properties over and over in the game client can become tedious; especially when
|
||||
|
|
@ -413,5 +413,5 @@ easily new game defining features can be added to Evennia.
|
|||
|
||||
You can easily build from this tutorial by expanding the map and creating more rooms to explore. Why
|
||||
not add more features to your game by trying other tutorials: [Add weather to your world](Weather-
|
||||
Tutorial), [fill your world with NPC's](../Howto/Tutorial-Aggressive-NPCs) or [implement a combat
|
||||
system](Turn-based-Combat-System).
|
||||
Tutorial), [fill your world with NPC's](../Howto/Tutorial-Aggressive-NPCs) or
|
||||
[implement a combat system](../Howto/Starting/Turn-based-Combat-System).
|
||||
|
|
@ -668,7 +668,7 @@ to understand our friendly Google-style docstrings used in classes and functions
|
|||
[commonmark-help](https://commonmark.org/help/)
|
||||
[sphinx-autodoc](http://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc)
|
||||
[sphinx-napoleon](http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)
|
||||
[getting-started]: Setup/Getting-Started
|
||||
[getting-started]: Setup/Setup-Quickstart
|
||||
[contributing]: Contributing
|
||||
[ReST](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html)
|
||||
[ReST-tables](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#tables)
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ For more extensive feature information, see the [Evennia Component overview](Com
|
|||
|
||||
## What you need to know to work with Evennia
|
||||
|
||||
Assuming you have Evennia working (see the [quick start instructions](Setup/Getting-Started)) and have
|
||||
Assuming you have Evennia working (see the [quick start instructions](Setup/Setup-Quickstart)) and have
|
||||
gotten as far as to start the server and connect to it with the client of your choice, here's what
|
||||
you need to know depending on your skills and needs.
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ presence (a website and a mud web client) to play around with ...
|
|||
### Where to from here?
|
||||
|
||||
From here you can continue browsing the [online documentation]([online documentation](index)) to
|
||||
find more info about Evennia. Or you can jump into the [Tutorials](Tutorials) and get your hands
|
||||
find more info about Evennia. Or you can jump into the [Tutorials](Howto/Howto-Overview) and get your hands
|
||||
dirty with code right away. You can also read the developer's [dev
|
||||
blog](https://evennia.blogspot.com/) for many tidbits and snippets about Evennia's development and
|
||||
structure.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ Character [Command Set](../Component/Command-Sets)?
|
|||
|
||||
**A:** Go to `mygame/commands/default_cmdsets.py`. Find the `CharacterCmdSet` class. It has one
|
||||
method named `at_cmdset_creation`. At the end of that method, add the following line:
|
||||
`self.remove(default_cmds.CmdGet())`. See the [Adding Commands Tutorial](Starting/Adding-Command-Tutorial)
|
||||
`self.remove(default_cmds.CmdGet())`. See the [Adding Commands Tutorial](Starting/Part1/Adding-Commands)
|
||||
for more info.
|
||||
|
||||
## Preventing character from moving based on a condition
|
||||
|
|
@ -157,7 +157,7 @@ class CmdWerewolf(Command):
|
|||
def func(self):
|
||||
# ...
|
||||
```
|
||||
Add this to the [default cmdset as usual](Starting/Adding-Command-Tutorial). The `is_full_moon` [lock
|
||||
Add this to the [default cmdset as usual](Starting/Part1/Adding-Commands). The `is_full_moon` [lock
|
||||
function](Locks#lock-functions) does not yet exist. We must create that:
|
||||
|
||||
```python
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ error message just told us that we couldn't go there.
|
|||
|
||||
## Adding default error commands
|
||||
|
||||
To solve this you need to be aware of how to [write and add new commands](Starting/Adding-Command-Tutorial).
|
||||
To solve this you need to be aware of how to [write and add new commands](Starting/Part1/Adding-Commands).
|
||||
What you need to do is to create new commands for all directions you want to support in your game.
|
||||
In this example all we'll do is echo an error message, but you could certainly consider more
|
||||
advanced uses. You add these commands to the default command set. Here is an example of such a set
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ in mind for your own game, this will give you a good start.
|
|||
|
||||
1. [Introduction & Overview](Starting/Starting-Part3)
|
||||
1. [Where to put code](Starting/First-Steps-Coding)
|
||||
1. [Adding a first command](Starting/Adding-Command-Tutorial)
|
||||
1. [Adding a first command](Starting/Part1/Adding-Commands)
|
||||
1. [Parsing strings](Starting/Parsing-command-arguments,-theory-and-best-practices)
|
||||
1. [Making a custom Character](Starting/Adding-Object-Typeclass-Tutorial)
|
||||
1. [The rules of the game](Starting/Implementing-a-game-rule-system)
|
||||
|
|
|
|||
|
|
@ -1,292 +0,0 @@
|
|||
# First Steps Coding
|
||||
|
||||
|
||||
This section gives a brief step-by-step introduction on how to set up Evennia for the first time so
|
||||
you can modify and overload the defaults easily. You should only need to do these steps once. It
|
||||
also walks through you making your first few tweaks.
|
||||
|
||||
Before continuing, make sure you have Evennia installed and running by following the [Getting
|
||||
Started](Getting-Started) instructions. You should have initialized a new game folder with the
|
||||
`evennia --init foldername` command. We will in the following assume this folder is called
|
||||
"mygame".
|
||||
|
||||
It might be a good idea to eye through the brief [Coding Introduction](../../Coding/Coding-Introduction) too
|
||||
(especially the recommendations in the section about the evennia "flat" API and about using `evennia
|
||||
shell` will help you here and in the future).
|
||||
|
||||
To follow this tutorial you also need to know the basics of operating your computer's
|
||||
terminal/command line. You also need to have a text editor to edit and create source text files.
|
||||
There are plenty of online tutorials on how to use the terminal and plenty of good free text
|
||||
editors. We will assume these things are already familiar to you henceforth.
|
||||
|
||||
|
||||
## Your First Changes
|
||||
|
||||
Below are some first things to try with your new custom modules. You can test these to get a feel
|
||||
for the system. See also [Tutorials](Tutorials) for more step-by-step help and special cases.
|
||||
|
||||
### Tweak Default Character
|
||||
|
||||
We will add some simple rpg attributes to our default Character. In the next section we will follow
|
||||
up with a new command to view those attributes.
|
||||
|
||||
1. Edit `mygame/typeclasses/characters.py` and modify the `Character` class. The
|
||||
`at_object_creation` method also exists on the `DefaultCharacter` parent and will overload it. The
|
||||
`get_abilities` method is unique to our version of `Character`.
|
||||
|
||||
```python
|
||||
class Character(DefaultCharacter):
|
||||
# [...]
|
||||
def at_object_creation(self):
|
||||
"""
|
||||
Called only at initial creation. This is a rather silly
|
||||
example since ability scores should vary from Character to
|
||||
Character and is usually set during some character
|
||||
generation step instead.
|
||||
"""
|
||||
#set persistent attributes
|
||||
self.db.strength = 5
|
||||
self.db.agility = 4
|
||||
self.db.magic = 2
|
||||
|
||||
def get_abilities(self):
|
||||
"""
|
||||
Simple access method to return ability
|
||||
scores as a tuple (str,agi,mag)
|
||||
"""
|
||||
return self.db.strength, self.db.agility, self.db.magic
|
||||
```
|
||||
|
||||
1. [Reload](../../Setup/Start-Stop-Reload) the server (you will still be connected to the game after doing
|
||||
this). Note that if you examine *yourself* you will *not* see any new Attributes appear yet. Read
|
||||
the next section to understand why.
|
||||
|
||||
#### Updating Yourself
|
||||
|
||||
It's important to note that the new [Attributes](../../Component/Attributes) we added above will only be stored on
|
||||
*newly* created characters. The reason for this is simple: The `at_object_creation` method, where we
|
||||
added those Attributes, is per definition only called when the object is *first created*, then never
|
||||
again. This is usually a good thing since those Attributes may change over time - calling that hook
|
||||
would reset them back to start values. But it also means that your existing character doesn't have
|
||||
them yet. You can see this by calling the `get_abilities` hook on yourself at this point:
|
||||
|
||||
```
|
||||
# (you have to be superuser to use @py)
|
||||
@py self.get_abilities()
|
||||
<<< (None, None, None)
|
||||
```
|
||||
|
||||
This is easily remedied.
|
||||
|
||||
```
|
||||
@update self
|
||||
```
|
||||
|
||||
This will (only) re-run `at_object_creation` on yourself. You should henceforth be able to get the
|
||||
abilities successfully:
|
||||
|
||||
```
|
||||
@py self.get_abilities()
|
||||
<<< (5, 4, 2)
|
||||
```
|
||||
|
||||
This is something to keep in mind if you start building your world before your code is stable -
|
||||
startup-hooks will not (and should not) automatically run on *existing* objects - you have to update
|
||||
your existing objects manually. Luckily this is a one-time thing and pretty simple to do. If the
|
||||
typeclass you want to update is in `typeclasses.myclass.MyClass`, you can do the following (e.g.
|
||||
from `evennia shell`):
|
||||
|
||||
```python
|
||||
from typeclasses.myclass import MyClass
|
||||
# loop over all MyClass instances in the database
|
||||
# and call .swap_typeclass on them
|
||||
for obj in MyClass.objects.all():
|
||||
obj.swap_typeclass(MyClass, run_start_hooks="at_object_creation")
|
||||
```
|
||||
|
||||
Using `swap_typeclass` to the same typeclass we already have will re-run the creation hooks (this is
|
||||
what the `@update` command does under the hood). From in-game you can do the same with `@py`:
|
||||
|
||||
```
|
||||
@py typeclasses.myclass import MyClass;[obj.swap_typeclass(MyClass) for obj in
|
||||
MyClass.objects.all()]
|
||||
```
|
||||
|
||||
See the [Object Typeclass tutorial](Adding-Object-Typeclass-Tutorial) for more help and the
|
||||
[Typeclasses](../../Component/Typeclasses) and [Attributes](../../Component/Attributes) page for detailed documentation about
|
||||
Typeclasses and Attributes.
|
||||
|
||||
#### Troubleshooting: Updating Yourself
|
||||
|
||||
One may experience errors for a number of reasons. Common beginner errors are spelling mistakes,
|
||||
wrong indentations or code omissions leading to a `SyntaxError`. Let's say you leave out a colon
|
||||
from the end of a class function like so: ```def at_object_creation(self)```. The client will reload
|
||||
without issue. *However*, if you look at the terminal/console (i.e. not in-game), you will see
|
||||
Evennia complaining (this is called a *traceback*):
|
||||
|
||||
```
|
||||
Traceback (most recent call last):
|
||||
File "C:\mygame\typeclasses\characters.py", line 33
|
||||
def at_object_creation(self)
|
||||
^
|
||||
SyntaxError: invalid syntax
|
||||
```
|
||||
|
||||
Evennia will still be restarting and following the tutorial, doing `@py self.get_abilities()` will
|
||||
return the right response `(None, None, None)`. But when attempting to `@typeclass/force self` you
|
||||
will get this response:
|
||||
|
||||
```python
|
||||
AttributeError: 'DefaultObject' object has no attribute 'get_abilities'
|
||||
```
|
||||
|
||||
The full error will show in the terminal/console but this is confusing since you did add
|
||||
`get_abilities` before. Note however what the error says - you (`self`) should be a `Character` but
|
||||
the error talks about `DefaultObject`. What has happened is that due to your unhandled `SyntaxError`
|
||||
earlier, Evennia could not load the `character.py` module at all (it's not valid Python). Rather
|
||||
than crashing, Evennia handles this by temporarily falling back to a safe default - `DefaultObject`
|
||||
- in order to keep your MUD running. Fix the original `SyntaxError` and reload the server. Evennia
|
||||
will then be able to use your modified `Character` class again and things should work.
|
||||
|
||||
> Note: Learning how to interpret an error traceback is a critical skill for anyone learning Python.
|
||||
Full tracebacks will appear in the terminal/Console you started Evennia from. The traceback text can
|
||||
sometimes be quite long, but you are usually just looking for the last few lines: The description of
|
||||
the error and the filename + line number for where the error occurred. In the example above, we see
|
||||
it's a `SyntaxError` happening at `line 33` of `mygame\typeclasses\characters.py`. In this case it
|
||||
even points out *where* on the line it encountered the error (the missing colon). Learn to read
|
||||
tracebacks and you'll be able to resolve the vast majority of common errors easily.
|
||||
|
||||
### Add a New Default Command
|
||||
|
||||
The `@py` command used above is only available to privileged users. We want any player to be able to
|
||||
see their stats. Let's add a new [command](../../Component/Commands) to list the abilities we added in the previous
|
||||
section.
|
||||
|
||||
1. Open `mygame/commands/command.py`. You could in principle put your command anywhere but this
|
||||
module has all the imports already set up along with some useful documentation. Make a new class at
|
||||
the bottom of this file:
|
||||
|
||||
```python
|
||||
class CmdAbilities(Command):
|
||||
"""
|
||||
List abilities
|
||||
|
||||
Usage:
|
||||
abilities
|
||||
|
||||
Displays a list of your current ability values.
|
||||
"""
|
||||
key = "abilities"
|
||||
aliases = ["abi"]
|
||||
lock = "cmd:all()"
|
||||
help_category = "General"
|
||||
|
||||
def func(self):
|
||||
"implements the actual functionality"
|
||||
|
||||
str, agi, mag = self.caller.get_abilities()
|
||||
string = "STR: %s, AGI: %s, MAG: %s" % (str, agi, mag)
|
||||
self.caller.msg(string)
|
||||
```
|
||||
|
||||
1. Next you edit `mygame/commands/default_cmdsets.py` and add a new import to it near the top:
|
||||
|
||||
```python
|
||||
from commands.command import CmdAbilities
|
||||
```
|
||||
|
||||
1. In the `CharacterCmdSet` class, add the following near the bottom (it says where):
|
||||
|
||||
```python
|
||||
self.add(CmdAbilities())
|
||||
```
|
||||
|
||||
1. [Reload](../../Setup/Start-Stop-Reload) the server (noone will be disconnected by doing this).
|
||||
|
||||
You (and anyone else) should now be able to use `abilities` (or its alias `abi`) as part of your
|
||||
normal commands in-game:
|
||||
|
||||
```
|
||||
abilities
|
||||
STR: 5, AGI: 4, MAG: 2
|
||||
```
|
||||
|
||||
See the [Adding a Command tutorial](Adding-Command-Tutorial) for more examples and the
|
||||
[Commands](../../Component/Commands) section for detailed documentation about the Command system.
|
||||
|
||||
### Make a New Type of Object
|
||||
|
||||
Let's test to make a new type of object. This example is an "wise stone" object that returns some
|
||||
random comment when you look at it, like this:
|
||||
|
||||
> look stone
|
||||
|
||||
A very wise stone
|
||||
|
||||
This is a very wise old stone.
|
||||
It grumbles and says: 'The world is like a rock of chocolate.'
|
||||
|
||||
1. Create a new module in `mygame/typeclasses/`. Name it `wiseobject.py` for this example.
|
||||
1. In the module import the base `Object` (`typeclasses.objects.Object`). This is empty by default,
|
||||
meaning it is just a proxy for the default `evennia.DefaultObject`.
|
||||
1. Make a new class in your module inheriting from `Object`. Overload hooks on it to add new
|
||||
functionality. Here is an example of how the file could look:
|
||||
|
||||
```python
|
||||
from random import choice
|
||||
from typeclasses.objects import Object
|
||||
|
||||
class WiseObject(Object):
|
||||
"""
|
||||
An object speaking when someone looks at it. We
|
||||
assume it looks like a stone in this example.
|
||||
"""
|
||||
def at_object_creation(self):
|
||||
"Called when object is first created"
|
||||
self.db.wise_texts = \
|
||||
["Stones have feelings too.",
|
||||
"To live like a stone is to not have lived at all.",
|
||||
"The world is like a rock of chocolate."]
|
||||
|
||||
def return_appearance(self, looker):
|
||||
"""
|
||||
Called by the look command. We want to return
|
||||
a wisdom when we get looked at.
|
||||
"""
|
||||
# first get the base string from the
|
||||
# parent's return_appearance.
|
||||
string = super().return_appearance(looker)
|
||||
wisewords = "\n\nIt grumbles and says: '%s'"
|
||||
wisewords = wisewords % choice(self.db.wise_texts)
|
||||
return string + wisewords
|
||||
```
|
||||
|
||||
1. Check your code for bugs. Tracebacks will appear on your command line or log. If you have a grave
|
||||
Syntax Error in your code, the source file itself will fail to load which can cause issues with the
|
||||
entire cmdset. If so, fix your bug and [reload the server from the command line](../../Setup/Start-Stop-Reload)
|
||||
(noone will be disconnected by doing this).
|
||||
1. Use `@create/drop stone:wiseobject.WiseObject` to create a talkative stone. If the `@create`
|
||||
command spits out a warning or cannot find the typeclass (it will tell you which paths it searched),
|
||||
re-check your code for bugs and that you gave the correct path. The `@create` command starts looking
|
||||
for Typeclasses in `mygame/typeclasses/`.
|
||||
1. Use `look stone` to test. You will see the default description ("You see nothing special")
|
||||
followed by a random message of stony wisdom. Use `@desc stone = This is a wise old stone.` to make
|
||||
it look nicer. See the [Builder Docs](Builder-Docs) for more information.
|
||||
|
||||
Note that `at_object_creation` is only called once, when the stone is first created. If you make
|
||||
changes to this method later, already existing stones will not see those changes. As with the
|
||||
`Character` example above you can use `@typeclass/force` to tell the stone to re-run its
|
||||
initialization.
|
||||
|
||||
The `at_object_creation` is a special case though. Changing most other aspects of the typeclass does
|
||||
*not* require manual updating like this - you just need to `@reload` to have all changes applied
|
||||
automatically to all existing objects.
|
||||
|
||||
## Where to Go From Here?
|
||||
|
||||
There are more [Tutorials](Tutorials), including one for building a [whole little MUSH-like
|
||||
game](Tutorial-for-basic-MUSH-like-game) - that is instructive also if you have no interest in
|
||||
MUSHes per se. A good idea is to also get onto the [IRC
|
||||
chat](http://webchat.freenode.net/?channels=evennia) and the [mailing
|
||||
list](https://groups.google.com/forum/#!forum/evennia) to get in touch with the community and other
|
||||
developers.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
This tutorial will elaborate on the many ways one can parse command arguments. The first step after
|
||||
[adding a command](Adding-Command-Tutorial) usually is to parse its arguments. There are lots of
|
||||
[adding a command](Part1/Adding-Commands) usually is to parse its arguments. There are lots of
|
||||
ways to do it, but some are indeed better than others and this tutorial will try to present them.
|
||||
|
||||
If you're a Python beginner, this tutorial might help you a lot. If you're already familiar with
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ tend to jump directly to this part without doing the **Planning** first. Neither
|
|||
*will* lead to you having to redo all your hard work at least once, probably more.
|
||||
|
||||
Evennia's [Evennia Component overview](../../../Component/Component-Overview) tries to help you with this bit of development. We
|
||||
also have a slew of [Tutorials](Tutorials) with worked examples. Evennia tries hard to make this
|
||||
also have a slew of [Tutorials](../../Howto-Overview) with worked examples. Evennia tries hard to make this
|
||||
part easier for you, but there is no way around the fact that if you want anything but a very basic
|
||||
Talker-type game you *will* have to bite the bullet and code your game (or find a coder willing to
|
||||
do it for you).
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ class CmdAttack(Command):
|
|||
```
|
||||
|
||||
The `attack` command will not go into the combat cmdset but rather into the default cmdset. See e.g.
|
||||
the [Adding Command Tutorial](Adding-Command-Tutorial) if you are unsure about how to do this.
|
||||
the [Adding Command Tutorial](Part1/Adding-Commands) if you are unsure about how to do this.
|
||||
|
||||
## Expanding the example
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ focused on free form storytelling. Even if you are not interested in MUSH:es, th
|
|||
first game-type to try since it's not so code heavy. You will be able to use the same principles for
|
||||
building other types of games.
|
||||
|
||||
The tutorial starts from scratch. If you did the [First Steps Coding](First-Steps-Coding) tutorial
|
||||
The tutorial starts from scratch. If you did the [First Steps Coding](Starting-Part1) tutorial
|
||||
already you should have some ideas about how to do some of the steps already.
|
||||
|
||||
The following are the (very simplistic and cut-down) features we will implement (this was taken from
|
||||
|
|
@ -650,5 +650,5 @@ useful, same is true for the combat score principle. The `+attack` could be made
|
|||
specific player (or npc) and automatically compare their relevant attributes to determine a result.
|
||||
|
||||
To continue from here, you can take a look at the [Tutorial World](Part1/Tutorial-World-Introduction). For
|
||||
more specific ideas, see the [other tutorials and hints](Tutorials) as well
|
||||
more specific ideas, see the [other tutorials and hints](../Howto-Overview) as well
|
||||
as the [Evennia Component overview](../../Component/Component-Overview).
|
||||
|
|
@ -449,7 +449,7 @@ Reload) the Evennia server. You may also want to familiarize yourself with some
|
|||
in our Glossary](Glossary). After that, why not experiment with [creating some new items and build
|
||||
some new rooms](Building-Quickstart) out from Limbo.
|
||||
|
||||
From here on, you could move on to do one of our [introductory tutorials](Tutorials) or simply dive
|
||||
From here on, you could move on to do one of our [introductory tutorials](../Howto/Howto-Overview) or simply dive
|
||||
headlong into Evennia's comprehensive [manual](https://github.com/evennia/evennia/wiki). While
|
||||
Evennia has no major game systems out of the box, we do supply a range of optional *contribs* that
|
||||
you can use or borrow from. They range from dice rolling and alternative color schemes to barter and
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pip install python-twitter
|
|||
|
||||
Evennia doesn't have a `tweet` command out of the box so you need to write your own little
|
||||
[Command](../Component/Commands) in order to tweet. If you are unsure about how commands work and how to add
|
||||
them, it can be an idea to go through the [Adding a Command Tutorial](../Howto/Starting/Adding-Command-Tutorial)
|
||||
them, it can be an idea to go through the [Adding a Command Tutorial](../Howto/Starting/Part1/Adding-Commands)
|
||||
before continuing.
|
||||
|
||||
You can create the command in a separate command module (something like `mygame/commands/tweet.py`)
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ Docker) to deploy your game to the remote server; it will likely ease installati
|
|||
Docker images may be a little confusing if you are completely new to them though.
|
||||
|
||||
If not using docker, and assuming you know how to connect to your account over ssh/PuTTy, you should
|
||||
be able to follow the [Getting Started](Getting-Started) instructions normally. You only need Python
|
||||
be able to follow the [Setup Quickstart](Setup-Quickstart) instructions normally. You only need Python
|
||||
and GIT pre-installed; these should both be available on any servers (if not you should be able to
|
||||
easily ask for them to be installed). On a VPS or Cloud service you can install them yourself as
|
||||
needed.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ evennia|docker /usr/src/game $
|
|||
This is a normal shell prompt. We are in the `/usr/src/game` location inside the docker container.
|
||||
If you had anything in the folder you started from, you should see it here (with `ls`) since we
|
||||
mounted the current directory to `usr/src/game` (with `-v` above). You have the `evennia` command
|
||||
available and can now proceed to create a new game as per the [Getting Started](Getting-Started)
|
||||
available and can now proceed to create a new game as per the [Setup Quickstart](Setup-Quickstart)
|
||||
instructions (you can skip the virtualenv and install 'globally' in the container though).
|
||||
|
||||
You can run Evennia from inside this container if you want to, it's like you are root in a little
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
You control Evennia from your game folder (we refer to it as `mygame/` here), using the `evennia`
|
||||
program. If the `evennia` program is not available on the command line you must first install
|
||||
Evennia as described in the [Getting Started](Getting-Started) page.
|
||||
Evennia as described in the [Setup Quickstart](Setup-Quickstart) page.
|
||||
|
||||
> Hint: If you ever try the `evennia` command and get an error complaining that the command is not
|
||||
available, make sure your [virtualenv](../Glossary#virtualenv) is active.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
- [Coding/Coding Overview](Coding/Coding-Overview)
|
||||
- [Coding/Continuous Integration](Coding/Continuous-Integration)
|
||||
- [Coding/Debugging](Coding/Debugging)
|
||||
- [Coding/Execute Python Code](Coding/Execute-Python-Code)
|
||||
- [Coding/Flat API](Coding/Flat-API)
|
||||
- [Coding/Profiling](Coding/Profiling)
|
||||
- [Coding/Quirks](Coding/Quirks)
|
||||
|
|
@ -35,8 +34,10 @@
|
|||
- [Component/MonitorHandler](Component/MonitorHandler)
|
||||
- [Component/Nicks](Component/Nicks)
|
||||
- [Component/Objects](Component/Objects)
|
||||
- [Component/Outputfuncs](Component/Outputfuncs)
|
||||
- [Component/Portal And Server](Component/Portal-And-Server)
|
||||
- [Component/Scripts](Component/Scripts)
|
||||
- [Component/Server](Component/Server)
|
||||
- [Component/Server Conf](Component/Server-Conf)
|
||||
- [Component/Sessions](Component/Sessions)
|
||||
- [Component/Signals](Component/Signals)
|
||||
|
|
@ -94,7 +95,6 @@
|
|||
- [Howto/NPC shop Tutorial](Howto/NPC-shop-Tutorial)
|
||||
- [Howto/Starting/Add a simple new web page](Howto/Starting/Add-a-simple-new-web-page)
|
||||
- [Howto/Starting/Coordinates](Howto/Starting/Coordinates)
|
||||
- [Howto/Starting/First Steps Coding](Howto/Starting/First-Steps-Coding)
|
||||
- [Howto/Starting/Implementing a game rule system](Howto/Starting/Implementing-a-game-rule-system)
|
||||
- [Howto/Starting/Parsing command arguments, theory and best practices](Howto/Starting/Parsing-command-arguments,-theory-and-best-practices)
|
||||
- [Howto/Starting/Part1/Adding Commands](Howto/Starting/Part1/Adding-Commands)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue