Wiz Programming Tutorials

In order for your Jython code to make things happen in Wyvern, it has to call game functions. The game functions are all written in Java. This tutorial will show you how to access those functions.

First, make a bookmark to this link:

	The Wyvern Game API

You'll need it.

Next, take a look at that API. It's automatically generated from the Wyvern source code comments using a program called "javadoc". When we change Wyvern, we update the API on the website — usually every few weeks. The API is shown as a bunch of things called packages. We'll cover those first.

Packages

A package is a collection of classes. We're not going to cover classes here — if you're not familiar with them, you should read up on Python programming. They'll teach you all about objects, classes, methods, and object-oriented programming. Then you can come back and finish this tutorial.

Back to packages. In Java, classes are all grouped into packages. For instance, if you have a collection of classes to implement a Zoo (such as Elephant, Rhino, and Lion), then you might put them in a package called "zoo". If you want to use Elephant in your program, you have to import it from the zoo package first. In Jython, importing looks like this:

from zoo import Elephant

You put this line at the top of your program. Then you can make and use Elephants in your program.

Wyvern has several dozen packages available to you, and we'll cover a few of the important ones next.

The Wyvern API

Wyvern has over a thousand classes in its API. You don't need to use all of them. In fact, even if you write a whole bunch of Wyvern Jython code, you'll probably only use a few dozen of the same Wyvern classes, over and over.

However, it's extremely difficult to tell which classes you need to use just by looking at those API docs. That's sort of a problem with javadoc - it doesn't assign any relative importance to one class or package over another one. So what do you do? Well, two things:

  • You read all our tutorials carefully, and copy them as much as you can.

  • You ask fellow Wizards for help if you get stuck.

With that in mind, we'll mention a few of the classes and packages you'll be using most frequently in your Jython code.

First, be aware that Wyvern packages are heirarchical, and they all start with "wyvern". There's a wyvern.lib, and underneath that there's a wyvern.lib.classes, a wyvern.lib.commands, a wyvern.lib.classes.armor, and so on. All the packages are listed in the API docs on the first page.

So as an example, if you want to use the class Door, which is located in wyvern.lib.classes.construct, you'd do:

from wyvern.lib.classes.construct import Door

Then you can create and use Doors in your Jython program.

You have to list every class you want to import in the import statement, so if you also wanted to use SpiralStair, you'd do this:

from wyvern.lib.classes.construct import Door, SpiralStair

You typically have multiple import statements in your program, such as:

<span class='keyword'></span>from<span class='keyword'></span> <span class='keyword'></span>java<span class='keyword'></span>.<span class='keyword'></span>util<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Iterator<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>GameMap<span class='keyword'></span>, <span class='keyword'></span>Kernel<span class='keyword'></span>, <span class='keyword'></span>Timed<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>predicates<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>ArchetypePredicate<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>properties<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Applyable<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>StaticObject<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>kernel<span class='keyword'></span>.<span class='keyword'></span>maps<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>MapLoader<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>world<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>World<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>common<span class='keyword'></span>.<span class='keyword'></span>config<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Wyvern<span class='keyword'></span>

It's a common mistake to forget to import a class you're using. In Jython, pretty much everything is lowercased, so if you're using something that's capitalized, it's probably a Java class that you need to import.

Important Wyvern Packages and classes

This table shows a few of the classes you'll use most frequently:

Class or Package Description
everything in wyvern.lib This has lots of useful game interfaces, and you should familiarize yourself with just about all of them. It has Monster,  Player,  GameMap, and most of the other really important ones covered in the Tutorials.

wyvern.lib.classes.DynamicObject This is the most common class to subclass for your Jython objects that can be picked up by players.

wyvern.lib.classes.StaticObject This is the most common class to subclass for your Jython objects that can't be picked up, such as trees or fountains.

wyvern.world.World The World keeps track of all the current players and maps in the game.
wyvern.common.config.Wyvern This class keeps track of the directory structure for Wyvern, so you use it to find where certain files are located.
wyvern.kernel.combat.Combat This class provides functions for damaging and killing monsters and players.

There are plenty of others as well, but nearly all of the classes you'll use on a regular basis are in wyvern.lib or one of its sub-packages (like wyvern.lib.properties or wyvern.lib.classes).

Using Java Classes

OK, so now you know how to import Java classes into your Jython program. What next?

You can do three different things with a Java class in your program:

  1. You can subclass it.
  2. You can instantiate it.
  3. You can call methods on it.
  4. You can set properties on it.

You'll use one or more of these, depending on what you're trying to accomplish.

