Here we'll show you how to create objects that give players
access to new commands.
Contents
To make a new command, have your python class implement
the wyvern.lib.Command interface. This interface requires
that you add 3 new methods to your class:
- knowsCommand - return true (1)
if the passed command is one you're handling, else false (0).
- createEvent - takes the passed
event, which is just a wrapper for the command you're
providing, and "stuffs" it with extra information you
want to provide to hook callbacks. For simple extenders,
it's OK to just return the event that was passed in,
with no changes.
- execute - this is where you
actually handle the command.
Here's a simple example, which we'll put in a file called
wiz/rhialto/python/command_test.py:
<span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>java<span class='keyword'></span>.<span class='keyword'></span>lang<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>String<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Command<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span>.<span class='keyword'></span>classes<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>DynamicObject<span class='keyword'></span><br><br><span class='comment'># lets you type "hello" and it'll spit out "Hello, World"</span><br><span class='keyword'>class</span> <span class='function'>command_test</span>(DynamicObject, Command):<br><br> <span class='keyword'>def</span> <span class='function'>initialize</span>(self):<br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__initialize<span class='keyword'></span>()<br><br><span class='comment'> # give it some random appearance so you can see it</span><br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>setDefaultImage<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>objects<span class='keyword'></span>/<span class='keyword'></span>jade_key<span class='keyword'></span>"</span>)<br><br> <span class='keyword'>def</span> <span class='function'>knowsCommand</span>(self, cmd):<br> <span class='keyword'></span>return<span class='keyword'></span> <span class='keyword'></span>String<span class='keyword'></span>.<span class='keyword'></span>equals<span class='keyword'></span>(<span class='keyword'></span>cmd<span class='keyword'></span>, <span class='string'>"<span class='keyword'></span>hello<span class='keyword'></span>"</span>)<br><br> <span class='keyword'>def</span> <span class='function'>createEvent</span>(self, event):<br> <span class='keyword'></span>return<span class='keyword'></span> <span class='keyword'></span>event<span class='keyword'></span><br><br> <span class='keyword'>def</span> <span class='function'>execute</span>(self, event):<br><br><span class='comment'> # this is whoever typed "hello"</span><br> <span class='keyword'></span>agent<span class='keyword'></span> = <span class='keyword'></span>event<span class='keyword'></span>.<span class='keyword'></span>getAgent<span class='keyword'></span>()<br><br> <span class='keyword'></span>agent<span class='keyword'></span>.<span class='keyword'></span>message<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>Hello<span class='keyword'></span>, <span class='keyword'></span>World<span class='keyword'></span>!"</span>)<br><br> <span class='keyword'>def</span> <span class='function'>toString</span>(self):<br> <span class='keyword'></span>return<span class='keyword'></span> <span class='string'>"<span class='keyword'></span>hello<span class='keyword'></span> <span class='keyword'></span>tester<span class='keyword'></span>"</span>
|
To test it, I did this:
- clone wiz/rhialto/python/command_test.py
- hello
I.e. after typing "hello", it told me "Hello, World!"
We made it a wyvern.lib.classes.DynamicObject, since that's
a useful class for objects that can be picked up and dropped.
It could have also been a wyvern.kernel.maps.MapObject.
Note: we frequently use the word "agent" instead of "player",
because the agent could be a monster. Monsters can move,
cast spells, and do pretty much any command that a player
has access to.
When you type in a command, the game looks in four places
to see if it can find a handler for the command:
- first it asks if any Command has registered a command
directly with the player using <player>.registerCommand()
- next it looks in the agent's inventory to see if there
is an Command that knows the command. It does this
(you guessed it) by calling knowsCommand()
on each Command in the agent's inventory. This is how
our example worked.
- next it looks in the map where the agent is standing
and asks all the Commands if they know the command (same way).
So if you drop your command_tester, it'll still work if
you're standing on it.
- finally, it asks the map itself if some Command has
registered this command with the map
(using <map>.registerCommand())
So you have four chances to get your Command invoked. The
easiest way is to just make it work in inventory or on the
ground, since you don't have to do anything special for that.
For map-wide commands, you'll want to register with the map,
and for commands that follow the player around, you'll want
to register them with the player. More on this later.
We used String.equals(cmd, "hello") because
we want the comparison to be character-by-character, rather
than just checking the pointers. I'm sure Jython has a way
to do this, but I haven't found it.
If this doesn't make sense to you, don't worry - just use
String.equals() for comparing strings.
This is Wyvern's most powerful extension feature, although
we didn't use it here. We'll talk more about it in the
Hooks and Events manual.
The basic idea is that you can add properties to the event
so that other people can know about it and modify it if
they want. In our case, there isn't much to add. For some
commands, like "give", for example, the GiveCommand
(a built-in Command) sets the giver, the recipient, and
the gift, among other things.
This is the part that actually executes your command. The
event that gets passed in is an instance of
wyvern.lib.CommandEvent , so it gives you
some useful methods:
- getAgent - one you use almost
every time. Gives you the player (or monster) who
typed the command in.
- getOriginalText - gets the
exact string (unparsed, unformatted) that the agent
typed in, if you need it.
- getVerb - the command verb,
which is the first word of the command. In our
case it was "hello".
- getArgs - all the rest of
the words, after the verb, put into an array for you.
In our case it would be null (None in jython).
- getArgString - everything
after the verb, like in getArgs(), but in a single string.
CommandEvent provides these and many other very useful methods.
The event is your friend - it's your scratchpad for putting
and getting all sorts of useful data about the event and the
context in which it's being executed.
We mentioned that you can "register" your Command, so it
gets called for everyone in the map, or for a player in any map.
For maps, you register a command with a "room", which is a
rectangle in the map. It could be the entire map, if you
want, in which case you'd call map.getBounds() to get the
bounding rectangle.
Here's a simple extension to our example that registers
the "honk" command with the game map when you drop it. It's
in a file called wiz/rhialto/python/maptest.py:
<span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>java<span class='keyword'></span>.<span class='keyword'></span>lang<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>String<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Command<span class='keyword'></span><br><span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>wyvern<span class='keyword'></span>.<span class='keyword'></span>lib<span class='keyword'></span>.<span class='keyword'></span>classes<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>DynamicObject<span class='keyword'></span><br><br><br><span class='comment'># lets you type "hello" and it'll spit out "Hello, World"</span><br><span class='keyword'>class</span> <span class='function'>maptest</span>(DynamicObject, Command):<br><br> <span class='keyword'>def</span> <span class='function'>initialize</span>(self):<br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__initialize<span class='keyword'></span>()<br><br><span class='comment'> # give it some random appearance so you can see it</span><br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>setDefaultCategory<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>objects<span class='keyword'></span>"</span>)<br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>setDefaultBitmap<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>jade_key<span class='keyword'></span>"</span>)<br><br> <span class='keyword'>def</span> <span class='function'>knowsCommand</span>(self, cmd):<br> <span class='keyword'></span>return<span class='keyword'></span> <span class='keyword'></span>String<span class='keyword'></span>.<span class='keyword'></span>equals<span class='keyword'></span>(<span class='keyword'></span>cmd<span class='keyword'></span>, <span class='string'>"<span class='keyword'></span>hello<span class='keyword'></span>"</span>)<br><br> <span class='keyword'>def</span> <span class='function'>createEvent</span>(self, event):<br> <span class='keyword'></span>return<span class='keyword'></span> <span class='keyword'></span>event<span class='keyword'></span><br><br> <span class='keyword'>def</span> <span class='function'>execute</span>(self, event):<br><br><span class='comment'> # this is whoever typed "hello"</span><br> <span class='keyword'></span>agent<span class='keyword'></span> = <span class='keyword'></span>event<span class='keyword'></span>.<span class='keyword'></span>getAgent<span class='keyword'></span>()<br><br> <span class='keyword'></span>agent<span class='keyword'></span>.<span class='keyword'></span>message<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>Hello<span class='keyword'></span>, <span class='keyword'></span>World<span class='keyword'></span>"</span>)<br><br> <span class='keyword'>def</span> <span class='function'>toString</span>(self):<br> <span class='keyword'></span>return<span class='keyword'></span> <span class='string'>"<span class='keyword'></span>hello<span class='keyword'></span> <span class='keyword'></span>tester<span class='keyword'></span>"</span><br><br> <span class='keyword'>def</span> <span class='function'>setMap</span>(self, map, x, y):<br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__setMap<span class='keyword'></span>(<span class='keyword'></span>map<span class='keyword'></span>, <span class='keyword'></span>x<span class='keyword'></span>, <span class='keyword'></span>y<span class='keyword'></span>)<br><br> <span class='keyword'></span>if<span class='keyword'></span> <span class='keyword'></span>map<span class='keyword'></span>:<br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>rect<span class='keyword'></span> = <span class='keyword'></span>map<span class='keyword'></span>.<span class='keyword'></span>getBounds<span class='keyword'></span>()<br> <span class='keyword'></span>map<span class='keyword'></span>.<span class='keyword'></span>registerCommand<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>honk<span class='keyword'></span>"</span>, <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>, <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>rect<span class='keyword'></span>)<br><br><br> <span class='keyword'>def</span> <span class='function'>remove</span>(self):<br> <span class='keyword'></span>map<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getMap<span class='keyword'></span>()<br> <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>super__remove<span class='keyword'></span>()<br> <span class='keyword'></span>if<span class='keyword'></span> <span class='keyword'></span>not<span class='keyword'></span> <span class='keyword'></span>map<span class='keyword'></span>: <span class='keyword'></span>return<span class='keyword'></span><br><br> <span class='keyword'></span>map<span class='keyword'></span>.<span class='keyword'></span>unregisterCommand<span class='keyword'></span>(<span class='string'>"<span class='keyword'></span>honk<span class='keyword'></span>"</span>, <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>, <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>rect<span class='keyword'></span>)</<span class='keyword'></span>pre<span class='keyword'></span>>
|
Now our object knows two commands: "honk" and "hello", and both
of them tell the person who typed it "Hello, World!".
However:
- the "hello" command only works if you're carrying it
or it's on the ground right beneath you.
- the "honk" command only works if you've dropped the
object so it's sitting in the map somewhere. BUT,
it works no matter where you are in the map.
All we added were the 2 methods at the end: setMap() and remove().
setMap() is called when the object is added to the map (by
dropping it, or if it was in the map file when the map was
loaded). We call the superclass (important!) to put it in
the map, and then we register ourselves to handle "honk"
in the entire bounds of the map. On remove(), we remember
which map we were in, call the superclass, then unregister.
Notice something odd: we didn't add "honk" to the list
of commands we understand in our knowsCommand
method. Why didn't we? Well, we didn't really have to, because
we've already proclaimed that we know the command when we
registered with the map. In this case it's optional.
knowsCommand is only necessary for getting
your Command invoked automatically if it's in the agent's
inventory, or sitting on the ground beneath the agent. You
can just return 0 from this method if you're going to register
your command yourself. (Don't return 1, or you'll get called
for every single command, even ones you don't care about!)
Setting up a command for a player is pretty similar - you
just get a reference to the player and call registerCommand()
(no rectangle this time) on the player. Need example here.
We'll cover the more advanced functions in a later tutorial,
perhaps, but this should get you started making new game
commands.
|