Missiles.txt defines every projectile type in D2R: arrows, javelins, spell projectiles, sub-missiles spawned in flight or on impact, AoE clouds, and explosion effects. 736 rows across 172 columns (147 carry data; the 25 columns whose names start with * are inline annotation comments). skills references rows here by name (via columns like Missile, Missile2, SrvMissile) to specify which projectile a skill fires; the relationship is one-way — a skill points at a missile, the missile has no back-reference.
This table matters for rigorous "frames-to-damage" analysis. The clock on many caster skills starts when the missile is created, not when the player finishes the casting animation. Range (lifetime in frames) and Vel (pixels per frame) together determine how long before the projectile reaches its target.
Architecture: function pointers + numeric inputs
The missiles table uses a function-pointer dispatch model. Each row selects numbered engine routines for server-side and client-side behavior:
| Function-pointer column | Role |
|---|---|
pSrvDoFunc | Per-frame server behavior while the missile is alive. Movement, sub-missile spawning, homing. |
pSrvHitFunc | Server behavior on collision — deals damage, creates AoE effects, spawns follow-on missiles. |
pSrvDmgFunc | Server damage transformation invoked before the unit is damaged (rarely set; used for Holy Bolt's faction modifier, Blessed Hammer's undead/demon multipliers, etc.). |
pCltDoFunc | Per-frame client behavior — visual particle trails, flight animation, client-side sub-missiles. |
pCltHitFunc | Client-side collision behavior — visual hit effects and overlays. |
Each function code is a small integer that selects a hard-coded engine routine. Numeric inputs to the chosen routine live in paired columns: SrvCalc1 / Param1–5 (server-do), SHitCalc1 / sHitPar1–3 (server-hit), CltCalc1 / CltParam1–5 (client-do), CHitCalc1 / cHitPar1–3 (client-hit), DmgCalc1 / dParam1–2 (server-damage). The 25 *param1 desc columns next to each parameter hold a one-line annotation of what that parameter means for that row — they have no engine effect.
Identity
| Column | Meaning |
|---|---|
Missile | Unique name. Primary lookup key. Referenced by skills.txt via Missile, Missile2, SrvMissile, and by calc-DSL expressions like miss('abysscenter'.par1). Row order determines each missile's numeric ID; rows must not be reordered. |
*ID | Numeric missile ID (annotation column, equal to row order). Used by DSL expressions and engine internals. |
Velocity, lifetime, visibility
| Column | Meaning |
|---|---|
Vel | Launch speed in pixels per frame (25 fps). |
MaxVel | Speed cap. When Accel = 0, the missile travels at Vel for its full life. With Accel > 0, velocity grows each frame until it reaches MaxVel. |
VelLev | Extra velocity per caster level beyond level 1. |
Accel | Acceleration per frame. Positive = speeds up, negative = slows down. |
Range | Lifetime in frames (25 frames = 1 second). How long the missile lives before expiring if it has not hit anything. |
LevRange (file column Radius) | The file column in this slot is named Radius (locbones documents it as LevRange). Empirically, values match an AoE hit radius in sub-tiles — sigil missiles use 4 / 6 / 8 (small / medium / large), Warlock's Abyss family uses calc-DSL expressions like par3+(sksrc('Enhanced Entropy'.blvl)/par5). Empty for standard projectiles, whose AoE on impact is set by pSrvHitFunc parameters (sHitPar1) instead. |
InitSteps | Frames the missile must be alive before becoming visible to the client. Below this count the missile renders as invisible. Used by 274 rows for delayed-emergence effects. |
Activate | Frames the missile must be alive before it can collide. Below this, the missile passes through targets. Used by 9 rows. |
Collision and hit-class
| Column | Meaning |
|---|---|
CollideType | What the missile can collide with. 0 = nothing; 1 = players only; 2 = monsters only; 3 = players and monsters; 4 = nothing (duplicate); 5 = monsters (duplicate); 6 = barriers like doors; 7 = other missiles; 8 = players, monsters, barriers, and walls. Empty is treated as 0. The values that actually appear in shipping data are 1, 3, 6, 8, and empty. |
CollideKill | 1 = missile is destroyed on first collision. 0 = missile persists through collisions (piercing missiles, persistent clouds). |
CollideFriend | 1 = missile can hit friendly units, including the caster. |
Collision | 1 = missile has its own placement collision mask in the world (the engine treats it as a movable obstacle). |
ClientCol | 1 = client-side collision check, gated by CollideType. |
NextHit / NextDelay | When NextHit = 1, the missile cannot hit the same unit again for NextDelay frames. Prevents per-frame stacking on rapid-fire missiles. |
Explosion | 1 = missile is classified as an explosion; uses different nearby-unit search handlers when dealing damage. |
AlwaysExplode | 1 = missile always fires the explosion sequence on death (triggering pSrvHitFunc, HitSound, ExplosionMissile), regardless of whether it made a valid collision. |
ToHit | 1 = missile uses the caster's Attack Rating to determine if it lands. 0 = always hits on collision. |
Pierce | 1 = missile is eligible for the Pierce mechanic (Amazon passive, Pierce-affix items). |
KnockBack | Percentage chance (0–100, not a boolean) that the struck unit is knocked back. |
GetHit | 1 = struck unit enters hit-recovery animation (GH mode). |
Size | Diameter in sub-tiles (X and Y axes) that the missile occupies for collision. |
HitClass | Numeric bitfield controlling which hit sound and hit overlay the engine plays on collision — see the table below. Unrelated to the hitclass lookup table, which is for weapon-class animation tokens. |
HitClass bitfield codes
| Value | Layer |
|---|---|
| 16 | Double Layer |
| 32 | Fire Layer |
| 48 | Cold Layer |
| 64 | Lightning Layer |
| 80 | Poison Layer |
| 96 | Stun Layer |
| 112 | Bash Layer |
| 128 | Thorns Layer |
| 144 | Sanctuary Layer |
| 160 | Silent Voice Layer |
| 176 | Goo Layer |
Values are added together for missiles that should fire multiple layers (e.g. fire + stun = 32 + 96 = 128).
Sub-missile chains
| Column | Meaning |
|---|---|
SubMissile1/2/3 | Missiles spawned during flight, by pSrvDoFunc. The exact trigger (per-frame, per-interval, at a specific frame) is controlled by the function code, not this field. |
HitSubMissile1/2/3/4 | Missiles spawned on collision, by pSrvHitFunc. The primary mechanism for "explosion on impact" patterns. |
ExplosionMissile | Client-side missile spawned when this missile explodes or expires. Visual only. |
CltSubMissile1/2/3 | Client-only counterparts to SubMissile1–3. Visual particle trails — no game-damage effect. |
CltHitSubMissile1/2/3/4 | Client-only counterparts to HitSubMissile1–4. Visual hit effects only. |
MissileWeaponVFX | D2R-era column. Used by 3 rows (bladewarp, bladewarpexplode, echoingstrike) to attach a weapon visual effect. Empty for everything else. |
Damage
Most spell missiles carry 0 in MinDamage/MaxDamage and empty EMin/EMax — their damage flows from the linked skill. Two mechanisms connect missile to skill damage:
MissileSkill = 1— the missile looks up the skill that created it and uses that skill's damage in place of its own.Skill = <skill name>— the missile binds to a specific skill row inskills.txtfor damage values regardless of which skill spawned it.
| Column | Meaning |
|---|---|
MinDamage / MaxDamage | Base physical min/max damage. |
MinLevDam1–5 / MaxLevDam1–5 | Per-level physical damage increments across five level bands (levels 2–8, 9–16, 17–22, 23–28, 29+). |
HitShift | Damage modifier in 256ths, capped 0–8. The values are exponential, not linear: 8 = 256/256 (100%), 7 = 128/256 (50%), 6 = 64/256 (25%), 5 = 32/256 (12.5%), 4 = 16/256 (6.25%), 3 = 8/256 (3.13%), 2 = 4/256 (1.56%), 1 = 2/256 (0.78%), 0 = 1/256 (0.39%). Most spell missiles use 8. |
EType | Elemental damage type. Values seen: fire, cold, ltng, pois, mag, burn (open wounds-style burn), frze (cold-aura freeze). Empty = physical only. |
EMin / EMax | Base elemental min/max damage. |
MinELev1–5 / MaxELev1–5 | Per-level elemental damage increments (five-band, same thresholds as physical). |
ELen | Base elemental duration in frames. Relevant for poison (damage tick window), cold (chill/freeze length). |
ELevLen1–3 | Per-level duration increments across three bands (levels 2–8, 9–16, 17+). |
SrcDamage | Fraction of the caster's weapon damage added to the missile, in 128ths (128 = 100%). -1 or 0 = no weapon damage contribution. |
Half2HSrc | 1 = if SrcDamage is set and the caster wields a 2-handed weapon, halve the contribution. |
SrcMissDmg | Fraction (in 128ths) of the parent missile's damage carried over to a sub-missile. |
ApplyMastery | 1 = elemental mastery bonuses (Sorceress Fire/Cold/Lightning Mastery) apply to this missile's elemental damage. |
Special flags
| Column | Meaning |
|---|---|
Holy | Bitfield restricting which monster types this missile can damage. 0 = all units; 1 = undead only; 2 = demons only; 4 = beasts only. |
CanSlow | 1 = missile is affected by the slowmissiles state. |
Town | 1 = missile can exist in town areas. 0 = destroyed immediately when entering town. |
NoUniqueMod | 1 = missile does not pick up bonuses from the caster monster's unique modifiers. |
NoMultiShot | 1 = missile is not duplicated by the Multi-Shot monster mod. |
D2R-era function-code extensions
Locbones documents pSrvDoFunc 0–37, pCltDoFunc 0–68, pSrvHitFunc 0–59, and pCltHitFunc 0–64. The shipping D2R data uses values beyond those ranges:
| Column | locbones max | Data max |
|---|---|---|
pSrvDoFunc | 37 | 45 |
pCltDoFunc | 68 | 76 |
pSrvHitFunc | 59 | 60 |
pCltHitFunc | 64 | 65 |
The high codes back D2R-era content (Reign of the Warlock skills, post-LoD additions). Treat them as opaque engine routines — the shape of their parameter columns is documented case-by-case via the *param1 desc annotations on the rows that use them.
Cross-references
- skills — links missile names via
Missile,Missile2,SrvMissile. The skill's calc fields and elemental damage flow into the missile whenMissileSkill = 1or the missile'sSkillfield names that skill. - skilldesc —
descmissile1/2/3references missiles as inputs to tooltip calc formulas (miss('abysscenter'.par1)). - hitclass — unrelated to
missiles.HitClass. That table is for weapon-class animation tokens; the bitfield documented above is the elemental-layer system.
Worked example: Poison Javelin
Poison Javelin (an Amazon javelin skill) shows the missile-and-cloud pattern that almost every "trail" caster uses.
The skill fires poisonjav (the visible javelin shot). While in flight, the javelin spawns one poisonjavcloud per frame as a SubMissile1. The cloud sits stationary for its Range lifetime and damages anything that walks into it.
Where does the damage come from? Neither row carries elemental fields directly:
| Field | poisonjav | poisonjavcloud |
|---|---|---|
pSrvDoFunc | 2 (MissileDoPoisonJavelin) | 3 (StillMissileKludge — stationary) |
Vel | 24 px/frame | empty (stationary) |
Range | 25 (1 second) | 60 (2.4 seconds) |
SubMissile1 | poisonjavcloud | (empty) |
EType | (empty) | (empty) |
EMin / EMax | (empty) | (empty) |
Skill | (empty) | Poison Javelin |
The cloud's Skill = Poison Javelin field binds it back to the skills row, and the per-tick poison damage is read from there. This is the standard skill-bound carrier pattern: the missile rows control timing and shape, but damage values live in skills.txt.
-- Inspect the javelin → cloud chain
SELECT Missile, pSrvDoFunc, Vel, Range, SubMissile1, Skill
FROM missiles
WHERE Missile IN ('poisonjav', 'poisonjavcloud')
ORDER BY Missile;
-- Find every missile that binds back to a skill (carrier-pattern missiles)
SELECT Missile, pSrvDoFunc, Range, Skill
FROM missiles
WHERE Skill != ''
ORDER BY Skill, Missile
LIMIT 25;