Classes:PowerInvisibility

From ZDoom Wiki
Jump to navigation Jump to search
Note: Wait! Stop! You do not need to copy this actor's code into your project! Here's why:
  1. This actor is already defined in GZDoom, there's no reason to define it again.
  2. In fact, trying to define an actor with the same name will cause an error (because it already exists).
  3. If you want to make your own version of this actor, use inheritance.
  4. Definitions for existing actors are put on the wiki for reference purpose only.
Invisibility power
Actor type Power Game MiniZDoomLogoIcon.png (ZDoom)
DoomEd Number None Class Name PowerInvisibility


Classes: InventoryPowerupPowerInvisibility
 →PowerGhost
 →PowerShadow
   (more)


PowerInvisibility is a subtype of Powerup. While this item is in the player's inventory, it makes it harder for other monsters to hit them by giving the SHADOW flag to the actor that received the item. Note, all behavior related to the actual "partial invisibility" results from this flag, and is not at all tied to PowerInvisibility itself.

PowerInvisibility will modify the owner's RenderStyle to the value set through its Powerup.Mode property (not its RenderStyle property); this will affect both the PlayerPawn's sprites, and their on-screen weapon sprites. By default it'll use the Fuzzy renderstyle (like the Doom's Spectre).

If PowerInvisibility has the GHOST or CANTSEEK flags, it'll transfer them to the player when received, alongside the SHADOW flag.


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.
class PowerInvisibility : Powerup
{
	Default
	{
		+SHADOW;
		Powerup.Duration -60;
		Powerup.Strength 80;
		Powerup.Mode "Fuzzy";
	}
	
	//===========================================================================
	//
	// APowerInvisibility :: InitEffect
	//
	//===========================================================================

	override void InitEffect ()
	{
		Super.InitEffect();

		let Owner = self.Owner;
		if (Owner != NULL)
		{
			let savedShadow = Owner.bShadow;
			let savedGhost = Owner.bGhost;
			let savedCantSeek = Owner.bCantSeek;
			Owner.bShadow = bShadow;
			Owner.bGhost = bGhost;
			Owner.bCantSeek = bCantSeek;
			bShadow = savedShadow;
			bGhost = savedGhost;
			bCantSeek = savedCantSeek;
			DoEffect();
		}
	}

	//===========================================================================
	//
	// APowerInvisibility :: DoEffect
	//
	//===========================================================================
	
	override void DoEffect ()
	{
		Super.DoEffect();
		// Due to potential interference with other PowerInvisibility items
		// the effect has to be refreshed each tic.
		double ts = (Strength / 100.) * (special1 + 1);
		
		if (ts > 1.) ts = 1.;
		let newAlpha = clamp((1. - ts), 0., 1.);
		int newStyle;
		switch (Mode)
		{
		case 'Fuzzy':
			newStyle = STYLE_OptFuzzy;
			break;
		case 'Opaque':
			newStyle = STYLE_Normal;
			break;
		case 'Additive':
			newStyle = STYLE_Add;
			break;
		case 'Stencil':
			newStyle = STYLE_Stencil;
			break;
		case 'AddStencil' :
			newStyle = STYLE_AddStencil;
			break;
		case 'TranslucentStencil':
			newStyle = STYLE_TranslucentStencil;
			break;
		case 'None' :
		case 'Cumulative':
		case 'Translucent':
			newStyle = STYLE_Translucent;
			break;
		default: // Something's wrong
			newStyle = STYLE_Normal;
			newAlpha = 1.;
			break;
		}
		Owner.A_SetRenderStyle(newAlpha, newStyle);
	}

	//===========================================================================
	//
	// APowerInvisibility :: EndEffect
	//
	//===========================================================================

	override void EndEffect ()
	{
		Super.EndEffect();
		if (Owner != NULL)
		{
			Owner.bShadow = bShadow;
			Owner.bGhost = bGhost;
			Owner.bCantSeek = bCantSeek;

			Owner.A_SetRenderStyle(1, STYLE_Normal);

			// Check whether there are other invisibility items and refresh their effect.
			// If this isn't done there will be one incorrectly drawn frame when this
			// item expires.
			for(let item = Owner.Inv; item != null; item = item.Inv)
			{
				if (item != self && item is 'PowerInvisibility')
				{
					item.DoEffect();
				}
			}
		}
	}

	//===========================================================================
	//
	// APowerInvisibility :: AlterWeaponSprite
	//
	//===========================================================================

	override void AlterWeaponSprite (VisStyle vis, in out int changed)
	{
		// Blink if the powerup is wearing off
		if (changed == 0 && EffectTics < 4*32 && !(EffectTics & 8))
		{
			vis.RenderStyle = STYLE_Normal;
			vis.Alpha = 1.f;
			changed = 1;
			return;
		}
		else if (changed == 1)
		{
			// something else set the weapon sprite back to opaque but this item is still active.
			float ts = float((Strength / 100) * (special1 + 1));
			vis.Alpha = clamp((1. - ts), 0., 1.);
			switch (Mode)
			{
			case 'Fuzzy':
				vis.RenderStyle = STYLE_OptFuzzy;
				break;
			case 'Opaque':
				vis.RenderStyle = STYLE_Normal;
				break;
			case 'Additive':
				vis.RenderStyle = STYLE_Add;
				break;
			case 'Stencil':
				vis.RenderStyle = STYLE_Stencil;
				break;
			case 'TranslucentStencil':
				vis.RenderStyle = STYLE_TranslucentStencil;
				break;
			case 'AddStencil':
				vis.RenderStyle = STYLE_AddStencil;
				break;
			case 'None':
			case 'Cumulative':
			case 'Translucent':
			default:
				vis.RenderStyle = STYLE_Translucent;
				break;
			}
		}
		// Handling of Strife-like cumulative invisibility powerups, the weapon itself shouldn't become invisible
		if ((vis.Alpha < 0.25f && special1 > 0) || (vis.Alpha == 0))
		{
			vis.Alpha = clamp((1. - Strength/100.), 0., 1.);
			vis.invert = true;
		}
		changed = -1;	// This item is valid so another one shouldn't reset the translucency
	}

	//===========================================================================
	//
	// APowerInvisibility :: HandlePickup
	//
	// If the player already has the first stage of a cumulative powerup, getting 
	// it again increases the player's alpha. (But shouldn't this be in Use()?)
	//
	//===========================================================================

	override bool HandlePickup (Inventory item)
	{
		if (Mode == 'Cumulative' && ((Strength * special1) < 1.) && item.GetClass() == GetClass())
		{
			let power = Powerup(item);
			if (power.EffectTics == 0)
			{
				power.bPickupGood = true;
				return true;
			}
			// Only increase the EffectTics, not decrease it.
			// Color also gets transferred only when the new item has an effect.
			if (power.EffectTics > EffectTics)
			{
				EffectTics = power.EffectTics;
				BlendColor = power.BlendColor;
			}
			special1++;	// increases power
			power.bPickupGood = true;
			return true;
		}
		return Super.HandlePickup (item);
	}
}

DECORATE definition

Note: This is legacy code, kept for archival purposes only. DECORATE is deprecated in GZDoom and is completely superseded by ZScript. GZDoom internally uses the ZScript definition above.


ACTOR PowerInvisibility : Powerup native
{
  +SHADOW
  Powerup.Duration -60
  Powerup.Strength 80
  Powerup.Mode "Fuzzy"
}