Difficulty level
A setting the player picks before play that changes the game's rules, such as how much damage the player takes.
On this page
A difficulty level is chosen before play, unlike a difficulty ramp, which raises the challenge as play goes on. Doom halves the damage the player takes on its easiest skill1. Quake II does the same on Easy outside deathmatch, and its skill levels also remove the entities a map flags against them2. Perfect Dark keeps a table of multipliers per difficulty: a guard’s hit costs the player half as much on Agent, and the player’s shots count double there3. The same table sets the autoaim margin4.
- Damage halvedDoom (1993). The easiest skill halves the damage the player takes.1Quake II (1997). Outside deathmatch, Easy halves the damage a player takes and each skill removes the entities flagged against it.2
- Table of scalesPerfect Dark (2000). Each solo difficulty sets multipliers for damage taken and dealt, enemy accuracy, autoaim, and ammo, and Agent eases off further at low health.3,4
Games
| Game | Year | How | Note |
|---|---|---|---|
| Doom | 1993 | Damage halved | the easiest skill halves the damage the player takes |
| Quake II | 1997 | Damage halved | outside deathmatch, Easy halves the damage a player takes and each skill removes the entities flagged against it |
| Perfect Dark | 2000 | Table of scales | each solo difficulty sets multipliers for damage taken and dealt, enemy accuracy, autoaim, and ammo, and Agent eases off further at low health |
Every claim about this mechanic, by game (2)
References
- ^ abDamage to a Doom player is halved on the easiest skill (
sk_baby), and then armor takes a share: a third with the armor pickup (type 1) and half with the MegaArmor (type 2), until its points run out; monsters have no armor or defense value.Codeid-Software/DOOMHow we know
798 player = target->player; 799 if (player && gameskill == sk_baby) 800 damage >>= 1; // take half damage in trainer mode
linuxdoom-1.10/p_inter.c lines 798–800 at a77dfb9 · upstream ↗ 854 if (player->armortype) ⋮ 856 if (player->armortype == 1) 857 saved = damage/3; 858 else 859 saved = damage/2; ⋮ 861 if (player->armorpoints <= saved) ⋮ 863 // armor is used up 864 saved = player->armorpoints; 865 player->armortype = 0; ⋮ 867 player->armorpoints -= saved; 868 damage -= saved;
linuxdoom-1.10/p_inter.c lines 854–869 at a77dfb9 · upstream ↗ 370 case SPR_ARM1: 371 if (!P_GiveArmor (player, 1)) ⋮ 376 case SPR_ARM2: 377 if (!P_GiveArmor (player, 2))
linuxdoom-1.10/p_inter.c lines 370–380 at a77dfb9 · upstream ↗ 80#define GOTARMOR "Picked up the armor." 81#define GOTMEGA "Picked up the MegaArmor!"
linuxdoom-1.10/d_englsh.h lines 80–81 at a77dfb9 · upstream ↗ 886 // do the damage 887 target->health -= damage;
linuxdoom-1.10/p_inter.c lines 886–887 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abOn Easy (skill 0) outside deathmatch, Quake II's
T_Damagehalves the damage a player takes, to no less than 1; the knockback is worked out separately and isn't halved. Levels also pick their entities by skill: an entity flagged not-easy, not-medium, or not-hard is removed at load on that skill, with Nightmare (3) counted as hard.Codeid-Software/Quake-2How we know
404 // easy mode takes half damage 405 if (skill->value == 0 && deathmatch->value == 0 && targ->client) ⋮ 407 damage *= 0.5; 408 if (!damage) 409 damage = 1;
game/g_combat.c lines 404–410 at 372afde · upstream ↗ 428// figure momentum add ⋮ 444 VectorScale (dir, 500.0 * (float)knockback / mass, kvel);
game/g_combat.c lines 428–446 at 372afde · upstream ↗ 585 else ⋮ 587 if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */ 588 ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || 589 ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || 590 (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ⋮ 593 G_FreeEdict (ent);
game/g_spawn.c lines 585–593 at 372afde · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abSolo Perfect Dark scales damage by difficulty in
lv_update_solo_handicaps, which runs every tick: a guard's hit on the player is multiplied by 0.5 on Agent, 0.6 on Special Agent, and 1 on Perfect Agent (and on the Perfect Dark difficulty, times its own enemy-damage setting); the player's shots are doubled on Agent; and explosions hurt the player 0.25 times on Agent and 0.75 times on Special Agent. On Agent the scales for the damage the player takes, from guards and from explosions, shrink further once health plus shield is at or below 0.6, falling linearly to half at 0.125, so 0.25 for a guard's hit (computed); the player's ×2 on its own shots stays fixed. Doom halves all damage to the player on its easiest skill,sk_baby.Coderyandwyer/perfect-dark · id-Software/DOOMrevisedHow we know
1840 } else { 1841 if (g_Difficulty == DIFF_A) { 1842 f32 totalhealth; 1843 f32 frac = 1; ⋮ 1846 totalhealth = player_get_health_frac() + player_get_shield_frac(); ⋮ 1848 if (totalhealth <= 0.125f) { 1849 frac = 0.5f; 1850 } else if (totalhealth <= 0.6f) { 1851 frac = (totalhealth - 0.125f) * 0.5f / 0.47500002384186f + 0.5f; ⋮ 1861 g_PlayerDamageRxScale = 0.5f * frac; 1862 g_PlayerDamageTxScale = 2; 1863 g_ExplosionDamageTxScale = 0.25f * frac;
src/game/lv.c lines 1840–1866 at 46d3393 · upstream ↗ 1867 } else if (g_Difficulty == DIFF_SA) { ⋮ 1874 g_PlayerDamageRxScale = 0.6f; 1875 g_PlayerDamageTxScale = 1; 1876 g_ExplosionDamageTxScale = 0.75f;
src/game/lv.c lines 1867–1876 at 46d3393 · upstream ↗ 1884 } else if (g_Difficulty == DIFF_PA) { ⋮ 1891 g_PlayerDamageRxScale = 1; 1892 g_PlayerDamageTxScale = 1; 1893 g_ExplosionDamageTxScale = 1;
src/game/lv.c lines 1884–1893 at 46d3393 · upstream ↗ 1901 } else if (g_Difficulty == DIFF_PD) { ⋮ 1908 g_PlayerDamageRxScale = 1; 1909 g_PlayerDamageTxScale = 1; 1910 g_ExplosionDamageTxScale = 1;
src/game/lv.c lines 1901–1910 at 46d3393 · upstream ↗ 2297 lv_update_solo_handicaps();src/game/lv.c line 2297 at 46d3393 · upstream ↗ 4390 // Apply damage scaling based on difficulty settings 4391 if (g_Vars.mplayerisrunning == false) { 4392 // Solo 4393 if (explosion) { 4394 if (vprop->type == PROPTYPE_PLAYER) { 4395 damage *= g_ExplosionDamageTxScale; ⋮ 4397 } else if (aprop && aprop->type == PROPTYPE_PLAYER) { 4398 // Player is attacking 4399 damage *= g_PlayerDamageTxScale; 4400 headshotdamagescale = 25; 4401 } else if (aprop && aprop->type == PROPTYPE_CHR && vprop->type == PROPTYPE_PLAYER) { 4402 // Chr is attacking player ⋮
src/game/chraction.c lines 4390–4404 at 46d3393 · upstream ↗ 27f32 pdmode_get_enemy_damage(void) ⋮ 29 if (g_MissionConfig.pdmode) { 30 return g_MissionConfig.pdmodedamagef; ⋮ 33 return 1;
src/game/pdmode.c lines 27–33 at 46d3393 · upstream ↗ 798 player = target->player; 799 if (player && gameskill == sk_baby) 800 damage >>= 1; // take half damage in trainer mode
linuxdoom-1.10/p_inter.c lines 798–800 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abIn solo Perfect Dark the autoaim margin (perfect-dark/autoaim) is multiplied by
g_AutoAimScale, whichlv_update_solo_handicapssets by difficulty: 1.5 on Agent, 0.75 on Special Agent, 0.2 on Perfect Agent, and 1 on the Perfect Dark difficulty; the ntsc-final build takes the non-Japanese values (g_Jpnis false). Co-op and Counter-Operative use their own values.Coderyandwyer/perfect-darkHow we know
1840 } else { 1841 if (g_Difficulty == DIFF_A) { ⋮ 1864 g_AutoAimScale = 1.5f;
src/game/lv.c lines 1840–1864 at 46d3393 · upstream ↗ 1867 } else if (g_Difficulty == DIFF_SA) { ⋮ 1877#if VERSION >= VERSION_JPN_FINAL 1878 g_AutoAimScale = 0.75f; 1879#else 1880 g_AutoAimScale = g_Jpn ? 1.1f : 0.75f; 1881#endif
src/game/lv.c lines 1867–1881 at 46d3393 · upstream ↗ 1884 } else if (g_Difficulty == DIFF_PA) { ⋮ 1897 g_AutoAimScale = g_Jpn ? 0.75f : 0.2f; 1898#endif
src/game/lv.c lines 1884–1898 at 46d3393 · upstream ↗ 1901 } else if (g_Difficulty == DIFF_PD) { ⋮ 1911 g_AutoAimScale = 1;
src/game/lv.c lines 1901–1911 at 46d3393 · upstream ↗ 53#if VERSION >= VERSION_PAL_BETA 54bool g_Jpn = VERSION == VERSION_JPN_FINAL ? true : false;
src/game/lang.c lines 53–54 at 46d3393 · upstream ↗ 66bool g_Jpn = false;src/game/lang.c line 66 at 46d3393 · upstream ↗ 2451 if (!g_Vars.normmplayerisrunning) { 2452 sp48 = sp48 * g_AutoAimScale;
src/game/prop.c lines 2451–2453 at 46d3393 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
Sources
Code
- Software, id. 2024. “DOOM: the Linux source release (id-Software/DOOM, linuxdoom-1.10).” Commit a77dfb9. id-Software/DOOM @ a77dfb9 · licence, all uses
- Software, id. 2012. “Quake II: the GPL source release (id-Software/Quake-2, 3.19).” Commit 372afde. id-Software/Quake-2 @ 372afde · licence, all uses
- Dwyer, Ryan and perfect-dark contributors. 2026. “perfect-dark: a decompilation of Perfect Dark (Ryan Dwyer).” Commit 46d3393. ryandwyer/perfect-dark @ 46d3393 · licence, all uses