Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -18,6 +18,13 @@ namespace Barotrauma
{
public const float NeutralBallastPercentage = 0.07f;
public const Category CollidesWith =
Physics.CollisionItem |
Physics.CollisionLevel |
Physics.CollisionCharacter |
Physics.CollisionProjectile |
Physics.CollisionWall;
const float HorizontalDrag = 0.01f;
const float VerticalDrag = 0.05f;
const float MaxDrag = 0.1f;
@@ -32,6 +39,8 @@ namespace Barotrauma
private const float MaxCollisionImpact = 5.0f;
private const float Friction = 0.2f, Restitution = 0.0f;
private readonly List<Contact> levelContacts = new List<Contact>();
public List<Vector2> HullVertices
{
get;
@@ -39,6 +48,7 @@ namespace Barotrauma
}
private float depthDamageTimer = 10.0f;
private float damageSoundTimer = 10.0f;
private readonly Submarine submarine;
@@ -48,6 +58,9 @@ namespace Barotrauma
private readonly Queue<Impact> impactQueue = new Queue<Impact>();
private float forceUpwardsTimer;
private const float ForceUpwardsDelay = 30.0f;
struct Impact
{
public Fixture Target;
@@ -146,9 +159,13 @@ namespace Barotrauma
farseerBody.CollidesWith = collidesWith;
farseerBody.Enabled = false;
farseerBody.UserData = this;
if (sub.Info.IsOutpost)
{
farseerBody.BodyType = BodyType.Static;
}
foreach (var mapEntity in MapEntity.mapEntityList)
{
if (mapEntity.Submarine != submarine || !(mapEntity is Structure wall)) { continue; }
if (mapEntity.Submarine != submarine || mapEntity is not Structure wall) { continue; }
bool hasCollider = wall.HasBody && !wall.IsPlatform && wall.StairDirection == Direction.None;
Rectangle rect = wall.Rect;
@@ -185,13 +202,20 @@ namespace Barotrauma
foreach (Item item in Item.ItemList)
{
if (item.Submarine != submarine) { continue; }
if (item.StaticBodyConfig == null || item.Submarine != submarine) { continue; }
Vector2 simPos = ConvertUnits.ToSimUnits(item.Position);
if (item.GetComponent<Door>() is Door door)
{
door.OutsideSubmarineFixture = farseerBody.CreateRectangle(door.Body.Width, door.Body.Height, 5.0f, simPos, collisionCategory, collidesWith);
door.OutsideSubmarineFixture.UserData = item;
}
if (item.StaticBodyConfig == null) { continue; }
float radius = item.StaticBodyConfig.GetAttributeFloat("radius", 0.0f) * item.Scale;
float width = item.StaticBodyConfig.GetAttributeFloat("width", 0.0f) * item.Scale;
float height = item.StaticBodyConfig.GetAttributeFloat("height", 0.0f) * item.Scale;
Vector2 simPos = ConvertUnits.ToSimUnits(item.Position);
float simRadius = ConvertUnits.ToSimUnits(radius);
float simWidth = ConvertUnits.ToSimUnits(width);
float simHeight = ConvertUnits.ToSimUnits(height);
@@ -374,6 +398,33 @@ namespace Barotrauma
//-------------------------
//if heading up and there's another sub on top of us, gradually force it upwards
//(i.e. apply "artificial buoyancy" to it) to prevent us from getting pinned under it
//only applies to enemy subs with no enemies inside them (like destroyed pirate subs)
if (totalForce.Y > 0)
{
ContactEdge contactEdge = Body?.FarseerBody?.ContactList;
while (contactEdge?.Next != null)
{
if (contactEdge.Contact.Enabled &&
contactEdge.Other.UserData is Submarine otherSubmarine &&
otherSubmarine.TeamID != Submarine.TeamID &&
contactEdge.Contact.IsTouching)
{
contactEdge.Contact.GetWorldManifold(out Vector2 _, out FixedArray2<Vector2> points);
if (points[0].Y > Body.SimPosition.Y &&
!Character.CharacterList.Any(c => c.Submarine == otherSubmarine && !c.IsIncapacitated && c.TeamID == otherSubmarine.TeamID))
{
otherSubmarine.SubBody.forceUpwardsTimer += deltaTime;
break;
}
}
contactEdge = contactEdge.Next;
}
}
//-------------------------
if (Body.LinearVelocity.LengthSquared() > 0.0001f)
{
//TODO: sync current drag with clients?
@@ -397,7 +448,34 @@ namespace Barotrauma
ApplyForce(totalForce);
if (Velocity.LengthSquared() < 0.01f)
{
levelContacts.Clear();
levelContacts.AddRange(GetLevelContacts(Body));
for (int i = 0; i < levelContacts.Count; i++)
{
for (int j = i + 1; j < levelContacts.Count; j++)
{
levelContacts[i].GetWorldManifold(out Vector2 normal1, out _);
levelContacts[j].GetWorldManifold(out Vector2 normal2, out _);
//normals pointing in different directions = sub lodged between two walls
if (Vector2.Dot(normal1, normal2) < 0)
{
//apply an extra force to hopefully dislodge the sub
ApplyForce(totalForce * 100.0f);
i = levelContacts.Count;
break;
}
}
}
}
totalForcePerFrame = Vector2.Zero;
UpdateDepthDamage(deltaTime);
forceUpwardsTimer = MathHelper.Clamp(forceUpwardsTimer - deltaTime * 0.1f, 0.0f, ForceUpwardsDelay);
}
partial void ClientUpdatePosition(float deltaTime);
@@ -464,16 +542,28 @@ namespace Barotrauma
float buoyancy = NeutralBallastPercentage - waterPercentage;
if (buoyancy > 0.0f)
{
buoyancy *= 2.0f;
}
else
{
buoyancy = Math.Max(buoyancy, -0.5f);
}
if (forceUpwardsTimer > 0.0f)
{
buoyancy = MathHelper.Lerp(buoyancy, 0.1f, forceUpwardsTimer / ForceUpwardsDelay);
}
return new Vector2(0.0f, buoyancy * Body.Mass * 10.0f);
}
private Vector2 totalForcePerFrame;
public void ApplyForce(Vector2 force)
{
Body.ApplyForce(force);
totalForcePerFrame += force;
}
public void SetPosition(Vector2 position)
@@ -489,36 +579,58 @@ namespace Barotrauma
if (Level.Loaded == null) { return; }
//camera shake and sounds start playing 500 meters before crush depth
float depthEffectThreshold = 500.0f;
if (Submarine.RealWorldDepth < Level.Loaded.RealWorldCrushDepth - depthEffectThreshold || Submarine.RealWorldDepth < Submarine.RealWorldCrushDepth - depthEffectThreshold)
const float CosmeticEffectThreshold = -500.0f;
//breaches won't get any more severe 500 meters below crush depth
const float MaxEffectThreshold = 500.0f;
const float MinWallDamageProbability = 0.1f;
const float MaxWallDamageProbability = 1.0f;
const float MinWallDamage = 50f;
const float MaxWallDamage = 500.0f;
const float MinCameraShake = 5f;
const float MaxCameraShake = 50.0f;
if (Submarine.RealWorldDepth < Level.Loaded.RealWorldCrushDepth + CosmeticEffectThreshold || Submarine.RealWorldDepth < Submarine.RealWorldCrushDepth + CosmeticEffectThreshold)
{
return;
}
depthDamageTimer -= deltaTime;
if (depthDamageTimer > 0.0f) { return; }
#if CLIENT
SoundPlayer.PlayDamageSound("pressure", Rand.Range(0.0f, 100.0f), submarine.WorldPosition + Rand.Vector(Rand.Range(0.0f, Math.Min(submarine.Borders.Width, submarine.Borders.Height))), 20000.0f);
#endif
foreach (Structure wall in Structure.WallList)
damageSoundTimer -= deltaTime;
if (damageSoundTimer <= 0.0f)
{
if (wall.Submarine != submarine) { continue; }
float wallCrushDepth = wall.CrushDepth;
float pastCrushDepth = submarine.RealWorldDepth - wallCrushDepth;
if (pastCrushDepth > 0)
{
Explosion.RangedStructureDamage(wall.WorldPosition, 100.0f, pastCrushDepth * 0.1f, levelWallDamage: 0.0f);
}
if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
{
GameMain.GameScreen.Cam.Shake = Math.Max(GameMain.GameScreen.Cam.Shake, MathHelper.Clamp(pastCrushDepth * 0.001f, 1.0f, 50.0f));
}
#if CLIENT
SoundPlayer.PlayDamageSound("pressure", Rand.Range(0.0f, 100.0f), submarine.WorldPosition + Rand.Vector(Rand.Range(0.0f, Math.Min(submarine.Borders.Width, submarine.Borders.Height))), 20000.0f);
#endif
damageSoundTimer = Rand.Range(5.0f, 10.0f);
}
depthDamageTimer = 10.0f;
depthDamageTimer -= deltaTime;
if (depthDamageTimer <= 0.0f)
{
foreach (Structure wall in Structure.WallList)
{
if (wall.Submarine != submarine) { continue; }
float wallCrushDepth = wall.CrushDepth;
float pastCrushDepth = submarine.RealWorldDepth - wallCrushDepth;
float pastCrushDepthRatio = Math.Clamp(pastCrushDepth / MaxEffectThreshold, 0.0f, 1.0f);
if (Rand.Range(0.0f, 1.0f) > MathHelper.Lerp(MinWallDamageProbability, MaxWallDamageProbability, pastCrushDepthRatio)) { continue; }
float damage = MathHelper.Lerp(MinWallDamage, MaxWallDamage, pastCrushDepthRatio);
if (pastCrushDepth > 0)
{
Explosion.RangedStructureDamage(wall.WorldPosition, 100.0f, damage, levelWallDamage: 0.0f);
#if CLIENT
SoundPlayer.PlayDamageSound("StructureBlunt", Rand.Range(0.0f, 100.0f), wall.WorldPosition, 2000.0f);
#endif
}
if (Character.Controlled != null && Character.Controlled.Submarine == submarine)
{
GameMain.GameScreen.Cam.Shake = Math.Max(GameMain.GameScreen.Cam.Shake, MathHelper.Lerp(MinCameraShake, MaxCameraShake, pastCrushDepthRatio));
}
}
depthDamageTimer = Rand.Range(5.0f, 10.0f);
}
}
public void FlipX()
@@ -623,7 +735,7 @@ namespace Barotrauma
attackMultiplier = enemyAI.ActiveAttack.SubmarineImpactMultiplier;
}
if (impactMass * attackMultiplier > MinImpactLimbMass)
if (impactMass * attackMultiplier > MinImpactLimbMass && Body.BodyType != BodyType.Static)
{
Vector2 normal =
Vector2.DistanceSquared(Body.SimPosition, limb.SimPosition) < 0.0001f ?
@@ -641,20 +753,10 @@ namespace Barotrauma
}
//find all contacts between the limb and level walls
List<Contact> levelContacts = new List<Contact>();
ContactEdge contactEdge = limb.body.FarseerBody.ContactList;
while (contactEdge?.Contact != null)
{
if (contactEdge.Contact.Enabled &&
contactEdge.Contact.IsTouching &&
contactEdge.Other?.UserData is VoronoiCell)
{
levelContacts.Add(contactEdge.Contact);
}
contactEdge = contactEdge.Next;
}
IEnumerable<Contact> levelContacts = GetLevelContacts(limb.body);
int levelContactCount = levelContacts.Count();
if (levelContacts.Count == 0) { return; }
if (levelContactCount == 0) { return; }
//if the limb is in contact with the level, apply an artifical impact to prevent the sub from bouncing on top of it
//not a very realistic way to handle the collisions (makes it seem as if the characters were made of reinforced concrete),
@@ -677,9 +779,9 @@ namespace Barotrauma
avgContactNormal += contactNormal;
//apply impacts at the positions where this sub is touching the limb
ApplyImpact((Vector2.Dot(-collision.Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, collision.ImpactPos, applyDamage: false);
ApplyImpact((Vector2.Dot(-collision.Velocity, contactNormal) / 2.0f) / levelContactCount, contactNormal, collision.ImpactPos, applyDamage: false);
}
avgContactNormal /= levelContacts.Count;
avgContactNormal /= levelContactCount;
float contactDot = Vector2.Dot(Body.LinearVelocity, -avgContactNormal);
if (contactDot > 0.001f)
@@ -718,6 +820,21 @@ namespace Barotrauma
}
}
private IEnumerable<Contact> GetLevelContacts(PhysicsBody body)
{
ContactEdge contactEdge = body.FarseerBody.ContactList;
while (contactEdge?.Contact != null)
{
if (contactEdge.Contact.Enabled &&
contactEdge.Contact.IsTouching &&
contactEdge.Other?.UserData is VoronoiCell)
{
yield return contactEdge.Contact;
}
contactEdge = contactEdge.Next;
}
}
private void HandleLevelCollision(Impact impact, VoronoiCell cell = null)
{
if (GameMain.GameSession != null && GameMain.GameSession.RoundDuration < 10)
@@ -786,21 +903,9 @@ namespace Barotrauma
}
//find all contacts between this sub and level walls
List<Contact> levelContacts = new List<Contact>();
ContactEdge contactEdge = Body?.FarseerBody?.ContactList;
while (contactEdge?.Next != null)
{
if (contactEdge.Contact.Enabled &&
contactEdge.Other.UserData is VoronoiCell &&
contactEdge.Contact.IsTouching)
{
levelContacts.Add(contactEdge.Contact);
}
contactEdge = contactEdge.Next;
}
if (levelContacts.Count == 0) { return; }
IEnumerable<Contact> levelContacts = GetLevelContacts(Body);
int levelContactCount = levelContacts.Count();
if (levelContactCount == 0) { return; }
//if this sub is in contact with the level, apply artifical impacts
//to both subs to prevent the other sub from bouncing on top of this one
@@ -811,8 +916,7 @@ namespace Barotrauma
levelContact.GetWorldManifold(out Vector2 contactNormal, out FixedArray2<Vector2> temp);
//if the contact normal is pointing from the sub towards the level cell we collided with, flip the normal
VoronoiCell cell = levelContact.FixtureB.UserData is VoronoiCell ?
((VoronoiCell)levelContact.FixtureB.UserData) : ((VoronoiCell)levelContact.FixtureA.UserData);
VoronoiCell cell = levelContact.FixtureB.UserData as VoronoiCell ?? levelContact.FixtureA.UserData as VoronoiCell;
var cellDiff = ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center;
if (Vector2.Dot(contactNormal, cellDiff) < 0)
@@ -823,9 +927,9 @@ namespace Barotrauma
avgContactNormal += contactNormal;
//apply impacts at the positions where this sub is touching the level
ApplyImpact((Vector2.Dot(impact.Velocity, contactNormal) / 2.0f) * massRatio / levelContacts.Count, contactNormal, impact.ImpactPos);
ApplyImpact((Vector2.Dot(impact.Velocity, contactNormal) / 2.0f) * massRatio / levelContactCount, contactNormal, impact.ImpactPos);
}
avgContactNormal /= levelContacts.Count;
avgContactNormal /= levelContactCount;
//apply an impact to the other sub
float contactDot = Vector2.Dot(otherSub.PhysicsBody.LinearVelocity, -avgContactNormal);