wyvern.lib
Interface Archetype

All Superinterfaces:
PropertyList
All Known Implementing Classes:
ArchetypeImpl

public interface Archetype
extends PropertyList

A list of properties that a game object can inherit from.

Archetypes are the game's persistence mechanism: they are stored on disk as XML files. An archetype file represents one "game object instance", and has a GameObject implementation class to instantiate, plus optional extra properties and their values.

GameObjects and Archetypes

An Archetype is in some ways like a Java class - it can be instantiated and it has unique behavior. Archetypes differ from Java or Jython classes in that they contain no code - just properties.

Nearly every GameObject originates as an Archetype in an XML archetype file on the server. An Archetype needs to specify a GameObject class or subclass to instantiate, along with an optional list of properties to add to the game object after instantiating it.

Archetypes can inherit from other archetypes. For instance, there is a "wand" archetype that specifies a GameObject class (wyvern.lib.classes.magic.Wand), a default weight, a default description, and a default appearance. The standard wand archetype is actually not strictly necessary, because the default properties could have been specified in the Wand class. However, sub-archetypes of wand have more specific properties, such as the spell to cast, the number of charges, the value of the wand, the maximum charges the wand can hold, and so on.

Archetypes Implement Persistence

The main reason for archetypes is that you don't want to create a new Java or Jython class for every unique combination of object properties. Creating a class is time-consuming, requires a compilation step (for Java), and is system-resource intensive. Archetypes are fairly lightweight entities by comparison.

