The damage effect tag determines the results of damage application in a wide range of use cases, including but not limited to: projectile impacts, detonations, melee attacks, falling, and vehicle collisions. They can be part of an effect.

A damage effect is not strictly about applying shield and health damage to units; these tags can have an area of effect, impart acceleration on additional objects like items and projectiles too, and cause screen effects like colour flashes and shaking.

Bleedthrough

When damage to shields exceeds the currently shield vitality, damage carries over to health. When this occurs, the damage multiplier of the shields still carries over to the health damage. This even occurs if the current shield vitality is 0. The result is that the initial carryover health damage may be higher than expected with weapons like the plasma rifle, which have a 2x shield multiplier. Subsequent shots will impact the body and use its material type modifiers instead.

Impact damage formula

When applying a damage_effect as a projectile impact, the game may take projectile fields into account as well. When air or water damage ranges are set, the projectile's travel distance will scale damage between damage lower bound and a random selection between upper bounds. If air damage range is not set, it always uses the random high bound.

Firstly, the game randomly picks a value between the two upper bounds (will always be the same if both values are the same). Up to the projectile minimum air damage range, 100% unmodified damage is applied. However, past the minimum and up to the maximum damage ranges, damage linearly scales to the lower bound. Past this distance, the projectile disappears (but does not detonate).

In pseudocode, and assuming within max range:

//falloff is 0 to 1 based on travel distance between air damage ranges
let falloff = max(0,
  (travel_distance - air_damage_min) /
  (air_damage_max - air_damage_min)
);

//given a random_value between 0 and 1, interpolate between the two high bounds
let upper_bound_delta = upper_bound_2 - upper_bound_1;
let random_upper_bound = upper_bound_1 + random_value * upper_bound_delta;

//interpolate between lower and random upper bound
let raw_damage = (
  falloff * lower_bound +
  (1.0 - falloff) * random_upper_bound
);
//finally, damage is scaled by the multiplier for the impacted material
let damage_done = material_damage_multiplier * raw_damage;

Or, more visually:

Diagram of damage falloff for the shotgun

Related HaloScript

The following are related functions that you can use in your scenario scripts and/or debug globals that you can enter into the developer console for troubleshooting.

Function/global

Type

(ai_print_damage_modifiers [boolean])

When an encounter is selected, damage modifiers are logged at the bottom of the screen.

Global
(cheat_reflexive_damage_effects [boolean])

Any damage_effect applied to other characters, even dead ones, will appear on the player's screen regardless of who applied the damage. For example, if an Elite shoots a flood infection form, the player will see their screen flash blue and damage direction indicators appear. The player takes no actual damage. This can be helpful for testing visual effects.

Global
(debug_damage [boolean])

When enabled, looking at any collideable object and pressing Space will display the object's body and shield vitalities on the HUD.

Global
(debug_damage_taken [boolean])

Logs damage to the player as messages at the bottom of the screen. Includes body and shield vitality and the damage source.

Global
(rasterizer_screen_flashes)

Toggles the display of screen flashes, such as those from a damage_effect or powerup equipment.

Global

Structure and fields

FieldTypeComments
radiusBounds
  • Unit: world units

The minimum radius determines the sphere in which damage is 100% of damage upper bound. Damage fades linearly to damage lower bound at the maximum radius. Outside the maximum radius, 0 damage is dealt. The aoe core radius field does not affect this calculation.

FieldTypeComments
minfloat
maxfloat
cutoff scalefloat
  • Min: 0
  • Max: 1
flagsbitfield
FlagMaskComments
do not scale damage by distance0x1
typeenum
OptionValueComments
none0x0
lighten0x1
darken0x2
max0x3
min0x4
invert0x5
tint0x6
priorityenum
OptionValueComments
low0x0
medium0x1
high0x2
durationfloat
  • Unit: seconds
fade functionenum
OptionValueComments
linear0x0
early0x1
very early0x2
late0x3
very late0x4
cosine0x5
maximum intensityfloat
  • Min: 0
  • Max: 1
  • Default: 1
colorColorARGB
FieldTypeComments
alphafloat
redfloat
greenfloat
bluefloat
low frequency vibrate frequencyfloat
  • Min: 0
  • Max: 1
low frequency vibrate durationfloat
  • Unit: seconds
low frequency vibrate fade functionenum?
high frequency vibrate frequencyfloat
  • Min: 0
  • Max: 1
high frequency vibrate durationfloat
  • Unit: seconds
high frequency vibrate fade functionenum?
temporary camera impulse durationfloat
  • Unit: seconds
temporary camera impulse fade functionenum?
temporary camera impulse rotationfloat
temporary camera impulse pushbackfloat
  • Unit: world units
jitterBounds?
  • Unit: world units
permanent camera impulse anglefloat
camera shaking durationfloat
  • Unit: seconds

Controls how long camera shaking lasts. In H1CE and H1CE, short camera shakes (0.05) get skipped occasionally at high FPS since this feature is still tied to frame rate. This is fixed and interpolated by Chimera and by H1A natively.

camera shaking falloff functionenum?
camera shaking random translationfloat
  • Unit: world units
