#20: Hobgoblins, Part Two

February 8, 2001  "Lack of consistency is the hobgoblin of online games." That's the conclusion that I came to last week, and you can put it in your quotes dictionary right next to Emerson.

Though I have some other things that I'm dying to write about (including dreams, plots, change, self-sacrifice, identity, and redemption), I'm going to be good and follow my mantra. I'm going to talk about consistency again this week, consistently staying to the course I laid out. We'll get to that other stuff in seven days, I promise.

So, consistency. If you haven't already read my last article go do so now, to get the ground work on this topic. As a quick reminder, last week I talked about the weird implementation of verbs in online prose and how it can lead to inconsistency. There's another place where consistency really matters in online prose games, and that's in inheritance. This week I'm going to explain exactly what inheritance is, how it works, and how we can be inconsistent in its use. I hope the whole exercise will be eye opening for potential StoryBuilders and interesting for everyone else, because I'm going to expose a little bit of the guts of our system.

If you're bored by the technical details, go ahead and skip to my general thoughts. And then, next week I'll be back to substantially less techie topics.

The Problem with Definitions

So what is inheritance? It's a creation method that's related to objects. Which I'll need to take a step back and explain.

(For the tech heads out there, let me say that the objects I'm referring to here aren't quite the same thing as the objects you'd find in OOP.)

In the Skotos StoryBuilder Server every discrete thing is an object. That's to say each thing is an individual unit that's defined in certain, common terms and can be interacted with by certain, common methods.

Everything you see in Castle Marrach is an object. A sword, a pin, a dress  all objects. A cat, a rat, a shadow  all objects. The Dining Hall, the Grand Hall, your Guest Room  all objects. Sir Launfal, the Queen, you  all objects.

Beyond these physical objects, we have a lot of intangible objects too. Social verbs like hug, kiss, and cry are objects. So are adverbs such as slyly, happily, and merrily. So are the help files and the tip files and even the error messages for action verbs.

Each object is made up of certain individual attributes. A sword, for example, has a look description and a brief description and a weight and a length. It has details too, like a guard and a hilt and a pommel.

Making everything in the world into an object lets us view things in a much more abstract way. We can now look at two objects, say Sir Launfal and Sir Boreas, and see that they actually have a lot of attributes in common. They both have feet and legs and knees, for example. And, the descriptions of those particular details might be identical for these two characters.

When considering how much similar objects have in common, we begin to realize that its pretty silly to rewrite all of those common details every time you create a new object (in this case, every time we create a new person). So, we try and figure out a way to link together similar objects.

And that is where inheritance comes in.

With inheritance, we would create a parent object that's used by all "Men" (maybe; there's variations as we'll see below). We'd put all of the common information in that parent object. Then, we'd create children objects which inherit from that object. In our above example we'd create Launfal and Boreas as children of our "Men" object. They inherit all of the common information from the parent object. If "Man" has "ordinary" knees, then both Boreas and Launfal have "ordinary" knees. A little restrictive it seems. What is Launfal or Boreas should have "unordinary" knees? There's more. Each child object can "overload" data it inherits from its parent. This means the child can replace some specific information with its own local data. Say Boreas had "hairy" knees. We'd put the "hairy knees" attribute in Boreas, the child object, and that would overload the "ordinary knees" in the "Man" object.

Easy. We get all of the standard information from the parent, then we change any information we want in the child.

Much of what we've talked about so far is called "data inheritance". This is when you inherit some attribute or other information from a parent. In our games, you might inherit a description or a detail.

There's another type of inheritance too: "method inheritance". This is when you inherit how to do something. In a prose game like ours, an object could inherit how to do something via method inheritance (a person might inherit the "walk" and "talk" methods; a frying pan might inherit the "cook" method) or how to react to something via method inheritance (a log could inherit the how-to-react-to-burning method; a trombone could inherit the how-to-react-to-playing method).

Whew. Summary:

Two types of inheritance. Data and Method.

Via inheritance children objects can get data or methods from parent objects.

Data inheritance means an object inherits specific information, such as a description, a weight, or some other attribute.

Method inheritances means an object inherits how to do something, such as a verb or reaction to external stimuli.

So, how can inheritance cause inconsistency?

The Problem with Inheritance

Before I try and answer this question, I want to talk about how inheritance has been done in MUDs. The problems will quickly become obvious.

Traditionally there have been two inheritance methods in MUDs: none and chaotic. I'll briefly run through each of these, then talk about how we're doing it at Skotos and what challenges we still face.

The oldest MUD, including MUD (1) and AberMUD, didn't do inheritance at all. Each object was totally separate. If you wanted to make two similar objects you'd do it by copying the attributes and methods from a similar object and changing them ... or more likely you'd just ignore older objects all together and just create what made sense to you.

This way of doing things provided for zero consistency. Players would have no guarantees that similar items would look or work the same. You might be able to cook with frying pans but not pots. Likewise, since the correlation between items was so poor, you had no guarantee that similar items would be related in the correction proportions. Daggers might be more damaging than swords (And, in fact, when I used to play AberMUD this was a noticeable issue.).

C++ and OOP started becoming popular among programmers in the 1980s and they brought with them the whole idea of objects and inheritance. Thus later MUDs, starting with LPMUD, started to make good use of inheritance. In fact, they dove headfirst into inheritance without looking back. You could build trees of objects, with each object inheriting appropriate methods and attributes from its parents.

As you can, huge trees would developed, and they'd offer a lot of very useful correlation. It makes sense that Ham and Bacon are very closely related and that Ham and Hamburger are fairly closely related and that Hamburger and Cereal have some features in common. That's all represented by this tree and thus by the methods and attributes inherited.

But, unfortunately, the structure of the tree is totally arbitrary. We gain some consistency because similar objects will usually have similar attributes and methods, but we don't resolve the issue totally, because similar objects might actually end up far apart on our inheritance tree  just by chance or by people thinking about things in different ways.

In my example above, Weapons is a class that describes what its children do (hurt people) and Smithery is a class that describes what its children are made of (metal). The classes were probably created by different people with different ideas of how the world works ... and we ended up with a situation where swords could be found in two locations. Because they're far apart in the inheritance tree, a longsword and a broadsword may actually be very different items. And, they may work in very different ways. The inheritance of both data and methods begin to fall apart as our inheritance tree increases in size.

This isn't just a terrible example that I'm demonstrating. This always happens in inheritance trees of objects, particularly when you have a bunch of designers all working together on the same tree. In a real inheritance tree for a real game you might end up with weapons in a half-dozen places, with most people not knowing where most of the weapons are. Thus, not only do you end up with massive inconsistency, but you also end up with lots of redundant work.

In Skotos games, we've done our best to start resolving the issue of inconsistent inheritance while still maintaining the power of the concept.

Our first attempt to fix the consistency problems with inheritance isn't particularly inventive. We did two things:

We restricted data inheritance to one level.

We largely got rid of method inheritance. We defined huge classes of objects (e.g., all physical objects, all help files, etc.) and determined that all objects in that class would use the same methods.

This resolves several problems.

First, it allows us to use the global verbs that I mentioned last week. Methods are global (to a very large class of objects) and thus verbs for interacting with objects are global. Even better, all objects will react to all stimuli. You could use a teapot as a weapon (though an ineffective one). You could try and burn your dirk (unlikely) or eat your longsword (ouch!).

Restricting data inheritance to one level resolved much of the problem of inconsistent trees  because those inconsistencies usually happen when you get a few levels into a tree. However, it also creates inconsistencies because we have to constantly remake items. Sure, our longsword and broadsword will be guaranteed similar because they both descend from Sword, and sure all of our weapons will have the same methods for reacting to combat, but our Broadsword and Dirk aren't guaranteed to be consistent in detail because they don't have a common parent.

Let me offer an in-game example. All male characters have the same parent that they inherit from. It's called the UrMale ("Ur" is a word meaning generic; it's kind of like a platonic ideal). Likewise, all the female characters have the same parent that they inherit from. It's (cleverly) called UrFemale. All characters of both sexes can do the same things, because verbs are global, and they can all react to the same things, because methods are global.