Subclassing

This is where you start with an existing class, and make a Jython version of it that extends its functionality.

You'll need to do this in almost every Jython program you write for Wyvern, because almost everything you create will be a GameObject or a GameMap. GameObjects are the things players interact with - other players, monsters, bags, armor, weapons, terrain, trees, buildings, teleporters, spells, and so on. GameMaps are, well, maps, of course.

Whenever you subclass a GameObject, you should provide an initialize method for it, which sets up its default properties. For example, this is a fully-functional Jython program:

<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>weapons<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Sword<span class='keyword'></span><br><br><span class='keyword'>class</span> <span class='function'>my_sword</span>(Sword):<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>setProperty<span class='keyword'></span>('<span class='keyword'></span>short<span class='keyword'></span>', '<span class='keyword'></span>My<span class='keyword'></span> <span class='keyword'></span>Sword<span class='keyword'></span>')

If you created one of these in the game, you'd have a regular old sword, except its name would be "My Sword". You can do this using a regular old archetype, as well:

<arch class="wyvern.lib.classes.weapons.Sword">
  <string name="short" value="My Sword"/>
</arch>

So our Jython example above doesn't gain you anything by being written in Jython. You should only use Jython if you're attempting to do something fancier than setting properties on an object.

How did we know Sword is a GameObject? Well, the Wyvern Game API documentation tells you. Go to your trusty bookmark, click on wyvern.lib.classes.weapons, scroll down, and click on Sword. Near the top of the page, you'll see Class Sword with a tree underneath it showing all the superclasses for Sword:


java.lang.Object
  |
  +--wyvern.kernel.properties.PList
        |
        +--wyvern.kernel.maps.MapObject
              |
              +--wyvern.lib.classes.weapons.WeaponImpl
                    |
                    +--wyvern.lib.classes.weapons.MeleeWeapon
                          |
                          +--wyvern.lib.classes.weapons.Blade
                                |
                                +--wyvern.lib.classes.weapons.Sword

All Implemented Interfaces:
Applyable, Attack, Damageable, Drawable, GameObject, Locatable, MethodHookable, Movable, PickupInterest, PropertyList, Readyable, Weapon


What does this mean? Well, for starters, it means swords are pretty complicated beasts. A Sword's direct superclasses are:

  • Blade - includes swords, rapiers, knives, etc.
  • MeleeWeapon - includes clubs, blades, axes, etc.
  • WeaponImpl - includes range weapons, hurled weapons and melee weapons
  • MapObject - includes weapons, armor, players, terrain, etc.
  • PList - includes all game objects and game maps (they both have property lists)
  • Object - the superclass of all classes in Java

As you can see, the superclasses get more and more generic as they go up the chain.

Below the class tree, you see a list of All Implemented Interfaces. Interfaces are pretty much like classes, except they don't have any code in them. They simply specify that your class has to behave a certain way. For instance, Sword implements the Damageable interface, meaning swords have hit points and can take damage.

Finally, you'll see that GameObject is in the list of interfaces for the Sword class. That's how we knew. =)

So where were we? Ah yes, subclassing. Well, we pointed out that subclasses are more specialized than their superclasses. That's how you make Jython objects that do unique things. You pick a game object that's sort of like the one you want to make, and you subclass it.

In our example above, we just wanted to make a Sword that has a special description. Our sword is basically just a sword, but has some extra "stuff" in it, so we subclassed wyvern.lib.classes.weapons.Sword. Make sense?

When you read through the other tutorials, take a look at the classes that the tutorials subclass. The most popular ones to subclass are:

  • wyvern.lib.classes.DynamicObject — any time you just want to make something that players can pick up and carry, use this.

  • wyvern.lib.classes.StaticObject — a popular choice for non-teleporters that are part of the scenery.

  • wyvern.lib.classes.Structure — used for buildings and other visible teleporters. Its superclass is wyvern.lib.classes.Teleporter, which is useful for invisible teleporters.

However, don't feel obligated to use these. If you want to make a special MagicMouth, feel free to subclass wyvern.lib.classes.construct.MagicMouth! There are dozens of useful game classes that you can use as the starting point for your Jython class.

You should browse through the wyvern.lib.classes and wyvern.lib.classes.construct packages in the Wyvern API Docs, since these two packages contain 90% of the classes you'll want to subclass when you're programming.

Instantiating

Sometimes you'll want to create objects and stick them in a map, a player's inventory, a bag, or whatever. This is called instantiation. You do it by putting () (parentheses) after the name of the class to instantiate.

