WorldHitscanPreFired
bool WorldHitscanPreFired (WorldEvent e) (New from 4.14.0)
Usage
An event handler virtual function that is called before a hitscan attack is fired in the level. This event can be used to block hitscan attacks from happening and potentially replace them with something else, such as projectiles.
Note: This event is triggered by "bullet" hitscan attack function, such as LineAttack() or any of its derivatives. However, it's NOT triggered by "railgun" functions such as RailAttack(); for a similar railgun-related function see WorldRailgunPreFired.
Passed values
This event gets a pointer to the WorldEvent struct, and can read certain fields from it preceding the value with e.
. Since this event was designed to be hooked into hitscan attack functions, the fields are mostly the same as the arguments of hitscan-firing functions such as LineAttack or A_FireBullets, and the values passed to those fields are passed directly from those attack functions:
- Actor thing
- A pointer to the actor who fired the attack.
- angle AttackAngle
- The absolute horizontal angle offset at which the attack was fired, as passed from the attack function. To convert this to a relative angle, subtract
e.thing.angle
from this value.
- angle AttackPitch
- The vertical angle offset at which the attack was fired, as passed from the attack function.
- double AttackDistance
- The maximum range of the the attack, as passed from the attack function. For reference, player attacks by default use PLAYERMISSILERANGE (8192) and monster attacks use MISSILERANGE (2048), but all hitscan functions allow specifying a custom distance.
- int damage
- The damage the hitscan attack should deal. Note, this is the value after all randomization has been applied to it by the function, if any (for example, by default A_FireBullets multiplies its damage by random(1, 3)), but before any other special handling, such as damage types, the puff calling its DoSpecialDamage and such.
- Name damageType
- The damage type applied to the attack (either through its arguments or a custom puff).
- int AttackLineFlags
- The flags passed from the attack function. These are the same as the LineAttack() flags:
- LAF_ISMELEEATTACK — enables, but does not force, the puff to enter its Melee state if it has it.
- LAF_NORANDOMPUFFZ — disables the random z offset given to the puff when spawned.
- LAF_NOIMPACTDECAL — disables the generation of decals as a result of the attack.
- LAF_NOINTERACT — guarantees puff spawning and returns it directly to the calling function. Damage is not inflicted, sounds are not played, and blood splatters are not spawned.
- LAF_TARGETISSOURCE — the calling actor's target is considered the source of the damage, otherwise it is the calling actor itself.
- LAF_OVERRIDEZ — disregards the default calculations for the height at which the attack is fired, and instead fires it from the base of the actor, only taking offsetz into account.
- LAF_ABSOFFSET — the forward/side offset parameters will not be rotated by the angle value, instead aligning to the global X/Y axes (they will still be offsets from the actor's position, however).
- LAF_ABSPOSITION — the offset parameters will be treated like global map position, not relative to the actor's current position. (Clarificaton needed: Does this imply LAF_ABSOFFSET?)
- class<Actor> AttackPuffType
- The puff class used by the attack.
- double AttackZ
- Vertical offset of the attack from the shooter's origin. Corresponds to the offsetz argument of LineAttack().
- double AttackOffsetForward
- Forward offset of the attack from the shooter's origin. Corresponds to the offsetforward argument of LineAttack().
- double AttackOffsetSide
- Side offset of the attack from the shooter's origin. Corresponds to the offsetside argument of LineAttack().
Return value
- bool — returning
true
will block the attack from happening (note, this will not prevent anything else that might normally be tied to the attack, such as ammo consumption, sounds, etc.). By default returnsfalse
.
Examples
This event handler will replace all hitscan attacks by PlasmaBall projectiles. Note, it uses slightly different handling depending on whether the shooter was a player or a monster:
class HitscanOverrideHandler : EventHandler
{
override bool WorldHitscanPreFired(WorldEvent e)
{
// If the shooter is a player, use SpawnPlayerMissile.
// Modify the player's pitch temporarily to implement
// attack pitch (just like A_FireProjectile does it),
// and pass the other values to their respective arguments:
if (e.thing.player)
{
double savedPitch = e.thing.pitch;
e.thing.pitch = e.AttackPitch;
e.thing.SpawnPlayerMissile('Plasmaball',
angle: e.AttackAngle,
x: e.AttackOffsetSide,
z: e.AttackZ);
e.thing.pitch = savedPitch;
}
// For monsters, just pass values to A_SpawnProjectile.
// CMD_AIMDIRECTION is required here to prevent the
// function from automatically aiming at the monster's
// current target. Note, we also need to subtract
// e.thing.angle from e.AttackAngle, since the latter is
// absolute:
else
{
e.thing.A_SpawnProjectile('Plasmaball',
angle: e.AttackAngle - e.thing.angle,
pitch: e.AttackPitch,
flags: CMF_AIMDIRECTION);
}
return true;
}
}