ArmorDefenseCalculator

Centralized, read-only defense reader for any ItemStack (elite or vanilla).

This class is one half of the elite→player damage formula. It handles the gear adjustment layer — determining how much a player's equipped armor and protection enchantments reduce incoming damage from elite mobs. The other half (skill adjustment) lives in com.magmaguy.elitemobs.api.PlayerDamagedByEliteMobEvent.

Design Goals

  1. Unified item handling — one code path for both elite and vanilla items, eliminating the old split where vanilla armor was ignored entirely.
  2. Damage-type awareness — Projectile, Blast, and Fire Protection enchantments now actually contribute to defense against their respective damage types, rather than being flat subtraction or ignored.
  3. No data mutation — this class only reads item data through existing APIs (EliteItemManager, ItemTagger). It never writes to items or modifies player state.
  4. Smooth progression curve — the two-part gear reduction ensures gear always matters (no dead zones) while preventing over-geared players from becoming completely invulnerable.

How This Fits Into the Damage Formula

The full elite→player damage formula is:
finalDamage = baseDamage × skillAdjustment × gearAdjustment × otherMultipliers

where:
  baseDamage      = playerMaxHP / 5.0
  skillAdjustment = 2^((mobLevel - armorSkillLevel) / 7.5)   [from LevelScaling]
  gearAdjustment  = 2.0 × (1 - gearReduction)               [from THIS class]

This class computes the gearAdjustment multiplier. It converts the player's equipped armor and enchantments into a single "gear score", compares that to the attacking mob's level, and outputs a multiplier:

  • 2.0 — naked player, gear provides zero protection (0% reduction)
  • 1.0 — gear matches mob level, baseline combat (50% reduction)
  • 0.5 — peak gear, maximum protection (75% reduction, hard cap)

Gear Score Composition

gearScore = (sum of armorLevel across 4 armor slots) / 4
          + (sum of enchantBonus across ALL 6 slots) / 4
  • Armor level: elite items use their stored level, vanilla items use a material-based lookup (leather=1 through netherite=7).
  • Enchant bonus: Protection (all types) + damage-type-specific protection, scaled by ENCHANT_SCALE (1/3) to convert enchant levels into armor-level-equivalent units.
  • Mainhand + offhand contribute enchant bonus only (not armor level), allowing tank builds with Protection on shields/weapons.
  • The /4 on enchant sum normalizes to per-armor-slot units, while counting 6 slots means full enchants can provide up to 50% more bonus than 4 alone.

Gear Reduction Curve (Two-Part Linear)

Reduction
  75% |                              ___________  ← hard cap
      |                            /
  50% |..........................X  ← matching gear = 50%
      |                        /
  25% |                      /
      |                    /
   0% |__________________/___________________________
      0        gearScore=mobLevel        gearScore

Below matching (gearScore ≤ mobLevel):
  reduction = 0.50 × (gearScore / mobLevel)
  Slope depends on mob level — linear from 0% to 50%.

Above matching (gearScore > mobLevel):
  reduction = 0.50 + (gearScore - mobLevel) × 0.025
  Flat 2.5% per gear level above mob, up to 75% cap.
  Requires +10 gear levels above mob to hit cap.

Target Scenario Table

These are the combat outcomes this system is designed to produce. "Hits" = playerMaxHP / finalDamage, the number of hits to kill the player.

Lv1 naked vs Lv11.00%2.02.5
Lv1 naked vs Lv51.450%2.0~1.7
Lv1 vanilla diamond vs Lv51.4550%1.0~3.5
Lv25 matched vs Lv251.050%1.05.0
Lv25 matched+ProtIV vs Lv251.053.3%0.935.4
Lv25 matched vs Lv301.5941.7%1.172.7
Lv25 peak gear vs Lv251.075%0.5010.0
Lv50 matched vs Lv501.050%1.05.0

Key design targets verified by the table:

  • 5 hits at matched level — the core balance target. A properly geared player survives exactly 5 normal hits from a same-level elite mob, at ALL levels.
  • 2.5 hits naked — no gear = double damage penalty via 2.0 multiplier. Immediate incentive to equip any armor.
  • Vanilla armor matters — a level 1 player in diamond armor survives ~3.5 hits from a level 5 mob instead of ~1.7 naked. This fixes the old system where vanilla armor was completely ignored.
  • Enchants are meaningful but not dominant — Protection IV on all 4 armor pieces adds ~1.33 to gear score (via ENCHANT_SCALE=1/3), pushing from 50% to 53.3% reduction. Noticeable (~8% more survivability) but not game-breaking.
  • Level-consistent — matched combat at level 25 and level 50 both produce exactly 5 hits. The formula scales perfectly across all levels.
  • Peak gear cap at 10 hits — even with the best possible gear (+10 levels above mob), players still take meaningful damage. Prevents invulnerability.

