Build 1.1.4.0
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user