A_ReFire

From ZDoom Wiki
Jump to navigation Jump to search

StateProvider

action void A_ReFire(statelabel flash = null)

DoomWiki.org
For more information on this article, visit the A_ReFire page on the Doom Wiki.


Usage

This function is normally called by weapons after the attack. It checks whether the fire key is still held, and if so, enters the relevant state sequence.

Contrary to what its name may suggest, weapons can fire continuously without the use of this function: as soon as the weapon reaches an A_WeaponReady call, it will be allowed to fire again. This means that, for most weapons, if the player keeps holding the attack button all the way through the weapon's Fire/AltFire sequence, as soon as the weapon returns to the Ready sequence, it'll immediately go back to Fire/AltFire if the player is still holding the relevant attack button.

The only way to actually completely disable the ability to fire continuously is to not use A_Refire and to also use the NOAUTOFIRE flag on the weapon: using this flag disables the ability for A_WeaponReady to send the weapon to Fire/AltFire if the player was holding down the attack button.

However, using A_Refire is necessary for certain features unique to this function:

  • It allows cutting the normal firing sequence short if the attack button is held. Looking at most Doom weapons, you will notice that the Fire animation is longer if the player taps the attack button than it is when they're holding the button down. A_ReFire functions similarly to state jump functions, which means, if the state with this function is reached and the condition is met (the player is holding down the attack button), the frame this function is attached to will not be displayed, and instead the animation will immediately jump to Fire/AltFire (or Hold/AltHold, if present). Using the Doom Pistol as an example, the Fire animation when firing once is 5 tics longer than it is when firing continuously.
  • This function will automatically jump from Fire to the Hold state sequence (if present) or from AltFire to AltHold (if present), which makes it a convenient tool to make different firing animations for tapping the attack button and holding it.
  • Calling A_ReFire increments the player.refire field in the PlayerInfo struct of the attacking player. (The value of this field is increased by 1 every time A_ReFire is called, and is reset to 0 as soon as the player releases the attack button).
This field is relevant for several things, most notably the behavior of A_FireBullets: if the value of player.refire is 0 and the number of fired hitscal bullets is 1, A_FireBullets will fire with perfect accuracy; the spread arguments of A_FireBullets will only be applied on subsequent attacks after refiring, when player.refire is 2 or above. This is why the Pistol and the Chaingun fire with perfect accuracy when tap-firing.
This behavior, however, can be circumvented: using -1 as the numbullets argument of A_FireBullets will force the function to always use the specified spread values, regardless of the player.refire value.

Parameters

  • flash: The label of the state sequence to go to. The value must be provided in quotation marks. By default, it is the Hold sequence, or the Fire sequence (if Hold is not defined), or the AltHold or AltFire state if the function is called from the AltFire sequence.
Note, although the internal name of this argument is "flash," it has nothing to do with muzzle flashes or overlays.

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.
action void A_ReFire(statelabel flash = null)
{
	let player = player;
	bool pending;

	if (NULL == player)
	{
		return;
	}
	pending = player.PendingWeapon != WP_NOCHANGE && (player.WeaponState & WF_REFIRESWITCHOK);
	if ((player.cmd.buttons & BT_ATTACK)
		&& !player.ReadyWeapon.bAltFire && !pending && player.health > 0)
	{
		player.refire++;
		player.mo.FireWeapon(ResolveState(flash));
	}
	else if ((player.cmd.buttons & BT_ALTATTACK)
		&& player.ReadyWeapon.bAltFire && !pending && player.health > 0)
	{
		player.refire++;
		player.mo.FireWeaponAlt(ResolveState(flash));
	}
	else
	{
		player.refire = 0;
		player.ReadyWeapon.CheckAmmo (player.ReadyWeapon.bAltFire? Weapon.AltFire : Weapon.PrimaryFire, true);
	}
}

Examples

From Doom Pistol:

Fire:
	PISG A 4;
	PISG B 6 A_FirePistol;
	PISG C 4;
	PISG B 5 A_ReFire; //If fire button is held, then it goes back to the beginning of the sequence, Otherwise it would continue
	Goto Ready;

This is an example of a firing sequence that has a charge animation period when it begins firing which isn't showed for shots beyond the first one:

Fire:
	TNT1 A 0 A_StartSound("weapons/laser/charge", CHAN_WEAPON);
	WEAP AAAAA 2 A_WeaponOffset(frandom(-1,1), WEAPONTOP + frandom(0, 2), WOF_INTERPOLATE); //shake the sprite randomly
// intentional fall-through:
Hold:
	WEAP B 2 bright 
	{
		A_GunFlash();
		A_FireProjectile("Plasmaball");
	}
	WEAP CD 2;
	TNT1 A 0 A_Refire; //jumps back to Hold
	goto Ready;