Unstable 1.8.4.0
This commit is contained in:
@@ -38,21 +38,7 @@ namespace Barotrauma
|
||||
public readonly AnimationType AnimationType;
|
||||
public readonly AnimationParams TemporaryAnimation;
|
||||
public readonly float Priority;
|
||||
public bool IsActive
|
||||
{
|
||||
get { return _isActive; }
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
expirationTimer = expirationTime;
|
||||
}
|
||||
_isActive = value;
|
||||
}
|
||||
}
|
||||
private bool _isActive;
|
||||
private float expirationTimer;
|
||||
private const float expirationTime = 0.1f;
|
||||
public bool IsActive;
|
||||
|
||||
public AnimSwap(AnimationParams temporaryAnimation, float priority)
|
||||
{
|
||||
@@ -61,15 +47,6 @@ namespace Barotrauma
|
||||
Priority = priority;
|
||||
IsActive = true;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
expirationTimer -= deltaTime;
|
||||
if (expirationTimer <= 0)
|
||||
{
|
||||
IsActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly Dictionary<AnimationType, AnimSwap> tempAnimations = new Dictionary<AnimationType, AnimSwap>();
|
||||
@@ -151,7 +128,8 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
return Math.Abs(TargetMovement.X) > (WalkParams.MovementSpeed + RunParams.MovementSpeed) / 2.0f;
|
||||
float movementSpeed = IsClimbing ? TargetMovement.Y : TargetMovement.X;
|
||||
return Math.Abs(movementSpeed) > (WalkParams.MovementSpeed + RunParams.MovementSpeed) / 2.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +204,7 @@ namespace Barotrauma
|
||||
|
||||
public void UpdateAnimations(float deltaTime)
|
||||
{
|
||||
UpdateTemporaryAnimations(deltaTime);
|
||||
UpdateTemporaryAnimations();
|
||||
UpdateAnim(deltaTime);
|
||||
}
|
||||
|
||||
@@ -338,6 +316,31 @@ namespace Barotrauma
|
||||
{
|
||||
FlipLockTime = (float)Timing.TotalTime + time;
|
||||
}
|
||||
|
||||
protected void UpdateConstantTorque(float deltaTime)
|
||||
{
|
||||
foreach (var limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (Math.Abs(limb.Params.ConstantTorque) > 0)
|
||||
{
|
||||
// TODO: not sure if this works on ground
|
||||
float movementFactor = Math.Max(character.AnimController.Collider.LinearVelocity.Length() * 0.5f, 1);
|
||||
limb.body.SmoothRotate(MainLimb.Rotation + MathHelper.ToRadians(limb.Params.ConstantAngle) * Dir, limb.Mass * limb.Params.ConstantTorque * movementFactor, wrapAngle: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateBlink(float deltaTime)
|
||||
{
|
||||
foreach (var limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (limb.Params.BlinkFrequency <= 0) { continue; }
|
||||
if (!limb.InWater && limb.Params.OnlyBlinkInWater) { continue; }
|
||||
limb.UpdateBlink(deltaTime, MainLimb.Rotation);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateUseItem(bool allowMovement, Vector2 handWorldPos)
|
||||
{
|
||||
@@ -408,9 +411,9 @@ namespace Barotrauma
|
||||
character.WorldPosition.Y - handWorldPos.Y > ConvertUnits.ToDisplayUnits(CurrentGroundedParams.TorsoPosition) / 4 &&
|
||||
this is HumanoidAnimController humanoidAnimController)
|
||||
{
|
||||
humanoidAnimController.Crouching = true;
|
||||
humanoidAnimController.Crouch();
|
||||
// TODO: is this redundant/required?
|
||||
humanoidAnimController.ForceSelectAnimationType = AnimationType.Crouch;
|
||||
character.SetInput(InputType.Crouch, hit: false, held: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,7 +608,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!character.Inventory.IsInLimbSlot(item, i == 0 ? InvSlotType.RightHand : InvSlotType.LeftHand)) { continue; }
|
||||
#if DEBUG
|
||||
if (handlePos[i].LengthSquared() > ArmLength)
|
||||
if (ArmLength > 0 && 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)",
|
||||
item.Prefab.ContentPackage);
|
||||
@@ -696,6 +699,290 @@ namespace Barotrauma
|
||||
hand.body.SmoothRotate(handAngle, 10.0f * handTorque * hand.Mass, wrapAngle: false);
|
||||
}
|
||||
}
|
||||
|
||||
private float prevFootPos;
|
||||
protected void UpdateClimbing()
|
||||
{
|
||||
var ladder = character.SelectedSecondaryItem?.GetComponent<Ladder>();
|
||||
if (character.IsIncapacitated)
|
||||
{
|
||||
Anim = Animation.None;
|
||||
return;
|
||||
}
|
||||
else if (ladder == null)
|
||||
{
|
||||
StopClimbing();
|
||||
return;
|
||||
}
|
||||
|
||||
onGround = false;
|
||||
IgnorePlatforms = true;
|
||||
|
||||
bool climbFast = !character.Params.ForceSlowClimbing && character.AnimController.IsMovingFast;
|
||||
var animParams = climbFast ? RunParams : WalkParams;
|
||||
// Don't slide if we can climb faster than slide.
|
||||
bool slide = animParams.SlideSpeed > animParams.ClimbSpeed && targetMovement.Y < -0.1f && climbFast;
|
||||
float maxClimbingSpeed = climbFast && !character.Params.ForceSlowClimbing ? RunParams.ClimbSpeed : WalkParams.ClimbSpeed;
|
||||
Vector2 tempTargetMovement = TargetMovement;
|
||||
tempTargetMovement.Y = Math.Clamp(tempTargetMovement.Y, slide ? -animParams.SlideSpeed : -maxClimbingSpeed, maxClimbingSpeed);
|
||||
|
||||
movement = MathUtils.SmoothStep(movement, tempTargetMovement, 0.3f);
|
||||
|
||||
Limb leftFoot = GetClimbingLimb(LimbType.LeftFoot);
|
||||
Limb rightFoot = GetClimbingLimb(LimbType.RightFoot);
|
||||
Limb head = GetClimbingLimb(LimbType.Head);
|
||||
Limb torso = GetClimbingLimb(LimbType.Torso);
|
||||
|
||||
Limb leftHand = GetClimbingLimb(LimbType.LeftHand);
|
||||
Limb rightHand = GetClimbingLimb(LimbType.RightHand);
|
||||
|
||||
Vector2 ladderSimPos = ConvertUnits.ToSimUnits(
|
||||
ladder.Item.Rect.X + ladder.Item.Rect.Width / 2.0f,
|
||||
ladder.Item.Rect.Y);
|
||||
|
||||
Vector2 ladderSimSize = ConvertUnits.ToSimUnits(ladder.Item.Rect.Size.ToVector2());
|
||||
|
||||
var lowestNearbyLadder = GetLowestNearbyLadder(ladder);
|
||||
if (lowestNearbyLadder != null && lowestNearbyLadder != ladder)
|
||||
{
|
||||
ladderSimSize.Y = ConvertUnits.ToSimUnits(ladder.Item.WorldRect.Y - (lowestNearbyLadder.Item.WorldRect.Y - lowestNearbyLadder.Item.Rect.Size.Y));
|
||||
}
|
||||
|
||||
float stepHeight = ConvertUnits.ToSimUnits(animParams.ClimbStepHeight);
|
||||
|
||||
if (currentHull == null && ladder.Item.Submarine != null)
|
||||
{
|
||||
ladderSimPos += ladder.Item.Submarine.SimPosition;
|
||||
}
|
||||
else if (currentHull?.Submarine != null && currentHull.Submarine != ladder.Item.Submarine && ladder.Item.Submarine != null)
|
||||
{
|
||||
ladderSimPos += ladder.Item.Submarine.SimPosition - currentHull.Submarine.SimPosition;
|
||||
}
|
||||
else if (currentHull?.Submarine != null && ladder.Item.Submarine == null)
|
||||
{
|
||||
ladderSimPos -= currentHull.Submarine.SimPosition;
|
||||
}
|
||||
|
||||
float bottomPos = Collider.SimPosition.Y - ColliderHeightFromFloor - Collider.Radius - Collider.Height / 2.0f;
|
||||
float torsoPos = TorsoPosition ?? 0;
|
||||
float bodyMoveForce = animParams.ClimbBodyMoveForce;
|
||||
if (torso != null)
|
||||
{
|
||||
MoveLimb(torso, new Vector2(ladderSimPos.X - 0.35f * Dir, bottomPos + torsoPos), bodyMoveForce);
|
||||
}
|
||||
if (head != null)
|
||||
{
|
||||
float headPos = HeadPosition ?? 0;
|
||||
MoveLimb(head, new Vector2(ladderSimPos.X - 0.2f * Dir, bottomPos + headPos), bodyMoveForce);
|
||||
}
|
||||
|
||||
Collider.MoveToPos(new Vector2(ladderSimPos.X - 0.1f * Dir, Collider.SimPosition.Y), bodyMoveForce);
|
||||
|
||||
Vector2 handPos = new Vector2(
|
||||
ladderSimPos.X,
|
||||
bottomPos + torsoPos + movement.Y * 0.1f - ladderSimPos.Y);
|
||||
if (climbFast) { handPos.Y -= stepHeight; }
|
||||
|
||||
float handMoveForce = animParams.ClimbHandMoveForce;
|
||||
|
||||
//prevent the hands from going above the top of the ladders
|
||||
handPos.Y = Math.Min(-0.5f, handPos.Y);
|
||||
if (!Aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
{
|
||||
if (rightHand != null)
|
||||
{
|
||||
MoveLimb(rightHand,
|
||||
new Vector2(slide ? handPos.X + ladderSimSize.X * 0.75f : handPos.X,
|
||||
(slide ? handPos.Y + stepHeight : MathUtils.Round(handPos.Y, stepHeight * 2.0f)) + ladderSimPos.Y),
|
||||
handMoveForce);
|
||||
rightHand.body.ApplyTorque(Dir * 2.0f);
|
||||
}
|
||||
}
|
||||
if (!Aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
{
|
||||
if (leftHand != null)
|
||||
{
|
||||
MoveLimb(leftHand,
|
||||
new Vector2(handPos.X - ladderSimSize.X * (slide ? 1.0f : 0.5f),
|
||||
(slide ? handPos.Y + stepHeight : MathUtils.Round(handPos.Y - stepHeight, stepHeight * 2.0f) + stepHeight) + ladderSimPos.Y),
|
||||
handMoveForce); ;
|
||||
leftHand.body.ApplyTorque(Dir * 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
float stepHeightAdjustment = stepHeight * 2.7f;
|
||||
Vector2 footPos = new Vector2(
|
||||
handPos.X - Dir * 0.05f,
|
||||
bottomPos + ColliderHeightFromFloor - stepHeightAdjustment - ladderSimPos.Y);
|
||||
if (climbFast) { footPos.Y += stepHeight; }
|
||||
|
||||
//apply torque to the legs to make the knees bend
|
||||
Limb leftLeg = GetClimbingLimb(LimbType.LeftLeg);
|
||||
Limb rightLeg = GetClimbingLimb(LimbType.RightLeg);
|
||||
|
||||
//only move the feet if they're above the bottom of the ladders
|
||||
//(if not, they'll just dangle in air, and the character holds itself up with its arms)
|
||||
if (footPos.Y > -ladderSimSize.Y - 0.2f && leftFoot != null && rightFoot != null && leftLeg != null && rightLeg != null)
|
||||
{
|
||||
Limb refLimb = GetClimbingLimb(LimbType.Waist) ?? GetClimbingLimb(LimbType.Torso) ?? MainLimb;
|
||||
bool leftLegBackwards = Math.Abs(leftLeg.body.Rotation - refLimb.body.Rotation) > MathHelper.Pi;
|
||||
bool rightLegBackwards = Math.Abs(rightLeg.body.Rotation - refLimb.body.Rotation) > MathHelper.Pi;
|
||||
float footMoveForce = animParams.ClimbFootMoveForce;
|
||||
if (slide)
|
||||
{
|
||||
if (!leftLegBackwards) { MoveLimb(leftFoot, new Vector2(footPos.X - ladderSimSize.X * 0.5f, footPos.Y + ladderSimPos.Y), footMoveForce, pullFromCenter: true); }
|
||||
if (!rightLegBackwards) { MoveLimb(rightFoot, new Vector2(footPos.X, footPos.Y + ladderSimPos.Y), footMoveForce, pullFromCenter: true); }
|
||||
}
|
||||
else
|
||||
{
|
||||
float leftFootPos = MathUtils.Round(footPos.Y + stepHeight, stepHeight * 2.0f) - stepHeight;
|
||||
float prevLeftFootPos = MathUtils.Round(prevFootPos + stepHeight, stepHeight * 2.0f) - stepHeight;
|
||||
if (!leftLegBackwards) { MoveLimb(leftFoot, new Vector2(footPos.X, leftFootPos + ladderSimPos.Y), footMoveForce, pullFromCenter: true); }
|
||||
|
||||
float rightFootPos = MathUtils.Round(footPos.Y, stepHeight * 2.0f);
|
||||
float prevRightFootPos = MathUtils.Round(prevFootPos, stepHeight * 2.0f);
|
||||
if (!rightLegBackwards) { MoveLimb(rightFoot, new Vector2(footPos.X, rightFootPos + ladderSimPos.Y), footMoveForce, pullFromCenter: true); }
|
||||
#if CLIENT
|
||||
if (Math.Abs(leftFootPos - prevLeftFootPos) > stepHeight && leftFoot.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
|
||||
{
|
||||
SoundPlayer.PlaySound("footstep_armor_heavy", leftFoot.WorldPosition, hullGuess: currentHull);
|
||||
leftFoot.LastImpactSoundTime = (float)Timing.TotalTime;
|
||||
}
|
||||
if (Math.Abs(rightFootPos - prevRightFootPos) > stepHeight && rightFoot.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
|
||||
{
|
||||
SoundPlayer.PlaySound("footstep_armor_heavy", rightFoot.WorldPosition, hullGuess: currentHull);
|
||||
rightFoot.LastImpactSoundTime = (float)Timing.TotalTime;
|
||||
}
|
||||
#endif
|
||||
prevFootPos = footPos.Y;
|
||||
}
|
||||
|
||||
if (!leftLegBackwards) { leftLeg.body.ApplyTorque(Dir * -8.0f); } // TODO: expose?
|
||||
if (!rightLegBackwards) { rightLeg.body.ApplyTorque(Dir * -8.0f); }
|
||||
}
|
||||
|
||||
float movementFactor = (handPos.Y / stepHeight) * (float)Math.PI;
|
||||
movementFactor = 0.8f + (float)Math.Abs(Math.Sin(movementFactor));
|
||||
|
||||
Vector2 subSpeed = currentHull != null || ladder.Item.Submarine == null
|
||||
? Vector2.Zero : ladder.Item.Submarine.Velocity;
|
||||
|
||||
//reached the top of the ladders -> can't go further up
|
||||
Vector2 climbForce = new Vector2(0.0f, movement.Y) * movementFactor;
|
||||
|
||||
if (!InWater) { climbForce.Y += 0.3f * movementFactor; }
|
||||
|
||||
if (character.SimPosition.Y > ladderSimPos.Y) { climbForce.Y = Math.Min(0.0f, climbForce.Y); }
|
||||
//reached the bottom -> can't go further down
|
||||
float minHeightFromFloor = ColliderHeightFromFloor / 2 + Collider.Height;
|
||||
if (floorFixture != null &&
|
||||
!floorFixture.CollisionCategories.HasFlag(Physics.CollisionStairs) &&
|
||||
!floorFixture.CollisionCategories.HasFlag(Physics.CollisionPlatform) &&
|
||||
character.SimPosition.Y < standOnFloorY + minHeightFromFloor)
|
||||
{
|
||||
climbForce.Y = MathHelper.Clamp((standOnFloorY + minHeightFromFloor - character.SimPosition.Y) * 5.0f, climbForce.Y, 1.0f);
|
||||
}
|
||||
|
||||
//apply forces to the collider to move the Character up/down
|
||||
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
|
||||
// Don't rotate the head on non-humanoids, because it can cause issues with some ragdolls.
|
||||
// E.g. the head might not actually be head, or it's not where we expect it to be.
|
||||
if (head != null && character.IsHumanoid)
|
||||
{
|
||||
if (Aiming)
|
||||
{
|
||||
RotateHead(head);
|
||||
}
|
||||
else if (Anim == Animation.UsingItemWhileClimbing && character.SelectedItem is { } selectedItem)
|
||||
{
|
||||
Vector2 diff = (selectedItem.WorldPosition - head.WorldPosition) * Dir;
|
||||
float targetRotation = MathHelper.WrapAngle(MathUtils.VectorToAngle(diff) - MathHelper.PiOver4 * Dir);
|
||||
head.body.SmoothRotate(targetRotation, force: animParams.HeadTorque);
|
||||
}
|
||||
else
|
||||
{
|
||||
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
|
||||
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, force: animParams.HeadTorque);
|
||||
}
|
||||
}
|
||||
|
||||
if (ladder.Item.Prefab.Triggers.None())
|
||||
{
|
||||
character.ReleaseSecondaryItem();
|
||||
return;
|
||||
}
|
||||
|
||||
Rectangle trigger = ladder.Item.Prefab.Triggers.FirstOrDefault();
|
||||
trigger = ladder.Item.TransformTrigger(trigger);
|
||||
|
||||
bool isRemote = false;
|
||||
bool isClimbing = true;
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
isRemote = character.IsRemotelyControlled;
|
||||
}
|
||||
//if the character is remotely controlled,
|
||||
//let the server decide when to deselect the ladder and stop climbing
|
||||
if (!isRemote)
|
||||
{
|
||||
if ((character.IsKeyDown(InputType.Left) || character.IsKeyDown(InputType.Right)) &&
|
||||
(!character.IsKeyDown(InputType.Up) && !character.IsKeyDown(InputType.Down)))
|
||||
{
|
||||
isClimbing = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isClimbing)
|
||||
{
|
||||
character.StopClimbing();
|
||||
IgnorePlatforms = false;
|
||||
}
|
||||
|
||||
Ladder GetLowestNearbyLadder(Ladder currentLadder, float threshold = 16.0f)
|
||||
{
|
||||
foreach (Ladder ladder in Ladder.List)
|
||||
{
|
||||
if (ladder == currentLadder || !ladder.Item.IsInteractable(character)) { continue; }
|
||||
if (Math.Abs(ladder.Item.WorldPosition.X - currentLadder.Item.WorldPosition.X) > threshold) { continue; }
|
||||
if (ladder.Item.WorldPosition.Y > currentLadder.Item.WorldPosition.Y) { continue; }
|
||||
if ((currentLadder.Item.WorldRect.Y - currentLadder.Item.Rect.Height) - ladder.Item.WorldRect.Y > threshold) { continue; }
|
||||
return ladder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Limb GetClimbingLimb(LimbType limbType)
|
||||
{
|
||||
if (HasMultipleLimbsOfSameType)
|
||||
{
|
||||
// First try to find a match using the secondary type, if that fails, use the primary type and exclude all the limbs with the secondary type.
|
||||
// Secondary limbs are first excluded and then targeted, because some feet are meant to be used as hands in this context, which means we don't want to get them when seeking the feet.
|
||||
return GetLimb(limbType, useSecondaryType: true) ?? GetLimb(limbType, excludeLimbsWithSecondaryType: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetLimb(limbType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void RotateHead(Limb head)
|
||||
{
|
||||
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
||||
Vector2 dir = (mousePos - head.SimPosition) * Dir;
|
||||
float rot = MathUtils.VectorToAngle(dir);
|
||||
var neckJoint = GetJointBetweenLimbs(LimbType.Head, LimbType.Torso);
|
||||
if (neckJoint != null)
|
||||
{
|
||||
float offset = MathUtils.WrapAnglePi(GetLimb(LimbType.Torso).body.Rotation);
|
||||
float lowerLimit = neckJoint.LowerLimit + offset;
|
||||
float upperLimit = neckJoint.UpperLimit + offset;
|
||||
float min = Math.Min(lowerLimit, upperLimit);
|
||||
float max = Math.Max(lowerLimit, upperLimit);
|
||||
rot = Math.Clamp(rot, min, max);
|
||||
}
|
||||
head.body.SmoothRotate(rot, CurrentAnimationParams.HeadTorque);
|
||||
}
|
||||
|
||||
public void ApplyPose(Vector2 leftHandPos, Vector2 rightHandPos, Vector2 leftFootPos, Vector2 rightFootPos, float footMoveForce = 10)
|
||||
{
|
||||
@@ -754,8 +1041,16 @@ namespace Barotrauma
|
||||
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 });
|
||||
rightShoulder =
|
||||
GetJointBetweenLimbs(LimbType.Torso, LimbType.RightArm) ??
|
||||
GetJointBetweenLimbs(LimbType.Head, LimbType.RightArm) ??
|
||||
GetJoint(LimbType.RightArm, new LimbType[] { LimbType.RightHand, LimbType.RightForearm }) ??
|
||||
GetJointBetweenLimbs(LimbType.Torso, LimbType.RightHand);
|
||||
leftShoulder =
|
||||
GetJointBetweenLimbs(LimbType.Torso, LimbType.LeftArm) ??
|
||||
GetJointBetweenLimbs(LimbType.Head, LimbType.LeftArm) ??
|
||||
GetJoint(LimbType.LeftArm, new LimbType[] { LimbType.LeftHand, LimbType.LeftForearm }) ??
|
||||
GetJointBetweenLimbs(LimbType.Torso, LimbType.LeftHand);
|
||||
|
||||
Vector2 localAnchorShoulder = Vector2.Zero;
|
||||
Vector2 localAnchorElbow = Vector2.Zero;
|
||||
@@ -818,6 +1113,13 @@ namespace Barotrauma
|
||||
CalculateArmLengths();
|
||||
}
|
||||
}
|
||||
|
||||
public void RecreateAndRespawn(RagdollParams ragdollParams = null)
|
||||
{
|
||||
Vector2 pos = character.WorldPosition;
|
||||
Recreate(ragdollParams);
|
||||
character.TeleportTo(pos);
|
||||
}
|
||||
|
||||
private void StartAnimation(Animation animation)
|
||||
{
|
||||
@@ -906,7 +1208,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateTemporaryAnimations(float deltaTime)
|
||||
private void UpdateTemporaryAnimations()
|
||||
{
|
||||
if (tempAnimations.None()) { return; }
|
||||
foreach ((AnimationType animationType, AnimSwap animSwap) in tempAnimations)
|
||||
@@ -932,7 +1234,8 @@ namespace Barotrauma
|
||||
expiredAnimations.Clear();
|
||||
foreach (AnimSwap animSwap in tempAnimations.Values)
|
||||
{
|
||||
animSwap.Update(deltaTime);
|
||||
// Will be removed on the next frame, unless something keeps it alive.
|
||||
animSwap.IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+59
-101
@@ -139,26 +139,15 @@ namespace Barotrauma
|
||||
ResetState();
|
||||
return;
|
||||
}
|
||||
UpdateConstantTorque(deltaTime);
|
||||
UpdateBlink(deltaTime);
|
||||
var mainLimb = MainLimb;
|
||||
|
||||
levitatingCollider = !IsHangingWithRope;
|
||||
levitatingCollider = !IsHangingWithRope && !IsClimbing;
|
||||
|
||||
if (!character.CanMove)
|
||||
{
|
||||
levitatingCollider = false;
|
||||
Collider.FarseerBody.FixedRotation = false;
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
Collider.Enabled = false;
|
||||
Collider.LinearVelocity = mainLimb.LinearVelocity;
|
||||
Collider.SetTransformIgnoreContacts(mainLimb.SimPosition, mainLimb.Rotation);
|
||||
//reset pull joints to prevent the character from "hanging" mid-air if pull joints had been active when the character was still moving
|
||||
//(except when dragging, then we need the pull joints)
|
||||
if (!Draggable || character.SelectedBy == null)
|
||||
{
|
||||
ResetPullJoints();
|
||||
}
|
||||
}
|
||||
UpdateRagdollControlsMovement();
|
||||
if (character.IsDead && deathAnimTimer < deathAnimDuration)
|
||||
{
|
||||
deathAnimTimer += deltaTime;
|
||||
@@ -184,11 +173,11 @@ namespace Barotrauma
|
||||
|
||||
if (InWater)
|
||||
{
|
||||
Collider.SetTransform(new Vector2(Collider.SimPosition.X, MainLimb.SimPosition.Y), 0.0f);
|
||||
Collider.SetTransformIgnoreContacts(new Vector2(Collider.SimPosition.X, MainLimb.SimPosition.Y), 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider.SetTransform(new Vector2(
|
||||
Collider.SetTransformIgnoreContacts(new Vector2(
|
||||
Collider.SimPosition.X,
|
||||
Math.Max(lowestLimb.SimPosition.Y + (Collider.Radius + Collider.Height / 2), Collider.SimPosition.Y)),
|
||||
0.0f);
|
||||
@@ -208,6 +197,11 @@ namespace Barotrauma
|
||||
{
|
||||
TargetMovement = TargetMovement.ClampLength(2);
|
||||
}
|
||||
|
||||
if (IsClimbing)
|
||||
{
|
||||
UpdateClimbing();
|
||||
}
|
||||
|
||||
if (inWater && !forceStanding)
|
||||
{
|
||||
@@ -336,7 +330,6 @@ namespace Barotrauma
|
||||
if (target == null) { return; }
|
||||
Limb mouthLimb = GetLimb(LimbType.Head);
|
||||
if (mouthLimb == null) { return; }
|
||||
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
//stop dragging if there's something between the pull limb and the target
|
||||
@@ -357,23 +350,23 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float dmg = character.Params.EatingSpeed;
|
||||
float eatSpeed = dmg / ((float)Math.Sqrt(Math.Max(target.Mass, 1)) * 10);
|
||||
eatTimer += deltaTime * eatSpeed;
|
||||
|
||||
Vector2 mouthPos = SimplePhysicsEnabled ? character.SimPosition : GetMouthPosition().Value;
|
||||
Vector2 attackSimPosition = character.Submarine == null ? ConvertUnits.ToSimUnits(target.WorldPosition) : target.SimPosition;
|
||||
|
||||
Vector2 limbDiff = attackSimPosition - mouthPos;
|
||||
float extent = Math.Max(mouthLimb.body.GetMaxExtent(), 1);
|
||||
bool tooFar = character.InWater ? limbDiff.LengthSquared() > extent * extent : limbDiff.X > extent;
|
||||
if (tooFar)
|
||||
{
|
||||
character.SelectedCharacter = null;
|
||||
}
|
||||
else
|
||||
if (Character.CanEat)
|
||||
{
|
||||
Vector2 mouthPos = SimplePhysicsEnabled ? character.SimPosition : GetMouthPosition() ?? Vector2.Zero;
|
||||
Vector2 attackSimPosition = character.Submarine == null ? ConvertUnits.ToSimUnits(target.WorldPosition) : target.SimPosition;
|
||||
Vector2 limbDiff = attackSimPosition - mouthPos;
|
||||
float extent = Math.Max(mouthLimb.body.GetMaxExtent(), 1);
|
||||
bool tooFar = character.InWater ? limbDiff.LengthSquared() > extent * extent : limbDiff.X > extent;
|
||||
if (tooFar)
|
||||
{
|
||||
character.DeselectCharacter();
|
||||
return;
|
||||
}
|
||||
|
||||
float dmg = character.Params.EatingSpeed;
|
||||
float eatSpeed = dmg / ((float)Math.Sqrt(Math.Max(target.Mass, 1)) * 10);
|
||||
eatTimer += deltaTime * eatSpeed;
|
||||
|
||||
//pull the target character to the position of the mouth
|
||||
//(+ make the force fluctuate to waggle the character a bit)
|
||||
float dragForce = MathHelper.Clamp(eatSpeed * 10, 0, 40);
|
||||
@@ -405,20 +398,19 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
float force = (float)Math.Sin(eatTimer * 100) * mouthLimb.Mass;
|
||||
mouthLimb.body.ApplyLinearImpulse(Vector2.UnitY * force * 2, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
mouthLimb.body.ApplyTorque(-force * 50);
|
||||
mouthLimb.body.ApplyLinearImpulse(Vector2.UnitY * force * mouthLimb.Params.EatImpulse, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
mouthLimb.body.ApplyTorque(-force * mouthLimb.Params.EatTorque);
|
||||
}
|
||||
|
||||
if (Character.CanEat && target.IsDead)
|
||||
|
||||
var jaw = GetLimb(LimbType.Jaw);
|
||||
if (jaw != null)
|
||||
{
|
||||
jaw.body.ApplyTorque(-(float)Math.Sin(eatTimer * 150) * jaw.Mass * 25);
|
||||
}
|
||||
character.ApplyStatusEffects(ActionType.OnEating, deltaTime);
|
||||
|
||||
if (target.IsDead)
|
||||
{
|
||||
var jaw = GetLimb(LimbType.Jaw);
|
||||
if (jaw != null)
|
||||
{
|
||||
jaw.body.ApplyTorque(-(float)Math.Sin(eatTimer * 150) * jaw.Mass * 25);
|
||||
}
|
||||
|
||||
character.ApplyStatusEffects(ActionType.OnEating, deltaTime);
|
||||
|
||||
float particleFrequency = MathHelper.Clamp(eatSpeed / 2, 0.02f, 0.5f);
|
||||
if (Rand.Value() < particleFrequency / 6)
|
||||
{
|
||||
@@ -430,7 +422,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f)
|
||||
{
|
||||
static bool CanBeSevered(LimbJoint j) => !j.IsSevered && j.CanBeSevered && j.LimbA != null && !j.LimbA.IsSevered && j.LimbB != null && !j.LimbB.IsSevered;
|
||||
static bool CanBeSevered(LimbJoint j) => !j.IsSevered && j.CanBeSevered && j.LimbA is { IsSevered: false } && j.LimbB is { IsSevered: false };
|
||||
//keep severing joints until there is only one limb left
|
||||
var nonSeveredJoints = target.AnimController.LimbJoints.Where(CanBeSevered);
|
||||
if (nonSeveredJoints.None())
|
||||
@@ -440,16 +432,13 @@ namespace Barotrauma
|
||||
{
|
||||
target.Inventory?.AllItemsMod.ForEach(it => it?.Drop(dropper: null));
|
||||
}
|
||||
|
||||
//only one limb left, the character is now full eaten
|
||||
Entity.Spawner?.AddEntityToRemoveQueue(target);
|
||||
|
||||
if (Character.AIController is EnemyAIController enemyAi)
|
||||
{
|
||||
enemyAi.PetBehavior?.OnEat(target);
|
||||
}
|
||||
|
||||
character.SelectedCharacter = null;
|
||||
character.DeselectCharacter();
|
||||
}
|
||||
else //sever a random joint
|
||||
{
|
||||
@@ -460,7 +449,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool reverse;
|
||||
public bool Reverse;
|
||||
|
||||
void UpdateSineAnim(float deltaTime)
|
||||
{
|
||||
@@ -510,7 +499,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 transformedMovement = reverse ? -movement : movement;
|
||||
Vector2 transformedMovement = Reverse ? -movement : movement;
|
||||
float movementAngle = MathUtils.VectorToAngle(transformedMovement) - MathHelper.PiOver2;
|
||||
float mainLimbAngle = 0;
|
||||
if (mainLimb.type == LimbType.Torso && TorsoAngle.HasValue)
|
||||
@@ -555,7 +544,6 @@ namespace Barotrauma
|
||||
foreach (var limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (limb.type != LimbType.Tail) { continue; }
|
||||
if (!limb.Params.ApplyTailAngle) { continue; }
|
||||
RotateTail(limb);
|
||||
isAngleApplied = true;
|
||||
@@ -592,7 +580,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
|
||||
if (reverse)
|
||||
if (Reverse)
|
||||
{
|
||||
movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi);
|
||||
}
|
||||
@@ -651,29 +639,21 @@ namespace Barotrauma
|
||||
foreach (var limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
switch (limb.type)
|
||||
if (limb.type is LimbType.LeftFoot or LimbType.RightFoot)
|
||||
{
|
||||
case LimbType.LeftFoot:
|
||||
case LimbType.RightFoot:
|
||||
if (CurrentSwimParams.FootAnglesInRadians.ContainsKey(limb.Params.ID))
|
||||
{
|
||||
SmoothRotateWithoutWrapping(limb, movementAngle + CurrentSwimParams.FootAnglesInRadians[limb.Params.ID] * Dir, mainLimb, FootTorque);
|
||||
}
|
||||
break;
|
||||
case LimbType.Tail:
|
||||
if (waveLength > 0 && waveAmplitude > 0)
|
||||
{
|
||||
float waveRotation = (float)Math.Sin(WalkPos * limb.Params.SineFrequencyMultiplier);
|
||||
limb.body.ApplyTorque(waveRotation * limb.Mass * waveAmplitude * limb.Params.SineAmplitudeMultiplier);
|
||||
}
|
||||
break;
|
||||
if (CurrentSwimParams.FootAnglesInRadians.ContainsKey(limb.Params.ID))
|
||||
{
|
||||
SmoothRotateWithoutWrapping(limb, movementAngle + CurrentSwimParams.FootAnglesInRadians[limb.Params.ID] * Dir, mainLimb, FootTorque);
|
||||
}
|
||||
}
|
||||
if (limb.type == LimbType.Tail || limb.Params.ApplySineMovement)
|
||||
{
|
||||
if (waveLength > 0 && waveAmplitude > 0)
|
||||
{
|
||||
float waveRotation = (float)Math.Sin(WalkPos * limb.Params.SineFrequencyMultiplier);
|
||||
limb.body.ApplyTorque(waveRotation * limb.Mass * waveAmplitude * limb.Params.SineAmplitudeMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < Limbs.Length; i++)
|
||||
{
|
||||
var limb = Limbs[i];
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (limb.SteerForce <= 0.0f) { continue; }
|
||||
if (!Collider.PhysEnabled) { continue; }
|
||||
Vector2 pullPos = limb.PullJointWorldAnchorA;
|
||||
@@ -698,20 +678,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (Math.Abs(limb.Params.ConstantTorque) > 0)
|
||||
{
|
||||
float movementFactor = Math.Max(character.AnimController.Collider.LinearVelocity.Length() * 0.5f, 1);
|
||||
limb.body.SmoothRotate(MainLimb.Rotation + MathHelper.ToRadians(limb.Params.ConstantAngle) * Dir, limb.Mass * limb.Params.ConstantTorque * movementFactor, wrapAngle: true);
|
||||
}
|
||||
if (limb.Params.BlinkFrequency > 0)
|
||||
{
|
||||
limb.UpdateBlink(deltaTime, MainLimb.Rotation);
|
||||
}
|
||||
}
|
||||
|
||||
floorY = Limbs[0].SimPosition.Y;
|
||||
}
|
||||
|
||||
@@ -744,9 +710,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float offset = MathHelper.Pi * CurrentGroundedParams.StepLiftOffset;
|
||||
if (CurrentGroundedParams.MultiplyByDir)
|
||||
if (character.AnimController.Dir < 0)
|
||||
{
|
||||
offset *= Dir;
|
||||
offset += MathHelper.Pi * CurrentGroundedParams.StepLiftFrequency;
|
||||
}
|
||||
float stepLift = TargetMovement.X == 0.0f ? 0 :
|
||||
(float)Math.Sin(WalkPos * Dir * CurrentGroundedParams.StepLiftFrequency + offset) * (CurrentGroundedParams.StepLiftAmount / 100);
|
||||
@@ -847,14 +813,6 @@ namespace Barotrauma
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) { continue; }
|
||||
if (Math.Abs(limb.Params.ConstantTorque) > 0)
|
||||
{
|
||||
limb.body.SmoothRotate(MainLimb.Rotation + MathHelper.ToRadians(limb.Params.ConstantAngle) * Dir, limb.Mass * limb.Params.ConstantTorque, wrapAngle: true);
|
||||
}
|
||||
if (limb.Params.BlinkFrequency > 0 && !limb.Params.OnlyBlinkInWater)
|
||||
{
|
||||
limb.UpdateBlink(deltaTime, MainLimb.Rotation);
|
||||
}
|
||||
switch (limb.type)
|
||||
{
|
||||
case LimbType.LeftFoot:
|
||||
@@ -1024,7 +982,7 @@ namespace Barotrauma
|
||||
if (RagdollParams.IsSpritesheetOrientationHorizontal)
|
||||
{
|
||||
//horizontally aligned limbs need to be flipped 180 degrees
|
||||
l.body.SetTransform(l.SimPosition, l.body.Rotation + MathHelper.Pi * Dir);
|
||||
l.body.SetTransformIgnoreContacts(l.SimPosition, l.body.Rotation + MathHelper.Pi * Dir);
|
||||
}
|
||||
//no need to do anything when flipping vertically oriented limbs
|
||||
//the sprite gets flipped horizontally, which does the job
|
||||
|
||||
+23
-290
@@ -13,10 +13,8 @@ namespace Barotrauma
|
||||
private const float SteepestWalkableSlopeAngleDegrees = 55f;
|
||||
private const float SlowlyWalkableSlopeAngleDegrees = 30f;
|
||||
|
||||
private static readonly float SteepestWalkableSlopeNormalX =
|
||||
MathF.Sin(MathHelper.ToRadians(SteepestWalkableSlopeAngleDegrees));
|
||||
private static readonly float SlowlyWalkableSlopeNormalX =
|
||||
MathF.Sin(MathHelper.ToRadians(SlowlyWalkableSlopeAngleDegrees));
|
||||
private static readonly float SteepestWalkableSlopeNormalX = MathF.Sin(MathHelper.ToRadians(SteepestWalkableSlopeAngleDegrees));
|
||||
private static readonly float SlowlyWalkableSlopeNormalX = MathF.Sin(MathHelper.ToRadians(SlowlyWalkableSlopeAngleDegrees));
|
||||
|
||||
private const float MaxSpeedOnStairs = 1.7f;
|
||||
private const float SteepSlopePushMagnitude = MaxSpeedOnStairs;
|
||||
@@ -254,7 +252,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (Frozen) { return; }
|
||||
if (MainLimb == null) { return; }
|
||||
|
||||
UpdateConstantTorque(deltaTime);
|
||||
UpdateBlink(deltaTime);
|
||||
levitatingCollider = !IsHangingWithRope;
|
||||
if (onGround && character.CanMove)
|
||||
{
|
||||
@@ -297,25 +296,7 @@ namespace Barotrauma
|
||||
fallingProneAnimTimer += deltaTime;
|
||||
UpdateFallingProne(1.0f);
|
||||
}
|
||||
levitatingCollider = false;
|
||||
Collider.FarseerBody.FixedRotation = false;
|
||||
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
if (Collider.Enabled)
|
||||
{
|
||||
//deactivating the collider -> make the main limb inherit the collider's velocity because it'll control the movement now
|
||||
MainLimb.body.LinearVelocity = Collider.LinearVelocity;
|
||||
Collider.Enabled = false;
|
||||
}
|
||||
Collider.LinearVelocity = MainLimb.LinearVelocity;
|
||||
Collider.SetTransformIgnoreContacts(MainLimb.SimPosition, MainLimb.Rotation);
|
||||
//reset pull joints to prevent the character from "hanging" mid-air if pull joints had been active when the character was still moving
|
||||
//(except when dragging, then we need the pull joints)
|
||||
if (!Draggable || character.SelectedBy == null)
|
||||
{
|
||||
ResetPullJoints();
|
||||
}
|
||||
}
|
||||
UpdateRagdollControlsMovement();
|
||||
return;
|
||||
}
|
||||
fallingProneAnimTimer = 0.0f;
|
||||
@@ -325,7 +306,7 @@ namespace Barotrauma
|
||||
{
|
||||
var lowestLimb = FindLowestLimb();
|
||||
|
||||
Collider.SetTransform(new Vector2(
|
||||
Collider.SetTransformIgnoreContacts(new Vector2(
|
||||
Collider.SimPosition.X,
|
||||
Math.Max(lowestLimb.SimPosition.Y + (Collider.Radius + Collider.Height / 2), Collider.SimPosition.Y)),
|
||||
Collider.Rotation);
|
||||
@@ -357,7 +338,7 @@ namespace Barotrauma
|
||||
float angleDiff = MathUtils.GetShortestAngle(Collider.Rotation, 0.0f);
|
||||
if (Math.Abs(angleDiff) > 0.001f)
|
||||
{
|
||||
Collider.SetTransform(Collider.SimPosition, Collider.Rotation + angleDiff);
|
||||
Collider.SetTransformIgnoreContacts(Collider.SimPosition, Collider.Rotation + angleDiff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,9 +563,7 @@ namespace Barotrauma
|
||||
footMid += (Math.Max(Math.Abs(walkPosX) * limpAmount, 0.0f) * Math.Min(Math.Abs(TargetMovement.X), 0.3f)) * Dir;
|
||||
}
|
||||
|
||||
movement = overrideTargetMovement == Vector2.Zero ?
|
||||
MathUtils.SmoothStep(movement, TargetMovement, movementLerp) :
|
||||
overrideTargetMovement;
|
||||
movement = overrideTargetMovement ?? MathUtils.SmoothStep(movement, TargetMovement, movementLerp);
|
||||
|
||||
if (Math.Abs(movement.X) < 0.005f)
|
||||
{
|
||||
@@ -652,9 +631,14 @@ namespace Barotrauma
|
||||
{
|
||||
movement = Vector2.Zero;
|
||||
}
|
||||
|
||||
|
||||
float offset = MathHelper.Pi * currentGroundedParams.StepLiftOffset;
|
||||
if (character.AnimController.Dir < 0)
|
||||
{
|
||||
offset += MathHelper.Pi * currentGroundedParams.StepLiftFrequency;
|
||||
}
|
||||
float stepLift = TargetMovement.X == 0.0f ? 0 :
|
||||
(float)Math.Sin(WalkPos * currentGroundedParams.StepLiftFrequency + MathHelper.Pi * currentGroundedParams.StepLiftOffset) * (currentGroundedParams.StepLiftAmount / 100);
|
||||
(float)Math.Sin(WalkPos * Dir * currentGroundedParams.StepLiftFrequency + offset) * (currentGroundedParams.StepLiftAmount / 100);
|
||||
|
||||
float y = colliderPos.Y + stepLift;
|
||||
|
||||
@@ -987,7 +971,7 @@ namespace Barotrauma
|
||||
{
|
||||
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
|
||||
}
|
||||
else
|
||||
else if (character.FollowCursor)
|
||||
{
|
||||
RotateHead(head);
|
||||
}
|
||||
@@ -1145,245 +1129,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private float prevFootPos;
|
||||
|
||||
void UpdateClimbing()
|
||||
{
|
||||
var ladder = character.SelectedSecondaryItem?.GetComponent<Ladder>();
|
||||
if (character.IsIncapacitated)
|
||||
{
|
||||
Anim = Animation.None;
|
||||
return;
|
||||
}
|
||||
else if (ladder == null)
|
||||
{
|
||||
StopClimbing();
|
||||
return;
|
||||
}
|
||||
|
||||
onGround = false;
|
||||
IgnorePlatforms = true;
|
||||
|
||||
bool climbFast = targetMovement.Y > 3.0f;
|
||||
bool slide = targetMovement.Y < -1.1f;
|
||||
Vector2 tempTargetMovement = TargetMovement;
|
||||
tempTargetMovement.Y = climbFast ?
|
||||
Math.Min(tempTargetMovement.Y, 2.0f) :
|
||||
Math.Min(tempTargetMovement.Y, 1.0f);
|
||||
|
||||
movement = MathUtils.SmoothStep(movement, tempTargetMovement, 0.3f);
|
||||
|
||||
Limb leftFoot = GetLimb(LimbType.LeftFoot);
|
||||
Limb rightFoot = GetLimb(LimbType.RightFoot);
|
||||
Limb head = GetLimb(LimbType.Head);
|
||||
Limb torso = GetLimb(LimbType.Torso);
|
||||
|
||||
Limb leftHand = GetLimb(LimbType.LeftHand);
|
||||
Limb rightHand = GetLimb(LimbType.RightHand);
|
||||
|
||||
if (leftHand == null || rightHand == null || head == null || torso == null) { return; }
|
||||
|
||||
Vector2 ladderSimPos = ConvertUnits.ToSimUnits(
|
||||
ladder.Item.Rect.X + ladder.Item.Rect.Width / 2.0f,
|
||||
ladder.Item.Rect.Y);
|
||||
|
||||
Vector2 ladderSimSize = ConvertUnits.ToSimUnits(ladder.Item.Rect.Size.ToVector2());
|
||||
|
||||
float lowestLadderSimPos = ladderSimPos.Y - ladderSimPos.Y;
|
||||
var lowestNearbyLadder = GetLowestNearbyLadder(ladder);
|
||||
if (lowestNearbyLadder != null && lowestNearbyLadder != ladder)
|
||||
{
|
||||
ladderSimSize.Y = ConvertUnits.ToSimUnits(ladder.Item.WorldRect.Y - (lowestNearbyLadder.Item.WorldRect.Y - lowestNearbyLadder.Item.Rect.Size.Y));
|
||||
}
|
||||
|
||||
float stepHeight = ConvertUnits.ToSimUnits(30.0f);
|
||||
if (climbFast) { stepHeight *= 2; }
|
||||
|
||||
if (currentHull == null && ladder.Item.Submarine != null)
|
||||
{
|
||||
ladderSimPos += ladder.Item.Submarine.SimPosition;
|
||||
}
|
||||
else if (currentHull?.Submarine != null && currentHull.Submarine != ladder.Item.Submarine && ladder.Item.Submarine != null)
|
||||
{
|
||||
ladderSimPos += ladder.Item.Submarine.SimPosition - currentHull.Submarine.SimPosition;
|
||||
}
|
||||
else if (currentHull?.Submarine != null && ladder.Item.Submarine == null)
|
||||
{
|
||||
ladderSimPos -= currentHull.Submarine.SimPosition;
|
||||
}
|
||||
|
||||
float bottomPos = Collider.SimPosition.Y - ColliderHeightFromFloor - Collider.Radius - Collider.Height / 2.0f;
|
||||
float torsoPos = TorsoPosition ?? 0;
|
||||
MoveLimb(torso, new Vector2(ladderSimPos.X - 0.35f * Dir, bottomPos + torsoPos), 10.5f);
|
||||
float headPos = HeadPosition ?? 0;
|
||||
MoveLimb(head, new Vector2(ladderSimPos.X - 0.2f * Dir, bottomPos + headPos), 10.5f);
|
||||
|
||||
Collider.MoveToPos(new Vector2(ladderSimPos.X - 0.1f * Dir, Collider.SimPosition.Y), 10.5f);
|
||||
|
||||
Vector2 handPos = new Vector2(
|
||||
ladderSimPos.X,
|
||||
bottomPos + torsoPos + movement.Y * 0.1f - ladderSimPos.Y);
|
||||
if (climbFast) { handPos.Y -= stepHeight; }
|
||||
|
||||
//prevent the hands from going above the top of the ladders
|
||||
handPos.Y = Math.Min(-0.5f, handPos.Y);
|
||||
if (!Aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
{
|
||||
MoveLimb(rightHand,
|
||||
new Vector2(slide ? handPos.X + ladderSimSize.X * 0.5f : handPos.X,
|
||||
(slide ? handPos.Y : MathUtils.Round(handPos.Y, stepHeight * 2.0f)) + ladderSimPos.Y),
|
||||
5.2f);
|
||||
rightHand.body.ApplyTorque(Dir * 2.0f);
|
||||
}
|
||||
if (!Aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
{
|
||||
MoveLimb(leftHand,
|
||||
new Vector2(handPos.X - ladderSimSize.X * 0.5f,
|
||||
(slide ? handPos.Y : MathUtils.Round(handPos.Y - stepHeight, stepHeight * 2.0f) + stepHeight) + ladderSimPos.Y),
|
||||
5.2f); ;
|
||||
leftHand.body.ApplyTorque(Dir * 2.0f);
|
||||
}
|
||||
|
||||
Vector2 footPos = new Vector2(
|
||||
handPos.X - Dir * 0.05f,
|
||||
bottomPos + ColliderHeightFromFloor - stepHeight * 2.7f - ladderSimPos.Y);
|
||||
if (climbFast) { footPos.Y += stepHeight; }
|
||||
|
||||
//apply torque to the legs to make the knees bend
|
||||
Limb leftLeg = GetLimb(LimbType.LeftLeg);
|
||||
Limb rightLeg = GetLimb(LimbType.RightLeg);
|
||||
|
||||
//only move the feet if they're above the bottom of the ladders
|
||||
//(if not, they'll just dangle in air, and the character holds itself up with it's arms)
|
||||
if (footPos.Y > -ladderSimSize.Y - 0.2f && leftFoot != null && rightFoot != null)
|
||||
{
|
||||
Limb refLimb = GetLimb(LimbType.Waist) ?? GetLimb(LimbType.Torso);
|
||||
bool leftLegBackwards = Math.Abs(leftLeg.body.Rotation - refLimb.body.Rotation) > MathHelper.Pi;
|
||||
bool rightLegBackwards = Math.Abs(rightLeg.body.Rotation - refLimb.body.Rotation) > MathHelper.Pi;
|
||||
|
||||
if (slide)
|
||||
{
|
||||
if (!leftLegBackwards) { MoveLimb(leftFoot, new Vector2(footPos.X - ladderSimSize.X * 0.5f, footPos.Y + ladderSimPos.Y), 15.5f, true); }
|
||||
if (!rightLegBackwards) { MoveLimb(rightFoot, new Vector2(footPos.X, footPos.Y + ladderSimPos.Y), 15.5f, true); }
|
||||
}
|
||||
else
|
||||
{
|
||||
float leftFootPos = MathUtils.Round(footPos.Y + stepHeight, stepHeight * 2.0f) - stepHeight;
|
||||
float prevLeftFootPos = MathUtils.Round(prevFootPos + stepHeight, stepHeight * 2.0f) - stepHeight;
|
||||
if (!leftLegBackwards) { MoveLimb(leftFoot, new Vector2(footPos.X, leftFootPos + ladderSimPos.Y), 15.5f, true); }
|
||||
|
||||
float rightFootPos = MathUtils.Round(footPos.Y, stepHeight * 2.0f);
|
||||
float prevRightFootPos = MathUtils.Round(prevFootPos, stepHeight * 2.0f);
|
||||
if (!rightLegBackwards) { MoveLimb(rightFoot, new Vector2(footPos.X, rightFootPos + ladderSimPos.Y), 15.5f, true); }
|
||||
#if CLIENT
|
||||
if (Math.Abs(leftFootPos - prevLeftFootPos) > stepHeight && leftFoot.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
|
||||
{
|
||||
SoundPlayer.PlaySound("footstep_armor_heavy", leftFoot.WorldPosition, hullGuess: currentHull);
|
||||
leftFoot.LastImpactSoundTime = (float)Timing.TotalTime;
|
||||
}
|
||||
if (Math.Abs(rightFootPos - prevRightFootPos) > stepHeight && rightFoot.LastImpactSoundTime < Timing.TotalTime - Limb.SoundInterval)
|
||||
{
|
||||
SoundPlayer.PlaySound("footstep_armor_heavy", rightFoot.WorldPosition, hullGuess: currentHull);
|
||||
rightFoot.LastImpactSoundTime = (float)Timing.TotalTime;
|
||||
}
|
||||
#endif
|
||||
prevFootPos = footPos.Y;
|
||||
}
|
||||
|
||||
if (!leftLegBackwards) { leftLeg.body.ApplyTorque(Dir * -8.0f); }
|
||||
if (!rightLegBackwards) { rightLeg.body.ApplyTorque(Dir * -8.0f); }
|
||||
}
|
||||
|
||||
float movementFactor = (handPos.Y / stepHeight) * (float)Math.PI;
|
||||
movementFactor = 0.8f + (float)Math.Abs(Math.Sin(movementFactor));
|
||||
|
||||
Vector2 subSpeed = currentHull != null || ladder.Item.Submarine == null
|
||||
? Vector2.Zero : ladder.Item.Submarine.Velocity;
|
||||
|
||||
//reached the top of the ladders -> can't go further up
|
||||
Vector2 climbForce = new Vector2(0.0f, movement.Y) * movementFactor;
|
||||
|
||||
if (!InWater) { climbForce.Y += 0.3f * movementFactor; }
|
||||
|
||||
if (character.SimPosition.Y > ladderSimPos.Y) { climbForce.Y = Math.Min(0.0f, climbForce.Y); }
|
||||
//reached the bottom -> can't go further down
|
||||
float minHeightFromFloor = ColliderHeightFromFloor / 2 + Collider.Height;
|
||||
if (floorFixture != null &&
|
||||
!floorFixture.CollisionCategories.HasFlag(Physics.CollisionStairs) &&
|
||||
!floorFixture.CollisionCategories.HasFlag(Physics.CollisionPlatform) &&
|
||||
character.SimPosition.Y < standOnFloorY + minHeightFromFloor)
|
||||
{
|
||||
climbForce.Y = MathHelper.Clamp((standOnFloorY + minHeightFromFloor - character.SimPosition.Y) * 5.0f, climbForce.Y, 1.0f);
|
||||
}
|
||||
|
||||
//apply forces to the collider to move the Character up/down
|
||||
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
|
||||
if (Aiming)
|
||||
{
|
||||
RotateHead(head);
|
||||
}
|
||||
else if (Anim == Animation.UsingItemWhileClimbing && character.SelectedItem is { } selectedItem)
|
||||
{
|
||||
Vector2 diff = (selectedItem.WorldPosition - head.WorldPosition) * Dir;
|
||||
float targetRotation = MathHelper.WrapAngle(MathUtils.VectorToAngle(diff) - MathHelper.PiOver4 * Dir);
|
||||
head.body.SmoothRotate(targetRotation, force: WalkParams.HeadTorque);
|
||||
}
|
||||
else
|
||||
{
|
||||
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
|
||||
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, force: WalkParams.HeadTorque);
|
||||
}
|
||||
|
||||
if (ladder.Item.Prefab.Triggers.None())
|
||||
{
|
||||
character.ReleaseSecondaryItem();
|
||||
return;
|
||||
}
|
||||
|
||||
Rectangle trigger = ladder.Item.Prefab.Triggers.FirstOrDefault();
|
||||
trigger = ladder.Item.TransformTrigger(trigger);
|
||||
|
||||
bool isRemote = false;
|
||||
bool isClimbing = true;
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
isRemote = character.IsRemotelyControlled;
|
||||
}
|
||||
if (isRemote)
|
||||
{
|
||||
if (Math.Abs(targetMovement.X) > 0.05f ||
|
||||
(TargetMovement.Y < 0.0f && ConvertUnits.ToSimUnits(trigger.Height) + handPos.Y < HeadPosition) ||
|
||||
(TargetMovement.Y > 0.0f && handPos.Y > 0.1f))
|
||||
{
|
||||
isClimbing = false;
|
||||
}
|
||||
}
|
||||
else if ((character.IsKeyDown(InputType.Left) || character.IsKeyDown(InputType.Right)) &&
|
||||
(!character.IsKeyDown(InputType.Up) && !character.IsKeyDown(InputType.Down)))
|
||||
{
|
||||
isClimbing = false;
|
||||
}
|
||||
|
||||
if (!isClimbing)
|
||||
{
|
||||
character.StopClimbing();
|
||||
IgnorePlatforms = false;
|
||||
}
|
||||
|
||||
Ladder GetLowestNearbyLadder(Ladder currentLadder, float threshold = 16.0f)
|
||||
{
|
||||
foreach (Ladder ladder in Ladder.List)
|
||||
{
|
||||
if (ladder == currentLadder || !ladder.Item.IsInteractable(character)) { continue; }
|
||||
if (Math.Abs(ladder.Item.WorldPosition.X - currentLadder.Item.WorldPosition.X) > threshold) { continue; }
|
||||
if (ladder.Item.WorldPosition.Y > currentLadder.Item.WorldPosition.Y) { continue; }
|
||||
if ((currentLadder.Item.WorldRect.Y - currentLadder.Item.Rect.Height) - ladder.Item.WorldRect.Y > threshold) { continue; }
|
||||
return ladder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateFallingProne(float strength, bool moveHands = true, bool moveTorso = true, bool moveLegs = true)
|
||||
{
|
||||
if (strength <= 0.0f) { return; }
|
||||
@@ -1518,7 +1263,7 @@ namespace Barotrauma
|
||||
|
||||
float cprBoost = character.GetStatValue(StatTypes.CPRBoost);
|
||||
|
||||
int skill = (int)character.GetSkillLevel("medical");
|
||||
int skill = (int)character.GetSkillLevel(Tags.MedicalSkill);
|
||||
|
||||
if (GameMain.NetworkMember is not { IsClient: true })
|
||||
{
|
||||
@@ -1595,7 +1340,7 @@ namespace Barotrauma
|
||||
//otherwise it's easy to abuse the system by repeatedly reviving in a low-oxygen room
|
||||
if (!target.IsDead)
|
||||
{
|
||||
target.CharacterHealth.CalculateVitality();
|
||||
target.CharacterHealth.RecalculateVitality();
|
||||
if (wasCritical && target.Vitality > 0.0f && Timing.TotalTime > lastReviveTime + 10.0f)
|
||||
{
|
||||
character.Info?.ApplySkillGain(Tags.MedicalSkill, SkillSettings.Current.SkillIncreasePerCprRevive);
|
||||
@@ -1811,7 +1556,7 @@ namespace Barotrauma
|
||||
string errorMsg =
|
||||
$"Attempted to move the anchor B of a limb's pull joint extremely far from the limb in {nameof(DragCharacter)}. " +
|
||||
$"Character in sub: {character.Submarine != null}, target in sub: {target.Submarine != null}.";
|
||||
GameAnalyticsManager.AddErrorEventOnce("DragCharacter:PullJointTooFar", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("DragCharacter:PullJointTooFar", GameAnalyticsManager.ErrorSeverity.Warning, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#endif
|
||||
@@ -1876,23 +1621,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RotateHead(Limb head)
|
||||
|
||||
public void Crouch()
|
||||
{
|
||||
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
||||
Vector2 dir = (mousePos - head.SimPosition) * Dir;
|
||||
float rot = MathUtils.VectorToAngle(dir);
|
||||
var neckJoint = GetJointBetweenLimbs(LimbType.Head, LimbType.Torso);
|
||||
if (neckJoint != null)
|
||||
{
|
||||
float offset = MathUtils.WrapAnglePi(GetLimb(LimbType.Torso).body.Rotation);
|
||||
float lowerLimit = neckJoint.LowerLimit + offset;
|
||||
float upperLimit = neckJoint.UpperLimit + offset;
|
||||
float min = Math.Min(lowerLimit, upperLimit);
|
||||
float max = Math.Max(lowerLimit, upperLimit);
|
||||
rot = Math.Clamp(rot, min, max);
|
||||
}
|
||||
head.body.SmoothRotate(rot, CurrentAnimationParams.HeadTorque);
|
||||
Crouching = true;
|
||||
character.SetInput(InputType.Crouch, hit: false, held: true);
|
||||
}
|
||||
|
||||
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
|
||||
|
||||
@@ -64,6 +64,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<Body> limbBodies = new List<Body>();
|
||||
public IEnumerable<Body> LimbBodies => limbBodies;
|
||||
|
||||
public bool HasMultipleLimbsOfSameType => limbs != null && limbs.Length > limbDictionary.Count;
|
||||
|
||||
private bool frozen;
|
||||
@@ -91,7 +94,7 @@ namespace Barotrauma
|
||||
private bool simplePhysicsEnabled;
|
||||
|
||||
public Character Character => character;
|
||||
protected Character character;
|
||||
protected readonly Character character;
|
||||
|
||||
protected float strongestImpact;
|
||||
|
||||
@@ -108,7 +111,7 @@ namespace Barotrauma
|
||||
|
||||
//a movement vector that overrides targetmovement if trying to steer
|
||||
//a Character to the position sent by server in multiplayer mode
|
||||
protected Vector2 overrideTargetMovement;
|
||||
protected Vector2? overrideTargetMovement;
|
||||
|
||||
protected float floorY, standOnFloorY;
|
||||
protected Fixture floorFixture;
|
||||
@@ -138,6 +141,12 @@ namespace Barotrauma
|
||||
|
||||
private Category prevCollisionCategory = Category.None;
|
||||
|
||||
/// <summary>
|
||||
/// When the character is alive/conscious, the collider drives the character's movement and is used to sync the character's position in MP.
|
||||
/// When unconscious, the ragdoll controls the movement and the collider just sticks to the main limb.
|
||||
/// </summary>
|
||||
public bool ColliderControlsMovement => character.CanMove;
|
||||
|
||||
public bool IsStuck => Limbs.Any(l => l.IsStuck);
|
||||
|
||||
public PhysicsBody Collider
|
||||
@@ -185,7 +194,7 @@ namespace Barotrauma
|
||||
Vector2 pos = collider[colliderIndex].SimPosition;
|
||||
pos.Y -= collider[colliderIndex].Height * 0.5f;
|
||||
pos.Y += collider[value].Height * 0.5f;
|
||||
collider[value].SetTransform(pos, collider[colliderIndex].Rotation);
|
||||
collider[value].SetTransformIgnoreContacts(pos, collider[colliderIndex].Rotation);
|
||||
|
||||
collider[value].LinearVelocity = collider[colliderIndex].LinearVelocity;
|
||||
collider[value].AngularVelocity = collider[colliderIndex].AngularVelocity;
|
||||
@@ -282,7 +291,7 @@ namespace Barotrauma
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered || !limb.body.PhysEnabled) { continue; }
|
||||
limb.body.SetTransform(Collider.SimPosition, Collider.Rotation);
|
||||
limb.body.SetTransformIgnoreContacts(Collider.SimPosition, Collider.Rotation);
|
||||
//reset pull joints (they may be somewhere far away if the character has moved from the position where animations were last updated)
|
||||
limb.PullJointEnabled = false;
|
||||
limb.PullJointWorldAnchorB = limb.SimPosition;
|
||||
@@ -297,11 +306,11 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
return (overrideTargetMovement == Vector2.Zero) ? targetMovement : overrideTargetMovement;
|
||||
return overrideTargetMovement ?? targetMovement;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
if (!MathUtils.IsValid(value)) { return; }
|
||||
targetMovement.X = MathHelper.Clamp(value.X, -MAX_SPEED, MAX_SPEED);
|
||||
targetMovement.Y = MathHelper.Clamp(value.Y, -MAX_SPEED, MAX_SPEED);
|
||||
}
|
||||
@@ -385,15 +394,16 @@ namespace Barotrauma
|
||||
if (ragdollParams != null)
|
||||
{
|
||||
RagdollParams = ragdollParams;
|
||||
if (!character.VariantOf.IsEmpty)
|
||||
{
|
||||
RagdollParams.TryApplyVariantScale(character.Params.VariantFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only re-equip items if the ragdoll doesn't change, because re-equiping items might throw exceptions if the limbs have changed.
|
||||
items = limbs?.ToDictionary(l => l.Params, l => l.WearingItems);
|
||||
}
|
||||
if (character.Params.VariantFile is XDocument variantFile)
|
||||
{
|
||||
RagdollParams.TryApplyVariantScale(variantFile);
|
||||
}
|
||||
foreach (var limbParams in RagdollParams.Limbs)
|
||||
{
|
||||
if (!PhysicsBody.IsValidShape(limbParams.Radius, limbParams.Height, limbParams.Width))
|
||||
@@ -430,18 +440,13 @@ namespace Barotrauma
|
||||
|
||||
if (character.IsHusk && character.Params.UseHuskAppendage)
|
||||
{
|
||||
bool inEditor = false;
|
||||
#if CLIENT
|
||||
inEditor = Screen.Selected == GameMain.CharacterEditorScreen;
|
||||
#endif
|
||||
|
||||
var characterPrefab = CharacterPrefab.FindByFilePath(character.ConfigPath);
|
||||
if (characterPrefab?.ConfigElement != null)
|
||||
{
|
||||
var mainElement = characterPrefab.ConfigElement;
|
||||
foreach (var huskAppendage in mainElement.GetChildElements("huskappendage"))
|
||||
{
|
||||
if (!inEditor && huskAppendage.GetAttributeBool("onlyfromafflictions", false)) { continue; }
|
||||
if (huskAppendage.GetAttributeBool("onlyfromafflictions", false)) { continue; }
|
||||
|
||||
Identifier afflictionIdentifier = huskAppendage.GetAttributeIdentifier("affliction", Identifier.Empty);
|
||||
if (!AfflictionPrefab.Prefabs.TryGet(afflictionIdentifier, out AfflictionPrefab affliction) ||
|
||||
@@ -452,7 +457,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
AfflictionHusk.AttachHuskAppendage(character, matchingAffliction, huskAppendage, ragdoll: this);
|
||||
AfflictionHusk.AttachHuskAppendage(character, matchingAffliction, huskedSpeciesName: character.SpeciesName, huskAppendage, ragdoll: this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,7 +483,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Invalid collider dimensions: " + cParams.Name);
|
||||
break; ;
|
||||
}
|
||||
var body = new PhysicsBody(cParams);
|
||||
var body = new PhysicsBody(cParams, findNewContacts: false);
|
||||
collider.Add(body);
|
||||
body.UserData = character;
|
||||
body.FarseerBody.OnCollision += OnLimbCollision;
|
||||
@@ -520,7 +525,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (joint == null) { continue; }
|
||||
float angle = (joint.LowerLimit + joint.UpperLimit) / 2.0f;
|
||||
joint.LimbB?.body?.SetTransform(
|
||||
joint.LimbB?.body?.SetTransformIgnoreContacts(
|
||||
(joint.WorldAnchorA - MathUtils.RotatePointAroundTarget(joint.LocalAnchorB, Vector2.Zero, joint.BodyA.Rotation + angle, true)),
|
||||
joint.BodyA.Rotation + angle);
|
||||
}
|
||||
@@ -528,11 +533,13 @@ namespace Barotrauma
|
||||
|
||||
protected void CreateLimbs()
|
||||
{
|
||||
limbBodies.Clear();
|
||||
limbs?.ForEach(l => l.Remove());
|
||||
Mass = 0;
|
||||
DebugConsole.Log($"Creating limbs from {RagdollParams.Name}.");
|
||||
limbDictionary = new Dictionary<LimbType, Limb>();
|
||||
limbs = new Limb[RagdollParams.Limbs.Count];
|
||||
RagdollParams.Limbs.ForEach(l => AddLimb(l));
|
||||
RagdollParams.Limbs.ForEach(AddLimb);
|
||||
if (limbs.Contains(null)) { return; }
|
||||
SetupDrawOrder();
|
||||
}
|
||||
@@ -549,11 +556,11 @@ namespace Barotrauma
|
||||
|
||||
/// <summary>
|
||||
/// Resets the serializable data to the currently selected ragdoll params.
|
||||
/// Force reloading always loads the xml stored on the disk.
|
||||
/// Always loads the xml stored on the disk.
|
||||
/// </summary>
|
||||
public void ResetRagdoll(bool forceReload = false)
|
||||
public void ResetRagdoll()
|
||||
{
|
||||
RagdollParams.Reset(forceReload);
|
||||
RagdollParams.Reset(forceReload: true);
|
||||
ResetJoints();
|
||||
ResetLimbs();
|
||||
}
|
||||
@@ -577,7 +584,7 @@ namespace Barotrauma
|
||||
|
||||
public void AddJoint(JointParams jointParams)
|
||||
{
|
||||
if (!checkLimbIndex(jointParams.Limb2, "Limb1") || !checkLimbIndex(jointParams.Limb2, "Limb2"))
|
||||
if (!checkLimbIndex(jointParams.Limb1, "Limb1") || !checkLimbIndex(jointParams.Limb2, "Limb2"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -621,6 +628,7 @@ namespace Barotrauma
|
||||
{
|
||||
throw new Exception($"Failed to add a limb to the character \"{Character?.ConfigPath ?? "null"}\" (limb index {ID} out of bounds). The ragdoll file may be configured incorrectly.");
|
||||
}
|
||||
limbBodies.Add(limb.body.FarseerBody);
|
||||
Limbs[ID] = limb;
|
||||
Mass += limb.Mass;
|
||||
if (!limbDictionary.ContainsKey(limb.type)) { limbDictionary.Add(limb.type, limb); }
|
||||
@@ -632,6 +640,7 @@ namespace Barotrauma
|
||||
limb.body.FarseerBody.OnCollision += OnLimbCollision;
|
||||
Array.Resize(ref limbs, Limbs.Length + 1);
|
||||
Limbs[Limbs.Length - 1] = limb;
|
||||
limbBodies.Add(limb.body.FarseerBody);
|
||||
Mass += limb.Mass;
|
||||
if (!limbDictionary.ContainsKey(limb.type)) { limbDictionary.Add(limb.type, limb); }
|
||||
SetupDrawOrder();
|
||||
@@ -639,14 +648,14 @@ namespace Barotrauma
|
||||
|
||||
public void RemoveLimb(Limb limb)
|
||||
{
|
||||
if (!Limbs.Contains(limb)) return;
|
||||
if (!Limbs.Contains(limb)) { return; }
|
||||
|
||||
Limb[] newLimbs = new Limb[Limbs.Length - 1];
|
||||
|
||||
int i = 0;
|
||||
foreach (Limb existingLimb in Limbs)
|
||||
{
|
||||
if (existingLimb == limb) continue;
|
||||
if (existingLimb == limb) { continue; }
|
||||
newLimbs[i] = existingLimb;
|
||||
i++;
|
||||
}
|
||||
@@ -684,8 +693,10 @@ namespace Barotrauma
|
||||
LimbJoints = newJoints;
|
||||
}
|
||||
|
||||
SubtractMass(limb);
|
||||
limbBodies.Remove(limb.body.FarseerBody);
|
||||
limb.Remove();
|
||||
System.Diagnostics.Debug.Assert(!limbs.Contains(limb));
|
||||
System.Diagnostics.Debug.Assert(limbs.None(l => l.Removed));
|
||||
foreach (LimbJoint limbJoint in attachedJoints)
|
||||
{
|
||||
GameMain.World.Remove(limbJoint.Joint);
|
||||
@@ -819,9 +830,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.DisableImpactDamageTimer > 0.0f) { return; }
|
||||
|
||||
if (f2.Body?.UserData is Item)
|
||||
if (f2.Body?.UserData is Item &&
|
||||
f2.Body.BodyType != BodyType.Static)
|
||||
{
|
||||
//no impact damage from items
|
||||
//no impact damage from items with a non-static body
|
||||
//items that can impact characters (melee weapons, projectiles) should handle the damage themselves
|
||||
return;
|
||||
}
|
||||
@@ -1073,7 +1085,7 @@ namespace Barotrauma
|
||||
Vector2 moveDir = hullDiff.LengthSquared() < 0.001f ? Vector2.UnitY : Vector2.Normalize(hullDiff);
|
||||
|
||||
//find a position 32 units away from the hull
|
||||
if (MathUtils.GetLineRectangleIntersection(
|
||||
if (MathUtils.GetLineWorldRectangleIntersection(
|
||||
newHull.WorldPosition,
|
||||
newHull.WorldPosition + moveDir * Math.Max(newHull.Rect.Width, newHull.Rect.Height),
|
||||
new Rectangle(newHull.WorldRect.X - 32, newHull.WorldRect.Y + 32, newHull.WorldRect.Width + 64, newHull.Rect.Height + 64),
|
||||
@@ -1294,6 +1306,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
|
||||
Collider.LinearVelocity = new Vector2(
|
||||
NetConfig.Quantize(Collider.LinearVelocity.X, -MaxVel, MaxVel, 12),
|
||||
NetConfig.Quantize(Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12));
|
||||
|
||||
if (forceStanding)
|
||||
{
|
||||
inWater = false;
|
||||
@@ -1400,7 +1417,12 @@ namespace Barotrauma
|
||||
limb.Update(deltaTime);
|
||||
}
|
||||
|
||||
if (!inWater && character.AllowInput && levitatingCollider)
|
||||
bool isAttachedToController =
|
||||
character.SelectedItem?.GetComponent<Items.Components.Controller>() is { } controller &&
|
||||
controller.User == character &&
|
||||
controller.IsAttachedUser(controller.User);
|
||||
|
||||
if (!inWater && character.AllowInput && levitatingCollider && !isAttachedToController)
|
||||
{
|
||||
if (onGround && Collider.LinearVelocity.Y > -ImpactTolerance)
|
||||
{
|
||||
@@ -1433,7 +1455,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
// Falling -> ragdoll briefly if we are not moving at all, because we are probably stuck.
|
||||
if (Collider.LinearVelocity == Vector2.Zero)
|
||||
if (Collider.LinearVelocity == Vector2.Zero && !character.IsRemotePlayer)
|
||||
{
|
||||
character.IsRagdolled = true;
|
||||
if (character.IsBot)
|
||||
@@ -1448,6 +1470,30 @@ namespace Barotrauma
|
||||
forceNotStanding = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the logic that needs to run when the ragdoll is what controls the character's movement instead of the collider <see cref="ColliderControlsMovement"/>
|
||||
/// (making the collider stick to the ragdoll's main limb).
|
||||
/// </summary>
|
||||
protected void UpdateRagdollControlsMovement()
|
||||
{
|
||||
levitatingCollider = false;
|
||||
Collider.FarseerBody.FixedRotation = false;
|
||||
if (Collider.Enabled)
|
||||
{
|
||||
//deactivating the collider -> make the main limb inherit the collider's velocity because it'll control the movement now
|
||||
MainLimb.body.LinearVelocity = Collider.LinearVelocity;
|
||||
Collider.Enabled = false;
|
||||
}
|
||||
Collider.LinearVelocity = MainLimb.LinearVelocity;
|
||||
Collider.SetTransformIgnoreContacts(MainLimb.SimPosition, MainLimb.Rotation);
|
||||
//reset pull joints to prevent the character from "hanging" mid-air if pull joints had been active when the character was still moving
|
||||
//(except when dragging, then we need the pull joints)
|
||||
if (!Draggable || character.SelectedBy == null)
|
||||
{
|
||||
ResetPullJoints();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckBodyInRest(float deltaTime)
|
||||
{
|
||||
if (SimplePhysicsEnabled) { return; }
|
||||
@@ -1910,7 +1956,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider.SetTransform(simPosition, Collider.Rotation);
|
||||
Collider.SetTransformIgnoreContacts(simPosition, Collider.Rotation);
|
||||
}
|
||||
|
||||
if (!MathUtils.NearlyEqual(limbMoveAmount, Vector2.Zero))
|
||||
@@ -2009,7 +2055,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
limb.body.SetTransform(movePos, rotation);
|
||||
limb.body.SetTransformIgnoreContacts(movePos, rotation);
|
||||
limb.PullJointWorldAnchorB = limb.PullJointWorldAnchorA;
|
||||
limb.PullJointEnabled = false;
|
||||
}
|
||||
@@ -2084,7 +2130,7 @@ namespace Barotrauma
|
||||
partial void UpdateNetPlayerPositionProjSpecific(float deltaTime, float lowestSubPos);
|
||||
private void UpdateNetPlayerPosition(float deltaTime)
|
||||
{
|
||||
if (GameMain.NetworkMember == null) return;
|
||||
if (GameMain.NetworkMember == null) { return; }
|
||||
|
||||
float lowestSubPos = float.MaxValue;
|
||||
if (Submarine.Loaded.Any())
|
||||
@@ -2113,26 +2159,48 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
|
||||
/// </summary>
|
||||
public Limb GetLimb(LimbType limbType, bool excludeSevered = true)
|
||||
/// <param name="limbType"></param>
|
||||
/// <param name="excludeSevered">Should we filter out severed limbs?</param>
|
||||
/// <param name="useSecondaryType">Should we target limbs with secondary type instead of (primary) type?</param>
|
||||
/// <param name="excludeLimbsWithSecondaryType">Should we filter out all limbs with a secondary type something else than "None"?</param>
|
||||
/// <returns></returns>
|
||||
public Limb GetLimb(LimbType limbType, bool excludeSevered = true, bool excludeLimbsWithSecondaryType = false, bool useSecondaryType = false)
|
||||
{
|
||||
if (limbDictionary.TryGetValue(limbType, out Limb limb))
|
||||
Limb limb = null;
|
||||
if (!HasMultipleLimbsOfSameType && !useSecondaryType && !excludeLimbsWithSecondaryType)
|
||||
{
|
||||
if (excludeSevered && limb.IsSevered)
|
||||
// Faster method, but doesn't work when there's multiple limbs of the same type or if we want to seek/exclude limbs with different conditions.
|
||||
if (limbDictionary.TryGetValue(limbType, out limb))
|
||||
{
|
||||
limb = null;
|
||||
}
|
||||
if (limb.Removed)
|
||||
{
|
||||
limb = null;
|
||||
}
|
||||
if (excludeSevered && limb is { IsSevered: true } )
|
||||
{
|
||||
limb = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (limb == null && HasMultipleLimbsOfSameType)
|
||||
if (limb == null)
|
||||
{
|
||||
// Didn't find a (valid) limb of the matching type. If there's multiple limbs of the same type, check the other limbs.
|
||||
// Didn't seek or find a (valid) limb of the matching type. If there's multiple limbs of the same type, check the other limbs.
|
||||
foreach (var l in limbs)
|
||||
{
|
||||
if (l.type != limbType) { continue; }
|
||||
if (!excludeSevered || !l.IsSevered)
|
||||
if (l.Removed) { continue; }
|
||||
if (useSecondaryType)
|
||||
{
|
||||
limb = l;
|
||||
break;
|
||||
if (l.Params.SecondaryType != limbType) { continue; }
|
||||
}
|
||||
else if (l.type != limbType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (excludeSevered && l.IsSevered) { continue; }
|
||||
if (excludeLimbsWithSecondaryType && l.Params.SecondaryType != LimbType.None) { continue; }
|
||||
// Found a valid and match
|
||||
limb = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return limb;
|
||||
@@ -2220,6 +2288,7 @@ namespace Barotrauma
|
||||
}
|
||||
limbs = null;
|
||||
}
|
||||
limbBodies.Clear();
|
||||
|
||||
if (collider != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user