But there's no link between the attributes and details of UrMale and UrFemale.

Just because a man has a waist doesn't mean a woman will have a waist (or an arm, or a head, or an eye.).

Oh, we're very careful to keep the UrMale and the UrFemale synced, but there's no system that enforces it. And I know that we've already gotten sloppy with some of our others parallel Ur objects, such as the UrOutside and UrInside objects that we use as parent objects for some of our rooms in Marrach. (Want to know why you can almost always find the "center" or a room inside or why you can almost always interact with the "wind" outside? It's because they're built into Ur rooms.) These two Ur objects should be very similar because they both represent rooms ... but again there's no guarantee that they'll stay synced.

To better resolve some of these issues we're in the process of expanding our data inheritance system into two-dimensional inheritance, or property-based inheritance. The idea is that all inheritance is only one-level deep, as in the diagram above, but that we inherit the basic form of the object from an Ur object "above" and that we inherit certain properties of the object  like color, substance, and quality  from attribute descriptions "to the left". (In a certain sense, an object can have lots of different parents that it inherits from, each offering attributes of very specific types).

It's a little more complicated then the one-dimensional inheritance tree, but it allows for some more complex possibilities.

So, looking at our earlier problems:

We have no problems with methods inheritance because we make those method global.

We can maintain a high level of data consistency by carefully inheriting the shape and important attributes of an object.

