From 04bcc6b9b1607470c0b4307856d3e44c229aa551 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Sat, 2 Dec 2017 15:42:13 +0200 Subject: [PATCH] Modifications to the damage/armor system: - Armor values aren't reduced from the damage taken, but instead multiply the damage (e.g. an item reduces damage by 10% instead of 10 hp). Now armor doesn't make characters invulnerable to small amounts of damage. - Armoring isn't defined as a single "armor value", but instead there are "damage modifiers" which can be added to items and limbs. The modifiers can only affect specific types of damage and have separate multipliers for the damage amount and bleeding amount. - Having a fire proof item on a limb doesn't make that limb invulnerable to burn damage. Item's that protect against fire now have a damage modifier for the Burn damage type. --- .../BarotraumaShared.projitems | 1 + .../Content/Characters/Carrier/carrier.xml | 5 +- .../Content/Characters/Crawler/crawler.xml | 9 +- .../Content/Characters/Mantis/mantis.xml | 15 ++- .../Content/Characters/Moloch/moloch.xml | 3 +- .../Content/Characters/Watcher/watcher.xml | 3 +- .../Content/Items/Diving/divinggear.xml | 6 +- .../Content/Items/Jobgear/engigear.xml | 11 +- .../Content/Items/Jobgear/securitygear.xml | 11 +- .../Content/Items/Weapons/railgun.xml | 6 +- .../Source/Characters/Attack.cs | 20 ++- .../Source/Characters/DamageModifier.cs | 66 ++++++++++ .../Source/Characters/Limb.cs | 78 ++++++------ .../Source/Items/Components/Projectile.cs | 4 +- .../Source/Items/Components/Wearable.cs | 115 ++++++------------ .../BarotraumaShared/Source/Items/Item.cs | 2 +- .../BarotraumaShared/Source/Map/FireSource.cs | 2 - 17 files changed, 209 insertions(+), 148 deletions(-) create mode 100644 Barotrauma/BarotraumaShared/Source/Characters/DamageModifier.cs diff --git a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems index d7f24d232..b2beaca84 100644 --- a/Barotrauma/BarotraumaShared/BarotraumaShared.projitems +++ b/Barotrauma/BarotraumaShared/BarotraumaShared.projitems @@ -1356,6 +1356,7 @@ + diff --git a/Barotrauma/BarotraumaShared/Content/Characters/Carrier/carrier.xml b/Barotrauma/BarotraumaShared/Content/Characters/Carrier/carrier.xml index 99d366bd0..ec69f90e3 100644 --- a/Barotrauma/BarotraumaShared/Content/Characters/Carrier/carrier.xml +++ b/Barotrauma/BarotraumaShared/Content/Characters/Carrier/carrier.xml @@ -24,12 +24,15 @@ - + + + + diff --git a/Barotrauma/BarotraumaShared/Content/Characters/Crawler/crawler.xml b/Barotrauma/BarotraumaShared/Content/Characters/Crawler/crawler.xml index 7972a2cc5..631ee917a 100644 --- a/Barotrauma/BarotraumaShared/Content/Characters/Crawler/crawler.xml +++ b/Barotrauma/BarotraumaShared/Content/Characters/Crawler/crawler.xml @@ -30,17 +30,20 @@ - + + - 0 + + - + + diff --git a/Barotrauma/BarotraumaShared/Content/Characters/Mantis/mantis.xml b/Barotrauma/BarotraumaShared/Content/Characters/Mantis/mantis.xml index d3038cf53..b6f0d3057 100644 --- a/Barotrauma/BarotraumaShared/Content/Characters/Mantis/mantis.xml +++ b/Barotrauma/BarotraumaShared/Content/Characters/Mantis/mantis.xml @@ -33,25 +33,28 @@ - + + - + + - + + - + - - + + diff --git a/Barotrauma/BarotraumaShared/Content/Characters/Moloch/moloch.xml b/Barotrauma/BarotraumaShared/Content/Characters/Moloch/moloch.xml index 6fe19a384..aa8e40274 100644 --- a/Barotrauma/BarotraumaShared/Content/Characters/Moloch/moloch.xml +++ b/Barotrauma/BarotraumaShared/Content/Characters/Moloch/moloch.xml @@ -19,9 +19,10 @@ - + + diff --git a/Barotrauma/BarotraumaShared/Content/Characters/Watcher/watcher.xml b/Barotrauma/BarotraumaShared/Content/Characters/Watcher/watcher.xml index 7ba3c6a56..d89840630 100644 --- a/Barotrauma/BarotraumaShared/Content/Characters/Watcher/watcher.xml +++ b/Barotrauma/BarotraumaShared/Content/Characters/Watcher/watcher.xml @@ -25,9 +25,10 @@ - + + diff --git a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml index a35919b7e..cbd95c95d 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Diving/divinggear.xml @@ -63,8 +63,7 @@ @@ -73,7 +72,7 @@ - + @@ -142,7 +141,6 @@ - diff --git a/Barotrauma/BarotraumaShared/Content/Items/Jobgear/engigear.xml b/Barotrauma/BarotraumaShared/Content/Items/Jobgear/engigear.xml index a4281f7e1..6856a3bdf 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Jobgear/engigear.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Jobgear/engigear.xml @@ -1,8 +1,7 @@  @@ -19,7 +18,10 @@ - + + + + @@ -48,6 +50,9 @@ + + + diff --git a/Barotrauma/BarotraumaShared/Content/Items/Jobgear/securitygear.xml b/Barotrauma/BarotraumaShared/Content/Items/Jobgear/securitygear.xml index 804017f10..438f7cc0c 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Jobgear/securitygear.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Jobgear/securitygear.xml @@ -10,17 +10,18 @@ - + + + + - @@ -34,6 +35,8 @@ + + diff --git a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml index 4480fe655..969b6213c 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Weapons/railgun.xml @@ -72,8 +72,7 @@ @@ -103,8 +102,7 @@ diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs index 64081f55e..3ea9aa97e 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs @@ -11,24 +11,32 @@ namespace Barotrauma Damage, Bloodloss, Pressure, Suffocation, Drowning, Burn, Husk, Disconnected } - public enum DamageType { None, Blunt, Slash, Burn } + [Flags] + public enum DamageType + { + None = 0, + Blunt = 1, + Slash = 2, + Burn = 4, + Any = Blunt | Slash | Burn + } struct AttackResult { public readonly float Damage; public readonly float Bleeding; - - public readonly bool HitArmor; - public AttackResult(float damage, float bleeding, bool hitArmor=false) + public readonly List AppliedDamageModifiers; + + public AttackResult(float damage, float bleeding, List appliedDamageModifiers = null) { this.Damage = damage; this.Bleeding = bleeding; - this.HitArmor = hitArmor; + this.AppliedDamageModifiers = appliedDamageModifiers; } } - + partial class Attack { public readonly float Range; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/DamageModifier.cs b/Barotrauma/BarotraumaShared/Source/Characters/DamageModifier.cs new file mode 100644 index 000000000..e97d57971 --- /dev/null +++ b/Barotrauma/BarotraumaShared/Source/Characters/DamageModifier.cs @@ -0,0 +1,66 @@ +using Microsoft.Xna.Framework; +using System.Xml.Linq; + +namespace Barotrauma +{ + class DamageModifier + { + [Serialize(DamageType.None, false)] + public DamageType DamageType + { + get; + private set; + } + + [Serialize(1.0f, false)] + public float DamageMultiplier + { + get; + private set; + } + + [Serialize(1.0f, false)] + public float BleedingMultiplier + { + get; + private set; + } + + [Serialize("0.0,360", false)] + public Vector2 ArmorSector + { + get; + private set; + } + + [Serialize(true, false)] + public bool IsArmor + { + get; + private set; + } + + [Serialize(true, false)] + public bool DeflectProjectiles + { + get; + private set; + } + + +#if CLIENT + [Serialize(DamageSoundType.None, false)] + public DamageSoundType DamageSoundType + { + get; + private set; + } +#endif + + public DamageModifier(XElement element) + { + SerializableProperty.DeserializeProperties(this, element); + ArmorSector = new Vector2(MathHelper.ToRadians(ArmorSector.X), MathHelper.ToRadians(ArmorSector.Y)); + } + } +} diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs index 48c33837d..cc3ce8e8d 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs @@ -72,10 +72,7 @@ namespace Barotrauma private bool isSevered; private float severedFadeOutTimer; - - private readonly Vector2 armorSector; - private readonly float armorValue; - + public Vector2? MouthPos; //a timer for delaying when a hitsound/attacksound can be played again @@ -91,6 +88,8 @@ namespace Barotrauma private Vector2 animTargetPos; private float scale; + + private List damageModifiers; public float AttackTimer; @@ -179,7 +178,7 @@ namespace Barotrauma public float Burnt { get { return burnt; } - set { burnt = MathHelper.Clamp(value,0.0f,100.0f); } + protected set { burnt = MathHelper.Clamp(value, 0.0f, 100.0f); } } public List WearingItems @@ -255,15 +254,7 @@ namespace Barotrauma GameMain.World.AddJoint(pullJoint); steerForce = element.GetAttributeFloat("steerforce", 0.0f); - - //maxHealth = Math.Max(ToolBox.GetAttributeFloat(element, "health", 100.0f),1.0f); - - armorSector = element.GetAttributeVector2("armorsector", Vector2.Zero); - armorSector.X = MathHelper.ToRadians(armorSector.X); - armorSector.Y = MathHelper.ToRadians(armorSector.Y); - - armorValue = Math.Max(element.GetAttributeFloat("armor", 0.0f), 0.0f); - + if (element.Attribute("mouthpos") != null) { MouthPos = ConvertUnits.ToSimUnits(element.GetAttributeVector2("mouthpos", Vector2.Zero)); @@ -272,6 +263,8 @@ namespace Barotrauma body.BodyType = BodyType.Dynamic; body.FarseerBody.AngularDamping = LimbAngularDamping; + damageModifiers = new List(); + foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) @@ -322,6 +315,9 @@ namespace Barotrauma case "attack": attack = new Attack(subElement); break; + case "damagemodifier": + damageModifiers.Add(new DamageModifier(subElement)); + break; } } @@ -344,46 +340,51 @@ namespace Barotrauma public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, bool playSound) { - bool hitArmor = false; - float totalArmorValue = 0.0f; + List appliedDamageModifiers = new List(); - if (armorValue > 0.0f && SectorHit(armorSector, position)) + foreach (DamageModifier damageModifier in damageModifiers) { - hitArmor = true; - totalArmorValue += armorValue; + if (damageModifier.DamageType.HasFlag(damageType) && SectorHit(damageModifier.ArmorSector, position)) + { + appliedDamageModifiers.Add(damageModifier); + } } - + foreach (WearableSprite wearable in wearingItems) { - if (wearable.WearableComponent.ArmorValue > 0.0f && - SectorHit(wearable.WearableComponent.ArmorSectorLimits, position)) + foreach (DamageModifier damageModifier in wearable.WearableComponent.DamageModifiers) { - hitArmor = true; - totalArmorValue += wearable.WearableComponent.ArmorValue; + if (damageModifier.DamageType.HasFlag(damageType) && SectorHit(damageModifier.ArmorSector, position)) + { + appliedDamageModifiers.Add(damageModifier); + } } - } + } - if (hitArmor) + foreach (DamageModifier damageModifier in appliedDamageModifiers) { - totalArmorValue = Math.Max(totalArmorValue, 0.0f); - - amount = Math.Max(0.0f, amount - totalArmorValue); - bleedingAmount = Math.Max(0.0f, bleedingAmount - totalArmorValue); + amount *= damageModifier.DamageMultiplier; + bleedingAmount *= damageModifier.BleedingMultiplier; } #if CLIENT if (playSound) { DamageSoundType damageSoundType = (damageType == DamageType.Blunt) ? DamageSoundType.LimbBlunt : DamageSoundType.LimbSlash; - if (hitArmor) - { - damageSoundType = DamageSoundType.LimbArmor; - } + foreach (DamageModifier damageModifier in appliedDamageModifiers) + { + if (damageModifier.DamageSoundType != DamageSoundType.None) + { + damageSoundType = damageModifier.DamageSoundType; + break; + } + } + SoundPlayer.PlayDamageSound(damageSoundType, amount, position); } - float bloodParticleAmount = hitArmor || bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10); + float bloodParticleAmount = bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10); float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f); for (int i = 0; i < bloodParticleAmount; i++) @@ -402,9 +403,14 @@ namespace Barotrauma #endif + if (damageType == DamageType.Burn) + { + Burnt += amount * 10.0f; + } + damage += Math.Max(amount,bleedingAmount) / character.MaxHealth * 100.0f; - return new AttackResult(amount, bleedingAmount, hitArmor); + return new AttackResult(amount, bleedingAmount, appliedDamageModifiers); } public bool SectorHit(Vector2 armorSector, Vector2 simPosition) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs index 56373779e..569a34735 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Projectile.cs @@ -5,6 +5,7 @@ using FarseerPhysics.Dynamics.Joints; using Microsoft.Xna.Framework; using System; using System.Collections.Generic; +using System.Linq; using System.Xml.Linq; namespace Barotrauma.Items.Components @@ -255,7 +256,8 @@ namespace Barotrauma.Items.Components target.Body.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass); - if (attackResult.HitArmor) + if (attackResult.AppliedDamageModifiers != null && + attackResult.AppliedDamageModifiers.Any(dm => dm.DeflectProjectiles)) { item.body.LinearVelocity *= 0.1f; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs index 941753833..9bfd51af6 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Wearable.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; @@ -27,79 +28,62 @@ namespace Barotrauma.Items.Components class Wearable : Pickable { - WearableSprite[] wearableSprites; - LimbType[] limbType; - Limb[] limb; + private WearableSprite[] wearableSprites; + private LimbType[] limbType; + private Limb[] limb; - private float armorValue; + private List damageModifiers; - private Vector2 armorSector; - - [Serialize(0.0f, false)] - public float ArmorValue + public List DamageModifiers { - get { return armorValue; } - set { armorValue = MathHelper.Clamp(value, 0.0f, 100.0f); } + get { return damageModifiers; } } - - [Serialize("0.0,360.0", false)] - public Vector2 ArmorSector - { - get { return armorSector; } - set - { - armorSector.X = MathHelper.ToRadians(value.X); - armorSector.Y = MathHelper.ToRadians(value.Y); - } - } - - public Vector2 ArmorSectorLimits - { - get { return armorSector; } - } - + public Wearable (Item item, XElement element) : base(item, element) { this.item = item; - var sprites = element.Elements().Where(x => x.Name.ToString() == "sprite").ToList(); - int spriteCount = sprites.Count; + damageModifiers = new List(); + + int spriteCount = element.Elements().Count(x => x.Name.ToString() == "sprite"); wearableSprites = new WearableSprite[spriteCount]; limbType = new LimbType[spriteCount]; limb = new Limb[spriteCount]; int i = 0; - foreach (XElement subElement in sprites) + foreach (XElement subElement in element.Elements()) { - //Rectangle sourceRect = new Rectangle( - // ToolBox.GetAttributeInt(subElement, "sourcex", 1), - // ToolBox.GetAttributeInt(subElement, "sourcey", 1), - // ToolBox.GetAttributeInt(subElement, "sourcewidth", 1), - // ToolBox.GetAttributeInt(subElement, "sourceheight", 1)); - - if (subElement.Attribute("texture") == null) + switch (subElement.Name.ToString().ToLower()) { - DebugConsole.ThrowError("Item \"" + item.Name + "\" doesn't have a texture specified!"); - return; + case "sprite": + if (subElement.Attribute("texture") == null) + { + DebugConsole.ThrowError("Item \"" + item.Name + "\" doesn't have a texture specified!"); + return; + } + + string spritePath = subElement.Attribute("texture").Value; + spritePath = Path.GetDirectoryName(item.Prefab.ConfigFile) + "/" + spritePath; + + var sprite = new Sprite(subElement, "", spritePath); + wearableSprites[i] = new WearableSprite(this, sprite, + subElement.GetAttributeBool("hidelimb", false), + subElement.GetAttributeBool("inheritlimbdepth", true), + (LimbType)Enum.Parse(typeof(LimbType), subElement.GetAttributeString("depthlimb", "None"), true)); + + limbType[i] = (LimbType)Enum.Parse(typeof(LimbType), + subElement.GetAttributeString("limb", "Head"), true); + + i++; + break; + case "damagemodifier": + damageModifiers.Add(new DamageModifier(subElement)); + break; } - - string spritePath = subElement.Attribute("texture").Value; - spritePath = Path.GetDirectoryName( item.Prefab.ConfigFile)+"/"+spritePath; - - var sprite = new Sprite(subElement, "", spritePath); - wearableSprites[i] = new WearableSprite(this, sprite, - subElement.GetAttributeBool("hidelimb", false), - subElement.GetAttributeBool("inheritlimbdepth", true), - (LimbType)Enum.Parse(typeof(LimbType), subElement.GetAttributeString("depthlimb", "None"), true)); - - limbType[i] = (LimbType)Enum.Parse(typeof(LimbType), - subElement.GetAttributeString("limb", "Head"), true); - - i++; } } - + public override void Equip(Character character) { picker = character; @@ -107,15 +91,7 @@ namespace Barotrauma.Items.Components { Limb equipLimb = character.AnimController.GetLimb(limbType[i]); if (equipLimb == null) continue; - - //something is already on the limb -> unequip it - //if (equipLimb.WearingItem != null && equipLimb.WearingItem != this) - //{ - // equipLimb.WearingItem.Unequip(character); - //} - - //sprite[i].Depth = equipLimb.sprite.Depth - 0.001f; - + item.body.Enabled = false; IsActive = true; @@ -143,20 +119,9 @@ namespace Barotrauma.Items.Components Limb equipLimb = character.AnimController.GetLimb(limbType[i]); if (equipLimb == null) continue; - //foreach (WearableSprite wearable in equipLimb.WearingItems) - //{ - // if (wearable != wearableSprites[i]) continue; + equipLimb.WearingItems.RemoveAll(w => w != null && w == wearableSprites[i]); - // equipLimb.WearingItems.Remove(wearableSprites[i]); - //} - - equipLimb.WearingItems.RemoveAll(w=> w!=null && w==wearableSprites[i]); - - //if (equipLimb.WearingItem != this) continue; - limb[i] = null; - //equipLimb.WearingItem = null; - //equipLimb.WearingItemSprite = null; } IsActive = false; diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index 92c3ddad5..e4282a895 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -761,7 +761,7 @@ namespace Barotrauma float damageAmount = attack.GetStructureDamage(deltaTime); Condition -= damageAmount; - return new AttackResult(damageAmount, 0.0f, false); + return new AttackResult(damageAmount, 0.0f, null); } private bool IsInWater() diff --git a/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs b/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs index 8f44317e0..bfa7eb231 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/FireSource.cs @@ -205,8 +205,6 @@ namespace Barotrauma float dmg = (float)Math.Sqrt(size.X) * deltaTime / c.AnimController.Limbs.Length; foreach (Limb limb in c.AnimController.Limbs) { - if (limb.WearingItems.Find(w => w != null && w.WearableComponent.Item.FireProof) != null) continue; - limb.Burnt += dmg * 10.0f; c.AddDamage(limb.SimPosition, DamageType.Burn, dmg, 0, 0, false); } }