A_BFGSpray

From ZDoom Wiki
Jump to navigation Jump to search
DoomWiki.org
For more information on this article, visit the A_BFGSpray page on the Doom Wiki.


Actor

void A_BFGSpray(class<Actor> spraytype = "BFGExtra", int numrays = 40, int damagecnt = 15, double ang = 90, double distance = 16*64, double vrange = 32, int defdamage = 0, int flags = 0)

Usage

Performs the secondary, "tracer" attack of the BFG9000. Note that this function will create unpredictable effects if used on a non-missile.

The tracer actors (spraytype) which are spawned by the function could have custom damage types applied to them, much like other weapon puffs. Note that the EXTREMEDEATH flag still has no effect on this, however, so modders must use DamageType "Extreme" for it to work properly. If PUFFGETSOWNER is used, however, it will use the calling actor's owner as the inflictor -- meaning if the owner has EXTREMEDEATH, then it will actually enact that flag. Specifically, if a BFG ball shot from a player calls A_BFGSpray and the sprays have the PUFFGETSOWNER flag, it relies upon the player's actor to determine causing extreme death or not. A tracer with the MTHRUSPECIES flag set prevents this function from having any effect on actors with the same species as the shooter's own.

Parameters

  • class<Actor> spraytype
The actor to spawn at the position of each shootable actor that is hit. Default is "BFGExtra".
  • int numrays
Spawns this many of the specified actor across an angle of 90 degrees with the target in the center. Default is 40, i.e. one tracer every 2.25°.
  • int damagecnt
The count of iterations to calculate the damage for original BFG formula; it will add N random values from 1 to 8 together based on this value. Default is 15.
  • double ang
Determines the field of view. Any actors within this angle are subject to being sprayed and damaged. Default is 90 (which is the player's FOV).
  • double distance
Determines how far the function should search for monsters from the calling actor. Default is 1024.
  • double vrange
Determines maximum vertical angle to autoaim at, in degrees. Default is 32.
  • int defdamage
If greater than 0, the tracers deal this exact amount of damage and damagecnt is ignored. Default is 0.
  • int flags
Flags that modify the function's behavior. Multiple flags can be combined with |:
  • BFGF_MISSILEORIGIN — If set, the tracers are emitted from the projectile rather than the shooter.
  • BFGF_HURTSOURCE — If set, the shooter can be struck by their own projectile's tracers. This only has an effect if BFGF_MISSILEORIGIN is also set.

Examples

Because of the unique behavior of the BFG, this function has very limited use in custom projects. The only built-in class that makes use of it is the BFGBall, which is fired by the BFG, and triggers the function upon exploding.

Death:
    BFE1 AB 8 Bright;
    BFE1 C 8 Bright A_BFGSpray;
    BFE1 DEF 8 Bright;
    Stop;

ZScript definition

Note: The ZScript definition below is for reference and may be different in the current version of GZDoom.The most up-to-date version of this code can be found on GZDoom GitHub.
	void A_BFGSpray(class<Actor> spraytype = "BFGExtra", int numrays = 40, int damagecnt = 15, double ang = 90, double distance = 16*64, double vrange = 32, int defdamage = 0, int flags = 0)
	{
		int damage;
		FTranslatedLineTarget t;

		// validate parameters
		if (spraytype == null) spraytype = "BFGExtra";
		if (numrays <= 0) numrays = 40;
		if (damagecnt <= 0) damagecnt = 15;
		if (ang == 0) ang = 90.;
		if (distance <= 0) distance = 16 * 64;
		if (vrange == 0) vrange = 32.;

		// [RH] Don't crash if no target
		if (!target) return;

		// [XA] Set the originator of the rays to the projectile (self) if
		//      the new flag is set, else set it to the player (target)
		Actor originator = (flags & BFGF_MISSILEORIGIN) ? self : target;

		// offset angles from its attack ang
		for (int i = 0; i < numrays; i++)
		{
			double an = angle - ang / 2 + ang / numrays*i;

			originator.AimLineAttack(an, distance, t, vrange);

			if (t.linetarget != null)
			{
				Actor spray = Spawn(spraytype, t.linetarget.pos + (0, 0, t.linetarget.Height / 4), ALLOW_REPLACE);

				int dmgFlags = 0;
				Name dmgType = 'BFGSplash';

				if (spray != null)
				{
					if ((spray.bMThruSpecies && target.GetSpecies() == t.linetarget.GetSpecies()) || 
						(!(flags & BFGF_HURTSOURCE) && target == t.linetarget)) // [XA] Don't hit oneself unless we say so.
					{
						spray.Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them.
						continue;
					}
					if (spray.bPuffGetsOwner) spray.target = target;
					if (spray.bFoilInvul) dmgFlags |= DMG_FOILINVUL;
					if (spray.bFoilBuddha) dmgFlags |= DMG_FOILBUDDHA;
					dmgType = spray.DamageType;
				}

				if (defdamage == 0)
				{
					damage = 0;
					for (int j = 0; j < damagecnt; ++j)
						damage += Random[BFGSpray](1, 8);
				}
				else
				{
					// if this is used, damagecnt will be ignored
					damage = defdamage;
				}

				int newdam = t.linetarget.DamageMobj(originator, target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource);
				t.TraceBleed(newdam > 0 ? newdam : damage, self);
			}
		}
	}