v1.4.4.1 (Blood in the Water Update)
This commit is contained in:
@@ -32,6 +32,48 @@ namespace Barotrauma
|
||||
public abstract GroundedMovementParams RunParams { get; set; }
|
||||
public abstract SwimParams SwimSlowParams { get; set; }
|
||||
public abstract SwimParams SwimFastParams { get; set; }
|
||||
|
||||
protected class AnimSwap
|
||||
{
|
||||
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 AnimSwap(AnimationParams temporaryAnimation, float priority)
|
||||
{
|
||||
AnimationType = temporaryAnimation.AnimationType;
|
||||
TemporaryAnimation = temporaryAnimation;
|
||||
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>();
|
||||
protected readonly HashSet<AnimationType> expiredAnimations = new HashSet<AnimationType>();
|
||||
|
||||
public AnimationParams CurrentAnimationParams
|
||||
{
|
||||
@@ -87,7 +129,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public bool CanWalk => RagdollParams.CanWalk;
|
||||
public bool IsMovingBackwards => !InWater && Math.Sign(targetMovement.X) == -Math.Sign(Dir) && CurrentAnimationParams is not FishGroundedParams { Flip: false };
|
||||
public bool IsMovingBackwards =>
|
||||
!InWater &&
|
||||
Math.Sign(targetMovement.X) == -Math.Sign(Dir) &&
|
||||
CurrentAnimationParams is not FishGroundedParams { Flip: false } &&
|
||||
Anim != Animation.Climbing;
|
||||
|
||||
// TODO: define death anim duration in XML
|
||||
protected float deathAnimTimer, deathAnimDuration = 5.0f;
|
||||
@@ -177,8 +223,14 @@ namespace Barotrauma
|
||||
public float WalkPos { get; protected set; }
|
||||
|
||||
public AnimController(Character character, string seed, RagdollParams ragdollParams = null) : base(character, seed, ragdollParams) { }
|
||||
|
||||
public void UpdateAnimations(float deltaTime)
|
||||
{
|
||||
UpdateTemporaryAnimations(deltaTime);
|
||||
UpdateAnim(deltaTime);
|
||||
}
|
||||
|
||||
public abstract void UpdateAnim(float deltaTime);
|
||||
protected abstract void UpdateAnim(float deltaTime);
|
||||
|
||||
public abstract void DragCharacter(Character target, float deltaTime);
|
||||
|
||||
@@ -253,23 +305,26 @@ namespace Barotrauma
|
||||
switch (type)
|
||||
{
|
||||
case AnimationType.Walk:
|
||||
return WalkParams;
|
||||
return CanWalk ? WalkParams : null;
|
||||
case AnimationType.Run:
|
||||
return RunParams;
|
||||
return CanWalk ? RunParams : null;
|
||||
case AnimationType.Crouch:
|
||||
if (this is HumanoidAnimController humanAnimController)
|
||||
{
|
||||
return humanAnimController.HumanCrouchParams;
|
||||
}
|
||||
throw new NotImplementedException(type.ToString());
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Animation params of type {type} not implemented for non-humanoids!");
|
||||
return null;
|
||||
}
|
||||
case AnimationType.SwimSlow:
|
||||
return SwimSlowParams;
|
||||
case AnimationType.SwimFast:
|
||||
return SwimFastParams;
|
||||
case AnimationType.NotDefined:
|
||||
return null;
|
||||
default:
|
||||
throw new NotImplementedException(type.ToString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +431,7 @@ namespace Barotrauma
|
||||
private Direction previousDirection;
|
||||
private readonly Vector2[] transformedHandlePos = new Vector2[2];
|
||||
//TODO: refactor this method, it's way too convoluted
|
||||
public void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimMelee = false)
|
||||
public void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 itemPos, bool aim, float holdAngle, float itemAngleRelativeToHoldAngle = 0.0f, bool aimMelee = false, Vector2? targetPos = null)
|
||||
{
|
||||
aimingMelee = aimMelee;
|
||||
if (character.Stun > 0.0f || character.IsIncapacitated)
|
||||
@@ -385,22 +440,20 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//calculate the handle positions
|
||||
Matrix itemTransfrom = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
transformedHandlePos[0] = Vector2.Transform(handlePos[0], itemTransfrom);
|
||||
transformedHandlePos[1] = Vector2.Transform(handlePos[1], itemTransfrom);
|
||||
Matrix itemTransform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
transformedHandlePos[0] = Vector2.Transform(handlePos[0], itemTransform);
|
||||
transformedHandlePos[1] = Vector2.Transform(handlePos[1], itemTransform);
|
||||
|
||||
Limb torso = GetLimb(LimbType.Torso) ?? MainLimb;
|
||||
Limb leftHand = GetLimb(LimbType.LeftHand);
|
||||
Limb rightHand = GetLimb(LimbType.RightHand);
|
||||
|
||||
Vector2 itemPos = aim ? aimPos : holdPos;
|
||||
|
||||
var controller = character.SelectedItem?.GetComponent<Controller>();
|
||||
bool usingController = controller != null && !controller.AllowAiming;
|
||||
bool usingController = controller is { AllowAiming: false };
|
||||
if (!usingController)
|
||||
{
|
||||
controller = character.SelectedSecondaryItem?.GetComponent<Controller>();
|
||||
usingController = controller != null && !controller.AllowAiming;
|
||||
usingController = controller is { AllowAiming: false };
|
||||
}
|
||||
bool isClimbing = character.IsClimbing && Math.Abs(character.AnimController.TargetMovement.Y) > 0.01f;
|
||||
float itemAngle;
|
||||
@@ -408,15 +461,17 @@ namespace Barotrauma
|
||||
float torsoRotation = torso.Rotation;
|
||||
|
||||
Item rightHandItem = character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand);
|
||||
bool equippedInRightHand = rightHandItem == item && rightHand != null && !rightHand.IsSevered;
|
||||
bool equippedInRightHand = rightHandItem == item && rightHand is { IsSevered: false };
|
||||
Item leftHandItem = character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand);
|
||||
bool equippedInLefthand = leftHandItem == item && leftHand != null && !leftHand.IsSevered;
|
||||
bool equippedInLeftHand = leftHandItem == item && leftHand is { IsSevered: false };
|
||||
if (aim && !isClimbing && !usingController && character.Stun <= 0.0f && itemPos != Vector2.Zero && !character.IsIncapacitated)
|
||||
{
|
||||
Vector2 mousePos = ConvertUnits.ToSimUnits(character.SmoothedCursorPosition);
|
||||
Vector2 diff = holdable.Aimable ?
|
||||
(mousePos - AimSourceSimPos) * Dir :
|
||||
targetPos ??= ConvertUnits.ToSimUnits(character.SmoothedCursorPosition);
|
||||
|
||||
Vector2 diff = holdable.Aimable ?
|
||||
(targetPos.Value - AimSourceSimPos) * Dir :
|
||||
MathUtils.RotatePoint(Vector2.UnitX, torsoRotation);
|
||||
|
||||
holdAngle = MathUtils.VectorToAngle(new Vector2(diff.X, diff.Y * Dir)) - torsoRotation * Dir;
|
||||
holdAngle += GetAimWobble(rightHand, leftHand, item);
|
||||
itemAngle = torsoRotation + holdAngle * Dir;
|
||||
@@ -424,7 +479,7 @@ namespace Barotrauma
|
||||
if (holdable.ControlPose)
|
||||
{
|
||||
//if holding two items that should control the characters' pose, let the item in the right hand do it
|
||||
bool anotherItemControlsPose = equippedInLefthand && rightHandItem != item && (rightHandItem?.GetComponent<Holdable>()?.ControlPose ?? false);
|
||||
bool anotherItemControlsPose = equippedInLeftHand && rightHandItem != item && (rightHandItem?.GetComponent<Holdable>()?.ControlPose ?? false);
|
||||
if (!anotherItemControlsPose && TargetMovement == Vector2.Zero && inWater)
|
||||
{
|
||||
torso.body.AngularVelocity -= torso.body.AngularVelocity * 0.1f;
|
||||
@@ -441,7 +496,7 @@ namespace Barotrauma
|
||||
{
|
||||
itemAngle = rightHand.Rotation + holdAngle * Dir;
|
||||
}
|
||||
else if (equippedInLefthand)
|
||||
else if (equippedInLeftHand)
|
||||
{
|
||||
itemAngle = leftHand.Rotation + holdAngle * Dir;
|
||||
}
|
||||
@@ -465,7 +520,7 @@ namespace Barotrauma
|
||||
transformedHoldPos = rightHand.PullJointWorldAnchorA - transformedHandlePos[0];
|
||||
itemAngle = rightHand.Rotation + (holdAngle - rightHand.Params.GetSpriteOrientation() + MathHelper.PiOver2) * Dir;
|
||||
}
|
||||
else if (equippedInLefthand)
|
||||
else if (equippedInLeftHand)
|
||||
{
|
||||
transformedHoldPos = leftHand.PullJointWorldAnchorA - transformedHandlePos[1];
|
||||
itemAngle = leftHand.Rotation + (holdAngle - leftHand.Params.GetSpriteOrientation() + MathHelper.PiOver2) * Dir;
|
||||
@@ -478,7 +533,7 @@ namespace Barotrauma
|
||||
transformedHoldPos = rightShoulder.WorldAnchorA;
|
||||
rightHand.Disabled = true;
|
||||
}
|
||||
if (equippedInLefthand)
|
||||
if (equippedInLeftHand)
|
||||
{
|
||||
if (leftShoulder == null) { return; }
|
||||
transformedHoldPos = leftShoulder.WorldAnchorA;
|
||||
@@ -803,5 +858,260 @@ namespace Barotrauma
|
||||
public void StopUsingItem() => StopAnimation(Animation.UsingItem);
|
||||
|
||||
public void StopClimbing() => StopAnimation(Animation.Climbing);
|
||||
|
||||
private readonly Dictionary<AnimationType, AnimationParams> defaultAnimations = new Dictionary<AnimationType, AnimationParams>();
|
||||
|
||||
/// <summary>
|
||||
/// Loads an animation (variation) that automatically resets in 0.1s, unless triggered again.
|
||||
/// Meant e.g. for triggering animations in status effects, without having to worry about resetting them.
|
||||
/// </summary>
|
||||
public bool TryLoadTemporaryAnimation(StatusEffect.AnimLoadInfo animLoadInfo, bool throwErrors)
|
||||
{
|
||||
AnimationType animType = animLoadInfo.Type;
|
||||
if (tempAnimations.TryGetValue(animType, out AnimSwap animSwap))
|
||||
{
|
||||
if (animLoadInfo.File.TryGet(out string fileName) && animSwap.TemporaryAnimation.FileNameWithoutExtension.Equals(fileName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Already loaded, keep active
|
||||
animSwap.IsActive = true;
|
||||
return true;
|
||||
}
|
||||
else if (animLoadInfo.File.TryGet(out ContentPath contentPath) && animSwap.TemporaryAnimation.Path == contentPath)
|
||||
{
|
||||
// Already loaded, keep active
|
||||
animSwap.IsActive = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (animSwap.Priority >= animLoadInfo.Priority)
|
||||
{
|
||||
// If the priority of the current animation is higher than the new animation, just return and do nothing.
|
||||
// Returning false would tell the status effect to not try again, which is not what we want here, which is why we fake a bit with the return value.
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Override any previous animations of the same type.
|
||||
tempAnimations.Remove(animType);
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimationParams defaultAnimation = GetAnimationParamsFromType(animType);
|
||||
if (defaultAnimation == null) { return false; }
|
||||
if (!TryLoadAnimation(animType, animLoadInfo.File, out AnimationParams tempParams, throwErrors)) { return false; }
|
||||
// Store the default animation, if not yet stored. There should always be just one of the same type.
|
||||
defaultAnimations.TryAdd(animType, defaultAnimation);
|
||||
tempAnimations.Add(animType, new AnimSwap(tempParams, animLoadInfo.Priority));
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateTemporaryAnimations(float deltaTime)
|
||||
{
|
||||
if (tempAnimations.None()) { return; }
|
||||
foreach ((AnimationType animationType, AnimSwap animSwap) in tempAnimations)
|
||||
{
|
||||
if (!animSwap.IsActive)
|
||||
{
|
||||
if (defaultAnimations.TryGetValue(animSwap.AnimationType, out AnimationParams defaultAnimation))
|
||||
{
|
||||
TrySwapAnimParams(defaultAnimation);
|
||||
expiredAnimations.Add(animationType);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"[AnimController] Failed to find the default animation parameters of type {animSwap.AnimationType}. Cannot swap back the default animations!");
|
||||
tempAnimations.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (AnimationType anim in expiredAnimations)
|
||||
{
|
||||
tempAnimations.Remove(anim);
|
||||
}
|
||||
expiredAnimations.Clear();
|
||||
foreach (AnimSwap animSwap in tempAnimations.Values)
|
||||
{
|
||||
animSwap.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads animations. Non-permanent (= resets on load).
|
||||
/// </summary>
|
||||
public bool TryLoadAnimation(AnimationType animationType, Either<string, ContentPath> file, out AnimationParams animParams, bool throwErrors)
|
||||
{
|
||||
animParams = null;
|
||||
if (character.IsHumanoid && this is HumanoidAnimController humanAnimController)
|
||||
{
|
||||
switch (animationType)
|
||||
{
|
||||
case AnimationType.Walk:
|
||||
humanAnimController.WalkParams = HumanWalkParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = humanAnimController.WalkParams;
|
||||
break;
|
||||
case AnimationType.Run:
|
||||
humanAnimController.RunParams = HumanRunParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = humanAnimController.RunParams;
|
||||
break;
|
||||
case AnimationType.Crouch:
|
||||
humanAnimController.HumanCrouchParams = HumanCrouchParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = humanAnimController.HumanCrouchParams;
|
||||
break;
|
||||
case AnimationType.SwimSlow:
|
||||
humanAnimController.SwimSlowParams = HumanSwimSlowParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = humanAnimController.SwimSlowParams;
|
||||
break;
|
||||
case AnimationType.SwimFast:
|
||||
humanAnimController.SwimFastParams = HumanSwimFastParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = humanAnimController.SwimFastParams;
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"[AnimController] Animation of type {animationType} not implemented!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (animationType)
|
||||
{
|
||||
case AnimationType.Walk:
|
||||
if (CanWalk)
|
||||
{
|
||||
character.AnimController.WalkParams = FishWalkParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = character.AnimController.WalkParams;
|
||||
}
|
||||
break;
|
||||
case AnimationType.Run:
|
||||
if (CanWalk)
|
||||
{
|
||||
character.AnimController.RunParams = FishRunParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = character.AnimController.RunParams;
|
||||
}
|
||||
break;
|
||||
case AnimationType.SwimSlow:
|
||||
character.AnimController.SwimSlowParams = FishSwimSlowParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = character.AnimController.SwimSlowParams;
|
||||
break;
|
||||
case AnimationType.SwimFast:
|
||||
character.AnimController.SwimFastParams = FishSwimFastParams.GetAnimParams(character, file, throwErrors);
|
||||
animParams = character.AnimController.SwimFastParams;
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"[AnimController] Animation of type {animationType} not implemented!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool success = animParams != null;
|
||||
if (!file.TryGet(out string fileName))
|
||||
{
|
||||
if (file.TryGet(out ContentPath contentPath))
|
||||
{
|
||||
fileName = contentPath.Value;
|
||||
if (success)
|
||||
{
|
||||
success = contentPath == animParams.Path;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
success = animParams.FileNameWithoutExtension.Equals(fileName, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
DebugConsole.NewMessage($"Animation {fileName} successfully loaded for {character.DisplayName}", Color.LightGreen, debugOnly: true);
|
||||
}
|
||||
else if (throwErrors)
|
||||
{
|
||||
DebugConsole.ThrowError($"Animation {fileName} for {character.DisplayName} could not be loaded!");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simply swaps existing animation parameters as current parameters.
|
||||
/// </summary>
|
||||
protected bool TrySwapAnimParams(AnimationParams newParams)
|
||||
{
|
||||
AnimationType animationType = newParams.AnimationType;
|
||||
if (character.IsHumanoid && this is HumanoidAnimController humanAnimController)
|
||||
{
|
||||
switch (animationType)
|
||||
{
|
||||
case AnimationType.Walk:
|
||||
if (newParams is HumanWalkParams newWalkParams)
|
||||
{
|
||||
humanAnimController.WalkParams = newWalkParams;
|
||||
}
|
||||
return true;
|
||||
case AnimationType.Run:
|
||||
if (newParams is HumanRunParams newRunParams)
|
||||
{
|
||||
humanAnimController.HumanRunParams = newRunParams;
|
||||
}
|
||||
break;
|
||||
case AnimationType.Crouch:
|
||||
if (newParams is HumanCrouchParams newCrouchParams)
|
||||
{
|
||||
humanAnimController.HumanCrouchParams = newCrouchParams;
|
||||
}
|
||||
return true;
|
||||
case AnimationType.SwimSlow:
|
||||
if (newParams is HumanSwimSlowParams newSwimSlowParams)
|
||||
{
|
||||
humanAnimController.HumanSwimSlowParams = newSwimSlowParams;
|
||||
}
|
||||
return true;
|
||||
case AnimationType.SwimFast:
|
||||
if (newParams is HumanSwimFastParams newSwimFastParams)
|
||||
{
|
||||
humanAnimController.HumanSwimFastParams = newSwimFastParams;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
DebugConsole.ThrowError($"[AnimController] Animation of type {animationType} not implemented!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (animationType)
|
||||
{
|
||||
case AnimationType.Walk:
|
||||
if (newParams is FishWalkParams walkParams)
|
||||
{
|
||||
character.AnimController.WalkParams = walkParams;
|
||||
}
|
||||
return true;
|
||||
case AnimationType.Run:
|
||||
if (newParams is FishRunParams runParams)
|
||||
{
|
||||
character.AnimController.RunParams = runParams;
|
||||
}
|
||||
return true;
|
||||
case AnimationType.SwimSlow:
|
||||
if (newParams is FishSwimSlowParams swimSlowParams)
|
||||
{
|
||||
character.AnimController.SwimSlowParams = swimSlowParams;
|
||||
}
|
||||
return true;
|
||||
case AnimationType.SwimFast:
|
||||
if (newParams is FishSwimFastParams swimFastParams)
|
||||
{
|
||||
character.AnimController.SwimFastParams = swimFastParams;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
DebugConsole.ThrowError($"[AnimController] Animation of type {animationType} not implemented!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-16
@@ -22,11 +22,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (_ragdollParams == null)
|
||||
{
|
||||
_ragdollParams = FishRagdollParams.GetDefaultRagdollParams(character.SpeciesName);
|
||||
if (!character.VariantOf.IsEmpty)
|
||||
{
|
||||
_ragdollParams.ApplyVariantScale(character.Params.VariantFile);
|
||||
}
|
||||
_ragdollParams = FishRagdollParams.GetDefaultRagdollParams(character);
|
||||
}
|
||||
return _ragdollParams;
|
||||
}
|
||||
@@ -133,7 +129,7 @@ namespace Barotrauma
|
||||
|
||||
public FishAnimController(Character character, string seed, FishRagdollParams ragdollParams = null) : base(character, seed, ragdollParams) { }
|
||||
|
||||
public override void UpdateAnim(float deltaTime)
|
||||
protected override void UpdateAnim(float deltaTime)
|
||||
{
|
||||
//wait a bit for the ragdoll to "settle" (for joints to force the limbs to appropriate positions) before starting to animate
|
||||
if (Timing.TotalTime - character.SpawnTime < 0.1f) { return; }
|
||||
@@ -145,7 +141,7 @@ namespace Barotrauma
|
||||
}
|
||||
var mainLimb = MainLimb;
|
||||
|
||||
levitatingCollider = !IsHanging;
|
||||
levitatingCollider = !IsHangingWithRope;
|
||||
|
||||
if (!character.CanMove)
|
||||
{
|
||||
@@ -1011,15 +1007,7 @@ namespace Barotrauma
|
||||
{
|
||||
//make sure the angle "has the same number of revolutions" as the reference limb
|
||||
//(e.g. we don't want to rotate the legs to 0 if the torso is at 360, because that'd blow up the hip joints)
|
||||
while (referenceLimb.Rotation - angle > MathHelper.TwoPi)
|
||||
{
|
||||
angle += MathHelper.TwoPi;
|
||||
}
|
||||
while (referenceLimb.Rotation - angle < -MathHelper.TwoPi)
|
||||
{
|
||||
angle -= MathHelper.TwoPi;
|
||||
}
|
||||
|
||||
angle = referenceLimb.body.WrapAngleToSameNumberOfRevolutions(angle);
|
||||
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
|
||||
}
|
||||
|
||||
|
||||
+42
-9
@@ -10,7 +10,7 @@ namespace Barotrauma
|
||||
{
|
||||
class HumanoidAnimController : AnimController
|
||||
{
|
||||
private const float SteepestWalkableSlopeAngleDegrees = 50f;
|
||||
private const float SteepestWalkableSlopeAngleDegrees = 55f;
|
||||
private const float SlowlyWalkableSlopeAngleDegrees = 30f;
|
||||
|
||||
private static readonly float SteepestWalkableSlopeNormalX =
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (_ragdollParams == null)
|
||||
{
|
||||
_ragdollParams = RagdollParams.GetDefaultRagdollParams<HumanRagdollParams>(character.SpeciesName);
|
||||
_ragdollParams = HumanRagdollParams.GetDefaultRagdollParams(character);
|
||||
}
|
||||
return _ragdollParams;
|
||||
}
|
||||
@@ -248,12 +248,12 @@ namespace Barotrauma
|
||||
GetLimb(footType).PullJointLocalAnchorA);
|
||||
}
|
||||
|
||||
public override void UpdateAnim(float deltaTime)
|
||||
protected override void UpdateAnim(float deltaTime)
|
||||
{
|
||||
if (Frozen) { return; }
|
||||
if (MainLimb == null) { return; }
|
||||
|
||||
levitatingCollider = !IsHanging;
|
||||
levitatingCollider = !IsHangingWithRope;
|
||||
if (onGround && character.CanMove)
|
||||
{
|
||||
if ((character.SelectedItem?.GetComponent<Controller>()?.ControlCharacterPose ?? false) ||
|
||||
@@ -396,7 +396,9 @@ namespace Barotrauma
|
||||
if (SimplePhysicsEnabled)
|
||||
{
|
||||
UpdateStandingSimple();
|
||||
IsHanging = false;
|
||||
StopHangingWithRope();
|
||||
StopHoldingToRope();
|
||||
StopGettingDraggedWithRope();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -490,7 +492,21 @@ namespace Barotrauma
|
||||
aiming = false;
|
||||
wasAimingMelee = aimingMelee;
|
||||
aimingMelee = false;
|
||||
IsHanging = IsHanging && character.IsRagdolled;
|
||||
if (!shouldHangWithRope)
|
||||
{
|
||||
StopHangingWithRope();
|
||||
}
|
||||
if (!shouldHoldToRope)
|
||||
{
|
||||
StopHoldingToRope();
|
||||
}
|
||||
if (!shouldBeDraggedWithRope)
|
||||
{
|
||||
StopGettingDraggedWithRope();
|
||||
}
|
||||
shouldHoldToRope = false;
|
||||
shouldHangWithRope = false;
|
||||
shouldBeDraggedWithRope = false;
|
||||
}
|
||||
|
||||
void UpdateStanding()
|
||||
@@ -686,6 +702,16 @@ namespace Barotrauma
|
||||
|
||||
if (!onGround)
|
||||
{
|
||||
const float MaxFootVelocityDiff = 5.0f;
|
||||
const float MaxFootVelocityDiffSqr = MaxFootVelocityDiff * MaxFootVelocityDiff;
|
||||
//if the feet have a significantly different velocity from the main limb, try moving them back to a neutral pose below the torso
|
||||
//this can happen e.g. when jumping over an obstacle: the feet can have a large upwards velocity during the walk/run animation,
|
||||
//and just "letting go of the animations" would let them keep moving upwards, twisting the character to a weird pose
|
||||
if ((leftFoot != null && (MainLimb.LinearVelocity - leftFoot.LinearVelocity).LengthSquared() > MaxFootVelocityDiffSqr) ||
|
||||
(rightFoot != null && (MainLimb.LinearVelocity - rightFoot.LinearVelocity).LengthSquared() > MaxFootVelocityDiffSqr))
|
||||
{
|
||||
UpdateFallingProne(10.0f, moveHands: false, moveTorso: false, moveLegs: true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -786,7 +812,12 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
footPos = new Vector2(colliderPos.X + stepSize.X * i * 0.2f, colliderPos.Y - 0.1f);
|
||||
float footPosX = stepSize.X * i * 0.2f;
|
||||
if (CurrentGroundedParams.StepSizeWhenStanding != Vector2.Zero)
|
||||
{
|
||||
footPosX = Math.Sign(stepSize.X) * CurrentGroundedParams.StepSizeWhenStanding.X * i;
|
||||
}
|
||||
footPos = new Vector2(colliderPos.X + footPosX, colliderPos.Y - 0.1f);
|
||||
}
|
||||
if (Stairs == null && !onSlopeThatMakesSlow)
|
||||
{
|
||||
@@ -1519,6 +1550,8 @@ namespace Barotrauma
|
||||
{
|
||||
torso.body.ApplyLinearImpulse(new Vector2(0, -20f), maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
targetTorso.body.ApplyLinearImpulse(new Vector2(0, -20f), maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
//the pumping animation can sometimes cause impact damage, prevent that by briefly disabling it
|
||||
target.DisableImpactDamageTimer = 0.15f;
|
||||
cprPumpTimer = 0;
|
||||
|
||||
if (skill < CPRSettings.Active.DamageSkillThreshold)
|
||||
@@ -1727,7 +1760,7 @@ namespace Barotrauma
|
||||
if (targetLimb.type == LimbType.Torso || targetLimb == target.AnimController.MainLimb)
|
||||
{
|
||||
pullLimb.PullJointMaxForce = 5000.0f;
|
||||
if (!character.HasAbilityFlag(AbilityFlags.MoveNormallyWhileDragging))
|
||||
if (!character.CanRunWhileDragging())
|
||||
{
|
||||
targetMovement *= MathHelper.Clamp(Mass / target.Mass, 0.5f, 1.0f);
|
||||
}
|
||||
@@ -1811,7 +1844,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//limit movement if moving away from the target
|
||||
if (!character.HasAbilityFlag(AbilityFlags.MoveNormallyWhileDragging) && Vector2.Dot(target.WorldPosition - WorldPosition, targetMovement) < 0)
|
||||
if (!character.CanRunWhileDragging() && Vector2.Dot(target.WorldPosition - WorldPosition, targetMovement) < 0)
|
||||
{
|
||||
targetMovement *= MathHelper.Clamp(1.5f - dist, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ namespace Barotrauma
|
||||
public bool Frozen
|
||||
{
|
||||
get { return frozen; }
|
||||
set
|
||||
{
|
||||
set
|
||||
{
|
||||
if (frozen == value) return;
|
||||
|
||||
frozen = value;
|
||||
@@ -81,7 +81,7 @@ namespace Barotrauma
|
||||
Collider.FarseerBody.IgnoreGravity = frozen;
|
||||
|
||||
//Collider.PhysEnabled = !frozen;
|
||||
if (frozen && MainLimb != null) MainLimb.PullJointWorldAnchorB = MainLimb.SimPosition;
|
||||
if (frozen && MainLimb != null) { MainLimb.PullJointWorldAnchorB = MainLimb.SimPosition; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,12 +109,12 @@ 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 float floorY, standOnFloorY;
|
||||
protected Fixture floorFixture;
|
||||
protected Vector2 floorNormal = Vector2.UnitY;
|
||||
protected float surfaceY;
|
||||
|
||||
|
||||
protected bool inWater, headInWater;
|
||||
protected bool onGround;
|
||||
public bool OnGround => onGround;
|
||||
@@ -128,7 +128,7 @@ namespace Barotrauma
|
||||
public float ColliderHeightFromFloor => ConvertUnits.ToSimUnits(RagdollParams.ColliderHeightFromFloor) * RagdollParams.JointScale;
|
||||
|
||||
public Structure Stairs;
|
||||
|
||||
|
||||
protected Direction dir;
|
||||
|
||||
public Direction TargetDir;
|
||||
@@ -153,7 +153,7 @@ namespace Barotrauma
|
||||
collider = null;
|
||||
try
|
||||
{
|
||||
collider = this.collider?[index];
|
||||
collider = this.collider?[index];
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
@@ -322,7 +322,7 @@ namespace Barotrauma
|
||||
impactTolerance = RagdollParams.ImpactTolerance;
|
||||
if (character.Params.VariantFile != null)
|
||||
{
|
||||
float? tolerance = character.Params.VariantFile.Root.GetChildElement("ragdoll")?.GetAttributeFloat("impacttolerance", impactTolerance.Value);
|
||||
float? tolerance = character.Params.VariantFile.GetRootExcludingOverride().GetChildElement("ragdoll")?.GetAttributeFloat("impacttolerance", impactTolerance.Value);
|
||||
if (tolerance.HasValue)
|
||||
{
|
||||
impactTolerance = tolerance;
|
||||
@@ -334,7 +334,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public bool Draggable => RagdollParams.Draggable;
|
||||
public bool CanEnterSubmarine => RagdollParams.CanEnterSubmarine;
|
||||
|
||||
public CanEnterSubmarine CanEnterSubmarine => RagdollParams.CanEnterSubmarine;
|
||||
|
||||
public float Dir => dir == Direction.Left ? -1.0f : 1.0f;
|
||||
|
||||
@@ -384,6 +385,10 @@ namespace Barotrauma
|
||||
if (ragdollParams != null)
|
||||
{
|
||||
RagdollParams = ragdollParams;
|
||||
if (!character.VariantOf.IsEmpty)
|
||||
{
|
||||
RagdollParams.TryApplyVariantScale(character.Params.VariantFile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -696,21 +701,34 @@ namespace Barotrauma
|
||||
|
||||
public bool OnLimbCollision(Fixture f1, Fixture f2, Contact contact)
|
||||
{
|
||||
if (f2.Body.UserData is Submarine && character.Submarine == (Submarine)f2.Body.UserData) { return false; }
|
||||
if (f2.UserData is Hull && character.Submarine != null) { return false; }
|
||||
if (f2.Body.UserData is Submarine submarine && character.Submarine == submarine) { return false; }
|
||||
if (f2.UserData is Hull)
|
||||
{
|
||||
if (character.Submarine != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (CanEnterSubmarine == CanEnterSubmarine.Partial)
|
||||
{
|
||||
//collider collides with hulls to prevent the character going fully inside the sub, limbs don't
|
||||
return
|
||||
f1.Body == Collider.FarseerBody ||
|
||||
(f1.Body.UserData is Limb limb && !limb.Params.CanEnterSubmarine);
|
||||
}
|
||||
}
|
||||
|
||||
//using the velocity of the limb would make the impact damage more realistic,
|
||||
//but would also make it harder to edit the animations because the forces/torques
|
||||
//would all have to be balanced in a way that prevents the character from doing
|
||||
//impact damage to itself
|
||||
Vector2 velocity = Collider.LinearVelocity;
|
||||
if (character.Submarine == null && f2.Body.UserData is Submarine)
|
||||
if (character.Submarine == null && f2.Body.UserData is Submarine sub)
|
||||
{
|
||||
velocity -= ((Submarine)f2.Body.UserData).Velocity;
|
||||
velocity -= sub.Velocity;
|
||||
}
|
||||
|
||||
//always collides with bodies other than structures
|
||||
if (!(f2.Body.UserData is Structure structure))
|
||||
if (f2.Body.UserData is not Structure structure)
|
||||
{
|
||||
if (!f2.IsSensor)
|
||||
{
|
||||
@@ -1021,7 +1039,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Ragdoll r in list)
|
||||
{
|
||||
r.Update(deltaTime, cam);
|
||||
r.UpdateRagdoll(deltaTime, cam);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,7 +1059,8 @@ namespace Barotrauma
|
||||
|
||||
if (newHull == currentHull) { return; }
|
||||
|
||||
if (!CanEnterSubmarine || (character.AIController != null && !character.AIController.CanEnterSubmarine))
|
||||
if (CanEnterSubmarine == CanEnterSubmarine.False ||
|
||||
(character.AIController != null && character.AIController.CanEnterSubmarine == CanEnterSubmarine.False))
|
||||
{
|
||||
//character is inside the sub even though it shouldn't be able to enter -> teleport it out
|
||||
|
||||
@@ -1066,6 +1085,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (CanEnterSubmarine != CanEnterSubmarine.True)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (setSubmarine)
|
||||
{
|
||||
//in -> out
|
||||
@@ -1075,13 +1099,13 @@ namespace Barotrauma
|
||||
if (Gap.FindAdjacent(Gap.GapList.Where(g => g.Submarine == currentHull.Submarine), findPos, 150.0f) != null) { return; }
|
||||
if (Limbs.Any(l => Gap.FindAdjacent(currentHull.ConnectedGaps, l.WorldPosition, ConvertUnits.ToDisplayUnits(l.body.GetSize().Combine())) != null)) { return; }
|
||||
character.MemLocalState?.Clear();
|
||||
Teleport(ConvertUnits.ToSimUnits(currentHull.Submarine.Position), currentHull.Submarine.Velocity, detachProjectiles: false);
|
||||
Teleport(ConvertUnits.ToSimUnits(currentHull.Submarine.Position), currentHull.Submarine.Velocity);
|
||||
}
|
||||
//out -> in
|
||||
else if (currentHull == null && newHull.Submarine != null)
|
||||
{
|
||||
character.MemLocalState?.Clear();
|
||||
Teleport(-ConvertUnits.ToSimUnits(newHull.Submarine.Position), -newHull.Submarine.Velocity, detachProjectiles: false);
|
||||
Teleport(-ConvertUnits.ToSimUnits(newHull.Submarine.Position), -newHull.Submarine.Velocity);
|
||||
}
|
||||
//from one sub to another
|
||||
else if (newHull != null && currentHull != null && newHull.Submarine != currentHull.Submarine)
|
||||
@@ -1089,7 +1113,7 @@ namespace Barotrauma
|
||||
character.MemLocalState?.Clear();
|
||||
Vector2 newSubPos = newHull.Submarine == null ? Vector2.Zero : newHull.Submarine.Position;
|
||||
Vector2 prevSubPos = currentHull.Submarine == null ? Vector2.Zero : currentHull.Submarine.Position;
|
||||
Teleport(ConvertUnits.ToSimUnits(prevSubPos - newSubPos), Vector2.Zero, detachProjectiles: false);
|
||||
Teleport(ConvertUnits.ToSimUnits(prevSubPos - newSubPos), Vector2.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,7 +1180,7 @@ namespace Barotrauma
|
||||
|
||||
character.DisableImpactDamageTimer = 0.25f;
|
||||
|
||||
SetPosition(Collider.SimPosition + moveAmount, detachProjectiles: detachProjectiles);
|
||||
SetPosition(Collider.SimPosition + moveAmount);
|
||||
character.CursorPosition += moveAmount;
|
||||
|
||||
Collider?.UpdateDrawPosition();
|
||||
@@ -1221,7 +1245,7 @@ namespace Barotrauma
|
||||
public bool forceStanding;
|
||||
public bool forceNotStanding;
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
public void UpdateRagdoll(float deltaTime, Camera cam)
|
||||
{
|
||||
if (!character.Enabled || character.Removed || Frozen || Invalid || Collider == null || Collider.Removed) { return; }
|
||||
|
||||
@@ -1389,7 +1413,8 @@ namespace Barotrauma
|
||||
if (floorNormal.Y is > 0f and < 1f
|
||||
&& Math.Sign(movement.X) == Math.Sign(floorNormal.X))
|
||||
{
|
||||
slopePull = Math.Abs(movement.X * floorNormal.X / floorNormal.Y) / LevitationSpeedMultiplier;
|
||||
float steepness = Math.Abs(floorNormal.X);
|
||||
slopePull = Math.Abs(movement.X * steepness) / LevitationSpeedMultiplier;
|
||||
}
|
||||
|
||||
if (Math.Abs(Collider.SimPosition.Y - targetY - slopePull) > 0.01f)
|
||||
@@ -1743,7 +1768,7 @@ namespace Barotrauma
|
||||
return closestFraction;
|
||||
}, rayStart, rayEnd, Physics.CollisionStairs | Physics.CollisionPlatform | Physics.CollisionWall | Physics.CollisionLevel);
|
||||
|
||||
if (standOnFloorFixture != null && !IsHanging)
|
||||
if (standOnFloorFixture != null && !IsHangingWithRope)
|
||||
{
|
||||
floorFixture = standOnFloorFixture;
|
||||
standOnFloorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * standOnFloorFraction;
|
||||
@@ -1845,7 +1870,7 @@ namespace Barotrauma
|
||||
return (surfaceY, ceilingY);
|
||||
}
|
||||
|
||||
public void SetPosition(Vector2 simPosition, bool lerp = false, bool ignorePlatforms = true, bool forceMainLimbToCollider = false, bool detachProjectiles = true)
|
||||
public void SetPosition(Vector2 simPosition, bool lerp = false, bool ignorePlatforms = true, bool forceMainLimbToCollider = false, bool moveLatchers = true)
|
||||
{
|
||||
if (!MathUtils.IsValid(simPosition))
|
||||
{
|
||||
@@ -1858,10 +1883,14 @@ namespace Barotrauma
|
||||
}
|
||||
if (MainLimb == null) { return; }
|
||||
|
||||
Vector2 limbMoveAmount = forceMainLimbToCollider ? simPosition - MainLimb.SimPosition : simPosition - Collider.SimPosition;
|
||||
|
||||
// A Work-around for an issue with teleporting the characters:
|
||||
// Detach every latcher when either one of the latchers or the target is teleported,
|
||||
// because otherwise all the characters are teleported to invalid positions.
|
||||
if (Character.AIController is EnemyAIController enemyAI && enemyAI.LatchOntoAI != null && enemyAI.LatchOntoAI.IsAttached)
|
||||
// because otherwise all the characters are teleported to invalid positions.
|
||||
const float ForceDeattachThreshold = 10.0f;
|
||||
if (limbMoveAmount.LengthSquared() > ForceDeattachThreshold * ForceDeattachThreshold &&
|
||||
Character.AIController is EnemyAIController enemyAI && enemyAI.LatchOntoAI != null && enemyAI.LatchOntoAI.IsAttached)
|
||||
{
|
||||
var target = enemyAI.LatchOntoAI.TargetCharacter;
|
||||
if (target != null)
|
||||
@@ -1874,7 +1903,6 @@ namespace Barotrauma
|
||||
Character.Latchers.ForEachMod(l => l?.DeattachFromBody(reset: true));
|
||||
Character.Latchers.Clear();
|
||||
|
||||
Vector2 limbMoveAmount = forceMainLimbToCollider ? simPosition - MainLimb.SimPosition : simPosition - Collider.SimPosition;
|
||||
if (lerp)
|
||||
{
|
||||
Collider.TargetPosition = simPosition;
|
||||
@@ -1896,15 +1924,62 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is attached to something with a rope.
|
||||
/// </summary>
|
||||
public bool IsHoldingToRope { get; private set; }
|
||||
protected bool shouldHoldToRope;
|
||||
|
||||
public bool IsHanging { get; protected set; }
|
||||
/// <summary>
|
||||
/// Is hanging to something with a rope, so that can reel towards it. Currently only possible in water.
|
||||
/// </summary>
|
||||
public bool IsHangingWithRope { get; private set; }
|
||||
protected bool shouldHangWithRope;
|
||||
|
||||
/// <summary>
|
||||
/// Has someone attached to the character with a rope?
|
||||
/// </summary>
|
||||
public bool IsDraggedWithRope { get; private set; }
|
||||
protected bool shouldBeDraggedWithRope;
|
||||
|
||||
public void Hang()
|
||||
public void HangWithRope()
|
||||
{
|
||||
shouldHangWithRope = true;
|
||||
IsHangingWithRope = true;
|
||||
ResetPullJoints();
|
||||
onGround = false;
|
||||
levitatingCollider = false;
|
||||
IsHanging = true;
|
||||
}
|
||||
|
||||
public void HoldToRope()
|
||||
{
|
||||
shouldHoldToRope = true;
|
||||
IsHoldingToRope = true;
|
||||
}
|
||||
|
||||
public void DragWithRope()
|
||||
{
|
||||
shouldBeDraggedWithRope = true;
|
||||
IsDraggedWithRope = true;
|
||||
}
|
||||
|
||||
protected void StopHangingWithRope()
|
||||
{
|
||||
shouldHangWithRope = false;
|
||||
IsHangingWithRope = false;
|
||||
}
|
||||
|
||||
protected void StopHoldingToRope()
|
||||
{
|
||||
shouldHoldToRope = false;
|
||||
IsHoldingToRope = false;
|
||||
}
|
||||
|
||||
protected void StopGettingDraggedWithRope()
|
||||
{
|
||||
shouldBeDraggedWithRope = false;
|
||||
IsDraggedWithRope = false;
|
||||
}
|
||||
|
||||
protected void TrySetLimbPosition(Limb limb, Vector2 original, Vector2 simPosition, float rotation, bool lerp = false, bool ignorePlatforms = true)
|
||||
|
||||
Reference in New Issue
Block a user