Merge branch 'dev' of https://github.com/Regalis11/Barotrauma.git into unstable-tests

This commit is contained in:
Evil Factory
2022-04-08 12:52:28 -03:00
990 changed files with 44338 additions and 38589 deletions
@@ -24,6 +24,8 @@ namespace Barotrauma
public bool IsAiming => wasAiming;
public bool IsAimingMelee => wasAimingMelee;
protected bool Aiming => aiming || aimingMelee;
public float ArmLength => upperArmLength + forearmLength;
public abstract GroundedMovementParams WalkParams { get; set; }
@@ -99,8 +101,7 @@ namespace Barotrauma
{
if (InWater || !CanWalk)
{
float avg = (SwimSlowParams.MovementSpeed + SwimFastParams.MovementSpeed) / 2.0f;
return TargetMovement.LengthSquared() > avg * avg;
return TargetMovement.LengthSquared() > MathUtils.Pow2(SwimSlowParams.MovementSpeed);
}
else
{
@@ -22,8 +22,9 @@ namespace Barotrauma
{
if (_ragdollParams == null)
{
_ragdollParams = FishRagdollParams.GetDefaultRagdollParams(character.VariantOf ?? character.SpeciesName);
if (character.VariantOf != null)
#warning TODO: this is kinda janky, this should probably be done better
_ragdollParams = FishRagdollParams.GetDefaultRagdollParams(character.VariantOf.IfEmpty(character.SpeciesName));
if (!character.VariantOf.IsEmpty)
{
_ragdollParams.ApplyVariantScale(character.Params.VariantFile);
}
@@ -192,7 +193,7 @@ namespace Barotrauma
strongestImpact = 0.0f;
}
if (aiming)
if (Aiming)
{
TargetMovement = TargetMovement.ClampLength(2);
}
@@ -232,7 +233,7 @@ namespace Barotrauma
//don't flip when simply physics is enabled
if (SimplePhysicsEnabled) { return; }
if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip) && !aiming)
if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip) && !Aiming)
{
if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
{
@@ -421,7 +422,7 @@ namespace Barotrauma
}
//only one limb left, the character is now full eaten
Entity.Spawner?.AddToRemoveQueue(target);
Entity.Spawner?.AddEntityToRemoveQueue(target);
if (Character.AIController is EnemyAIController enemyAi)
{
@@ -432,10 +433,10 @@ namespace Barotrauma
}
else //sever a random joint
{
target.AnimController.SeverLimbJoint(nonSeveredJoints.GetRandom());
target.AnimController.SeverLimbJoint(nonSeveredJoints.GetRandomUnsynced());
}
}
}
}
}
}
@@ -447,21 +448,18 @@ namespace Barotrauma
movement = TargetMovement;
bool isMoving = movement.LengthSquared() > 0.00001f;
var mainLimb = MainLimb;
if (isMoving)
float t = 0.5f;
if (isMoving && !SimplePhysicsEnabled && CurrentSwimParams.RotateTowardsMovement)
{
float t = 0.5f;
if (!SimplePhysicsEnabled && CurrentSwimParams.RotateTowardsMovement)
Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2);
float dot = Vector2.Dot(forward, Vector2.Normalize(movement));
if (dot < 0)
{
Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2);
float dot = Vector2.Dot(forward, Vector2.Normalize(movement));
if (dot < 0)
{
// Reduce the linear movement speed when not facing the movement direction
t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f);
}
// Reduce the linear movement speed when not facing the movement direction
t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f);
}
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t);
}
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t);
//limbs are disabled when simple physics is enabled, no need to move them
if (SimplePhysicsEnabled) { return; }
mainLimb.PullJointEnabled = true;
@@ -1016,24 +1014,29 @@ namespace Barotrauma
{
if (l.IsSevered) { continue; }
float rotation = l.body.Rotation;
if (l.DoesFlip)
{
if (RagdollParams.IsSpritesheetOrientationHorizontal)
{
//horizontally oriented sprites can be mirrored by rotating 180 deg and inverting the angle
rotation = -(l.body.Rotation + MathHelper.Pi);
}
else
{
//vertically oriented limbs can be mirrored by inverting the angle (neutral angle is straight upwards)
rotation = -l.body.Rotation;
}
}
TrySetLimbPosition(l,
centerOfMass,
new Vector2(centerOfMass.X - (l.SimPosition.X - centerOfMass.X), l.SimPosition.Y),
rotation,
lerp);
l.body.PositionSmoothingFactor = 0.8f;
if (!l.DoesFlip) { continue; }
if (RagdollParams.IsSpritesheetOrientationHorizontal)
{
//horizontally oriented sprites can be mirrored by rotating 180 deg and inverting the angle
l.body.SetTransform(l.SimPosition, -(l.body.Rotation + MathHelper.Pi));
}
else
{
//vertically oriented limbs can be mirrored by inverting the angle (neutral angle is straight upwards)
l.body.SetTransform(l.SimPosition, -l.body.Rotation);
}
}
if (character.SelectedCharacter != null && CanDrag(character.SelectedCharacter))
{
@@ -25,7 +25,7 @@ namespace Barotrauma
{
if (_ragdollParams == null)
{
_ragdollParams = RagdollParams.GetDefaultRagdollParams<HumanRagdollParams>(character.VariantOf ?? character.SpeciesName);
_ragdollParams = RagdollParams.GetDefaultRagdollParams<HumanRagdollParams>(character.SpeciesName);
}
return _ragdollParams;
}
@@ -178,6 +178,14 @@ namespace Barotrauma
else if (Crouching)
{
shoulderHeight -= 0.15f;
if (Crouching)
{
bool movingHorizontally = !MathUtils.NearlyEqual(TargetMovement.X, 0.0f);
if (!movingHorizontally)
{
shoulderHeight -= HumanCrouchParams.MoveDownAmountWhenStationary;
}
}
}
return Collider.SimPosition + new Vector2(
@@ -435,8 +443,6 @@ namespace Barotrauma
if (CurrentGroundedParams == null) { return; }
Vector2 handPos;
//if you're allergic to magic numbers, stop reading now
Limb leftFoot = GetLimb(LimbType.LeftFoot);
Limb rightFoot = GetLimb(LimbType.RightFoot);
Limb head = GetLimb(LimbType.Head);
@@ -591,16 +597,20 @@ namespace Barotrauma
{
float torsoAngle = TorsoAngle.Value;
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
if (Crouching && !movingHorizontally) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
if (Crouching && !movingHorizontally && !Aiming) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
torsoAngle -= herpesStrength / 150.0f;
torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque);
}
if (HeadAngle.HasValue)
if (!Aiming && CurrentGroundedParams.FixedHeadAngle && HeadAngle.HasValue)
{
float headAngle = HeadAngle.Value;
if (Crouching && !movingHorizontally) { headAngle -= HumanCrouchParams.ExtraHeadAngleWhenStationary; }
head.body.SmoothRotate(headAngle * Dir, CurrentGroundedParams.HeadTorque);
}
else
{
RotateHead(head);
}
if (!onGround)
{
@@ -807,48 +817,16 @@ namespace Barotrauma
Limb torso = GetLimb(LimbType.Torso);
if (head == null) { return; }
if (torso == null) { return; }
//check both hulls: the hull whose coordinate space the ragdoll is in, and the hull whose bounds the character's origin actually is inside
const float DisableMovementAboveSurfaceThreshold = 50.0f;
if (currentHull != null && character.CurrentHull != null)
{
float surfacePos = currentHull.Surface;
float surfacePos = GetSurfaceY();
float surfaceThreshold = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f);
//if the hull is almost full of water, check if there's a water-filled hull above it
//and use its water surface instead of the current hull's
if (currentHull.Rect.Y - currentHull.Surface < 5.0f)
{
GetSurfacePos(currentHull, ref surfacePos);
void GetSurfacePos(Hull hull, ref float prevSurfacePos)
{
if (prevSurfacePos > surfaceThreshold) { return; }
foreach (Gap gap in hull.ConnectedGaps)
{
if (gap.IsHorizontal || gap.Open <= 0.0f || gap.WorldPosition.Y < hull.WorldPosition.Y) { continue; }
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; }
//if the gap is above us and leads outside, there's no surface to limit the movement
if (!gap.IsRoomToRoom && gap.Position.Y > hull.Position.Y)
{
prevSurfacePos += 100000.0f;
return;
}
foreach (var linkedTo in gap.linkedTo)
{
if (linkedTo is Hull otherHull && otherHull != hull && otherHull != currentHull)
{
prevSurfacePos = Math.Max(surfacePos, otherHull.Surface);
GetSurfacePos(otherHull, ref prevSurfacePos);
break;
}
}
}
}
}
surfaceLimiter = Math.Max(1.0f, surfaceThreshold - surfacePos);
if (surfaceLimiter > 50.0f) { return; }
}
if (surfaceLimiter > DisableMovementAboveSurfaceThreshold) { return; }
}
Limb leftHand = GetLimb(LimbType.LeftHand);
Limb rightHand = GetLimb(LimbType.RightHand);
@@ -862,37 +840,36 @@ namespace Barotrauma
{
rotation += 360;
}
if (!character.IsRemotelyControlled && !aiming && Anim != Animation.UsingConstruction &&
!(character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false))
{
if (rotation > 20 && rotation < 170)
{
TargetDir = Direction.Left;
}
else if (rotation > 190 && rotation < 340)
{
TargetDir = Direction.Right;
}
}
float targetSpeed = TargetMovement.Length();
if (targetSpeed > 0.1f)
if (targetSpeed > 0.1f && !character.IsRemotelyControlled && !character.IsKeyDown(InputType.Aim))
{
if (!aiming)
if (Anim != Animation.UsingConstruction && !(character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false))
{
float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
if (rotation > 20 && rotation < 170)
{
TargetDir = Direction.Left;
}
else if (rotation > 190 && rotation < 340)
{
TargetDir = Direction.Right;
}
}
}
else
if (Aiming)
{
if (aiming)
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
if (diff.LengthSquared() > MathUtils.Pow2(0.4f))
{
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
float newRotation = MathUtils.VectorToAngle(diff);
float newRotation = MathHelper.WrapAngle(MathUtils.VectorToAngle(diff) - MathHelper.PiOver4 * Dir);
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
}
}
else if (targetSpeed > 0.1f)
{
float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
}
torso.body.MoveToPos(Collider.SimPosition + new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f, 5.0f);
@@ -906,13 +883,14 @@ namespace Barotrauma
{
torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.TorsoTorque);
}
if (HeadAngle.HasValue)
if (!Aiming && CurrentSwimParams.FixedHeadAngle && HeadAngle.HasValue)
{
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
}
else
{
head.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.HeadTorque);
RotateHead(head);
}
//dont try to move upwards if head is already out of water
@@ -935,7 +913,7 @@ namespace Barotrauma
head.body.ApplyTorque(Dir);
}
movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / 50.0f));
movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / DisableMovementAboveSurfaceThreshold));
}
bool isNotRemote = true;
@@ -943,7 +921,18 @@ namespace Barotrauma
if (isNotRemote)
{
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, movementLerp);
float t = movementLerp;
if (targetSpeed > 0.00001f && !SimplePhysicsEnabled)
{
Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2);
float dot = Vector2.Dot(forward, Vector2.Normalize(movement));
if (dot < 0)
{
// Reduce the linear movement speed when not facing the movement direction
t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f);
}
}
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t);
}
WalkPos += movement.Length();
@@ -1125,10 +1114,9 @@ namespace Barotrauma
bottomPos + torsoPos + movement.Y * 0.1f - ladderSimPos.Y);
if (climbFast) { handPos.Y -= stepHeight; }
bool aiming = this.aiming || aimingMelee;
//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 (!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,
@@ -1136,7 +1124,7 @@ namespace Barotrauma
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)
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,
@@ -1219,7 +1207,11 @@ namespace Barotrauma
//apply forces to the collider to move the Character up/down
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
if (!aiming)
if (Aiming)
{
RotateHead(head);
}
else
{
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque);
@@ -1401,8 +1393,8 @@ namespace Barotrauma
else
{
//stabilize the oxygen level but don't allow it to go positive and revive the character yet
float stabilizationAmount = skill * CPRSettings.StabilizationPerSkill;
stabilizationAmount = MathHelper.Clamp(stabilizationAmount, CPRSettings.StabilizationMin, CPRSettings.StabilizationMax);
float stabilizationAmount = skill * CPRSettings.Active.StabilizationPerSkill;
stabilizationAmount = MathHelper.Clamp(stabilizationAmount, CPRSettings.Active.StabilizationMin, CPRSettings.Active.StabilizationMax);
character.Oxygen -= 1.0f / stabilizationAmount * deltaTime; //Worse skill = more oxygen required
if (character.Oxygen > 0.0f) { target.Oxygen += stabilizationAmount * deltaTime; } //we didn't suffocate yet did we
}
@@ -1426,23 +1418,23 @@ namespace Barotrauma
targetTorso.body.ApplyLinearImpulse(new Vector2(0, -20f), maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
cprPump = 0;
if (skill < CPRSettings.DamageSkillThreshold)
if (skill < CPRSettings.Active.DamageSkillThreshold)
{
target.LastDamageSource = null;
target.DamageLimb(
targetTorso.WorldPosition, targetTorso,
new[] { CPRSettings.InsufficientSkillAffliction.Instantiate((CPRSettings.DamageSkillThreshold - skill) * CPRSettings.DamageSkillMultiplier, source: character) },
new[] { CPRSettings.Active.InsufficientSkillAffliction.Instantiate((CPRSettings.Active.DamageSkillThreshold - skill) * CPRSettings.Active.DamageSkillMultiplier, source: character) },
0.0f, true, 0.0f, attacker: null);
}
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
{
float reviveChance = skill * CPRSettings.ReviveChancePerSkill;
reviveChance = (float)Math.Pow(reviveChance, CPRSettings.ReviveChanceExponent);
reviveChance = MathHelper.Clamp(reviveChance, CPRSettings.ReviveChanceMin, CPRSettings.ReviveChanceMax);
float reviveChance = skill * CPRSettings.Active.ReviveChancePerSkill;
reviveChance = (float)Math.Pow(reviveChance, CPRSettings.Active.ReviveChanceExponent);
reviveChance = MathHelper.Clamp(reviveChance, CPRSettings.Active.ReviveChanceMin, CPRSettings.Active.ReviveChanceMax);
if (powerfulCPR) { reviveChance *= 2.0f; }
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) <= reviveChance)
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient) <= reviveChance)
{
//increase oxygen and clamp it above zero
// -> the character should be revived if there are no major afflictions in addition to lack of oxygen
@@ -1469,7 +1461,7 @@ namespace Barotrauma
target.CharacterHealth.CalculateVitality();
if (wasCritical && target.Vitality > 0.0f && Timing.TotalTime > lastReviveTime + 10.0f)
{
character.Info?.IncreaseSkillLevel("medical", SkillSettings.Current.SkillIncreasePerCprRevive);
character.Info?.IncreaseSkillLevel("medical".ToIdentifier(), SkillSettings.Current.SkillIncreasePerCprRevive);
SteamAchievementManager.OnCharacterRevived(target, character);
lastReviveTime = (float)Timing.TotalTime;
#if SERVER
@@ -1512,11 +1504,14 @@ namespace Barotrauma
return;
}
Limb targetTorso = target.AnimController.GetLimb(LimbType.Torso);
if (targetTorso == null) targetTorso = target.AnimController.MainLimb;
if (targetTorso == null)
{
targetTorso = target.AnimController.MainLimb;
}
if (target.AnimController.Dir != Dir)
{
target.AnimController.Flip();
}
Vector2 transformedTorsoPos = torso.SimPosition;
if (character.Submarine == null && target.Submarine != null)
{
@@ -1560,7 +1555,10 @@ namespace Barotrauma
{
//only grab with one hand when swimming
leftHand.Disabled = true;
if (!inWater) rightHand.Disabled = true;
if (!inWater)
{
rightHand.Disabled = true;
}
for (int i = 0; i < 2; i++)
{
@@ -1708,6 +1706,24 @@ namespace Barotrauma
}
}
private 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);
}
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
{
if (!MathUtils.IsValid(pos))
@@ -1844,11 +1860,9 @@ namespace Barotrauma
}
float angle = flipAngle ? -limb.body.Rotation : limb.body.Rotation;
if (wrapAngle) angle = MathUtils.WrapAnglePi(angle);
if (wrapAngle) { angle = MathUtils.WrapAnglePi(angle); }
TrySetLimbPosition(limb, Collider.SimPosition, position);
limb.body.SetTransform(limb.body.SimPosition, angle);
TrySetLimbPosition(limb, Collider.SimPosition, position, angle);
}
}
@@ -69,7 +69,7 @@ namespace Barotrauma
"Attempted to access a potentially removed ragdoll. Character: " + character.SpeciesName + ", id: " + character.ID + ", removed: " + character.Removed + ", ragdoll removed: " + !list.Contains(this) + "\n" + Environment.StackTrace.CleanupStackTrace());
accessRemovedCharacterErrorShown = true;
}
return new Limb[0];
return Array.Empty<Limb>();
}
return limbs;
}
@@ -424,13 +424,13 @@ namespace Barotrauma
#endif
var characterPrefab = CharacterPrefab.FindByFilePath(character.ConfigPath);
if (characterPrefab?.XDocument != null)
if (characterPrefab?.ConfigElement != null)
{
var mainElement = characterPrefab.XDocument.Root.IsOverride() ? characterPrefab.XDocument.Root.FirstElement() : characterPrefab.XDocument.Root;
var mainElement = characterPrefab.ConfigElement;
foreach (var huskAppendage in mainElement.GetChildElements("huskappendage"))
{
if (!inEditor && huskAppendage.GetAttributeBool("onlyfromafflictions", false)) { continue; }
AfflictionHusk.AttachHuskAppendage(character, huskAppendage.GetAttributeString("affliction", string.Empty), huskAppendage, ragdoll: this);
AfflictionHusk.AttachHuskAppendage(character, huskAppendage.GetAttributeIdentifier("affliction", Identifier.Empty), huskAppendage, ragdoll: this);
}
}
}
@@ -811,9 +811,9 @@ namespace Barotrauma
}
SeverLimbJointProjSpecific(limbJoint, playSound: true);
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
if (GameMain.NetworkMember is { IsServer: true })
{
GameMain.NetworkMember.CreateEntityEvent(character, new object[] { NetEntityEvent.Type.Status });
GameMain.NetworkMember.CreateEntityEvent(character, new Character.CharacterStatusEventData());
}
return true;
}
@@ -1201,13 +1201,9 @@ namespace Barotrauma
headInWater = false;
inWater = false;
RefreshFloorY(ignoreStairs: Stairs == null);
if (currentHull.WaterVolume > currentHull.Volume * 0.95f)
if (currentHull.WaterPercentage > 0.001f)
{
inWater = true;
}
else
{
float waterSurface = ConvertUnits.ToSimUnits(currentHull.Surface);
float waterSurface = ConvertUnits.ToSimUnits(GetSurfaceY());
if (targetMovement.Y < 0.0f)
{
Vector2 colliderBottom = GetColliderBottom();
@@ -1220,11 +1216,8 @@ namespace Barotrauma
if (lowerHull != null) floorY = ConvertUnits.ToSimUnits(lowerHull.Rect.Y - lowerHull.Rect.Height);
}
}
float standHeight =
HeadPosition.HasValue ? HeadPosition.Value :
TorsoPosition.HasValue ? TorsoPosition.Value :
Collider.GetMaxExtent() * 0.5f;
if (Collider.SimPosition.Y < waterSurface && waterSurface - floorY > standHeight * 0.95f)
float standHeight = HeadPosition ?? TorsoPosition ?? Collider.GetMaxExtent() * 0.5f;
if (Collider.SimPosition.Y < waterSurface && waterSurface - floorY > standHeight * 0.8f)
{
inWater = true;
}
@@ -1416,7 +1409,7 @@ namespace Barotrauma
#else
DebugConsole.NewMessage(errorMsg.Replace("[name]", Character.Name), Color.Red);
#endif
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.CheckValidity:" + character.ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", Character.SpeciesName));
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.CheckValidity:" + character.ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", Character.SpeciesName.Value));
if (!MathUtils.IsValid(Collider.SimPosition) || Math.Abs(Collider.SimPosition.X) > 1e10f || Math.Abs(Collider.SimPosition.Y) > 1e10f)
{
@@ -1529,7 +1522,6 @@ namespace Barotrauma
}
}
private float GetFloorY(Vector2 simPosition, bool ignoreStairs = false)
{
onGround = false;
@@ -1648,6 +1640,51 @@ namespace Barotrauma
}
}
public float GetSurfaceY()
{
//check both hulls: the hull whose coordinate space the ragdoll is in, and the hull whose bounds the character's origin actually is inside
if (currentHull == null || character.CurrentHull == null)
{
return float.PositiveInfinity;
}
float surfacePos = currentHull.Surface;
float surfaceThreshold = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f);
//if the hull is almost full of water, check if there's a water-filled hull above it
//and use its water surface instead of the current hull's
if (currentHull.Rect.Y - currentHull.Surface < 5.0f)
{
GetSurfacePos(currentHull, ref surfacePos);
void GetSurfacePos(Hull hull, ref float prevSurfacePos)
{
if (prevSurfacePos > surfaceThreshold) { return; }
foreach (Gap gap in hull.ConnectedGaps)
{
if (gap.IsHorizontal || gap.Open <= 0.0f || gap.WorldPosition.Y < hull.WorldPosition.Y) { continue; }
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; }
//if the gap is above us and leads outside, there's no surface to limit the movement
if (!gap.IsRoomToRoom && gap.Position.Y > hull.Position.Y)
{
prevSurfacePos += 100000.0f;
return;
}
foreach (var linkedTo in gap.linkedTo)
{
if (linkedTo is Hull otherHull && otherHull != hull && otherHull != currentHull)
{
prevSurfacePos = Math.Max(surfacePos, otherHull.Surface);
GetSurfacePos(otherHull, ref prevSurfacePos);
break;
}
}
}
}
}
return surfacePos;
}
public void SetPosition(Vector2 simPosition, bool lerp = false, bool ignorePlatforms = true, bool forceMainLimbToCollider = false, bool detachProjectiles = true)
{
if (!MathUtils.IsValid(simPosition))
@@ -1701,7 +1738,7 @@ namespace Barotrauma
if (limb.IsSevered) { continue; }
//check visibility from the new position of the collider to the new position of this limb
Vector2 movePos = limb.SimPosition + limbMoveAmount;
TrySetLimbPosition(limb, simPosition, movePos, lerp, ignorePlatforms);
TrySetLimbPosition(limb, simPosition, movePos, limb.Rotation, lerp, ignorePlatforms);
}
}
}
@@ -1716,7 +1753,7 @@ namespace Barotrauma
IsHanging = true;
}
protected void TrySetLimbPosition(Limb limb, Vector2 original, Vector2 simPosition, bool lerp = false, bool ignorePlatforms = true)
protected void TrySetLimbPosition(Limb limb, Vector2 original, Vector2 simPosition, float rotation, bool lerp = false, bool ignorePlatforms = true)
{
Vector2 movePos = simPosition;
@@ -1738,11 +1775,12 @@ namespace Barotrauma
if (lerp)
{
limb.body.TargetPosition = movePos;
limb.body.MoveToTargetPosition(true);
limb.body.TargetRotation = rotation;
limb.body.MoveToTargetPosition(true);
}
else
{
limb.body.SetTransform(movePos, limb.Rotation);
limb.body.SetTransform(movePos, rotation);
limb.PullJointWorldAnchorB = limb.PullJointWorldAnchorA;
limb.PullJointEnabled = false;
}