Worked Examples

Example 1: Lv25 matched gear + Prot IV vs Lv25 (melee)

Player: armorSkillLevel=25, maxHP = 20 + 24*2 = 68
        4 elite armor pieces each at armorLevel=25, each with Protection IV
Mob:    level=25, melee attack

Step 1 — Armor level per piece: 25 (elite item, stored value)
Step 2 — Enchant bonus per piece: Protection IV = 4 * (1/3) = 1.333
         (melee → only general Protection, no type-specific)
Step 3 — Gear score:
         armorLevelSum = 25*4 = 100, /4 = 25.0
         enchantBonusSum = 1.333*4 = 5.333 (no mainhand/offhand enchants), /4 = 1.333
         gearScore = 25.0 + 1.333 = 26.333
Step 4 — Gear reduction:
         gearScore(26.333) > mobLevel(25) → above-matching formula
         reduction = 0.50 + (26.333 - 25) * 0.025 = 0.50 + 0.033 = 0.533 (53.3%)
Step 5 — Gear adjustment: 2.0 * (1 - 0.533) = 0.933
Step 6 — Final damage: baseDamage(13.6) * skillAdj(1.0) * gearAdj(0.933) = 12.69
         Hits to kill: 68 / 12.69 = 5.36 ≈ 5.4 hits

Example 2: Lv1 vanilla diamond vs Lv5 skeleton (projectile)

Player: armorSkillLevel=1, maxHP = 20
        Full vanilla diamond armor (no enchants), no mainhand/offhand enchants
Mob:    level=5, skeleton arrow (PROJECTILE damage type)

Step 1 — Armor level per piece: 5 (vanilla diamond → VANILLA_ARMOR_LEVELS lookup)
Step 2 — Enchant bonus: 0 (no enchants on any piece)
Step 3 — Gear score: (5+5+5+5)/4 + 0/4 = 5.0
Step 4 — Gear reduction: gearScore(5) == mobLevel(5)
         reduction = 0.50 * (5/5) = 0.50 (50%)
Step 5 — Gear adjustment: 2.0 * (1 - 0.50) = 1.0
Step 6 — Final damage: baseDamage(4) * skillAdj(1.447) * gearAdj(1.0) = 5.79
         Hits to kill: 20 / 5.79 = 3.45 ≈ 3.5 hits

Note: If the diamond armor had Projectile Protection IV, the enchant bonus
would be (4+4) * (1/3) = 2.667 per piece (Protection IV would be 0 since it's
vanilla unenchanted, so just Proj Prot IV = 4 * 1/3 = 1.333 per piece).
This would raise gear score to 5 + (1.333*4)/4 = 6.333, increasing reduction
to 53.3% and improving survival noticeably against arrows specifically.

Types

Link copied to clipboard
public enum DamageType
Damage type categories for damage-type-aware defense calculation.

Properties

Link copied to clipboard
public final static double ENCHANT_SCALE
Converts enchantment levels into armor-level-equivalent units.
Link copied to clipboard
public final static double GEAR_BASE_REDUCTION
The maximum gear reduction achievable at exactly matching gear score.
Link copied to clipboard
public final static double GEAR_BONUS_PER_LEVEL
Additional damage reduction per gear-score level above the mob's level.
Link copied to clipboard
public final static double GEAR_MAX_REDUCTION
Hard cap on gear reduction, preventing invulnerability.

Functions

Link copied to clipboard
public static ArmorDefenseCalculator.DamageType fromEvent(EntityDamageByEntityEvent event)
Maps an EntityDamageByEntityEvent's cause to a DamageType.
Link copied to clipboard
public static double getEffectiveArmorLevel(ItemStack item)
Returns the effective armor level for a single item.
Link copied to clipboard
public static double getEnchantBonus(ItemStack item, ArmorDefenseCalculator.DamageType type)
Calculates the enchantment bonus for a single item, converted to armor-level units.
Link copied to clipboard
public static double getGearAdjustment(double gearScore, int mobLevel)
Converts gear reduction into the final damage multiplier used in the formula.
Link copied to clipboard
public static double getGearReduction(double gearScore, int mobLevel)
Calculates the gear reduction percentage from gear score vs mob level.
Link copied to clipboard
public static double getGearScore(Player player, ArmorDefenseCalculator.DamageType type)
Computes the player's total gear score for the gear reduction formula.