Archetypes are stored in an XML format on disk. Most archetypes are created in the Map Editor (or will be, although it's not supported as of 8/26/2000), but they can also be hand-edited in any text editor, which makes them very convenient to use.

One disadvantage of archetypes is that you can't put code in them. If, for example, you wanted to create a wand that casts a different spell every time you zap it, you'd have to write a class - either a Wand subclass, or perhaps a RandomSpell class that you could attach to the wand as its spell. So there's a limit to how much extensibility you get using Archetypes, and to do really interesting things you have to write in Jython or Java.

Strong/Weak Typing with Archetypes

One disadvantage of using archetypes is that the typing is extremely weak. We'll need to go through an example for this to make sense, but it's really important to understand and keep in mind as you write your Wizard code.

Let's say you're writing a quest that requires the player to obtain a length of rope from anywhere else in the game. You want them to find any object that is of type "rope".

There isn't a GameObject subclass called Rope (or if there is, let's pretend that there isn't). However, it's easy to create a rope-like object by making an archetype file like so:

 
   
   
   
   
   
     
   
 
 
The Archetype above has chosen to use DynamicObject as its GameObject implementation class, a fairly generic class. The Archetype then adds properties to make the object look like a rope, weigh as much as a rope, have a short description that says "rope", and have the proper material for a rope. At this point, most people would say it's pretty much a rope.

However, how does your quest code know that this is a rope? What property, or set of properties, does it check? Java has an instanceof operator to tell you if an object is of a certain class. No such operation exists for archetypes, nor could it, really. They're just bundles of properties with a generic parent class. Your code could check the description to see if it matches "rope", but someone could easily have created a "robe" archetype and mistyped it, thereby allowing your players to solve your quest using a robe. Not good. Or you could check the appearance, but someone may have used a different picture called "string", and then you'd fail to recognize what might be a valid rope.

In a nutshell, you can't do effective strong typing using Archetypes - you can make guesses or use heuristics, but if you really want strong typing, you need to make a real GameObject subclass in Jython or Java. This is the reason that things like Coins have their own class - there are times when you need to be absolutely sure that an object is of the correct type, and in these cases, only a class will do.

Instantiating Archetypes

There are several ways to turn an archetype into an actual, usable game object at runtime. If you have a reference to the Archetype object, you can call its instantiate() method, which creates an object that inherits from the Archetype. The object's Java class will be whatever was specified in the Archetype's "class" property.

If, as is more common, you just have the name/path of the archetype, such as "terrain/water" (a system archetype) or "wiz/foobar/sword_of_coolness" (a wizard-defined archetype), you can call the instantiate() method of wyvern.lib.Kernel.

There are still other ways to create archetypes, but most of them are for rather obscure purposes, and you shouldn't worry about them too much if you stumble across them.

Are Archetypes Required?

Given that you can simply create a Jython class that extends any existing Java or Jython class, and in your subclass you can set any properties you like, why do you need to bother creating Archetypes?

The short answer is: you don't. Jython is a perfectly acceptable way to define your game objects. Archetypes are slightly more efficient, but Jython classes are far more flexible. Archetypes were designed for people who want to build game areas without doing any programming, and it's easy to create and manipulate them in the map editor, or in a text editor, with little or no programming experience. You can certainly use Jython for everything if you prefer.

Version:
1.0, Jan 25, 1998
Author:
Steve Yegge

Field Summary
 
Fields inherited from interface wyvern.lib.PropertyList
PROPERTY_PACKAGE
 
Method Summary
 java.lang.String getName()
          Returns the name of the archetype file, e.g.
 java.lang.String getPythonPath()
          Returns the "path" attribute of the Archetype
 GameObject instantiate()
          Creates an instance of this archetype.
 boolean isPythonArch()
          Returns true if this is a Jython archetype.
 java.lang.Class loadClass()
          Loads an Archetype's class.
 java.lang.String provideName()
          Returns a name for the archetype suitable for writing it to a map file.
 void setName(java.lang.String name)
          Sets the name of the archetype file.
 java.lang.String toString()
          Returns the archetype formatted as a property list, for debugging.
 java.lang.String toString(boolean inherit)
          Returns a string representation of this archetype.
 
Methods inherited from interface wyvern.lib.PropertyList
addProperty, addTransientProperty, adjustDoubleProperty, adjustIntProperty, adjustLongProperty, adjustTransientDoubleProperty, adjustTransientIntProperty, adjustTransientLongProperty, countLocalProperties, getDoubleProperty, getInheritedProperty, getIntProperty, getLocalProperties, getLocalProperty, getLongProperty, getParent, getPersistentDoubleProperty, getPersistentIntProperty, getPersistentLocalProperties, getPersistentLongProperty, getPersistentProperty, getProperties, getProperties, getPropertiesIncludingTransients, getPropertiesIncludingTransients, getProperty, getSerializableProperties, getSerializableProperty, getStringProperty, getTransientDoubleProperty, getTransientIntProperty, getTransientLongProperty, getTransientProperties, getTransientProperty, hasLocalProperty, hasPersistentProperty, hasProperty, hasTransientProperty, inheritProperty, isReadOnly, isRemoved, isTransientlyRemoved, printLocalProperties, printProperties, printProperties, printTransientProperties, removeProperty, removeTransientProperty, setDoubleProperty, setIntProperty, setLongProperty, setParent, setProperty, setReadOnly, setTransientDoubleProperty, setTransientIntProperty, setTransientLongProperty, setTransientProperty, transientlyRemoveProperty
 

Method Detail

instantiate

public GameObject instantiate()
                       throws java.lang.Exception
Creates an instance of this archetype. Looks for a "class" property to load and instantiate, and adds a pointer to this archetype on the new object.

Returns:
a GameObject that inherits from this archetype. The GameObject does not get copies of the archetype's properties; it inherits them via the archetype parent pointer.
Throws:
java.lang.Exception

loadClass

public java.lang.Class loadClass()
                          throws java.lang.Exception
Loads an Archetype's class. Don't call this method if the class is a python class - use the PythonInterpreter to instantiate python objects.

Returns:
the class specified in the "class" property, if found
Throws:
java.lang.Exception

toString

public java.lang.String toString()
Returns the archetype formatted as a property list, for debugging.

Returns:
the property list, not including inherited properties

toString

public java.lang.String toString(boolean inherit)
Returns a string representation of this archetype. Includes inherited properties.

Specified by:
toString in interface PropertyList
Parameters:
inherit - true to include inherited properties, false to include only ones in the local list.
Returns:
the formatted property list

getName

public java.lang.String getName()
Returns the name of the archetype file, e.g. "terrain/water".

Returns:
the local or relative path to the archetype file

setName

public void setName(java.lang.String name)
Sets the name of the archetype file. Should only be called by the MapLoader.

Parameters:
name - the local or relative path to the archetype file

provideName

public java.lang.String provideName()
Returns a name for the archetype suitable for writing it to a map file. (It's what goes in the "path" attribute). This will be one of several possibilities:

a) if name returned by getName() returns non-null, then:

b) the parent archetype's name, if there's a parent archetype c) the class to instantiate (b) and (c) are the possible options for an anonymous archetype.


isPythonArch

public boolean isPythonArch()
Returns true if this is a Jython archetype.

Returns:
true if it was defined as ...

getPythonPath

public java.lang.String getPythonPath()
Returns the "path" attribute of the Archetype

Returns:
the relative python path that the archetype inherits from, or null if it's not a jython archetype