You don't actually use plain old object instantiation for GameObjects. Instead, you ask the Kernel to do it for you. It's hard to come up with a 3- to 5-line example showing when you'd want to do this, but we'll do our best. The following example is a simple Monster Dispenser - you pull the lever and a monster comes out. It's what every player dreams about!

<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>construct<span class='keyword'></span> <span class='keyword'></span>import<span class='keyword'></span> <span class='keyword'></span>Lever<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>Kernel<span class='keyword'></span><br><br><span class='keyword'>class</span> <span class='function'>monster_dispenser</span>(Lever):<br>    <span class='keyword'>def</span> <span class='function'>apply</span>(self, agent):<br>        <span class='keyword'></span>mon<span class='keyword'></span> = <span class='keyword'></span>Kernel<span class='keyword'></span>.<span class='keyword'></span>instantiate<span class='keyword'></span>('<span class='keyword'></span>monsters<span class='keyword'></span>/<span class='keyword'></span>goblin<span class='keyword'></span>/<span class='keyword'></span>orc<span class='keyword'></span>')<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>ref<span class='keyword'></span> = <span class='keyword'></span><span class='instance'>self</span><span class='keyword'></span>.<span class='keyword'></span>getReferenceLoc<span class='keyword'></span>()<br>        <span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>setMap<span class='keyword'></span>(<span class='keyword'></span>map<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>x<span class='keyword'></span>, <span class='keyword'></span>ref<span class='keyword'></span>.<span class='keyword'></span>y<span class='keyword'></span>)<br>        <span class='keyword'></span>mon<span class='keyword'></span>.<span class='keyword'></span>start<span class='keyword'></span>()

Notice we skipped the instantiate method here, because we didn't want to give it any special properties. It's going to look like a regular old lever to a player.

Notice also that Jython class names typically_look_like_this, whereas Java class names TypicallyLookLikeThis.

We imported two handy-dandy Wyvern classes: Lever, which we subclassed, and also Kernel, which we use to instantiate an orc.

You can ignore all the lines in the example for now, except for this one:

mon = Kernel.instantiate('monsters/goblin/orc')

We're going to focus a bit on that line. What's it doing? It's creating a variable called mon, and instantiating an Orc, and then assigning the Orc to the mon variable so we can do stuff with it afterwards (like stick it in the map and start it up.)

We've invoked a built-in game function on this line. The function is called instantiate, and it exists in the class wyvern.lib.Kernel. Its purpose in life is to take the path to an archetype file, turn it into a Game Object, and return it to you.

We didn't really cover regular instantiation here, because you don't often need to do it. You usually ask the Kernel to instantiate archetypes for you instead. However, in later tutorials we may show you specific examples of when you'd want to instantiate an object directly. No point in learning how until you need to do it!

Calling Functions

This is the third thing you can do with Java objects. You call functions (also called "methods") on the objects, and the functions do things for you.

If you've been reading carefully, you'll have noticed that this is exactly what we did in the MonsterDispenser example above. How many times did we call a game function? We actually called five functions:

  1. we called instantiate on the Kernel class, to get ourselves a monster.

  2. we called getMap on ourself, to figure out what map we're in. This is a function that we inherited from GameObject.

  3. we called getReferenceLoc on ourself, to get our upper-left corner location. Since we're only a 1x1 object, this is the only location we have. This function is also inherited from our GameObject superclass.

  4. we called setMap on the orc, to put it in our map at our location. You guessed it, this one is also inherited from GameObject. Hmmm, maybe you should take a look at that interface!

  5. lastly, we called start on the orc, to make it start moving, attacking and so on. This method is actually inherited from the orc's Monster superclass (superinterface, actually, but who's counting?) You can start monsters, but you can't start buildings or other non-commandable objects.

If you want to be picky, you'll notice that the player is standing on the lever, and we put the Orc on that location, so the Orc will actually be in the same square as the player. Oops! Well, we tried to keep the example simple. There's actually another function you can call to find the free spot nearest to a given location. It's in the GameMap interface, and it's called findFreeSpot, if you really care.

Setting Properties

This is the fourth and final thing you can do to a Wyvern object, and it's by far the most common.

Setting properties is covered, appropriately, in the Properties tutorial, so we won't cover it here.

Wrapping Things Up

We have to end this tutorial now (alas!), but hopefully you should feel like you have a better understanding of how to use that bookmark you made. Read all the tutorials, ask for help from fellow Wizards, and study the Python/Jython manuals and Wyvern APIs, and it should all eventually start to become clear.

Good luck!

<< Previous Chapter Next Chapter >>