Wiz Programming Tutorials

This manual covers scripting/coding for the Wyvern Platform. It's for advanced users only: you should already be fairly comfortable in at least one programming language before you read this manual.

Contents

Overview

You can do just about anything in Wyvern using Jython or Java. The two languages are basically equivalent — different syntax, but you can do the same things in each of them.

Some of our examples will be in Java and some will be in Jython. After a while you'll see how to translate between the two of them. The calls to the game functions have the same names and arguments.

Most of the game is written in Java, because it's faster. Jython is an implementation of the language Python for Java, so it has to get translated down into Java before the game can run the code.

Despite it being about 2x slower, Jython is the best language for doing Wiz areas, because you don't have to compile it. You just create objects with it, and any changes you make show up in the new objects (but not the old ones). You can test different code side-by-side with multiple game objects. We recommend you use Jython for your Wyvern programming.

This manual doesn't cover the Jython or Java language syntax. We focus primarily on the services that are available within the game for creating and manipulating objects and maps. From time to time we'll point out Jython- or Java-specific issues you have to be aware of.

Jython and Java are both Object Oriented languages. You will have a lot of trouble using them if you're not familiar with the the basic Object-Oriented Programming (OOP) concepts: classes, objects, instantiation, inheritance, interfaces, methods, instance variables, and encapsulation. They're not difficult concepts to lean, and you should find yourself an OOP tutorial if you're unfamiliar with this programming style.

Wyvern Platform

The Wyvern game engine, which we'll call the Wyvern Platform in the rest of the document, is designed to give you maximum flexibility for controlling the game environment. We've written hundreds of game extensions, including:

  • all the spells (120 or so)
  • all the guilds
  • all the special magical items like crystal balls, portable holes, monster-suckos, cloak of thieves, and so on
  • the Minath Monster Arena and the Alaria Fight Arena
  • the Tower of Sokoban
  • the Chess and Checkers games
  • the Side-Scroller quest
As well as many, many others. We're only scratching the surface, though — we expect that over time, Wizards will create hundreds or even thousands of completely new experiences for the game.

