2022-02-06 19:27:15 +01:00
|
|
|
# Adding custom commands
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
In this lesson we'll learn how to create our own Evennia _Commands_. If you are new to Python you'll
|
|
|
|
|
also learn some more basics about how to manipulate strings and get information out of Evennia.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
A Command is something that handles the input from a user and causes a result to happen.
|
|
|
|
|
An example is `look`, which examines your current location and tells how it looks like and
|
2021-08-06 17:16:44 +02:00
|
|
|
what is in it.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
```{sidebar} Commands are not typeclassed
|
2020-07-06 00:05:15 +02:00
|
|
|
|
2022-02-06 23:31:59 +01:00
|
|
|
If you just came from the previous lesson, you might want to know that Commands and
|
|
|
|
|
CommandSets are not `typeclassed`. That is, instances of them are not saved to the
|
|
|
|
|
database. They are "just" normal Python classes.
|
2020-07-06 00:05:15 +02:00
|
|
|
```
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
In Evennia, a Command is a Python _class_. If you are unsure about what a class is, review the
|
2020-07-06 00:05:15 +02:00
|
|
|
previous lessons! A Command inherits from `evennia.Command` or from one of the alternative command-
|
2021-08-06 17:16:44 +02:00
|
|
|
classes, such as `MuxCommand` which is what most default commands use.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2020-07-03 22:32:50 +02:00
|
|
|
All Commands are in turn grouped in another class called a _Command Set_. Think of a Command Set
|
2021-08-06 17:16:44 +02:00
|
|
|
as a bag holding many different commands. One CmdSet could for example hold all commands for
|
|
|
|
|
combat, another for building etc. By default, Evennia groups all character-commands into one
|
|
|
|
|
big cmdset.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Command-Sets are then associated with objects, for example with your Character. Doing so makes the
|
|
|
|
|
commands in that cmdset available to the object. So, to summarize:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
- Commands are classes
|
|
|
|
|
- A group of Commands is stored in a CmdSet
|
2020-07-03 22:32:50 +02:00
|
|
|
- CmdSets are stored on objects - this defines which commands are available to that object.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
## Creating a custom command
|
|
|
|
|
|
|
|
|
|
Open `mygame/commands/command.py`:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
"""
|
|
|
|
|
(module docstring)
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from evennia import Command as BaseCommand
|
|
|
|
|
# from evennia import default_cmds
|
|
|
|
|
|
|
|
|
|
class Command(BaseCommand):
|
|
|
|
|
"""
|
|
|
|
|
(class docstring)
|
2021-08-06 17:16:44 +02:00
|
|
|
"""
|
2020-07-03 01:00:13 +02:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# (lots of commented-out stuff)
|
|
|
|
|
# ...
|
|
|
|
|
```
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
Ignoring the docstrings (which you can read if you want), this is the only really active code in the module.
|
|
|
|
|
|
|
|
|
|
We can see that we import `Command` from `evennia` and use the `from ... import ... as ...` form to rename it
|
|
|
|
|
to `BaseCommand`. This is so we can let our child class also be named `Command` for reference. The class
|
2021-08-06 17:16:44 +02:00
|
|
|
itself doesn't do anything, it just has `pass`. So in the same way as `Object` in the previous lesson, this
|
|
|
|
|
class is identical to its parent.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
> The commented out `default_cmds` gives us access to Evennia's default commands for easy overriding. We'll try
|
2021-08-06 17:16:44 +02:00
|
|
|
> that a little later.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
We could modify this module directly, but to train imports we'll work in a separate module. Open a new file
|
2021-08-06 17:16:44 +02:00
|
|
|
`mygame/commands/mycommands.py` and add the following code:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
|
|
from commands.command import Command
|
|
|
|
|
|
|
|
|
|
class CmdEcho(Command):
|
|
|
|
|
key = "echo"
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
This is the simplest form of command you can imagine. It just gives itself a name, "echo". This is
|
|
|
|
|
what you will use to call this command later.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
Next we need to put this in a CmdSet. It will be a one-command CmdSet for now! Change your file as such:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
|
|
|
|
from commands.command import Command
|
|
|
|
|
from evennia import CmdSet
|
|
|
|
|
|
|
|
|
|
class CmdEcho(Command):
|
|
|
|
|
key = "echo"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MyCmdSet(CmdSet):
|
|
|
|
|
|
|
|
|
|
def at_cmdset_creation(self):
|
|
|
|
|
self.add(CmdEcho)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Our `EchoCmdSet` class must have an `at_cmdset_creation` method, named exactly
|
|
|
|
|
like this - this is what Evennia will be looking for when setting up the cmdset later, so
|
|
|
|
|
if you didn't set it up, it will use the parent's version, which is empty. Inside we add the
|
|
|
|
|
command class to the cmdset by `self.add()`. If you wanted to add more commands to this CmdSet you
|
|
|
|
|
could just add more lines of `self.add` after this.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
Finally, let's add this command to ourselves so we can try it out. In-game you can experiment with `py` again:
|
|
|
|
|
|
|
|
|
|
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Now try
|
|
|
|
|
|
|
|
|
|
> echo
|
2020-07-03 01:00:13 +02:00
|
|
|
Command echo has no defined `func()` - showing on-command variables:
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
You should be getting a long list of outputs. The reason for this is that your `echo` function is not really
|
2020-07-03 01:00:13 +02:00
|
|
|
"doing" anything yet and the default function is then to show all useful resources available to you when you
|
|
|
|
|
use your Command. Let's look at some of those listed:
|
|
|
|
|
|
|
|
|
|
Command echo has no defined `func()` - showing on-command variables:
|
|
|
|
|
obj (<class 'typeclasses.characters.Character'>): YourName
|
|
|
|
|
lockhandler (<class 'evennia.locks.lockhandler.LockHandler'>): cmd:all()
|
|
|
|
|
caller (<class 'typeclasses.characters.Character'>): YourName
|
|
|
|
|
cmdname (<class 'str'>): echo
|
|
|
|
|
raw_cmdname (<class 'str'>): echo
|
|
|
|
|
cmdstring (<class 'str'>): echo
|
2021-08-06 17:16:44 +02:00
|
|
|
args (<class 'str'>):
|
2020-07-03 01:00:13 +02:00
|
|
|
cmdset (<class 'evennia.commands.cmdset.CmdSet'>): @mail, about, access, accounts, addcom, alias, allcom, ban, batchcode, batchcommands, boot, cboot, ccreate,
|
|
|
|
|
cdesc, cdestroy, cemit, channels, charcreate, chardelete, checklockstring, clientwidth, clock, cmdbare, cmdsets, color, copy, cpattr, create, cwho, delcom,
|
|
|
|
|
desc, destroy, dig, dolphin, drop, echo, emit, examine, find, force, get, give, grapevine2chan, help, home, ic, inventory, irc2chan, ircstatus, link, lock,
|
|
|
|
|
look, menutest, mudinfo, mvattr, name, nick, objects, ooc, open, option, page, password, perm, pose, public, py, quell, quit, reload, reset, rss2chan, say,
|
|
|
|
|
script, scripts, server, service, sessions, set, setdesc, sethelp, sethome, shutdown, spawn, style, tag, tel, test2010, test2028, testrename, testtable,
|
|
|
|
|
tickers, time, tunnel, typeclass, unban, unlink, up, up, userpassword, wall, whisper, who, wipe
|
|
|
|
|
session (<class 'evennia.server.serversession.ServerSession'>): Griatch(#1)@1:2:7:.:0:.:0:.:1
|
|
|
|
|
account (<class 'typeclasses.accounts.Account'>): Griatch(account 1)
|
2021-08-06 17:16:44 +02:00
|
|
|
raw_string (<class 'str'>): echo
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
--------------------------------------------------
|
|
|
|
|
echo - Command variables from evennia:
|
|
|
|
|
--------------------------------------------------
|
|
|
|
|
name of cmd (self.key): echo
|
|
|
|
|
cmd aliases (self.aliases): []
|
|
|
|
|
cmd locks (self.locks): cmd:all();
|
|
|
|
|
help category (self.help_category): General
|
|
|
|
|
object calling (self.caller): Griatch
|
|
|
|
|
object storing cmdset (self.obj): Griatch
|
|
|
|
|
command string given (self.cmdstring): echo
|
|
|
|
|
current cmdset (self.cmdset): ChannelCmdSet
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
These are all properties you can access with `.` on the Command instance, such as `.key`, `.args` and so on.
|
|
|
|
|
Evennia makes these available to you and they will be different every time a command is run. The most
|
|
|
|
|
important ones we will make use of now are:
|
|
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
- `caller` - this is 'you', the person calling the command.
|
2021-08-06 17:16:44 +02:00
|
|
|
- `args` - this is all arguments to the command. Now it's empty, but if you tried `echo foo bar` you'd find
|
2020-07-03 01:00:13 +02:00
|
|
|
that this would be `" foo bar"`.
|
|
|
|
|
- `obj` - this is object on which this Command (and CmdSet) "sits". So you, in this case.
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
The reason our command doesn't do anything yet is because it's missing a `func` method. This is what Evennia
|
2020-07-03 01:00:13 +02:00
|
|
|
looks for to figure out what a Command actually does. Modify your `CmdEcho` class:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
class CmdEcho(Command):
|
|
|
|
|
"""
|
|
|
|
|
A simple echo command
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
Usage:
|
2021-08-06 17:16:44 +02:00
|
|
|
echo <something>
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
key = "echo"
|
|
|
|
|
|
|
|
|
|
def func(self):
|
2021-08-06 17:16:44 +02:00
|
|
|
self.caller.msg(f"Echo: '{self.args}'")
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
# ...
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
First we added a docstring. This is always a good thing to do in general, but for a Command class, it will also
|
|
|
|
|
automatically become the in-game help entry! Next we add the `func` method. It has one active line where it
|
|
|
|
|
makes use of some of those variables we found the Command offers to us. If you did the
|
2022-08-30 23:03:39 +02:00
|
|
|
[basic Python tutorial](./Beginner-Tutorial-Python-basic-introduction.md), you will recognize `.msg` - this will send a message
|
2020-07-03 01:00:13 +02:00
|
|
|
to the object it is attached to us - in this case `self.caller`, that is, us. We grab `self.args` and includes
|
2021-08-06 17:16:44 +02:00
|
|
|
that in the message.
|
|
|
|
|
|
|
|
|
|
Since we haven't changed `MyCmdSet`, that will work as before. Reload and re-add this command to ourselves to
|
|
|
|
|
try out the new version:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
> reload
|
2020-07-03 01:00:13 +02:00
|
|
|
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
2021-08-06 17:16:44 +02:00
|
|
|
> echo
|
2020-07-03 01:00:13 +02:00
|
|
|
Echo: ''
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Try to pass an argument:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
> echo Woo Tang!
|
|
|
|
|
Echo: ' Woo Tang!'
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
Note that there is an extra space before `Woo!`. That is because self.args contains the _everything_ after
|
2021-08-06 17:16:44 +02:00
|
|
|
the command name, including spaces. Evennia will happily understand if you skip that space too:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
> echoWoo Tang!
|
|
|
|
|
Echo: 'Woo Tang!'
|
2021-08-06 17:16:44 +02:00
|
|
|
|
|
|
|
|
There are ways to force Evennia to _require_ an initial space, but right now we want to just ignore it since
|
|
|
|
|
it looks a bit weird for our echo example. Tweak the code:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
class CmdEcho(Command):
|
|
|
|
|
"""
|
|
|
|
|
A simple echo command
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
Usage:
|
2021-08-06 17:16:44 +02:00
|
|
|
echo <something>
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
key = "echo"
|
|
|
|
|
|
|
|
|
|
def func(self):
|
2021-08-06 17:16:44 +02:00
|
|
|
self.caller.msg(f"Echo: '{self.args.strip()}'")
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
# ...
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The only difference is that we called `.strip()` on `self.args`. This is a helper method available on all
|
|
|
|
|
strings - it strips out all whitespace before and after the string. Now the Command-argument will no longer
|
|
|
|
|
have any space in front of it.
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
> reload
|
2020-07-03 01:00:13 +02:00
|
|
|
> py self.cmdset.add("commands.mycommands.MyCmdSet")
|
|
|
|
|
> echo Woo Tang!
|
|
|
|
|
Echo: 'Woo Tang!'
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Don't forget to look at the help for the echo command:
|
|
|
|
|
|
|
|
|
|
> help echo
|
|
|
|
|
|
|
|
|
|
You will get the docstring you put in your Command-class.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
### Making our cmdset persistent
|
|
|
|
|
|
|
|
|
|
It's getting a little annoying to have to re-add our cmdset every time we reload, right? It's simple
|
2021-08-06 17:16:44 +02:00
|
|
|
enough to make `echo` a _persistent_ change though:
|
|
|
|
|
|
|
|
|
|
> py self.cmdset.add("commands.mycommands.MyCmdSet", persistent=True)
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Now you can `reload` as much as you want and your code changes will be available directly without
|
2020-07-03 01:00:13 +02:00
|
|
|
needing to re-add the MyCmdSet again. To remove the cmdset again, do
|
|
|
|
|
|
|
|
|
|
> py self.cmdset.remove("commands.mycommands.MyCmdSet")
|
|
|
|
|
|
|
|
|
|
But for now, keep it around, we'll expand it with some more examples.
|
|
|
|
|
|
|
|
|
|
### Figuring out who to hit
|
|
|
|
|
|
|
|
|
|
Let's try something a little more exciting than just echo. Let's make a `hit` command, for punching
|
2021-08-06 17:16:44 +02:00
|
|
|
someone in the face! This is how we want it to work:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
> hit <target>
|
2021-08-06 17:16:44 +02:00
|
|
|
You hit <target> with full force!
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
Not only that, we want the <target> to see
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
You got hit by <hitter> with full force!
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Here, `<hitter>` would be the one using the `hit` command and `<target>` is the one doing the punching.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Still in `mygame/commands/mycommands.py`, add a new class, between `CmdEcho` and `MyCmdSet`.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2022-02-06 23:31:59 +01:00
|
|
|
```{code-block} python
|
|
|
|
|
:linenos:
|
|
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
class CmdHit(Command):
|
|
|
|
|
"""
|
|
|
|
|
Hit a target.
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
Usage:
|
|
|
|
|
hit <target>
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
key = "hit"
|
|
|
|
|
|
|
|
|
|
def func(self):
|
|
|
|
|
args = self.args.strip()
|
|
|
|
|
if not args:
|
|
|
|
|
self.caller.msg("Who do you want to hit?")
|
2021-08-06 17:16:44 +02:00
|
|
|
return
|
2020-07-03 01:00:13 +02:00
|
|
|
target = self.caller.search(args)
|
|
|
|
|
if not target:
|
2021-08-06 17:16:44 +02:00
|
|
|
return
|
|
|
|
|
self.caller.msg(f"You hit {target.key} with full force!")
|
2020-07-03 01:00:13 +02:00
|
|
|
target.msg(f"You got hit by {self.caller.key} with full force!")
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
A lot of things to dissect here:
|
2022-02-06 23:31:59 +01:00
|
|
|
- **Line 3**: The normal `class` header. We inherit from `Command` which we imported at the top of this file.
|
|
|
|
|
- **Lines 4-10**: The docstring and help-entry for the command. You could expand on this as much as you wanted.
|
|
|
|
|
- **Line 11**: We want to write `hit` to use this command.
|
|
|
|
|
- **Line 14**: We strip the whitespace from the argument like before. Since we don't want to have to do
|
2020-07-03 01:00:13 +02:00
|
|
|
`self.args.strip()` over and over, we store the stripped version
|
|
|
|
|
in a _local variable_ `args`. Note that we don't modify `self.args` by doing this, `self.args` will still
|
|
|
|
|
have the whitespace and is not the same as `args` in this example.
|
2021-10-21 21:04:14 +02:00
|
|
|
```{sidebar} if-statements
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2022-02-06 23:31:59 +01:00
|
|
|
The full form of the if statement is
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2022-02-06 23:31:59 +01:00
|
|
|
if condition:
|
|
|
|
|
...
|
|
|
|
|
elif othercondition:
|
|
|
|
|
...
|
|
|
|
|
else:
|
|
|
|
|
...
|
2021-08-06 17:16:44 +02:00
|
|
|
|
2022-02-06 23:31:59 +01:00
|
|
|
There can be any number of `elifs` to mark when different branches of the code should run. If
|
|
|
|
|
the `else` condition is given, it will run if none of the other conditions was truthy. In Python
|
|
|
|
|
the `if..elif..else` structure also serves the same function as `case` in some other languages.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
```
|
2022-02-06 23:31:59 +01:00
|
|
|
- **Line 15** has our first _conditional_, an `if` statement. This is written on the form `if <condition>:` and only
|
2020-07-03 01:00:13 +02:00
|
|
|
if that condition is 'truthy' will the indented code block under the `if` statement run. To learn what is truthy in
|
2021-08-06 17:16:44 +02:00
|
|
|
Python it's usually easier to learn what is "falsy":
|
2020-07-03 01:00:13 +02:00
|
|
|
- `False` - this is a reserved boolean word in Python. The opposite is `True`.
|
|
|
|
|
- `None` - another reserved word. This represents nothing, a null-result or value.
|
2021-08-06 17:16:44 +02:00
|
|
|
- `0` or `0.0`
|
2020-07-03 01:00:13 +02:00
|
|
|
- The empty string `""` or `''` or `""""""` or `''''''`
|
|
|
|
|
- Empty _iterables_ we haven't seen yet, like empty lists `[]`, empty tuples `()` and empty dicts `{}`.
|
2021-08-06 17:16:44 +02:00
|
|
|
- Everything else is "truthy".
|
|
|
|
|
|
2020-07-03 01:00:13 +02:00
|
|
|
Line 16's condition is `not args`. The `not` _inverses_ the result, so if `args` is the empty string (falsy), the
|
2021-08-06 17:16:44 +02:00
|
|
|
whole conditional becomes truthy. Let's continue in the code:
|
2022-02-06 23:31:59 +01:00
|
|
|
- **Lines 16-17**: This code will only run if the `if` statement is truthy, in this case if `args` is the empty string.
|
|
|
|
|
- **Line 17**: `return` is a reserved Python word that exits `func` immediately.
|
|
|
|
|
- **Line 18**: We use `self.caller.search` to look for the target in the current location.
|
|
|
|
|
- **Lines 19-20**: A feature of `.search` is that it will already inform `self.caller` if it couldn't find the target.
|
2021-08-06 17:16:44 +02:00
|
|
|
In that case, `target` will be `None` and we should just directly `return`.
|
2022-02-06 23:31:59 +01:00
|
|
|
- **Lines 21-22**: At this point we have a suitable target and can send our punching strings to each.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Finally we must also add this to a CmdSet. Let's add it to `MyCmdSet` which we made persistent earlier.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
# ...
|
|
|
|
|
|
|
|
|
|
class MyCmdSet(CmdSet):
|
|
|
|
|
|
|
|
|
|
def at_cmdset_creation(self):
|
|
|
|
|
self.add(CmdEcho)
|
|
|
|
|
self.add(CmdHit)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
```{sidebar} Errors in your code
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2022-02-06 23:31:59 +01:00
|
|
|
With longer code snippets to try, it gets more and more likely you'll
|
|
|
|
|
make an error and get a `traceback` when you reload. This will either appear
|
|
|
|
|
directly in-game or in your log (view it with `evennia -l` in a terminal).
|
|
|
|
|
Don't panic; tracebacks are your friends - they are to be read bottom-up and usually describe
|
|
|
|
|
exactly where your problem is. Refer to `The Python intro <Python-basic-introduction.html>`_ for
|
|
|
|
|
more hints. If you get stuck, reach out to the Evennia community for help.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
Next we reload to let Evennia know of these code changes and try it out:
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
> reload
|
2020-07-03 01:00:13 +02:00
|
|
|
hit
|
|
|
|
|
Who do you want to hit?
|
|
|
|
|
hit me
|
|
|
|
|
You hit YourName with full force!
|
|
|
|
|
You got hit by YourName with full force!
|
|
|
|
|
|
|
|
|
|
Lacking a target, we hit ourselves. If you have one of the dragons still around from the previous lesson
|
|
|
|
|
you could try to hit it (if you dare):
|
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
hit smaug
|
2020-07-03 01:00:13 +02:00
|
|
|
You hit Smaug with full force!
|
|
|
|
|
|
|
|
|
|
You won't see the second string. Only Smaug sees that (and is not amused).
|
|
|
|
|
|
|
|
|
|
|
2020-07-03 22:32:50 +02:00
|
|
|
## Summary
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
In this lesson we learned how to create our own Command, add it to a CmdSet and then to ourselves.
|
|
|
|
|
We also upset a dragon.
|
2020-07-03 01:00:13 +02:00
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
In the next lesson we'll learn how to hit Smaug with different weapons. We'll also
|
|
|
|
|
get into how we replace and extend Evennia's default Commands.
|