v1.4.4.1 (Blood in the Water Update)

This commit is contained in:
Regalis11
2024-04-24 18:09:05 +03:00
parent 89b91d1c3e
commit ff1b8951a7
397 changed files with 15250 additions and 6479 deletions
@@ -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;
}
}
}