DamageFunction
DamageFunction is an Actor property that serves as an alternative to the Damage property and allows adding entirely custom behavior for calculating the damage that a projectile would deal.
Warning: An actor can utilize either DamageFunction or Damage but NOT both. If a projectile has both specified, it will utilize Damage and follow standard randomization rules, ignoring DamageFunction entirely. |
.
Purpose
By default projectile damage is multiplied by a random integer value between 1 and 8; with the STRIFEDAMAGE flag it's multiplied by a value between 1 and 4. As a result, damage of projectiles can be vastly unpredictable: a projectile with Damage 10;
in its Default block can deal 10, 20, 30, 40, 50, 60, 70 or 80 damage (or 10, 20, 30, 40 with STRIFEDAMAGE). Not only is this a very large range, it also provides only a few fixed values (so, for example, if Damage is defined as 10, the projectile will never deal 15 damage, since the randomization multiplier uses integer values only and will never be equal to 1.5).
DamageFunction allows higher control. It can be used to turn damage into a fixed value, or add custom rules (such as, for example, distance-based damage falloff).
Note: DamageFunction is currently the ONLY actor property that natively supports custom expressions. No other actor properties can be defined this way. |
How to define
DamageFunction can be define in one of two ways:
- DamageFunction expression
- This defines a simple mathematical expression. For example:
DamageFunction 10
— will force the damage to be exactly 10 without randomization.DamageFunction 10 * random(1,3)
— will multiply damage by a value between 1-3 only (incidentally, this is the randomization range used by hitscan attacks by default).DamageFunction int(10 * frandom(1,4))
— this will multiply 10 by a float-point value between 1.0 and 4.0 and only then convert the calculated value to an integer value (since damage can only be integer values). As a result, there will be more possible calcualted values instead of just 10, 20, 30 and 40; for example, the resulting value may end up being 14, 28, etc.
- DamageFunction CustomFunctionName()
- This lets you feed an actual function to the damage. The function can do basically anything you like, the only rule is that it must return an int. The integer value it returns will determine the projectile's damage.
Warning: Calling SetDamage on a projectile will completely disable whatever DamageFunction you might've set up, and will instead force it to deal damage using standard randomization rules. |
Examples
Here's an example of using a custom function to calculate damage with falloff:
class BulletProjectile : Actor
{
Default
{
Projectile;
Speed 80;
// Attach GetBulletDamage function and pass 40
// as the base damage value:
DamageFunction GetBulletDamage(40);
}
int GetBulletDamage(int baseDmg)
{
// Get distance between projectile and its shooter,
// clamped between shooter's radius and 1024:
double dist = Clamp(target.Distance3D(self), target.radius, 1024);
// Convert it to a factor that is equal to 1.0 at the minimum
// distance, and 0 at 1024 or higher distance:
double distFac = 1.0 - (dist / 1024.0);
// Multiply base damage by that value and round
// it to the closest value. Then also clamp it
// between 1 and initial damage, so the projectile
// will still deal at least 1 damage if the distance
// was too high:
int finalDmg = Clamp(round(baseDmg * distFac), 1, baseDmg);
return finalDmg;
}
// This example doesn't define any sprites,
// although the projectile will work without
// them, just invisible.
}