diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp
index abe25a753..f0054b290 100644
--- a/src/d_dehacked.cpp
+++ b/src/d_dehacked.cpp
@@ -1948,19 +1948,18 @@ static int PatchMisc (int dummy)
 
 	// Update default item properties by patching the affected items
 	// Note: This won't have any effect on DECORATE derivates of these items!
-	ABasicArmorPickup *armor;
 
-	armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("GreenArmor"));
+	auto armor = GetDefaultByName ("GreenArmor");
 	if (armor!=NULL)
 	{
-		armor->SaveAmount = 100 * deh.GreenAC;
-		armor->SavePercent = deh.GreenAC == 1 ? 0.33335 : 0.5;
+		armor->IntVar(NAME_SaveAmount) = 100 * deh.GreenAC;
+		armor->FloatVar(NAME_SavePercent) = deh.GreenAC == 1 ? 0.33335 : 0.5;
 	}
-	armor = static_cast<ABasicArmorPickup *> (GetDefaultByName ("BlueArmor"));
+	armor = GetDefaultByName ("BlueArmor");
 	if (armor!=NULL)
 	{
-		armor->SaveAmount = 100 * deh.BlueAC;
-		armor->SavePercent = deh.BlueAC == 1 ? 0.33335 : 0.5;
+		armor->IntVar(NAME_SaveAmount) = 100 * deh.BlueAC;
+		armor->FloatVar(NAME_SavePercent) = deh.BlueAC == 1 ? 0.33335 : 0.5;
 	}
 
 	auto barmor = GetDefaultByName ("ArmorBonus");
diff --git a/src/g_inventory/a_armor.cpp b/src/g_inventory/a_armor.cpp
index 5f4b0dbbe..816cf1620 100644
--- a/src/g_inventory/a_armor.cpp
+++ b/src/g_inventory/a_armor.cpp
@@ -47,7 +47,6 @@
 
 IMPLEMENT_CLASS(AArmor, false, false)
 IMPLEMENT_CLASS(ABasicArmor, false, false)
-IMPLEMENT_CLASS(ABasicArmorPickup, false, false)
 IMPLEMENT_CLASS(AHexenArmor, false, false)
 
 //===========================================================================
@@ -85,231 +84,6 @@ void ABasicArmor::Serialize(FSerializer &arc)
 		("actualsaveamount", ActualSaveAmount, def->ActualSaveAmount);
 }
 
