Puff

From ZDoom Wiki
Jump to navigation Jump to search

Puffs are actors spawned by hitscan attacks when the attack hits something: usually map geometry (wall/floor/plane), but in certain conditions they can also spawn when hitting actors.

Hitscan attacks encompass bullet attacks (fired by functions like A_FireBullets), railgun attacks (such as A_RailAttack) and melee attacks (such as A_CustomPunch).

Puffs have a few purposes:

  • Modifying hitscan behavior. While when using projectiles things like damage types or flags like EXTREMEDEATH would be defined in the projectile, in case of hitscan attacks all of these definitions must be attached to the puff. Puffs can also use the DoSpecialDamage virtual function, like projectiles.
  • Visuals. Puffs make hitscan attacks more interesting by creating a visual effect when hitting something. For example, in Doom bullet weapons will spawn a puff of smoke when hitting geometry. This effect can be expanded to make a puff spawn some extra visuals, like dynamic smoke effects, particles, sparks, etc.
  • Sounds. Puffs can play different sounds depending on what they hit, which can provide nice audio feedback, especially for melee attacks.

There's a misconception that creating new puffs requires inheriting from BulletPuff. In reality, there's no special "puff" class. A puff is just an actor; it starts acting as a puff automatically when it's used by the appropriate attack functions. There are no special flags or properties that have to be given to the Actor in order for it to be useable as puff. In fact, even classes that aren't designed to be puffs, like items or monsters, can still be used as puffs and will spawn at the points where the attack hits.

Most of the time puffs don't need any collision and will use NOBLOCKMAP and NOGRAVITY. NOINTERACTION is usually possible as well, although it may sometimes cause weird positioning of the puff on top of floor/ceiling planes.

Puff usage and behavior

To become a puff, an actor must be spawned with the SpawnPuff function, or any of the hitscan-firing functions such as A_FireBullets. When spawned this way, these actors get the following properties:

  • They get the ISPUFF flag, and the the actor's DamageSource field will contain a pointer to the actor responsible for spawning the puff.
  • They will pass their properties such as DamageType and damage-related flags (such as EXTREMEDEATH, FORCEPAIN and others) to the attack.
  • They can utilize VSpeed property to automatically float upwards when they spawn.
  • Puffs may be replaced by particles when spawned if the ALLOWPARTICLES flag is set (and the player has the appropriate option enabled in their configuration settings).
  • Most importantly, puffs will automatically utilize special sounds and special states in their behavior.

Puff states and flags

Puffs have deceptively complex behavior when it comes to picking states. This behavior is tied to several aspects:

1. Bullets - fired by LineAttack, A_FireBullets, A_CustomBulletAttack or built-in functions based on those (like A_FirePistol)
2. Rails - fired by RailAttack, A_RailAttack or A_CustomRailgun
3. Melee - performed by A_CustomPunch, A_CustomMeleeAttack or similar
Puff state entered
Bullet attack Rail attack Melee attack
No flags ALWAYSPUFF PUFFONACTORS No flags ALWAYSPUFF PUFFONACTORS No flags ALWAYSPUFF PUFFONACTORS
Hit a shootable non-bleeding actor
(Non-bleeding requires one of the flollowing flags:
NOBLOOD, INVULNERABLE, DORMANT.)
Spawn Spawn Spawn Spawn Spawn Spawn Melee Melee Melee
Hit a shootable bleeding actor none none XDeath none XDeath none Melee
(animation isn't played,
pointers aren't obtained)
Melee
(animation isn't played,
pointers aren't obtained)
XDeath
Hit geometry Crash (if present) Crash (if present) Crash (if present) none Crash (if present) none Crash (if present) Crash (if present) Crash (if present)
Hit nothing (If the attack has limited range and ends in the air.
Normally this happens with melee attacks, but hitscan/railgun
also can have a limited range specified.)
none Crash (if present) none none none none none Crash (if present) none

Note:

  • If Crash of XDeath states are supposed to be entered but aren't defined in the puff, Spawn will be used instead.
  • ALWAYSPUFF and PUFFONACTORS can be combined. For bullets and nelee attacks it means that the puff will be able to both enter XDeath when hitting a bleeding actor, and Crash will be used when hitting nothing.
  • For rail attacks ALWAYSPUFF functions the same way as PUFFONACTORS for other attacks, while PUFFONACTORS has no effect on them. It's also not possible to force rail puffs to trigger when hitting nothing.
  • Even when the puff gets replaced by blood (which is the default behavior when an attack hits a bleeding actor), it'll still call its DoSpecialDamage virtual.

Puff sounds

Puff can also play SeeSound, AttackSound or ActiveSound under certain conditions:

Puff sound played
Bullet attack Rail attack Melee attack
No flags ALWAYSPUFF PUFFONACTORS No flags ALWAYSPUFF PUFFONACTORS No flags ALWAYSPUFF PUFFONACTORS
Hit a shootable non-bleeding actor
(Non-bleeding requires one of the flollowing flags:
NOBLOOD, INVULNERABLE, DORMANT.)
SeeSound SeeSound SeeSound SeeSound SeeSound SeeSound SeeSound SeeSound SeeSound
Hit a shootable bleeding actor none none SeeSound none SeeSound none none none SeeSound
Hit geometry AttackSound AttackSound AttackSound none AttackSound none AttackSound AttackSound AttackSound
Hit nothing (If the attack has limited range and ends in the air.
Normally this happens with melee attacks, but hitscan/railgun
also can have a limited range specified.)
none AttackSound none none none none ActiveSound AttackSound AND ActiveSound ActiveSound

Note that sounds don't follow any fallback rules, in contrast to states: if a specific sound isn't defined, it simply won't play; no different sound will be used instead.

Puff pointers

Puffs can utilize actor pointers under the following conditions:

  • By default, a puff will have a readonly DamageSource pointer to the actor responsible for the attack that spawned the puff. Prior to 4.13.0, puffs did not get any pointers by default at all.
  • With PUFFGETSOWNER flag, the puff will have a target pointer to the actor responsible for the attacked (similar to projectiles).
  • Puffs, just like projectiles, utilize the DoSpecialDamage virtual function, which can be overridden to add special behavior. Within the context of that function, the puff will have a local victim pointer to the actor it hit.
  • HITTRACER/HITMASTER/HITTARGET flags will write a pointer to the actor hit by the attack to the puff's tracer/master/target field respectively.

Further customization

There are several extra features that can be utilized on puffs:

  • Using the PUFFONACTORS will make the puff respect the three HIT* flags (HITTRACER, HITTARGET and HITMASTER): this allows performing thigs with the actor that was hit using the obtained pointer (with HITTRACER it'll be tracer) and one of the states entered when the attack hits an actor (such as Melee).
  • Using PUFFGETSOWNER flag will set whoever used the attack as the target of the puff, which allows performing conditional checks and such based on the shooter's class and properties.
  • The hitscan attack can be made to pass through certain actors when using flags like MTHRUSPECIES, THRUGHOST and such.

Note that puffs are spawned so as to face the originator of the attack.

See also