By keeping inheritance to one-level we avoid complex structures that hurt consistency.

But we still have some problems with maintaining relationships between our objects. There's no guarantee that a longsword will be better than a dirk.

So again I have to offer the same advice I did to StoryBuilders last week: Be aware of consistency problems (regarding inheritance) and try and keep your inheritance clean and consistent.

And that is the end of my delving into highly technical issues in order to make a point ... for now at least.

The Problems with StoryBuilding

Over the last two weeks I've investigated two systems that interested me  verbs and inheritance. In each case the systems highlighted consistency problems. In truth there can be consistency problems in anything you do with online game design, so it's a problem that you have to be constantly aware of.

Here's a few more places where inconsistency can hamper your online games:

Room descriptions. Is everything written in the same voice? Is the level of description the same for all briefs / looks / examines?

Language. Is your use of language the same throughout or do armor and gray mix with armour and grey?

Danger level. Is similar warning always given for similar danger? Or, might an ancient red dragon be a pussycat in part of your world and a deadly opponent in another?

Reward level. Within reason, does similar danger usually result in similar reward? Or, can killing a cow give you 100 gold while killing that ancient red dragon (the mean one) only gives you a few coppers?

StoryTelling. Do different StoryTellers have the same criteria for doing things? Do some StoryTellers give out tons of help to players while others ask them to get along on their own?

The list goes on. Some may even be worthy of future columns on their own.

Just be aware of the basic maxim which I already suggested last week: Consistency matters.

See you in 7 when I'll tell you about my second dream of Castle Marrach ... and what it got me thinking about.

8/15/01. I've since learned that the original MUD did do inheritance. Richard Bartle says, "It did have a very limited form [of inheritance], which happens to coincide exactly with the Skotos Mark 1 Data Inheritance model, ie. inheriting data at one level deep. I could (and did) define a class such as GOBLIN and then have GOBLIN1 through GOBLIN10 as instantiations of that class." I'll still stand by my "Early MUD Inheritance" diagram as an example of the simplest form of (non)inheritance, in general... and it matches my memory of messing around with AberMUD in the late 1980s.  SA