diff --git a/Barotrauma/BarotraumaClient/Source/Map/Structure.cs b/Barotrauma/BarotraumaClient/Source/Map/Structure.cs index 5f7989073..acdb62496 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Structure.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Structure.cs @@ -5,7 +5,6 @@ using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Linq; -using System.Xml.Linq; namespace Barotrauma { diff --git a/Barotrauma/BarotraumaShared/Content/Characters/Endworm/endworm.xml b/Barotrauma/BarotraumaShared/Content/Characters/Endworm/endworm.xml index 085858637..ac631c8a0 100644 --- a/Barotrauma/BarotraumaShared/Content/Characters/Endworm/endworm.xml +++ b/Barotrauma/BarotraumaShared/Content/Characters/Endworm/endworm.xml @@ -54,12 +54,12 @@ - + - + diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs index 0f836eae8..6d6aa09cf 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Attack.cs @@ -21,6 +21,12 @@ namespace Barotrauma Any = Blunt | Slash | Burn } + public enum HitDetection + { + Distance, + Contact + } + struct AttackResult { public readonly float Damage; @@ -39,90 +45,87 @@ namespace Barotrauma partial class Attack { - public readonly float Range; - public readonly float DamageRange; - public readonly float Duration; + [Serialize(HitDetection.Distance, false)] + public HitDetection HitDetectionType { get; private set; } - public readonly DamageType DamageType; + [Serialize(0.0f, false)] + public float Range { get; private set; } - private readonly float structureDamage; - private readonly float damage; - private readonly float bleedingDamage; + [Serialize(0.0f, false)] + public float DamageRange { get; private set; } - private readonly bool onlyHumans; + [Serialize(0.0f, false)] + public float Duration { get; private set; } - private readonly List statusEffects; + [Serialize(DamageType.None, false)] + public DamageType DamageType { get; private set; } - public readonly float Force; + [Serialize(0.0f, false)] + public float StructureDamage { get; private set; } - public readonly float Torque; + [Serialize(0.0f, false)] + public float Damage { get; private set; } - public readonly float TargetForce; + [Serialize(0.0f, false)] + public float BleedingDamage { get; private set; } - public readonly float SeverLimbsProbability; + [Serialize(0.0f, false)] + public float Stun { get; private set; } + + [Serialize(false, false)] + public bool OnlyHumans { get; private set; } + + [Serialize(0.0f, false)] + public float Force { get; private set; } + + [Serialize(0.0f, false)] + public float Torque { get; private set; } + + [Serialize(0.0f, false)] + public float TargetForce { get; private set; } + + [Serialize(0.0f, false)] + public float SeverLimbsProbability { get; private set; } + + [Serialize(0.0f, false)] + public float Priority { get; private set; } //the indices of the limbs Force is applied on //(if none, force is applied only to the limb the attack is attached to) public readonly List ApplyForceOnLimbs; - public readonly float Stun; - - private float priority; + private readonly List statusEffects; public float GetDamage(float deltaTime) { - return (Duration == 0.0f) ? damage : damage * deltaTime; + return (Duration == 0.0f) ? Damage : Damage * deltaTime; } public float GetBleedingDamage(float deltaTime) { - return (Duration == 0.0f) ? bleedingDamage : bleedingDamage * deltaTime; + return (Duration == 0.0f) ? BleedingDamage : BleedingDamage * deltaTime; } public float GetStructureDamage(float deltaTime) { - return (Duration == 0.0f) ? structureDamage : structureDamage * deltaTime; + return (Duration == 0.0f) ? StructureDamage : StructureDamage * deltaTime; } public Attack(float damage, float structureDamage, float bleedingDamage, float range = 0.0f) { Range = range; DamageRange = range; - this.damage = damage; - this.structureDamage = structureDamage; - this.bleedingDamage = bleedingDamage; + this.Damage = damage; + this.StructureDamage = structureDamage; + this.BleedingDamage = bleedingDamage; } public Attack(XElement element) { - try - { - DamageType = (DamageType)Enum.Parse(typeof(DamageType), element.GetAttributeString("damagetype", "None"), true); - } - catch - { - DamageType = DamageType.None; - } - - damage = element.GetAttributeFloat("damage", 0.0f); - structureDamage = element.GetAttributeFloat("structuredamage", 0.0f); - bleedingDamage = element.GetAttributeFloat("bleedingdamage", 0.0f); - Stun = element.GetAttributeFloat("stun", 0.0f); - - SeverLimbsProbability = element.GetAttributeFloat("severlimbsprobability", 0.0f); - - Force = element.GetAttributeFloat("force", 0.0f); - TargetForce = element.GetAttributeFloat("targetforce", 0.0f); - Torque = element.GetAttributeFloat("torque", 0.0f); - - Range = element.GetAttributeFloat("range", 0.0f); + SerializableProperty.DeserializeProperties(this, element); + DamageRange = element.GetAttributeFloat("damagerange", Range); - Duration = element.GetAttributeFloat("duration", 0.0f); - - priority = element.GetAttributeFloat("priority", 1.0f); - - onlyHumans = element.GetAttributeBool("onlyhumans", false); - + InitProjSpecific(element); string limbIndicesStr = element.GetAttributeString("applyforceonlimbs", ""); @@ -158,7 +161,7 @@ namespace Barotrauma public AttackResult DoDamage(Character attacker, IDamageable target, Vector2 worldPosition, float deltaTime, bool playSound = true) { - if (onlyHumans) + if (OnlyHumans) { Character character = target as Character; if (character != null && character.ConfigPath != Character.HumanConfigFile) return new AttackResult(); @@ -189,7 +192,7 @@ namespace Barotrauma { if (targetLimb == null) return new AttackResult(); - if (onlyHumans) + if (OnlyHumans) { if (targetLimb.character != null && targetLimb.character.ConfigPath != Character.HumanConfigFile) return new AttackResult(); } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs index c0d435e75..9c1e1e2ab 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Limb.cs @@ -2,6 +2,7 @@ using Barotrauma.Items.Components; using FarseerPhysics; using FarseerPhysics.Dynamics; +using FarseerPhysics.Dynamics.Contacts; using FarseerPhysics.Dynamics.Joints; using Microsoft.Xna.Framework; using System; @@ -479,12 +480,69 @@ namespace Barotrauma body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque); - if (dist < attack.DamageRange) + bool wasHit = false; + + if (damageTarget != null) + { + switch (attack.HitDetectionType) + { + case HitDetection.Distance: + wasHit = dist < attack.DamageRange; + break; + case HitDetection.Contact: + List targetBodies = new List(); + if (damageTarget is Character) + { + Character targetCharacter = (Character)damageTarget; + foreach (Limb limb in targetCharacter.AnimController.Limbs) + { + if (!limb.IsSevered && limb.body?.FarseerBody != null) targetBodies.Add(limb.body.FarseerBody); + } + } + else if (damageTarget is Structure) + { + Structure targetStructure = (Structure)damageTarget; + + if (character.Submarine == null && targetStructure.Submarine != null) + { + targetBodies.Add(targetStructure.Submarine.PhysicsBody.FarseerBody); + } + else + { + targetBodies.AddRange(targetStructure.Bodies); + } + } + else if (damageTarget is Item) + { + Item targetItem = damageTarget as Item; + if (targetItem.body?.FarseerBody != null) targetBodies.Add(targetItem.body.FarseerBody); + } + + if (targetBodies != null) + { + ContactEdge contactEdge = body.FarseerBody.ContactList; + while (contactEdge != null) + { + if (contactEdge.Contact != null && + contactEdge.Contact.IsTouching && + targetBodies.Any(b => b == contactEdge.Contact.FixtureA?.Body || b == contactEdge.Contact.FixtureB?.Body)) + { + wasHit = true; + break; + } + + contactEdge = contactEdge.Next; + } + } + break; + } + } + + if (wasHit) { if (AttackTimer >= attack.Duration && damageTarget != null) { attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f)); - SoundTimer = SoundInterval; } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs index beb737fb9..86f51b512 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs @@ -89,6 +89,11 @@ namespace Barotrauma get { return prefab.Body; } } + public List Bodies + { + get { return bodies; } + } + public bool CastShadow { get { return prefab.CastShadow; } @@ -651,23 +656,28 @@ namespace Barotrauma Vector2 transformedPos = worldPosition; if (Submarine != null) transformedPos -= Submarine.Position; - int i = FindSectionIndex(transformedPos); - if (i == -1) return new AttackResult(0.0f, 0.0f); - - float damageAmount = attack.GetStructureDamage(deltaTime); - - AddDamage(i, damageAmount, attacker); + float damageAmount = 0.0f; + for (int i = 0; i < SectionCount; i++) + { + if (Vector2.DistanceSquared(SectionPosition(i, true), worldPosition) <= attack.DamageRange * attack.DamageRange) + { + damageAmount = attack.GetStructureDamage(deltaTime); + AddDamage(i, damageAmount, attacker); #if CLIENT GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f); +#endif + } + } +#if CLIENT if (playSound)// && !SectionBodyDisabled(i)) { DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash; SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags); } #endif - + return new AttackResult(damageAmount, 0.0f); }