Classes:BasicArmor

From ZDoom Wiki
Jump to navigation Jump to search
Note: Wait! Stop! Before you copy this actor's definition into your mod, remember the following things:
  1. You do NOT need to copy that actor, since it is already defined.
  2. In fact, it's not just useless, it will cause problems.
  3. If you want to modify it, or use a modified version, using inheritance is the way to go.
  4. The actor definitions here are put on the wiki for reference purpose only. Learn from them, don't copy them.
Basic armor
Actor type Internal Game MiniZDoomLogoIcon.png (ZDoom)
DoomEd Number None Class Name BasicArmor


Classes: InventoryArmorBasicArmor

BasicArmor is the internal class used to keep track of a player's current armor values in GZDoom, as well as performing the actual armor functions (i.e. damage mitigation). Note that it's not a basic class for armor pickups, rather it's a controller that stores the current armor icon, amount, absorption, etc. Creating new armor pickups requires creating items based on the BasicArmorPickup class (for regular armor pickups) or BasicArmorBonus (for armor bonus-type pickups that add to the current armor without overriding it).

The damage mitigation itself is handled through the AbsorbDamage function. That function by itself isn't limited to BasicArmor, since it's defined in Inventory, and can be utilized in any item.

Hexen utilizes HexenArmor rather than BasicArmor for its armor system.

BasicArmor and HexenArmor are given to the player automatically at the start of the game (both classes are given regardless of what game/IWAD is being used). Armor pickups based on the BasicArmorPickup class are never placed in the player's inventory. Instead, upon being picked up, they interact with the BasicArmor (or HexenArmor) instance in that player's inventory and modify its fields (such as icon, savepercent, and so on), after which the armor pickup is removed.

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 BasicArmor : Armor
{
	
	int AbsorbCount;
	double SavePercent;
	int MaxAbsorb;
	int MaxFullAbsorb;
	int BonusCount;
	Name ArmorType;
	int ActualSaveAmount;
	
	Default
	{
		Inventory.Amount 0;
		+Inventory.KEEPDEPLETED
	}

	//===========================================================================
	//
	// ABasicArmor :: Tick
	//
	// If BasicArmor is given to the player by means other than a
	// BasicArmorPickup, then it may not have an icon set. Fix that here.
	//
	//===========================================================================

	override void Tick ()
	{
		Super.Tick ();
		AbsorbCount = 0;
		if (!Icon.isValid())
		{
			String icontex = gameinfo.ArmorIcon1;

			if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Length() != 0)
				icontex = gameinfo.ArmorIcon2;

			if (icontex.Length() != 0)
				Icon = TexMan.CheckForTexture (icontex, TexMan.TYPE_Any);
		}
	}

	//===========================================================================
	//
	// ABasicArmor :: CreateCopy
	//
	//===========================================================================

	override Inventory CreateCopy (Actor other)
	{
		// BasicArmor that is in use is stored in the inventory as BasicArmor.
		// BasicArmor that is in reserve is not.
		let copy = BasicArmor(Spawn("BasicArmor"));
		copy.SavePercent = SavePercent != 0 ? SavePercent : 0.33335;	// slightly more than 1/3 to avoid roundoff errors.
		copy.Amount = Amount;
		copy.MaxAmount = MaxAmount;
		copy.Icon = Icon;
		copy.BonusCount = BonusCount;
		copy.ArmorType = ArmorType;
		copy.ActualSaveAmount = ActualSaveAmount;
		GoAwayAndDie ();
		return copy;
	}


	//===========================================================================
	//
	// ABasicArmor :: HandlePickup
	//
	//===========================================================================

	override bool HandlePickup (Inventory item)
	{
		if (item.GetClass() == "BasicArmor")
		{
			// You shouldn't be picking up BasicArmor anyway.
			return true;
		}
		return false;
	}
	
	//===========================================================================
	//
	// ABasicArmor :: AbsorbDamage
	//
	//===========================================================================

	override void AbsorbDamage (int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags)
	{
		int saved;

		if (!DamageTypeDefinition.IgnoreArmor(damageType))
		{
			int full = MAX(0, MaxFullAbsorb - AbsorbCount);
			
			if (damage < full)
			{
				saved = damage;
			}
			else
			{
				saved = full + int((damage - full) * SavePercent);
				if (MaxAbsorb > 0 && saved + AbsorbCount > MaxAbsorb) 
				{
					saved = MAX(0,  MaxAbsorb - AbsorbCount);
				}
			}

			if (Amount < saved)
			{
				saved = Amount;
			}
			newdamage -= saved;
			Amount -= saved;
			AbsorbCount += saved;
			if (Amount == 0)
			{
				// The armor has become useless
				SavePercent = 0;
				ArmorType = 'None'; // Not NAME_BasicArmor.
				// Now see if the player has some more armor in their inventory
				// and use it if so. As in Strife, the best armor is used up first.
				BasicArmorPickup best = null;
				Inventory probe = Owner.Inv;
				while (probe != null)
				{
					let inInv = BasicArmorPickup(probe);
					if (inInv != null)
					{
						if (best == null || best.SavePercent < inInv.SavePercent)
						{
							best = inInv;
						}
					}
					probe = probe.Inv;
				}
				if (best != null)
				{
					Owner.UseInventory (best);
				}
			}
			damage = newdamage;
		}

		// Once the armor has absorbed its part of the damage, then apply its damage factor, if any, to the player
		if ((damage > 0) && (ArmorType != 'None')) // BasicArmor is not going to have any damage factor, so skip it.
		{
			newdamage = ApplyDamageFactors(ArmorType, damageType, damage, damage);
		}
	}
}

DECORATE definition

ACTOR BasicArmor : Armor native
{
  +INVENTORY.KEEPDEPLETED
}