Before you can realistically understand the examples we give, though, you have to know what things you can (and can't) do with the game engine. We'll cover them briefly here before moving on to more detailed tutorials.

Wizard Tools

You have 4 basic tools at your disposal for creating content for the game:
  • game maps, which you can create with the map editor
  • archetypes, which (right now) you have to create by hand
  • jython and java source-code files
  • xml files for storing things like High Score lists and other rich content. The game provides utilities that make it fairly straightforward to write and read your own custom xml files.
We're going to assume, for this manual, that you know how to create maps and archetypes. At some point we'll have a comprehensive manual on how to do it, but right now Wizards should be able to help you figure it out.

Speaking of tools, in order to program for Wyvern you'll need:

  • the Map Editor (try to stay in sync with the latest version)
  • any plain-text editor like Notepad, vi, or Emacs
  • an image editor that can make GIF files (if you're doing artwork)
You do not need:
  • jython on your local machine. It's on the server. All you need to do is upload your .py files.
  • a java compiler. This is also on the server. There's no way to test your source code on your local box.
This manual will focus on creating objects in Jython and Java.

Before you go much further, you should read the Getting Started document — it shows you how to create, upload, and execute python files.

Platform Basics

The game has a number of concepts or abstractions that you should familiarize yourself with:
  • Maps — the game has maps that consist of objects at (x, y) locations. x goes to the right (positive) and y goes down. Maps are connected together by teleporters (buildings, stairs, invisible teleporters, and so on). There are two main kinds of maps, "unbounded" and "bounded", but 99.9% of the maps in the game are bounded maps, and you'll almost always use unbounded ones.

  • Game Objects — any object that can be placed in a map is a Game Object, including terrain, buildings, monsters, players, weapons, armor, spells, traps, and some invisible objects like teleporters, shops, and no-monsters squares. Any archetype you can select in the map editor and put into the map is a Game Object.

  • Properties — game objects have properties, such as their image, height, width, short name, long name, hit points, weight, and so on. Every property has a name (a string) and a value that can be a double, int, boolean, string, Archetype, or JavaBean. More on this later.

  • Archetypes — these are templates from which Game Objects are produced. They function a bit like classes, but with no code. They're basically just lists of properties, usually stored in an XML file with the extension ".arch".

  • Monster AIs — monsters (and some spells) are controlled by AIs (Artificial Intelligences). Most monsters are controlled by the StandardAI, which is fairly customizable via properties on the monster, but you can also create your own AIs.

  • Cameras — a Camera is something that can provide a view of a map. Every player has a camera that you can take control of. For instance, ships can move the player's camera inside and outside the ship. The Wizard Eye spell and Crystal Ball also control the player's camera.

  • Timers — you can set timers, so you can get called back after a certain period. There's a special utility class that lets you set timers that suspend when the object's map is suspended or unloaded, and resume if the map resumes.

  • Hooks — these are special notifications you can register for. If you want to know if someone has done something (and possibly change it), you use Hooks. There are least four different kinds, and we'll talk a LOT more about them in this manual, since they're the way you get the most interesting things accomplished.

  • Commands — also known as Commands, these are objects that provide commands to players, monsters, and wizards. All the player commands and wiz commands are provided by Commands. You can make your own Commands to give the player access to new commands. For instance, the Alaria Fight Arena is an Command that gives you "fight", "match", and the other arena commands.

  • Events and Event Queues — every command in the game is encapsulated as an Event. Every monster and player in the game (and some other objects) has at least one Event Queue for holding the events while they're waiting to be executed. You can issue commands to a player or monster by sticking events in their queue.

  • Predicates — a Predicate is a test, like "is this player blind", or "is this object made of gold". Predicates are encapsulated as objects so you can pass them into a map (or bag, or whatever) to look for GameObjects that "match" your test. The game has dozens of built-in predicates you can use, or you can easily create your own.

  • Logs — a Log lets you write a timestamped message to a text file. The game provides APIs for writing to your own log files.

We'll talk in more detail about each of these abstractions later in the manual. For now, just be aware that these are the major types of objects in the game — the ones you'll be dealing with the most as you create custom content.

Map Loading Sequence

Before we go into too much more detail, it's useful to cover the steps that the game goes through to load the game, or load a map, or load an object in a map.

Loading the Game

The game starts by creating the World object, which maintains the player lists and active maps. Whenever you want to see who's online, or what maps are loaded, you ask the World object (wyvern.world.World).

The World bootstraps the Game Scheduler, which handles all events in the game. This includes:

  • command events, such as players saying "move north" or "kill kobold".

  • timer events, for objects that have set timers. The most common ones are animation timers, but we also have corpse decay timers, lava timers, and many others.

  • camera events — well, just one. The game stops every 1/15th of a second or so and refreshes all the cameras in the game. This is handled as an event that goes through the queue just like any other event, largely for auditing purposes.

Once the Scheduler is started, the World loads up all the maps in the system preload list. This is just a text file of all the maps (usually cathedrals) that we want loaded on startup. After preloading the maps, the World fires off a few processes to update the high score list and deaths list, and returns control to the server.

The last thing the Server does is open a listener for incoming connections. Whenever a connection comes in, it hands the connection to the wyvern.world.Registration, which handles connecting a new player and logging them in.

Loading Maps

A map is loaded by a class called wyvern.kernel.maps.MapLoader. There is no other way to load a map, unless you want to do a LOT of work by yourself.

You don't usually load maps by creating a MapLoader (although you can). Typically you just ask the World to load the map for you. The World normally does this on a separate thread of execution (i.e. in the "background"), so the game doesn't lock up while the map is loading. This is why you get the message "Please wait while this map is loaded." when you first apply a teleporter.

Maps are stored in XML files with a special format. They look like this:

<map>

<header>
  (map properties)
</header>

<arch ...>
<arch ...>
<arch ...>

</map>

That is, the first XML element is a "header" element that has the properties for the map, such as whether it's dark, and whether it allows player-killing.

All the remaining elements are "arch" entries, which stands for archetypes. An arch element specifies 3 things:

  • the (x, y) location in the map where the object should be placed
  • the path of the archetype to load OR class of the object to create
  • (optionally) any additional properties to put on the created object

The MapLoader reads each object in sequence and puts them in the map one at a time, building the map up from scratch. If an object needs to know when all the objects are finally in the map, there's a special "done-loading" notification it can register for. More on this later.

All objects that can go in a map file are GameObjects — that is, an archetype always specifies a GameObject to create, plus some additional properties to add to the object. GameObjects can be written in Java or Jython.

Object Loading

As the MapLoader loads objects and puts them in the map, it goes through the following sequence:
  1. The object's properties are all parsed from the XML. They can be of type double, int, boolean, string, archetype, or javabean. We'll talk more about this later.

  2. All of the object's parent archetypes are loaded from disk (if any). For instance, if you put in a diamond, the game may have to load the "gem" parent-archetype as well (if diamond inherits from gem, which in fact it does).

  3. The MapLoader "instantiates" the archetype, which means it finds the Java or Jython class (such as Bag, or Monster), and creates an object of that class. Then it copies the properties from the archetype onto the object.

  4. Finally, it places the object in the map at the location specified in the "<arch..." xml element.

That may all sound pretty boring, but it's useful to keep it in mind when you're creating your objects.

How Stuff Happens

All we've talked about so far is how the game builds up the in-game data structures that represent maps, objects, and properties. How does stuff happen? How do things move around?

Everything in the game happens through an Event of some sort. Well, almost everything. If a player wants to move, for example, the following sequence of events occurs:

  1. the player types "move" (or clicks in their view with the mouse)

  2. the client sends a command ("move east", or a direction key, or "mouse x y") to the server

  3. the server takes the text command and wraps it with a CommandEvent, which parses the verb and arguments. The command verb is the first word. The arguments are everything after the first word.

  4. the server stuffs the new CommandEvent into the player's Event Queue.

  5. some time later, the Game Scheduler notices this new event in the player's queue, and tells the Executive to execute the event.

  6. the Executive asks the player object to say which object ("Command") will handle the command, in this case, "move".

  7. our example command, "move", is handled by the MoveCommand (wyvern.kernel.motion.MoveCommand). The MoveCommand has code for figuring out whether the player can move, how fast to move, whether the move is actually a push or an attack, and then, ultimately, it moves the player to the new spot in the map.

That's pretty much the sequence of things, over and over.

We've basically got enough background now to be able to start talking about the meatier coding details — in other words, how you can make YOUR stuff happen.

Making Your Own Stuff Happen

There are several fundamentally different things you can do by writing code:

  • You can create objects and put them in maps. You can load them from archetype files, or assemble them yourself. This includes ALL GameObjects — terrain, monsters, spells, shops, everything. Well, not Players — that would be a bad idea. But everything else.

  • You can examine or set an object's properties. For example, your code could make a player blind, or invisible, or flying, or change their name or title. There are wizard commands that can do this as well. Setting properties is by far the most common thing that happens in Wyvern code, so we'll do plenty of examples for it.

  • You can call game functions — for instance, you can load maps, shout to everyone, have players broadcast messages to people near them, and hundreds (if not thousands) of other functions that are already implemented for you. The complete list is available in javadoc format.

  • You can provide new commands for players. For example, the Portable Hole provides the command "exit" for getting out of the hole. Ships, shops, guilds, and other objects provide new commands for players.

  • You can change what happens for existing commands. For instance, the Sokoban game prevents you from moving diagonally. This is the hooks mechanism we've mentioned, and you'll learn a lot more about it later.

  • You can be notified when specific things happen. Perhaps you want your monster to start moving when someone gets too close to your altar. These notifications are also done using hooks (a slightly different kind).

  • You can read and write data in files. You can use plain text files, XML files, or binary data — your choice. Java and Jython provide excellent file I/O mechanisms, and Wyvern provides an XML wrapper class for doing XML input and output.

Most of the interesting objects in the game do several of these things. For instance, the Minath Monster Arena does a bunch of them:
  1. it provides the "start" and "bail" commands for starting a fight or wimping out.

  2. it creates monsters on the fly (actually by reading them out of an XML file, which says which monsters should be used for each level in the areana).

  3. it calls game functions — for example, when the Game Driver shouts "So-and-so is fighting in the Minath Arena", the arena is called the World.shout() function.

  4. it hooks the DeathEvent, and instead of actually dying, the player gets teleported out of the arena. It also hooks the "apply" command, to prevent players from entering portable holes.

  5. it writes to a file (XML again) with the player's ranking, level, best time, and so on.

  6. it sets properties on the player (healing them and restoring drained XP when the match is over).

So the Minath Arena is an example of a game extension that uses many of the mechanisms available to you. We'll probably provide the source code for it so you can see how it was done.

Gory Details

OK, we've hopefully given you a nice preview of some of the things you can do by coding in Jython. Now it's time to move into the real details — exactly what hooks are, how to use properties, how to make an Command to provide new commands, and so forth.

<< Previous Chapter Next Chapter >>