0/0
CRADL // DOCUMENTATION
PORTAL DEV WIKI ENEMY_RECIPES
UTC 00:00:00
◀ RETURN
ENEMY_RECIPES.md 3957 words ~18 min read Updated 2026-07-03

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) + StatTuningUGE_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 MaxHealthEnemyMaxHealthPerHitpointsLevel, 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 fieldsUEnemyDefinition::{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 MaxHealthUCradlCombatSettings::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:

  1. 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).
  2. DefenseMultiplier[type] — the per-type bias, default 1.0. This is the "weak to crush / resistant to stab" shape. Authored as BP children of the five UGE_DefMult_* carrier GEs, dropped into UEnemyDefinition::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.Aggressive so the max-hit math reads off Melee level cleanly (see Max-hit cheat sheet).
  • The items DataTable validator (UCradlItemTableValidator) and the enemy validator's WeaponItemId-resolution check both still apply — a typo'd mob_goblln_fists is 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 by USlayerComponent's Combat.Event.Kill handler (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::IsAttackPermitted blocks 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

  1. Pick the family table above whose shape matches the new enemy's role (sponge? glass cannon? caster? boss?).
  2. Locate the OSRS anchor closest to the intended power band; read off target HP, Melee/Defense levels, and the max-hit pair.
  3. Author (or reuse) the weapon row: WeaponDamageType, SwingInterval, StrengthBonus, AttackBonus[type], DefaultStyle = Aggressive (see Natural-weapon item rows).
  4. On the UEnemyDefinition: set FamilyTag, Hostility, AggroRadiusCm, LevelGate, bRequireLOS, MaxAttackers, LeashRadiusCm.
  5. Set HitpointsLevel — at the default EnemyMaxHealthPerHitpointsLevel = 1 it is the base MaxHealth (HP) — and the Melee/Defense level surface (see Where enemy levels live); optionally add an FEnemyStatTuning MaxHealth entry for per-spawn [Min,Max] variety on top of that base.
  6. Set the slayer surface: SlayerXp (default ≈ MaxHealth midpoint; bump only for harder-than-HP profiles — see Slayer XP & resilience gate) and RequiredSlayerLevel (default 0; nonzero only for slayer-gated archetypes).
  7. If the monster has a per-type weakness/resistance, drop a reusable BP_GE_DefMult_* into InnateStatsEffects — don't author a bespoke GE per monster.
  8. Add at least one FWeightedEnemyVariant (every definition needs ≥1; use the array for "same monster, different weapon").
  9. Declare the Enemy.Family.* leaf in Config/DefaultGameplayTags.ini only if this archetype introduces a new one (Goblin/Cow already exist).
  10. Run UCradlEnemyDefinitionValidator (Source/CRADLEditor/Validators/) — it checks FamilyTag is under Enemy.Family.*, every variant's WeaponItemId resolves, SlayerXp ≥ 0, RequiredSlayerLevel within [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.