More updates to the starting tutorial
This commit is contained in:
parent
dc811f2e08
commit
e7f4967201
10 changed files with 553 additions and 194 deletions
|
|
@ -298,7 +298,7 @@ This is a [clickable link][mylink]. This is [another link][1].
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
[mylink]: http://...
|
[mylink](http://...)
|
||||||
[1]: My-Document
|
[1]: My-Document
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -662,19 +662,19 @@ to understand our friendly Google-style docstrings used in classes and functions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[sphinx]: https://www.sphinx-doc.org/en/master/
|
[sphinx](https://www.sphinx-doc.org/en/master/)
|
||||||
[recommonmark]: https://recommonmark.readthedocs.io/en/latest/index.html
|
[recommonmark](https://recommonmark.readthedocs.io/en/latest/index.html)
|
||||||
[commonmark]: https://spec.commonmark.org/current/
|
[commonmark](https://spec.commonmark.org/current/)
|
||||||
[commonmark-help]: https://commonmark.org/help/
|
[commonmark-help](https://commonmark.org/help/)
|
||||||
[sphinx-autodoc]: http://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc
|
[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
|
[sphinx-napoleon](http://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)
|
||||||
[getting-started]: Setup/Getting-Started
|
[getting-started]: Setup/Getting-Started
|
||||||
[contributing]: Contributing
|
[contributing]: Contributing
|
||||||
[ReST]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html
|
[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
|
[ReST-tables](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#tables)
|
||||||
[ReST-directives]: https://www.sphinx-doc.org/en/master/usage/restruturedtext/directives.html
|
[ReST-directives](https://www.sphinx-doc.org/en/master/usage/restruturedtext/directives.html)
|
||||||
[Windows-WSL]: https://docs.microsoft.com/en-us/windows/wsl/install-win10
|
[Windows-WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
|
||||||
[linkdemo]: #Links
|
[linkdemo]: #Links
|
||||||
[retext]: https://github.com/retext-project/retext
|
[retext](https://github.com/retext-project/retext)
|
||||||
[grip]: https://github.com/joeyespo/grip
|
[grip](https://github.com/joeyespo/grip)
|
||||||
[pycharm]: https://www.jetbrains.com/pycharm/
|
[pycharm](https://www.jetbrains.com/pycharm/)
|
||||||
|
|
|
||||||
|
|
@ -105,14 +105,14 @@ beyond our manpower. However, if your code were to *not* be accepted for merger
|
||||||
will instead add a link to your online repository so people can still find and use your work if they
|
will instead add a link to your online repository so people can still find and use your work if they
|
||||||
want.
|
want.
|
||||||
|
|
||||||
[ohloh]: http://www.ohloh.net/p/evennia
|
[ohloh](http://www.ohloh.net/p/evennia)
|
||||||
[patron]: https://www.patreon.com/griatch
|
[patron](https://www.patreon.com/griatch)
|
||||||
[donate]: https://www.paypal.com/en/cgi-bin/webscr?cmd=_flow&SESSION=TWy_epDPSWqNr4UJCOtVWxl-
|
[donate](https://www.paypal.com/en/cgi-bin/webscr?cmd=_flow&SESSION=TWy_epDPSWqNr4UJCOtVWxl-)
|
||||||
pO1X1jbKiv_-
|
pO1X1jbKiv_-
|
||||||
UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4
|
UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4
|
||||||
[forking]: https://github.com/evennia/evennia/wiki/Version-Control#wiki-forking-from-evennia
|
[forking](https://github.com/evennia/evennia/wiki/Version-Control#wiki-forking-from-evennia)
|
||||||
[pullrequest]: https://github.com/evennia/evennia/pulls
|
[pullrequest](https://github.com/evennia/evennia/pulls)
|
||||||
[issues]: https://github.com/evennia/evennia/issues
|
[issues](https://github.com/evennia/evennia/issues)
|
||||||
[patch]: https://secure.wikimedia.org/wikipedia/en/wiki/Patch_%28computing%29
|
[patch](https://secure.wikimedia.org/wikipedia/en/wiki/Patch_%28computing%29 )
|
||||||
[codestyle]: https://github.com/evennia/evennia/blob/master/CODING_STYLE.md
|
[codestyle](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md)
|
||||||
[tutorials]: https://github.com/evennia/evennia/wiki/Tutorials
|
[tutorials](https://github.com/evennia/evennia/wiki/Tutorials)
|
||||||
|
|
@ -54,15 +54,15 @@ appreciate the work done with the server! You can also encourage the community t
|
||||||
issues by putting up a monetary [bounty][bountysource] on it.
|
issues by putting up a monetary [bounty][bountysource] on it.
|
||||||
|
|
||||||
|
|
||||||
[form]: https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid=0
|
[form](https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid=0)
|
||||||
[group]: http://groups.google.com/group/evennia/
|
[group](http://groups.google.com/group/evennia/)
|
||||||
[issues]: https://github.com/evennia/evennia/issues
|
[issues](https://github.com/evennia/evennia/issues)
|
||||||
[issues-master]: https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Abug%20label%3Amaster-branch
|
[issues-master](https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Abug%20label%3Amaster-branch)
|
||||||
[chat]: http://webchat.freenode.net/?channels=evennia
|
[chat](http://webchat.freenode.net/?channels=evennia)
|
||||||
[paypal]: https://www.paypal.com/se/cgi-bin/webscr?cmd=_flow&SESSION=Z-VlOvfGjYq2qvCDOUGpb6C8Due7skT0qOklQEy5EbaD1f0eyEQaYlmCc8O&dispatch=5885d80a13c0db1f8e263663d3faee8d64ad11bbf4d2a5a1a0d303a50933f9b2
|
[paypal](https://www.paypal.com/se/cgi-bin/webscr?cmd=_flow&SESSION=Z-VlOvfGjYq2qvCDOUGpb6C8Due7skT0qOklQEy5EbaD1f0eyEQaYlmCc8O&dispatch=5885d80a13c0db1f8e263663d3faee8d64ad11bbf4d2a5a1a0d303a50933f9b2)
|
||||||
[donate-img]: http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://www.paypalobjects.com/en%255fUS/SE/i/btn/btn%255fdonateCC%255fLG.gif&container=focus&gadget=a&rewriteMime=image/*
|
[donate-img](http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://www.paypalobjects.com/en%255fUS/SE/i/btn/btn%255fdonateCC%255fLG.gif&container=focus&gadget=a&rewriteMime=image/*)
|
||||||
[patreon]: https://www.patreon.com/griatch
|
[patreon](https://www.patreon.com/griatch)
|
||||||
[patreon-img]: http://www.evennia.com/_/rsrc/1424724909023/home/evennia_patreon_100x100.png
|
[patreon-img](http://www.evennia.com/_/rsrc/1424724909023/home/evennia_patreon_100x100.png)
|
||||||
[issues-bounties]: https://github.com/evennia/evennia/labels/bounty
|
[issues-bounties](https://github.com/evennia/evennia/labels/bounty)
|
||||||
[bountysource]: https://www.bountysource.com/teams/evennia
|
[bountysource](https://www.bountysource.com/teams/evennia)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,15 @@ This created a new 'box' (of the default object type) in your inventory. Use the
|
||||||
|
|
||||||
name box = very large box;box;very;crate
|
name box = very large box;box;very;crate
|
||||||
|
|
||||||
|
```warning:: MUD clients and semi-colon
|
||||||
|
|
||||||
|
Some traditional MUD clients use the semi-colon `;` to separate client inputs. If so,
|
||||||
|
the above line will give an error. You need to change your client to use another command-separator
|
||||||
|
or to put it in 'verbatim' mode. If you still have trouble, use the Evennia web client instead.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
We now renamed the box to _very large box_ (and this is what we will see when looking at it), but we
|
We now renamed the box to _very large box_ (and this is what we will see when looking at it), but we
|
||||||
will also recognize it by any of the other names we give - like _crate_ or simply _box_ as before.
|
will also recognize it by any of the other names we give - like _crate_ or simply _box_ as before.
|
||||||
We could have given these aliases directly after the name in the `create` command, this is true for
|
We could have given these aliases directly after the name in the `create` command, this is true for
|
||||||
|
|
@ -297,13 +306,11 @@ the history of your game world:
|
||||||
|
|
||||||
sethelp/add History = At the dawn of time ...
|
sethelp/add History = At the dawn of time ...
|
||||||
|
|
||||||
Next we will take a little detour to look at the _Tutorial World_. This is a little solo adventure
|
You will now find your new `History` entry in the `help` list and read your help-text with `help History`.
|
||||||
that comes with Evennia, a showcase for some of the things that are possible.
|
|
||||||
|
|
||||||
|
|
||||||
## Adding a World
|
## Adding a World
|
||||||
|
|
||||||
After this brief introduction to building you may be ready to see a more fleshed-out example.
|
After this brief introduction to building and using in-game commands you may be ready to see a more fleshed-out
|
||||||
Evennia comes with a tutorial world for you to explore. We will try that out in the next section.
|
example. Evennia comes with a tutorial world for you to explore. We will try that out in the next section.
|
||||||
|
|
||||||
[prev lesson](Starting-Part1) | [next lesson](Tutorial-World-Introduction)
|
[prev lesson](Starting-Part1) | [next lesson](Tutorial-World-Introduction)
|
||||||
|
|
|
||||||
|
|
@ -99,4 +99,4 @@ chat](http://webchat.freenode.net/?channels=evennia) are also there for you.
|
||||||
And finally, of course, have fun!
|
And finally, of course, have fun!
|
||||||
|
|
||||||
[feature-request]: (https://github.com/evennia/evennia/issues/new?title=Feature+Request%3a+%3Cdescriptive+title+here%3E&body=%23%23%23%23+Description+of+the+suggested+feature+and+how+it+is+supposed+to+work+for+the+admin%2fend+user%3a%0D%0A%0D%0A%0D%0A%23%23%23%23+A+list+of+arguments+for+why+you+think+this+new+feature+should+be+included+in+Evennia%3a%0D%0A%0D%0A1.%0D%0A2.%0D%0A%0D%0A%23%23%23%23+Extra+information%2c+such+as+requirements+or+ideas+on+implementation%3a%0D%0A%0D%0A
|
[feature-request]: (https://github.com/evennia/evennia/issues/new?title=Feature+Request%3a+%3Cdescriptive+title+here%3E&body=%23%23%23%23+Description+of+the+suggested+feature+and+how+it+is+supposed+to+work+for+the+admin%2fend+user%3a%0D%0A%0D%0A%0D%0A%23%23%23%23+A+list+of+arguments+for+why+you+think+this+new+feature+should+be+included+in+Evennia%3a%0D%0A%0D%0A1.%0D%0A2.%0D%0A%0D%0A%23%23%23%23+Extra+information%2c+such+as+requirements+or+ideas+on+implementation%3a%0D%0A%0D%0A
|
||||||
[bug]: https://github.com/evennia/evennia/issues/new?title=Bug%3a+%3Cdescriptive+title+here%3E&body=%23%23%23%23+Steps+to+reproduce+the+issue%3a%0D%0A%0D%0A1.+%0D%0A2.+%0D%0A3.+%0D%0A%0D%0A%23%23%23%23+What+I+expect+to+see+and+what+I+actually+see+%28tracebacks%2c+error+messages+etc%29%3a%0D%0A%0D%0A%0D%0A%0D%0A%23%23%23%23+Extra+information%2c+such+as+Evennia+revision%2frepo%2fbranch%2c+operating+system+and+ideas+for+how+to+solve%3a%0D%0A%0D%0A
|
[bug](https://github.com/evennia/evennia/issues/new?title=Bug%3a+%3Cdescriptive+title+here%3E&body=%23%23%23%23+Steps+to+reproduce+the+issue%3a%0D%0A%0D%0A1.+%0D%0A2.+%0D%0A3.+%0D%0A%0D%0A%23%23%23%23+What+I+expect+to+see+and+what+I+actually+see+%28tracebacks%2c+error+messages+etc%29%3a%0D%0A%0D%0A%0D%0A%0D%0A%23%23%23%23+Extra+information%2c+such+as+Evennia+revision%2frepo%2fbranch%2c+operating+system+and+ideas+for+how+to+solve%3a%0D%0A%0D%0A)
|
||||||
|
|
@ -29,7 +29,7 @@ game. This is useful for quick testing. From the game's input line, enter the fo
|
||||||
|
|
||||||
```sidebar:: Command input
|
```sidebar:: Command input
|
||||||
|
|
||||||
The lines with a `>` indicate input to enter in-game, while the lines below are the
|
The line with `>` indicates input to enter in-game, while the lines below are the
|
||||||
expected return from that input.
|
expected return from that input.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -41,51 +41,140 @@ You will see
|
||||||
To understand what is going on: some extra info: The `print(...)` *function* is the basic, in-built
|
To understand what is going on: some extra info: The `print(...)` *function* is the basic, in-built
|
||||||
way to output text in Python. We are sending "Hello World" as an _argument_ to this function. The quotes `"..."`
|
way to output text in Python. We are sending "Hello World" as an _argument_ to this function. The quotes `"..."`
|
||||||
mean that you are inputting a *string* (i.e. text). You could also have used single-quotes `'...'`,
|
mean that you are inputting a *string* (i.e. text). You could also have used single-quotes `'...'`,
|
||||||
Python accepts both.
|
Python accepts both. A third variant is triple-quotes (`"""..."""` or `'''...'''`, which work across multiple
|
||||||
|
lines and are common for larger text-blocks. The way we use the `py` command right now only supports
|
||||||
|
single-line input however.
|
||||||
|
|
||||||
The `print` command is a standard Python structure. We can use that here in the `py` command since
|
### Making some text 'graphics'
|
||||||
we can se the output. It's great for debugging and quick testing. But if you need to send a text
|
|
||||||
to an actual player, `print` won't do, because it doesn't know _who_ to send to. Try this:
|
|
||||||
|
|
||||||
> py me.msg("Hello world!")
|
When making a text-game you will, unsurprisingly, be working a lot with text. Even if you have the occational
|
||||||
Hello world!
|
button or even graphical element, the normal process is for the user to input commands as
|
||||||
|
text and get text back. As we saw above, a piece of text is called a _string_ in Python and is enclosed in
|
||||||
|
either single- or double-quotes.
|
||||||
|
|
||||||
This looks the same as the `print` result, but we are now actually messaging a specific *object*,
|
Strings can be added together:
|
||||||
`me`. The `me` is a shortcut to 'us', the one running the `py` command. It is not some special
|
|
||||||
Python thing, but something Evennia just makes available in the `py` command for convenience
|
|
||||||
(`self` is an alias).
|
|
||||||
|
|
||||||
The `me` is an example of an *Object instance*. Objects are fundamental in Python and Evennia.
|
> py print("This is a " + "breaking change.")
|
||||||
The `me` object also contains a lot of useful resources for doing
|
This is a breaking change.
|
||||||
things with that object. We access those resources with '`.`'.
|
|
||||||
|
|
||||||
One such resource is `msg`, which works like `print` except it sends the text to the object it
|
A string multiplied with a number will repeat that string as many times:
|
||||||
is attached to. So if we, for example, had an object `you`, doing `you.msg(...)` would send a message
|
|
||||||
to the object `you`.
|
> py print("|" + "-" * 40 + "|")
|
||||||
|
|----------------------------------------|
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
> py print("A" + "a" * 5 + "rgh!")
|
||||||
|
Aaaaaargh!
|
||||||
|
|
||||||
|
While combining different strings is useful, even more powerful is the ability to modify the contents
|
||||||
|
of the string in-place. There are several ways to do this in Python and we'll show two of them here. The first
|
||||||
|
is to use the `.format` _method_ of the string:
|
||||||
|
|
||||||
```sidebar:: Functions and Methods
|
```sidebar:: Functions and Methods
|
||||||
|
|
||||||
Function:
|
Function:
|
||||||
Stand-alone in a python module, like `print()`
|
Something that performs and action when you `call` it with zero or more `arguments`. A function
|
||||||
|
is stand-alone in a python module, like `print()`
|
||||||
Method:
|
Method:
|
||||||
Something that sits "on" an object, like `.msg()`
|
A function that sits "on" an object, like `<string>.format()`.
|
||||||
```
|
```
|
||||||
|
|
||||||
For now, `print` and `me.msg` behaves the same, just remember that `print` is mainly used for
|
A method can be thought of as a resource "on" another object. The method knows on which object it
|
||||||
debugging and `.msg()` will be more useful for you in the future.
|
sits and can thus affect it in various ways. You access it with the period `.`. In this case, the
|
||||||
|
string has a resource `format(...)` that modifies it. More specifically, it replaced the `{}` marker
|
||||||
|
inside the string with the value passed to the format. You can do so many times:
|
||||||
|
|
||||||
For fun, try printing other things. Also try this:
|
|
||||||
|
|
||||||
> py self.msg("|rThis is red text!")
|
|
||||||
|
> py print("This is a {} idea!".format("bad"))
|
||||||
|
This is a bad idea!
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
> py print("This is the {} and {} {} idea!".format("first", "second", "great"))
|
||||||
|
This is the first and second great idea!
|
||||||
|
|
||||||
Adding that `|r` at the start will turn our output red. Enter the command `color ansi` or `color xterm`
|
> Note the double-parenthesis at the end - the first closes the `format(...` method and the outermost
|
||||||
to see which colors are available.
|
closes the `print(...`. Not closing them will give you a scary `SyntaxError`. We will talk a
|
||||||
|
little more about errors in the next section, for now just fix until it prints as expected.
|
||||||
|
|
||||||
|
Here we passed three comma-separated strings as _arguments_ to the string's `format` method. These
|
||||||
|
replaced the `{}` markers in the same order as they were given.
|
||||||
|
|
||||||
|
The input does not have to be strings either:
|
||||||
|
|
||||||
|
> py print("STR: {}, DEX: {}, INT: {}".format(12, 14, 8))
|
||||||
|
STR: 12, DEX: 14, INT: 8
|
||||||
|
|
||||||
|
To separate two Python instructions on the same line, you use the semi-colon, `;`. Try this:
|
||||||
|
|
||||||
|
> py a = "awesome sauce" ; print("This is {}!".format(a))
|
||||||
|
This is awesome sauce!
|
||||||
|
|
||||||
|
```warning:: MUD clients and semi-colon
|
||||||
|
|
||||||
|
Some MUD clients use the semi-colon `;` to split client-inputs
|
||||||
|
into separate sends. If so, the above will give an error. Most clients allow you to
|
||||||
|
run in 'verbatim' mode or to remap to use some other separator than `;`. If you still have
|
||||||
|
trouble, just use the Evennia web client for now. In real Python code you'll pretty much never use
|
||||||
|
the semi-colon.
|
||||||
|
```
|
||||||
|
|
||||||
|
What happened here was that we _assigned_ the string `"awesome sauce"` to a _variable_ we chose
|
||||||
|
to name `a`. In the next statement, Python remembered what `a` was and we passed that into `format()`
|
||||||
|
to get the output. If you replaced the value of `a` with something else in between, _that_ would be printed
|
||||||
|
instead.
|
||||||
|
|
||||||
|
Here's the stat-example again, moving the stats to variables (here we just set them, but in a real
|
||||||
|
game they may be changed over time, or modified by circumstance):
|
||||||
|
|
||||||
|
> py str, dex, int = 13, 14, 8 ; print("STR: {}, DEX: {}, INT: {}".format(stren, dex, int))
|
||||||
|
STR: 13, DEX: 14, INT: 8
|
||||||
|
|
||||||
|
The point is that even if the values of the stats change, the print() statement would not change - it just keeps
|
||||||
|
pretty-printing whatever is given to it.
|
||||||
|
|
||||||
|
Using `.format()` is convenient (and there is a [lot more](https://www.w3schools.com/python/ref_string_format.asp)
|
||||||
|
you can do with it). But the _f-string_ can be even more convenient. An
|
||||||
|
f-string looks like a normal string ... except there is an `f` front of it, like this:
|
||||||
|
|
||||||
|
f"this is now an f-string."
|
||||||
|
|
||||||
|
An f-string on its own is just like any other string. But let's redo the example we did before, using an f-string:
|
||||||
|
|
||||||
|
> py a = "awesome sauce" ; print(f"This is {a}!")
|
||||||
|
This is awesome sauce!
|
||||||
|
|
||||||
|
We could just insert that `a` variable directly into the f-string using `{a}`. Fewer parentheses to
|
||||||
|
remember and arguable easier to read as well.
|
||||||
|
|
||||||
|
> py str, dex, int = 13, 14, 8 ; print(f"STR: {str}, DEX: {dex}, INT: {int}")
|
||||||
|
STR: 13, DEX: 14, INT: 8
|
||||||
|
|
||||||
|
We will be exploring more complex string concepts when we get to creating Commands and need to
|
||||||
|
parse and understand player input.
|
||||||
|
|
||||||
|
Python itself knows nothing about colored text, this is an Evennia thing. Evennia supports the
|
||||||
|
standard color schemes of traditional MUDs.
|
||||||
|
|
||||||
|
> py print("|rThis is red text!|n This is normal color.")
|
||||||
|
|
||||||
|
Adding that `|r` at the start will turn our output bright red. `|R` will make it dark red. `|n`
|
||||||
|
gives the normal text color. You can also use RGB (Red-Green-Blue) values from 0-5 (Xterm256 colors):
|
||||||
|
|
||||||
|
> py print("|043This is a blue-green color.|[530|003 This is dark blue text on orange background.")
|
||||||
|
|
||||||
|
> If you don't see the expected color, your client or terminal may not support Xterm256 (or
|
||||||
|
color at all). Use the Evennia webclient.
|
||||||
|
|
||||||
|
Use the commands `color ansi` or `color xterm` to see which colors are available. Experiment!
|
||||||
|
|
||||||
### Importing code from other modules
|
### Importing code from other modules
|
||||||
|
|
||||||
As we saw in the previous section, we could use `me.msg` to access the `msg` method on `me`. This
|
As we saw in the previous sections, we used `.format` to format strings and `me.msg` to access
|
||||||
use of the full-stop character is used to access all sorts of resources, including that in other
|
the `msg` method on `me`. This use of the full-stop character is used to access all sorts of resources,
|
||||||
Python modules. If you've been following along, this is what we've referred to as the "Python path".
|
including that in other Python modules.
|
||||||
|
|
||||||
Keep your game running, then open a text editor of your choice. If your game folder is called
|
Keep your game running, then open a text editor of your choice. If your game folder is called
|
||||||
`mygame`, create a new text file `test.py` in the subfolder `mygame/world`. This is how the file
|
`mygame`, create a new text file `test.py` in the subfolder `mygame/world`. This is how the file
|
||||||
|
|
@ -130,16 +219,12 @@ path - Evennia handles this for us.
|
||||||
When you import the module, the top "level" of it will execute. In this case, it will immediately
|
When you import the module, the top "level" of it will execute. In this case, it will immediately
|
||||||
print "Hello World".
|
print "Hello World".
|
||||||
|
|
||||||
> If you look in the folder you'll also often find new files ending with `.pyc`. These are compiled
|
|
||||||
Python binaries that Python auto-creates when running code. Just ignore them, you should never edit
|
|
||||||
those anyway.
|
|
||||||
|
|
||||||
Now try to run this a second time:
|
Now try to run this a second time:
|
||||||
|
|
||||||
> py import world.test
|
> py import world.test
|
||||||
|
|
||||||
You will *not* see any output this second time or any subsequent times! This is not a bug. Rather
|
You will *not* see any output this second time or any subsequent times! This is not a bug. Rather
|
||||||
it is because Python is being clever - it stores all imported modules and to be efficient it will
|
it is because of how Python importing works - it stores all imported modules and will
|
||||||
avoid importing them more than once. So your `print` will only run the first time, when the module
|
avoid importing them more than once. So your `print` will only run the first time, when the module
|
||||||
is first imported.
|
is first imported.
|
||||||
|
|
||||||
|
|
@ -159,29 +244,124 @@ not very useful.
|
||||||
> We'll get back to more advanced ways to import code in later tutorial sections - this is an
|
> We'll get back to more advanced ways to import code in later tutorial sections - this is an
|
||||||
> important topic. But for now, let's press on and resolve this particular problem.
|
> important topic. But for now, let's press on and resolve this particular problem.
|
||||||
|
|
||||||
### Parsing Python errors
|
|
||||||
|
|
||||||
Running print only on import is not too helpful. We want to print whenever we like to!
|
### Our first own function
|
||||||
Go back to your `test.py` file and erase the single `print` statement you had. Replace
|
|
||||||
it with this instead:
|
We want to be able to print our hello-world message at any time, not just once after a server
|
||||||
|
reload. Change your `mygame/world/test.py` file to look like this:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
me.msg("Hello World!")
|
def hello_world():
|
||||||
|
print("Hello World!")
|
||||||
```
|
```
|
||||||
|
|
||||||
As you recall we used this with `py` earlier - it echoed "Hello World!" in-game.
|
As we are moving to multi-line Python code, there are some important things to remember:
|
||||||
Save your file and `reload` your server - this makes sure Evennia knows to re-import
|
|
||||||
it (with our new, fresh code this time).
|
|
||||||
|
|
||||||
To test it, import it using `py` as before
|
- Capitalization matters in Python. It must be `def` and not `DEF`, `who` is not the same as `Who`.
|
||||||
|
- Indentation matters in Python. The second line must be indented or it's not valid code. You should
|
||||||
|
also use a consistent indentation length. We *strongly* recommend that you, for your own sanity's sake,
|
||||||
|
set up your editor to always indent *4 spaces* (**not** a single tab-character) when you press the TAB key.
|
||||||
|
|
||||||
> py import world.test
|
So about that function. Line 1:
|
||||||
|
|
||||||
|
- `def` is short for "define" and defines a *function* (or a *method*, if sitting on an object).
|
||||||
|
This is a [reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html); try not to use
|
||||||
|
these words anywhere else.
|
||||||
|
- A function name can not have spaces but otherwise we could have called it almost anything. We call
|
||||||
|
it `hello_world`. Evennia follows [Python's standard naming style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style-points)
|
||||||
|
with lowercase letters and underscores. We recommend you do the same.
|
||||||
|
- The colon (`:`) at the end of line 1 indicates that the header of the function is complete.
|
||||||
|
|
||||||
|
Line 2:
|
||||||
|
|
||||||
|
- The indentation marks the beginning of the actual operating code of the function (the function's
|
||||||
|
*body*). If we wanted more lines to belong to this function those lines would all have to
|
||||||
|
start at least at this indentation level.
|
||||||
|
|
||||||
|
Now let's try this out. First `reload` your game to have it pick up
|
||||||
|
our updated Python module, then import it.
|
||||||
|
|
||||||
|
> reload
|
||||||
|
> py import world.test
|
||||||
|
|
||||||
|
Nothing happened! That is because the function in our module won't do anything just by importing it (this
|
||||||
|
is what we wanted). It will only act when we *call* it. So we need to first import the module and then access the
|
||||||
|
function within:
|
||||||
|
|
||||||
|
> py import world.test ; world.test.hello_world()
|
||||||
|
Hello world!
|
||||||
|
|
||||||
|
There is our "Hello World"! As mentioned earlier, use use semi-colon to put multiple
|
||||||
|
Python-statements on one line. Note also the previous warning about mud-clients using the `;` to their
|
||||||
|
own ends.
|
||||||
|
|
||||||
|
So what happened there? First we imported `world.test` as usual. But this time we continued and
|
||||||
|
accessed the `hello_world` function _inside_ the newly imported module.
|
||||||
|
|
||||||
|
By adding `()` to the `hello_world` function we _call_ it, that is we run the body of the function and
|
||||||
|
print our text. We can now redo this as many times as we want without having to `reload` in between:
|
||||||
|
|
||||||
|
|
||||||
|
> py import world.test ; world.test.hello_world()
|
||||||
|
Hello world!
|
||||||
|
> py import world.test ; world.test.hello_world()
|
||||||
|
Hello world!
|
||||||
|
|
||||||
|
> **Extra Credit:** As an exercise, try to pass something else into `hello_world`. Try for example
|
||||||
|
>to pass the number `5` or the string `"foo"`. You'll get errors telling you that they don't have
|
||||||
|
>the attribute `msg`. They don't care about `me` itself not being a string or a number. If you are
|
||||||
|
>familiar with other programming languages (especially C/Java) you may be tempted to start *validating*
|
||||||
|
>`who` to make sure it's of the right type before you send it. This is usually not recommended in Python.
|
||||||
|
>Python philosophy is to [handle](https://docs.python.org/2/tutorial/errors.html) the error if it happens
|
||||||
|
>rather than to add a lot of code to prevent it from happening. See [duck typing](https://en.wikipedia.org/wiki/Duck_typing)
|
||||||
|
>and the concept of _Leap before you Look_.
|
||||||
|
|
||||||
|
### Sending text to others
|
||||||
|
|
||||||
|
The `print` command is a standard Python structure. We can use that here in the `py` command since
|
||||||
|
we can se the output. It's great for debugging and quick testing. But if you need to send a text
|
||||||
|
to an actual player, `print` won't do, because it doesn't know _who_ to send to. Try this:
|
||||||
|
|
||||||
|
> py me.msg("Hello world!")
|
||||||
|
Hello world!
|
||||||
|
|
||||||
|
This looks the same as the `print` result, but we are now actually messaging a specific *object*,
|
||||||
|
`me`. The `me` is a shortcut to 'us', the one running the `py` command. It is not some special
|
||||||
|
Python thing, but something Evennia just makes available in the `py` command for convenience
|
||||||
|
(`self` is an alias).
|
||||||
|
|
||||||
|
The `me` is an example of an *Object instance*. Objects are fundamental in Python and Evennia.
|
||||||
|
The `me` object also contains a lot of useful resources for doing
|
||||||
|
things with that object. We access those resources with '`.`'.
|
||||||
|
|
||||||
|
One such resource is `msg`, which works like `print` except it sends the text to the object it
|
||||||
|
is attached to. So if we, for example, had an object `you`, doing `you.msg(...)` would send a message
|
||||||
|
to the object `you`.
|
||||||
|
|
||||||
|
For now, `print` and `me.msg` behaves the same, just remember that `print` is mainly used for
|
||||||
|
debugging and `.msg()` will be more useful for you in the future.
|
||||||
|
|
||||||
|
|
||||||
|
### Parsing Python errors
|
||||||
|
|
||||||
|
Let's try this new text-sending in the function we just created. Go back to
|
||||||
|
your `test.py` file and Replace the function with this instead:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def hello_world():
|
||||||
|
me.msg("Hello World!")
|
||||||
|
```
|
||||||
|
|
||||||
|
Save your file and `reload` your server to tell Evennia to re-import new code,
|
||||||
|
then run it like before:
|
||||||
|
|
||||||
|
> py import world.test ; world.test.hello_world()
|
||||||
|
|
||||||
No go - this time you get an error!
|
No go - this time you get an error!
|
||||||
|
|
||||||
```python
|
```python
|
||||||
File "./world/test.py", line 1, in <module>
|
File "./world/test.py", line 2, in hello_world
|
||||||
me.msg("Hello world!")
|
me.msg("Hello World!")
|
||||||
NameError: name 'me' is not defined
|
NameError: name 'me' is not defined
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -216,92 +396,258 @@ reserved word (as mentioned, it's just something Evennia came up with for conven
|
||||||
command). As far as the module is concerned `me` is an unfamiliar name, appearing out of nowhere.
|
command). As far as the module is concerned `me` is an unfamiliar name, appearing out of nowhere.
|
||||||
Hence the `NameError`.
|
Hence the `NameError`.
|
||||||
|
|
||||||
### Our first own function
|
### Passing arguments to functions
|
||||||
|
|
||||||
Let's see if we can resolve that `NameError` from the previous section. We know that `me` is defined
|
We know that `me` exists at the point when we run the `py` command, because we can do `py me.msg("Hello World!")`
|
||||||
at the time we use the `py` command. We know this because if we do `py me.msg("Hello World!")`
|
with no problem. So let's _pass_ that me along to the function so it knows what it should be.
|
||||||
directly in-game it works fine. What if we could *send* that `me` to the `test.py` module so it
|
Go back to your `test.py` and change it to this:
|
||||||
knows what it is? One way to do this is with a *function*.
|
|
||||||
|
|
||||||
Change your `mygame/world/test.py` file to look like this:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def hello_world(who):
|
def hello_world(who):
|
||||||
who.msg("Hello World!")
|
who.msg("Hello World!")
|
||||||
```
|
```
|
||||||
|
We now added an _argument_ to the function. We could have named it anything. Whatever `who` is,
|
||||||
|
we will call a method `.msg()` on it.
|
||||||
|
|
||||||
As we are moving to multi-line Python code, there are some important things to remember:
|
As usual, `reload` the server to make sure the new code is available.
|
||||||
|
|
||||||
- Capitalization matters in Python. It must be `def` and not `DEF`, `who` is not the same as `Who`.
|
|
||||||
- Indentation matters in Python. The second line must be indented or it's not valid code. You should
|
|
||||||
also use a consistent indentation length. We *strongly* recommend that you, for your own sanity's sake,
|
|
||||||
set up your editor to always indent *4 spaces* (**not** a single tab-character) when you press the TAB key.
|
|
||||||
|
|
||||||
So about that function. Line 1:
|
|
||||||
|
|
||||||
- `def` is short for "define" and defines a *function* (or a *method*, if sitting on an object).
|
|
||||||
This is a [reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html); try not to use
|
|
||||||
these words anywhere else.
|
|
||||||
- A function name can not have spaces but otherwise we could have called it almost anything. We call
|
|
||||||
it `hello_world`. Evennia follows [Python's standard naming style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style-points)
|
|
||||||
with lowercase letters and underscores. We recommend you do the same.
|
|
||||||
- `who` is what we call the *argument* to our function. Arguments are variables _passed_ to the
|
|
||||||
function. We could have named it anything and we could also have multiple arguments separated by
|
|
||||||
commas. What `who` is depends on what we pass to this function when we *call* it later (hint: we'll
|
|
||||||
pass `me` to it).
|
|
||||||
- The colon (`:`) at the end of line 1 indicates that the header of the function is complete.
|
|
||||||
|
|
||||||
Line 2:
|
|
||||||
|
|
||||||
- The indentation marks the beginning of the actual operating code of the function (the function's
|
|
||||||
*body*). If we wanted more lines to belong to this function those lines would all have to
|
|
||||||
start at least at this indentation level.
|
|
||||||
- In the function body we take the `who` argument and treat it as we would have treated `me`
|
|
||||||
earlier- we expect it to have a `.msg` method we can use to send "Hello World" to.
|
|
||||||
|
|
||||||
Now let's try this out. First `reload` your game to have it pick up
|
|
||||||
our updated Python module when we reload.
|
|
||||||
|
|
||||||
> reload
|
|
||||||
> py import world.test
|
|
||||||
|
|
||||||
Nothing happened! That is because the function in our module won't do anything just by importing it.
|
|
||||||
It will only act when we *call* it. So we need to first import the module and then access the
|
|
||||||
function within:
|
|
||||||
|
|
||||||
> py import world.test ; world.test.hello_world(me)
|
> py import world.test ; world.test.hello_world(me)
|
||||||
Hello world!
|
Hello World!
|
||||||
|
|
||||||
|
Now it worked. We _passed_ `me` to our function. It will appear inside the function renamed as `who` and
|
||||||
|
now the function works and prints as expected. Note how the `hello_world` function doesn't care _what_ you
|
||||||
|
pass into it as long as it has a `.msg()` method on it. So you could reuse this function over and over for other
|
||||||
|
suitable targets.
|
||||||
|
|
||||||
There is our "Hello World"! Using `;` is the way to put multiple Python-statements on one line.
|
### Finding others to send to
|
||||||
|
|
||||||
```warning:: MUD clients and semi-colon
|
Let's wrap up this first Python `py` crash-course by finding someone else to send to.
|
||||||
|
|
||||||
A common issue is that some MUD clients use the semi-colon `;` to split client-inputs
|
In Evennia's `contrib/` folder (`evennia/contrib/tutorial_examples/mirror.py`) is a handy little
|
||||||
into separate sends. If so, you'll get a `NameError` above, stating that
|
object called the `TutorialMirror`. The mirror will echo whatever is being sent to it to
|
||||||
`world` is not defined. Check so you understand why this is! Most clients allow you to
|
the room it is in.
|
||||||
remap to use some other separator than `;`. You can use the Evennia web client if this
|
|
||||||
problem remains.
|
On the game command-line, let's create a mirror:
|
||||||
|
|
||||||
|
> create/drop mirror:contrib.tutorial_examples.mirror.TutorialMirror
|
||||||
|
|
||||||
|
```sidebar:: Creating objects
|
||||||
|
|
||||||
|
The `create` command was first used to create boxes in the
|
||||||
|
`Building Stuff <Building-Quickstart>`_ tutorial. Note how it
|
||||||
|
uses a "python-path" to describe where to load the mirror's code from.
|
||||||
```
|
```
|
||||||
|
|
||||||
So what happened there? First we imported `world.test` as usual. But this time we continued and
|
A mirror should appear in your location.
|
||||||
accessed the `hello_world` function _inside_ the newly imported module.
|
|
||||||
|
|
||||||
We *call* the function with `me`, which becomes the `who` variable we use inside
|
> look mirror
|
||||||
the `hello_function` (they are be the same object). And since `me.msg` works, so does `who.msg`
|
The mirror shows your reflection:
|
||||||
inside the function.
|
This is User #1
|
||||||
|
|
||||||
> **Extra Credit:** As an exercise, try to pass something else into `hello_world`. Try for example
|
What you are seeing is actually your own avatar in the game, the same thing that is available as `me` in the `py`
|
||||||
>to pass the number `5` or the string `"foo"`. You'll get errors telling you that they don't have
|
command.
|
||||||
>the attribute `msg`. They don't care about `me` itself not being a string or a number. If you are
|
|
||||||
>familiar with other programming languages (especially C/Java) you may be tempted to start *validating*
|
What we are aiming for now is the equivalent of `mirror.msg("Mirror Mirror on the wall")`. But the first thing that
|
||||||
>`who` to make sure it's of the right type before you send it. This is usually not recommended in Python.
|
comes to mind will not work:
|
||||||
>Python philosophy is to [handle](https://docs.python.org/2/tutorial/errors.html) the error if it happens
|
|
||||||
>rather than to add a lot of code to prevent it from happening. See [duck typing](https://en.wikipedia.org/wiki/Duck_typing)
|
> py mirror.msg("Mirror, Mirror on the wall ...")
|
||||||
>and the concept of _Leap before you Look_.
|
NameError: name 'mirror' is not defined.
|
||||||
|
|
||||||
|
This is not surprising: Python knows nothing about "mirrors" or locations or anything. The `me` we've been using
|
||||||
|
is, as mentioned, just a convenient thing the Evennia devs makes available to the `py` command. They couldn't possibly
|
||||||
|
predict that you wanted to talk to mirrors.
|
||||||
|
|
||||||
|
Instead we will need to _search_ for that `mirror` object before we can send to it.
|
||||||
|
Make sure you are in the same location as the mirror and try:
|
||||||
|
|
||||||
|
> py me.search("mirror")
|
||||||
|
mirror
|
||||||
|
|
||||||
|
`me.search("name")` will, by default, search and _return_ an object with the given name found in _the same location_
|
||||||
|
as the `me` object is. If it can't find anything you'll see an error.
|
||||||
|
|
||||||
|
```sidebar:: Function returns
|
||||||
|
|
||||||
|
Whereas a function like `print` only prints its arguments, it's very common
|
||||||
|
for functions/methods to `return` a result of some kind. Think of the function
|
||||||
|
as a machine - you put something in and out comes a result you can use. In the case
|
||||||
|
of `me.search`, it will perform a database search and spit out the object it finds.
|
||||||
|
```
|
||||||
|
|
||||||
|
> py me.search("dummy")
|
||||||
|
Could not find 'dummy'.
|
||||||
|
|
||||||
|
Wanting to find things in the same location is very common, but as we continue we'll
|
||||||
|
find that Evennia provides ample tools for tagging, searching and finding things from all over your game.
|
||||||
|
|
||||||
|
Now that we know how to find the 'mirror' object, we just need to use that instead of `me`!
|
||||||
|
|
||||||
|
> py mirror = self.search("mirror") ; mirror.msg("Mirror, Mirror on the wall ...")
|
||||||
|
The mirror echoes back to you:
|
||||||
|
"Mirror, Mirror on the wall ..."
|
||||||
|
|
||||||
|
The mirror is useful for testing because its `.msg` method just echoes whatever is sent to it back to the room. More common
|
||||||
|
would be to talk to a player character, in which case the text you sent would have appeared in their game client.
|
||||||
|
|
||||||
|
|
||||||
This gives you some initial feeling for how to run Python and import Python modules. We also
|
### Multi-line py
|
||||||
tried to put a module in `module/world/`. Now let's look at the rest of the stuff you've got
|
|
||||||
inside that `mygame/` folder ...
|
So far we have use `py` in single-line mode, using `;` to separate multiple inputs. This is very convenient
|
||||||
|
when you want to do some quick testing. But you can also start a full multi-line Python interactive interpreter
|
||||||
|
inside Evennia.
|
||||||
|
|
||||||
|
> py
|
||||||
|
Evennia Interactive Python mode
|
||||||
|
Python 3.7.1 (default, Oct 22 2018, 11:21:55)
|
||||||
|
[GCC 8.2.0] on Linux
|
||||||
|
[py mode - quit() to exit]
|
||||||
|
|
||||||
|
(the details of the output will vary with your Python version and OS). You are now in python interpreter mode. It means
|
||||||
|
that _everything_ you insert from now on will become a line of Python (you can no longer look around or do other
|
||||||
|
commands).
|
||||||
|
|
||||||
|
> print("Hello World")
|
||||||
|
|
||||||
|
>>> print("Hello World")
|
||||||
|
Hello World
|
||||||
|
[py mode - quit() to exit]
|
||||||
|
|
||||||
|
Note that we didn't need to put `py` in front now. The system will also echo your input (that's the bit after
|
||||||
|
the `>>>`). For brevity in this tutorual we'll turn the echo off. First exit `py` and then start again with the
|
||||||
|
`/noecho` flag.
|
||||||
|
|
||||||
|
> quit()
|
||||||
|
Closing the Python console.
|
||||||
|
> py/noecho
|
||||||
|
Evennia Interactive Python mode
|
||||||
|
Python 3.7.1 (default, Oct 22 2018, 11:21:55)
|
||||||
|
[GCC 8.2.0] on Linux
|
||||||
|
[py mode - quit() to exit]
|
||||||
|
|
||||||
|
```sidebar:: interactive py
|
||||||
|
|
||||||
|
- Start with `py`.
|
||||||
|
- Use `py/noecho` if you don't want your input to be echoed for every line.
|
||||||
|
- All your inputs will now be interpreted as Python code.
|
||||||
|
- Exit with `quit()`.
|
||||||
|
```
|
||||||
|
|
||||||
|
We can now enter multi-line Python code:
|
||||||
|
|
||||||
|
> a = "Test"
|
||||||
|
> print(f"This is a {a}."}
|
||||||
|
This is a Test.
|
||||||
|
|
||||||
|
Let's try to define a function:
|
||||||
|
|
||||||
|
> def hello_world(who, txt):
|
||||||
|
...
|
||||||
|
> who.msg(txt)
|
||||||
|
...
|
||||||
|
>
|
||||||
|
[py mode - quit() to exit]
|
||||||
|
|
||||||
|
Some important things above:
|
||||||
|
|
||||||
|
- Definining a function with `def` means we are starting a new code block. Python works so that you mark the content
|
||||||
|
of the block with indention. So the next line must be manually indented (4 spaces is a good standard) in order
|
||||||
|
for Python to know it's part of the function body.
|
||||||
|
- We expand the `hello_world` function with another argument `txt`. This allows us to send any text, not just
|
||||||
|
"Hello World" over and over.
|
||||||
|
- To tell `py` that no more lines will be added to the function body, we end with an empty input. When
|
||||||
|
the normal prompt on how to exit returns, we know we are done.
|
||||||
|
|
||||||
|
Now we have defined a new function. Let's try it out:
|
||||||
|
|
||||||
|
> hello_world(me, "Hello world to me!")
|
||||||
|
Hello world to me!
|
||||||
|
|
||||||
|
The `me` is still available to us, so we pass that as the `who` argument, along with a little longer
|
||||||
|
string. Let's combine this with searching for the mirror.
|
||||||
|
|
||||||
|
> mirror = me.search("mirror")
|
||||||
|
> hello_world(mirror, "Mirror, Mirror on the wall ...")
|
||||||
|
The mirror echoes back to you:
|
||||||
|
"Mirror, Mirror on the wall ..."
|
||||||
|
|
||||||
|
Exit the `py` mode with
|
||||||
|
|
||||||
|
> quit()
|
||||||
|
Closing the Python console.
|
||||||
|
|
||||||
|
## Other ways to test Python code
|
||||||
|
|
||||||
|
The `py` command is very powerful for experimenting with Python in-game. It's great for quick testing.
|
||||||
|
But you are still limited to working over telnet or the webclient, interfaces that doesn't know anything
|
||||||
|
about Python per-se.
|
||||||
|
|
||||||
|
Outside the game, go to the terminal where you ran Evennia (or any terminal where the `evennia` command
|
||||||
|
is available).
|
||||||
|
|
||||||
|
- `cd` to your game dir.
|
||||||
|
- `evennia shell`
|
||||||
|
|
||||||
|
A Python shell opens. This works like `py` did inside the game, with the exception that you don't have
|
||||||
|
`me` available out of the box. If you want `me`, you need to first find yourself:
|
||||||
|
|
||||||
|
> import evennia
|
||||||
|
> me = evennia.search_object("YourChar")[0]
|
||||||
|
|
||||||
|
Here we make use of one of evennia's search functions, available by importing `evennia` directly.
|
||||||
|
We will cover more advanced searching later, but suffice to say, you put your own character name instead of
|
||||||
|
"YourChar" above.
|
||||||
|
|
||||||
|
> The `[0]` at the end is because `.search_object` returns a list of objects and we want to
|
||||||
|
get at the first of them (counting starts from 0).
|
||||||
|
|
||||||
|
Use `Ctrl-D` (`Cmd-D` on Mac) or `quit()` to exit the Python console.
|
||||||
|
|
||||||
|
### ipython
|
||||||
|
|
||||||
|
The default Python shell is quite limited and ugly. It's *highly* recommended to install `ipython` instead. This
|
||||||
|
is a much nicer, third-party Python interpreter with colors and many usability improvements.
|
||||||
|
|
||||||
|
pip install ipython
|
||||||
|
|
||||||
|
If `ipython` is installed, `evennia shell` will use it automatically.
|
||||||
|
|
||||||
|
evennia shell
|
||||||
|
...
|
||||||
|
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help
|
||||||
|
In [1]:
|
||||||
|
|
||||||
|
You now have Tab-completion:
|
||||||
|
|
||||||
|
> import evennia
|
||||||
|
> evennia.<TAB>
|
||||||
|
|
||||||
|
That is, enter `evennia.` and then press the TAB key - you will be given a list of all the resources
|
||||||
|
available on the `evennia` object. This is great for exploring what Evennia has to offer. For example,
|
||||||
|
use your arrow keys to scroll to `search_object()` to fill it in.
|
||||||
|
|
||||||
|
> evennia.search_object?
|
||||||
|
|
||||||
|
Adding a `?` and pressing return will give you the full documentation for `.search_object`. Use `??` if you
|
||||||
|
want to see the entire source code.
|
||||||
|
|
||||||
|
As for the normal python interpreter, use `Ctrl-D`/`Cmd-D` or `quit()` to exit ipython.
|
||||||
|
|
||||||
|
```important:: Persistent code
|
||||||
|
|
||||||
|
Common for both `py` and `python`/`ipython` is that the code you write is not persistent - it will
|
||||||
|
be gone after you shut down the interpreter (but ipython will remember your input history). For making long-lasting
|
||||||
|
Python code, we need to save it in a Python module, like we did for `world/test.py`.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Conclusions
|
||||||
|
|
||||||
|
This covers quite a lot of basic Python usage. We printed and formatted strings, defined our own
|
||||||
|
first function, fixed an error and even searched and talked to a mirror! Being able to access
|
||||||
|
python inside and outside of the game is an important skill for testing and debugging, but in
|
||||||
|
practice you will be writing most your code in Python modules.
|
||||||
|
|
||||||
|
To that end we also created a first new Python module in the `mygame/` game dir, then imported and used it.
|
||||||
|
Now let's look at the rest of the stuff you've got going on inside that `mygame/` folder ...
|
||||||
|
|
||||||
[prev lesson](Tutorial-World-Introduction) | [next lesson](Gamedir-Overview)
|
[prev lesson](Tutorial-World-Introduction) | [next lesson](Gamedir-Overview)
|
||||||
|
|
|
||||||
|
|
@ -44,28 +44,28 @@ as ù character. Also seems to run the `version` command on connection, which wi
|
||||||
`MULTISESSION_MODES` above 1.
|
`MULTISESSION_MODES` above 1.
|
||||||
[KildClient][22] | 2.11.1 | No known issues.
|
[KildClient][22] | 2.11.1 | No known issues.
|
||||||
|
|
||||||
[1]: https://github.com/evennia/evennia/wiki/Web%20features#web-client
|
[1](https://github.com/evennia/evennia/wiki/Web%20features#web-client)
|
||||||
[2]: https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=client+status%3Dopen+]
|
[2](https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=client+status%3Dopen+])
|
||||||
[3]: http://tintin.sourceforge.net/
|
[3](http://tintin.sourceforge.net/)
|
||||||
[4]: http://tinyfugue.sourceforge.net/
|
[4](http://tinyfugue.sourceforge.net/)
|
||||||
[5]: http://mushclient.com/
|
[5](http://mushclient.com/)
|
||||||
[6]: http://forums.zuggsoft.com/index.php?page=4&action=file&file_id=65
|
[6](http://forums.zuggsoft.com/index.php?page=4&action=file&file_id=65)
|
||||||
[7]: http://forums.zuggsoft.com/index.php?page=4&action=category&cat_id=11
|
[7](http://forums.zuggsoft.com/index.php?page=4&action=category&cat_id=11)
|
||||||
[8]: http://www.potatomushclient.com/
|
[8](http://www.potatomushclient.com/)
|
||||||
[9]: http://www.mudlet.org/
|
[9](http://www.mudlet.org/)
|
||||||
[10]: https://archive.org/details/tucows_196173_SimpleMU_MU_Client
|
[10](https://archive.org/details/tucows_196173_SimpleMU_MU_Client)
|
||||||
[11]: http://www.riverdark.net/atlantis/
|
[11](http://www.riverdark.net/atlantis/)
|
||||||
[12]: https://sourceforge.net/projects/g-mud/
|
[12](https://sourceforge.net/projects/g-mud/)
|
||||||
[13]: http://www.beipmu.com/
|
[13](http://www.beipmu.com/)
|
||||||
[14]: https://itunes.apple.com/us/app/mudrammer-a-modern-mud-client/id597157072
|
[14](https://itunes.apple.com/us/app/mudrammer-a-modern-mud-client/id597157072)
|
||||||
[15]: https://itunes.apple.com/us/app/mudmaster/id341160033
|
[15](https://itunes.apple.com/us/app/mudmaster/id341160033)
|
||||||
[16]: http://bt.happygoatstudios.com/
|
[16](http://bt.happygoatstudios.com/)
|
||||||
[17]: https://play.google.com/store/apps/details?id=com.crap.mukluk
|
[17](https://play.google.com/store/apps/details?id=com.crap.mukluk)
|
||||||
[18]: https://github.com/GNOME/gnome-mud
|
[18](https://github.com/GNOME/gnome-mud)
|
||||||
[19]: https://spyrit.ierne.eu.org/
|
[19](https://spyrit.ierne.eu.org/)
|
||||||
[20]: http://jamochamud.org/
|
[20](http://jamochamud.org/)
|
||||||
[21]: http://duckclient.com/
|
[21](http://duckclient.com/)
|
||||||
[22]: https://www.kildclient.org/
|
[22](https://www.kildclient.org/)
|
||||||
|
|
||||||
## Workarounds for client issues:
|
## Workarounds for client issues:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -406,16 +406,16 @@ servers with this option as they don't have a lot of support.
|
||||||
*Please help us expand this list.*
|
*Please help us expand this list.*
|
||||||
|
|
||||||
[1]: http:silvren.com
|
[1]: http:silvren.com
|
||||||
[2]: https://www.digitalocean.com/pricing
|
[2](https://www.digitalocean.com/pricing)
|
||||||
[3]: https://aws.amazon.com/pricing/
|
[3](https://aws.amazon.com/pricing/)
|
||||||
[4]: http://www.genesismuds.com/
|
[4](http://www.genesismuds.com/)
|
||||||
[5]: https://www.host1plus.com/
|
[5](https://www.host1plus.com/)
|
||||||
[6]: https://www.scaleway.com/
|
[6](https://www.scaleway.com/)
|
||||||
[7]: https://lowendbox.com/
|
[7](https://lowendbox.com/)
|
||||||
[8]: https://www.lowendtalk.com
|
[8](https://www.lowendtalk.com)
|
||||||
[9]: https://amazonlightsail.com
|
[9](https://amazonlightsail.com)
|
||||||
[10]: https://prgmr.com/
|
[10](https://prgmr.com/)
|
||||||
[11]: https://www.linode.com/
|
[11](https://www.linode.com/)
|
||||||
|
|
||||||
## Cloud9
|
## Cloud9
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,19 +116,23 @@ _github_issue_choose = "https://github.com/evennia/evennia/issues/new/choose"
|
||||||
|
|
||||||
|
|
||||||
def url_resolver(url):
|
def url_resolver(url):
|
||||||
|
"""
|
||||||
|
Convert urls by catching special markers.
|
||||||
|
"""
|
||||||
githubstart = "github:"
|
githubstart = "github:"
|
||||||
apistart = "api:"
|
apistart = "api:"
|
||||||
choose_issue = ("feature-request", "report-bug", "issue", "bug-report")
|
choose_issue = "github:issue"
|
||||||
|
|
||||||
if url.lower().strip() in choose_issue:
|
if url.endswith(choose_issue):
|
||||||
return _github_issue_choose
|
return _github_issue_choose
|
||||||
elif url.startswith(githubstart):
|
elif githubstart in url:
|
||||||
urlpath = url[len(githubstart):]
|
urlpath = url[url.index(githubstart) + len(githubstart):]
|
||||||
if not (urlpath.startswith("develop/") or urlpath.startswith("master")):
|
if not (urlpath.startswith("develop/") or urlpath.startswith("master")):
|
||||||
urlpath = "master/" + urlpath
|
urlpath = "master/" + urlpath
|
||||||
return _github_code_root + urlpath
|
return _github_code_root + urlpath
|
||||||
elif url.startswith(apistart):
|
elif apistart in url:
|
||||||
return "api/" + url[len(apistart):] + ".html"
|
urlpath = url[url.index(apistart) + len(apistart):]
|
||||||
|
return "api/" + urlpath + ".html"
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -392,7 +392,9 @@ class CmdPy(COMMAND_DEFAULT_CLASS):
|
||||||
if noecho:
|
if noecho:
|
||||||
prompt = "..." if console.push(line) else main_prompt
|
prompt = "..." if console.push(line) else main_prompt
|
||||||
else:
|
else:
|
||||||
prompt = line if console.push(line) else f"{line}\n{main_prompt}"
|
if line:
|
||||||
|
self.caller.msg(f">>> {line}")
|
||||||
|
prompt = line if console.push(line) else main_prompt
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
break
|
break
|
||||||
self.msg("|gClosing the Python console.|n")
|
self.msg("|gClosing the Python console.|n")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue