Wiz Programming Tutorials

Here we'll show you how to create objects that give players access to new commands.

Contents

Commands

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.

How does it work?

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.

knowsCommand

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.

createEvent

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.

execute

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.

Registering Commands

We mentioned that you can "register" your Command, so it gets called for everyone in the map, or for a player in any map.

Map-Wide Commands

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!)

Player Commands

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.

Advanced Features

We'll cover the more advanced functions in a later tutorial, perhaps, but this should get you started making new game commands.

<< Previous Chapter Next Chapter >>