In _Civilization and its Discontents_, Sigmund Freud describes Man as a kind
of "cybernetic god" -- by ourselves we are weak, vulnerable, and impotent,
but with our machines we can move mountains, build or destroy worlds, and
make Roguelike games in our spare time. This is a vitally important
observation in Roguelikes, where the power of a character can be summed up
in two things: a) Their own statistics, and b) what they're carrying. A
mighty wizard with Raal's Tome of Destruction is a lot more powerful than
one without, as is a plevel 50 warrior with Ringil and Speed Boots a lot
more frightening than a plevel 50 warrior with chainmail and a whip.
And so it should be with monsters, and is in some (NetHack) games. That
gnome is easy bait -- until he fires up his lightsaber.
You should *strongly* consider allowing monsters both to carry and _use_
objects, and to drop them afterwards. For one, it provides a lot more
variety. Second, it adds realism, in that it makes creatures with *hands*
much more intimidating. In Roguelike World, a sabre-tooth tiger is more
dangerous than a small kobold because it is faster and stronger. In the
Real World (or at least the version that has small kobolds in it), our
kobold is the deadlier because he could carry *and use* something much
nastier than sabre-teeth. Third, it adds variety. Having hundreds of
monsters is cool. But if you let them hold an item (and a good item system
will have thousands of different items, by combining different traits
together, as in the "Whip of Freezing" and so on), then you have hundreds of
thousands of combinations. Let them hold multiple items, and pick new items
up, and the variety is astronomical -- and has a real impact on gameplay.
Now for some coding ideas. In my own game (not yet released), I have
decided that creatures should have the same ability to wear/wield/carry
items as the player -- unless it is biologically or mentally unable to (more
on this below). Why is it that in so many games the player is a walking
blacksmith's shop, but the creatures seem to have no material needs except
bags full of gold? Since I also leave open the ability to hold one item
inside another item, and even put creatures into items (like tigers into
cages), I find a *tree* structure to be most efficient.
Everyone learns (or should learn) all about making trees in their first
computer course, and all about the optimising of trees in their first theory
course, so I won't go too deep into the data structure (look on the Internet
if you need it). For this article, I am defining a tree as a collection of
objects such that each object has exactly one "parent" object, except for
one object which is the "root" of the tree. A parent can have any number of
children, including none. The resulting shape looks like a tree, hence the
name.
I like objects, so that's how I define my structures. The first object I
need is a Unit, which is my name for an "Item or Creature". So into Units
we put information that applies to both: weight, name, etc. Actually I
implement these not as data but as virtual functions along the lines of
getWeight() and getName() -- this latter method is more "OO", but I could
understand if you used variables instead for the sake of efficiency. I also
keep a small array of all the possible child nodes -- I use an array because
I keep an arbitrary limit of no more than 20 child nodes, and though a list
would be more efficient it's also complicated. I then subclass this into
Items and Creatures. You might think of subclassing items into Weapons,
Armor, and so on, but I didn't find it worth it. It *is* worth it to
subclass "Creature" into "Player", though. So you get an object definition
something like this:
OBJECT: Unit
{
# Array of child units
UnitPtr children[MAX_UNITS]
# Keep reference to the parent too -- this is technically unnecessary and
requires a bit more care in your
# tree-manipulation functions, but you'll thank me the first time you have a
unit and want to know what
# its parent is. If parent is NULL then the unit is on the map somewhere.
UnitPtr parent
# Some tree functions you should implement
detach() # Detach node from its parent
destroy() # Destroy this and all children
attach(UnitPtr newParent) # Attach to another node, detaching if necessary
replace(UnitPtr newUnit) # Put the new unit in this position, and delete
self
# Common unit functions
getWeight() # Object weight
getTotalWeight() # Weight of object and all its children
getName()
.
}
OBJECT: Creature EXTENDS Unit
{
move() # Move the creature
getHPs() # Get creature hit points
.
}
OBJECT: Item EXTENDS Unit
{
itemType # It's more OO to subclass items, but what the heck
damage # In the case of weapons
isWielded # Boolean, if true then the parent (a creature) is
wielding this. The value is
. # meaningless unless the parent is a creature
.
}
I won't get into all the cool things you can do with trees: how easy it is
to move nodes around, and recurse or iterate over them, and so on --
instead, I will recommend that you put some time into adding some good tree
manipulation functions, probably build right into the Unit class (but *not*
as virtual methods, as they shouldn't need to be overridden, and you really
want these to be efficient as you'll be using them a lot). The four
functions I stuck into the Unit object above should be a good start. Do
make sure if you have a limit on child nodes that methods like "attach" can
fail gracefully, because at some point something in your program is going to
try to exceed that limit (you could of course always test before attaching a
new child, but why bother when you can just put the test in the attach
routine itself?).
I will point out what I found most useful about trees in a roguelike game:
that you can deal with only the root node, and it will affect all the child
nodes. For example, let's say I drop a chest. That means detaching the
chest from my own inventory hierarchy (so it becomes the root node of its
own tree), and put it on the ground (the map, of course, can hold pointers
to Units -- that's how creatures and items are held on the map!). The cool
thing: all the child nodes go with it, so the items in the chest are moved
automatically, in constant time!
Now how do we return this to the question of monsters? In my trees, there
are clearly four kinds of relationships: an item can contain an item, an
item can contain a creature, a creature can contain an item, and a creature
can contain a creature. I interpret each of these differently. An item
containing an item I think of as physical containment -- like a sword in a
chest, a scroll in a bag, and so on (I suppose I could also see it as a
battery in a flashlight or a bullet in a gun, but there aren't such things
in my game). An item containing a creature refers to some kind of caging --
a bird in a birdcage or a ghost in a magic ghosttrap, etc. A creature
containing an item is obvious -- that's the creature's inventory! And a
creature containing a creature means the contained creature is swallowed (or
would; I don't actually use this anywhere in the game).
So what happens if a monster is killed? Simple: he simply transforms into
(is replaced with) a corpse, which is an item. Or more specifically, a
*container* item, like a chest or bag. See? All the things he is carrying,
by the definitions we're using, become items contained by the corpse. This
way we avoid the clutter you get in, say, Angband, where the last act of a
powerful unique is apparently to throw his belongings all over the room
(since you don't have stacks of items on the floor in Angband). Getting
items from the corpse is handled just like getting them from a treasure
chest (and can be quite as dangerous).
So now we've handled data structures, but how do we decide what monsters
actually carry? There are three relationships a monster can have with an
item, and for each of them I have a flag. First, is it possible for the
monster to carry it? This usually involves having hands, though I suppose
telekinesis works. Second, where applicable, is it possible for a monster
to use it? Helmets require appropriately-shaped heads, scrolls require the
ability to read, etc. Third, is there a chance that the monster will start
out with it?
I implement these first two as flags, and the third as a pair of numbers:
the average number of items the creature has (i.e. "from 0 to 6"), and the
dungeon level equivalent of the items (i.e. a kobold only gets the kind of
items you find on level 1). The items are generated randomly when the
monster is created, plus a few rules are applied to preserve sanity (no
creature carries more than one armor or more than two weapons; only unique
creatures can start out with artifacts, etc.) Et voila! I also keep a flag
to let some monsters carry only one item, and can't fight while carrying --
this is great for animals that can only carry things in their mouths.
Of course, mosters should be able to acquire objects, and perhaps steal them
as well (hello Green Glutton Ghosts or the Nymphs of Nethack). That is easy
enough to manage, and also lets monsters get items way out of their depth
("The kobold hits! Snicker-snack!"). Again, sanity should be applied --
monsters should have no better idea of what an item is than the player would
(depending on how you handle identification), they should not be able to
touch items inimical to themselves (evil monsters should not touch holy
weapons, goblins are not likely to go around swinging Orcrist), and so on.
Care must be taken that game-balance is not hurt. The biggest danger is
when small creatures have powerful items. It's very cool when our small
kobold has a big weapon, but if you can stand a few meters away and magic
missile him to death, then you have a free major item. And in most
roguelikes a really good artifact would increase the power of a low-level
character many times over. Luckily, a well-balanced and realistic monsters
definition file will handle most of that. Normally the little guys won't
get the big weapons, and if they occasionally do that's just interesting,
and good (or disasterous) luck for the player -- much like Wormtongue
throwing the Palantir at Gandalf without knowing what it was. The other
thing is that the tough guys are going to be a *lot* tougher in this system
(which by my book is a good thing). Imagine an Angband Nazgul if he was
also guaranteed to be carrying a few "good" or "excellent" items on him.
The rest you can think of yourself: like destroying the other creature's
items and so on. Heck, if a fire-breathing dragon can burn up all my
scrolls, I want to be able to destroy his scrolls with a wand of fire. I
would also point out that the more things a monster carries, the more fun it
is to play a thief. On the flip side, you could make a really good-aligned
character like a paladin very strong, but unable on moral grounds to remove
items from corpses.
|