Armor and damage
How armor reduces the damage of a hit, how each body part's armor is summed, how armor weight slows you down, how equipment adds stealth, and which items drop as loot, at full precision for game v1.4.8. Content scopes: base (SandBoxCore, SandBox, StoryMode) and naval (base + NavalDLC). How items are scored and ranked from these formulas is on Ratings and results.
NavalDLC delegates the strike magnitude, stealth and battle reward models; it replaces CalculateAdjustedArmorForBlow only to add Mariner perk penetration, which is not modelled. See NavalDLC. The numbers in the examples and tables are computed by the Python model in src/bannerlord/equipment/.
At a glance
| What | Game code | Rule |
|---|---|---|
| Damage after armor | SandboxStrikeMagnitudeModel.ComputeRawDamage |
magnitude * 50 / (50 + armor), then a per-type share b skips the k*armor subtraction and the rest loses it, down to 0 |
| Body-part armor | Agent.GetBaseArmorEffectivenessForBodyPart, Equipment.Get*ArmorSum |
head, body, arm and leg armor each summed over equipment slots 5..9 |
| Armor weight | Equipment.GetTotalWeightOfArmor(isHuman) |
plain sum of item weights; cost per kg equal in every armor slot |
| Stealth | SandboxAgentStatCalculateModel.GetEquipmentStealthBonus |
plain sum of stealth_factor over head, cape, body, gloves, legs |
| Loot | BattleRewardModel.GetLootedItemFromTroop |
a random element of the casualty's BattleEquipments |
Damage after armor
SandboxStrikeMagnitudeModel.ComputeRawDamage; NavalStrikeMagnitudeModel delegates to it.
d = magnitude * 50 / (50 + armor)
raw = b*d + (1 - b) * max(0, d - k*armor)
magnitude: the strength of the hit.armor: the armor of the body part that is hit, from Body parts and armor sums.d: the magnitude after the50 / (50 + armor)reduction.b: the share ofdthat gets through regardless ofk*armor.k: the armor slope; the(1 - b)share applies tomax(0, d - k*armor), not tod.raw: the damage that gets through.
| Type | b | k |
|---|---|---|
| cut | 0.10 | 0.50 |
| pierce | 0.25 | 0.33 |
| blunt | 0.60 | 0.20 |
NavalDLC replaces CalculateAdjustedArmorForBlow only to add Mariner perk penetration; not modelled.
Damage that gets through armor from a hit of 80.
| Armor | Cut | Pierce | Blunt |
|---|---|---|---|
| 0 | 80.0 | 80.0 | 80.0 |
| 10 | 62.2 | 64.2 | 65.9 |
| 20 | 48.1 | 52.2 | 55.5 |
| 40 | 26.4 | 34.5 | 41.2 |
| 60 | 9.4 | 21.5 | 31.6 |
| 80 | 3.1 | 11.0 | 24.4 |
Line chart of the share of an 80-strength hit that gets through, for armor 0 to 80 on the hit body part. Cut, pierce, blunt and their average all start at 100%. At armor 80, blunt lets 30% through, pierce 14%, cut 4% and the average 16%. Once armor is above about 68, the cut line falls only slowly from about 4%, because d - 0.50·armor drops below 0 and only 0.10·d gets through.
The kink in the cut line is the max(0, d - k*armor) term. For a hit of 80, d = 4000 / (50 + armor); above about 68 armor, d falls below 0.50*armor, the term is 0, and only b*d = 0.10*d gets through.
Body parts and armor sums
Agent.GetBaseArmorEffectivenessForBodyPart, Equipment.Get*ArmorSum. Head, body, arm and leg armor are each summed over equipment slots 5..9 (head, body, leg, gloves, cape).
head, neck -> head armor sum
chest, abdomen, shoulders L/R -> body armor sum
arms L/R -> arm armor sum
legs -> leg armor sum
horse (any part) -> harness body armor
Example: heavy kit, body hit by an 80 cut
The kits below are the best item per slot in each weight third; the second table gives each kit's armor sums and the damage of a hit of 80 on each part. The last table, expected damage, is defined on Ratings and results.
Best kit per weight third (naval items, battle mode, all cultures, ranked by damage saved).
| Slot | Light | Medium | Heavy |
|---|---|---|---|
| Head | Berserker Helmet | Heavy Nasalhelm over Padding | Closed Huscarl Helmet |
| Body | Woodland Garments | Heavy Lamellar Vest | Heavy Scale Armor over Mail Hauberk |
| Hands | Fian Bracers | Bronze Bracers | Reinforced Northern Mail Mittens |
| Legs | Folded Leather Boots | Reinforced Suede Boots | Scaled Boots |
| Cape | Scale Shoulderguards | Northmen Raider Heavy Fur Cape | Berserker Cloak |
| Weight (kg) | 6.4 | 15.9 | 33.9 |
Armor per body part and damage that gets through from a hit of 80.
| Kit | Part | Armor | Cut | Pierce | Blunt |
|---|---|---|---|---|---|
| Light | Head | 42 | 24.6 | 33.1 | 40.1 |
| Light | Torso | 30 | 36.5 | 42.6 | 47.6 |
| Light | Arms | 30 | 36.5 | 42.6 | 47.6 |
| Light | Legs | 15 | 54.8 | 57.8 | 60.3 |
| Medium | Head | 48 | 19.2 | 28.9 | 37.0 |
| Medium | Torso | 54 | 14.2 | 25.1 | 34.1 |
| Medium | Arms | 34 | 32.3 | 39.2 | 44.9 |
| Medium | Legs | 38 | 28.4 | 36.0 | 42.4 |
| Heavy | Head | 55 | 13.3 | 24.5 | 33.7 |
| Heavy | Torso | 77 | 3.1 | 12.4 | 25.3 |
| Heavy | Arms | 49 | 18.4 | 28.3 | 36.5 |
| Heavy | Legs | 46 | 21.0 | 30.3 | 38.0 |
Expected damage of a hit of 80, averaged over cut, pierce and blunt; hits land head 15%, torso 55%, arms 15%, legs 15%.
| Kit | Expected damage |
|---|---|
| Naked | 80.0 |
| Light | 43.1 |
| Medium | 28.9 |
| Heavy | 19.7 |
A cut of magnitude 80 hits the chest of a character in the heavy kit. Chest maps to the body armor sum, the Torso row: armor = 77. Cut has b = 0.10, k = 0.50.
d = magnitude * 50 / (50 + armor) = 80 * 50 / (50 + 77) = 4000 / 127 = 31.496.d - k*armor = 31.496 - 0.50 * 77 = 31.496 - 38.5 = -7.004, somax(0, d - k*armor) = 0.raw = b*d + (1 - b) * 0 = 0.10 * 31.496 = 3.1496, shown as 3.1 in the Heavy Torso Cut cell.
The heavy torso is past the cut kink: only the b*d share gets through.
Armor weight and movement
Equipment.GetTotalWeightOfArmor(isHuman) = plain sum of item weights over slots 5..9 (human) or slot 11 only (horse harness). Cost per kg is equal in every armor slot.
armor_eff = max(0, armor_weight * (1 + FormFittingArmor.PrimaryBonus)) perk held, else factor 1
total = armor_eff + weapons_weight
armor_weight:Equipment.GetTotalWeightOfArmor(isHuman)of the agent's equipment, as above.FormFittingArmor.PrimaryBonus: the primary bonus of the Athletics perk Form Fitting Armor; added to the factor 1 only when the character holds the perk (CharacterObject.GetPerkValue).armor_eff: the effective armor encumbrance, the return value ofGetEffectiveArmorEncumbrance.weapons_weight: sum fromMissionEquipment.GetTotalWeightOfWeapons()on the agent's equipment.total: armor and weapon weight together.
SandboxAgentStatCalculateModel.GetEffectiveArmorEncumbrance, UpdateHumanStats:
penalty = ExplainedNumber(0.2, min 0, + AthleticsWeightFactor skill bonus) * total / monster_weight
MaxSpeedMultiplier = env_factor * clamp(0.7 + AthleticsSpeedFactor bonus - penalty, 0, 0.7 + AthleticsSpeedFactor bonus at skill 300)
CombatMaxSpeedMultiplier = min(1, Lerp(param6, param5, min(total / monster_weight, 1)))
total:armor_eff + weapons_weight, from the block above.monster_weight:Agent.Monster.Weight, the weight of the agent'sMonster.ExplainedNumber(0.2, min 0, ...): starts at 0.2, limited to at least 0.AthleticsWeightFactor skill bonus: theDefaultSkillEffects.AthleticsWeightFactorbonus added bySkillHelper.AddSkillBonusForSkillLevelat the agent's effective Athletics skill (GetEffectiveSkill(Athletics)).penalty: the weight penalty subtracted from the speed multiplier.AthleticsSpeedFactor bonus: theDefaultSkillEffects.AthleticsSpeedFactorbonus added the same way to a base of 0.7, at the agent's effective Athletics skill;at skill 300is the same bonus at skill level 300, which sets the upper clamp.env_factor: input computed byAgentStatCalculateModel.GetEnvironmentSpeedFactor.Lerp(param6, param5, x):MBMath.Lerpfromparam6atx = 0toparam5atx = 1, withx = min(total / monster_weight, 1); the call also passes1e-05as its fourth argument.
param5, param6 = ManagedParameters indices 5 and 6. AgentStatCalculateModel holds the base-class hooks.
Stealth
SandboxAgentStatCalculateModel.GetEquipmentStealthBonus = plain sum of stealth_factor over head, cape, body, gloves, legs; NavalAgentStatCalculateModel delegates. The per-slot constants passed by the caller (head 25, cape 15, body 30, gloves 10, legs 20) are unused by the callee; they equal the maximum stealth_factor per slot in the data.
What drops as loot
Loot source: MapEvent.LootDefeatedPartyCasualties → LootCasualtyCharacter → BattleRewardModel.GetLootedItemFromTroop, a random element of the casualty's BattleEquipments; died and wounded rosters, no hero filter. NavalDLCBattleRewardModel delegates.
Which items count as obtainable (shop, loot, dropped) is on Ratings and results.
NavalDLC
| Model | NavalDLC |
|---|---|
SandboxStrikeMagnitudeModel |
NavalStrikeMagnitudeModel delegates; replaces CalculateAdjustedArmorForBlow only to add Mariner perk penetration, not modelled |
SandboxAgentStatCalculateModel (stealth) |
NavalAgentStatCalculateModel delegates |
BattleRewardModel |
NavalDLCBattleRewardModel delegates |
Game code
IL for every method on this page, decoded from game v1.4.8 with the steps in How the findings were reversed:
- SandboxStrikeMagnitudeModel.il:
ComputeRawDamage. - NavalStrikeMagnitudeModel.il: delegation,
CalculateAdjustedArmorForBlow. - Agent.il:
GetBaseArmorEffectivenessForBodyPart. - Equipment.il:
Get*ArmorSum,GetTotalWeightOfArmor. - SandboxAgentStatCalculateModel.il:
GetEffectiveArmorEncumbrance,UpdateHumanStats,GetEquipmentStealthBonus. - AgentStatCalculateModel.il: base-class hooks.
- NavalAgentStatCalculateModel.il: stealth delegation.
- MapEvent.il:
LootDefeatedPartyCasualties,LootCasualtyCharacter. - DefaultBattleRewardModel.il:
GetLootedItemFromTroop. - NavalDLCBattleRewardModel.il: loot delegation.
Changelog
- v1.4.8 (2026-11-11): Moved from equipment ratings page; facts unchanged.