Anatomy

Overview

Some races look very different from other races, and this must be modelled somehow.  Otherwise we'll run into problems when determining if a snake could wear pants, or when determining where my arrow hits the ten-armed two-headed swamp mutant, and what effect it has.

For this purpose there is class called Anatomy.  This contains all the information about how a creature is built up, anatomically.  It is based on the container hierarchy (as usual) where each body part "contains" other body parts.

The goal is to use this as a basis for clothing, combat, and damage handling in White Orb.

Classes involved

 

Anatomy

Each Creature has an Anatomy.  The Anatomy object contains all information about the anatomical structure of the creature, such as what limbs it has and how they relate to each other.  An Anatomy consists of a number of BodyParts, and also maintains an internal damage state.  It has these methods: The size is, well, the size of the body.  I haven't decided which "scale" to use for these values, but it doesn't really matter as long as it's reasonably consistent.  The rule is that the size must be equal to the total size of all BodyParts included in the Anatomy.  Example: If Leg consists of Thigh (size = 20), Knee (size = 4), Shin (size = 14), and Foot (size = 10) then the size of the Leg must be 48.

The getRandomBodyPart method is used to provide a random body part with at least the given size.  The size argument is to avoid a catapult stone hitting someone's left eye and dumb things like that.  If the minimum size is larger than the Anatomy itself then the Anatomy itself is returned (so a catapult stone CAN hit a mosquito...).  Later on we can add functionality for aiming for certain body parts, etc, but for now I want it simple.

getHolderLimbs provides a quick way of accessing all BodyParts that can hold things.  For a Humanoid this will return a set of two Hands.  For a GiantOctopusAnatomy it might return a set of ten Tentacles...

The getProtection method is used to find out how resistant this body is to damage, usually based on the armour and clothing that it currently worn.  If total is false then only the protection of this specific anatomy is included.  If total is true then all protection of other BodyParts that are involved is included as well.  Let's say I am wearing some kind of elbow plate, and then a heavy coat on top of that.  elbow.getProtection(false) will return the protection provided by the elbow plate only, while elbow.getProtection(true) will include the heavy coat, since it protects the elbow indirectly.

BodyPart

The Anatomy is made up of body parts, which in turn extend Anatomy.  So an Anatomy is in fact made up of Anatomies.  The difference between BodyPart and Anatomy is that BodyParts can wear things.  A BodyPart will keep track of what items it is wearing.  It provides the following methods: Typical subclasses of BodyPart will be Leg, Elbow, Finger, Nose, etc (depending on how detailed we want to get).

HolderLimb

This is a specific type of BodyPart that can hold things. Typical subclasses of HolderLimb will be Hand, Tentacle, Tail... whatever limbs might be able to hold things.

Holdable

This is an interface for all items that can be held.  It will probably be implemented by Thing and Creature.  Holdable provides the following methods: getHoldingLimbs will return an enumeration of all HolderLimbs that are currently holding this item.  hold will put this item in the given holder limbs.  You don't have to specify exactly which limbs should hold it - if you send null, the Holdable will find limbs on it's own.  If it fails it will throw an ItemHolderException (for example if you try to pick up a sword and your hands are full).

The location of a Holdable will always be equal to the owner of the body parts it is being held by.

Wearable

Wearable is an interface for all items that can be worn.  All items that can be worn can also be held (you have to hold it first before you can wear it) so Wearable extends Holdable.  It adds the following methods: These methods correspond to the Holdable methods.  getProtection will return a Protection object that describes how this item protects against different forms of attacks.  Most Wearables will provide some sort of Protection, but some may just return null.

If you don't know or care exactly how a Wearable is supposed to be worn, just call wear(null).  The Wearable will automatically find a nice place to be worn.  A helmet would place itself on the head (if there is a head and the head isn't occupied...), a ring would place itself on one of the fingers.  Etc.

This is funny.  It means a two-headed giant can actually wear two helmets :o)

Anatomy structure example

Here is an example of an anatomical container hierarchy for a typical humanoid.  It is not complete, as you can see, it's just a general example of how it may look.

 

What about the container hierarchy?

Anatomy is a subclass of Physical and therefore part of the container hierarchy.  That means the subparts of an Anatomy are container children, etc.  The holding/wearing relations, however, are not part of the container hierarchy, ie the helmet worn on the head is not a child of the head.  Why not?  Because the BodyPart--Wearable relationship is many-to-many.  One body part can wear many things, and one Wearable can cover many body parts (a sleeveless robe would cover shoulders, thorax, thights, and knees).  It doesn't fit in the container hierarchy.

This means that if Fred is wearing a ring, the ring will be a child of Fred no matter where he is wearing it.  It will not be child of his finger.  The same goes for stuff he is holding.

Limiting where things can be worn

A helmet can be held in any hand, but cannot be worn on the arm.  How is stuff like this enforced?

When helmet.hold is called the helmet will look at the holdingLimbs parameter.  If it is null, the helmet will automatically search through the HolderLimsb (using anatomy.getHolderLimbs()) and place itself in whatever none-occupied hands, tentacles or other HolderLimbs that it can find.  If the object is large and must be held by two hands (like a barrel) then it will look for two empy HolderLimbs, etc.

When helmet.wear is called the helmet will look at the coveredBodyParts parameter.  If it specifies a head, then it will be worn on that head.  If it specifies an arm an ItemHolderException will be generated saying that "NO, bozo, you can't wear the helmet on your &%#¤ ARM!  Airhead!".  If it doesn't specify anything, the helmet will look through the Anatomy and try to find an unoccupied head.  If none are found, an ItemHolderException will be generated.

Nested Damage

Let's say my Arm receives 5 damage and my Hand receives 2 damage.  The hand is part of the arm, so what does this mean?

Well the Arm could be implemented in two ways.  Either it keep track of it's own damage, or it actual divides up the damage among it's subparts (elbow, upper arm, hand, etc).  When you ask the arm how much damage it has, it will then either simple report it's own damage or sum up the damage of it's children.

What about the hand?  Well the hand received 2 damage.  If I ask the hand afterwards how much damage it has, it will either return 2 (if the arm didn't spread out the damage) or 2 + something (if the arm spread out the damage among it's children).

The second way may seem cooler, but it may be quite slow.  Imagine if a massive fireball hits me and does 40 damage to my actual Anatomy (ie the WHOLE body).  This would cause a recursive behaviour downwards until finally only my BodyPart "leaf nodes" will be actually damaged.  So instead of my Anatomy registering 40 points of damage, it will give 1 damage to each of my fingers, 2 damage to my elbow, 1 damage to my nose, etc, etc, etc.  So it may actually be better to simply register 40 damage in one go.

Another approach is to, when asking the hand how damaged it is, have the hand actually include the damage of it's parent.  So the hand reasons "well I have 2 damage, but my parent the arm has 5 damage and 20% of that would apply to me, so my total damage is 3".  So even though it internally contains 2 points of damage, it will report 3 points of damage when asked.

I don't know which method is best, but it doesn't really matter since it is the internal matter of the BodyPart classes and won't affect any other classes.

Is this too complex?

Nah, I think it's fine.  The complexity depends on how advanced anatomical structures we define, and in the simplest case we can always use a SimpleAnatomy for all races, which consists of nothing at all - it is just a single body.  This means you can't distinguish between where something is worn, and where damage is done, etc.  It will be the good ol' D&D style with a single AC and HP for the whole body - when you wear a helmet, your AC goes up... :o)

So we can use this design to make both very simple and very complex things.


Henrik Kniberg

Last updated: