Monsters & threat filter

3.6 · 3.7 · 5.0

Every row here is read out of the monster tables in the NetHack source — include/monsters.h for 3.7 and 5.0, src/monst.c for 3.6 — by scripts/gen-monsters.py. The threat filter is a direct port of rndmonst() in src/makemon.c: the same difficulty window, the same G_NOGEN/G_UNIQ/Gehennom exclusions, and the same generation weights, so the percentages below are the game's actual selection probabilities and not an estimate.

Threat filter — what can spawn on me here?
Branch
Table

level_difficulty() is normally just the depth of the level, so the dungeon level field is that depth. It is not your depth if you are carrying the Amulet (then it is the deepest level you ever reached) or in the endgame. The level alignment shifts every monster's weight by align_shift(); ordinary dungeon levels are unaligned, so leave it there unless you are somewhere special.

Filter
Monster class
Monsters click a row for full flags
How the generation rule works
The exact rule, from rndmonst()

Every time the game wants a random monster it walks mons[] from the first entry up to but not including SPECIAL_PM (the long worm tail; everything from there on is quest and endgame material that is never generated randomly) and keeps the entries that pass all of:

  • difficulty >= level_difficulty / 6 — the too-weak cutoff. This is why sewer rats stop showing up.
  • difficulty <= (level_difficulty + experience_level) / 2 — the ceiling. Note your experience level is half of it: levelling up is what lets nastier things appear, not just going deeper.
  • not G_NOGEN and not G_UNIQ.
  • outside Gehennom, not G_HELL; inside Gehennom, not G_NOHELL, and only monsters whose alignment is 0 or negative.

Each survivor gets a weight of (geno & G_FREQ) + align_shift(), plus 3 in 3.7/5.0 if the level has a temperature the monster resists. A weight of zero means it is never picked. One survivor is then chosen with probability weight ÷ total weight — 3.6 walks a running total, 3.7 and 5.0 use weighted reservoir sampling, which gives the same distribution.

What this page cannot know: whether you have genocided or extinct-ed something (mvitals[]), the quest branch's own monster list (qt_montype(), used 6 times out of 7 there), the Rogue level's uppercase-only filter, the elemental planes, and goodpos() rejecting a monster that cannot survive on the square that was picked. Special levels and Sokoban also place monsters directly. Treat the list as "what the random generator may hand you", not as everything you will meet.

Where difficulty comes from
Attack severity colours

The colour on an attack is keyed off its AD_* damage type, which is a fact from the table — not a judgement about the monster. red marks damage types that can end a game outright or take something back permanently: petrification, sliming, disintegration, level drain, digestion, and the Riders' touches. orange marks damage that costs you equipment, stats, items or control: disenchantment, corrosion and rust, seduction and theft, paralysis, the stat drains, lycanthropy, teleport, polymorph. yellow marks the merely inconvenient — stun, confusion, blindness, sleep, sticking.

Differences between the versions