Unstable 0.1500.5.0 (almost forgor edition 💀)

This commit is contained in:
Markus Isberg
2021-10-01 23:56:14 +09:00
parent 3043a9a7bc
commit 08bdfc6cea
150 changed files with 5669 additions and 4403 deletions
@@ -1,12 +1,31 @@
using FarseerPhysics;
using Barotrauma.Items.Components;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
abstract class AnimController : Ragdoll
{
public Vector2 RightHandIKPos { get; protected set; }
public Vector2 LeftHandIKPos { get; protected set; }
protected LimbJoint rightShoulder, leftShoulder;
protected float upperArmLength, forearmLength;
protected float useItemTimer;
protected bool aiming;
protected bool wasAiming;
protected bool aimingMelee;
protected bool wasAimingMelee;
public bool IsAiming => wasAiming;
public bool IsAimingMelee => wasAimingMelee;
public float ArmLength => upperArmLength + forearmLength;
public abstract GroundedMovementParams WalkParams { get; set; }
public abstract GroundedMovementParams RunParams { get; set; }
public abstract SwimParams SwimSlowParams { get; set; }
@@ -60,14 +79,14 @@ namespace Barotrauma
}
else
{
return IsMovingFast? SwimFastParams : SwimSlowParams;
return IsMovingFast ? SwimFastParams : SwimSlowParams;
}
}
}
public bool CanWalk => RagdollParams.CanWalk;
public bool IsMovingBackwards => !InWater && Math.Sign(targetMovement.X) == -Math.Sign(Dir);
// TODO: define death anim duration in XML
protected float deathAnimTimer, deathAnimDuration = 5.0f;
@@ -155,13 +174,9 @@ namespace Barotrauma
public AnimController(Character character, string seed, RagdollParams ragdollParams = null) : base(character, seed, ragdollParams) { }
public virtual void UpdateAnim(float deltaTime) { }
public abstract void UpdateAnim(float deltaTime);
public virtual void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimingMelee = false) { }
public virtual void DragCharacter(Character target, float deltaTime) { }
public virtual void UpdateUseItem(bool allowMovement, Vector2 handWorldPos) { }
public abstract void DragCharacter(Character target, float deltaTime);
public virtual float GetSpeed(AnimationType type)
{
@@ -253,5 +268,437 @@ namespace Barotrauma
throw new NotImplementedException(type.ToString());
}
}
public void UpdateUseItem(bool allowMovement, Vector2 handWorldPos)
{
useItemTimer = 0.5f;
Anim = Animation.UsingConstruction;
if (!allowMovement)
{
TargetMovement = Vector2.Zero;
TargetDir = handWorldPos.X > character.WorldPosition.X ? Direction.Right : Direction.Left;
float sqrDist = Vector2.DistanceSquared(character.WorldPosition, handWorldPos);
if (sqrDist > MathUtils.Pow(ConvertUnits.ToDisplayUnits(upperArmLength + forearmLength), 2))
{
TargetMovement = Vector2.Normalize(handWorldPos - character.WorldPosition) * GetCurrentSpeed(false) * Math.Max(character.SpeedMultiplier, 1);
}
}
if (!character.Enabled) { return; }
Vector2 handSimPos = ConvertUnits.ToSimUnits(handWorldPos);
if (character.Submarine != null)
{
handSimPos -= character.Submarine.SimPosition;
}
var leftHand = GetLimb(LimbType.LeftHand);
if (leftHand != null)
{
leftHand.Disabled = true;
leftHand.PullJointEnabled = true;
leftHand.PullJointWorldAnchorB = handSimPos;
}
var rightHand = GetLimb(LimbType.RightHand);
if (rightHand != null)
{
rightHand.Disabled = true;
rightHand.PullJointEnabled = true;
rightHand.PullJointWorldAnchorB = handSimPos;
}
}
public void Grab(Vector2 rightHandPos, Vector2 leftHandPos)
{
for (int i = 0; i < 2; i++)
{
Limb pullLimb = (i == 0) ? GetLimb(LimbType.LeftHand) : GetLimb(LimbType.RightHand);
pullLimb.Disabled = true;
pullLimb.PullJointEnabled = true;
pullLimb.PullJointWorldAnchorB = (i == 0) ? rightHandPos : leftHandPos;
pullLimb.PullJointMaxForce = 500.0f;
}
}
private Direction previousDirection;
private readonly Vector2[] transformedHandlePos = new Vector2[2];
//TODO: refactor this method, it's way too convoluted
public void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimMelee = false)
{
aimingMelee = aimMelee;
if (character.Stun > 0.0f || character.IsIncapacitated)
{
aim = false;
}
//calculate the handle positions
Matrix itemTransfrom = Matrix.CreateRotationZ(item.body.Rotation);
float horizontalOffset = ConvertUnits.ToSimUnits((item.Sprite.size.X / 2 - item.Sprite.Origin.X) * item.Scale);
//handlePos[0] = ConvertUnits.ToSimUnits(new Vector2(-45,25) * 0.5f);
//handlePos[1] = ConvertUnits.ToSimUnits(new Vector2(-65,30) * 0.5f);
transformedHandlePos[0] = Vector2.Transform(new Vector2(handlePos[0].X + horizontalOffset, handlePos[0].Y), itemTransfrom);
transformedHandlePos[1] = Vector2.Transform(new Vector2(handlePos[1].X + horizontalOffset, handlePos[1].Y), itemTransfrom);
Limb torso = GetLimb(LimbType.Torso) ?? MainLimb;
Limb leftHand = GetLimb(LimbType.LeftHand);
Limb rightHand = GetLimb(LimbType.RightHand);
Vector2 itemPos = aim ? aimPos : holdPos;
var controller = character.SelectedConstruction?.GetComponent<Controller>();
bool usingController = controller != null && !controller.AllowAiming;
bool isClimbing = character.IsClimbing && Math.Abs(character.AnimController.TargetMovement.Y) > 0.01f;
float itemAngle;
Holdable holdable = item.GetComponent<Holdable>();
float torsoRotation = torso.Rotation;
bool equippedInRightHand = character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == item && rightHand != null && !rightHand.IsSevered;
bool equippedInLefthand = character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == item && leftHand != null && !leftHand.IsSevered;
if (aim && !isClimbing && !usingController && character.Stun <= 0.0f && itemPos != Vector2.Zero && !character.IsIncapacitated)
{
Vector2 mousePos = ConvertUnits.ToSimUnits(character.SmoothedCursorPosition);
Vector2 diff = holdable.Aimable ? (mousePos - AimSourceSimPos) * Dir : Vector2.UnitX;
holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torsoRotation * Dir;
holdAngle += GetAimWobble(rightHand, leftHand, item);
itemAngle = torsoRotation + holdAngle * Dir;
if (holdable.ControlPose)
{
var head = GetLimb(LimbType.Head);
if (head != null)
{
head.body.SmoothRotate(itemAngle, force: 30 * head.Mass);
}
if (TargetMovement == Vector2.Zero && inWater)
{
torso.body.AngularVelocity -= torso.body.AngularVelocity * 0.1f;
torso.body.ApplyForce(torso.body.LinearVelocity * -0.5f);
}
aiming = true;
}
}
else
{
if (holdable.UseHandRotationForHoldAngle)
{
if (equippedInRightHand)
{
itemAngle = rightHand.Rotation + holdAngle * Dir;
}
else if (equippedInLefthand)
{
itemAngle = leftHand.Rotation + holdAngle * Dir;
}
else
{
itemAngle = torsoRotation + holdAngle * Dir;
}
}
else
{
itemAngle = torsoRotation + holdAngle * Dir;
}
}
if (rightShoulder == null) { return; }
Vector2 transformedHoldPos = rightShoulder.WorldAnchorA;
if (itemPos == Vector2.Zero || isClimbing || usingController)
{
if (equippedInRightHand)
{
transformedHoldPos = rightHand.PullJointWorldAnchorA - transformedHandlePos[0];
itemAngle = rightHand.Rotation + (holdAngle - rightHand.Params.GetSpriteOrientation() + MathHelper.PiOver2) * Dir;
}
else if (equippedInLefthand)
{
transformedHoldPos = leftHand.PullJointWorldAnchorA - transformedHandlePos[1];
itemAngle = leftHand.Rotation + (holdAngle - leftHand.Params.GetSpriteOrientation() + MathHelper.PiOver2) * Dir;
}
}
else
{
if (equippedInRightHand)
{
transformedHoldPos = rightShoulder.WorldAnchorA;
rightHand.Disabled = true;
}
if (equippedInLefthand)
{
if (leftShoulder == null) { return; }
transformedHoldPos = leftShoulder.WorldAnchorA;
leftHand.Disabled = true;
}
itemPos.X *= Dir;
transformedHoldPos += Vector2.Transform(itemPos, Matrix.CreateRotationZ(itemAngle));
}
item.body.ResetDynamics();
Vector2 currItemPos = equippedInRightHand ?
rightHand.PullJointWorldAnchorA - transformedHandlePos[0] :
leftHand.PullJointWorldAnchorA - transformedHandlePos[1];
if (!MathUtils.IsValid(currItemPos))
{
string errorMsg = "Attempted to move the item \"" + item + "\" to an invalid position in HumanidAnimController.HoldItem: " +
currItemPos + ", rightHandPos: " + rightHand.PullJointWorldAnchorA + ", leftHandPos: " + leftHand.PullJointWorldAnchorA +
", handlePos[0]: " + handlePos[0] + ", handlePos[1]: " + handlePos[1] +
", transformedHandlePos[0]: " + transformedHandlePos[0] + ", transformedHandlePos[1]:" + transformedHandlePos[1] +
", item pos: " + item.SimPosition + ", itemAngle: " + itemAngle +
", collider pos: " + character.SimPosition;
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"HumanoidAnimController.HoldItem:InvalidPos:" + character.Name + item.Name,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
return;
}
if (holdable.Pusher != null)
{
if (character.Stun > 0.0f || character.IsIncapacitated)
{
holdable.Pusher.Enabled = false;
}
else
{
if (!holdable.Pusher.Enabled)
{
holdable.Pusher.Enabled = true;
holdable.Pusher.ResetDynamics();
holdable.Pusher.SetTransform(currItemPos, itemAngle);
}
else
{
holdable.Pusher.TargetPosition = currItemPos;
holdable.Pusher.TargetRotation = holdAngle * Dir;
holdable.Pusher.MoveToTargetPosition(true);
currItemPos = holdable.Pusher.SimPosition;
itemAngle = holdable.Pusher.Rotation;
}
}
}
float targetAngle = MathUtils.WrapAngleTwoPi(itemAngle + itemAngleRelativeToHoldAngle * Dir);
float currentRotation = MathUtils.WrapAngleTwoPi(item.body.Rotation);
float itemRotation = MathHelper.SmoothStep(currentRotation, targetAngle, deltaTime * 25);
if (previousDirection != dir || Math.Abs(targetAngle - currentRotation) > MathHelper.Pi)
{
itemRotation = targetAngle;
}
item.SetTransform(currItemPos, itemRotation, setPrevTransform: false);
previousDirection = dir;
if (!isClimbing && !character.IsIncapacitated && itemPos != Vector2.Zero && (aim || !holdable.UseHandRotationForHoldAngle))
{
for (int i = 0; i < 2; i++)
{
if (!character.Inventory.IsInLimbSlot(item, i == 0 ? InvSlotType.RightHand : InvSlotType.LeftHand)) { continue; }
#if DEBUG
if (handlePos[i].LengthSquared() > ArmLength)
{
DebugConsole.AddWarning($"Aim position for the item {item.Name} may be incorrect (further than the length of the character's arm)");
}
#endif
HandIK(i == 0 ? rightHand : leftHand, transformedHoldPos + transformedHandlePos[i], CurrentAnimationParams.ArmIKStrength, CurrentAnimationParams.HandIKStrength);
}
}
}
private float GetAimWobble(Limb rightHand, Limb leftHand, Item heldItem)
{
float wobbleStrength = 0.0f;
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == heldItem)
{
wobbleStrength += Character.CharacterHealth.GetLimbDamage(rightHand, afflictionType: "damage");
}
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == heldItem)
{
wobbleStrength += Character.CharacterHealth.GetLimbDamage(leftHand, afflictionType: "damage");
}
if (wobbleStrength <= 0.1f) { return 0.0f; }
wobbleStrength = (float)Math.Min(wobbleStrength, 1.0f);
float lowFreqNoise = PerlinNoise.GetPerlin((float)Timing.TotalTime / 320.0f, (float)Timing.TotalTime / 240.0f) - 0.5f;
float highFreqNoise = PerlinNoise.GetPerlin((float)Timing.TotalTime / 40.0f, (float)Timing.TotalTime / 50.0f) - 0.5f;
return (lowFreqNoise * 1.0f + highFreqNoise * 0.1f) * wobbleStrength;
}
public void HandIK(Limb hand, Vector2 pos, float armTorque = 1.0f, float handTorque = 1.0f)
{
Vector2 shoulderPos;
Limb arm, forearm;
if (hand.type == LimbType.LeftHand)
{
if (leftShoulder == null) { return; }
shoulderPos = leftShoulder.WorldAnchorA;
arm = GetLimb(LimbType.LeftArm);
forearm = GetLimb(LimbType.LeftForearm);
LeftHandIKPos = pos;
}
else
{
if (rightShoulder == null) { return; }
shoulderPos = rightShoulder.WorldAnchorA;
arm = GetLimb(LimbType.RightArm);
forearm = GetLimb(LimbType.RightForearm);
RightHandIKPos = pos;
}
if (arm == null) { return; }
//distance from shoulder to holdpos
float c = Vector2.Distance(pos, shoulderPos);
c = MathHelper.Clamp(c, Math.Abs(upperArmLength - forearmLength), forearmLength + upperArmLength - 0.01f);
float armAngle = MathUtils.VectorToAngle(pos - shoulderPos) + arm.Params.GetSpriteOrientation() - MathHelper.PiOver2;
float upperArmAngle = MathUtils.SolveTriangleSSS(forearmLength, upperArmLength, c) * Dir;
float lowerArmAngle = MathUtils.SolveTriangleSSS(upperArmLength, forearmLength, c) * Dir;
//make sure the arm angle "has the same number of revolutions" as the arm
while (arm.Rotation - armAngle > MathHelper.Pi)
{
armAngle += MathHelper.TwoPi;
}
while (arm.Rotation - armAngle < -MathHelper.Pi)
{
armAngle -= MathHelper.TwoPi;
}
arm?.body.SmoothRotate(armAngle - upperArmAngle, 100.0f * armTorque * arm.Mass, wrapAngle: false);
float forearmAngle = armAngle + lowerArmAngle;
forearm?.body.SmoothRotate(forearmAngle, 100.0f * handTorque * forearm.Mass, wrapAngle: false);
float handAngle = forearm != null ? forearmAngle : armAngle;
hand?.body.SmoothRotate(handAngle, 10.0f * handTorque * hand.Mass, wrapAngle: false);
}
public void ApplyPose(Vector2 leftHandPos, Vector2 rightHandPos, Vector2 leftFootPos, Vector2 rightFootPos, float footMoveForce = 10)
{
var leftHand = GetLimb(LimbType.LeftHand);
var rightHand = GetLimb(LimbType.RightHand);
var waist = GetLimb(LimbType.Waist) ?? GetLimb(LimbType.Torso);
if (waist == null) { return; }
Vector2 midPos = waist.SimPosition;
if (leftHand != null)
{
leftHand.Disabled = true;
leftHandPos.X *= Dir;
leftHandPos += midPos;
HandIK(leftHand, leftHandPos);
}
if (rightHand != null)
{
rightHand.Disabled = true;
rightHandPos.X *= Dir;
rightHandPos += midPos;
HandIK(rightHand, rightHandPos);
}
var leftFoot = GetLimb(LimbType.LeftFoot);
if (leftFoot != null)
{
leftFoot.Disabled = true;
leftFootPos = new Vector2(waist.SimPosition.X + leftFootPos.X * Dir, GetColliderBottom().Y + leftFootPos.Y);
MoveLimb(leftFoot, leftFootPos, Math.Abs(leftFoot.SimPosition.X - leftFootPos.X) * footMoveForce * leftFoot.Mass, true);
}
var rightFoot = GetLimb(LimbType.RightFoot);
if (rightFoot != null)
{
rightFoot.Disabled = true;
rightFootPos = new Vector2(waist.SimPosition.X + rightFootPos.X * Dir, GetColliderBottom().Y + rightFootPos.Y);
MoveLimb(rightFoot, rightFootPos, Math.Abs(rightFoot.SimPosition.X - rightFootPos.X) * footMoveForce * rightFoot.Mass, true);
}
}
public void ApplyTestPose()
{
var waist = GetLimb(LimbType.Waist) ?? GetLimb(LimbType.Torso);
if (waist != null)
{
ApplyPose(
new Vector2(-0.75f, -0.2f),
new Vector2(0.75f, -0.2f),
new Vector2(-WalkParams.StepSize.X * 0.5f, -0.1f * RagdollParams.JointScale),
new Vector2(WalkParams.StepSize.X * 0.5f, -0.1f * RagdollParams.JointScale));
}
}
protected void CalculateArmLengths()
{
//calculate arm and forearm length (atm this assumes that both arms are the same size)
Limb rightForearm = GetLimb(LimbType.RightForearm);
Limb rightHand = GetLimb(LimbType.RightHand);
if (rightHand == null) { return; }
rightShoulder = GetJointBetweenLimbs(LimbType.Torso, LimbType.RightArm) ?? GetJointBetweenLimbs(LimbType.Head, LimbType.RightArm) ?? GetJoint(LimbType.RightArm, new LimbType[] { LimbType.RightHand, LimbType.RightForearm });
leftShoulder = GetJointBetweenLimbs(LimbType.Torso, LimbType.LeftArm) ?? GetJointBetweenLimbs(LimbType.Head, LimbType.LeftArm) ?? GetJoint(LimbType.LeftArm, new LimbType[] { LimbType.LeftHand, LimbType.LeftForearm });
Vector2 localAnchorShoulder = Vector2.Zero;
Vector2 localAnchorElbow = Vector2.Zero;
if (rightShoulder != null)
{
localAnchorShoulder = rightShoulder.LimbA.type == LimbType.RightArm ? rightShoulder.LocalAnchorA : rightShoulder.LocalAnchorB;
}
LimbJoint rightElbow = rightForearm == null ?
GetJointBetweenLimbs(LimbType.RightArm, LimbType.RightHand) :
GetJointBetweenLimbs(LimbType.RightArm, LimbType.RightForearm);
if (rightElbow != null)
{
localAnchorElbow = rightElbow.LimbA.type == LimbType.RightArm ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB;
}
upperArmLength = Vector2.Distance(localAnchorShoulder, localAnchorElbow);
if (rightElbow != null)
{
if (rightForearm == null)
{
forearmLength = Vector2.Distance(
rightHand.PullJointLocalAnchorA,
rightElbow.LimbA.type == LimbType.RightHand ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB);
}
else
{
LimbJoint rightWrist = GetJointBetweenLimbs(LimbType.RightForearm, LimbType.RightHand);
if (rightWrist != null)
{
forearmLength = Vector2.Distance(
rightElbow.LimbA.type == LimbType.RightForearm ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB,
rightWrist.LimbA.type == LimbType.RightForearm ? rightWrist.LocalAnchorA : rightWrist.LocalAnchorB);
forearmLength += Vector2.Distance(
rightHand.PullJointLocalAnchorA,
rightElbow.LimbA.type == LimbType.RightHand ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB);
}
}
}
}
protected LimbJoint GetJointBetweenLimbs(LimbType limbTypeA, LimbType limbTypeB)
{
return LimbJoints.FirstOrDefault(lj =>
(lj.LimbA.type == limbTypeA && lj.LimbB.type == limbTypeB) ||
(lj.LimbB.type == limbTypeA && lj.LimbA.type == limbTypeB));
}
protected LimbJoint GetJoint(LimbType matchingType, IEnumerable<LimbType> ignoredTypes)
{
return LimbJoints.FirstOrDefault(lj =>
lj.LimbA.type == matchingType && ignoredTypes.None(t => lj.LimbB.type == t) ||
lj.LimbB.type == matchingType && ignoredTypes.None(t => lj.LimbB.type == t));
}
public override void Recreate(RagdollParams ragdollParams = null)
{
base.Recreate(ragdollParams);
if (Character.Params.CanInteract)
{
CalculateArmLengths();
}
}
}
}
@@ -139,7 +139,7 @@ namespace Barotrauma
if (MainLimb == null) { return; }
var mainLimb = MainLimb;
levitatingCollider = true;
levitatingCollider = !IsHanging;
if (!character.CanMove)
{
@@ -192,6 +192,11 @@ namespace Barotrauma
strongestImpact = 0.0f;
}
if (aiming)
{
TargetMovement = TargetMovement.ClampLength(2);
}
if (inWater && !forceStanding)
{
Collider.FarseerBody.FixedRotation = false;
@@ -202,7 +207,7 @@ namespace Barotrauma
if (CurrentGroundedParams != null)
{
//rotate collider back upright
float standAngle = dir == Direction.Right ? CurrentGroundedParams.ColliderStandAngleInRadians : -CurrentGroundedParams.ColliderStandAngleInRadians;
float standAngle = CurrentGroundedParams.ColliderStandAngleInRadians * Dir;
if (Math.Abs(MathUtils.GetShortestAngle(Collider.Rotation, standAngle)) > 0.001f)
{
Collider.AngularVelocity = MathUtils.GetShortestAngle(Collider.Rotation, standAngle) * 60.0f;
@@ -215,17 +220,19 @@ namespace Barotrauma
}
UpdateWalkAnim(deltaTime);
}
if (character.SelectedCharacter != null)
{
DragCharacter(character.SelectedCharacter, deltaTime);
return;
}
if (character.AnimController.AnimationTestPose)
{
ApplyTestPose();
}
//don't flip when simply physics is enabled
if (SimplePhysicsEnabled) { return; }
if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip))
if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip) && !aiming)
{
if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
{
@@ -290,6 +297,10 @@ namespace Barotrauma
{
flipTimer = 0.0f;
}
wasAiming = aiming;
aiming = false;
wasAimingMelee = aimingMelee;
aimingMelee = false;
}
private bool CanDrag(Character target)
@@ -449,6 +460,16 @@ namespace Barotrauma
//limbs are disabled when simple physics is enabled, no need to move them
if (SimplePhysicsEnabled) { return; }
mainLimb.PullJointEnabled = true;
if (aiming && movement.Length() <= 0.1f)
{
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
Vector2 diff = (mousePos - (GetLimb(LimbType.Torso) ?? MainLimb).SimPosition) * Dir;
TargetMovement = new Vector2(0.0f, -0.1f);
float newRotation = MathUtils.VectorToAngle(diff);
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
}
if (!isMoving)
{
WalkPos = MathHelper.SmoothStep(WalkPos, MathHelper.PiOver2, deltaTime * 5);
@@ -146,34 +146,8 @@ namespace Barotrauma
public bool Crouching;
private float upperArmLength = 0.0f, forearmLength = 0.0f;
public float ArmLength => upperArmLength + forearmLength;
public Vector2 RightHandIKPos
{
get;
private set;
}
public Vector2 LeftHandIKPos
{
get;
private set;
}
private LimbJoint rightShoulder, leftShoulder;
private float upperLegLength = 0.0f, lowerLegLength = 0.0f;
private bool aiming;
private bool wasAiming;
private bool aimingMelee;
private bool wasAimingMelee;
public bool IsAiming => wasAiming;
public bool IsAimingMelee => wasAimingMelee;
private readonly float movementLerp;
private float cprAnimTimer;
@@ -184,7 +158,6 @@ namespace Barotrauma
//prevents rapid switches between swimming/walking if the water level is fluctuating around the minimum swimming depth
private float swimmingStateLockTimer;
private float useItemTimer;
public float HeadLeanAmount => CurrentGroundedParams.HeadLeanAmount;
public float TorsoLeanAmount => CurrentGroundedParams.TorsoLeanAmount;
public Vector2 FootMoveOffset => CurrentGroundedParams.FootMoveOffset * RagdollParams.JointScale;
@@ -219,61 +192,12 @@ namespace Barotrauma
movementLerp = RagdollParams.MainElement.GetAttributeFloat("movementlerp", 0.4f);
}
public override void Recreate(RagdollParams ragdollParams)
public override void Recreate(RagdollParams ragdollParams = null)
{
base.Recreate(ragdollParams);
CalculateArmLengths();
CalculateLegLengths();
}
private void CalculateArmLengths()
{
//calculate arm and forearm length (atm this assumes that both arms are the same size)
Limb rightForearm = GetLimb(LimbType.RightForearm);
Limb rightHand = GetLimb(LimbType.RightHand);
if (rightHand == null) { return; }
rightShoulder = GetJointBetweenLimbs(LimbType.Torso, LimbType.RightArm);
leftShoulder = GetJointBetweenLimbs(LimbType.Torso, LimbType.LeftArm);
Vector2 localAnchorShoulder = Vector2.Zero;
Vector2 localAnchorElbow = Vector2.Zero;
if (rightShoulder != null)
{
localAnchorShoulder = rightShoulder.LimbA.type == LimbType.RightArm ? rightShoulder.LocalAnchorA : rightShoulder.LocalAnchorB;
}
LimbJoint rightElbow = rightForearm == null ?
GetJointBetweenLimbs(LimbType.RightArm, LimbType.RightHand) :
GetJointBetweenLimbs(LimbType.RightArm, LimbType.RightForearm);
if (rightElbow != null)
{
localAnchorElbow = rightElbow.LimbA.type == LimbType.RightArm ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB;
}
upperArmLength = Vector2.Distance(localAnchorShoulder, localAnchorElbow);
if (rightElbow != null)
{
if (rightForearm == null)
{
forearmLength = Vector2.Distance(
rightHand.PullJointLocalAnchorA,
rightElbow.LimbA.type == LimbType.RightHand ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB);
}
else
{
LimbJoint rightWrist = GetJointBetweenLimbs(LimbType.RightForearm, LimbType.RightHand);
if (rightWrist != null)
{
forearmLength = Vector2.Distance(
rightElbow.LimbA.type == LimbType.RightForearm ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB,
rightWrist.LimbA.type == LimbType.RightForearm ? rightWrist.LocalAnchorA : rightWrist.LocalAnchorB);
forearmLength += Vector2.Distance(
rightHand.PullJointLocalAnchorA,
rightElbow.LimbA.type == LimbType.RightHand ? rightElbow.LocalAnchorA : rightElbow.LocalAnchorB);
}
}
}
}
private void CalculateLegLengths()
{
//calculate upper and lower leg length (atm this assumes that both legs are the same size)
@@ -304,21 +228,16 @@ namespace Barotrauma
ankleJoint.LimbA.type == footType ? ankleJoint.LocalAnchorA : ankleJoint.LocalAnchorB,
GetLimb(footType).PullJointLocalAnchorA);
}
private LimbJoint GetJointBetweenLimbs(LimbType limbTypeA, LimbType limbTypeB)
{
return LimbJoints.FirstOrDefault(lj =>
(lj.LimbA.type == limbTypeA && lj.LimbB.type == limbTypeB) ||
(lj.LimbB.type == limbTypeA && lj.LimbA.type == limbTypeB));
}
public override void UpdateAnim(float deltaTime)
{
if (Frozen) return;
if (MainLimb == null) { return; }
levitatingCollider = true;
levitatingCollider = !IsHanging;
ColliderIndex = Crouching && !swimming ? 1 : 0;
if (character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false ||
character.SelectedConstruction?.GetComponent<Ladder>() != null ||
(ForceSelectAnimationType != AnimationType.Crouch && ForceSelectAnimationType != AnimationType.NotDefined))
{
Crouching = false;
@@ -422,41 +341,25 @@ namespace Barotrauma
midPos += Vector2.Transform(new Vector2(-0.3f * Dir, -0.2f), torsoTransform);
if (rightHand.PullJointEnabled) midPos = (midPos + rightHand.PullJointWorldAnchorB) / 2.0f;
HandIK(rightHand, midPos, CurrentHumanAnimParams.ArmIKStrength, CurrentHumanAnimParams.HandIKStrength);
HandIK(leftHand, midPos, CurrentHumanAnimParams.ArmIKStrength, CurrentHumanAnimParams.HandIKStrength);
HandIK(rightHand, midPos, CurrentAnimationParams.ArmIKStrength, CurrentAnimationParams.HandIKStrength);
HandIK(leftHand, midPos, CurrentAnimationParams.ArmIKStrength, CurrentAnimationParams.HandIKStrength);
}
else if (character.AnimController.AnimationTestPose)
{
var leftHand = GetLimb(LimbType.LeftHand);
var rightHand = GetLimb(LimbType.RightHand);
var waist = GetLimb(LimbType.Waist) ?? GetLimb(LimbType.Torso);
rightHand.Disabled = true;
leftHand.Disabled = true;
Vector2 midPos = waist.SimPosition;
HandIK(rightHand, midPos + new Vector2(-1, -0.2f) * Dir);
HandIK(leftHand, midPos + new Vector2(1, -0.2f) * Dir);
var leftFoot = GetLimb(LimbType.LeftFoot);
var rightFoot = GetLimb(LimbType.RightFoot);
rightFoot.Disabled = true;
leftFoot.Disabled = true;
// The code here is a bit obscure, but it's pretty much copy-pasted from the block that is used for crouching.
for (int i = -1; i < 2; i += 2)
{
Vector2 footPos = GetColliderBottom();
footPos = new Vector2(waist.SimPosition.X + Math.Sign(WalkParams.StepSize.X * i) * Dir * 0.3f, footPos.Y - 0.1f * RagdollParams.JointScale);
var foot = i == -1 ? rightFoot : leftFoot;
MoveLimb(foot, footPos, Math.Abs(foot.SimPosition.X - footPos.X) * 100.0f, true);
}
ApplyTestPose();
}
else
{
if (Anim != Animation.UsingConstruction) ResetPullJoints();
if (Anim != Animation.UsingConstruction)
{
ResetPullJoints();
}
}
if (SimplePhysicsEnabled)
{
UpdateStandingSimple();
IsHanging = false;
return;
}
@@ -520,12 +423,11 @@ namespace Barotrauma
{
limb.Disabled = false;
}
wasAiming = aiming;
aiming = false;
wasAimingMelee = aimingMelee;
aimingMelee = false;
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) return;
IsHanging = false;
}
void UpdateStanding()
@@ -844,16 +746,18 @@ namespace Barotrauma
var arm = GetLimb(armType);
if (arm != null && Math.Abs(arm.body.AngularVelocity) < 10.0f)
{
arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.1f, 0.1f), arm.Mass * 10.0f);
arm.body.SmoothRotate(MathHelper.Clamp(-arm.body.AngularVelocity, -0.5f, 0.5f), arm.Mass * 50.0f);
}
//get the elbow to a neutral rotation
if (Math.Abs(hand.body.AngularVelocity) < 10.0f)
{
LimbJoint elbow = GetJointBetweenLimbs(armType, hand.type) ?? GetJointBetweenLimbs(armType, foreArmType);
var forearm = GetLimb(foreArmType) ?? hand;
LimbJoint elbow = GetJointBetweenLimbs(armType, foreArmType) ?? GetJointBetweenLimbs(armType, hand.type);
if (elbow != null)
{
hand.body.ApplyTorque(MathHelper.Clamp(-elbow.JointAngle, -MathHelper.PiOver2, MathHelper.PiOver2) * hand.Mass * 10.0f);
float diff = elbow.JointAngle - (Dir > 0 ? elbow.LowerLimit : elbow.UpperLimit);
forearm.body.ApplyTorque(MathHelper.Clamp(-diff, -MathHelper.PiOver2, MathHelper.PiOver2) * forearm.Mass * 100.0f);
}
}
}
@@ -1099,6 +1003,7 @@ namespace Barotrauma
rightHandPos.X = (Dir == 1.0f) ? Math.Max(0.3f, rightHandPos.X) : Math.Min(-0.3f, rightHandPos.X);
rightHandPos = Vector2.Transform(rightHandPos, rotationMatrix);
float speedMultiplier = character.SpeedMultiplier * (1 - Character.GetRightHandPenalty());
// Limb hand, Vector2 pos, float force = 1.0f
HandIK(rightHand, handPos + rightHandPos, CurrentSwimParams.ArmMoveStrength * speedMultiplier, CurrentSwimParams.HandMoveStrength * speedMultiplier);
}
@@ -1390,6 +1295,8 @@ namespace Barotrauma
{
target.Oxygen += deltaTime * 0.5f; //Stabilize them
}
bool powerfulCPR = character.HasAbilityFlag(AbilityFlags.PowerfulCPR);
int skill = (int)character.GetSkillLevel("medical");
//pump for 15 seconds (cprAnimTimer 0-15), then do mouth-to-mouth for 2 seconds (cprAnimTimer 15-17)
@@ -1406,13 +1313,19 @@ namespace Barotrauma
{
if (target.Oxygen < -10.0f)
{
//stabilize the oxygen level but don't allow it to go positive and revive the character yet
float stabilizationAmount = skill * CPRSettings.StabilizationPerSkill;
stabilizationAmount = MathHelper.Clamp(stabilizationAmount, CPRSettings.StabilizationMin, CPRSettings.StabilizationMax);
character.Oxygen -= (1.0f / stabilizationAmount) * deltaTime; //Worse skill = more oxygen required
if (character.Oxygen > 0.0f) target.Oxygen += stabilizationAmount * deltaTime; //we didn't suffocate yet did we
//DebugConsole.NewMessage("CPR Us: " + character.Oxygen + " Them: " + target.Oxygen + " How good we are: restore " + cpr + " use " + (30.0f - cpr), Color.Aqua);
if (powerfulCPR)
{
//prevent the patient from suffocating no matter how fast their oxygen level is dropping
target.Oxygen = Math.Max(target.Oxygen, -10.0f);
}
else
{
//stabilize the oxygen level but don't allow it to go positive and revive the character yet
float stabilizationAmount = skill * CPRSettings.StabilizationPerSkill;
stabilizationAmount = MathHelper.Clamp(stabilizationAmount, CPRSettings.StabilizationMin, CPRSettings.StabilizationMax);
character.Oxygen -= 1.0f / stabilizationAmount * deltaTime; //Worse skill = more oxygen required
if (character.Oxygen > 0.0f) { target.Oxygen += stabilizationAmount * deltaTime; } //we didn't suffocate yet did we
}
}
}
}
@@ -1447,6 +1360,8 @@ namespace Barotrauma
reviveChance = (float)Math.Pow(reviveChance, CPRSettings.ReviveChanceExponent);
reviveChance = MathHelper.Clamp(reviveChance, CPRSettings.ReviveChanceMin, CPRSettings.ReviveChanceMax);
if (powerfulCPR) { reviveChance *= 2.0f; }
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) <= reviveChance)
{
//increase oxygen and clamp it above zero
@@ -1706,248 +1621,6 @@ namespace Barotrauma
}
}
public void Grab(Vector2 rightHandPos, Vector2 leftHandPos)
{
for (int i = 0; i < 2; i++)
{
Limb pullLimb = (i == 0) ? GetLimb(LimbType.LeftHand) : GetLimb(LimbType.RightHand);
pullLimb.Disabled = true;
pullLimb.PullJointEnabled = true;
pullLimb.PullJointWorldAnchorB = (i == 0) ? rightHandPos : leftHandPos;
pullLimb.PullJointMaxForce = 500.0f;
}
}
//TODO: refactor this method, it's way too convoluted
public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimingMelee = false)
{
if (character.Stun > 0.0f || character.IsIncapacitated)
{
aim = false;
}
//calculate the handle positions
Matrix itemTransfrom = Matrix.CreateRotationZ(item.body.Rotation);
// TODO: don't create new arrays, reuse
Vector2[] transformedHandlePos = new Vector2[2];
transformedHandlePos[0] = Vector2.Transform(handlePos[0], itemTransfrom);
transformedHandlePos[1] = Vector2.Transform(handlePos[1], itemTransfrom);
Limb head = GetLimb(LimbType.Head);
Limb torso = GetLimb(LimbType.Torso);
Limb leftHand = GetLimb(LimbType.LeftHand);
Limb rightHand = GetLimb(LimbType.RightHand);
// TODO: Remove this. Provide the position in params.
Vector2 itemPos = aim ? aimPos : holdPos;
var controller = character.SelectedConstruction?.GetComponent<Controller>();
bool usingController = controller != null && !controller.AllowAiming;
bool isClimbing = character.IsClimbing && Math.Abs(character.AnimController.TargetMovement.Y) > 0.01f;
float itemAngle;
Holdable holdable = item.GetComponent<Holdable>();
this.aimingMelee = aimingMelee;
if (!isClimbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero && !character.IsIncapacitated)
{
Vector2 mousePos = ConvertUnits.ToSimUnits(character.SmoothedCursorPosition);
Vector2 diff = holdable.Aimable ? (mousePos - AimSourceSimPos) * Dir : Vector2.UnitX;
holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torso.body.Rotation * Dir;
holdAngle += GetAimWobble(rightHand, leftHand, item);
itemAngle = torso.body.Rotation + holdAngle * Dir;
if (holdable.ControlPose)
{
head?.body.SmoothRotate(itemAngle);
if (TargetMovement == Vector2.Zero && inWater)
{
torso.body.AngularVelocity -= torso.body.AngularVelocity * 0.1f;
torso.body.ApplyForce(torso.body.LinearVelocity * -0.5f);
}
aiming = true;
}
}
else
{
itemAngle = torso.body.Rotation + holdAngle * Dir;
}
Vector2 transformedHoldPos = rightShoulder.WorldAnchorA;
if (itemPos == Vector2.Zero || isClimbing || usingController)
{
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == item)
{
if (rightHand == null || rightHand.IsSevered) { return; }
transformedHoldPos = rightHand.PullJointWorldAnchorA - transformedHandlePos[0];
itemAngle = (rightHand.Rotation + (holdAngle - MathHelper.PiOver2) * Dir);
}
else if (character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == item)
{
if (leftHand == null || leftHand.IsSevered) { return; }
transformedHoldPos = leftHand.PullJointWorldAnchorA - transformedHandlePos[1];
itemAngle = (leftHand.Rotation + (holdAngle - MathHelper.PiOver2) * Dir);
}
}
else
{
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == item)
{
if (rightHand == null || rightHand.IsSevered) { return; }
transformedHoldPos = rightShoulder.WorldAnchorA;
rightHand.Disabled = true;
}
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == item)
{
if (leftHand == null || leftHand.IsSevered) { return; }
transformedHoldPos = leftShoulder.WorldAnchorA;
leftHand.Disabled = true;
}
itemPos.X *= Dir;
transformedHoldPos += Vector2.Transform(itemPos, Matrix.CreateRotationZ(itemAngle));
}
item.body.ResetDynamics();
Vector2 currItemPos = (character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == item) ?
rightHand.PullJointWorldAnchorA - transformedHandlePos[0] :
leftHand.PullJointWorldAnchorA - transformedHandlePos[1];
if (!MathUtils.IsValid(currItemPos))
{
string errorMsg = "Attempted to move the item \"" + item + "\" to an invalid position in HumanidAnimController.HoldItem: " +
currItemPos + ", rightHandPos: " + rightHand.PullJointWorldAnchorA + ", leftHandPos: " + leftHand.PullJointWorldAnchorA +
", handlePos[0]: " + handlePos[0] + ", handlePos[1]: " + handlePos[1] +
", transformedHandlePos[0]: " + transformedHandlePos[0] + ", transformedHandlePos[1]:" + transformedHandlePos[1] +
", item pos: " + item.SimPosition + ", itemAngle: " + itemAngle +
", collider pos: " + character.SimPosition;
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"HumanoidAnimController.HoldItem:InvalidPos:" + character.Name + item.Name,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
return;
}
if (holdable.Pusher != null)
{
if (character.Stun > 0.0f || character.IsIncapacitated)
{
holdable.Pusher.Enabled = false;
}
else
{
if (!holdable.Pusher.Enabled)
{
holdable.Pusher.Enabled = true;
holdable.Pusher.ResetDynamics();
holdable.Pusher.SetTransform(currItemPos, itemAngle);
}
else
{
holdable.Pusher.TargetPosition = currItemPos;
holdable.Pusher.TargetRotation = holdAngle * Dir;
holdable.Pusher.MoveToTargetPosition(true);
currItemPos = holdable.Pusher.SimPosition;
itemAngle = holdable.Pusher.Rotation;
}
}
}
item.SetTransform(currItemPos, itemAngle + itemAngleRelativeToHoldAngle * Dir, setPrevTransform: false);
if (!isClimbing && !character.IsIncapacitated && itemPos != Vector2.Zero)
{
for (int i = 0; i < 2; i++)
{
if (!character.Inventory.IsInLimbSlot(item, i == 0 ? InvSlotType.RightHand : InvSlotType.LeftHand)) { continue; }
HandIK(i == 0 ? rightHand : leftHand, transformedHoldPos + transformedHandlePos[i], CurrentHumanAnimParams.ArmIKStrength, CurrentHumanAnimParams.HandIKStrength);
}
}
}
private float GetAimWobble(Limb rightHand, Limb leftHand, Item heldItem)
{
float wobbleStrength = 0.0f;
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand) == heldItem)
{
wobbleStrength += Character.CharacterHealth.GetLimbDamage(rightHand, afflictionType: "damage");
}
if (character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand) == heldItem)
{
wobbleStrength += Character.CharacterHealth.GetLimbDamage(leftHand, afflictionType: "damage");
}
if (wobbleStrength <= 0.1f) { return 0.0f; }
wobbleStrength = (float)Math.Min(wobbleStrength, 1.0f);
float lowFreqNoise = PerlinNoise.GetPerlin((float)Timing.TotalTime / 320.0f, (float)Timing.TotalTime / 240.0f) - 0.5f;
float highFreqNoise = PerlinNoise.GetPerlin((float)Timing.TotalTime / 40.0f, (float)Timing.TotalTime / 50.0f) - 0.5f;
return (lowFreqNoise * 1.0f + highFreqNoise * 0.1f) * wobbleStrength;
}
private void HandIK(Limb hand, Vector2 pos, float armTorque = 1.0f, float handTorque = 1.0f)
{
Vector2 shoulderPos;
Limb arm, forearm;
if (hand.type == LimbType.LeftHand)
{
if (leftShoulder == null) { return; }
shoulderPos = leftShoulder.WorldAnchorA;
arm = GetLimb(LimbType.LeftArm);
forearm = GetLimb(LimbType.LeftForearm);
LeftHandIKPos = pos;
}
else
{
if (rightShoulder == null) { return; }
shoulderPos = rightShoulder.WorldAnchorA;
arm = GetLimb(LimbType.RightArm);
forearm = GetLimb(LimbType.RightForearm);
RightHandIKPos = pos;
}
if (arm == null) { return; }
//distance from shoulder to holdpos
float c = Vector2.Distance(pos, shoulderPos);
c = MathHelper.Clamp(c, Math.Abs(upperArmLength - forearmLength), forearmLength + upperArmLength - 0.01f);
float armAngle = MathUtils.VectorToAngle(pos - shoulderPos) + MathHelper.PiOver2;
float upperArmAngle = MathUtils.SolveTriangleSSS(forearmLength, upperArmLength, c) * Dir;
float lowerArmAngle = MathUtils.SolveTriangleSSS(upperArmLength, forearmLength, c) * Dir;
//make sure the arm angle "has the same number of revolutions" as the arm
while (arm.Rotation - armAngle > MathHelper.Pi)
{
armAngle += MathHelper.TwoPi;
}
while (arm.Rotation - armAngle < -MathHelper.Pi)
{
armAngle -= MathHelper.TwoPi;
}
arm?.body.SmoothRotate(armAngle - upperArmAngle, 100.0f * armTorque * arm.Mass, wrapAngle: false);
float forearmAngle = armAngle + lowerArmAngle;
forearm?.body.SmoothRotate(forearmAngle, 100.0f * handTorque * forearm.Mass, wrapAngle: false);
float handAngle = forearm != null ? armAngle : forearmAngle;
hand?.body.SmoothRotate(handAngle, 100.0f * handTorque * hand.Mass, wrapAngle: false);
}
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
{
if (!MathUtils.IsValid(pos))
@@ -2014,47 +1687,6 @@ namespace Barotrauma
foot.body.SmoothRotate((legAngle - (lowerLegAngle + footAngle) * Dir), foot.Mass * footTorque, wrapAngle: false);
}
public override void UpdateUseItem(bool allowMovement, Vector2 handWorldPos)
{
useItemTimer = 0.5f;
Anim = Animation.UsingConstruction;
if (!allowMovement)
{
TargetMovement = Vector2.Zero;
TargetDir = handWorldPos.X > character.WorldPosition.X ? Direction.Right : Direction.Left;
float sqrDist = Vector2.DistanceSquared(character.WorldPosition, handWorldPos);
if (sqrDist > MathUtils.Pow(ConvertUnits.ToDisplayUnits(upperArmLength + forearmLength), 2))
{
TargetMovement = Vector2.Normalize(handWorldPos - character.WorldPosition) * GetCurrentSpeed(false) * Math.Max(character.SpeedMultiplier, 1);
}
}
if (!character.Enabled) { return; }
Vector2 handSimPos = ConvertUnits.ToSimUnits(handWorldPos);
if (character.Submarine != null)
{
handSimPos -= character.Submarine.SimPosition;
}
var leftHand = GetLimb(LimbType.LeftHand);
if (leftHand != null)
{
leftHand.Disabled = true;
leftHand.PullJointEnabled = true;
leftHand.PullJointWorldAnchorB = handSimPos;
}
var rightHand = GetLimb(LimbType.RightHand);
if (rightHand != null)
{
rightHand.Disabled = true;
rightHand.PullJointEnabled = true;
rightHand.PullJointWorldAnchorB = handSimPos;
}
}
public override void Flip()
{
base.Flip();
@@ -2073,7 +1705,8 @@ namespace Barotrauma
{
heldItem.FlipX(relativeToSub: false);
}
heldItem.FlipX(relativeToSub: false);
// TODO: was this added by a mistake?
//heldItem.FlipX(relativeToSub: false);
}
foreach (Limb limb in Limbs)
@@ -125,7 +125,8 @@ namespace Barotrauma
protected float surfaceY;
protected bool inWater, headInWater;
public bool onGround;
protected bool onGround;
public bool OnGround => onGround;
private Vector2 lastFloorCheckPos;
private bool lastFloorCheckIgnoreStairs, lastFloorCheckIgnorePlatforms;
@@ -887,7 +888,7 @@ namespace Barotrauma
/// <param name="pullFromCenter">if false, force is applied to the position of pullJoint</param>
protected void MoveLimb(Limb limb, Vector2 pos, float amount, bool pullFromCenter = false)
public void MoveLimb(Limb limb, Vector2 pos, float amount, bool pullFromCenter = false)
{
limb.MoveToPos(pos, amount, pullFromCenter);
}
@@ -974,8 +975,7 @@ namespace Barotrauma
Vector2 newSubPos = newHull.Submarine == null ? Vector2.Zero : newHull.Submarine.Position;
Vector2 prevSubPos = currentHull.Submarine == null ? Vector2.Zero : currentHull.Submarine.Position;
Teleport(ConvertUnits.ToSimUnits(prevSubPos - newSubPos),
Vector2.Zero);
Teleport(ConvertUnits.ToSimUnits(prevSubPos - newSubPos), Vector2.Zero);
}
}
@@ -1099,6 +1099,7 @@ namespace Barotrauma
}
public bool forceStanding;
public bool forceNotStanding;
public void Update(float deltaTime, Camera cam)
{
@@ -1270,6 +1271,7 @@ namespace Barotrauma
}
}
UpdateProjSpecific(deltaTime, cam);
forceNotStanding = false;
}
private void CheckBodyInRest(float deltaTime)
@@ -1569,7 +1571,7 @@ namespace Barotrauma
return closestFraction;
}, rayStart, rayEnd, Physics.CollisionStairs | Physics.CollisionPlatform | Physics.CollisionWall | Physics.CollisionLevel);
if (standOnFloorFixture != null)
if (standOnFloorFixture != null && !IsHanging)
{
standOnFloorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * standOnFloorFraction;
if (rayStart.Y - standOnFloorY < Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor * 1.2f)
@@ -1606,6 +1608,13 @@ namespace Barotrauma
}
if (MainLimb == null) { return; }
if (Character.AIController is EnemyAIController enemyAI && enemyAI.LatchOntoAI != null && enemyAI.LatchOntoAI.IsAttached)
{
enemyAI.LatchOntoAI.DeattachFromBody(reset: true);
}
Character.Latchers.ForEachMod(l => l.DeattachFromBody(reset: true));
Character.Latchers.Clear();
Vector2 limbMoveAmount = forceMainLimbToCollider ? simPosition - MainLimb.SimPosition : simPosition - Collider.SimPosition;
if (lerp)
{
@@ -1629,6 +1638,16 @@ namespace Barotrauma
}
}
public bool IsHanging { get; protected set; }
public void Hang()
{
ResetPullJoints();
onGround = false;
levitatingCollider = false;
IsHanging = true;
}
protected void TrySetLimbPosition(Limb limb, Vector2 original, Vector2 simPosition, bool lerp = false, bool ignorePlatforms = true)
{
Vector2 movePos = simPosition;