2020-04-07 23:13:24 +02:00
|
|
|
|
# Building a mech tutorial
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
> This page was adapted from the article "Building a Giant Mech in Evennia" by Griatch, published in
|
|
|
|
|
|
Imaginary Realities Volume 6, issue 1, 2014. The original article is no longer available online,
|
|
|
|
|
|
this is a version adopted to be compatible with the latest Evennia.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
## Creating the Mech
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
Let us create a functioning giant mech using the Python MUD-creation system Evennia. Everyone likes
|
|
|
|
|
|
a giant mech, right? Start in-game as a character with build privileges (or the superuser).
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@create/drop Giant Mech ; mech
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
Boom. We created a Giant Mech Object and dropped it in the room. We also gave it an alias *mech*.
|
|
|
|
|
|
Let’s describe it.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@desc mech = This is a huge mech. It has missiles and stuff.
|
|
|
|
|
|
|
|
|
|
|
|
Next we define who can “puppet” the mech object.
|
|
|
|
|
|
|
|
|
|
|
|
@lock mech = puppet:all()
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
This makes it so that everyone can control the mech. More mechs to the people! (Note that whereas
|
|
|
|
|
|
Evennia’s default commands may look vaguely MUX-like, you can change the syntax to look like
|
|
|
|
|
|
whatever interface style you prefer.)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
Before we continue, let’s make a brief detour. Evennia is very flexible about its objects and even
|
|
|
|
|
|
more flexible about using and adding commands to those objects. Here are some ground rules well
|
|
|
|
|
|
worth remembering for the remainder of this article:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
|
- The [Account](../Components/Accounts.md) represents the real person logging in and has no game-world existence.
|
|
|
|
|
|
- Any [Object](../Components/Objects.md) can be puppeted by an Account (with proper permissions).
|
|
|
|
|
|
- [Characters](../Components/Objects.md#characters), [Rooms](../Components/Objects.md#rooms), and [Exits](../Components/Objects.md#exits) are just
|
2020-06-16 16:53:35 +02:00
|
|
|
|
children of normal Objects.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
- Any Object can be inside another (except if it creates a loop).
|
|
|
|
|
|
- Any Object can store custom sets of commands on it. Those commands can:
|
|
|
|
|
|
- be made available to the puppeteer (Account),
|
|
|
|
|
|
- be made available to anyone in the same location as the Object, and
|
|
|
|
|
|
- be made available to anyone “inside” the Object
|
2020-06-16 16:53:35 +02:00
|
|
|
|
- Also Accounts can store commands on themselves. Account commands are always available unless
|
|
|
|
|
|
commands on a puppeted Object explicitly override them.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
In Evennia, using the `@ic` command will allow you to puppet a given Object (assuming you have
|
|
|
|
|
|
puppet-access to do so). As mentioned above, the bog-standard Character class is in fact like any
|
|
|
|
|
|
Object: it is auto-puppeted when logging in and just has a command set on it containing the normal
|
|
|
|
|
|
in-game commands, like look, inventory, get and so on.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@ic mech
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
You just jumped out of your Character and *are* now the mech! If people look at you in-game, they
|
|
|
|
|
|
will look at a mech. The problem at this point is that the mech Object has no commands of its own.
|
|
|
|
|
|
The usual things like look, inventory and get sat on the Character object, remember? So at the
|
|
|
|
|
|
moment the mech is not quite as cool as it could be.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@ic <Your old Character>
|
|
|
|
|
|
|
|
|
|
|
|
You just jumped back to puppeting your normal, mundane Character again. All is well.
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
> (But, you ask, where did that `@ic` command come from, if the mech had no commands on it? The
|
|
|
|
|
|
answer is that it came from the Account's command set. This is important. Without the Account being
|
|
|
|
|
|
the one with the `@ic` command, we would not have been able to get back out of our mech again.)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Arming the Mech
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
Let us make the mech a little more interesting. In our favorite text editor, we will create some new
|
|
|
|
|
|
mech-suitable commands. In Evennia, commands are defined as Python classes.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# in a new file mygame/commands/mechcommands.py
|
|
|
|
|
|
|
|
|
|
|
|
from evennia import Command
|
|
|
|
|
|
|
|
|
|
|
|
class CmdShoot(Command):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Firing the mech’s gun
|
|
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
shoot [target]
|
|
|
|
|
|
|
|
|
|
|
|
This will fire your mech’s main gun. If no
|
|
|
|
|
|
target is given, you will shoot in the air.
|
|
|
|
|
|
"""
|
|
|
|
|
|
key = "shoot"
|
|
|
|
|
|
aliases = ["fire", "fire!"]
|
|
|
|
|
|
|
|
|
|
|
|
def func(self):
|
|
|
|
|
|
"This actually does the shooting"
|
|
|
|
|
|
|
|
|
|
|
|
caller = self.caller
|
|
|
|
|
|
location = caller.location
|
|
|
|
|
|
|
|
|
|
|
|
if not self.args:
|
|
|
|
|
|
# no argument given to command - shoot in the air
|
2020-06-07 02:35:06 +02:00
|
|
|
|
message = "BOOM! The mech fires its gun in the air!"
|
2020-04-07 23:13:24 +02:00
|
|
|
|
location.msg_contents(message)
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
# we have an argument, search for target
|
2020-06-06 19:38:34 +02:00
|
|
|
|
target = caller.search(self.args.strip())
|
2020-04-07 23:13:24 +02:00
|
|
|
|
if target:
|
2021-10-12 12:13:42 -06:00
|
|
|
|
location.msg_contents(
|
|
|
|
|
|
f"BOOM! The mech fires its gun at {target.key}"
|
|
|
|
|
|
)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
class CmdLaunch(Command):
|
|
|
|
|
|
# make your own 'launch'-command here as an exercise!
|
|
|
|
|
|
# (it's very similar to the 'shoot' command above).
|
2020-06-07 02:35:06 +02:00
|
|
|
|
|
2020-04-07 23:13:24 +02:00
|
|
|
|
```
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
This is saved as a normal Python module (let’s call it `mechcommands.py`), in a place Evennia looks
|
|
|
|
|
|
for such modules (`mygame/commands/`). This command will trigger when the player gives the command
|
|
|
|
|
|
“shoot”, “fire,” or even “fire!” with an exclamation mark. The mech can shoot in the air or at a
|
|
|
|
|
|
target if you give one. In a real game the gun would probably be given a chance to hit and give
|
|
|
|
|
|
damage to the target, but this is enough for now.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
We also make a second command for launching missiles (`CmdLaunch`). To save
|
|
|
|
|
|
space we won’t describe it here; it looks the same except it returns a text
|
|
|
|
|
|
about the missiles being fired and has different `key` and `aliases`. We leave
|
|
|
|
|
|
that up to you to create as an exercise. You could have it print "WOOSH! The
|
|
|
|
|
|
mech launches missiles against <target>!", for example.
|
|
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
|
Now we shove our commands into a command set. A [Command Set](../Components/Command-Sets.md) (CmdSet) is a container
|
2020-06-16 16:53:35 +02:00
|
|
|
|
holding any number of commands. The command set is what we will store on the mech.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# in the same file mygame/commands/mechcommands.py
|
|
|
|
|
|
|
|
|
|
|
|
from evennia import CmdSet
|
|
|
|
|
|
from evennia import default_cmds
|
|
|
|
|
|
|
|
|
|
|
|
class MechCmdSet(CmdSet):
|
|
|
|
|
|
"""
|
|
|
|
|
|
This allows mechs to do do mech stuff.
|
|
|
|
|
|
"""
|
|
|
|
|
|
key = "mechcmdset"
|
|
|
|
|
|
|
|
|
|
|
|
def at_cmdset_creation(self):
|
|
|
|
|
|
"Called once, when cmdset is first created"
|
|
|
|
|
|
self.add(CmdShoot())
|
|
|
|
|
|
self.add(CmdLaunch())
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
This simply groups all the commands we want. We add our new shoot/launch commands. Let’s head back
|
|
|
|
|
|
into the game. For testing we will manually attach our new CmdSet to the mech.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@py self.search("mech").cmdset.add("commands.mechcommands.MechCmdSet")
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
This is a little Python snippet (run from the command line as an admin) that searches for the mech
|
|
|
|
|
|
in our current location and attaches our new MechCmdSet to it. What we add is actually the Python
|
|
|
|
|
|
path to our cmdset class. Evennia will import and initialize it behind the scenes.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@ic mech
|
|
|
|
|
|
|
|
|
|
|
|
We are back as the mech! Let’s do some shooting!
|
|
|
|
|
|
|
|
|
|
|
|
fire!
|
|
|
|
|
|
BOOM! The mech fires its gun in the air!
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
There we go, one functioning mech. Try your own `launch` command and see that it works too. We can
|
|
|
|
|
|
not only walk around as the mech — since the CharacterCmdSet is included in our MechCmdSet, the mech
|
|
|
|
|
|
can also do everything a Character could do, like look around, pick up stuff, and have an inventory.
|
|
|
|
|
|
We could now shoot the gun at a target or try the missile launch command. Once you have your own
|
|
|
|
|
|
mech, what else do you need?
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
> Note: You'll find that the mech's commands are available to you by just standing in the same
|
|
|
|
|
|
location (not just by puppeting it). We'll solve this with a *lock* in the next section.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
## Making a Mech production line
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
What we’ve done so far is just to make a normal Object, describe it and put some commands on it.
|
|
|
|
|
|
This is great for testing. The way we added it, the MechCmdSet will even go away if we reload the
|
|
|
|
|
|
server. Now we want to make the mech an actual object “type” so we can create mechs without those
|
|
|
|
|
|
extra steps. For this we need to create a new Typeclass.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2021-10-21 21:04:14 +02:00
|
|
|
|
A [Typeclass](../Components/Typeclasses.md) is a near-normal Python class that stores its existence to the database
|
2020-06-16 16:53:35 +02:00
|
|
|
|
behind the scenes. A Typeclass is created in a normal Python source file:
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# in the new file mygame/typeclasses/mech.py
|
|
|
|
|
|
|
|
|
|
|
|
from typeclasses.objects import Object
|
|
|
|
|
|
from commands.mechcommands import MechCmdSet
|
|
|
|
|
|
from evennia import default_cmds
|
|
|
|
|
|
|
|
|
|
|
|
class Mech(Object):
|
|
|
|
|
|
"""
|
|
|
|
|
|
This typeclass describes an armed Mech.
|
|
|
|
|
|
"""
|
|
|
|
|
|
def at_object_creation(self):
|
|
|
|
|
|
"This is called only when object is first created"
|
|
|
|
|
|
self.cmdset.add_default(default_cmds.CharacterCmdSet)
|
2021-08-06 17:16:44 +02:00
|
|
|
|
self.cmdset.add(MechCmdSet, persistent=True)
|
2020-04-07 23:13:24 +02:00
|
|
|
|
self.locks.add("puppet:all();call:false()")
|
|
|
|
|
|
self.db.desc = "This is a huge mech. It has missiles and stuff."
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
For convenience we include the full contents of the default `CharacterCmdSet` in there. This will
|
|
|
|
|
|
make a Character’s normal commands available to the mech. We also add the mech-commands from before,
|
|
|
|
|
|
making sure they are stored persistently in the database. The locks specify that anyone can puppet
|
|
|
|
|
|
the meck and no-one can "call" the mech's Commands from 'outside' it - you have to puppet it to be
|
|
|
|
|
|
able to shoot.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
That’s it. When Objects of this type are created, they will always start out with the mech’s command
|
|
|
|
|
|
set and the correct lock. We set a default description, but you would probably change this with
|
|
|
|
|
|
`@desc` to individualize your mechs as you build them.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
Back in the game, just exit the old mech (`@ic` back to your old character) then do
|
|
|
|
|
|
|
|
|
|
|
|
@create/drop The Bigger Mech ; bigmech : mech.Mech
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
We create a new, bigger mech with an alias bigmech. Note how we give the python-path to our
|
|
|
|
|
|
Typeclass at the end — this tells Evennia to create the new object based on that class (we don't
|
|
|
|
|
|
have to give the full path in our game dir `typeclasses.mech.Mech` because Evennia knows to look in
|
|
|
|
|
|
the `typeclasses` folder already). A shining new mech will appear in the room! Just use
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
|
|
|
|
|
@ic bigmech
|
|
|
|
|
|
|
|
|
|
|
|
to take it on a test drive.
|
|
|
|
|
|
|
|
|
|
|
|
## Future Mechs
|
|
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
To expand on this you could add more commands to the mech and remove others. Maybe the mech
|
|
|
|
|
|
shouldn’t work just like a Character after all. Maybe it makes loud noises every time it passes from
|
|
|
|
|
|
room to room. Maybe it cannot pick up things without crushing them. Maybe it needs fuel, ammo and
|
|
|
|
|
|
repairs. Maybe you’ll lock it down so it can only be puppeted by emo teenagers.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
Having you puppet the mech-object directly is also just one way to implement a giant mech in
|
|
|
|
|
|
Evennia.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2020-06-16 16:53:35 +02:00
|
|
|
|
For example, you could instead picture a mech as a “vehicle” that you “enter” as your normal
|
|
|
|
|
|
Character (since any Object can move inside another). In that case the “insides” of the mech Object
|
|
|
|
|
|
could be the “cockpit”. The cockpit would have the `MechCommandSet` stored on itself and all the
|
|
|
|
|
|
shooting goodness would be made available to you only when you enter it.
|
2020-04-07 23:13:24 +02:00
|
|
|
|
|
2021-08-06 17:16:44 +02:00
|
|
|
|
And of course you could put more guns on it. And make it fly.
|