Option to make limb attacks do damage based on contact with physics bodies instead of distance. Attacks also do damage to all sections of a structure that are within damage range. Closes #108
This commit is contained in:
@@ -5,7 +5,6 @@ using Microsoft.Xna.Framework.Graphics;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,12 +54,12 @@
|
|||||||
|
|
||||||
<limb id = "8" width="50" height="320">
|
<limb id = "8" width="50" height="320">
|
||||||
<sprite texture="Content/Characters/Endworm/endworm.png" sourcerect="755,552,137,470" depth="0.08" origin="0.5,0.5"/>
|
<sprite texture="Content/Characters/Endworm/endworm.png" sourcerect="755,552,137,470" depth="0.08" origin="0.5,0.5"/>
|
||||||
<attack range="1400" damagerange="1300" duration="0.5" damage="30" stun="5.0" force="100" torque="-100" structuredamage="500" damagetype="slash"/>
|
<attack range="1000" hitdetectiontype="Contact" duration="0.25" damage="30" stun="5.0" force="100" torque="-100" structuredamage="500" damagetype="slash"/>
|
||||||
</limb>
|
</limb>
|
||||||
|
|
||||||
<limb id = "9" width="50" height="320">
|
<limb id = "9" width="50" height="320">
|
||||||
<sprite texture="Content/Characters/Endworm/endworm.png" sourcerect="892,552,137,470" depth="0.08" origin="0.6,0.5"/>
|
<sprite texture="Content/Characters/Endworm/endworm.png" sourcerect="892,552,137,470" depth="0.08" origin="0.6,0.5"/>
|
||||||
<attack range="1400" damagerange="1300" duration="0.5" damage="30" stun="5.0" force="100" torque="100" structuredamage="500" damagetype="slash"/>
|
<attack range="1000" hitdetectiontype="Contact" duration="0.25" damage="30" stun="5.0" force="100" torque="100" structuredamage="500" damagetype="slash"/>
|
||||||
</limb>
|
</limb>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ namespace Barotrauma
|
|||||||
Any = Blunt | Slash | Burn
|
Any = Blunt | Slash | Burn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum HitDetection
|
||||||
|
{
|
||||||
|
Distance,
|
||||||
|
Contact
|
||||||
|
}
|
||||||
|
|
||||||
struct AttackResult
|
struct AttackResult
|
||||||
{
|
{
|
||||||
public readonly float Damage;
|
public readonly float Damage;
|
||||||
@@ -39,90 +45,87 @@ namespace Barotrauma
|
|||||||
|
|
||||||
partial class Attack
|
partial class Attack
|
||||||
{
|
{
|
||||||
public readonly float Range;
|
[Serialize(HitDetection.Distance, false)]
|
||||||
public readonly float DamageRange;
|
public HitDetection HitDetectionType { get; private set; }
|
||||||
public readonly float Duration;
|
|
||||||
|
|
||||||
public readonly DamageType DamageType;
|
[Serialize(0.0f, false)]
|
||||||
|
public float Range { get; private set; }
|
||||||
|
|
||||||
private readonly float structureDamage;
|
[Serialize(0.0f, false)]
|
||||||
private readonly float damage;
|
public float DamageRange { get; private set; }
|
||||||
private readonly float bleedingDamage;
|
|
||||||
|
|
||||||
private readonly bool onlyHumans;
|
[Serialize(0.0f, false)]
|
||||||
|
public float Duration { get; private set; }
|
||||||
|
|
||||||
private readonly List<StatusEffect> 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
|
//the indices of the limbs Force is applied on
|
||||||
//(if none, force is applied only to the limb the attack is attached to)
|
//(if none, force is applied only to the limb the attack is attached to)
|
||||||
public readonly List<int> ApplyForceOnLimbs;
|
public readonly List<int> ApplyForceOnLimbs;
|
||||||
|
|
||||||
public readonly float Stun;
|
private readonly List<StatusEffect> statusEffects;
|
||||||
|
|
||||||
private float priority;
|
|
||||||
|
|
||||||
public float GetDamage(float deltaTime)
|
public float GetDamage(float deltaTime)
|
||||||
{
|
{
|
||||||
return (Duration == 0.0f) ? damage : damage * deltaTime;
|
return (Duration == 0.0f) ? Damage : Damage * deltaTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float GetBleedingDamage(float 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)
|
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)
|
public Attack(float damage, float structureDamage, float bleedingDamage, float range = 0.0f)
|
||||||
{
|
{
|
||||||
Range = range;
|
Range = range;
|
||||||
DamageRange = range;
|
DamageRange = range;
|
||||||
this.damage = damage;
|
this.Damage = damage;
|
||||||
this.structureDamage = structureDamage;
|
this.StructureDamage = structureDamage;
|
||||||
this.bleedingDamage = bleedingDamage;
|
this.BleedingDamage = bleedingDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attack(XElement element)
|
public Attack(XElement element)
|
||||||
{
|
{
|
||||||
try
|
SerializableProperty.DeserializeProperties(this, element);
|
||||||
{
|
|
||||||
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);
|
|
||||||
DamageRange = element.GetAttributeFloat("damagerange", Range);
|
DamageRange = element.GetAttributeFloat("damagerange", Range);
|
||||||
Duration = element.GetAttributeFloat("duration", 0.0f);
|
|
||||||
|
|
||||||
priority = element.GetAttributeFloat("priority", 1.0f);
|
|
||||||
|
|
||||||
onlyHumans = element.GetAttributeBool("onlyhumans", false);
|
|
||||||
|
|
||||||
InitProjSpecific(element);
|
InitProjSpecific(element);
|
||||||
|
|
||||||
string limbIndicesStr = element.GetAttributeString("applyforceonlimbs", "");
|
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)
|
public AttackResult DoDamage(Character attacker, IDamageable target, Vector2 worldPosition, float deltaTime, bool playSound = true)
|
||||||
{
|
{
|
||||||
if (onlyHumans)
|
if (OnlyHumans)
|
||||||
{
|
{
|
||||||
Character character = target as Character;
|
Character character = target as Character;
|
||||||
if (character != null && character.ConfigPath != Character.HumanConfigFile) return new AttackResult();
|
if (character != null && character.ConfigPath != Character.HumanConfigFile) return new AttackResult();
|
||||||
@@ -189,7 +192,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (targetLimb == null) return new AttackResult();
|
if (targetLimb == null) return new AttackResult();
|
||||||
|
|
||||||
if (onlyHumans)
|
if (OnlyHumans)
|
||||||
{
|
{
|
||||||
if (targetLimb.character != null && targetLimb.character.ConfigPath != Character.HumanConfigFile) return new AttackResult();
|
if (targetLimb.character != null && targetLimb.character.ConfigPath != Character.HumanConfigFile) return new AttackResult();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using FarseerPhysics;
|
using FarseerPhysics;
|
||||||
using FarseerPhysics.Dynamics;
|
using FarseerPhysics.Dynamics;
|
||||||
|
using FarseerPhysics.Dynamics.Contacts;
|
||||||
using FarseerPhysics.Dynamics.Joints;
|
using FarseerPhysics.Dynamics.Joints;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
@@ -479,12 +480,69 @@ namespace Barotrauma
|
|||||||
|
|
||||||
body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque);
|
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<Body> targetBodies = new List<Body>();
|
||||||
|
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)
|
if (AttackTimer >= attack.Duration && damageTarget != null)
|
||||||
{
|
{
|
||||||
attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f));
|
attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f));
|
||||||
|
|
||||||
SoundTimer = SoundInterval;
|
SoundTimer = SoundInterval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ namespace Barotrauma
|
|||||||
get { return prefab.Body; }
|
get { return prefab.Body; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Body> Bodies
|
||||||
|
{
|
||||||
|
get { return bodies; }
|
||||||
|
}
|
||||||
|
|
||||||
public bool CastShadow
|
public bool CastShadow
|
||||||
{
|
{
|
||||||
get { return prefab.CastShadow; }
|
get { return prefab.CastShadow; }
|
||||||
@@ -651,23 +656,28 @@ namespace Barotrauma
|
|||||||
Vector2 transformedPos = worldPosition;
|
Vector2 transformedPos = worldPosition;
|
||||||
if (Submarine != null) transformedPos -= Submarine.Position;
|
if (Submarine != null) transformedPos -= Submarine.Position;
|
||||||
|
|
||||||
int i = FindSectionIndex(transformedPos);
|
float damageAmount = 0.0f;
|
||||||
if (i == -1) return new AttackResult(0.0f, 0.0f);
|
for (int i = 0; i < SectionCount; i++)
|
||||||
|
{
|
||||||
float damageAmount = attack.GetStructureDamage(deltaTime);
|
if (Vector2.DistanceSquared(SectionPosition(i, true), worldPosition) <= attack.DamageRange * attack.DamageRange)
|
||||||
|
{
|
||||||
AddDamage(i, damageAmount, attacker);
|
damageAmount = attack.GetStructureDamage(deltaTime);
|
||||||
|
AddDamage(i, damageAmount, attacker);
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CLIENT
|
||||||
if (playSound)// && !SectionBodyDisabled(i))
|
if (playSound)// && !SectionBodyDisabled(i))
|
||||||
{
|
{
|
||||||
DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash;
|
DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash;
|
||||||
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
|
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return new AttackResult(damageAmount, 0.0f);
|
return new AttackResult(damageAmount, 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user