Enemy Recipes
Status: Reference / authoring aid. Companion to: PROGRESSION_RECIPES.md, ENEMY_SYSTEM.md, STAT_PIPELINE.md, COMBAT_SYSTEM.md
Scope
Tabular reference for stamping OSRS-shape enemies onto the UEnemyDefinition authoring surface — the enemy-side mirror of PROGRESSION_RECIPES.md, which does the same for player gear. Each table pairs an OSRS reference monster (so the curve is anchored to a known-good ramp) with the concrete enemy authoring values that reproduce a similar HP / resistance / damage-output profile through the CRADL combat pipeline.
As in the gear doc: absolute numbers are not sacred — the shape is the contract. The relative ramp between tiers (HP growth, max-hit growth, how defense scales, where per-type weaknesses bite) is what transfers; final tuning belongs to playtest.
The named monsters are reference anchors, not a build list. "Green Dragon" below does not mean the project must ship a green dragon — it means if you author one, here are its effective CRADL stats and the shape of its profile. Likewise the Enemy.Family.* leaves used in the tables are illustrative. Only Enemy.Family.Goblin (+ .Warrior / .Wizard) and Enemy.Family.Cow are declared in Config/DefaultGameplayTags.ini today; any other family leaf (Enemy.Family.Undead, .Demon, .Dragon, …) lands alongside the archetype that first needs it (per ENEMY_SYSTEM.md "Tag Taxonomy") — it is not a prerequisite for reading this doc.
This document is not a balance spec, and it does not redesign the enemy system — it stamps numbers onto the surfaces ENEMY_SYSTEM.md already defined.
Field Mapping (OSRS monster → CRADL)
| OSRS monster column | CRADL surface | Where it's authored | Notes |
|---|---|---|---|
| Hitpoints | MaxHealth base from HitpointsLevel; FEnemyStatTuning adds ± variance |
UEnemyDefinition::HitpointsLevel (base) + StatTuning → UGE_Enemy_InnateStats (variance) |
AEnemyCharacter::ApplyDefinition writes the base MaxHealth = HitpointsLevel × UCradlCombatSettings::EnemyMaxHealthPerHitpointsLevel (default 1, OSRS-faithful — the enemy analog of the player's ×4 MaxHealthPerHitpointsLevel), so at the default the listed HP is the HitpointsLevel to author and effective HP tracks the displayed combat level. Enemies have no USkillsComponent::OnLevelUp (COMBAT_SYSTEM.md "Health & Damage"), so this runs once at spawn and never recomputes. A MaxHealth StatTuning entry is now optional [Min,Max] per-spawn variety on top of that base, not the pool itself. |
| Attack / Strength level | enemy Melee / Ranged / Magic level → feeds effectiveAttackLevel and effectiveStrengthLevel |
enemy ICombatStatsProvider::GetCombatSkillLevel (see Where enemy levels live below) |
CRADL collapses Attack+Strength into one weapon-style skill (COMBAT_SYSTEM.md "Damage Formula" footgun). One number per style. |
| Defense level | enemy Defense level → feeds effectiveDefenseLevel (the dominant evasion lever) |
enemy ICombatStatsProvider::GetCombatSkillLevel(Skill.Combat.Defense) |
This, not equipment, is where most of a monster's "hard to hit" comes from — the +64 floor means the level scales the whole defense roll. |
| Max hit | derived from the weapon's StrengthBonus + the enemy's Melee level |
weapon FItemRow::StrengthBonus (Bucket 1) + level |
maxHit = floor(0.5 + effStr·(StrengthBonus + 64) / 640). See Max-hit cheat sheet. |
| Attack style (Stab/Slash/Crush/Ranged/Magic) | weapon FItemRow::WeaponDamageType |
the variant's WeaponItemId row |
The enemy's single equipped weapon picks the axis it swings on. |
| Attack speed (ticks) | weapon FItemRow::SwingInterval (seconds) |
the variant's WeaponItemId row |
SwingInterval = ticks · 0.6. |
| Attack accuracy bonus | weapon FItemRow::AttackBonus[type] |
the variant's WeaponItemId row |
Per-type, same matrix as player gear; SumAttackBonus reads the enemy's one slot. |
| Per-type defense bonus (armoured monsters) | weapon FItemRow::DefenseBonus[type] |
the variant's WeaponItemId row |
The MainHand slot is the enemy's only equipped item, so SumDefenseBonus resolves equipment defense off it. Most low-tier monsters leave this 0 and lean on Defense level. |
| Weak to / resistant to a type | DefenseMultiplier[Stab/Slash/Crush/Ranged/Magic] |
reusable BP_GE_DefMult_* in UEnemyDefinition::InnateStatsEffects |
1.0 = neutral; 0.80 = "weak to" (def roll ×0.80); 1.15 = "resistant". One BP serves every fragile-to-magic mob. See STAT_PIPELINE.md "Defense Granularity". |
| Species / type | UEnemyDefinition::FamilyTag (Enemy.Family.*) |
definition | Surfaces during damage resolution via FTargetClassificationScope and on Combat.Event.Kill — this is what player conditional weapons (Salve, Dragon hunter) and quests key off. |
| Aggression | EEnemyHostility + AggroRadiusCm + LevelGate + bRequireLOS |
definition | Passive = no first strike (still retaliates); LevelGate = OSRS auto-aggro fade. |
| Multi-attacker cap | MaxAttackers |
definition | Default 3; bosses raise it, trash may lower it. |
| Drops | DropTable soft-ref |
definition | Authored per ENEMY_SYSTEM.md "Drop Tables"; out of scope for this doc. |
Combat level is not stored on enemies — it is derived. OSRS combat level is shown in the tables for anchoring intuition; CRADL feeds the enemy's five authored skill levels (the four below + HitpointsLevel) through the same CradlCombat::ComputeCombatLevel formula the player uses, so there is still no enemy combat-level field — the number is computed for the LevelGate check and the right-click risk token alike (ENEMY_SYSTEM.md "Combat Level Scalar"). HitpointsLevel now does double duty: it feeds the displayed combat level and drives the base MaxHealth (× EnemyMaxHealthPerHitpointsLevel, default 1 → HitpointsLevel is the HP), so the displayed level and effective health no longer drift. StatTuning / VariantStatsEffect / InnateStatsEffects layer ± variance on top of that base — the variance moves real HP per spawn but not the displayed level (which reads HitpointsLevel, never the attribute).
Where enemy levels live
The Attack/Defense levels in the tables below feed the effective-level math; the implementation settled this seam on definition fields — UEnemyDefinition::{MeleeLevel, RangedLevel, MagicLevel, DefenseLevel, HitpointsLevel}, read through ICombatStatsProvider::GetCombatSkillLevel ("Combat Reuse"). They are authored, not rolled — static per-archetype identity. HitpointsLevel additionally seeds the base MaxHealth (× UCradlCombatSettings::EnemyMaxHealthPerHitpointsLevel, default 1 → HitpointsLevel == HP). Per-spawn numerical variance layers on top of that base via FEnemyStatTuning (and VariantStatsEffect / InnateStatsEffects) — it nudges real HP but does not change the derived combat level, which reads the authored levels, never the attribute. Stamp the target levels below into the definition's combat-skill fields.
Reading the HP columns below. At the default EnemyMaxHealthPerHitpointsLevel = 1, the MaxHealth/HP figure in each tier table is the HitpointsLevel to author. For a single value, set HitpointsLevel to it. For a [Min,Max] band (e.g. a giant's 30–40), set HitpointsLevel to the band base (30) and add a MaxHealth FEnemyStatTuning entry for the [0, spread] per-spawn variance ([0,10]) — the level feeds the displayed combat level off the base; the tuning supplies the wobble.
Tick → SwingInterval cheat sheet
3t = 1.8s · 4t = 2.4s · 5t = 3.0s · 6t = 3.6s · 7t = 4.2s · 8t = 4.8s. (Shared with PROGRESSION_RECIPES.md.) Most melee monsters are 4t; heavy giants and dragons read slower (5–6t).
Max-hit cheat sheet
Outgoing damage is not a stored field — it falls out of the player-side formula in COMBAT_SYSTEM.md "Damage Formula", applied to the enemy as attacker:
effStr = MeleeLevel + styleBonus + 8 (styleBonus = +3 for Aggressive)
maxHit = floor(0.5 + effStr · (StrengthBonus + 64) / 640)
hit = uniform integer in [0, maxHit]
Author enemies' weapons with DefaultStyle = Combat.Style.Aggressive so effStr = MeleeLevel + 11 and max hit reads cleanly off (MeleeLevel, StrengthBonus). To hit a target max hit, the two levers trade off — raise the Melee level (also raises accuracy) or raise the weapon's StrengthBonus (damage only). The tables pick a pair and show the resulting maxHit.
Reference points (Aggressive, so effStr = Melee + 11):
| Melee level | StrengthBonus | effStr | → maxHit |
|---|---|---|---|
| 1 | 0 | 12 | 1 |
| 15 | 10 | 26 | 3 |
| 18 | 22 | 29 | 4 |
| 26 | 20 | 37 | 5 |
| 50 | 20 | 61 | 8 |
| 60 | 35 | 71 | 11 |
| 80 | 35 | 91 | 14 |
| 120 | 60 | 131 | 25 |
(Floor effect: with effStr ≥ 12 the minimum nonzero max hit is 1 — a literal OSRS "max 0" critter reads as max-hit-1 in CRADL. The harmless feel comes from Passive hostility + low accuracy, not a literal 0. See Critters below.)
Critters (Passive, harmless filler)
Chickens, cows, rats — XP/drop fodder that barely fights back. Hostility = Passive (no first strike; still retaliates if hit, per ENEMY_SYSTEM.md "Hostility"). Tiny HP, floor max hit, low accuracy.
| Anchor | OSRS lvl / HP / max hit | HitpointsLevel (= HP) |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
AttackBonus |
Defense lvl | → maxHit |
|---|---|---|---|---|---|---|---|---|---|
| Chicken | 1 / 3 / 0 | 3 | 1 | ...Crush (peck) |
2.4 | 0 | 0 | 1 | 1 |
| Cow | 2 / 8 / 1 | 8 | 1 | ...Crush (gore) |
3.0 | 0 | 1 | 1 | 1 |
| Giant rat | 3 / 8 / 1 | 8 | 2 | ...Stab (bite) |
2.4 | 0 | 1 | 1 | 1 |
Hostility = Passive, LevelGate irrelevant (Passive ignores it), MaxAttackers 1–2. Family: Enemy.Family.Cow exists today; a chicken/rat leaf would land with the archetype. No DefenseMultiplier biases — neutral to everything.
Low-tier humanoids (the variant showcase)
Goblins, men, guards — the canonical "same monster, different weapon" case that the variant system exists for. Author one UEnemyDefinition with multiple FWeightedEnemyVariant entries; each variant's WeaponItemId swings a different axis.
OSRS goblin: lvl 2, 5 HP, max hit 1, low defense.
| Variant | DisplayName |
WeaponItemId row → WeaponDamageType |
SwingInterval |
StrengthBonus |
AttackBonus |
Weight |
|---|---|---|---|---|---|---|
| Spear goblin | "Spear-wielding Goblin" | ...Stab |
2.4 | 0 | 2 / 0 / 0 | 1 |
| Sword goblin | "Sword-wielding Goblin" | ...Slash |
2.4 | 0 | 0 / 2 / 0 | 1 |
Shared across both variants (definition-level): HitpointsLevel = 5 (→ 5 HP), Melee lvl 1, Defense lvl 1 → maxHit 1. FamilyTag = Enemy.Family.Goblin (use .Warrior for these; reserve .Wizard for the caster recipe below). Hostility = Aggressive, LevelGate ≈ 10 (low-level goblins stop pestering combat-10+ players), AggroRadiusCm ≈ 600, bRequireLOS = true.
The two variants differ only in the weapon row → the WeaponDamageType / AttackBonus axis follows the weapon for free (ENEMY_SYSTEM.md "Variants"). A man/guard archetype is the same recipe with higher HP (lvl 3–22 men: 7–22 HP) and a real bronze/iron weapon row instead of a goblin-specific one.
Undead (the Salve-amulet hook)
Skeletons, zombies, ghosts. The point of this family is the FamilyTag — it's what makes PROGRESSION_RECIPES.md's Salve amulet (+15% vs Enemy.Family.Undead) fire. If you author undead, declare Enemy.Family.Undead (and/or .Skeleton) and the Salve recipe becomes shippable. OSRS skeletons read as crush-weak / stab-resistant.
| Anchor | OSRS lvl / HP / max hit / def | MaxHealth |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
Defense lvl | DefenseMultiplier bias |
→ maxHit |
|---|---|---|---|---|---|---|---|---|---|
| Ghost | 19 / 19 / 2 | 19 | 12 | ...Slash |
2.4 | 5 | 8 | Magic 0.85 (weak), Stab/Slash/Crush 1.15 |
2 |
| Skeleton | 22 / 18 / 3 | 18 | 15 | ...Slash |
2.4 | 10 | 14 | Crush 0.80 (weak), Stab 1.15 (resist) |
3 |
| Zombie | 24 / 25 / 3 | 25 | 16 | ...Crush |
3.0 | 12 | 12 | Crush 0.85 |
3 |
FamilyTag = Enemy.Family.Undead.*, Hostility = Aggressive, MaxAttackers 3. Biases authored as BP children of UGE_DefMult_* dropped into InnateStatsEffects — e.g. one shared BP_GE_WeakToCrush_20 reused across every undead that smashes easily. The crush-weakness is the in-engine reason a mace (PROGRESSION_RECIPES.md Mace family) shines against skeletons.
Giants (HP sponges, slow heavy hits)
Hill / moss / fire giants. High HP, big slow crush max hit, mediocre defense (easy to hit, takes a while to drop).
| Anchor | OSRS lvl / HP / max hit / def | MaxHealth |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
AttackBonus |
Defense lvl | → maxHit |
|---|---|---|---|---|---|---|---|---|---|
| Hill giant | 28 / 35 / 4 | 30–40 | 18 | ...Crush |
3.6 (6t) | 22 | 4 / 4 / 8 | 26 | 4 |
| Moss giant | 42 / 60 / 5 | 55–65 | 26 | ...Crush |
3.6 (6t) | 20 | 5 / 5 / 10 | 30 | 5 |
| Fire giant | 86 / 111 / 12 | 105–115 | 65 | ...Crush |
3.6 (6t) | 30 | 8 / 8 / 16 | 65 | 12 |
FamilyTag = Enemy.Family.Giant.*, Hostility = Aggressive, MaxAttackers 3–4 (they're big — more players can surround one). Note the [Min,Max] HP range giving per-spawn variety ("this moss giant is a little tankier") — exactly the Stat Tuning intent. No per-type weakness; the slow SwingInterval plus low Defense level is the profile.
Demons (mid-high melee, the demonbane hook)
Lesser / greater / black demons. Fast-ish heavy melee; the FamilyTag is the hook for any future "+X vs demons" conditional weapon (same machinery as Salve/Dragon hunter in PROGRESSION_RECIPES.md "Target-Conditional").
| Anchor | OSRS lvl / HP / max hit / def | MaxHealth |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
AttackBonus |
Defense lvl | → maxHit |
|---|---|---|---|---|---|---|---|---|---|
| Lesser demon | 82 / 79 / 8 | 75–85 | 50 | ...Slash (claw) |
2.4 | 20 | 0 / 20 / 0 | 60 | 8 |
| Greater demon | 92 / 87 / 11 | 85–95 | 60 | ...Slash (claw) |
2.4 | 35 | 0 / 28 / 0 | 70 | 11 |
| Black demon | 172 / 157 / 14 | 150–165 | 80 | ...Slash (claw) |
2.4 | 35 | 0 / 40 / 0 | 100 | 14 |
FamilyTag = Enemy.Family.Demon.*, Hostility = Aggressive, LevelGate high (these don't fade for most players), MaxAttackers 3. Optional DefenseMultiplier[Magic] 1.10 to nudge them toward a melee/ranged kill if the design wants demons to read as magic-resistant.
Dragons (the Dragon-hunter hook + dragonfire caveat)
Baby / green / blue / metal dragons. High all-round Defense level, the Enemy.Family.Dragon tag that fires PROGRESSION_RECIPES.md Dragon hunter lance (+20% vs Enemy.Family.Dragon), and a melee profile. Dragonfire is out of scope here — it's a special-attack/ranged-breath mechanic, parked exactly like weapon special attacks are parked in the gear doc; model only the melee body.
| Anchor | OSRS lvl / HP / melee max hit / def | MaxHealth |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
AttackBonus |
Defense lvl | DefenseMultiplier bias |
|---|---|---|---|---|---|---|---|---|---|
| Baby (green) dragon | 83 / 65 / 8 | 60–70 | 50 | ...Slash (bite) |
2.4 | 20 | 10 / 20 / 0 | 60 | — |
| Green dragon | 79 / 75 / 8 (+fire) | 70–80 | 50 | ...Slash (bite) |
2.4 | 20 | 10 / 20 / 0 | 65 | — |
| Steel dragon | 246 / 210 / 14 (+fire) | 200–220 | 90 | ...Stab (bite) |
3.0 | 35 | 30 / 20 / 0 | 130 | Magic 0.85 (metal-weak) |
FamilyTag = Enemy.Family.Dragon.*, Hostility = Aggressive, MaxAttackers 3. Metal dragons read as magic-weak via a shared BP_GE_WeakToMagic_* in InnateStatsEffects — the same reusable BP STAT_PIPELINE cites. The high Defense level is what makes dragons "need good gear to hit" without any equipment-defense authoring.
Beasts (incl. the blind-aggro example)
Wolves, bears, scorpions. Mostly unremarkable melee; the one architectural note is the blind-aggro flag — giant scorpions / OSRS dust-devil archetype set bRequireLOS = false so they aggro through obstacles (ENEMY_SYSTEM.md "Enemy Definition" footgun: "single biggest pacing footgun").
| Anchor | OSRS lvl / HP / max hit | MaxHealth |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
Defense lvl | Notes | → maxHit |
|---|---|---|---|---|---|---|---|---|---|
| Wolf | 25 / 28 / 4 | 25–30 | 18 | ...Stab (bite) |
2.4 | 22 | 18 | bRequireLOS = true |
4 |
| Black bear | 19 / 25 / 3 | 25 | 15 | ...Slash (claw) |
2.4 | 10 | 15 | — | 3 |
| Giant scorpion | 28 / 28 / 5 | 28 | 20 | ...Stab (sting) |
2.4 | 26 | 20 | bRequireLOS = false |
5 |
FamilyTag = Enemy.Family.Beast.*, Hostility = Aggressive, MaxAttackers 3.
Casters & rangers (non-melee WeaponDamageType)
The combat pipeline treats Magic and Ranged as just two more WeaponDamageType axes, so a caster is "a humanoid whose weapon row is WeaponDamageType = Magic," and a ranger is the same with Ranged + an AmmoItemId on the variant (server treats enemy ammo as infinite — ENEMY_SYSTEM.md "Variants").
| Anchor | OSRS lvl / HP / max hit | MaxHealth |
Style lvl | WeaponDamageType |
SwingInterval |
dmg lever | AttackBonus |
Defense lvl |
|---|---|---|---|---|---|---|---|---|
| Dark wizard | 20 / 22 / 2 (magic) | 22 | Magic 16 | ...Magic |
3.0 (5t) | MagicDamageBonus on staff row, or fixed spell |
AttackBonus[Magic] 12 |
10 |
| Hobgoblin (ranged var.) | 28 / 29 / 4 (ranged) | 29 | Ranged 18 | ...Ranged |
3.0 | RangedStrengthBonus on AmmoItemId |
AttackBonus[Ranged] 6 |
15 |
FamilyTag = Enemy.Family.Goblin.Wizard exists today for the dark-wizard-style caster; a ranged variant is one extra FWeightedEnemyVariant with WeaponItemId (a bow row) + AmmoItemId. Magic damage works like the player path: it scales (1 + MagicDamage), so author the staff row's MagicDamageBonus rather than a StrengthBonus.
Boss capstone (high cap, multi-style)
The Enemy.Rank.Boss namespace is reserved (.ini only, no consumers — ENEMY_SYSTEM.md "Open Questions"); boss-ness rides on FamilyTag/MaxAttackers, not a bIsBoss flag. A King-Black-Dragon-shaped capstone, melee body only (dragonfire/specials parked):
| Anchor | OSRS lvl / HP / melee max hit | MaxHealth |
Melee lvl | WeaponDamageType |
SwingInterval |
StrengthBonus |
AttackBonus |
Defense lvl | MaxAttackers |
|---|---|---|---|---|---|---|---|---|---|
| KBD-style | 276 / 240 / ~25 | 230–250 | 120 | ...Stab (bite) |
2.4 | 60 | 40 / 30 / 0 | 140 | 6–8 |
FamilyTag = Enemy.Family.Dragon.* (+ optionally a reserved Enemy.Rank.Boss once a consumer exists), Hostility = Aggressive, LevelGate = 0 (never fades), LeashRadiusCm = 0 (boss holds its arena — disables leashing per ENEMY_SYSTEM.md "Leashing"). Raise MaxAttackers so a party can engage.
Resistance authoring — the DefenseMultiplier lever
Two surfaces compose into a monster's "hard to hit," and they are not interchangeable:
- Defense level (
effectiveDefenseLevel) — the flat difficulty knob. Raising it makes the monster harder to hit with every style equally. This is where the bulk of progression-gating lives (a steel dragon's Defense 130 is why you need good gear). DefenseMultiplier[type]— the per-type bias, default1.0. This is the "weak to crush / resistant to stab" shape. Authored as BP children of the fiveUGE_DefMult_*carrier GEs, dropped intoUEnemyDefinition::InnateStatsEffects(an array — drop in as many small reusable biases as you want).0.80≈ "weak to" (defense roll ×0.80 for that type),1.15≈ "resistant".
Because the shipped formula scales the full defense roll including the +64 floor (STAT_PIPELINE.md "Defense Granularity"), a DefenseMultiplier bias bites even on a monster with zero equipment defense — so the "weak to magic" intent works on low-armour mobs, which was the whole reason the formula was changed. Reuse one BP across many archetypes (BP_GE_WeakToMagic_20 on every metal dragon, imp, and ghost) — that's the design intent, not one-BP-per-monster.
Per-type equipment defense (FItemRow::DefenseBonus[type] on the enemy's weapon row) is the third, rarely-needed surface — reserve it for genuinely armoured humanoids where OSRS gives the monster real per-slot defense; most mobs express their whole defensive character through level + multiplier.
Natural-weapon item rows
Most monsters don't wield a player weapon — they bite, claw, breathe, or punch. Since an enemy's combat stats resolve through its MainHand FItemRow (ENEMY_SYSTEM.md "Combat Reuse"), give these monsters a synthetic "natural weapon" row in the items DataTable that carries the WeaponDamageType / SwingInterval / StrengthBonus / AttackBonus[type] (and any DefenseBonus[type]) the recipe calls for:
- Name them by convention (e.g.
mob_goblin_fists,mob_dragon_bite) so they're filterable. - Make them non-obtainable: zero store price, not on any shop/drop table, referenced only by a variant's
WeaponItemId. The weapon is a stat carrier, not loot — if you want "kill the spear goblin, get a chance at his spear," that spear is a separate drop-table entry (ENEMY_SYSTEM.md "Death" footgun). DefaultStyle = Combat.Style.Aggressiveso the max-hit math reads off Melee level cleanly (see Max-hit cheat sheet).- The items DataTable validator (
UCradlItemTableValidator) and the enemy validator'sWeaponItemId-resolution check both still apply — a typo'dmob_goblln_fistsis caught at save.
A monster that does carry a recognizable real weapon (a guard with a real bronze sword) just references the existing player weapon row — no synthetic row needed.
Slayer XP & resilience gate
Two UEnemyDefinition fields surface slayer to the combat path (contract in SLAYER_SYSTEM.md):
SlayerXp— per-kill Slayer XP granted while the player has a matching slayer task. Read off the victim's active definition byUSlayerComponent'sCombat.Event.Killhandler (SLAYER_SYSTEM.md "Kill Tracking"). The OSRS anchor is "XP ≈ HP" — bigger monsters bank more per assignment. Authors bump up modestly (≈1.05–1.20×) when the combat profile reads harder-than-HP (high Defense level, slow tempo, awkward resistances) and break the curve for bosses on purpose.RequiredSlayerLevel— the resilience gate (SlayerCombat::IsAttackPermittedblocks the swing/cast when attacker Slayer level < this; SLAYER_SYSTEM.md "Combat Modifiers"). Default 0 — every non-resilient enemy. A nonzero value is a design statement that this archetype is slayer-gated content; don't sprinkle it for flavor.
Illustrative XP progression
Anchored on the MaxHealth from the tier tables above. The shape: chest of the curve sits at SlayerXp = MaxHealth (midpoint of the [Min,Max] band); a small multiplicative bump rides high-defense / awkward archetypes; bosses break the curve deliberately so the rare kill is meaningful.
| Anchor (tier table above) | MaxHealth |
SlayerXp |
Why this number |
|---|---|---|---|
| Chicken | 3 | 3 | flat HP anchor |
| Cow | 8 | 8 | flat HP anchor |
| Giant rat | 8 | 8 | flat HP anchor |
| Goblin (any variant) | 5 | 5 | flat HP anchor |
| Ghost | 19 | 22 | ×1.15 stab/slash/crush resist — harder than HP suggests |
| Skeleton | 18 | 22 | stab-resistant; small bump |
| Zombie | 25 | 25 | flat HP anchor |
| Hill giant | 30–40 | 35 | flat HP anchor (midpoint) |
| Moss giant | 55–65 | 60 | flat HP anchor (midpoint) |
| Fire giant | 105–115 | 115 | def 65 + slow 6t; small bump |
| Wolf | 25–30 | 28 | flat HP anchor |
| Giant scorpion | 28 | 32 | blind-aggro pacing penalty — small bump |
| Lesser demon | 75–85 | 90 | def 60 slog — bump |
| Greater demon | 85–95 | 105 | def 70 — bigger bump |
| Black demon | 150–165 | 175 | def 100 |
| Baby (green) dragon | 60–70 | 75 | def 60 |
| Green dragon | 70–80 | 90 | def 65 + (future) dragonfire pressure |
| Steel dragon | 200–220 | 245 | def 130 + metal armour — premium XP |
| KBD-style boss | 230–250 | 320 | boss break — HP undersells the kill |
The lever, in one line: raise SlayerXp above HP only when the kill takes longer than HP suggests. Two monsters with the same HP should bank similar XP unless one is conspicuously slower / better-defended / type-resistant.
Resilience gate examples
Most enemies leave RequiredSlayerLevel = 0. Reserve nonzero values for archetypes whose whole point is to be slayer-locked — the OSRS rockslug / banshee / abyssal-demon shape. Specific monster names below are illustrative anchors (same rule as the rest of this doc: shape transfers, names do not).
| Archetype role | RequiredSlayerLevel |
OSRS anchor |
|---|---|---|
| Open content (most enemies in tables above) | 0 | — |
| Introductory slayer-locked critter | 5 | crawling hand |
| Early-tier resilience | 15–20 | banshee / rockslug |
| Mid-tier resilience | 30–40 | pyrefiend / basilisk |
| High-tier (often paired with blind-aggro) | 60–65 | aberrant spectre / dust devil |
| Endgame resilience | 85–90 | abyssal demon / dark beast |
The gate is attacker-side: the monster doesn't change behavior, the player just can't damage it until trained. Combine with a clear owner-client message at the swing/cast site (SLAYER_SYSTEM.md "Combat Modifiers" footgun).
Quick recipe for new enemy authoring
- Pick the family table above whose shape matches the new enemy's role (sponge? glass cannon? caster? boss?).
- Locate the OSRS anchor closest to the intended power band; read off target HP, Melee/Defense levels, and the max-hit pair.
- Author (or reuse) the weapon row:
WeaponDamageType,SwingInterval,StrengthBonus,AttackBonus[type],DefaultStyle = Aggressive(see Natural-weapon item rows). - On the
UEnemyDefinition: setFamilyTag,Hostility,AggroRadiusCm,LevelGate,bRequireLOS,MaxAttackers,LeashRadiusCm. - Set
HitpointsLevel— at the defaultEnemyMaxHealthPerHitpointsLevel = 1it is the baseMaxHealth(HP) — and the Melee/Defense level surface (see Where enemy levels live); optionally add anFEnemyStatTuningMaxHealthentry for per-spawn[Min,Max]variety on top of that base. - Set the slayer surface:
SlayerXp(default ≈MaxHealthmidpoint; bump only for harder-than-HP profiles — see Slayer XP & resilience gate) andRequiredSlayerLevel(default 0; nonzero only for slayer-gated archetypes). - If the monster has a per-type weakness/resistance, drop a reusable
BP_GE_DefMult_*intoInnateStatsEffects— don't author a bespoke GE per monster. - Add at least one
FWeightedEnemyVariant(every definition needs ≥1; use the array for "same monster, different weapon"). - Declare the
Enemy.Family.*leaf in Config/DefaultGameplayTags.ini only if this archetype introduces a new one (Goblin/Cow already exist). - Run
UCradlEnemyDefinitionValidator(Source/CRADLEditor/Validators/) — it checksFamilyTagis underEnemy.Family.*, every variant'sWeaponItemIdresolves,SlayerXp ≥ 0,RequiredSlayerLevelwithin[0, registry max level], and every stat-tuning attribute is real. Update the validator in lockstep if you add fields, per CLAUDE.md.
Relationship to PROGRESSION_RECIPES.md
The two docs meet at the Enemy.Family.* tag. PROGRESSION_RECIPES authors player weapons that read "+X% vs Undead / vs Dragons" (Salve amulet, Dragon hunter lance) via OngoingTagRequirements on a conditional EquipEffects GE; those GEs stay inert until something publishes the family tag during damage resolution. The enemies in this doc are those publishers — a monster's FamilyTag surfaces through FTargetClassificationScope at swing time and on Combat.Event.Kill. Authoring an Enemy.Family.Undead monster is what flips PROGRESSION_RECIPES' Salve recipe from "needs ini leaf" to shippable. The two recipe books are the two halves of the same combat-triangle authoring story: gear shapes the player's output, enemies shape what that output is tuned against.