Armour Mechanics - HoraceAndTheSpider/Bloodwych-68k GitHub Wiki
Armour Mechanics
Armour protection is calculated from several champion fields and equipment objects. It is not a single value copied from the body-armour object. The SPS 439 combat routine first calculates an effective armour value, then uses that value when reducing physical damage.
The rules below describe the Amiga SPS 439 implementation. Object numbers are hexadecimal and refer to the SPS 439 object table.
Effective armour
Calculate_CharacterArmourLevel combines the following values:
- the champion's stored Armour Level at stats byte
$0B; - the currently worn spell at stats byte
$11; - body armour and shield objects in pocket bytes
$02and$03; - gloves at stats byte
$12; - the seven-entry shield lookup table.
The calculation can be written as follows. All values are unsigned bytes and the divisions in this page discard the remainder.
worn_spell_type = stats[$11] & $07
worn_spell_power = stats[$11] >> 3
if worn_spell_type == 0:
armour = min(stats[$0B], worn_spell_power)
else:
armour = 0
if body_armour != 0:
body_bonus = 3 + 2 * (body_armour - $1B)
armour = max(armour, body_bonus)
if gloves != 0:
armour += gloves - $2B
if shield is in $24-$2A:
armour += shield_bonus[shield - $24]
The zero worn-spell type is the Armour spell encoding. With no Armour spell active, its power is zero, so the first step contributes zero and the stored Armour Level is not used as an additional value after body armour is applied. An active non-Armour worn spell also makes the spell contribution zero.
The body-armour comparison uses max, not addition: the selected body armour
replaces a lower stored/spell armour value. Gloves and shields are then added
on top. The resulting value is the effective armour passed to the physical
attack routine.
Body armour
The valid body-armour objects are $1B-$23. Their protection is derived from
object number rather than from a separate body-armour table.
| Object | Name | Body contribution |
|---|---|---|
$1B |
Leather Armour | 3 |
$1C |
Chain Mail | 5 |
$1D |
Plate Mail | 7 |
$1E |
Mithril Chain | 9 |
$1F |
Mithril Plate | 11 |
$20 |
Adamant Chain | 13 |
$21 |
Adamant Plate | 15 |
$22 |
Crystal Chain | 17 |
$23 |
Crystal Plate | 19 |
The formula is 3 + 2 × (object - $1B). Consequently, higher-ranked body
armour does not stack with the champion's stored Armour Level or Armour spell;
it supplies the larger of those values at the body-armour step.
Gloves
Gloves are held in the champion stats record at byte $12. The five valid
glove objects add the following values:
| Object | Name | Armour contribution |
|---|---|---|
$2B |
Chaos Gloves | 0 |
$2C |
Battle Gloves | 1 |
$2D |
Mithril Gloves | 2 |
$2E |
Adamant Gloves | 3 |
$2F |
Crystal Gloves | 4 |
The contribution is object - $2B, so Chaos Gloves have no normal armour
bonus. They still have a separate weapon interaction: they enable the full
Ace of Swords combat record. See Fighting mechanics.
Shields
The shield object is stored in pocket byte $03. Objects $24-$2A are
indexed into Shield_ArmourBonuses:
| Object | Name | Armour contribution |
|---|---|---|
$24 |
Leather Shield | 1 |
$25 |
Buckler | 2 |
$26 |
Rune Shield | 4 |
$27 |
Large Shield | 3 |
$28 |
Moon Shield | 4 |
$29 |
Dragon Scale Shield | 5 |
$2A |
War Shield | 7 |
The extracted SPS 439 lookup is:
01 02 04 03 04 05 07 00
Only the first seven bytes are indexed by the combat routine. The final zero is retained because the extracted resource represents the complete original eight-byte source block; it is not an eighth shield bonus.
The equipment checks separately restrict large shields to the professions that
can use them. If those checks are bypassed, the armour calculation still
recognises object $27 as a shield and applies its table value. Rendering an
item and permitting the equipment combination are therefore separate rules.
Champion and extracted data layout
The standard SPS 439 champion block contains sixteen records of $20 bytes.
The fields relevant to armour are:
| Record field | Meaning |
|---|---|
$0B |
Stored Armour Level used as the initial Armour-spell fallback |
$11 |
Worn-spell byte: low three bits are the spell type, upper five bits are power |
$12 |
Worn gloves object |
Each champion pocket record contains $10 bytes. The relevant equipment
positions are:
| Pocket field | Meaning |
|---|---|
$02 |
Body armour object |
$03 |
Shield object |
For SPS 439, the extracted resources are:
| Resource | Binary file offset | Size | Record/layout |
|---|---|---|---|
data/champions.stats |
$E7A6 |
$200 |
16 × $20-byte champion records |
data/champions.pockets |
$E9A6 |
$100 |
16 × $10-byte pocket records |
data/Shield_ArmourBonuses.stats |
$5FF6 |
8 | Seven indexed shield values plus retained source byte |
Offsets above are file offsets in the SPS 439 executable, not Amiga runtime addresses. The resource names are those used by the ReSource extraction.
Armour and physical damage
Effective armour is not added to the defender's opposed combat score. It is
carried separately by Prepare_AttackAndDefenceScores and subtracted after a
physical attack has produced its hit-quality value.
Let A be effective armour and Q be the hit-quality value after the opposed
random rolls. The armour reduction is:
reduction = floor(A / 2)
if A is odd and (Q & $0F) >= $08:
reduction += 1
The odd-armour rule means that an odd point of armour is conditional rather than always effective. The low nibble of the hit-quality value determines whether that extra point is applied. Armour reduction occurs before the quality multiplier.
For the normal champion physical path, damage before armour and hit-quality multipliers is described in Fighting mechanics. After the armour reduction, the hit-quality ranges are:
Hit quality Q |
Damage multiplier |
|---|---|
$00-$09 |
×4 |
$0A-$18 |
×3 |
$19-$27 |
×2 |
$28-$40 |
×1 |
The routine caps the opposed result at $40. If armour reduces the damage to
zero or below, the attack records no damage and the quality multiplier is not
applied.
This ordering matters. For example, a raw damage value of 9 against effective armour 7 has an armour reduction of 3, or 4 when the odd-armour condition is met. The remaining damage is then multiplied according to hit quality; armour does not simply divide the final multiplied result.
Source labels and related tables
The relevant SPS 439 source labels are:
Calculate_CharacterArmourLevel— builds the effective armour value;Shield_ArmourBonuses— the seven-entry shield contribution lookup;Prepare_AttackAndDefenceScores— keeps effective armour separate from the opposed defender score;Resolve_PhysicalAttack— applies armour reduction and hit-quality damage multipliers;Weapon_CombatModifiers— the independent four-byte weapon table used to build raw physical damage and attack/defence bonuses.
The visible character status value is not the effective armour value itself.
The status routine displays 10 - effective_armour as a signed value, so a
high effective armour can appear as a negative displayed adjustment. This is
only a presentation convention; combat uses the positive effective armour
value described above.
Rendering data is separate
These extracted resources affect how worn character components are drawn, not the protection calculation:
| Resource | Binary file offset | Size | Purpose |
|---|---|---|---|
data/Character_WornArmour_RenderOverrides.lookup |
$A40E |
9 | Worn-armour rendering overrides |
data/characters-armour-material.palette |
$A81E |
4 | Armour-material palette selections |
Changing a rendering override or palette does not change effective armour. Likewise, changing an object's protection contribution does not by itself change its visible component unless the rendering data is also changed.