monstats.txt is the primary definition table for every monster unit in D2R: enemy monsters, pets, and NPCs. Each row encodes the monster's identity, per-difficulty stats, AI behavior, resistances, skills, and treasure classes. With 752 rows × 273 columns, it's the widest table in the canonical data set.
Related: monlvl supplies the per-level scaling multipliers applied to the base stats here. superuniques overlays named unique champions on top of monstats base rows.
Column count by group:
| Group | Columns |
|---|---|
| Identity and references | 12 |
| Spawn control | 7 |
| Grouping and escort | 9 |
| Movement | 2 |
| Level and rarity | 4 |
| AI behavior | 28 |
| Missiles | 8 |
| Boolean flags | 26 |
| D2R-era flags | 5 |
| Skills (8 slots) | 25 |
| Combat modifiers | 24 |
| Per-difficulty stats (Normal) | 12 |
| Per-difficulty stats (Nightmare) | 12 |
| Per-difficulty stats (Hell) | 12 |
| Elemental attacks (3 types × 3 diffs) | 42 |
| Treasure classes (8 columns × 3 diffs) | 24 |
| Quest TC and animation | 6 |
What's in a row
Identity
| Column | Meaning |
|---|---|
Id | Unique name key — the row's primary key. Used by all other tables to reference this monster (Class in superuniques, BaseId/NextInClass within monstats itself). |
*hcIdx | Numeric index (comment, not read by engine). Can be used as an index for tools. |
BaseId | Points to another Id to define this monster's base type. Used to group variants — skeleton1, skeleton2, skeleton3 all have BaseId=skeleton1, making them the same monster class for code-sharing purposes. |
NextInClass | Next monster in the class chain. The chain should be contiguous: skeleton1 → skeleton2 → skeleton3 → … |
TransLvl | Color transform index for the monster's palette. Controls the visual tier shift between variants (skeleton → returned → bone warrior). |
NameStr | String-table key for the display name. Multiple Id rows can share the same NameStr — see the Council Member example below. |
MonStatsEx | References a row in MonStats2.txt for extended properties. |
MonProp | References MonProp.txt for per-difficulty bonus properties (curses, auras). |
MonType | Type group (skeleton, councilmember, etc.) used by other systems to identify monster families. |
AI | References MonAi.txt for the monster's attack/movement logic. |
Code | Two-letter animation code for the monster's visual asset. |
Spawn control
| Column | Meaning |
|---|---|
enabled | 1 = monster can spawn. 0 = disabled (never spawns). 720 of 752 rows are enabled. |
rangedtype | Flags whether the monster is a ranged attacker. |
placespawn | 1 = can be placed by a spawn-point preset. |
spawn | References a minion type that spawns with this monster on death (e.g., skeletons that rise from corpses). |
Grouping and escort
| Column | Meaning |
|---|---|
minion1, minion2 | Monster Ids that can act as this monster's minions. |
PartyMin, PartyMax | Minimum and maximum party size for random packs. |
MinGrp, MaxGrp | Min/max count within a single group. |
SetBoss | 1 = this monster is the pack leader in its group. |
Level and rarity
| Column | Meaning |
|---|---|
Level | Base monster level (Normal difficulty). |
Level(N) | Monster level in Nightmare. |
Level(H) | Monster level in Hell. This is the index into monlvl for scaling multipliers. |
Rarity | Relative frequency of this monster variant when spawning from its base class. |
Boolean flags
Key flags relevant for queries:
| Column | Meaning |
|---|---|
killable | 1 = can be killed. 0 = invincible (NPCs, Tyrael). 649 of 752 rows are killable. |
demon | 1 = demon type. Affects Holy Bolt, Smite, Sanctuary aura mechanics. 192 demons. |
lUndead | 1 = low undead (zombies, skeletons). |
hUndead | 1 = high undead (vampires). Combined: 124 undead rows. |
boss | 1 = designated boss (not just any champion). 28 boss rows. |
primeevil | 1 = prime evil (act bosses: Andariel, Duriel, Mephisto, Diablo, Baal). |
npc | 1 = NPC unit (Akara, Warriv, etc.). |
flying | 1 = flying monster (bats, mosquitos, valkyrie). |
neverCount | 1 = does not count toward the player's kill total or density triggers. |
CannotDesecrate | 1 = cannot be a target in a Terror Zone (D2R-era column). |
CannotHerald | 1 = cannot trigger a Herald spawn (D2R-era column). |
Per-difficulty stats
The same stat block repeats three times — once for each difficulty. Normal uses no suffix; Nightmare appends (N); Hell appends (H):
| Column | Meaning |
|---|---|
minHP(H), maxHP(H) | Base HP range before monlvl scaling. Actual HP = roll(minHP, maxHP) × L-HP(H) / 100. |
AC(H) | Base defense before monlvl scaling. |
Exp(H) | Base XP before monlvl scaling. |
A1MinD(H), A1MaxD(H), A1TH(H) | Primary attack: min damage, max damage, attack rating. |
A2MinD(H), A2MaxD(H), A2TH(H) | Secondary attack. |
S1MinD(H), S1MaxD(H), S1TH(H) | Special attack. |
Resistances
Six resistance columns per difficulty (18 total):
| Columns | Meaning |
|---|---|
ResDm(H) | Physical damage reduction % |
ResMa(H) | Magic resistance % |
ResFi(H) | Fire resistance % |
ResLi(H) | Lightning resistance % |
ResCo(H) | Cold resistance % |
ResPo(H) | Poison resistance % |
Values ≥ 100 = immune. Negative values = extra vulnerability (Andariel has ResFi(H)=-50 — fire spells deal 50% bonus damage).
116 of 649 killable Hell monsters have ResFi(H) ≥ 100 (fire immune). This is why dual-element builds are standard for Hell progression.
Treasure classes
Eight TC variants per difficulty (24 total). For Hell:
| Column | Meaning |
|---|---|
TreasureClass(H) | Standard kill drop. |
TreasureClassChamp(H) | Drop when this monster is a champion. |
TreasureClassUnique(H) | Drop when this monster is a unique (rare boss). |
TreasureClassQuest(H) | Drop from a quest-scripted kill. |
TreasureClassDesecrated(H) | Drop when the area is a Terror Zone. |
TreasureClassDesecratedChamp(H) | Champion drop in a Terror Zone. |
TreasureClassDesecratedUnique(H) | Unique drop in a Terror Zone. |
TreasureClassHerald(H) | Herald event drop. |
The Desecrated/Herald columns are D2R-era additions for Terror Zone and Herald mechanics.
Worked example — Fallen (basic mob)
The Fallen family illustrates the per-difficulty level progression. The BaseId=fallen1 chain spans multiple variants (fallen1 through fallen5), each used in progressively higher-level areas.
SELECT Id, NameStr, "Level(H)", "MinHP(H)", "MaxHP(H)", "Exp(H)",
"ResFi(H)", "ResCo(H)", "ResMa(H)",
demon, killable, "TreasureClass(H)"
FROM monstats
WHERE Id = 'fallen1';
| Column | Value | Notes |
|---|---|---|
Id | fallen1 | Lowest-tier Fallen variant |
NameStr | Fallen | Display name key |
Level(H) | 67 | Used to look up monlvl multipliers |
MinHP(H) | 25, MaxHP(H)=55 | Base HP range — scaled by L-HP(H)=4049 (mlvl 67) |
Exp(H) | 65 | Base XP — scaled by L-XP(H) at mlvl 67 |
ResFi(H) | 100 | Fire immune — spawns only in Act 1 Hell but carries fire immunity from day one |
ResCo(H) | 40 | Cold resistant (not immune) |
demon | 1 | Demon type |
killable | 1 | Can be killed normally |
TreasureClass(H) | Act 1 H2H A | Standard Hell drop table |
Worked example — Council Members (multiple variants, one name)
The three Council Member variants in Travincal show how Id is the true key while NameStr can be shared:
SELECT Id, "Level(H)", "MinHP(H)", "MaxHP(H)", "ResFi(H)", "ResLi(H)", "ResCo(H)",
demon, MonType, "TreasureClass(H)", "TreasureClassDesecrated(H)"
FROM monstats
WHERE Id IN ('councilmember1','councilmember2','councilmember3');
| Id | Level(H) | MinHP(H) | MaxHP(H) | ResFi(H) | ResLi(H) | ResCo(H) | Desecrated TC |
|---|---|---|---|---|---|---|---|
councilmember1 | 88 | 200 | 350 | 120 (immune) | 33 | 33 | Council (H) Desecrated A |
councilmember2 | 88 | 200 | 350 | 33 | 100 (immune) | 33 | Council (H) Desecrated A |
councilmember3 | 88 | 200 | 350 | 33 | 100 (immune) | 33 | Council (H) Desecrated A |
All three share NameStr="Council Member" and MonType="councilmember", but councilmember1 is fire-immune while councilmember2/councilmember3 are lightning-immune. The superuniques table assigns two named Council members to each base type — Ismail Vilehand and Toorc Icefist spawn as councilmember1; Bremm Sparkfist and Maffer Dragonhand spawn as councilmember3. Querying NameStr alone would miss this resistance split; always filter on Id.
The TreasureClassDesecrated(H) column confirms these monsters have an elevated drop table when Travincal is the active Terror Zone.
Common queries
-- All Hell fire-immune killable monsters
SELECT Id, NameStr, "Level(H)", "ResFi(H)", "ResMa(H)", demon, lUndead, hUndead
FROM monstats
WHERE CAST("ResFi(H)" AS INTEGER) >= 100 AND killable = '1'
ORDER BY CAST("Level(H)" AS INTEGER) DESC;
-- 116 rows
-- Act boss lineup (prime evils only)
SELECT Id, NameStr, "Level(H)", "MinHP(H)", "MaxHP(H)",
"ResFi(H)", "ResLi(H)", "ResCo(H)", "ResMa(H)"
FROM monstats WHERE primeevil = '1'
ORDER BY CAST("Level(H)" AS INTEGER);
-- Demons with all resistances under 100 in Hell (dual-element viable)
SELECT Id, NameStr, "Level(H)",
"ResFi(H)", "ResLi(H)", "ResCo(H)", "ResPo(H)"
FROM monstats
WHERE demon = '1' AND killable = '1'
AND CAST("ResFi(H)" AS INTEGER) < 100
AND CAST("ResLi(H)" AS INTEGER) < 100
ORDER BY CAST("Level(H)" AS INTEGER) DESC
LIMIT 20;