-//===========================================================================
-//
-// 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.
-//
-//===========================================================================
-
-void ABasicArmor::Tick ()
-{
-	Super::Tick ();
-	AbsorbCount = 0;
-	if (!Icon.isValid())
-	{
-		FString icon = gameinfo.ArmorIcon1;
-
-		if (SavePercent >= gameinfo.Armor2Percent && gameinfo.ArmorIcon2.Len() != 0)
-			icon = gameinfo.ArmorIcon2;
-
-		if (icon[0] != 0)
-			Icon = TexMan.CheckForTexture (icon, FTexture::TEX_Any);
-	}
-}
-
-//===========================================================================
-//
-// ABasicArmor :: CreateCopy
-//
-//===========================================================================
-
-AInventory *ABasicArmor::CreateCopy (AActor *other)
-{
-	// BasicArmor that is in use is stored in the inventory as BasicArmor.
-	// BasicArmor that is in reserve is not.
-	ABasicArmor *copy = Spawn<ABasicArmor> ();
-	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 :: AbsorbDamage
-//
-//===========================================================================
-
-void ABasicArmor::AbsorbDamage (int damage, FName damageType, int &newdamage)
-{
-	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 = NAME_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.
-			ABasicArmorPickup *best = NULL;
-			AInventory *probe = Owner->Inventory;
-			while (probe != NULL)
-			{
-				if (probe->IsKindOf (PClass::FindActor(NAME_BasicArmorPickup)))
-				{
-					ABasicArmorPickup *inInv = static_cast<ABasicArmorPickup*>(probe);
-					if (best == NULL || best->SavePercent < inInv->SavePercent)
-					{
-						best = inInv;
-					}
-				}
-				probe = probe->Inventory;
-			}
-			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 != NAME_None)) // BasicArmor is not going to have any damage factor, so skip it.
-	{
-		// This code is taken and adapted from APowerProtection::ModifyDamage().
-		// The differences include not using a default value, and of course the way
-		// the damage factor info is obtained.
-
-		// ApplyDamageFactors(ArmorType, damageType, damage, damage);
-		DmgFactors *df = PClass::FindActor(ArmorType)->DamageFactors;
-		if (df != NULL)
-		{
-			damage = newdamage = df->Apply(damageType, damage);
-		}
-	}
-}
-
-//===========================================================================
-//
-//
-// BasicArmorPickup
-//
-//
-//===========================================================================
-
-
-DEFINE_FIELD(ABasicArmorPickup, SavePercent)
-DEFINE_FIELD(ABasicArmorPickup, MaxAbsorb)
-DEFINE_FIELD(ABasicArmorPickup, MaxFullAbsorb)
-DEFINE_FIELD(ABasicArmorPickup, SaveAmount)
-
-//===========================================================================
-//
-// ABasicArmorPickup :: Serialize
-//
-//===========================================================================
-
-void ABasicArmorPickup::Serialize(FSerializer &arc)
-{
-	Super::Serialize (arc);
-
-	auto def = (ABasicArmorPickup *)GetDefault();
-	arc("savepercent", SavePercent, def->SavePercent)
-		("saveamount", SaveAmount, def->SaveAmount)
-		("maxabsorb", MaxAbsorb, def->MaxAbsorb)
-		("maxfullabsorb", MaxFullAbsorb, def->MaxFullAbsorb);
-}
-
-//===========================================================================
-//
-// ABasicArmorPickup :: CreateCopy
-//
-//===========================================================================
-
-AInventory *ABasicArmorPickup::CreateCopy (AActor *other)
-{
-	ABasicArmorPickup *copy = static_cast<ABasicArmorPickup *> (Super::CreateCopy (other));
-
-	if (!(ItemFlags & IF_IGNORESKILL))
-	{
-		SaveAmount = int(SaveAmount * G_SkillProperty(SKILLP_ArmorFactor));
-	}
-
-	copy->SavePercent = SavePercent;
-	copy->SaveAmount = SaveAmount;
-	copy->MaxAbsorb = MaxAbsorb;
-	copy->MaxFullAbsorb = MaxFullAbsorb;
-
-	return copy;
-}
-
-//===========================================================================
-//
-// ABasicArmorPickup :: Use
-//
-// Either gives you new armor or replaces the armor you already have (if
-// the SaveAmount is greater than the amount of armor you own). When the
-// item is auto-activated, it will only be activated if its max amount is 0
-// or if you have no armor active already.
-//
-//===========================================================================
-
-bool ABasicArmorPickup::Use (bool pickup)
-{
-	ABasicArmor *armor = Owner->FindInventory<ABasicArmor> ();
-
-	if (armor == NULL)
-	{
-		armor = Spawn<ABasicArmor> ();
-		armor->BecomeItem ();
-		Owner->AddInventory (armor);
-	}
-	else
-	{
-		// If you already have more armor than this item gives you, you can't
-		// use it.
-		if (armor->Amount >= SaveAmount + armor->BonusCount)
-		{
-			return false;
-		}
-		// Don't use it if you're picking it up and already have some.
-		if (pickup && armor->Amount > 0 && MaxAmount > 0)
-		{
-			return false;
-		}
-	}
-	armor->SavePercent = SavePercent;
-	armor->Amount = SaveAmount + armor->BonusCount;
-	armor->MaxAmount = SaveAmount;
-	armor->Icon = Icon;
-	armor->MaxAbsorb = MaxAbsorb;
-	armor->MaxFullAbsorb = MaxFullAbsorb;
-	armor->ArmorType = this->GetClass()->TypeName;
-	armor->ActualSaveAmount = SaveAmount;
-	return true;
-}
-
 //===========================================================================
 //
 //
diff --git a/src/g_inventory/a_armor.h b/src/g_inventory/a_armor.h
index 7bfb40a0a..c09162f72 100644
--- a/src/g_inventory/a_armor.h
+++ b/src/g_inventory/a_armor.h
@@ -17,9 +17,6 @@ class ABasicArmor : public AArmor
 public:
 	
 	virtual void Serialize(FSerializer &arc) override;
-	virtual void Tick () override;
-	virtual AInventory *CreateCopy (AActor *other) override;
-	virtual void AbsorbDamage (int damage, FName damageType, int &newdamage) override;
 
 	int AbsorbCount;
 	double SavePercent;
@@ -30,22 +27,6 @@ public:
 	int ActualSaveAmount;
 };
 
-// BasicArmorPickup replaces the armor you have.
-class ABasicArmorPickup : public AArmor
-{
-	DECLARE_CLASS (ABasicArmorPickup, AArmor)
-public:
-	
-	virtual void Serialize(FSerializer &arc) override;
-	virtual AInventory *CreateCopy (AActor *other) override;
-	virtual bool Use (bool pickup) override;
-
-	double SavePercent;
-	int MaxAbsorb;
-	int MaxFullAbsorb;
-	int SaveAmount;
-};
-
 // Hexen armor consists of four separate armor types plus a conceptual armor
 // type (the player himself) that work together as a single armor.
 class AHexenArmor : public AArmor
diff --git a/src/gi.cpp b/src/gi.cpp
index a13804aad..6c7349592 100644
--- a/src/gi.cpp
+++ b/src/gi.cpp
@@ -47,6 +47,8 @@ gameinfo_t gameinfo;
 
 DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
 DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
+DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon1)
+DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, ArmorIcon2)
 
 
 const char *GameNames[17] =
diff --git a/src/info.cpp b/src/info.cpp
index bdfcb4057..a424c890f 100644
--- a/src/info.cpp
+++ b/src/info.cpp
@@ -758,6 +758,14 @@ bool DamageTypeDefinition::IgnoreArmor(FName type)
 	return false;
 }
 
+DEFINE_ACTION_FUNCTION(_DamageTypeDefinition, IgnoreArmor)
+{
+	PARAM_PROLOGUE;
+	PARAM_NAME(type);
+	ACTION_RETURN_BOOL(DamageTypeDefinition::IgnoreArmor(type));
+}
+
+
 //==========================================================================
 //
 // DamageTypeDefinition :: ApplyMobjDamageFactor
diff --git a/src/info.h b/src/info.h
index 54aac3e3c..4a6baa671 100644
--- a/src/info.h
+++ b/src/info.h
@@ -226,10 +226,12 @@ public:
 		NoArmor = false;
 	}
 
-	static DamageTypeDefinition *Get(FName type);
 	static bool IgnoreArmor(FName type);
-	static double GetMobjDamageFactor(FName type, DmgFactors const * const factors);
 	static int ApplyMobjDamageFactor(int damage, FName type, DmgFactors const * const factors);
+
+private:
+	static double GetMobjDamageFactor(FName type, DmgFactors const * const factors);
+	static DamageTypeDefinition *Get(FName type);
 };
 
 class DDropItem;
diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp
index 08a394ffe..9d2423154 100644
--- a/src/scripting/thingdef_properties.cpp
+++ b/src/scripting/thingdef_properties.cpp
@@ -1723,79 +1723,6 @@ DEFINE_CLASS_PROPERTY(forbiddento, Ssssssssssssssssssss, Inventory)
 	}
 }
 
