2f107db...5202af9

This commit is contained in:
Joonas Rikkonen
2019-03-18 21:42:26 +02:00
parent 58c92888b7
commit 044fd3344b
395 changed files with 27417 additions and 19754 deletions
@@ -119,33 +119,35 @@ namespace Barotrauma
if (force == 0.0f && attack.Stun == 0.0f && attack.GetTotalDamage(false) == 0.0f) return;
DamageCharacters(worldPosition, attack, force, damageSource);
if (flames && GameMain.Client == null)
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
{
foreach (Item item in Item.ItemList)
if (flames)
{
if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue;
//don't apply OnFire effects if the item is inside a fireproof container
//(or if it's inside a container that's inside a fireproof container, etc)
Item container = item.Container;
while (container != null)
foreach (Item item in Item.ItemList)
{
if (container.FireProof) return;
container = container.Container;
}
if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue;
if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.1f) continue;
//don't apply OnFire effects if the item is inside a fireproof container
//(or if it's inside a container that's inside a fireproof container, etc)
Item container = item.Container;
while (container != null)
{
if (container.FireProof) return;
container = container.Container;
}
item.ApplyStatusEffects(ActionType.OnFire, 1.0f);
if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.1f) continue;
if (item.Condition <= 0.0f && GameMain.Server != null)
{
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
item.ApplyStatusEffects(ActionType.OnFire, 1.0f);
if (item.Condition <= 0.0f && GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
}
}
}
}
}
partial void ExplodeProjSpecific(Vector2 worldPosition, Hull hull);
@@ -74,7 +74,9 @@ namespace Barotrauma
hull = Hull.FindHull(worldPosition, spawningHull);
if (hull == null || worldPosition.Y < hull.WorldSurface) return;
#if CLIENT
if (!isNetworkMessage && GameMain.Client != null) return;
#endif
hull.AddFireSource(this);
@@ -174,7 +176,9 @@ namespace Barotrauma
UpdateProjSpecific(growModifier);
#if CLIENT
if (GameMain.Client != null) return;
#endif
if (size.X < 1.0f) Remove();
}
@@ -230,7 +234,10 @@ namespace Barotrauma
private void DamageItems(float deltaTime)
{
if (size.X <= 0.0f || GameMain.Client != null) return;
if (size.X <= 0.0f) return;
#if CLIENT
if (GameMain.Client != null) return;
#endif
foreach (Item item in Item.ItemList)
{
@@ -250,9 +257,9 @@ namespace Barotrauma
if (item.Position.Y < position.Y - size.Y || item.Position.Y > hull.Rect.Y) continue;
item.ApplyStatusEffects(ActionType.OnFire, deltaTime);
if (item.Condition <= 0.0f && GameMain.Server != null)
if (item.Condition <= 0.0f && GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFire });
}
}
}
@@ -285,7 +292,9 @@ namespace Barotrauma
//evaporate some of the water
hull.WaterVolume -= extinguishAmount;
#if CLIENT
if (GameMain.Client != null) return;
#endif
if (size.X < 1.0f) Remove();
}
@@ -312,7 +321,9 @@ namespace Barotrauma
hull.WaterVolume -= extinguishAmount;
#if CLIENT
if (GameMain.Client != null) return;
#endif
if (size.X < 1.0f) Remove();
}
+19 -106
View File
@@ -49,16 +49,13 @@ namespace Barotrauma
private bool update;
public bool Visible = true;
float[] waveY; //displacement from the surface of the water
float[] waveVel; //velocity of the point
float[] leftDelta;
float[] rightDelta;
private float[] waveY; //displacement from the surface of the water
private float[] waveVel; //velocity of the point
private float lastSentVolume, lastSentOxygen;
private float sendUpdateTimer;
private float[] leftDelta;
private float[] rightDelta;
public List<Gap> ConnectedGaps;
public override string Name
@@ -407,7 +404,10 @@ namespace Barotrauma
{
FireSources.Add(fireSource);
if (GameMain.Server != null && !IdFreed) GameMain.Server.CreateEntityEvent(this);
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && !IdFreed)
{
GameMain.NetworkMember.CreateEntityEvent(this);
}
}
public override void Update(float deltaTime, Camera cam)
@@ -421,24 +421,6 @@ namespace Barotrauma
aiTarget.SightRange = Submarine == null ? 0.0f : Math.Max(Submarine.Velocity.Length() * 500.0f, 500.0f);
aiTarget.SoundRange -= deltaTime * 1000.0f;
//update client hulls if the amount of water has changed by >10%
//or if oxygen percentage has changed by 5%
if (Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f ||
Math.Abs(lastSentOxygen - OxygenPercentage) > 5f)
{
if (GameMain.Server != null && !IdFreed)
{
sendUpdateTimer -= deltaTime;
if (sendUpdateTimer < 0.0f)
{
GameMain.Server.CreateEntityEvent(this);
lastSentVolume = waterVolume;
lastSentOxygen = OxygenPercentage;
sendUpdateTimer = NetworkUpdateInterval;
}
}
}
if (!update)
{
lethalPressure = 0.0f;
@@ -597,9 +579,9 @@ namespace Barotrauma
{
FireSources.Remove(fire);
if (GameMain.Server != null && !Removed && !IdFreed)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer && !Removed && !IdFreed)
{
GameMain.Server.CreateEntityEvent(this);
GameMain.NetworkMember.CreateEntityEvent(this);
}
}
@@ -632,15 +614,18 @@ namespace Barotrauma
/// Approximate distance from this hull to the target hull, moving through open gaps without passing through walls.
/// Uses a greedy algo and may not use the most optimal path. Returns float.MaxValue if no path is found.
/// </summary>
public float GetApproximateDistance(Hull target, float maxDistance)
public float GetApproximateDistance(Vector2 startPos, Vector2 endPos, Hull targetHull, float maxDistance)
{
return GetApproximateHullDistance(new HashSet<Hull>(), target, 0.0f, maxDistance);
return GetApproximateHullDistance(startPos, endPos, new HashSet<Hull>(), targetHull, 0.0f, maxDistance);
}
private float GetApproximateHullDistance(HashSet<Hull> connectedHulls, Hull target, float distance, float maxDistance)
private float GetApproximateHullDistance(Vector2 startPos, Vector2 endPos, HashSet<Hull> connectedHulls, Hull target, float distance, float maxDistance)
{
if (distance >= maxDistance) return float.MaxValue;
if (this == target) return distance;
if (this == target)
{
return distance + Vector2.Distance(startPos, endPos);
}
connectedHulls.Add(this);
@@ -663,7 +648,7 @@ namespace Barotrauma
{
if (g.linkedTo[i] is Hull hull && !connectedHulls.Contains(hull))
{
float dist = hull.GetApproximateHullDistance(connectedHulls, target, distance + Vector2.Distance(g.Position, this.Position), maxDistance);
float dist = hull.GetApproximateHullDistance(g.Position, endPos, connectedHulls, target, distance + Vector2.Distance(startPos, g.Position), maxDistance);
if (dist < float.MaxValue) return dist;
}
}
@@ -847,78 +832,6 @@ namespace Barotrauma
return TextManager.Get("Sub" + roomPos.ToString());
}
public void ServerWrite(NetBuffer message, Client c, object[] extraData = null)
{
message.WriteRangedSingle(MathHelper.Clamp(waterVolume / Volume, 0.0f, 1.5f), 0.0f, 1.5f, 8);
message.WriteRangedSingle(MathHelper.Clamp(OxygenPercentage, 0.0f, 100.0f), 0.0f, 100.0f, 8);
message.Write(FireSources.Count > 0);
if (FireSources.Count > 0)
{
message.WriteRangedInteger(0, 16, Math.Min(FireSources.Count, 16));
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
{
var fireSource = FireSources[i];
Vector2 normalizedPos = new Vector2(
(fireSource.Position.X - rect.X) / rect.Width,
(fireSource.Position.Y - (rect.Y - rect.Height)) / rect.Height);
message.WriteRangedSingle(MathHelper.Clamp(normalizedPos.X, 0.0f, 1.0f), 0.0f, 1.0f, 8);
message.WriteRangedSingle(MathHelper.Clamp(normalizedPos.Y, 0.0f, 1.0f), 0.0f, 1.0f, 8);
message.WriteRangedSingle(MathHelper.Clamp(fireSource.Size.X / rect.Width, 0.0f, 1.0f), 0, 1.0f, 8);
}
}
}
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
{
WaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
OxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
bool hasFireSources = message.ReadBoolean();
int fireSourceCount = 0;
if (hasFireSources)
{
fireSourceCount = message.ReadRangedInteger(0, 16);
for (int i = 0; i < fireSourceCount; i++)
{
Vector2 pos = Vector2.Zero;
float size = 0.0f;
pos.X = MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f);
pos.Y = MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f);
size = message.ReadRangedSingle(0.0f, 1.0f, 8);
pos = new Vector2(
rect.X + rect.Width * pos.X,
rect.Y - rect.Height + (rect.Height * pos.Y));
size = size * rect.Width;
var newFire = i < FireSources.Count ?
FireSources[i] :
new FireSource(Submarine == null ? pos : pos + Submarine.Position, null, true);
newFire.Position = pos;
newFire.Size = new Vector2(size, newFire.Size.Y);
//ignore if the fire wasn't added to this room (invalid position)?
if (!FireSources.Contains(newFire))
{
newFire.Remove();
continue;
}
}
}
for (int i = FireSources.Count - 1; i >= fireSourceCount; i--)
{
FireSources[i].Remove();
if (i < FireSources.Count)
{
FireSources.RemoveAt(i);
}
}
}
public static Hull Load(XElement element, Submarine submarine)
{
Rectangle rect = Rectangle.Empty;
@@ -1416,15 +1416,15 @@ namespace Barotrauma
{
wall.Update(deltaTime);
}
if (GameMain.Server != null)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
networkUpdateTimer += deltaTime;
if (networkUpdateTimer > NetworkUpdateInterval)
{
if (extraWalls.Any(w => w.Body.BodyType != BodyType.Static))
{
GameMain.Server.CreateEntityEvent(this);
GameMain.NetworkMember.CreateEntityEvent(this);
}
networkUpdateTimer = 0.0f;
}
@@ -346,7 +346,9 @@ namespace Barotrauma
public Sprite BackgroundSprite { get; private set; }
public Sprite BackgroundTopSprite { get; private set; }
public Sprite WallSprite { get; private set; }
public Sprite WallSpriteSpecular { get; private set; }
public Sprite WallEdgeSprite { get; private set; }
public Sprite WallEdgeSpriteSpecular { get; private set; }
public Sprite WaterParticles { get; private set; }
public static List<Biome> GetBiomes()
@@ -419,9 +421,15 @@ namespace Barotrauma
case "wall":
WallSprite = new Sprite(subElement);
break;
case "wallspecular":
WallSpriteSpecular = new Sprite(subElement);
break;
case "walledge":
WallEdgeSprite = new Sprite(subElement);
break;
case "walledgespecular":
WallEdgeSpriteSpecular = new Sprite(subElement);
break;
case "waterparticles":
WaterParticles = new Sprite(subElement);
break;
@@ -14,6 +14,9 @@ namespace Barotrauma
public readonly LevelObjectPrefab Prefab;
public Vector3 Position;
public float NetworkUpdateTimer;
public const float NetworkUpdateInterval = 0.2f;
public float Scale;
public float Rotation;
@@ -336,12 +336,14 @@ namespace Barotrauma
{
foreach (LevelObject obj in objects)
{
if (GameMain.Server != null)
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
if (obj.NeedsNetworkSyncing)
obj.NetworkUpdateTimer -= deltaTime;
if (obj.NeedsNetworkSyncing && obj.NetworkUpdateTimer <= 0.0f)
{
GameMain.Server.CreateEntityEvent(this, new object[] { obj });
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { obj });
obj.NeedsNetworkSyncing = false;
obj.NetworkUpdateTimer = LevelObject.NetworkUpdateInterval;
}
}
@@ -279,6 +279,9 @@ namespace Barotrauma
break;
}
}
forceFluctuationTimer = Rand.Range(0.0f, ForceFluctuationInterval);
randomTriggerTimer = Rand.Range(0.0f, randomTriggerInterval);
}
private void UpdateCollisionCategories()
@@ -420,7 +423,12 @@ namespace Barotrauma
triggerers.RemoveWhere(t => t.Removed);
if (!UseNetworkSyncing || GameMain.Client == null)
bool isNotClient = true;
#if CLIENT
isNotClient = GameMain.Client == null;
#endif
if (!UseNetworkSyncing || isNotClient)
{
if (ForceFluctuationStrength > 0.0f)
{
@@ -636,14 +636,13 @@ namespace Barotrauma.RuinGeneration
foreach (RuinEntity ruinEntity in ruinEntities)
{
CreateConnections(ruinEntity);
ruinEntity.Entity.ParentRuin = this;
}
foreach (RuinEntity ruinEntity in ruinEntities)
{
if (ruinEntity.Entity is Item item)
{
foreach (ItemComponent ic in item.components)
foreach (ItemComponent ic in item.Components)
{
// Prevent wiring & interacting
if (ic is ConnectionPanel connectionPanel)
@@ -737,6 +736,11 @@ namespace Barotrauma.RuinGeneration
}
}
foreach (RuinEntity ruinEntity in ruinEntities)
{
ruinEntity.Entity.ParentRuin = this;
}
bool hullXIntersect(Rectangle rect1, Rectangle rect2)
{
return
@@ -7,7 +7,7 @@ namespace Barotrauma
partial class Location
{
public List<LocationConnection> Connections;
private string baseName;
private int nameFormatIndex;
@@ -1,14 +1,10 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
class LocationConnection
{
private Location[] locations;
private Level level;
public Biome Biome;
public float Difficulty;
@@ -17,24 +13,17 @@ namespace Barotrauma
public bool Passed;
public Level Level
{
get { return level; }
set { level = value; }
}
public Level Level { get; set; }
public Vector2 CenterPos
{
get
{
return (locations[0].MapPosition + locations[1].MapPosition) / 2.0f;
return (Locations[0].MapPosition + Locations[1].MapPosition) / 2.0f;
}
}
public Location[] Locations
{
get { return locations; }
}
public Location[] Locations { get; private set; }
public float Length
{
@@ -44,20 +33,20 @@ namespace Barotrauma
public LocationConnection(Location location1, Location location2)
{
locations = new Location[] { location1, location2 };
Locations = new Location[] { location1, location2 };
Length = Vector2.Distance(location1.MapPosition, location2.MapPosition);
}
public Location OtherLocation(Location location)
{
if (locations[0] == location)
if (Locations[0] == location)
{
return locations[1];
return Locations[1];
}
else if (locations[1] == location)
else if (Locations[1] == location)
{
return locations[0];
return Locations[0];
}
else
{
@@ -26,10 +26,9 @@ namespace Barotrauma
public Dictionary<int, float> CommonnessPerZone = new Dictionary<int, float>();
public readonly string Identifier;
public readonly string Name;
public readonly string DisplayName;
public readonly List<LocationTypeChange> CanChangeTo = new List<LocationTypeChange>();
public List<string> NameFormats
@@ -55,14 +54,9 @@ namespace Barotrauma
private LocationType(XElement element)
{
Name = element.Name.ToString();
DisplayName = element.GetAttributeString("name", "Name");
nameFormats = new List<string>();
foreach (XAttribute nameFormat in element.Element("nameformats").Attributes())
{
nameFormats.Add(nameFormat.Value);
}
Identifier = element.Name.ToString();
Name = TextManager.Get("LocationName." + Identifier);
nameFormats = TextManager.GetAll("LocationNameFormat." + Identifier);
string nameFile = element.GetAttributeString("namefile", "Content/Map/locationNames.txt");
try
@@ -71,7 +65,7 @@ namespace Barotrauma
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to read name file for location type \""+Name+"\"!", e);
DebugConsole.ThrowError("Failed to read name file for location type \""+Identifier+"\"!", e);
names = new List<string>() { "Name file not found" };
}
@@ -83,14 +77,14 @@ namespace Barotrauma
!int.TryParse(splitCommonnessPerZone[0].Trim(), out int zoneIndex) ||
!float.TryParse(splitCommonnessPerZone[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out float zoneCommonness))
{
DebugConsole.ThrowError("Failed to read commonness values for location type \"" + Name + "\" - commonness should be given in the format \"zone0index: zone0commonness, zone1index: zone1commonness\"");
DebugConsole.ThrowError("Failed to read commonness values for location type \"" + Identifier + "\" - commonness should be given in the format \"zone0index: zone0commonness, zone1index: zone1commonness\"");
break;
}
CommonnessPerZone[zoneIndex] = zoneCommonness;
}
hireableJobs = new List<Tuple<JobPrefab, float>>();
foreach (XElement subElement in element.Elements())
string nameFile = element.GetAttributeString("namefile", "Content/Map/locationNames.txt");
try
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -99,7 +93,7 @@ namespace Barotrauma
JobPrefab jobPrefab = null;
if (jobIdentifier == "")
{
DebugConsole.ThrowError("Error in location type \""+ Name + "\" - hireable jobs should be configured using identifiers instead of names.");
DebugConsole.ThrowError("Error in location type \""+ Identifier + "\" - hireable jobs should be configured using identifiers instead of names.");
jobIdentifier = subElement.GetAttributeString("name", "");
jobPrefab = JobPrefab.List.Find(jp => jp.Name.ToLowerInvariant() == jobIdentifier.ToLowerInvariant());
}
@@ -109,7 +103,7 @@ namespace Barotrauma
}
if (jobPrefab == null)
{
DebugConsole.ThrowError("Error in in location type " + Name + " - could not find a job with the identifier \"" + jobIdentifier + "\".");
DebugConsole.ThrowError("Error in in location type " + Identifier + " - could not find a job with the identifier \"" + jobIdentifier + "\".");
continue;
}
float jobCommonness = subElement.GetAttributeFloat("commonness", 1.0f);
@@ -122,7 +116,7 @@ namespace Barotrauma
SpriteColor = subElement.GetAttributeColor("color", Color.White);
break;
case "changeto":
CanChangeTo.Add(new LocationTypeChange(subElement));
CanChangeTo.Add(new LocationTypeChange(Identifier, subElement));
break;
case "portrait":
var portrait = new Sprite(subElement);
@@ -6,7 +6,7 @@ namespace Barotrauma
{
class LocationTypeChange
{
public readonly string ChangeTo;
public readonly string ChangeToType;
public readonly float Probability;
public readonly int RequiredDuration;
@@ -18,22 +18,16 @@ namespace Barotrauma
//the change can only happen if there's at least one of the given types of locations next to this one
public readonly List<string> RequiredAdjacentLocations;
public LocationTypeChange(XElement element)
public LocationTypeChange(string currentType, XElement element)
{
ChangeTo = element.GetAttributeString("type", "");
ChangeToType = element.GetAttributeString("type", "");
Probability = element.GetAttributeFloat("probability", 1.0f);
RequiredDuration = element.GetAttributeInt("requiredduration", 0);
DisallowedAdjacentLocations = element.GetAttributeStringArray("disallowedadjacentlocations", new string[0]).ToList();
RequiredAdjacentLocations = element.GetAttributeStringArray("requiredadjacentlocations", new string[0]).ToList();
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "message")
{
Messages.Add(subElement.GetAttributeString("text", ""));
}
}
Messages = TextManager.GetAll("LocationChange." + currentType + ".ChangeTo." + ChangeToType);
}
}
}
@@ -65,7 +65,7 @@ namespace Barotrauma
Vector2 center = new Vector2(size, size) / 2;
foreach (Location location in Locations)
{
if (location.Type.Name != "City") continue;
if (location.Type.Identifier != "City") continue;
float dist = Vector2.DistanceSquared(center, location.MapPosition);
if (dist > largestDist)
{
@@ -430,13 +430,6 @@ namespace Barotrauma
}
CurrentLocation.SelectedMissionIndex = missionIndex;
//the destination must be the same as the destination of the mission
if (CurrentLocation.SelectedMission != null &&
CurrentLocation.SelectedMission.Locations[1] != SelectedLocation)
{
SelectLocation(CurrentLocation.SelectedMission.Locations[1]);
}
SelectedLocation = location;
SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);
@@ -494,7 +487,7 @@ namespace Barotrauma
bool disallowedFound = false;
foreach (string disallowedLocationName in typeChange.DisallowedAdjacentLocations)
{
if (location.Connections.Any(c => c.OtherLocation(location).Type.Name.ToLowerInvariant() == disallowedLocationName.ToLowerInvariant()))
if (location.Connections.Any(c => c.OtherLocation(location).Type.Identifier.ToLowerInvariant() == disallowedLocationName.ToLowerInvariant()))
{
disallowedFound = true;
break;
@@ -506,7 +499,7 @@ namespace Barotrauma
bool requiredFound = false;
foreach (string requiredLocationName in typeChange.RequiredAdjacentLocations)
{
if (location.Connections.Any(c => c.OtherLocation(location).Type.Name.ToLowerInvariant() == requiredLocationName.ToLowerInvariant()))
if (location.Connections.Any(c => c.OtherLocation(location).Type.Identifier.ToLowerInvariant() == requiredLocationName.ToLowerInvariant()))
{
requiredFound = true;
break;
@@ -530,7 +523,7 @@ namespace Barotrauma
if (selectedTypeChange != null)
{
string prevName = location.Name;
location.ChangeType(LocationType.List.Find(lt => lt.Name.ToLowerInvariant() == selectedTypeChange.ChangeTo.ToLowerInvariant()));
location.ChangeType(LocationType.List.Find(lt => lt.Identifier.ToLowerInvariant() == selectedTypeChange.ChangeToType.ToLowerInvariant()));
ChangeLocationType(location, prevName, selectedTypeChange);
location.TypeChangeTimer = -1;
break;
@@ -584,7 +577,7 @@ namespace Barotrauma
string prevLocationName = location.Name;
LocationType prevLocationType = location.Type;
location.Discovered = true;
location.ChangeType(LocationType.List.Find(lt => lt.Name.ToLowerInvariant() == locationType.ToLowerInvariant()));
location.ChangeType(LocationType.List.Find(lt => lt.Identifier.ToLowerInvariant() == locationType.ToLowerInvariant()));
location.TypeChangeTimer = typeChangeTimer;
location.MissionsCompleted = missionsCompleted;
if (showNotifications && prevLocationType != location.Type)
@@ -592,7 +585,7 @@ namespace Barotrauma
ChangeLocationType(
location,
prevLocationName,
prevLocationType.CanChangeTo.Find(c => c.ChangeTo.ToLowerInvariant() == location.Type.Name.ToLowerInvariant()));
prevLocationType.CanChangeTo.Find(c => c.ChangeToType.ToLowerInvariant() == location.Type.Identifier.ToLowerInvariant()));
}
break;
case "connection":
@@ -617,7 +610,7 @@ namespace Barotrauma
if (!location.Discovered) continue;
var locationElement = new XElement("location", new XAttribute("i", i));
locationElement.Add(new XAttribute("type", location.Type.Name));
locationElement.Add(new XAttribute("type", location.Type.Identifier));
if (location.TypeChangeTimer > 0)
{
locationElement.Add(new XAttribute("changetimer", location.TypeChangeTimer));
@@ -287,12 +287,7 @@ namespace Barotrauma
mapEntityList.Insert(i, this);
}
public virtual bool IsVisible(Rectangle worldView)
{
return true;
}
/// <summary>
/// Remove the entity from the entity list without removing links to other entities
/// </summary>
@@ -68,30 +68,34 @@ namespace Barotrauma
private string CalculateHash(FileStream stream)
{
MD5 md5 = MD5.Create();
byte[] byteHash = md5.ComputeHash(stream);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteHash.Length; i++)
using (MD5 md5 = MD5.Create())
{
sb.Append(byteHash[i].ToString("X2"));
}
byte[] byteHash = md5.ComputeHash(stream);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteHash.Length; i++)
{
sb.Append(byteHash[i].ToString("X2"));
}
return sb.ToString();
return sb.ToString();
}
}
private string CalculateHash(byte[] bytes)
{
MD5 md5 = MD5.Create();
byte[] byteHash = md5.ComputeHash(bytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteHash.Length; i++)
using (MD5 md5 = MD5.Create())
{
sb.Append(byteHash[i].ToString("X2"));
}
byte[] byteHash = md5.ComputeHash(bytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < byteHash.Length; i++)
{
sb.Append(byteHash[i].ToString("X2"));
}
return sb.ToString();
return sb.ToString();
}
}
public static string GetShortHash(string fullHash)
@@ -47,7 +47,6 @@ namespace Barotrauma
const float LeakThreshold = 0.1f;
private StructurePrefab prefab;
private SpriteEffects SpriteEffects = SpriteEffects.None;
//dimensions of the wall sections' physics bodies (only used for debug rendering)
@@ -69,7 +68,7 @@ namespace Barotrauma
public bool IsPlatform
{
get { return prefab.Platform; }
get { return Prefab.Platform; }
}
public Direction StairDirection
@@ -85,14 +84,14 @@ namespace Barotrauma
public bool HasBody
{
get { return prefab.Body; }
get { return Prefab.Body; }
}
public List<Body> Bodies { get; private set; }
public bool CastShadow
{
get { return prefab.CastShadow; }
get { return Prefab.CastShadow; }
}
public bool IsHorizontal { get; private set; }
@@ -104,14 +103,14 @@ namespace Barotrauma
public float Health
{
get { return prefab.Health; }
get { return Prefab.Health; }
}
public override bool DrawBelowWater
{
get
{
return base.DrawBelowWater || prefab.BackgroundSprite != null;
return base.DrawBelowWater || Prefab.BackgroundSprite != null;
}
}
@@ -127,18 +126,15 @@ namespace Barotrauma
{
get
{
return prefab.Body;
return Prefab.Body;
}
}
public StructurePrefab Prefab
{
get { return prefab; }
}
public StructurePrefab Prefab => prefab as StructurePrefab;
public HashSet<string> Tags
{
get { return prefab.Tags; }
get { return prefab; }
}
protected Color spriteColor;
@@ -159,7 +155,7 @@ namespace Barotrauma
{
Rectangle oldRect = Rect;
base.Rect = value;
if (prefab.Body) CreateSections();
if (Prefab.Body) CreateSections();
else
{
foreach (WallSection sec in Sections)
@@ -179,11 +175,11 @@ namespace Barotrauma
public float BodyWidth
{
get { return prefab.BodyWidth > 0.0f ? prefab.BodyWidth : rect.Width; }
get { return Prefab.BodyWidth > 0.0f ? Prefab.BodyWidth : rect.Width; }
}
public float BodyHeight
{
get { return prefab.BodyHeight > 0.0f ? prefab.BodyHeight : rect.Height; }
get { return Prefab.BodyHeight > 0.0f ? Prefab.BodyHeight : rect.Height; }
}
/// <summary>
@@ -193,7 +189,7 @@ namespace Barotrauma
{
get
{
float rotation = MathHelper.ToRadians(prefab.BodyRotation);
float rotation = MathHelper.ToRadians(Prefab.BodyRotation);
if (FlippedX) rotation = -MathHelper.Pi - rotation;
if (FlippedY) rotation = -rotation;
return rotation;
@@ -206,7 +202,7 @@ namespace Barotrauma
{
get
{
Vector2 bodyOffset = prefab.BodyOffset;
Vector2 bodyOffset = Prefab.BodyOffset;
if (FlippedX) { bodyOffset.X = -bodyOffset.X; }
if (FlippedY) { bodyOffset.Y = -bodyOffset.Y; }
return bodyOffset;
@@ -255,7 +251,6 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(rectangle.Width > 0 && rectangle.Height > 0);
rect = rectangle;
prefab = sp;
#if CLIENT
TextureScale = sp.TextureScale;
#endif
@@ -280,11 +275,11 @@ namespace Barotrauma
}
}
StairDirection = prefab.StairDirection;
StairDirection = Prefab.StairDirection;
SerializableProperties = SerializableProperty.GetProperties(this);
if (prefab.Body)
if (Prefab.Body)
{
Bodies = new List<Body>();
WallList.Add(this);
@@ -313,11 +308,11 @@ namespace Barotrauma
public override MapEntity Clone()
{
var clone = new Structure(rect, prefab, Submarine);
var clone = new Structure(rect, Prefab, Submarine);
foreach (KeyValuePair<string, SerializableProperty> property in SerializableProperties)
{
if (!property.Value.Attributes.OfType<Editable>().Any()) continue;
clone.SerializableProperties[property.Key].TrySetValue(property.Value.GetValue());
clone.SerializableProperties[property.Key].TrySetValue(clone, property.Value.GetValue(this));
}
if (FlippedX) clone.FlipX(false);
if (FlippedY) clone.FlipY(false);
@@ -571,19 +566,9 @@ namespace Barotrauma
#endif
}
public override bool IsVisible(Rectangle worldView)
{
Rectangle worldRect = WorldRect;
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) return false;
if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) return false;
return true;
}
private bool OnWallCollision(Fixture f1, Fixture f2, Contact contact)
{
if (prefab.Platform)
if (Prefab.Platform)
{
if (f2.Body.UserData is Limb limb)
{
@@ -597,7 +582,7 @@ namespace Barotrauma
if (character.DisableImpactDamageTimer > 0.0f || ((Limb)f2.Body.UserData).Mass < 100.0f) return true;
}
if (!prefab.Platform && prefab.StairDirection == Direction.None)
if (!Prefab.Platform && Prefab.StairDirection == Direction.None)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(f2.Body.Position);
@@ -631,7 +616,7 @@ namespace Barotrauma
{
if (sectionIndex < 0 || sectionIndex >= Sections.Length) return false;
return (Sections[sectionIndex].damage >= prefab.Health);
return (Sections[sectionIndex].damage >= Prefab.Health);
}
/// <summary>
@@ -641,7 +626,7 @@ namespace Barotrauma
{
if (sectionIndex < 0 || sectionIndex >= Sections.Length) return false;
return (Sections[sectionIndex].damage >= prefab.Health * LeakThreshold);
return (Sections[sectionIndex].damage >= Prefab.Health * LeakThreshold);
}
public int SectionLength(int sectionIndex)
@@ -653,7 +638,7 @@ namespace Barotrauma
public void AddDamage(int sectionIndex, float damage, Character attacker = null)
{
if (!prefab.Body || prefab.Platform || Indestructible) return;
if (!Prefab.Body || Prefab.Platform || Indestructible) return;
if (sectionIndex < 0 || sectionIndex > Sections.Length - 1) return;
@@ -676,7 +661,14 @@ namespace Barotrauma
}
#endif
if (GameMain.Client == null) SetDamage(sectionIndex, section.damage + damage, attacker);
#if CLIENT
if (GameMain.Client == null)
{
#endif
SetDamage(sectionIndex, section.damage + damage, attacker);
#if CLIENT
}
#endif
}
public int FindSectionIndex(Vector2 displayPos, bool world = false, bool clamp = false)
@@ -721,7 +713,7 @@ namespace Barotrauma
{
if (sectionIndex < 0 || sectionIndex >= Sections.Length) return Vector2.Zero;
if (prefab.BodyRotation == 0.0f)
if (Prefab.BodyRotation == 0.0f)
{
Vector2 sectionPos = new Vector2(
Sections[sectionIndex].rect.X + Sections[sectionIndex].rect.Width / 2.0f,
@@ -754,31 +746,12 @@ namespace Barotrauma
}
private void AdjustKarma(IDamageable attacker, float amount)
{
if (GameMain.Server != null)
{
if (Submarine == null) return;
if (attacker == null) return;
if (attacker is Character)
{
Character attackerCharacter = attacker as Character;
Barotrauma.Networking.Client attackerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == attackerCharacter);
if (attackerClient != null)
{
if (attackerCharacter.TeamID == Submarine.TeamID)
{
attackerClient.Karma -= amount * 0.001f;
}
}
}
}
}
partial void AdjustKarma(IDamageable attacker, float amount);
public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = false)
{
if (Submarine != null && Submarine.GodMode) return new AttackResult(0.0f, null);
if (!prefab.Body || prefab.Platform || Indestructible) return new AttackResult(0.0f, null);
if (!Prefab.Body || Prefab.Platform || Indestructible) return new AttackResult(0.0f, null);
Vector2 transformedPos = worldPosition;
if (Submarine != null) transformedPos -= Submarine.Position;
@@ -811,16 +784,16 @@ namespace Barotrauma
private void SetDamage(int sectionIndex, float damage, Character attacker = null, bool createNetworkEvent = true)
{
if (Submarine != null && Submarine.GodMode || Indestructible) return;
if (!prefab.Body) return;
if (!Prefab.Body) return;
if (!MathUtils.IsValid(damage)) return;
damage = MathHelper.Clamp(damage, 0.0f, prefab.Health);
damage = MathHelper.Clamp(damage, 0.0f, Prefab.Health);
#if SERVER
if (GameMain.Server != null && createNetworkEvent && damage != Sections[sectionIndex].damage)
{
GameMain.Server.CreateEntityEvent(this);
}
bool noGaps = true;
for (int i = 0; i < Sections.Length; i++)
{
@@ -830,17 +803,20 @@ namespace Barotrauma
break;
}
}
#endif
if (damage < prefab.Health * LeakThreshold)
if (damage < Prefab.Health * LeakThreshold)
{
if (Sections[sectionIndex].gap != null)
{
#if SERVER
//the structure doesn't have any other gap, log the structure being fixed
if (noGaps && attacker != null)
{
GameServer.Log((Sections[sectionIndex].gap.IsRoomToRoom ? "Inner" : "Outer") + " wall repaired by " + attacker.Name, ServerLog.MessageType.ItemInteraction);
}
#endif
DebugConsole.Log("Removing gap (ID " + Sections[sectionIndex].gap.ID + ", section: " + sectionIndex + ") from wall " + ID);
//remove existing gap if damage is below leak threshold
@@ -884,7 +860,7 @@ namespace Barotrauma
gapRect.Height += 20;
bool horizontalGap = !IsHorizontal;
if (prefab.BodyRotation != 0.0f)
if (Prefab.BodyRotation != 0.0f)
{
//rotation within a 90 deg sector (e.g. 100 -> 10, 190 -> 10, -10 -> 80)
float sectorizedRotation = MathUtils.WrapAngleTwoPi(BodyRotation) % MathHelper.PiOver2;
@@ -908,31 +884,40 @@ namespace Barotrauma
DebugConsole.Log("Created gap (ID " + Sections[sectionIndex].gap.ID + ", section: " + sectionIndex + ") on wall " + ID);
//AdjustKarma(attacker, 300);
#if SERVER
//the structure didn't have any other gaps yet, log the breach
if (noGaps && attacker != null)
{
GameServer.Log((Sections[sectionIndex].gap.IsRoomToRoom ? "Inner" : "Outer") + " wall breached by " + attacker.Name, ServerLog.MessageType.ItemInteraction);
}
#endif
}
float gapOpen = (damage / prefab.Health - LeakThreshold) * (1.0f / (1.0f - LeakThreshold));
float gapOpen = (damage / Prefab.Health - LeakThreshold) * (1.0f / (1.0f - LeakThreshold));
Sections[sectionIndex].gap.Open = gapOpen;
}
float damageDiff = damage - Sections[sectionIndex].damage;
bool hadHole = SectionBodyDisabled(sectionIndex);
Sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, prefab.Health);
Sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, Prefab.Health);
//otherwise it's possible to infinitely gain karma by welding fixed things
if (attacker != null && damageDiff != 0.0f)
{
AdjustKarma(attacker, damageDiff);
if (damageDiff < 0.0f && GameMain.Client == null)
#if CLIENT
if (GameMain.Client == null)
{
attacker.Info.IncreaseSkillLevel("mechanical",
-damageDiff * SkillIncreaseMultiplier / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f),
SectionPosition(sectionIndex, true));
#endif
if (damageDiff < 0.0f)
{
attacker.Info.IncreaseSkillLevel("mechanical",
-damageDiff * SkillIncreaseMultiplier / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f),
SectionPosition(sectionIndex, true));
}
#if CLIENT
}
#endif
}
bool hasHole = SectionBodyDisabled(sectionIndex);
@@ -1018,7 +1003,7 @@ namespace Barotrauma
}
if (FlippedX) diffFromCenter = -diffFromCenter;
Vector2 bodyOffset = ConvertUnits.ToSimUnits(prefab.BodyOffset);
Vector2 bodyOffset = ConvertUnits.ToSimUnits(Prefab.BodyOffset);
if (FlippedX) { bodyOffset.X = -bodyOffset.X; }
if (FlippedY) { bodyOffset.Y = -bodyOffset.Y; }
@@ -1030,7 +1015,7 @@ namespace Barotrauma
//newBody.Position = ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2.0f, rect.Y - rect.Height / 2.0f));
newBody.Friction = 0.5f;
newBody.OnCollision += OnWallCollision;
newBody.CollisionCategories = (prefab.Platform) ? Physics.CollisionPlatform : Physics.CollisionWall;
newBody.CollisionCategories = (Prefab.Platform) ? Physics.CollisionPlatform : Physics.CollisionWall;
newBody.UserData = this;
Vector2 structureCenter = ConvertUnits.ToSimUnits(Position);
@@ -1059,27 +1044,11 @@ namespace Barotrauma
partial void CreateConvexHull(Vector2 position, Vector2 size, float rotation);
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
for (int i = 0; i < Sections.Length; i++)
{
msg.WriteRangedSingle(Sections[i].damage / Health, 0.0f, 1.0f, 8);
}
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
for (int i = 0; i < Sections.Length; i++)
{
float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * Health;
SetDamage(i, damage);
}
}
public override void FlipX(bool relativeToSub)
{
base.FlipX(relativeToSub);
if (prefab.CanSpriteFlipX)
if (Prefab.CanSpriteFlipX)
{
SpriteEffects ^= SpriteEffects.FlipHorizontally;
}
@@ -1105,7 +1074,7 @@ namespace Barotrauma
{
base.FlipY(relativeToSub);
if (prefab.CanSpriteFlipY)
if (Prefab.CanSpriteFlipY)
{
SpriteEffects ^= SpriteEffects.FlipVertically;
}
@@ -32,7 +32,7 @@ namespace Barotrauma
partial class Submarine : Entity, IServerSerializable
{
public byte TeamID = 1;
public Character.TeamType TeamID = Character.TeamType.None;
public static string SavePath = "Submarines";
@@ -109,6 +109,12 @@ namespace Barotrauma
set { name = value; }
}
private string displayName;
public string DisplayName
{
get { return displayName; }
}
public bool ShowSonarMarker = true;
public string Description
@@ -316,7 +322,12 @@ namespace Barotrauma
if (doc != null && doc.Root != null)
{
Description = doc.Root.GetAttributeString("description", "");
displayName = TextManager.Get("Submarine.Name." + name, true);
if (displayName == null || displayName.Length == 0) displayName = name;
Description = TextManager.Get("Submarine.Description." + name, true);
if (Description == null || Description.Length == 0) Description = doc.Root.GetAttributeString("description", "");
GameVersion = new Version(doc.Root.GetAttributeString("gameversion", "0.0.0.0"));
Enum.TryParse(doc.Root.GetAttributeString("tags", ""), out tags);
Dimensions = doc.Root.GetAttributeVector2("dimensions", Vector2.Zero);
@@ -397,7 +408,7 @@ namespace Barotrauma
if (me is Item item)
{
item.Indestructible = true;
foreach (ItemComponent ic in item.components)
foreach (ItemComponent ic in item.Components)
{
if (ic is ConnectionPanel connectionPanel)
{
@@ -507,6 +518,8 @@ namespace Barotrauma
{
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
}
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
}
if (minX < 0.0f && maxX > Level.Loaded.Size.X)
@@ -533,71 +546,6 @@ namespace Barotrauma
return spawnPos - diffFromDockedBorders;
}
//drawing ----------------------------------------------------
public static void CullEntities(Camera cam)
{
HashSet<Submarine> visibleSubs = new HashSet<Submarine>();
foreach (Submarine sub in Loaded)
{
if (sub.WorldPosition.Y < Level.MaxEntityDepth) continue;
Rectangle worldBorders = new Rectangle(
sub.Borders.X + (int)sub.WorldPosition.X - 500,
sub.Borders.Y + (int)sub.WorldPosition.Y + 500,
sub.Borders.Width + 1000,
sub.Borders.Height + 1000);
if (RectsOverlap(worldBorders, cam.WorldView))
{
visibleSubs.Add(sub);
}
}
HashSet<Ruin> visibleRuins = new HashSet<Ruin>();
if (Level.Loaded != null)
{
foreach (Ruin ruin in Level.Loaded.Ruins)
{
Rectangle worldBorders = new Rectangle(
ruin.Area.X - 500,
ruin.Area.Y + ruin.Area.Height + 500,
ruin.Area.Width + 1000,
ruin.Area.Height + 1000);
if (RectsOverlap(worldBorders, cam.WorldView))
{
visibleRuins.Add(ruin);
}
}
}
if (visibleEntities == null)
{
visibleEntities = new List<MapEntity>(MapEntity.mapEntityList.Count);
}
else
{
visibleEntities.Clear();
}
Rectangle worldView = cam.WorldView;
foreach (MapEntity entity in MapEntity.mapEntityList)
{
if (entity.Submarine != null)
{
if (!visibleSubs.Contains(entity.Submarine)) { continue; }
}
else if(entity.ParentRuin != null)
{
if (!visibleRuins.Contains(entity.ParentRuin)) { continue; }
}
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
}
}
public void UpdateTransform()
{
DrawPosition = Timing.Interpolate(prevPosition, Position);
@@ -751,7 +699,50 @@ namespace Barotrauma
return closestBody;
}
public static List<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, List<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null)
{
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f)
{
rayEnd += Vector2.UnitX * 0.001f;
}
float closestFraction = 1.0f;
List<Body> bodies = new List<Body>();
GameMain.World.RayCast((fixture, point, normal, fraction) =>
{
if (fixture == null ||
(ignoreSensors && fixture.IsSensor) ||
fixture.CollisionCategories == Category.None ||
fixture.CollisionCategories == Physics.CollisionItem) return -1;
if (customPredicate != null && !customPredicate(fixture)) return -1;
if (collisionCategory != null &&
!fixture.CollisionCategories.HasFlag((Category)collisionCategory) &&
!((Category)collisionCategory).HasFlag(fixture.CollisionCategories)) return -1;
if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body)) return -1;
if (fixture.Body.UserData is Structure structure)
{
if (structure.IsPlatform && collisionCategory != null && !((Category)collisionCategory).HasFlag(Physics.CollisionPlatform)) return -1;
}
bodies.Add(fixture.Body);
if (fraction < closestFraction)
{
lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction;
lastPickedFraction = fraction;
lastPickedNormal = normal;
}
return fraction;
}, rayStart, rayEnd);
return bodies;
}
/// <summary>
/// check visibility between two points (in sim units)
/// </summary>
@@ -1438,16 +1429,6 @@ namespace Barotrauma
PreviewImage = null;
#endif
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(ID);
//length in bytes
msg.Write((byte)(4 + 4));
msg.Write(PhysicsBody.SimPosition.X);
msg.Write(PhysicsBody.SimPosition.Y);
}
}
}
@@ -14,7 +14,7 @@ using Voronoi2;
namespace Barotrauma
{
class SubmarineBody
partial class SubmarineBody
{
public const float NeutralBallastPercentage = 0.07f;
@@ -39,7 +39,7 @@ namespace Barotrauma
public readonly PhysicsBody Body;
private List<PosInfo> memPos = new List<PosInfo>();
private List<PosInfo> positionBuffer = new List<PosInfo>();
public Rectangle Borders
{
@@ -62,9 +62,9 @@ namespace Barotrauma
get { return ConvertUnits.ToDisplayUnits(Body.SimPosition); }
}
public List<PosInfo> MemPos
public List<PosInfo> PositionBuffer
{
get { return memPos; }
get { return positionBuffer; }
}
public bool AtDamageDepth
@@ -246,58 +246,8 @@ namespace Barotrauma
{
if (Body.FarseerBody.IsStatic) { return; }
if (GameMain.Client != null)
{
if (memPos.Count == 0) return;
Vector2 newVelocity = Body.LinearVelocity;
Vector2 newPosition = Body.SimPosition;
Body.CorrectPosition(memPos, deltaTime, out newVelocity, out newPosition);
Vector2 moveAmount = ConvertUnits.ToDisplayUnits(newPosition - Body.SimPosition);
newVelocity = newVelocity.ClampLength(100.0f);
if (!MathUtils.IsValid(newVelocity))
{
return;
}
List<Submarine> subsToMove = submarine.GetConnectedSubs();
foreach (Submarine dockedSub in subsToMove)
{
if (dockedSub == submarine) continue;
//clear the position buffer of the docked subs to prevent unnecessary position corrections
dockedSub.SubBody.memPos.Clear();
}
Submarine closestSub = null;
if (Character.Controlled == null)
{
closestSub = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);
}
else
{
closestSub = Character.Controlled.Submarine;
}
bool displace = moveAmount.LengthSquared() > 100.0f * 100.0f;
foreach (Submarine sub in subsToMove)
{
sub.PhysicsBody.SetTransform(sub.PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(moveAmount), 0.0f);
sub.PhysicsBody.LinearVelocity = newVelocity;
if (displace) sub.SubBody.DisplaceCharacters(moveAmount);
}
if (closestSub != null && subsToMove.Contains(closestSub))
{
GameMain.GameScreen.Cam.Position += moveAmount;
if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero) GameMain.GameScreen.Cam.TargetPos += moveAmount;
if (Character.Controlled != null) Character.Controlled.CursorPosition += moveAmount;
}
return;
}
ClientUpdatePosition(deltaTime);
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
//if outside left or right edge of the level
if (Position.X < 0 || Position.X > Level.Loaded.Size.X)
@@ -348,7 +298,9 @@ namespace Barotrauma
UpdateDepthDamage(deltaTime);
}
partial void ClientUpdatePosition(float deltaTime);
/// <summary>
/// Moves away any character that is inside the bounding box of the sub (but not inside the sub)
/// </summary>
@@ -537,10 +489,10 @@ namespace Barotrauma
float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 50.0f) / 5.0f * Math.Min(limb.Mass / 200.0f, 1);
ApplyImpact(impact, -normal, contact);
ApplyImpact(impact, -normal, contact, applyDamage: false);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(impact, -normal, contact);
dockedSub.SubBody.ApplyImpact(impact, -normal, contact, applyDamage: false);
}
}
@@ -581,7 +533,7 @@ namespace Barotrauma
avgContactNormal += contactNormal;
//apply impacts at the positions where this sub is touching the limb
ApplyImpact((Vector2.Dot(-Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, levelContact);
ApplyImpact((Vector2.Dot(-Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, levelContact, applyDamage: false);
}
avgContactNormal /= levelContacts.Count;
@@ -736,9 +688,11 @@ namespace Barotrauma
}
}
private void ApplyImpact(float impact, Vector2 direction, Contact contact)
private void ApplyImpact(float impact, Vector2 direction, Contact contact, bool applyDamage = true)
{
if (impact < 3.0f) return;
float minImpact = 3.0f;
if (impact < minImpact) { return; }
contact.GetWorldManifold(out Vector2 tempNormal, out FixedArray2<Vector2> worldPoints);
Vector2 lastContactPoint = worldPoints[0];
@@ -776,14 +730,17 @@ namespace Barotrauma
item.body.ApplyLinearImpulse(item.body.Mass * impulse, 20.0f);
}
var damagedStructures = Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * ImpactDamageMultiplier);
var damagedStructures = Explosion.RangedStructureDamage(
ConvertUnits.ToDisplayUnits(lastContactPoint),
impact * 50.0f,
applyDamage ? impact * ImpactDamageMultiplier : 0.0f);
#if CLIENT
//play a damage sound for the structure that took the most damage
float maxDamage = 0.0f;
Structure maxDamageStructure = null;
foreach (KeyValuePair<Structure,float> structureDamage in damagedStructures)
foreach (KeyValuePair<Structure, float> structureDamage in damagedStructures)
{
if (maxDamageStructure == null || structureDamage.Value > maxDamage)
{
@@ -798,7 +755,7 @@ namespace Barotrauma
"StructureBlunt",
impact * 10.0f,
ConvertUnits.ToDisplayUnits(lastContactPoint),
MathHelper.Clamp(maxDamage * 4.0f, 2000.0f, 10000.0f),
MathHelper.Lerp(2000.0f, 10000.0f, (impact - minImpact) / 2.0f),
maxDamageStructure.Tags);
}
#endif