Character Definitions - HoraceAndTheSpider/Bloodwych-68k GitHub Wiki

Character definitions and graphics renderer

This page describes how Bloodwych SPS 439 builds the humanoid characters numbered $00 to $55. A character is not stored as one complete picture. The game selects a head and a body definition, colours several component masks, and then assembles the correct artwork for the character's distance and facing.

The labels and binary positions below refer to SPS 439. Extracted filenames follow the Extracted Data File Types convention.

Rendering in plain English

For each visible character, the game:

  1. Uses the character number to read one entry from characters.bodies and one from characters.heads.
  2. Uses the selected body number to find four graphic bases and one of two component-layout families.
  3. Uses the viewing distance and facing direction to choose a source picture, mirror it when required, and find its screen position.
  4. Draws the legs, torso, two arms, and head separately at the four nearer graphic distances.
  5. Uses a precomposed distant character picture for the final two graphic distances.
  6. Replaces the four mask colours for each part using the corresponding group in characters.colours.

The multiple distances in BodyParts.gfx and HeadParts.gfx are separately stored Atari ST four-plane strips. They are not produced by scaling the nearest picture at run time.

Per-character selection and colours

There are 86 character types, from $00 through $55 inclusive.

Extracted file SPS 439 binary position Size Meaning
data/characters.bodies $A418 $56 One body-definition number for each character type.
data/characters.heads $A596 $56 One head-definition number for each character type. There are 18 known head definitions, numbered $00 to $11.
data/characters.colours $34E44 $6B8 Twenty palette selections for each character: five parts multiplied by four replacement colours.
gfx/HeadParts.gfx $354FC $3E70 The raw head pictures for all definitions, distances, and facing variants.
gfx/BodyParts.gfx $3936C $8640 Raw legs, torso, arms, and distant precomposed character pictures.

Each character's 20-byte colour record contains five consecutive groups of four palette indices:

head colours
leg colours
torso colours
arm colours
distant-composite colours

The distant picture therefore has its own four-colour selection. It is not recoloured by combining the nearer head and body groups.

Body definitions

Character_BodyDefinitions is extracted as data/characters-body-definitions.layout.

Source label SPS 439 binary position Size
Character_BodyDefinitions $A50A $8C

The table contains 14 records of ten bytes. Each record is five big-endian words:

Word Purpose
0 Component-layout selector. Zero chooses the standard layout; any non-zero value chooses the alternate layout.
1 Base offset of the body's legs in BodyParts.gfx.
2 Base offset of the torso.
3 Shared base offset of the arm pictures.
4 Base offset of the precomposed distant character pictures.

The character's body selection is masked with $0F, so the existing selection mechanism can address up to 16 records. Only 11 of the 14 supplied body definitions are selected by the SPS 439 character table. Adding records 14 and 15 is therefore structurally possible if space is provided. A third genuinely different layout family would require a code change because the current test treats word 0 as a Boolean choice: standard or alternate.

Near and middle-distance components

The standard and alternate component layouts are each 304 bytes:

Source label Extracted file SPS 439 binary position Size
Character_RenderLayout_Standard data/characters-standard-render.layout $18480 $130
Character_RenderLayout_Alternate data/characters-alternate-render.layout $185C0 $130

Each layout contains three regions:

  1. 160 position bytes: four component distances × four facings × five parts × signed X/Y pairs.
  2. Five height tables: twelve bytes per part, arranged as four distances × three source variants.
  3. Five source-offset tables: twelve big-endian words per part, with the same four-distance × three-variant arrangement.

The five part indexes are head, legs, torso, first arm, and second arm. The two arm entries share the body's arm graphic base but have independent positions, facing rules, and animation adjustments.

Why the render-table offsets are one resource

Character_RenderTableOffsets is a single 20-byte table extracted as data/characters-render-table-offsets.lookup at $A5EC.

It contains five interleaved pairs of big-endian words:

part 0 height-table offset, part 0 source-table offset
part 1 height-table offset, part 1 source-table offset
...
part 4 height-table offset, part 4 source-table offset

Both offsets are relative to the selected standard or alternate render-layout block. They are not two independent data resources and should not produce two overlapping INCBIN statements.

The second word is at Character_RenderTableOffsets+$02: an address within this same table, not a second independent block.

Facing, mirroring, and animation

Character_PartFacingVariants is extracted as data/characters-part-variants.lookup at $A600. Its 20 bytes are five parts × four facing directions.

Each entry selects a source variant. Bit 7 requests horizontal mirroring, while $FF suppresses that component. This allows the two side facings to share artwork without requiring another stored picture.

Animated arms use Character_ArmAnimationPositions, extracted as data/characters-arm-animation.positions at $A778. Its 72 bytes contain two 36-byte blocks, one for each layout family. Each block supplies:

  • four Y corrections selected by component distance;
  • 32 X corrections selected by four distances × two arms × four facings.

When an arm is animated, the renderer selects the animation source variant and applies these corrections. Side-facing animated arms also reverse their normal mirroring rule.

The two distant character slots

The final two graphic distances use precomposed character pictures instead of drawing five components. Each position table contains four signed X/Y pairs, one per facing.

Source label Extracted file SPS 439 binary position Size
Character_Distant4_Positions_Standard data/characters-standard-distant-4.positions $185B0 $08
Character_Distant5_Positions_Standard data/characters-standard-distant-5.positions $185B8 $08
Character_Distant4_Positions_Alternate data/characters-alternate-distant-4.positions $186F0 $08
Character_Distant5_Positions_Alternate data/characters-alternate-distant-5.positions $186F8 $08

The distant source block contains three directional variants. One side direction is mirrored to produce the fourth facing.

The distant picture dimensions and strides are immediate values in Draw_Character, rather than table data:

Layout Slot 4 Slot 5
Standard height 22, stride $B0 height 17, stride $88, group offset $210
Alternate height 21, stride $A8 height 16, stride $80, group offset $1F8

These dimensions are embedded in the drawing instructions. They are not additional entries in the body-definition table.

Shared data and source boundaries

Draw_CharacterComponent at original adrCd00A998 is the routine that draws an individual part. The component tables it reads are data; the routine itself is code.

Colours, head selection and body selection belong to individual character definitions. In contrast, the position tables belong to one of the two shared layout families. Several character types can therefore use the same positions while selecting different head, leg, torso and arm pictures.

Picture offsets and heights describe the boundaries of the stored graphics. Resizing a picture changes those boundaries as well as its pixels; the dependent offsets and dimensions must agree with the resulting source layout.

See also: