/* ** 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 { Inventory.PickupSound "misc/armor_pkup"; } } //=========================================================================== // // // BasicArmor // // //=========================================================================== class BasicArmor : Armor native { native int AbsorbCount; native double SavePercent; native int MaxAbsorb; native int MaxFullAbsorb; native int BonusCount; native Name ArmorType; native int ActualSaveAmount; Default { +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; } if (!item.bIgnoreSkill) { if (item is "BasicArmorBonus") { let armor = BasicArmorBonus(item); armor.SaveAmount = int(armor.SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor)); } else if (item is "BasicArmorPickup") { let armor = BasicArmorPickup(item); armor.SaveAmount = int(armor.SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor)); } } 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 int MaxSaveAmount; int MaxAbsorb; int MaxFullAbsorb; int SaveAmount; int BonusCount; int BonusMax; property prefix: Armor; property MaxSaveAmount: MaxSaveAmount; property SaveAmount : SaveAmount; property SavePercent: SavePercent; property MaxAbsorb: MaxAbsorb; property MaxFullAbsorb: MaxFullAbsorb; property MaxBonus: BonusCount; property MaxBonusMax: BonusMax; Default { +Inventory.AUTOACTIVATE +Inventory.ALWAYSPICKUP Inventory.MaxAmount 0; Armor.SavePercent 33.335; } //=========================================================================== // // ABasicArmorBonus :: CreateCopy // //=========================================================================== override Inventory CreateCopy (Actor other) { let copy = BasicArmorBonus(Super.CreateCopy (other)); if (!bIgnoreSkill) { SaveAmount = int(SaveAmount * G_SkillPropertyFloat(SKILLP_ArmorFactor)); } copy.SavePercent = SavePercent; copy.SaveAmount = SaveAmount; copy.MaxSaveAmount = MaxSaveAmount; copy.BonusCount = BonusCount; copy.BonusMax = BonusMax; copy.MaxAbsorb = MaxAbsorb; copy.MaxFullAbsorb = MaxFullAbsorb; return copy; } //=========================================================================== // // ABasicArmorBonus :: Use // // Tries to add to the amount of BasicArmor a player has. // //=========================================================================== override bool Use (bool pickup) { let armor = BasicArmor(Owner.FindInventory("BasicArmor")); bool result = false; // This should really never happen but let's be prepared for a broken inventory. if (armor == null) { armor = BasicArmor(Spawn("BasicArmor")); armor.BecomeItem (); armor.Amount = 0; armor.MaxAmount = MaxSaveAmount; Owner.AddInventory (armor); } if (BonusCount > 0 && armor.BonusCount < BonusMax) { armor.BonusCount = min(armor.BonusCount + BonusCount, BonusMax); result = true; } int saveAmount = min(SaveAmount, MaxSaveAmount); if (saveAmount <= 0) { // If it can't give you anything, it's as good as used. return BonusCount > 0 ? result : true; } // If you already have more armor than this item can give you, you can't // use it. if (armor.Amount >= MaxSaveAmount + armor.BonusCount) { return result; } if (armor.Amount <= 0) { // Should never be less than 0, but might as well check anyway armor.Amount = 0; armor.Icon = Icon; armor.SavePercent = clamp(SavePercent, 0, 100) / 100; armor.MaxAbsorb = MaxAbsorb; armor.ArmorType = GetClassName(); armor.MaxFullAbsorb = MaxFullAbsorb; armor.ActualSaveAmount = MaxSaveAmount; } armor.Amount = min(armor.Amount + saveAmount, MaxSaveAmount + armor.BonusCount); armor.MaxAmount = max(armor.MaxAmount, MaxSaveAmount); return true; } } //=========================================================================== // // // BasicArmorPickup // // //=========================================================================== class BasicArmorPickup : Armor { 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 { native double Slots[5]; native double SlotsIncrement[4]; Default { +Inventory.KEEPDEPLETED +Inventory.UNTOSSABLE } }