camera shaking random rotationfloat
camera shaking wobble functionenum
OptionValueComments
one0x0
zero0x1
cosine0x2
cosine variable period0x3
diagonal wave0x4
diagonal wave variable period0x5
slide0x6
slide variable period0x7
noise0x8
jitter0x9
wander0xA
spark0xB
camera shaking wobble periodfloat
  • Unit: seconds
  • Default: 1
camera shaking wobble weightfloat
soundTagDependency: sound
breaking effect forward velocityfloat
  • Unit: world units per second
breaking effect forward radiusfloat
  • Unit: world units
breaking effect forward exponentfloat
breaking effect outward velocityfloat
  • Unit: world units per second
breaking effect outward radiusfloat
  • Unit: world units
breaking effect outward exponentfloat
damage side effectenum
OptionValueComments
none0x0
harmless0x1
lethal to the unsuspecting0x2
emp0x3

Completely depletes target units' energy shields, no matter their amount.

damage categoryenum
OptionValueComments
none0x0
falling0x1
bullet0x2
grenade0x3
high explosive0x4
sniper0x5
melee0x6
flame0x7
mounted weapon0x8
vehicle0x9
plasma0xA
needle0xB
shotgun0xC
damage flagsbitfield
FlagMaskComments
does not hurt owner0x1
can cause headshots0x2

If enabled, any headshot against an unshielded enemy will kill it regardless of the amount of damage inflicted. Even a 1-damage pistol still instantly kills a Hunter because of this flag. It is an instant kill even if the shield threshold is met with a headshot (after shields have been reduced to 0 by the damage effect but health is full). For example, even though the pistol deals 25 damage and players have 75 shield vitality, if the final shot is a headshot the player dies. Although there is also a can cause multiplayer headshots flag, it has a separate meaning and this flag applies to both SP and MP. A model's headshot area is determined by its head region.

pings resistant units0x4
does not hurt friends0x8
does not ping units0x10
detonates explosives0x20

If enabled, causes the effect to trigger the explosion of dropped grenades within its radius, used for explosion chaining. This only applies to maps loaded in singleplayer mode. Note that the item receiving damage (e.g. the grenade equipment) must also have its destroyed by explosions flag enabled. If the grenade has been placed within the scenario in Sapien, the does accelerate flag will also need to be checked in the properties window.

only hurts shields0x40
causes flaming death0x80
damage indicators always point down0x100
skips shields0x200
only hurts one infection form0x400
can cause multiplayer headshots0x800

Applies a 2x damage multiplier to headshots in multiplayer (based on how the map was loaded, not scenario type). This multiplier stacks with material modifiers below, so for example a cyborg armor modifier of 2 with this flag enabled results in a 4x headshot damage modifier. A model's headshot area is determined by its head region.

infection form pop0x1000
damage aoe core radiusfloat
  • Unit: world units

Objects within this radius will be damaged regardless of obstructions in the BSP. Outside this radius, there must be a line of sight between the effect and target. Contrary to the Guerilla tooltip, this field does not determine if the damage has an area of effect; see radius.

damage lower boundfloat

Sets the minimum amount of damage done when this effect is applied in a scaled way. For example, projectiles can have min and max damage ranges for air and water.

damage upper boundBounds?

Maximum damage will be randomly chosen from this range.

damage vehicle passthrough penaltyfloat
damage active camouflage damagefloat
damage stunfloat
  • Min: 0
  • Max: 1
damage maximum stunfloat
  • Min: 0
  • Max: 1
damage stun timefloat
  • Unit: seconds
damage instantaneous accelerationfloat

Controls how much moveable objects are accelerated by this effect. This is scaled by the acceleration scale field of object.

dirtfloat
sandfloat
stonefloat
snowfloat
woodfloat
metal hollowfloat
metal thinfloat
metal thickfloat
rubberfloat
glassfloat
force fieldfloat
gruntfloat
hunter armorfloat
hunter skinfloat
elitefloat
jackalfloat
jackal energy shieldfloat
engineer skinfloat
engineer force fieldfloat
flood combat formfloat
flood carrier formfloat
cyborg armorfloat

Also labeled as simply cyborg in Guerilla. Used to modify damage on all body parts of the cyborg (spartan) biped.

cyborg energy shieldfloat

Damage modifier for the "cyborg energy shield" material type. See the shield material type field of the unit's model_collision_geometry tag.

human armorfloat
human skinfloat
sentinelfloat
monitorfloat
plasticfloat
waterfloat
leavesfloat
elite energy shieldfloat

Damage modifier for the "elite energy shield" material type. See the shield material type field of the unit's model_collision_geometry tag. Note that this field receives a hard-coded singleplayer adjustment at map compile time for the pistol's damage effect.

icefloat
hunter shieldfloat

Acknowledgements

Thanks to the following individuals for their research or contributions to this topic:

  • Conscars (Checking multiplayer headshot flag and radii behaviour)
  • gbMichelle (Reverse engineering the damage formula)
  • Kavawuvi (Invader tag definitions)
  • King Feraligatr (Testing EMP effect on shields)
  • Mortis (Explaining headshot damage and bleedthrough)
  • MosesOfEgypt (Tag structure research)