ZDoom Damage and DPS Calculator
Compute exact damage range, expected DPS and time-to-kill for any ZDoom / GZDoom weapon or projectile. Includes the random(1,8) multiplier, STRIFEDAMAGE flag, and a tic-to-seconds converter for ACS scripts.
Damage range, DPS & tic converter for Doom modders.
Compute min/avg/max damage for any projectile, hitscan weapon or custom DamageFunction.
Damage formula
Uses Damage × random(1, 8) — the standard ZDoom projectile formula.
Pick a vanilla Doom projectile to autofill Damage. Editing Damage afterwards switches the preset back to Custom.
dmg
The N you put after Damage in DECORATE/ZScript (e.g. Damage 3 on the imp fireball).
Damage distribution
random(1, N) is uniform — every multiplier is equally likely.
| Damage per hit | Probability |
|---|---|
| 3 | 12.5% |
| 6 | 12.5% |
| 9 | 12.5% |
| 12 | 12.5% |
| 15 | 12.5% |
| 18 | 12.5% |
| 21 | 12.5% |
| 24 | 12.5% |
Vanilla projectile reference
Click a row to load it into the inputs above.
| Projectile | Damage | Multiplier | Min | Max | Avg | Speed (mu/tic) |
|---|---|---|---|---|---|---|
| Imp fireball — DoomImpBall | 3 | × random(1, 8) | 3 | 24 | 13.5 | 10 |
| Cacodemon ball — CacodemonBall | 5 | × random(1, 8) | 5 | 40 | 22.5 | 10 |
| Arachnotron plasma — ArachnotronPlasma | 5 | × random(1, 8) | 5 | 40 | 22.5 | 25 |
| Plasma rifle ball — PlasmaBall | 5 | × random(1, 8) | 5 | 40 | 22.5 | 25 |
| Baron of Hell / Hell Knight ball — BaronBall | 8 | × random(1, 8) | 8 | 64 | 36 | 15 |
| Mancubus fireball — FatShot | 8 | × random(1, 8) | 8 | 64 | 36 | 20 |
| Revenant tracer (homing) — RevenantTracer | 10 | × random(1, 8) | 10 | 80 | 45 | 10 |
| Rocket (direct hit) — Rocket | 20 | × random(1, 8) | 20 | 160 | 90 | 20 |
| BFG spray (per ray) | 67 | × 1..8 loop | 15 | 120 | 67.5 | — |
| BFG ball (direct hit) — BFGBall | 100 | × random(1, 8) | 100 | 800 | 450 | 25 |
DECORATE/ZScript snippet that reproduces these numbers.
ACTOR CustomProjectile : DoomImpBall{ Damage 3 // Min 3 Max 24 Avg 13.5 (× random(1, 8))}ZDoom damage calculator. Damage range, DPS and tics for Doom modders.
What is the ZDoom Damage and DPS Calculator?
How to calculate ZDoom damage, DPS and tic conversions (and how the calculator does it)
Damage, DPS and tic conversion — the engine formulas
- = Damage property from the DECORATE or ZScript actor's Default block (an integer)
- = Random multiplier bounds — 1 and 8 by default; 1 and 4 with +STRIFEDAMAGE; 1 and 3 for pistol/shotgun/chaingun pellets; 1 and 10 for fist/chainsaw
- = Tics per attack — the state-machine duration between consecutive fire calls in the actor's States block
- = Target HP — 20 for Zombieman, 60 for Imp, 400 for Cacodemon, 1000 for Baron of Hell, 3000 for Spider Mastermind, 4000 for Cyberdemon
- = DamageFactor multiplier — 1.0 normal, 0.5 resistance, 2.0 vulnerability, 0.0 invulnerable
- = Time in seconds — multiplied by TICRATE = 35 and rounded to integer tics for state durations and Delay() arguments
- = Travel distance in map units and projectile Speed in map units per tic; ceiling division gives tics because the engine moves in integer steps
Worked examples with the full math
Imp fireball vs Cacodemon — the default scenario
Pistol DPS against a Zombieman — "is the pistol really worthless"
Super shotgun on a Hell Knight — point-blank reality
BFG ball direct hit on a Cyberdemon (no spray)
ACS Delay math — "how many tics is 2.5 seconds"
ZDoom damage and balance tips for modders, mappers and curious players
- Read your actor's Damage property in expected-value terms, not literal-value terms. A projectile with Damage 5 averages 22.5 in-game (5 multiplied by 4.5), not 5. If your new monster's fireball is supposed to compete with the imp's 13.5-average fireball, set Damage 3 — not Damage 10. The #1 balance mistake in DECORATE is reading Damage 10 as "this hits for 10" when it actually hits for 10 to 80 with a 45 average.
- The +STRIFEDAMAGE flag is the lowest-overhead way to tighten a projectile's range. Same Damage value, max multiplier drops from 8 to 4, expected value drops from 4.5x to 2.5x. Useful when you want a predictable mid-range projectile (e.g. a custom rocket that should always feel like 60 to 240 instead of 60 to 480). It works on any actor in any ZDoom mod regardless of base game — the name comes from Strife (the engine's first non-Doom IWAD) but the flag itself is portable.
- Hitscan weapons ignore the Damage property entirely. Pistol, shotgun, chaingun, super shotgun all hardcode $5 \times \text{random}(1, 3)$ per pellet inside their A_FireBullets / A_FirePistol / A_FireShotgun calls. To raise a hitscan weapon's damage you change the pellet count, the A_CustomBulletAttack damage argument, or convert to projectile. The fist and chainsaw use $2 \times \text{random}(1, 10)$; the only way Berserk affects damage is on the fist, where it multiplies by 10 after the roll (so 20 to 200 per punch, expected 110).
- Tics per attack matters more than per-shot damage for DPS comparisons. The chaingun and the pistol have identical per-shot damage (5 to 15, expected 10), but the chaingun fires at ~4 tics per attack vs the pistol's ~14 — roughly 3.5x the DPS for the same per-pellet math. When balancing a weapon mod, decide DPS first (vanilla pistol ~25 DPS, shotgun ~70, super shotgun ~150, chaingun ~88, plasma ~263, rocket direct ~159), then back out the per-shot damage and the tics per attack that produce it.
- Use the 19-monster cheat-sheet to gut-check encounter design. Zombieman (HP 20), Shotgun Guy (30), Wolfenstein SS (50), Imp (60), Chaingunner (70), Lost Soul / Commander Keen (100), Demon / Spectre (150), Revenant (300), Pain Elemental / Cacodemon (400), Hell Knight / Arachnotron (500), Mancubus (600), Arch-vile (700), Baron of Hell (1000), Spider Mastermind (3000), Cyberdemon (4000). A super shotgun blast (expected 200, max 300) one-shots everything up to Revenant (HP 300) in the best case; Pain Elemental and Cacodemon (HP 400) need at least two best-case blasts. A pistol shot (expected 10) only one-shots a Zombieman. Designing a map's first encounter around a Demon vs a Mancubus is a 4x difficulty jump, not a 1.5x jump — the HP curve is geometric, not linear.
- GZDoom v3.2.2 (late 2017) and later guarantee that 35 tics equal exactly one second of real time. Earlier versions display a tic interval of 28 ms (so 35 tics show as 0.98 seconds) because of an integer-division truncation in the timer code. If your ACS Delay() math needs sub-second precision and you target a pre-late-2017 player base, account for the 2% drift — `Delay(35 * 60)` is 58.8 wall-clock seconds on the legacy timer, 1.2 seconds short of a full real-world minute.
- BFG spray is the one projectile that does not follow $\text{Damage} \times \text{random}(1, 8)$. Inside the A_BFGSpray function, the per-ray damage is computed as the sum of 15 independent random(1, 8) rolls — so range is 15 to 120, expected 67.5, distribution bell-shaped (not uniform). A BFG ball releases up to 40 rays in a 90-degree forward cone, so a full-coverage hit can stack 40 multiplied by 67.5 = 2700 expected damage on top of the ball's own 100 to 800. This is why a single BFG trigger pull can two-shot a Cyberdemon when both the direct ball and the spray cone connect.
- Map units have two conversion rates, not one. Horizontally, 16 map units equal one foot (0.3048 m); vertically, only 10 map units equal one foot because Doom's original 320x200 video mode stretched 20% vertically. For projectile speed conversions the calculator uses the horizontal ratio because projectiles travel along the map plane: Speed 10 (imp fireball) ≈ 6.67 m/s ≈ 15 mph; Speed 25 (plasma, BFG ball) ≈ 16.67 m/s ≈ 60 km/h ≈ 37 mph. Doomguy's running speed is around Speed 16 — about 24 mph, which is why imps occasionally outrun you in a corridor.
- DamageFactor handles resistance and vulnerability without rewriting your damage code. DamageFactor 'Fire', 0.5 on a monster halves all Fire-typed damage; DamageFactor 'Fire', 2.0 doubles it; DamageFactor 'Fire', 0 makes the monster fully immune. The calculator's DPS mode exposes a single scalar DamageFactor input so you can model the resistant case without a custom damage type — useful when you are comparing a vanilla weapon's TTK against, say, a Cacodemon variant with 0.7 plasma resistance.
- Range and worst-case numbers matter more than averages for survival math. "Expected shots-to-kill = 30" hides the fact that a Cacodemon can survive 134 imp fireballs in the pathological worst case. The calculator surfaces best/worst alongside expected for exactly this reason — when you are designing a slaughter map and an arena's monster has to die in a strict shot budget, you size to the worst case, not the expected. When you are designing a casual map, you size to the expected. The two numbers can differ by a factor of 5 to 10 for random(1, 8) projectiles.
ZDoom damage calculator — frequently asked questions
Why does my Damage 10 projectile hit for 80 sometimes?
ZDoom multiplies a projectile's Damage property by random(1, 8) on every hit. Damage 10 yields 10, 20, 30, 40, 50, 60, 70 or 80 — every value equally likely. Average is 45. The +STRIFEDAMAGE flag changes the multiplier to random(1, 4), giving 10, 20, 30 or 40 with an average of 25.
What is the formula for pistol damage in classic Doom?
The pistol uses 5 multiplied by random(1, 3) per shot, so each shot deals 5, 10 or 15 damage with an expected value of 10. The chaingun and the shotgun (per pellet) use the same formula. The Damage property on a hitscan actor is ignored — the formula is hardcoded inside A_FirePistol, A_FireShotgun and A_FireCGun.
How many tics is one second in ZDoom?
35 tics per second. TICRATE has been locked at 35 since the original 1993 release. GZDoom v3.2.2 and later guarantee that 35 tics equal exactly 1.000 seconds of real time; earlier versions truncated to 28 ms per tic so 35 tics displayed as 0.98 seconds — a 2% drift that only matters for long Delay() sequences.
How do I calculate ACS Delay() for X seconds?
Multiply seconds by 35 and round to an integer. 0.5 s = 18 tics, 1 s = 35 tics, 2 s = 70 tics, 5 s = 175 tics, 10 s = 350 tics, 60 s = 2100 tics. In ACS write Delay(35 * seconds) directly — the engine does the multiplication at compile time.
What does the +STRIFEDAMAGE flag do?
+STRIFEDAMAGE swaps the projectile damage multiplier from random(1, 8) to random(1, 4). Same Damage value, narrower range, lower average. It works on any actor in any ZDoom mod regardless of base game — the name comes from Strife but the flag is portable. Useful when you want a predictable mid-range projectile.
How much HP does a Cyberdemon have?
4000 HP. Cyberdemons take only direct damage — splash damage from rockets and Mancubus shots does nothing. The BFG9000 is the canonical kill (about 2 to 4 trigger pulls including spray); 20 expected super shotgun blasts at point-blank or ~45 expected rocket direct hits also do the job if you have the ammo. The calculator's 19-row monster table lists every vanilla Doom HP value.
Why is BFG damage so weird — what is the 15× loop?
The BFG main ball uses the standard formula (Damage 100 multiplied by random(1, 8) = 100 to 800), but the spray tracers do not. Each of up to 40 rays sums 15 independent random(1, 8) rolls, yielding 15 to 120 per ray with an average of 67.5. The Doom Wiki notes that pseudorandom-table determinism narrows the in-practice range to 49 to 87, but theoretical max remains 120 per ray.
Does this calculator work for ZScript actors too?
Yes. ZScript and DECORATE share the same Damage / DamageFunction / Speed / Health / +STRIFEDAMAGE semantics — they differ only in syntax. A ZScript actor with `Damage 5;` in its Default block rolls the exact same 5 multiplied by random(1, 8) formula as a DECORATE actor with the same property. The calculator's outputs apply to both.
Is the pistol really worthless?
No, but it is the worst weapon by DPS. Pistol expected DPS ≈ 25; chaingun ≈ 88 (same per-shot, three times the fire rate); shotgun ≈ 70; super shotgun ≈ 150; plasma rifle ≈ 263. The pistol two-shots Zombiemen and one-shots barrels — useful while you save shells. The moment you find a chaingun the pistol is a backup.
How accurate is this calculator vs the actual game?
Engine-exact for vanilla Doom and Doom II behavior under ZDoom / GZDoom. Engine cross-checks cover every projectile preset, every hitscan weapon, every monster HP value, and the BFG spray 15× loop — every damage range, monster HP and projectile speed matches the vanilla actor definitions to the unit. DECORATE / ZScript replacement actors, custom DamageFunction expressions and the modern Doom titles (2016, Eternal, The Dark Ages) use different math and are out of scope.
Why does the Revenant tracer deal 10 to 80, not 10 to 40?
RevenantTracer has Damage 10 in its actor block but does NOT carry the +STRIFEDAMAGE flag — it uses the default random(1, 8) multiplier. So its range is 10 to 80 with an expected value of 45, not 10 to 40. This is a common point of confusion because Revenant rockets feel like they should follow Strife-style math; they do not.
Does difficulty (UV / Nightmare) increase weapon damage?
No. Nightmare doubles monster aggression and ammo pickups, but weapon damage is identical across all five skill settings. The only damage multiplier that exists in vanilla Doom is the Berserk powerup, which multiplies fist damage by 10. Skill level changes who shoots first and how often, not how hard the shots hit.
Can I bookmark a specific damage scenario to share with another modder?
Yes. The selected mode is reflected in the URL query string (?mode=damage / dps / tics), so bookmarking the page restores that mode on the next visit. Inputs persist across reloads via localStorage, and the three modes — damage range, DPS / time-to-kill, and tic / speed conversion — share the same page so cross-mode lookups stay in one tab.
ZDoom damage and timing glossary
Damage property
A numeric property on a DECORATE or ZScript actor's Default block that the engine multiplies by random(1, 8) on every hit (random(1, 4) with +STRIFEDAMAGE). Setting Damage 10 produces an in-game range of 10 to 80, not a flat 10.
+STRIFEDAMAGE
An actor flag that changes the projectile damage multiplier from random(1, 8) to random(1, 4). Same Damage value, narrower range, lower average (Damage times 2.5 instead of Damage times 4.5). Works on any actor in any ZDoom mod regardless of base game.
tic
The atomic time unit of the Doom engine. TICRATE = 35 tics per second; 1 tic ≈ 28.5714 ms. State durations in DECORATE / ZScript and the argument to ACS Delay() are both expressed in tics. GZDoom v3.2.2+ guarantees 35 tics = exactly 1.000 seconds; earlier versions truncated at 28 ms.
Hitscan weapon
A weapon whose damage is resolved instantly along a straight line, no projectile actor involved. Pistol, shotgun, super shotgun and chaingun are hitscan; their damage formulas are hardcoded in their A_Fire* action functions (5 multiplied by random(1, 3) per pellet) and the Damage property on the actor is ignored.
DamageFactor
A multiplier on incoming damage of a specific damage type. DamageFactor 'Fire', 0.5 halves Fire damage; 2.0 doubles it; 0.0 makes the actor immune. The calculator's DPS mode exposes a single scalar DamageFactor input for the resistant / vulnerable cases.
Berserk
A powerup that multiplies fist damage by 10 after the random(1, 10) roll, yielding a 20 to 200 range with an expected value of 110. Only the fist gets the bonus; chainsaw, hitscan and projectile weapons are unaffected.
Map unit
Doom's spatial coordinate unit. 16 horizontal map units = 1 real-world foot = 0.3048 m, by Doom community consensus (Doomguy is 56 vertical units tall = 5 feet 7 inches). The calculator converts projectile Speed (map units per tic) to m/s, km/h and mph using the 16-mu-per-foot horizontal ratio.
Speed property
A projectile actor's velocity in map units per tic. Imp fireball Speed 10; rocket Speed 20; plasma ball and BFG ball Speed 25. Multiply by 35 to get map units per second; multiply by 0.667 to get meters per second; multiply by 1.49 to get mph.
BFG spray
The 40-ray cone the BFG ball releases on impact (the spray fires from the ball's death state via A_BFGSpray). Each ray's damage is the sum of 15 independent random(1, 8) rolls, yielding 15 to 120 per ray with an expected value of 67.5. The BFG's reputation for one-shotting Cyberdemons is the spray's doing, not the main ball's.
TICRATE
The engine constant locking Doom's frame rate at 35 tics per second since 1993. Defined in id Software's doomdef.h; preserved exactly by ZDoom, GZDoom, Zandronum, Boom, MBF21 and every other vanilla-compatible source port. Every state duration, every Delay() argument, every projectile travel-time computation uses 35 as the conversion constant.
DamageFunction
An alternative to the Damage property that lets a modder return a custom integer at hit time via a ZScript expression. Bypasses the random(1, 8) multiplier — return a flat number for deterministic damage, or compute it from the inflictor / target / distance for context-sensitive behavior.
Content verified by the Smart Calculators Team