mirror of
https://github.com/evennia/evennia.git
synced 2026-03-23 08:16:30 +01:00
Updated HTML docs.
This commit is contained in:
parent
59e50f3fa5
commit
06bc3c8bcd
663 changed files with 2 additions and 61705 deletions
|
|
@ -1,237 +0,0 @@
|
|||
# Building a mech tutorial
|
||||
|
||||
> 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.
|
||||
|
||||
## Creating the Mech
|
||||
|
||||
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).
|
||||
|
||||
@create/drop Giant Mech ; mech
|
||||
|
||||
Boom. We created a Giant Mech Object and dropped it in the room. We also gave it an alias *mech*.
|
||||
Let’s describe it.
|
||||
|
||||
@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()
|
||||
|
||||
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.)
|
||||
|
||||
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:
|
||||
|
||||
- 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
|
||||
children of normal Objects.
|
||||
- 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
|
||||
- Also Accounts can store commands on themselves. Account commands are always available unless
|
||||
commands on a puppeted Object explicitly override them.
|
||||
|
||||
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.
|
||||
|
||||
@ic mech
|
||||
|
||||
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.
|
||||
|
||||
@ic <Your old Character>
|
||||
|
||||
You just jumped back to puppeting your normal, mundane Character again. All is well.
|
||||
|
||||
> (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.)
|
||||
|
||||
|
||||
### Arming the Mech
|
||||
|
||||
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.
|
||||
|
||||
```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
|
||||
message = "BOOM! The mech fires its gun in the air!"
|
||||
location.msg_contents(message)
|
||||
return
|
||||
|
||||
# we have an argument, search for target
|
||||
target = caller.search(self.args.strip())
|
||||
if target:
|
||||
location.msg_contents(
|
||||
f"BOOM! The mech fires its gun at {target.key}"
|
||||
)
|
||||
|
||||
class CmdLaunch(Command):
|
||||
# make your own 'launch'-command here as an exercise!
|
||||
# (it's very similar to the 'shoot' command above).
|
||||
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Now we shove our commands into a command set. A [Command Set](../Components/Command-Sets.md) (CmdSet) is a container
|
||||
holding any number of commands. The command set is what we will store on the mech.
|
||||
|
||||
```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())
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
@py self.search("mech").cmdset.add("commands.mechcommands.MechCmdSet")
|
||||
|
||||
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.
|
||||
|
||||
@ic mech
|
||||
|
||||
We are back as the mech! Let’s do some shooting!
|
||||
|
||||
fire!
|
||||
BOOM! The mech fires its gun in the air!
|
||||
|
||||
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?
|
||||
|
||||
> 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.
|
||||
|
||||
## Making a Mech production line
|
||||
|
||||
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.
|
||||
|
||||
A [Typeclass](../Components/Typeclasses.md) is a near-normal Python class that stores its existence to the database
|
||||
behind the scenes. A Typeclass is created in a normal Python source file:
|
||||
|
||||
```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)
|
||||
self.cmdset.add(MechCmdSet, persistent=True)
|
||||
self.locks.add("puppet:all();call:false()")
|
||||
self.db.desc = "This is a huge mech. It has missiles and stuff."
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@ic bigmech
|
||||
|
||||
to take it on a test drive.
|
||||
|
||||
## Future Mechs
|
||||
|
||||
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.
|
||||
|
||||
Having you puppet the mech-object directly is also just one way to implement a giant mech in
|
||||
Evennia.
|
||||
|
||||
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.
|
||||
|
||||
And of course you could put more guns on it. And make it fly.
|
||||
Loading…
Add table
Add a link
Reference in a new issue