diff --git a/Barotrauma/Content/Characters/Carrier/carrier.xml b/Barotrauma/Content/Characters/Carrier/carrier.xml index 161ed1d71..268b41d76 100644 --- a/Barotrauma/Content/Characters/Carrier/carrier.xml +++ b/Barotrauma/Content/Characters/Carrier/carrier.xml @@ -54,10 +54,10 @@ - - + + - + diff --git a/Barotrauma/Content/Characters/Crawler/crawler.xml b/Barotrauma/Content/Characters/Crawler/crawler.xml index 649123d8a..42bb69cee 100644 --- a/Barotrauma/Content/Characters/Crawler/crawler.xml +++ b/Barotrauma/Content/Characters/Crawler/crawler.xml @@ -71,21 +71,21 @@ - + - + - + - - + + - - + + - - + + diff --git a/Barotrauma/Content/Characters/Fractalguardian/fractalguardian.xml b/Barotrauma/Content/Characters/Fractalguardian/fractalguardian.xml index 9cfe763b5..abb438036 100644 --- a/Barotrauma/Content/Characters/Fractalguardian/fractalguardian.xml +++ b/Barotrauma/Content/Characters/Fractalguardian/fractalguardian.xml @@ -49,14 +49,14 @@ - + - + - + - - + + diff --git a/Barotrauma/Content/Characters/Fractalguardian2/fractalguardian2.xml b/Barotrauma/Content/Characters/Fractalguardian2/fractalguardian2.xml index d665dde72..c3841f2c4 100644 --- a/Barotrauma/Content/Characters/Fractalguardian2/fractalguardian2.xml +++ b/Barotrauma/Content/Characters/Fractalguardian2/fractalguardian2.xml @@ -43,11 +43,11 @@ - - + + - - + + diff --git a/Barotrauma/Content/Characters/Human/human.xml b/Barotrauma/Content/Characters/Human/human.xml index 0f2e5d1ed..aaa479462 100644 --- a/Barotrauma/Content/Characters/Human/human.xml +++ b/Barotrauma/Content/Characters/Human/human.xml @@ -84,25 +84,25 @@ - - + + - + - + - - - + + + - - - + + + diff --git a/Barotrauma/Content/Characters/Human/humanhusk.xml b/Barotrauma/Content/Characters/Human/humanhusk.xml index 303981949..9b8b82df6 100644 --- a/Barotrauma/Content/Characters/Human/humanhusk.xml +++ b/Barotrauma/Content/Characters/Human/humanhusk.xml @@ -91,27 +91,27 @@ - - + + - + - + - - - + + + - - - + + + - + diff --git a/Barotrauma/Content/Characters/Husk/husk.xml b/Barotrauma/Content/Characters/Husk/husk.xml index 33952ffb0..3bd593b42 100644 --- a/Barotrauma/Content/Characters/Husk/husk.xml +++ b/Barotrauma/Content/Characters/Husk/husk.xml @@ -92,28 +92,28 @@ - + - + - + - + - + - - - + + + - - - + + + diff --git a/Barotrauma/Content/Characters/Mantis/mantis.xml b/Barotrauma/Content/Characters/Mantis/mantis.xml index 5c337d46d..202f16022 100644 --- a/Barotrauma/Content/Characters/Mantis/mantis.xml +++ b/Barotrauma/Content/Characters/Mantis/mantis.xml @@ -81,22 +81,22 @@ - + - + - + - - - + + + - - + + - - + + diff --git a/Barotrauma/Content/Characters/Moloch/moloch.xml b/Barotrauma/Content/Characters/Moloch/moloch.xml index 617384afd..30ab3d997 100644 --- a/Barotrauma/Content/Characters/Moloch/moloch.xml +++ b/Barotrauma/Content/Characters/Moloch/moloch.xml @@ -54,17 +54,17 @@ - - - + + + - - - + + + - - - + + + diff --git a/Barotrauma/Source/Characters/Animation/FishAnimController.cs b/Barotrauma/Source/Characters/Animation/FishAnimController.cs index bce305169..5b3188d6c 100644 --- a/Barotrauma/Source/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/Source/Characters/Animation/FishAnimController.cs @@ -260,7 +260,7 @@ namespace Barotrauma if (limb.RefJointIndex>-1) { - RevoluteJoint refJoint = limbJoints[limb.RefJointIndex]; + RevoluteJoint refJoint = LimbJoints[limb.RefJointIndex]; footPos.X = refJoint.WorldAnchorA.X; } footPos.X += limb.StepOffset.X * Dir; diff --git a/Barotrauma/Source/Characters/Animation/HumanoidAnimController.cs b/Barotrauma/Source/Characters/Animation/HumanoidAnimController.cs index d359ce3a0..2be6776b8 100644 --- a/Barotrauma/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Barotrauma/Source/Characters/Animation/HumanoidAnimController.cs @@ -1012,7 +1012,7 @@ namespace Barotrauma itemAngle = (torso.body.Rotation + holdAngle * Dir); } - Vector2 shoulderPos = limbJoints[2].WorldAnchorA; + Vector2 shoulderPos = LimbJoints[2].WorldAnchorA; Vector2 transformedHoldPos = shoulderPos; if (itemPos == Vector2.Zero || Anim == Animation.Climbing || usingController) @@ -1071,7 +1071,7 @@ namespace Barotrauma private void HandIK(Limb hand, Vector2 pos, float force = 1.0f) { - Vector2 shoulderPos = limbJoints[2].WorldAnchorA; + Vector2 shoulderPos = LimbJoints[2].WorldAnchorA; Limb arm = (hand.type == LimbType.LeftHand) ? GetLimb(LimbType.LeftArm) : GetLimb(LimbType.RightArm); diff --git a/Barotrauma/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/Source/Characters/Animation/Ragdoll.cs index f069d5d1f..51cfb642d 100644 --- a/Barotrauma/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/Source/Characters/Animation/Ragdoll.cs @@ -28,17 +28,13 @@ namespace Barotrauma if (frozen == value) return; frozen = value; - - /*foreach (Limb l in Limbs) - { - l.body.PhysEnabled = !frozen; - }*/ + Collider.PhysEnabled = !frozen; } } private Dictionary limbDictionary; - public RevoluteJoint[] limbJoints; + public LimbJoint[] LimbJoints; private bool simplePhysicsEnabled; @@ -166,7 +162,7 @@ namespace Barotrauma limb.body.Enabled = !simplePhysicsEnabled; } - foreach (RevoluteJoint joint in limbJoints) + foreach (RevoluteJoint joint in LimbJoints) { joint.Enabled = !simplePhysicsEnabled; } @@ -278,9 +274,9 @@ namespace Barotrauma float scale = ToolBox.GetAttributeFloat(element, "scale", 1.0f); - Limbs = new Limb[element.Elements("limb").Count()]; - limbJoints = new RevoluteJoint[element.Elements("joint").Count()]; - limbDictionary = new Dictionary(); + Limbs = new Limb[element.Elements("limb").Count()]; + LimbJoints = new LimbJoint[element.Elements("joint").Count()]; + limbDictionary = new Dictionary(); headPosition = ToolBox.GetAttributeFloat(element, "headposition", 50.0f); headPosition = ConvertUnits.ToSimUnits(headPosition); @@ -346,7 +342,7 @@ namespace Barotrauma UpdateCollisionCategories(); - foreach (var joint in limbJoints) + foreach (var joint in LimbJoints) { joint.BodyB.SetTransform( joint.BodyA.Position + (joint.LocalAnchorA - joint.LocalAnchorB)*0.1f, @@ -385,9 +381,8 @@ namespace Barotrauma Vector2 limb2Pos = ToolBox.GetAttributeVector2(subElement, "limb2anchor", Vector2.Zero) * scale; limb2Pos = ConvertUnits.ToSimUnits(limb2Pos); - RevoluteJoint joint = new RevoluteJoint(Limbs[limb1ID].body.FarseerBody, Limbs[limb2ID].body.FarseerBody, limb1Pos, limb2Pos); - - joint.CollideConnected = false; + LimbJoint joint = new LimbJoint(Limbs[limb1ID], Limbs[limb2ID], limb1Pos, limb2Pos); + joint.CanBeSevered = ToolBox.GetAttributeBool(subElement, "canbesevered", false); if (subElement.Attribute("lowerlimit") != null) { @@ -396,22 +391,18 @@ namespace Barotrauma joint.UpperLimit = float.Parse(subElement.Attribute("upperlimit").Value) * ((float)Math.PI / 180.0f); } - joint.MotorEnabled = true; - joint.MaxMotorTorque = 0.25f; - GameMain.World.AddJoint(joint); - for (int i = 0; i < limbJoints.Length; i++) + for (int i = 0; i < LimbJoints.Length; i++) { - if (limbJoints[i] != null) continue; + if (LimbJoints[i] != null) continue; - limbJoints[i] = joint; + LimbJoints[i] = joint; return; } - Array.Resize(ref limbJoints, limbJoints.Length + 1); - limbJoints[limbJoints.Length - 1] = joint; - + Array.Resize(ref LimbJoints, LimbJoints.Length + 1); + LimbJoints[LimbJoints.Length - 1] = joint; } public void AddLimb(Limb limb) @@ -531,6 +522,51 @@ namespace Barotrauma } } + public void SeverLimbJoint(LimbJoint limbJoint) + { + limbJoint.IsSevered = true; + limbJoint.Enabled = false; + + List connectedLimbs = new List(); + List checkedJoints = new List(); + + GetConnectedLimbs(connectedLimbs, checkedJoints, MainLimb); + foreach (Limb limb in Limbs) + { + if (!connectedLimbs.Contains(limb)) + { + limb.IsSevered = true; + } + } + + } + + private void GetConnectedLimbs(List connectedLimbs, List checkedJoints, Limb limb) + { + connectedLimbs.Add(limb); + + foreach (LimbJoint joint in LimbJoints) + { + if (joint.IsSevered || checkedJoints.Contains(joint)) continue; + if (joint.LimbA == limb) + { + if (!connectedLimbs.Contains(joint.LimbB)) + { + checkedJoints.Add(joint); + GetConnectedLimbs(connectedLimbs, checkedJoints, joint.LimbB); + } + } + else if (joint.LimbB == limb) + { + if (!connectedLimbs.Contains(joint.LimbA)) + { + checkedJoints.Add(joint); + GetConnectedLimbs(connectedLimbs, checkedJoints, joint.LimbA); + } + } + } + } + public virtual void Draw(SpriteBatch spriteBatch) { if (simplePhysicsEnabled) return; @@ -559,13 +595,15 @@ namespace Barotrauma GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), Color.Red, true, 0.01f); } - limb.body.DebugDraw(spriteBatch, inWater ? Color.Cyan : Color.White); + Color limbColor = inWater ? Color.Cyan : Color.White; + if (limb.IsSevered) limbColor = Color.Red; + limb.body.DebugDraw(spriteBatch, limbColor); } Collider.DebugDraw(spriteBatch, frozen ? Color.Red : (inWater ? Color.SkyBlue : Color.Gray)); GUI.Font.DrawString(spriteBatch, Collider.LinearVelocity.X.ToString(), new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y), Color.Orange); - foreach (RevoluteJoint joint in limbJoints) + foreach (RevoluteJoint joint in LimbJoints) { Vector2 pos = ConvertUnits.ToDisplayUnits(joint.WorldAnchorA); GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.White, true); @@ -619,22 +657,22 @@ namespace Barotrauma { dir = (dir == Direction.Left) ? Direction.Right : Direction.Left; - for (int i = 0; i < limbJoints.Length; i++) + for (int i = 0; i < LimbJoints.Length; i++) { - float lowerLimit = -limbJoints[i].UpperLimit; - float upperLimit = -limbJoints[i].LowerLimit; + float lowerLimit = -LimbJoints[i].UpperLimit; + float upperLimit = -LimbJoints[i].LowerLimit; - limbJoints[i].LowerLimit = lowerLimit; - limbJoints[i].UpperLimit = upperLimit; + LimbJoints[i].LowerLimit = lowerLimit; + LimbJoints[i].UpperLimit = upperLimit; - limbJoints[i].LocalAnchorA = new Vector2(-limbJoints[i].LocalAnchorA.X, limbJoints[i].LocalAnchorA.Y); - limbJoints[i].LocalAnchorB = new Vector2(-limbJoints[i].LocalAnchorB.X, limbJoints[i].LocalAnchorB.Y); + LimbJoints[i].LocalAnchorA = new Vector2(-LimbJoints[i].LocalAnchorA.X, LimbJoints[i].LocalAnchorA.Y); + LimbJoints[i].LocalAnchorB = new Vector2(-LimbJoints[i].LocalAnchorB.X, LimbJoints[i].LocalAnchorB.Y); } foreach (Limb limb in Limbs) { - if (limb == null) continue; + if (limb == null || limb.IsSevered) continue; if (limb.sprite != null) { @@ -665,6 +703,7 @@ namespace Barotrauma Vector2 centerOfMass = Vector2.Zero; foreach (Limb limb in Limbs) { + if (limb.IsSevered) continue; centerOfMass += limb.Mass * limb.SimPosition; } @@ -769,6 +808,7 @@ namespace Barotrauma { foreach (Limb limb in Limbs) { + if (limb.IsSevered) continue; if (limb.body.FarseerBody.ContactList == null) continue; ContactEdge ce = limb.body.FarseerBody.ContactList; @@ -781,6 +821,7 @@ namespace Barotrauma foreach (Limb limb in Limbs) { + if (limb.IsSevered) continue; limb.body.LinearVelocity += velocityChange; } @@ -805,7 +846,7 @@ namespace Barotrauma foreach (Limb limb in Limbs) { - if (limb.ignoreCollisions) continue; + if (limb.ignoreCollisions || limb.IsSevered) continue; try { @@ -1145,6 +1186,7 @@ namespace Barotrauma foreach (Limb limb in Limbs) { + if (limb.IsSevered) continue; //check visibility from the new position of the collider to the new position of this limb Vector2 movePos = limb.SimPosition + limbMoveAmount; @@ -1208,6 +1250,7 @@ namespace Barotrauma //(in case the ragdoll has gotten stuck somewhere) foreach (Limb limb in Limbs) { + if (limb.IsSevered) continue; limb.body.CollidesWith = Physics.CollisionNone; } @@ -1474,11 +1517,11 @@ namespace Barotrauma b.Remove(); } - foreach (RevoluteJoint joint in limbJoints) + foreach (RevoluteJoint joint in LimbJoints) { GameMain.World.RemoveJoint(joint); } - limbJoints = null; + LimbJoints = null; list.Remove(this); } diff --git a/Barotrauma/Source/Characters/Character.cs b/Barotrauma/Source/Characters/Character.cs index 0611d161f..86d5956b1 100644 --- a/Barotrauma/Source/Characters/Character.cs +++ b/Barotrauma/Source/Characters/Character.cs @@ -1755,10 +1755,31 @@ namespace Barotrauma AttackResult attackResult = closestLimb.AddDamage(worldPosition, damageType, amount, bleedingAmount, playSound); + //sever joints connected to the limb if the character was killed + //with an attack stronger than 50% of the characters max health + //TODO: maybe add a "CanSever" option to attacks + if (health - attackResult.Damage <= minHealth && attackResult.Damage >= MaxHealth * 0.5f) + { + foreach (LimbJoint joint in AnimController.LimbJoints) + { + if (joint.CanBeSevered && (joint.LimbA == closestLimb || joint.LimbB == closestLimb)) + { + AnimController.SeverLimbJoint(joint); + + if (joint.LimbA == closestLimb) + { + joint.LimbB.body.LinearVelocity = closestLimb.LinearVelocity*0.5f; + } + else + { + joint.LimbA.body.LinearVelocity = closestLimb.LinearVelocity * 0.5f; + } + } + } + } + AddDamage(damageType == DamageType.Burn ? CauseOfDeath.Burn : causeOfDeath, attackResult.Damage, null); - - //health -= attackResult.Damage; - //if (health <= 0.0f && damageType == DamageType.Burn) Kill(CauseOfDeath.Burn); + if (DoesBleed) { Bleeding += attackResult.Bleeding; @@ -1832,7 +1853,7 @@ namespace Barotrauma new Vector2(Rand.Range(-50f, 50f), Rand.Range(-100f, 50f))); } - foreach (var joint in AnimController.limbJoints) + foreach (var joint in AnimController.LimbJoints) { joint.LimitEnabled = false; } @@ -1895,7 +1916,7 @@ namespace Barotrauma limb.pullJoint.Enabled = false; } - foreach (RevoluteJoint joint in AnimController.limbJoints) + foreach (RevoluteJoint joint in AnimController.LimbJoints) { joint.MotorEnabled = false; } @@ -1914,9 +1935,16 @@ namespace Barotrauma Health = Math.Max(maxHealth * 0.1f, health); - foreach (RevoluteJoint joint in AnimController.limbJoints) + foreach (LimbJoint joint in AnimController.LimbJoints) { joint.MotorEnabled = true; + joint.Enabled = true; + joint.IsSevered = false; + } + + foreach (Limb limb in AnimController.Limbs) + { + limb.IsSevered = false; } if (GameMain.GameSession != null) diff --git a/Barotrauma/Source/Characters/CharacterNetworking.cs b/Barotrauma/Source/Characters/CharacterNetworking.cs index 0f52f1c80..83ef5b208 100644 --- a/Barotrauma/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/Source/Characters/CharacterNetworking.cs @@ -638,6 +638,19 @@ namespace Barotrauma if (isDead) { msg.Write((byte)causeOfDeath); + List severedJointIndices = new List(); + for (int i = 0; i < AnimController.LimbJoints.Length; i++) + { + if (AnimController.LimbJoints[i] != null && AnimController.LimbJoints[i].IsSevered) + { + severedJointIndices.Add(i); + } + } + msg.Write((byte)severedJointIndices.Count); + foreach (int jointIndex in severedJointIndices) + { + msg.Write((byte)jointIndex); + } } else { @@ -677,6 +690,7 @@ namespace Barotrauma if (isDead) { causeOfDeath = (CauseOfDeath)msg.ReadByte(); + byte severedLimbCount = msg.ReadByte(); if (causeOfDeath == CauseOfDeath.Pressure) { Implode(true); @@ -685,6 +699,11 @@ namespace Barotrauma { Kill(causeOfDeath, true); } + for (int i = 0; i < severedLimbCount; i++) + { + int severedJointIndex = msg.ReadByte(); + AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]); + } } else { diff --git a/Barotrauma/Source/Characters/Limb.cs b/Barotrauma/Source/Characters/Limb.cs index 246176e64..1853e2d9f 100644 --- a/Barotrauma/Source/Characters/Limb.cs +++ b/Barotrauma/Source/Characters/Limb.cs @@ -19,6 +19,25 @@ namespace Barotrauma LeftLeg, RightLeg, LeftFoot, RightFoot, Head, Torso, Tail, Legs, RightThigh, LeftThigh, Waist }; + class LimbJoint : RevoluteJoint + { + public bool IsSevered; + public bool CanBeSevered; + + public readonly Limb LimbA, LimbB; + + public LimbJoint(Limb limbA, Limb limbB, Vector2 anchor1, Vector2 anchor2) + : base(limbA.body.FarseerBody, limbB.body.FarseerBody, anchor1, anchor2) + { + CollideConnected = false; + MotorEnabled = true; + MaxMotorTorque = 0.25f; + + LimbA = limbA; + LimbB = limbB; + } + } + class Limb { private const float LimbDensity = 15; @@ -66,7 +85,13 @@ namespace Barotrauma private List wearingItems; private Vector2 animTargetPos; + + private float scale; + public float AttackTimer; + + public bool IsSevered; + public bool DoesFlip { get { return doesFlip; } @@ -141,49 +166,17 @@ namespace Barotrauma get { return burnt; } set { burnt = MathHelper.Clamp(value,0.0f,100.0f); } } - - private float scale; - - public float AttackTimer; - - //public float Damage - //{ - // get { return damage; } - // set - // { - // damage = Math.Max(value, 0.0f); - // if (damage >=maxHealth) Character.Kill(); - // } - //} - - //public float MaxHealth - //{ - // get { return maxHealth; } - //} - - //public float Bleeding - //{ - // get { return bleeding; } - // set { bleeding = MathHelper.Clamp(value, 0.0f, 100.0f); } - //} - + public List WearingItems { get { return wearingItems; } - set { wearingItems = value; } } - - //public WearableSprite WearingItemSprite - //{ - // get { return wearingItemSprite; } - // set { wearingItemSprite = value; } - //} - + public Limb (Character character, XElement element, float scale = 1.0f) { this.character = character; - WearingItems = new List(); + wearingItems = new List(); dir = Direction.Right; diff --git a/Barotrauma/Source/Screens/EditCharacterScreen.cs b/Barotrauma/Source/Screens/EditCharacterScreen.cs index 5c70fbd7b..4417ad71b 100644 --- a/Barotrauma/Source/Screens/EditCharacterScreen.cs +++ b/Barotrauma/Source/Screens/EditCharacterScreen.cs @@ -217,7 +217,7 @@ namespace Barotrauma } jointList.ClearChildren(); - foreach (RevoluteJoint joint in character.AnimController.limbJoints) + foreach (RevoluteJoint joint in character.AnimController.LimbJoints) { Limb limb1 = (Limb)(joint.BodyA.UserData); Limb limb2 = (Limb)(joint.BodyB.UserData); @@ -236,7 +236,7 @@ namespace Barotrauma private void DrawJoints(SpriteBatch spriteBatch, Limb limb, Vector2 limbBodyPos) { - foreach (var joint in editingCharacter.AnimController.limbJoints) + foreach (var joint in editingCharacter.AnimController.LimbJoints) { Vector2 jointPos = Vector2.Zero;