v1.6.17.0 (Unto the Breach update)
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,6 +699,294 @@ 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 (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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -818,6 +1109,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 +1204,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 +1230,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+55
-84
@@ -139,9 +139,11 @@ namespace Barotrauma
|
||||
ResetState();
|
||||
return;
|
||||
}
|
||||
UpdateConstantTorque(deltaTime);
|
||||
UpdateBlink(deltaTime);
|
||||
var mainLimb = MainLimb;
|
||||
|
||||
levitatingCollider = !IsHangingWithRope;
|
||||
levitatingCollider = !IsHangingWithRope && !IsClimbing;
|
||||
|
||||
if (!character.CanMove)
|
||||
{
|
||||
@@ -208,6 +210,11 @@ namespace Barotrauma
|
||||
{
|
||||
TargetMovement = TargetMovement.ClampLength(2);
|
||||
}
|
||||
|
||||
if (IsClimbing)
|
||||
{
|
||||
UpdateClimbing();
|
||||
}
|
||||
|
||||
if (inWater && !forceStanding)
|
||||
{
|
||||
@@ -336,7 +343,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 +363,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 +411,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 +435,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 +445,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 +462,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool reverse;
|
||||
public bool Reverse;
|
||||
|
||||
void UpdateSineAnim(float deltaTime)
|
||||
{
|
||||
@@ -510,7 +512,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 +557,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 +593,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
|
||||
if (reverse)
|
||||
if (Reverse)
|
||||
{
|
||||
movementAngle = MathUtils.WrapAngleTwoPi(movementAngle - MathHelper.Pi);
|
||||
}
|
||||
@@ -651,29 +652,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 +691,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 +723,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 +826,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:
|
||||
|
||||
+18
-265
@@ -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)
|
||||
{
|
||||
@@ -652,9 +651,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 +991,7 @@ namespace Barotrauma
|
||||
{
|
||||
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
|
||||
}
|
||||
else
|
||||
else if (character.FollowCursor)
|
||||
{
|
||||
RotateHead(head);
|
||||
}
|
||||
@@ -1145,245 +1149,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 +1283,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 +1360,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);
|
||||
@@ -1876,23 +1641,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)
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace Barotrauma
|
||||
private bool simplePhysicsEnabled;
|
||||
|
||||
public Character Character => character;
|
||||
protected Character character;
|
||||
protected readonly Character character;
|
||||
|
||||
protected float strongestImpact;
|
||||
|
||||
@@ -385,15 +385,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 +431,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 +448,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
AfflictionHusk.AttachHuskAppendage(character, matchingAffliction, huskAppendage, ragdoll: this);
|
||||
AfflictionHusk.AttachHuskAppendage(character, matchingAffliction, huskedSpeciesName: character.SpeciesName, huskAppendage, ragdoll: this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,7 +474,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 +516,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);
|
||||
}
|
||||
@@ -529,10 +525,11 @@ namespace Barotrauma
|
||||
protected void CreateLimbs()
|
||||
{
|
||||
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 +546,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 +574,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;
|
||||
}
|
||||
@@ -683,8 +680,7 @@ namespace Barotrauma
|
||||
}
|
||||
LimbJoints = newJoints;
|
||||
}
|
||||
|
||||
SubtractMass(limb);
|
||||
|
||||
limb.Remove();
|
||||
foreach (LimbJoint limbJoint in attachedJoints)
|
||||
{
|
||||
@@ -1400,7 +1396,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)
|
||||
{
|
||||
@@ -1910,7 +1911,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider.SetTransform(simPosition, Collider.Rotation);
|
||||
Collider.SetTransformIgnoreContacts(simPosition, Collider.Rotation);
|
||||
}
|
||||
|
||||
if (!MathUtils.NearlyEqual(limbMoveAmount, Vector2.Zero))
|
||||
@@ -2009,7 +2010,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
limb.body.SetTransform(movePos, rotation);
|
||||
limb.body.SetTransformIgnoreContacts(movePos, rotation);
|
||||
limb.PullJointWorldAnchorB = limb.PullJointWorldAnchorA;
|
||||
limb.PullJointEnabled = false;
|
||||
}
|
||||
@@ -2113,26 +2114,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;
|
||||
|
||||
Reference in New Issue
Block a user