diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs
index 723963e509..be307ce5af 100644
--- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs
+++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs
@@ -319,14 +319,24 @@ public void LockFlipping(float time = 0.2f)
protected void UpdateConstantTorque(float deltaTime)
{
+ if (character.IsIncapacitated) { return; }
+ if (character.Stun > 0.01f) { return; }
foreach (var limb in Limbs)
{
if (limb.IsSevered) { continue; }
- if (Math.Abs(limb.Params.ConstantTorque) > 0)
+ float angleToApply = limb.Params.ConstantAngle;
+ float torqueToApply = limb.Params.ConstantTorque;
+ float movementFactor = Math.Max(character.AnimController.Collider.LinearVelocity.Length() * 0.5f, 1);
+ if (CurrentAnimationParams.LimbConstantAnglesData.ContainsKey(limb.Params.ID))
{
- // 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);
+ var constantAngleData = CurrentAnimationParams.LimbConstantAnglesData[limb.Params.ID];
+
+ angleToApply = constantAngleData.ConstantAngle;
+ torqueToApply = constantAngleData.ConstantTorque;
+ }
+ if (torqueToApply > 0f)
+ {
+ limb.body.SmoothRotate(MainLimb.Rotation + MathHelper.ToRadians(angleToApply) * Dir, limb.Mass * torqueToApply * movementFactor, wrapAngle: true);
}
}
}
diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs
index 3a2562d48d..9efed3a00d 100644
--- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs
+++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/AnimationParams.cs
@@ -170,6 +170,29 @@ public float TorsoAngle
[Serialize(50.0f, IsPropertySaveable.Yes, description: "How much torque is used to rotate the torso to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
public float TorsoTorque { get; set; }
+ public struct LimbConstantAngleData
+ {
+ public float ConstantAngle { get; set; }
+ public float ConstantTorque { get; set; }
+
+ public LimbConstantAngleData(float constantAngle, float constantTorque)
+ {
+ ConstantAngle = constantAngle;
+ ConstantTorque = constantTorque;
+ }
+ }
+ ///
+ /// Key = limb id, value = LimbConstantAngleData struct with two properties: constant angle and constant torque
+ ///
+ public Dictionary LimbConstantAnglesData { get; set; } = new Dictionary();
+
+ [Serialize(null, IsPropertySaveable.Yes), Editable]
+ public string LimbConstantAngles
+ {
+ get => ParseLimbConstantAngles(LimbConstantAnglesData);
+ set => SetLimbConstantAngles(LimbConstantAnglesData, value);
+ }
+
[Header("Legs")]
[Serialize(25.0f, IsPropertySaveable.Yes, description: "How much torque is used to rotate the feet to the correct orientation."), Editable(MinValueFloat = 0, MaxValueFloat = 1000, ValueStep = 1)]
public float FootTorque { get; set; }
@@ -486,6 +509,12 @@ protected static string ParseFootAngles(Dictionary footAngles)
return string.Join(",", footAngles.Select(kv => kv.Key + ": " + kv.Value.ToString("G", CultureInfo.InvariantCulture)).ToArray());
}
+ protected static string ParseLimbConstantAngles(Dictionary limbAngles)
+ {
+ //convert to the format "id1:angle;torque,id2:angle;torque"
+ return string.Join(",", limbAngles.Select(kv => $"{kv.Key}: {kv.Value.ConstantAngle.ToString("G", CultureInfo.InvariantCulture)};" + $"{kv.Value.ConstantTorque.ToString("G", CultureInfo.InvariantCulture)}"));
+ }
+
protected static void SetFootAngles(Dictionary footAngles, string value)
{
footAngles.Clear();
@@ -509,6 +538,42 @@ protected static void SetFootAngles(Dictionary footAngles, string va
}
}
+ protected static void SetLimbConstantAngles(Dictionary limbAngles, string value)
+ {
+ limbAngles.Clear();
+ if (string.IsNullOrEmpty(value))
+ {
+ return;
+ }
+
+ string[] keyValuePairs = value.Split(',');
+ foreach (string joinedKvp in keyValuePairs)
+ {
+ string[] keyValuePair = joinedKvp.Split(':');
+ if (keyValuePair.Length != 2 ||
+ !int.TryParse(keyValuePair[0].Trim(), out int limbIndex))
+ {
+ DebugConsole.ThrowError("Failed to parse limb constant angles (" + value + ")");
+ continue;
+ }
+
+ string[] dataValues = keyValuePair[1].Split(';');
+ if (dataValues.Length != 2 ||
+ !float.TryParse(dataValues[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out float constantAngle) ||
+ !float.TryParse(dataValues[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out float constantTorque))
+ {
+ DebugConsole.ThrowError($"Failed to parse angle or torque for limb {limbIndex} ({keyValuePair[1]})");
+ continue;
+ }
+
+ limbAngles[limbIndex] = new LimbConstantAngleData
+ {
+ ConstantAngle = constantAngle,
+ ConstantTorque = constantTorque
+ };
+ }
+ }
+
public static Type GetParamTypeFromAnimType(AnimationType type, bool isHumanoid)
{
if (isHumanoid)