-//==========================================================================
-//
-//==========================================================================
-DEFINE_CLASS_PROPERTY(saveamount, I, Armor)
-{
-	PROP_INT_PARM(i, 0);
-
-	// Special case here because this property has to work for 2 unrelated classes
-	if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
-	{
-		defaults->IntVar(NAME_SaveAmount)=i;
-	}
-	else
-	{
-		I_Error("\"Armor.SaveAmount\" requires an actor of type \"Armor\"");
-	}
-}
-
-//==========================================================================
-//
-//==========================================================================
-DEFINE_CLASS_PROPERTY(savepercent, F, Armor)
-{
-	PROP_DOUBLE_PARM(i, 0);
-
-	i = clamp(i, 0., 100.)/100.;
-	// Special case here because this property has to work for 2 unrelated classes
-	if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
-	{
-		defaults->FloatVar(NAME_SavePercent) = i;
-	}
-	else
-	{
-		I_Error("\"Armor.SavePercent\" requires an actor of type \"Armor\"\n");
-	}
-}
-
-//==========================================================================
-//
-//==========================================================================
-DEFINE_CLASS_PROPERTY(maxabsorb, I, Armor)
-{
-	PROP_INT_PARM(i, 0);
-
-	// Special case here because this property has to work for 2 unrelated classes
-	if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
-	{
-		defaults->IntVar(NAME_MaxAbsorb) = i;
-	}
-	else
-	{
-		I_Error("\"Armor.MaxAbsorb\" requires an actor of type \"Armor\"\n");
-	}
-}
-
-//==========================================================================
-//
-//==========================================================================
-DEFINE_CLASS_PROPERTY(maxfullabsorb, I, Armor)
-{
-	PROP_INT_PARM(i, 0);
-
-	// Special case here because this property has to work for 2 unrelated classes
-	if (info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorPickup)) || info->IsDescendantOf(PClass::FindActor(NAME_BasicArmorBonus)))
-	{
-		defaults->IntVar(NAME_MaxFullAbsorb) = i;
-	}
-	else
-	{
-		I_Error("\"Armor.MaxFullAbsorb\" requires an actor of type \"Armor\"\n");
-	}
-}
-
 //==========================================================================
 //
 //==========================================================================
diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt
index 9cad3224e..2cf48363b 100644
--- a/wadsrc/static/zscript/base.txt
+++ b/wadsrc/static/zscript/base.txt
@@ -42,11 +42,18 @@ struct Console native
 	native static void HideConsole();
 }
 
+struct DamageTypeDefinition native
+{
+	native static bool IgnoreArmor(Name type);
+}
+
 struct GameInfoStruct native
 {
 	// will be extended as needed.
 	native Name backpacktype;
 	native double Armor2Percent;
+	native String ArmorIcon1;
+	native String ArmorIcon2;
 }
 
 class Object native
diff --git a/wadsrc/static/zscript/inventory/armor.txt b/wadsrc/static/zscript/inventory/armor.txt
index 16bffa78e..1d0f5fd9d 100644
--- a/wadsrc/static/zscript/inventory/armor.txt
+++ b/wadsrc/static/zscript/inventory/armor.txt
@@ -1,3 +1,38 @@
+/*
+** armor.txt
+** Implements all variations of armor objects
+**
+**---------------------------------------------------------------------------
+** Copyright 2002-2016 Randy Heit
+** Copyright 2006-2017 Christoph Oelckers
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** 1. Redistributions of source code must retain the above copyright
+**    notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+**    notice, this list of conditions and the following disclaimer in the
+**    documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+**    derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**---------------------------------------------------------------------------
+**
+*/
+
 class Armor : Inventory native
 {
 	Default
@@ -6,6 +41,14 @@ class Armor : Inventory native
 	}
 }
 
+//===========================================================================
+//
+//
+// BasicArmor
+//
+//
+//===========================================================================
+
 class BasicArmor : Armor native
 {
 	
@@ -21,7 +64,55 @@ class BasicArmor : Armor native
 	{
 		+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
@@ -50,8 +141,86 @@ class BasicArmor : Armor native
 		}
 		return false;
 	}
+	
+	//===========================================================================
+	//
+	// ABasicArmor :: AbsorbDamage
+	//
+	//===========================================================================
+
+	override void AbsorbDamage (int damage, Name damageType, out int newdamage)
+	{
+		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.
+		{
+			ApplyDamageFactors(ArmorType, damageType, damage, damage);
+		}
+	}
 }
 
+//===========================================================================
+//
+//
+// BasicArmorBonus
+//
+//
+//===========================================================================
+
 class BasicArmorBonus : Armor 
 {
 	double SavePercent;	// The default, for when you don't already have armor
@@ -119,7 +288,7 @@ class BasicArmorBonus : Armor
 		bool result = false;
 
 		// This should really never happen but let's be prepared for a broken inventory.
-		if (armor == NULL)
+		if (armor == null)
 		{
 			armor = BasicArmor(Spawn("BasicArmor"));
 			armor.BecomeItem ();
@@ -152,7 +321,7 @@ class BasicArmorBonus : Armor
 		{ // Should never be less than 0, but might as well check anyway
 			armor.Amount = 0;
 			armor.Icon = Icon;
-			armor.SavePercent = clamp(SavePercent, 0, 100);
+			armor.SavePercent = clamp(SavePercent, 0, 100) / 100;
 			armor.MaxAbsorb = MaxAbsorb;
 			armor.ArmorType = GetClassName();
 			armor.MaxFullAbsorb = MaxFullAbsorb;
@@ -167,21 +336,114 @@ class BasicArmorBonus : Armor
 	
 }
 
-class BasicArmorPickup : Armor native
+//===========================================================================
+//
+//
+// BasicArmorPickup
+//
+//
+//===========================================================================
+
+class BasicArmorPickup : Armor
 {
 
-	native double SavePercent;
-	native int MaxAbsorb;
-	native int MaxFullAbsorb;
-	native int SaveAmount;
-	
+	double SavePercent;
+	int MaxAbsorb;
+	int MaxFullAbsorb;
+	int SaveAmount;
+
+	property prefix: Armor;
+	property SaveAmount : SaveAmount;
+	property SavePercent: SavePercent;
+	property MaxAbsorb: MaxAbsorb;
+	property MaxFullAbsorb: MaxFullAbsorb;
+
 	Default
 	{
 		+Inventory.AUTOACTIVATE;
 		Inventory.MaxAmount 0;
 	}
+	
+	//===========================================================================
+	//
+	// ABasicArmorPickup :: CreateCopy
+	//
+	//===========================================================================
+
+	override Inventory CreateCopy (Actor other)
+	{
+		let copy = BasicArmorPickup(Super.CreateCopy (other));
+
+		if (!bIgnoreSkill)
+		{
+			SaveAmount = int(SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor));
+		}
+
+		copy.SavePercent = SavePercent;
+		copy.SaveAmount = SaveAmount;
+		copy.MaxAbsorb = MaxAbsorb;
+		copy.MaxFullAbsorb = MaxFullAbsorb;
+
+		return copy;
+	}
+	
+	//===========================================================================
+	//
+	// ABasicArmorPickup :: Use
+	//
+	// Either gives you new armor or replaces the armor you already have (if
+	// the SaveAmount is greater than the amount of armor you own). When the
+	// item is auto-activated, it will only be activated if its max amount is 0
+	// or if you have no armor active already.
+	//
+	//===========================================================================
+
+	override bool Use (bool pickup)
+	{
+		let armor = BasicArmor(Owner.FindInventory("BasicArmor"));
+
+		// This should really never happen but let's be prepared for a broken inventory.
+		if (armor == null)
+		{
+			armor = BasicArmor(Spawn("BasicArmor"));
+			armor.BecomeItem ();
+			Owner.AddInventory (armor);
+		}
+		else
+		{
+			// If you already have more armor than this item gives you, you can't
+			// use it.
+			if (armor.Amount >= SaveAmount + armor.BonusCount)
+			{
+				return false;
+			}
+			// Don't use it if you're picking it up and already have some.
+			if (pickup && armor.Amount > 0 && MaxAmount > 0)
+			{
+				return false;
+			}
+		}
+		
+		armor.SavePercent = clamp(SavePercent, 0, 100) / 100;
+		armor.Amount = SaveAmount + armor.BonusCount;
+		armor.MaxAmount = SaveAmount;
+		armor.Icon = Icon;
+		armor.MaxAbsorb = MaxAbsorb;
+		armor.MaxFullAbsorb = MaxFullAbsorb;
+		armor.ArmorType = GetClassName();
+		armor.ActualSaveAmount = SaveAmount;
+		return true;
+	}
 }
 
+//===========================================================================
+//
+//
+// HexenArmor
+//
+//
+//===========================================================================
+
 class HexenArmor : Armor native
 {