Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git
This commit is contained in:
@@ -18,8 +18,8 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
public readonly BallastFloraBehavior? ParentBallastFlora;
|
||||
public int ID = -1;
|
||||
|
||||
public ushort ClaimedItem;
|
||||
public bool HasClaimedItem;
|
||||
public Item ClaimedItem;
|
||||
public int ClaimedItemId = -1;
|
||||
|
||||
public float MaxHealth = 100f;
|
||||
public float Health = 100f;
|
||||
@@ -271,10 +271,29 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
{
|
||||
ClaimTarget(item, Branches.FirstOrDefault(b => b.ID == branchid), true);
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMsg = $"Error in BallastFloraBehavior.OnMapLoaded: could not find the item claimed by the ballast flora.";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("BallastFloraBehavior.OnMapLoaded:ClaimedItemNotFound", GameAnalyticsManager.ErrorSeverity.Warning, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (branch.ClaimedItemId > -1)
|
||||
{
|
||||
if (Entity.FindEntityByID((ushort)branch.ClaimedItemId) is Item item)
|
||||
{
|
||||
branch.ClaimedItem = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
string errorMsg = $"Error in BallastFloraBehavior.OnMapLoaded: could not find the item claimed by a branch.";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("BallastFloraBehavior.OnMapLoaded:BranchClaimedItemNotFound", GameAnalyticsManager.ErrorSeverity.Warning, errorMsg);
|
||||
}
|
||||
}
|
||||
UpdateConnections(branch);
|
||||
CreateBody(branch);
|
||||
}
|
||||
@@ -335,9 +354,9 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
new XAttribute("sides", (int)branch.Sides),
|
||||
new XAttribute("blockedsides", (int)branch.BlockedSides));
|
||||
|
||||
if (branch.HasClaimedItem)
|
||||
if (branch.ClaimedItem != null)
|
||||
{
|
||||
be.Add(new XAttribute("claimed", (int)branch.ClaimedItem));
|
||||
be.Add(new XAttribute("claimed", (int)(branch.ClaimedItem?.ID ?? -1)));
|
||||
}
|
||||
|
||||
saveElement.Add(be);
|
||||
@@ -345,6 +364,13 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
foreach (Item target in ClaimedTargets)
|
||||
{
|
||||
if (target.Infector == null)
|
||||
{
|
||||
string errorMsg = $"Error in BallastFloraBehavior.Save: claimed target \"{target.Prefab.Identifier}\" had no infector set.";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("BallastFloraBehavior.Save:InfectorNull", GameAnalyticsManager.ErrorSeverity.Warning, errorMsg);
|
||||
continue;
|
||||
}
|
||||
XElement te = new XElement("ClaimedTarget", new XAttribute("id", target.ID), new XAttribute("branchId", target.Infector.ID));
|
||||
saveElement.Add(te);
|
||||
}
|
||||
@@ -352,7 +378,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
element.Add(saveElement);
|
||||
}
|
||||
|
||||
public void LoadSave(XElement element)
|
||||
public void LoadSave(XElement element, IdRemap idRemap)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
Offset = element.GetAttributeVector2("offset", Vector2.Zero);
|
||||
@@ -361,21 +387,20 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "branch":
|
||||
LoadBranch(subElement);
|
||||
LoadBranch(subElement, idRemap);
|
||||
break;
|
||||
|
||||
case "claimedtarget":
|
||||
int id = subElement.GetAttributeInt("id", -1);
|
||||
int branchId = subElement.GetAttributeInt("branchId", -1);
|
||||
if (id > 0)
|
||||
{
|
||||
tempClaimedTargets.Add(Tuple.Create((UInt16)id, branchId));
|
||||
tempClaimedTargets.Add(Tuple.Create(idRemap.GetOffsetId(id), branchId));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void LoadBranch(XElement branchElement)
|
||||
void LoadBranch(XElement branchElement, IdRemap idRemap)
|
||||
{
|
||||
Vector2 pos = branchElement.GetAttributeVector2("pos", Vector2.Zero);
|
||||
bool isRoot = branchElement.GetAttributeBool("isroot", false);
|
||||
@@ -400,8 +425,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
if (claimedId > -1)
|
||||
{
|
||||
newBranch.HasClaimedItem = true;
|
||||
newBranch.ClaimedItem = (ushort) claimedId;
|
||||
newBranch.ClaimedItemId = idRemap.GetOffsetId((ushort)claimedId);
|
||||
}
|
||||
|
||||
Branches.Add(newBranch);
|
||||
@@ -767,8 +791,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
if (branch != null)
|
||||
{
|
||||
branch.ClaimedItem = target.ID;
|
||||
branch.HasClaimedItem = true;
|
||||
branch.ClaimedItem = target;
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
@@ -794,7 +817,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
if (otherBranch.BlockedSides.IsBitSet(connectingSide))
|
||||
if (otherBranch.BlockedSides.HasFlag(connectingSide))
|
||||
{
|
||||
branch.BlockedSides |= oppositeSide;
|
||||
continue;
|
||||
@@ -977,7 +1000,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
|
||||
if (isClient) { return; }
|
||||
|
||||
if (branch.HasClaimedItem)
|
||||
if (branch.ClaimedItem != null)
|
||||
{
|
||||
RemoveClaim(branch.ClaimedItem);
|
||||
}
|
||||
@@ -995,41 +1018,34 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
#endif
|
||||
}
|
||||
|
||||
public void RemoveClaim(ushort id)
|
||||
public void RemoveClaim(Item item)
|
||||
{
|
||||
ClaimedTargets.ForEachMod(item =>
|
||||
if (!IgnoredTargets.ContainsKey(item))
|
||||
{
|
||||
if (item.ID == id)
|
||||
IgnoredTargets.Add(item, 10);
|
||||
}
|
||||
|
||||
ClaimedTargets.Remove(item);
|
||||
item.Infector = null;
|
||||
|
||||
ClaimedJunctionBoxes.ForEachMod(jb =>
|
||||
{
|
||||
if (jb.Item == item)
|
||||
{
|
||||
if (!IgnoredTargets.ContainsKey(item))
|
||||
{
|
||||
IgnoredTargets.Add(item, 10);
|
||||
}
|
||||
|
||||
ClaimedTargets.Remove(item);
|
||||
item.Infector = null;
|
||||
|
||||
ClaimedJunctionBoxes.ForEachMod(jb =>
|
||||
{
|
||||
if (jb.Item == item)
|
||||
{
|
||||
ClaimedJunctionBoxes.Remove(jb);
|
||||
}
|
||||
});
|
||||
|
||||
ClaimedBatteries.ForEachMod(bat =>
|
||||
{
|
||||
if (bat.Item == item)
|
||||
{
|
||||
ClaimedBatteries.Remove(bat);
|
||||
}
|
||||
});
|
||||
|
||||
#if SERVER
|
||||
SendNetworkMessage(this, NetworkHeader.Infect, item.ID, false);
|
||||
#endif
|
||||
ClaimedJunctionBoxes.Remove(jb);
|
||||
}
|
||||
});
|
||||
|
||||
ClaimedBatteries.ForEachMod(bat =>
|
||||
{
|
||||
if (bat.Item == item)
|
||||
{
|
||||
ClaimedBatteries.Remove(bat);
|
||||
}
|
||||
});
|
||||
#if SERVER
|
||||
SendNetworkMessage(this, NetworkHeader.Infect, item.ID, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Kill()
|
||||
|
||||
@@ -68,10 +68,9 @@ namespace Barotrauma
|
||||
|
||||
force = element.GetAttributeFloat("force", 0.0f);
|
||||
|
||||
abilityExplosion = element.GetAttributeBool("abilityexplosion", false);
|
||||
applyToSelf = element.GetAttributeBool("applytoself", true);
|
||||
|
||||
bool showEffects = !abilityExplosion;
|
||||
bool showEffects = !element.GetAttributeBool("abilityexplosion", false) && element.GetAttributeBool("showeffects", true);
|
||||
sparks = element.GetAttributeBool("sparks", showEffects);
|
||||
shockwave = element.GetAttributeBool("shockwave", showEffects);
|
||||
flames = element.GetAttributeBool("flames", showEffects);
|
||||
@@ -151,7 +150,7 @@ namespace Barotrauma
|
||||
|
||||
if (!MathUtils.NearlyEqual(Attack.GetStructureDamage(1.0f), 0.0f) || !MathUtils.NearlyEqual(Attack.GetLevelWallDamage(1.0f), 0.0f))
|
||||
{
|
||||
RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker, IgnoredSubmarines);
|
||||
RangedStructureDamage(worldPosition, displayRange, Attack.GetStructureDamage(1.0f), Attack.GetLevelWallDamage(1.0f), attacker, IgnoredSubmarines, Attack.EmitStructureDamageParticles);
|
||||
}
|
||||
|
||||
if (BallastFloraDamage > 0.0f)
|
||||
@@ -388,7 +387,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (damages.TryGetValue(limb, out float damage))
|
||||
{
|
||||
c.TrySeverLimbJoints(limb, attack.SeverLimbsProbability * distFactor, damage, allowBeheading: true);
|
||||
c.TrySeverLimbJoints(limb, attack.SeverLimbsProbability * distFactor, damage, allowBeheading: true, attacker: attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,13 +395,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<Structure> damagedStructureList = new List<Structure>();
|
||||
private static readonly Dictionary<Structure, float> damagedStructures = new Dictionary<Structure, float>();
|
||||
/// <summary>
|
||||
/// Returns a dictionary where the keys are the structures that took damage and the values are the amount of damage taken
|
||||
/// </summary>
|
||||
public static Dictionary<Structure, float> RangedStructureDamage(Vector2 worldPosition, float worldRange, float damage, float levelWallDamage, Character attacker = null, IEnumerable<Submarine> ignoredSubmarines = null)
|
||||
public static Dictionary<Structure, float> RangedStructureDamage(Vector2 worldPosition, float worldRange, float damage, float levelWallDamage, Character attacker = null, IEnumerable<Submarine> ignoredSubmarines = null, bool emitWallDamageParticles = true)
|
||||
{
|
||||
List<Structure> structureList = new List<Structure>();
|
||||
float dist = 600.0f;
|
||||
damagedStructureList.Clear();
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
{
|
||||
if (!(entity is Structure structure)) { continue; }
|
||||
@@ -412,19 +413,19 @@ namespace Barotrauma
|
||||
!structure.IsPlatform &&
|
||||
Vector2.Distance(structure.WorldPosition, worldPosition) < dist * 3.0f)
|
||||
{
|
||||
structureList.Add(structure);
|
||||
damagedStructureList.Add(structure);
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<Structure, float> damagedStructures = new Dictionary<Structure, float>();
|
||||
foreach (Structure structure in structureList)
|
||||
damagedStructures.Clear();
|
||||
foreach (Structure structure in damagedStructureList)
|
||||
{
|
||||
for (int i = 0; i < structure.SectionCount; i++)
|
||||
{
|
||||
float distFactor = 1.0f - (Vector2.Distance(structure.SectionPosition(i, true), worldPosition) / worldRange);
|
||||
if (distFactor <= 0.0f) { continue; }
|
||||
|
||||
structure.AddDamage(i, damage * distFactor, attacker);
|
||||
structure.AddDamage(i, damage * distFactor, attacker, emitParticles: emitWallDamageParticles);
|
||||
|
||||
if (damagedStructures.ContainsKey(structure))
|
||||
{
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace Barotrauma
|
||||
Hull hull2 = linkedTo.Count < 2 ? null : (Hull)linkedTo[1];
|
||||
if (hull1 == hull2) { return; }
|
||||
|
||||
UpdateOxygen(hull1, hull2);
|
||||
UpdateOxygen(hull1, hull2, deltaTime);
|
||||
|
||||
if (linkedTo.Count == 1)
|
||||
{
|
||||
@@ -317,7 +317,7 @@ namespace Barotrauma
|
||||
|
||||
flowForce.X = MathHelper.Clamp(flowForce.X, -MaxFlowForce, MaxFlowForce);
|
||||
flowForce.Y = MathHelper.Clamp(flowForce.Y, -MaxFlowForce, MaxFlowForce);
|
||||
if (openedTimer > 0.0f && flowForce.Length() > lerpedFlowForce.Length())
|
||||
if (openedTimer > 0.0f && flowForce.LengthSquared() > lerpedFlowForce.LengthSquared())
|
||||
{
|
||||
//if the gap has just been opened/created, allow it to exert a large force instantly without any smoothing
|
||||
lerpedFlowForce = flowForce;
|
||||
@@ -326,6 +326,15 @@ namespace Barotrauma
|
||||
{
|
||||
lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, deltaTime * 5.0f);
|
||||
}
|
||||
if (FlowTargetHull != null && IsRoomToRoom)
|
||||
{
|
||||
var otherRoom = linkedTo[1] == FlowTargetHull ? linkedTo[0] : linkedTo[1];
|
||||
if ((otherRoom as Hull).Volume < FlowTargetHull.Volume)
|
||||
{
|
||||
lerpedFlowForce = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
openedTimer -= deltaTime;
|
||||
|
||||
EmitParticles(deltaTime);
|
||||
@@ -345,7 +354,7 @@ namespace Barotrauma
|
||||
subOffset = hull2.Submarine.Position - Submarine.Position;
|
||||
}
|
||||
|
||||
if (hull1.WaterVolume <= 0.0 && hull2.WaterVolume <= 0.0) return;
|
||||
if (hull1.WaterVolume <= 0.0 && hull2.WaterVolume <= 0.0) { return; }
|
||||
|
||||
float size = IsHorizontal ? rect.Height : rect.Width;
|
||||
|
||||
@@ -367,7 +376,7 @@ namespace Barotrauma
|
||||
//water flowing from the righthand room to the lefthand room
|
||||
if (dir == -1)
|
||||
{
|
||||
if (!(hull2.WaterVolume > 0.0f)) return;
|
||||
if (!(hull2.WaterVolume > 0.0f)) { return; }
|
||||
lowerSurface = hull1.Surface - hull1.WaveY[hull1.WaveY.Length - 1];
|
||||
//delta = Math.Min((room2.water.pressure - room1.water.pressure) * sizeModifier, Math.Min(room2.water.Volume, room2.Volume));
|
||||
//delta = Math.Min(delta, room1.Volume - room1.water.Volume + Water.MaxCompress);
|
||||
@@ -375,10 +384,10 @@ namespace Barotrauma
|
||||
flowTargetHull = hull1;
|
||||
|
||||
//make sure not to move more than what the room contains
|
||||
delta = Math.Min(((hull2.Pressure + subOffset.Y) - hull1.Pressure) * 5.0f * sizeModifier, Math.Min(hull2.WaterVolume, hull2.Volume));
|
||||
delta = Math.Min(((hull2.Pressure + subOffset.Y) - hull1.Pressure) * 300.0f * sizeModifier * deltaTime, Math.Min(hull2.WaterVolume, hull2.Volume));
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull1.Volume * Hull.MaxCompress - (hull1.WaterVolume));
|
||||
delta = Math.Min(delta, hull1.Volume * Hull.MaxCompress - hull1.WaterVolume);
|
||||
hull1.WaterVolume += delta;
|
||||
hull2.WaterVolume -= delta;
|
||||
if (hull1.WaterVolume > hull1.Volume)
|
||||
@@ -386,20 +395,20 @@ namespace Barotrauma
|
||||
hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure+subOffset.Y) / 2);
|
||||
}
|
||||
|
||||
flowForce = new Vector2(-delta, 0.0f);
|
||||
flowForce = new Vector2(-delta * (float)(Timing.Step / deltaTime), 0.0f);
|
||||
}
|
||||
else if (dir == 1)
|
||||
{
|
||||
if (!(hull1.WaterVolume > 0.0f)) return;
|
||||
if (!(hull1.WaterVolume > 0.0f)) { return; }
|
||||
lowerSurface = hull2.Surface - hull2.WaveY[hull2.WaveY.Length - 1];
|
||||
|
||||
flowTargetHull = hull2;
|
||||
|
||||
//make sure not to move more than what the room contains
|
||||
delta = Math.Min((hull1.Pressure - (hull2.Pressure + subOffset.Y)) * 5.0f * sizeModifier, Math.Min(hull1.WaterVolume, hull1.Volume));
|
||||
delta = Math.Min((hull1.Pressure - (hull2.Pressure + subOffset.Y)) * 300.0f * sizeModifier * deltaTime, Math.Min(hull1.WaterVolume, hull1.Volume));
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull2.Volume * Hull.MaxCompress - (hull2.WaterVolume));
|
||||
delta = Math.Min(delta, hull2.Volume * Hull.MaxCompress - hull2.WaterVolume);
|
||||
hull1.WaterVolume -= delta;
|
||||
hull2.WaterVolume += delta;
|
||||
if (hull2.WaterVolume > hull2.Volume)
|
||||
@@ -407,10 +416,10 @@ namespace Barotrauma
|
||||
hull2.Pressure = Math.Max(hull2.Pressure, ((hull1.Pressure-subOffset.Y) + hull2.Pressure) / 2);
|
||||
}
|
||||
|
||||
flowForce = new Vector2(delta, 0.0f);
|
||||
flowForce = new Vector2(delta * (float)(Timing.Step / deltaTime), 0.0f);
|
||||
}
|
||||
|
||||
if (delta > 100.0f && subOffset == Vector2.Zero)
|
||||
if (delta > 1.5f && subOffset == Vector2.Zero)
|
||||
{
|
||||
float avg = (hull1.Surface + hull2.Surface) / 2.0f;
|
||||
|
||||
@@ -450,7 +459,7 @@ namespace Barotrauma
|
||||
|
||||
flowForce = new Vector2(
|
||||
0.0f,
|
||||
Math.Min(Math.Min((hull2.Pressure + subOffset.Y) - hull1.Pressure, 200.0f), delta));
|
||||
Math.Min(Math.Min((hull2.Pressure + subOffset.Y) - hull1.Pressure, 200.0f), delta * (float)(Timing.Step / deltaTime)));
|
||||
|
||||
flowTargetHull = hull1;
|
||||
|
||||
@@ -478,7 +487,7 @@ namespace Barotrauma
|
||||
|
||||
flowForce = new Vector2(
|
||||
hull1.WaveY[hull1.GetWaveIndex(rect.X)] - hull1.WaveY[hull1.GetWaveIndex(rect.Right)],
|
||||
MathHelper.Clamp(-delta, -200.0f, 0.0f));
|
||||
MathHelper.Clamp(-delta * (float)(Timing.Step / deltaTime), -200.0f, 0.0f));
|
||||
|
||||
if (hull2.WaterVolume > hull2.Volume)
|
||||
{
|
||||
@@ -517,7 +526,7 @@ namespace Barotrauma
|
||||
delta = Math.Min(delta, hull1.Volume * Hull.MaxCompress - hull1.WaterVolume);
|
||||
hull1.WaterVolume += delta;
|
||||
|
||||
if (hull1.WaterVolume > hull1.Volume) hull1.Pressure += 0.5f;
|
||||
if (hull1.WaterVolume > hull1.Volume) { hull1.Pressure += 30.0f * deltaTime; }
|
||||
|
||||
flowTargetHull = hull1;
|
||||
|
||||
@@ -526,12 +535,12 @@ namespace Barotrauma
|
||||
//water flowing from right to left
|
||||
if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
|
||||
{
|
||||
flowForce = new Vector2(-delta, 0.0f);
|
||||
flowForce = new Vector2(-delta * (float)(Timing.Step / deltaTime), 0.0f);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
flowForce = new Vector2(delta, 0.0f);
|
||||
flowForce = new Vector2(delta * (float)(Timing.Step / deltaTime), 0.0f);
|
||||
}
|
||||
|
||||
higherSurface = hull1.Surface;
|
||||
@@ -542,39 +551,39 @@ namespace Barotrauma
|
||||
{
|
||||
if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
|
||||
{
|
||||
float vel = ((rect.Y - rect.Height / 2) - (hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1])) * 0.1f;
|
||||
float vel = ((rect.Y - rect.Height / 2) - (hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1])) * 6.0f;
|
||||
vel *= Math.Min(Math.Abs(flowForce.X) / 200.0f, 1.0f);
|
||||
|
||||
hull1.WaveVel[hull1.WaveY.Length - 1] += vel;
|
||||
hull1.WaveVel[hull1.WaveY.Length - 2] += vel;
|
||||
hull1.WaveVel[hull1.WaveY.Length - 1] += vel * deltaTime;
|
||||
hull1.WaveVel[hull1.WaveY.Length - 2] += vel * deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
float vel = ((rect.Y - rect.Height / 2) - (hull1.Surface + hull1.WaveY[0])) * 0.1f;
|
||||
float vel = ((rect.Y - rect.Height / 2) - (hull1.Surface + hull1.WaveY[0])) * 6.0f;
|
||||
vel *= Math.Min(Math.Abs(flowForce.X) / 200.0f, 1.0f);
|
||||
|
||||
hull1.WaveVel[0] += vel;
|
||||
hull1.WaveVel[1] += vel;
|
||||
hull1.WaveVel[0] += vel * deltaTime;
|
||||
hull1.WaveVel[1] += vel * deltaTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime;
|
||||
hull1.LethalPressure += ((Submarine != null && Submarine.AtDamageDepth) ? 100.0f : 10.0f) * deltaTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rect.Y > hull1.Rect.Y - hull1.Rect.Height / 2.0f)
|
||||
{
|
||||
flowForce = new Vector2(0.0f, -delta);
|
||||
flowForce = new Vector2(0.0f, -delta * (float)(Timing.Step / deltaTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
flowForce = new Vector2(0.0f, delta);
|
||||
flowForce = new Vector2(0.0f, delta * (float)(Timing.Step / deltaTime));
|
||||
}
|
||||
if (hull1.WaterVolume >= hull1.Volume / Hull.MaxCompress)
|
||||
{
|
||||
hull1.LethalPressure += (Submarine != null && Submarine.AtDamageDepth) ? 100.0f * deltaTime : 10.0f * deltaTime;
|
||||
hull1.LethalPressure += ((Submarine != null && Submarine.AtDamageDepth) ? 100.0f : 10.0f) * deltaTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -640,7 +649,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOxygen(Hull hull1, Hull hull2)
|
||||
private void UpdateOxygen(Hull hull1, Hull hull2, float deltaTime)
|
||||
{
|
||||
if (hull1 == null || hull2 == null) { return; }
|
||||
|
||||
@@ -656,10 +665,10 @@ namespace Barotrauma
|
||||
return;
|
||||
|
||||
float totalOxygen = hull1.Oxygen + hull2.Oxygen;
|
||||
float totalVolume = (hull1.Volume + hull2.Volume);
|
||||
float totalVolume = hull1.Volume + hull2.Volume;
|
||||
|
||||
float deltaOxygen = (totalOxygen * hull1.Volume / totalVolume) - hull1.Oxygen;
|
||||
deltaOxygen = MathHelper.Clamp(deltaOxygen, -Hull.OxygenDistributionSpeed, Hull.OxygenDistributionSpeed);
|
||||
deltaOxygen = MathHelper.Clamp(deltaOxygen, -Hull.OxygenDistributionSpeed * deltaTime, Hull.OxygenDistributionSpeed * deltaTime);
|
||||
|
||||
hull1.Oxygen += deltaOxygen;
|
||||
hull2.Oxygen -= deltaOxygen;
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace Barotrauma
|
||||
public static bool ShowHulls = true;
|
||||
|
||||
public static bool EditWater, EditFire;
|
||||
public const float OxygenDistributionSpeed = 500.0f;
|
||||
public const float OxygenDistributionSpeed = 30000.0f;
|
||||
public const float OxygenDeteriorationSpeed = 0.3f;
|
||||
public const float OxygenConsumptionSpeed = 700.0f;
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace Barotrauma
|
||||
|
||||
private float lethalPressure;
|
||||
|
||||
private float surface, drawSurface;
|
||||
private float surface;
|
||||
private float waterVolume;
|
||||
private float pressure;
|
||||
|
||||
@@ -241,7 +241,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
OxygenPercentage = prevOxygenPercentage;
|
||||
surface = drawSurface = rect.Y - rect.Height + WaterVolume / rect.Width;
|
||||
surface = rect.Y - rect.Height + WaterVolume / rect.Width;
|
||||
#if CLIENT
|
||||
drawSurface = surface;
|
||||
#endif
|
||||
Pressure = surface;
|
||||
|
||||
CreateBackgroundSections();
|
||||
@@ -275,17 +278,6 @@ namespace Barotrauma
|
||||
get { return surface; }
|
||||
}
|
||||
|
||||
public float DrawSurface
|
||||
{
|
||||
get { return drawSurface; }
|
||||
set
|
||||
{
|
||||
if (Math.Abs(drawSurface - value) < 0.00001f) return;
|
||||
drawSurface = MathHelper.Clamp(value, rect.Y - rect.Height, rect.Y);
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
public float WorldSurface
|
||||
{
|
||||
get { return Submarine == null ? surface : surface + Submarine.Position.Y; }
|
||||
@@ -628,7 +620,10 @@ namespace Barotrauma
|
||||
Gap.UpdateHulls();
|
||||
}
|
||||
|
||||
surface = drawSurface = rect.Y - rect.Height + WaterVolume / rect.Width;
|
||||
surface = rect.Y - rect.Height + WaterVolume / rect.Width;
|
||||
#if CLIENT
|
||||
drawSurface = surface;
|
||||
#endif
|
||||
Pressure = surface;
|
||||
}
|
||||
|
||||
@@ -753,8 +748,6 @@ namespace Barotrauma
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
|
||||
BallastFlora?.Update(deltaTime);
|
||||
|
||||
UpdateProjSpecific(deltaTime, cam);
|
||||
@@ -808,11 +801,6 @@ namespace Barotrauma
|
||||
surface,
|
||||
rect.Y - rect.Height + waterDepth,
|
||||
deltaTime * 10.0f), rect.Y - rect.Height);
|
||||
//interpolate the position of the rendered surface towards the "target surface"
|
||||
drawSurface = Math.Max(MathHelper.Lerp(
|
||||
drawSurface,
|
||||
rect.Y - rect.Height + waterDepth,
|
||||
deltaTime * 10.0f), rect.Y - rect.Height);
|
||||
|
||||
for (int i = 0; i < waveY.Length; i++)
|
||||
{
|
||||
@@ -900,10 +888,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//0.01 increase every ~1000 frames = reaches full dirtiness in ~27 minutes
|
||||
if (submergedSections.Count > 0 && Submarine != null && Submarine.Info.Type == SubmarineType.Player && Rand.Int(1000) == 1)
|
||||
//0.016 increase every ~2000 frames = reaches full dirtiness in ~35 minutes
|
||||
if (submergedSections.Count > 0 && Submarine != null && Submarine.Info.Type == SubmarineType.Player && Rand.Int(2000) == 1)
|
||||
{
|
||||
DirtySections(submergedSections, 0.01f);
|
||||
DirtySections(submergedSections, deltaTime);
|
||||
}
|
||||
|
||||
if (waterVolume < Volume)
|
||||
@@ -911,11 +899,13 @@ namespace Barotrauma
|
||||
LethalPressure -= 10.0f * deltaTime;
|
||||
if (WaterVolume <= 0.0f)
|
||||
{
|
||||
#if CLIENT
|
||||
//wait for the surface to be lerped back to bottom and the waves to settle until disabling update
|
||||
if (drawSurface > rect.Y - rect.Height + 1) return;
|
||||
if (drawSurface > rect.Y - rect.Height + 1) { return; }
|
||||
#endif
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
if (waveY[i] > 0.1f) return;
|
||||
if (waveY[i] > 0.1f) { return; }
|
||||
}
|
||||
|
||||
update = false;
|
||||
@@ -1233,7 +1223,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle subRect = Submarine.CalculateDimensions();
|
||||
Rectangle subRect = Submarine.Borders;
|
||||
|
||||
Alignment roomPos;
|
||||
if (rect.Y - rect.Height / 2 > subRect.Y + subRect.Height * 0.66f)
|
||||
@@ -1540,7 +1530,7 @@ namespace Barotrauma
|
||||
if (prefab != null)
|
||||
{
|
||||
hull.BallastFlora = new BallastFloraBehavior(hull, prefab, Vector2.Zero);
|
||||
hull.BallastFlora.LoadSave(subElement);
|
||||
hull.BallastFlora.LoadSave(subElement, idRemap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -205,6 +205,8 @@ namespace Barotrauma
|
||||
foreach (var cell in Cells)
|
||||
{
|
||||
cell.CellType = CellType.Removed;
|
||||
cell.OnDestroyed?.Invoke();
|
||||
cell.OnDestroyed = null;
|
||||
}
|
||||
GameMain.World.Remove(Body);
|
||||
Dispose();
|
||||
|
||||
@@ -25,7 +25,17 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public const int MaxSubmarineWidth = 16000;
|
||||
|
||||
public static Level Loaded { get; private set; }
|
||||
private static Level loaded;
|
||||
public static Level Loaded
|
||||
{
|
||||
get { return loaded; }
|
||||
private set
|
||||
{
|
||||
if (loaded == value) { return; }
|
||||
loaded = value;
|
||||
GameAnalyticsManager.SetCurrentLevel(loaded?.LevelData);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PositionType
|
||||
@@ -574,12 +584,12 @@ namespace Barotrauma
|
||||
siteCoordsX = new List<double>((borders.Height / siteInterval.Y) * (borders.Width / siteInterval.Y));
|
||||
siteCoordsY = new List<double>((borders.Height / siteInterval.Y) * (borders.Width / siteInterval.Y));
|
||||
int caveSiteInterval = 500;
|
||||
for (int x = siteInterval.X / 2; x < borders.Width; x += siteInterval.X)
|
||||
for (int x = siteInterval.X / 2; x < borders.Width - siteInterval.X / 2; x += siteInterval.X)
|
||||
{
|
||||
for (int y = siteInterval.Y / 2; y < borders.Height; y += siteInterval.Y)
|
||||
for (int y = siteInterval.Y / 2; y < borders.Height - siteInterval.Y / 2; y += siteInterval.Y)
|
||||
{
|
||||
int siteX = x + Rand.Range(-siteVariance.X, siteVariance.X, Rand.RandSync.Server);
|
||||
int siteY = y + Rand.Range(-siteVariance.Y, siteVariance.Y, Rand.RandSync.Server);
|
||||
int siteX = x + Rand.Range(-siteVariance.X, siteVariance.X + 1, Rand.RandSync.Server);
|
||||
int siteY = y + Rand.Range(-siteVariance.Y, siteVariance.Y + 1, Rand.RandSync.Server);
|
||||
|
||||
bool closeToTunnel = false;
|
||||
bool closeToCave = false;
|
||||
@@ -613,8 +623,11 @@ namespace Barotrauma
|
||||
if (Rand.Range(0, 10, Rand.RandSync.Server) != 0) { continue; }
|
||||
}
|
||||
|
||||
siteCoordsX.Add(siteX);
|
||||
siteCoordsY.Add(siteY);
|
||||
if (!TooClose(siteX, siteY))
|
||||
{
|
||||
siteCoordsX.Add(siteX);
|
||||
siteCoordsY.Add(siteY);
|
||||
}
|
||||
|
||||
if (closeToCave)
|
||||
{
|
||||
@@ -625,24 +638,45 @@ namespace Barotrauma
|
||||
int caveSiteX = x2 + Rand.Int(caveSiteInterval / 2, Rand.RandSync.Server);
|
||||
int caveSiteY = y2 + Rand.Int(caveSiteInterval / 2, Rand.RandSync.Server);
|
||||
|
||||
bool tooClose = false;
|
||||
for (int i = 0; i < siteCoordsX.Count; i++)
|
||||
if (!TooClose(caveSiteX, caveSiteY))
|
||||
{
|
||||
if (MathUtils.DistanceSquared(caveSiteX, caveSiteY, siteCoordsX[i], siteCoordsY[i]) < 10.0f * 10.0f)
|
||||
{
|
||||
tooClose = true;
|
||||
break;
|
||||
}
|
||||
siteCoordsX.Add(caveSiteX);
|
||||
siteCoordsY.Add(caveSiteY);
|
||||
}
|
||||
if (tooClose) { continue; }
|
||||
siteCoordsX.Add(caveSiteX);
|
||||
siteCoordsY.Add(caveSiteY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TooClose(double siteX, double siteY)
|
||||
{
|
||||
for (int i = 0; i < siteCoordsX.Count; i++)
|
||||
{
|
||||
if (MathUtils.DistanceSquared(siteCoordsX[i], siteCoordsY[i], siteX, siteY) < 10.0f * 10.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < siteCoordsX.Count; i++)
|
||||
{
|
||||
Debug.Assert(
|
||||
siteCoordsX[i] > 0 || siteCoordsY[i] > 0,
|
||||
$"Potential error in level generation: a voronoi site was outside the bounds of the level ({siteCoordsX[i]}, {siteCoordsY[i]})");
|
||||
Debug.Assert(
|
||||
siteCoordsX[i] < borders.Width || siteCoordsY[i] < borders.Height,
|
||||
$"Potential error in level generation: a voronoi site was outside the bounds of the level ({siteCoordsX[i]}, {siteCoordsY[i]})");
|
||||
for (int j = i + 1; j < siteCoordsX.Count; j++)
|
||||
{
|
||||
Debug.Assert(
|
||||
MathUtils.DistanceSquared(siteCoordsX[i], siteCoordsY[i], siteCoordsX[j], siteCoordsY[j]) > 1.0f,
|
||||
"Potential error in level generation: two voronoi sites are extremely close to each other.");
|
||||
}
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.Server));
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -1011,7 +1045,7 @@ namespace Barotrauma
|
||||
foreach (InterestingPosition pos in PositionsOfInterest)
|
||||
{
|
||||
if (pos.PositionType != PositionType.MainPath && pos.PositionType != PositionType.SidePath) { continue; }
|
||||
if (pos.Position.X < 5000 || pos.Position.X > Size.X - 5000) { continue; }
|
||||
if (pos.Position.X < pathBorders.X + minMainPathWidth || pos.Position.X > pathBorders.Right - minMainPathWidth) { continue; }
|
||||
if (Math.Abs(pos.Position.X - startPosition.X) < minMainPathWidth * 2 || Math.Abs(pos.Position.X - endPosition.X) < minMainPathWidth * 2) { continue; }
|
||||
if (GetTooCloseCells(pos.Position.ToVector2(), minMainPathWidth * 0.7f).Count > 0) { continue; }
|
||||
iceChunkPositions.Add(pos.Position);
|
||||
@@ -1689,7 +1723,7 @@ namespace Barotrauma
|
||||
{
|
||||
vertices[j] += position;
|
||||
}
|
||||
var newChunk = new LevelWall(vertices, GenerationParams.WallColor, this);
|
||||
var newChunk = new LevelWall(vertices, GenerationParams.WallColor, this, createBody: false);
|
||||
AbyssIslands.Add(new AbyssIsland(islandArea, newChunk.Cells));
|
||||
continue;
|
||||
}
|
||||
@@ -1752,12 +1786,12 @@ namespace Barotrauma
|
||||
new Point(0, BottomPos)
|
||||
};
|
||||
|
||||
int mountainCount = Rand.Range(GenerationParams.MountainCountMin, GenerationParams.MountainCountMax, Rand.RandSync.Server);
|
||||
int mountainCount = Rand.Range(GenerationParams.MountainCountMin, GenerationParams.MountainCountMax + 1, Rand.RandSync.Server);
|
||||
for (int i = 0; i < mountainCount; i++)
|
||||
{
|
||||
bottomPositions.Add(
|
||||
new Point(Size.X / (mountainCount + 1) * (i + 1),
|
||||
BottomPos + Rand.Range(GenerationParams.MountainHeightMin, GenerationParams.MountainHeightMax, Rand.RandSync.Server)));
|
||||
BottomPos + Rand.Range(GenerationParams.MountainHeightMin, GenerationParams.MountainHeightMax + 1, Rand.RandSync.Server)));
|
||||
}
|
||||
bottomPositions.Add(new Point(Size.X, BottomPos));
|
||||
|
||||
@@ -1770,7 +1804,7 @@ namespace Barotrauma
|
||||
bottomPositions.Insert(i + 1,
|
||||
new Point(
|
||||
(bottomPositions[i].X + bottomPositions[i + 1].X) / 2,
|
||||
(bottomPositions[i].Y + bottomPositions[i + 1].Y) / 2 + Rand.Range(0, GenerationParams.SeaFloorVariance, Rand.RandSync.Server)));
|
||||
(bottomPositions[i].Y + bottomPositions[i + 1].Y) / 2 + Rand.Range(0, GenerationParams.SeaFloorVariance + 1, Rand.RandSync.Server)));
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -1808,7 +1842,7 @@ namespace Barotrauma
|
||||
Rectangle allowedArea = new Rectangle(padding, padding, Size.X - padding * 2, Size.Y - padding * 2);
|
||||
|
||||
int radius = Math.Max(caveSize.X, caveSize.Y) / 2;
|
||||
var cavePos = FindPosAwayFromMainPath((parentTunnel.MinWidth + radius) * 1.5f, asCloseAsPossible: true, allowedArea);
|
||||
var cavePos = FindPosAwayFromMainPath((parentTunnel.MinWidth + radius) * 1.25f, asCloseAsPossible: true, allowedArea);
|
||||
|
||||
GenerateCave(caveParams, parentTunnel, cavePos, caveSize);
|
||||
|
||||
@@ -1857,7 +1891,7 @@ namespace Barotrauma
|
||||
Tunnels.Add(tunnel);
|
||||
caveBranches.Add(tunnel);
|
||||
|
||||
int branches = Rand.Range(caveParams.MinBranchCount, caveParams.MaxBranchCount, Rand.RandSync.Server);
|
||||
int branches = Rand.Range(caveParams.MinBranchCount, caveParams.MaxBranchCount + 1, Rand.RandSync.Server);
|
||||
for (int j = 0; j < branches; j++)
|
||||
{
|
||||
Tunnel parentBranch = caveBranches.GetRandom(Rand.RandSync.Server);
|
||||
@@ -2073,12 +2107,42 @@ namespace Barotrauma
|
||||
|
||||
private Point FindPosAwayFromMainPath(double minDistance, bool asCloseAsPossible, Rectangle? limits = null)
|
||||
{
|
||||
var validPoints = distanceField.FindAll(d => d.distance >= minDistance && (limits == null || limits.Value.Contains(d.point)));
|
||||
validPoints.RemoveAll(d => d.point.Y < GetBottomPosition(d.point.X).Y + minDistance);
|
||||
if (asCloseAsPossible || !validPoints.Any())
|
||||
var pointsAboveBottom = distanceField.FindAll(d => d.point.Y > GetBottomPosition(d.point.X).Y + minDistance);
|
||||
if (pointsAboveBottom.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in FindPosAwayFromMainPath: no valid positions above the bottom of the sea floor. Has the position of the sea floor been set too high up?");
|
||||
return distanceField[Rand.Int(distanceField.Count, Rand.RandSync.Server)].point;
|
||||
}
|
||||
|
||||
var validPoints = pointsAboveBottom.FindAll(d => d.distance >= minDistance && (limits == null || limits.Value.Contains(d.point)));
|
||||
if (!validPoints.Any())
|
||||
{
|
||||
DebugConsole.AddWarning("Failed to find a valid position far enough from the main path. Choosing the furthest possible position.\n" + Environment.StackTrace);
|
||||
if (limits != null)
|
||||
{
|
||||
//try choosing something within the specified limits
|
||||
validPoints = pointsAboveBottom.FindAll(d => limits.Value.Contains(d.point));
|
||||
}
|
||||
if (!validPoints.Any())
|
||||
{
|
||||
//couldn't find anything, let's just go with the furthest one
|
||||
validPoints = pointsAboveBottom;
|
||||
}
|
||||
(Point position, double distance) furthestPoint = validPoints.First();
|
||||
foreach (var point in validPoints)
|
||||
{
|
||||
if (point.distance > furthestPoint.distance)
|
||||
{
|
||||
furthestPoint = point;
|
||||
}
|
||||
}
|
||||
return furthestPoint.position;
|
||||
}
|
||||
|
||||
if (asCloseAsPossible)
|
||||
{
|
||||
if (!validPoints.Any()) { validPoints = distanceField; }
|
||||
(Point position, double distance) closestPoint = validPoints.First();
|
||||
(Point position, double distance) closestPoint = validPoints.First();
|
||||
foreach (var point in validPoints)
|
||||
{
|
||||
if (point.distance < closestPoint.distance)
|
||||
@@ -2138,7 +2202,7 @@ namespace Barotrauma
|
||||
{
|
||||
double xDiff = Math.Abs(point.X - ruinPos.X);
|
||||
double yDiff = Math.Abs(point.Y - ruinPos.Y);
|
||||
if (xDiff < ruinSize || yDiff < ruinSize)
|
||||
if (xDiff < ruinSize && yDiff < ruinSize)
|
||||
{
|
||||
shortestDistSqr = 0.0f;
|
||||
}
|
||||
@@ -2417,7 +2481,7 @@ namespace Barotrauma
|
||||
}, randSync: Rand.RandSync.Server);
|
||||
|
||||
if (location.Cell == null || location.Edge == null) { break; }
|
||||
int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y, Rand.RandSync.Server);
|
||||
int clusterSize = Rand.Range(GenerationParams.ResourceClusterSizeRange.X, GenerationParams.ResourceClusterSizeRange.Y + 1, Rand.RandSync.Server);
|
||||
PlaceResources(itemPrefab, clusterSize, location, out var abyssResources);
|
||||
var abyssClusterLocation = new ClusterLocation(location.Cell, location.Edge, initializeResourceList: true);
|
||||
abyssClusterLocation.Resources.AddRange(abyssResources);
|
||||
@@ -2897,6 +2961,7 @@ namespace Barotrauma
|
||||
float? edgeLength = null, float maxResourceOverlap = 0.4f)
|
||||
{
|
||||
edgeLength ??= Vector2.Distance(location.Edge.Point1, location.Edge.Point2);
|
||||
Vector2 edgeDir = (location.Edge.Point2 - location.Edge.Point1) / edgeLength.Value;
|
||||
var minResourceOverlap = -((edgeLength.Value - (resourceCount * resourcePrefab.Size.X)) / (resourceCount * resourcePrefab.Size.X));
|
||||
minResourceOverlap = Math.Max(minResourceOverlap, 0.0f);
|
||||
var lerpAmounts = new float[resourceCount];
|
||||
@@ -2912,7 +2977,7 @@ namespace Barotrauma
|
||||
placedResources = new List<Item>();
|
||||
for (int i = 0; i < resourceCount; i++)
|
||||
{
|
||||
Vector2 selectedPos = Vector2.Lerp(location.Edge.Point1, location.Edge.Point2, startOffset + lerpAmounts[i]);
|
||||
Vector2 selectedPos = Vector2.Lerp(location.Edge.Point1 + edgeDir * resourcePrefab.Size.X / 2, location.Edge.Point2 - edgeDir * resourcePrefab.Size.X / 2, startOffset + lerpAmounts[i]);
|
||||
var item = new Item(resourcePrefab, selectedPos, submarine: null);
|
||||
Vector2 edgeNormal = location.Edge.GetNormal(location.Cell);
|
||||
float moveAmount = (item.body == null ? item.Rect.Height / 2 : ConvertUnits.ToDisplayUnits(item.body.GetMaxExtent() * 0.7f));
|
||||
@@ -3285,13 +3350,6 @@ namespace Barotrauma
|
||||
return pathCells;
|
||||
}
|
||||
|
||||
public string GetWreckIDTag(string originalTag, Submarine wreck)
|
||||
{
|
||||
string shortSeed = ToolBox.StringToInt(LevelData.Seed + wreck?.Info.Name).ToString();
|
||||
if (shortSeed.Length > 6) { shortSeed = shortSeed.Substring(0, 6); }
|
||||
return originalTag + "_" + shortSeed;
|
||||
}
|
||||
|
||||
public bool IsCloseToStart(Vector2 position, float minDist) => IsCloseToStart(position.ToPoint(), minDist);
|
||||
public bool IsCloseToEnd(Vector2 position, float minDist) => IsCloseToEnd(position.ToPoint(), minDist);
|
||||
|
||||
@@ -3627,10 +3685,23 @@ namespace Barotrauma
|
||||
Wrecks = new List<Submarine>(wreckCount);
|
||||
for (int i = 0; i < wreckCount; i++)
|
||||
{
|
||||
ContentFile contentFile = wreckFiles[i];
|
||||
if (contentFile == null) { continue; }
|
||||
string wreckName = System.IO.Path.GetFileNameWithoutExtension(contentFile.Path);
|
||||
SpawnSubOnPath(wreckName, contentFile, SubmarineType.Wreck);
|
||||
//how many times we'll try placing another sub before giving up
|
||||
const int MaxSubsToTry = 2;
|
||||
int attempts = 0;
|
||||
while (wreckFiles.Any() && attempts < MaxSubsToTry)
|
||||
{
|
||||
ContentFile contentFile = wreckFiles.First();
|
||||
wreckFiles.RemoveAt(0);
|
||||
if (contentFile == null) { continue; }
|
||||
string wreckName = System.IO.Path.GetFileNameWithoutExtension(contentFile.Path);
|
||||
if (SpawnSubOnPath(wreckName, contentFile, SubmarineType.Wreck) != null)
|
||||
{
|
||||
//placed successfully
|
||||
break;
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
|
||||
}
|
||||
totalSW.Stop();
|
||||
Debug.WriteLine($"{Wrecks.Count} wrecks created in { totalSW.ElapsedMilliseconds} (ms)");
|
||||
@@ -4020,7 +4091,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Submarine wreck in Wrecks)
|
||||
{
|
||||
int corpseCount = Rand.Range(Loaded.GenerationParams.MinCorpseCount, Loaded.GenerationParams.MaxCorpseCount);
|
||||
int corpseCount = Rand.Range(Loaded.GenerationParams.MinCorpseCount, Loaded.GenerationParams.MaxCorpseCount + 1);
|
||||
var allSpawnPoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine == wreck && wp.CurrentHull != null);
|
||||
var pathPoints = allSpawnPoints.FindAll(wp => wp.SpawnType == SpawnType.Path);
|
||||
pathPoints.Shuffle(Rand.RandSync.Unsynced);
|
||||
@@ -4077,6 +4148,7 @@ namespace Barotrauma
|
||||
corpse.EnableDespawn = false;
|
||||
selectedPrefab.GiveItems(corpse, wreck);
|
||||
corpse.Kill(CauseOfDeathType.Unknown, causeOfDeathAffliction: null, log: false);
|
||||
corpse.GiveIdCardTags(sp);
|
||||
spawnCounter++;
|
||||
|
||||
static CorpsePrefab GetCorpsePrefab(Func<CorpsePrefab, bool> predicate)
|
||||
|
||||
+1
-1
@@ -304,7 +304,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (LevelObjectPrefab.ChildObject child in prefab.ChildObjects)
|
||||
{
|
||||
int childCount = Rand.Range(child.MinCount, child.MaxCount, Rand.RandSync.Server);
|
||||
int childCount = Rand.Range(child.MinCount, child.MaxCount + 1, Rand.RandSync.Server);
|
||||
for (int j = 0; j < childCount; j++)
|
||||
{
|
||||
var matchingPrefabs = LevelObjectPrefab.List.Where(p => child.AllowedNames.Contains(p.Name));
|
||||
|
||||
@@ -433,6 +433,32 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are there any active contacts between the physics body and the target entity
|
||||
/// </summary>
|
||||
public static bool CheckContactsForEntity(PhysicsBody triggerBody, Entity targetEntity)
|
||||
{
|
||||
foreach (Fixture fixture in triggerBody.FarseerBody.FixtureList)
|
||||
{
|
||||
ContactEdge contactEdge = fixture.Body.ContactList;
|
||||
while (contactEdge != null)
|
||||
{
|
||||
if (contactEdge.Contact != null &&
|
||||
contactEdge.Contact.Enabled &&
|
||||
contactEdge.Contact.IsTouching)
|
||||
{
|
||||
if ((contactEdge.Contact.FixtureA.Body == triggerBody.FarseerBody && GetEntity(contactEdge.Contact.FixtureB) == targetEntity) ||
|
||||
(contactEdge.Contact.FixtureB.Body == triggerBody.FarseerBody && GetEntity(contactEdge.Contact.FixtureA) == targetEntity))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
contactEdge = contactEdge.Next;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Entity GetEntity(Fixture fixture)
|
||||
{
|
||||
if (fixture.Body == null || fixture.Body.UserData == null) { return null; }
|
||||
@@ -472,9 +498,6 @@ namespace Barotrauma
|
||||
{
|
||||
if (ParentTrigger != null && !ParentTrigger.IsTriggered) { return; }
|
||||
|
||||
triggerers.RemoveWhere(t => t.Removed);
|
||||
|
||||
RemoveDistantTriggerers(PhysicsBody, triggerers, WorldPosition);
|
||||
|
||||
bool isNotClient = true;
|
||||
#if CLIENT
|
||||
@@ -518,7 +541,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RemoveInActiveTriggerers(PhysicsBody, triggerers);
|
||||
|
||||
if (stayTriggeredDelay > 0.0f)
|
||||
{
|
||||
if (triggerers.Count == 0)
|
||||
@@ -538,6 +563,8 @@ namespace Barotrauma
|
||||
|
||||
foreach (Entity triggerer in triggerers)
|
||||
{
|
||||
if (triggerer.Removed) { continue; }
|
||||
|
||||
ApplyStatusEffects(statusEffects, worldPosition, triggerer, deltaTime, targets);
|
||||
|
||||
if (triggerer is IDamageable damageable)
|
||||
@@ -583,15 +610,27 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveDistantTriggerers(PhysicsBody physicsBody, HashSet<Entity> triggerers, Vector2 calculateDistanceTo)
|
||||
private static readonly List<Entity> triggerersToRemove = new List<Entity>();
|
||||
public static void RemoveInActiveTriggerers(PhysicsBody physicsBody, HashSet<Entity> triggerers)
|
||||
{
|
||||
//failsafe to ensure triggerers get removed when they're far from the trigger
|
||||
if (physicsBody == null) { return; }
|
||||
float maxExtent = Math.Max(ConvertUnits.ToDisplayUnits(physicsBody.GetMaxExtent() * 5), 5000.0f);
|
||||
triggerers.RemoveWhere(t =>
|
||||
|
||||
triggerersToRemove.Clear();
|
||||
foreach (var triggerer in triggerers)
|
||||
{
|
||||
return Vector2.Distance(t.WorldPosition, calculateDistanceTo) > maxExtent;
|
||||
});
|
||||
if (triggerer.Removed)
|
||||
{
|
||||
triggerersToRemove.Add(triggerer);
|
||||
}
|
||||
else if (!CheckContactsForEntity(physicsBody, triggerer))
|
||||
{
|
||||
triggerersToRemove.Add(triggerer);
|
||||
}
|
||||
}
|
||||
foreach (var triggerer in triggerersToRemove)
|
||||
{
|
||||
triggerers.Remove(triggerer);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ApplyStatusEffects(List<StatusEffect> statusEffects, Vector2 worldPosition, Entity triggerer, float deltaTime, List<ISerializableEntity> targets)
|
||||
@@ -650,13 +689,15 @@ namespace Barotrauma
|
||||
float structureDamage = attack.GetStructureDamage(deltaTime);
|
||||
if (structureDamage > 0.0f)
|
||||
{
|
||||
Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage, levelWallDamage: 0.0f);
|
||||
Explosion.RangedStructureDamage(worldPosition, attack.DamageRange, structureDamage, levelWallDamage: 0.0f, emitWallDamageParticles: attack.EmitStructureDamageParticles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyForce(PhysicsBody body)
|
||||
{
|
||||
if (body == null) { return; }
|
||||
|
||||
float distFactor = 1.0f;
|
||||
if (ForceFalloff)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Barotrauma
|
||||
set { moveState = MathHelper.Clamp(value, 0.0f, MathHelper.TwoPi); }
|
||||
}
|
||||
|
||||
public LevelWall(List<Vector2> vertices, Color color, Level level, bool giftWrap = false)
|
||||
public LevelWall(List<Vector2> vertices, Color color, Level level, bool giftWrap = false, bool createBody = true)
|
||||
{
|
||||
this.level = level;
|
||||
this.color = color;
|
||||
@@ -74,14 +74,17 @@ namespace Barotrauma
|
||||
wallCell.Edges[i].IsSolid = true;
|
||||
}
|
||||
Cells = new List<VoronoiCell>() { wallCell };
|
||||
Body = CaveGenerator.GeneratePolygons(Cells, level, out triangles);
|
||||
if (triangles.Count == 0)
|
||||
if (createBody)
|
||||
{
|
||||
throw new ArgumentException("Failed to generate a wall (not enough triangles). Original vertices: " + string.Join(", ", originalVertices.Select(v => v.ToString())));
|
||||
}
|
||||
Body = CaveGenerator.GeneratePolygons(Cells, level, out triangles);
|
||||
if (triangles.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("Failed to generate a wall (not enough triangles). Original vertices: " + string.Join(", ", originalVertices.Select(v => v.ToString())));
|
||||
}
|
||||
#if CLIENT
|
||||
GenerateVertices();
|
||||
GenerateVertices();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public LevelWall(List<Vector2> edgePositions, Vector2 extendAmount, Color color, Level level)
|
||||
|
||||
@@ -147,8 +147,6 @@ namespace Barotrauma
|
||||
{
|
||||
List<Vector2> points = new List<Vector2>();
|
||||
|
||||
var wallPrefabs = StructurePrefab.Prefabs.Where(mp => mp.Body);
|
||||
|
||||
foreach (XElement element in rootElement.Elements())
|
||||
{
|
||||
if (element.Name != "Structure") { continue; }
|
||||
@@ -159,8 +157,12 @@ namespace Barotrauma
|
||||
StructurePrefab prefab = Structure.FindPrefab(name, identifier);
|
||||
if (prefab == null) { continue; }
|
||||
|
||||
float scale = element.GetAttributeFloat("scale", prefab.Scale);
|
||||
|
||||
var rect = element.GetAttributeVector4("rect", Vector4.Zero);
|
||||
|
||||
rect.Z *= scale / prefab.Scale;
|
||||
rect.W *= scale / prefab.Scale;
|
||||
|
||||
points.Add(new Vector2(rect.X, rect.Y));
|
||||
points.Add(new Vector2(rect.X + rect.Z, rect.Y));
|
||||
points.Add(new Vector2(rect.X, rect.Y - rect.W));
|
||||
@@ -352,6 +354,7 @@ namespace Barotrauma
|
||||
if (hull.Submarine != sub) { continue; }
|
||||
hull.WaterVolume = 0.0f;
|
||||
hull.OxygenPercentage = 100.0f;
|
||||
hull.BallastFlora?.Kill();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Abilities;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -132,6 +133,7 @@ namespace Barotrauma
|
||||
#endregion
|
||||
|
||||
private const float MechanicalMaxDiscountPercentage = 50.0f;
|
||||
private const float HealMaxDiscountPercentage = 10.0f;
|
||||
|
||||
private readonly List<TakenItem> takenItems = new List<TakenItem>();
|
||||
public IEnumerable<TakenItem> TakenItems
|
||||
@@ -780,7 +782,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (priceInfo.MaxAvailableAmount > priceInfo.MinAvailableAmount)
|
||||
{
|
||||
quantity = Rand.Range(priceInfo.MinAvailableAmount, priceInfo.MaxAvailableAmount);
|
||||
quantity = Rand.Range(priceInfo.MinAvailableAmount, priceInfo.MaxAvailableAmount + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -908,6 +910,12 @@ namespace Barotrauma
|
||||
return (int) Math.Ceiling((1.0f - discount) * cost * MechanicalPriceMultiplier);
|
||||
}
|
||||
|
||||
public int GetAdjustedHealCost(int cost)
|
||||
{
|
||||
float discount = Reputation.Value / Reputation.MaxReputation * (HealMaxDiscountPercentage / 100.0f);
|
||||
return (int) Math.Ceiling((1.0f - discount) * cost * PriceMultiplier);
|
||||
}
|
||||
|
||||
/// <param name="force">If true, the store will be recreated if it already exists.</param>
|
||||
public void CreateStore(bool force = false)
|
||||
{
|
||||
@@ -1002,7 +1010,7 @@ namespace Barotrauma
|
||||
|
||||
private void GenerateRandomPriceModifier()
|
||||
{
|
||||
StorePriceModifier = Rand.Range(-StorePriceModifierRange, StorePriceModifierRange);
|
||||
StorePriceModifier = Rand.Range(-StorePriceModifierRange, StorePriceModifierRange + 1);
|
||||
}
|
||||
|
||||
private void CreateStoreSpecials()
|
||||
@@ -1110,7 +1118,7 @@ namespace Barotrauma
|
||||
Discovered = true;
|
||||
if (checkTalents)
|
||||
{
|
||||
GameSession.GetSessionCrewCharacters().ForEach(c => c.CheckTalents(AbilityEffectType.OnLocationDiscovered, new Abilities.AbilityLocation(this)));
|
||||
GameSession.GetSessionCrewCharacters().ForEach(c => c.CheckTalents(AbilityEffectType.OnLocationDiscovered, new AbilityLocation(this)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1263,5 +1271,15 @@ namespace Barotrauma
|
||||
{
|
||||
HireManager?.Remove();
|
||||
}
|
||||
|
||||
class AbilityLocation : AbilityObject, IAbilityLocation
|
||||
{
|
||||
public AbilityLocation(Location location)
|
||||
{
|
||||
Location = location;
|
||||
}
|
||||
|
||||
public Location Location { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace Barotrauma
|
||||
System.Diagnostics.Debug.Assert(!Locations.Contains(null));
|
||||
for (int i = 0; i < Locations.Count; i++)
|
||||
{
|
||||
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, $"location.{i}", -100, 100, Rand.Range(-10, 10, Rand.RandSync.Server));
|
||||
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, Locations[i], $"location.{i}", -100, 100, Rand.Range(-10, 11, Rand.RandSync.Server));
|
||||
}
|
||||
|
||||
List<XElement> connectionElements = new List<XElement>();
|
||||
@@ -214,7 +214,7 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < Locations.Count; i++)
|
||||
{
|
||||
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, $"location.{i}", -100, 100, Rand.Range(-10, 10, Rand.RandSync.Server));
|
||||
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, Locations[i], $"location.{i}", -100, 100, Rand.Range(-10, 11, Rand.RandSync.Server));
|
||||
}
|
||||
|
||||
foreach (Location location in Locations)
|
||||
@@ -486,7 +486,8 @@ namespace Barotrauma
|
||||
{
|
||||
location.LevelData = new LevelData(location)
|
||||
{
|
||||
Difficulty = MathHelper.Clamp(GetLevelDifficulty(location.MapPosition.X / Width), 0.0f, 100.0f)
|
||||
Difficulty = MathHelper.Clamp(location.MapPosition.X / Width * 100, 0.0f, 100.0f)
|
||||
//Difficulty = MathHelper.Clamp(GetLevelDifficulty(location.MapPosition.X / Width), 0.0f, 100.0f)
|
||||
};
|
||||
location.UnlockInitialMissions();
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@ using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -20,14 +18,17 @@ namespace Barotrauma
|
||||
|
||||
protected List<ushort> linkedToID;
|
||||
public List<ushort> unresolvedLinkedToID;
|
||||
|
||||
|
||||
private const int GapUpdateInterval = 4;
|
||||
private static int gapUpdateTimer;
|
||||
|
||||
/// <summary>
|
||||
/// List of upgrades this item has
|
||||
/// </summary>
|
||||
protected readonly List<Upgrade> Upgrades = new List<Upgrade>();
|
||||
|
||||
|
||||
public HashSet<string> disallowedUpgrades = new HashSet<string>();
|
||||
|
||||
|
||||
[Editable, Serialize("", true)]
|
||||
public string DisallowedUpgrades
|
||||
{
|
||||
@@ -101,7 +102,7 @@ namespace Barotrauma
|
||||
return !DrawBelowWater;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual bool Linkable
|
||||
{
|
||||
get { return false; }
|
||||
@@ -231,6 +232,9 @@ namespace Barotrauma
|
||||
protected set;
|
||||
} = true;
|
||||
|
||||
[Serialize("", true, "Submarine editor layer")]
|
||||
public string Layer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The index of the outpost module this entity originally spawned in (-1 if not an outpost item)
|
||||
/// </summary>
|
||||
@@ -242,7 +246,7 @@ namespace Barotrauma
|
||||
{
|
||||
get { return ""; }
|
||||
}
|
||||
|
||||
|
||||
public MapEntity(MapEntityPrefab prefab, Submarine submarine, ushort id) : base(submarine, id)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
@@ -303,7 +307,7 @@ namespace Barotrauma
|
||||
{
|
||||
return GetUpgrade(identifier) != null;
|
||||
}
|
||||
|
||||
|
||||
public Upgrade GetUpgrade(string identifier)
|
||||
{
|
||||
return Upgrades.Find(upgrade => upgrade.Identifier == identifier);
|
||||
@@ -329,7 +333,7 @@ namespace Barotrauma
|
||||
}
|
||||
DebugConsole.Log($"Set (ID: {ID} {prefab.Name})'s \"{upgrade.Prefab.Name}\" upgrade to level {upgrade.Level}");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new upgrade to the item
|
||||
/// </summary>
|
||||
@@ -407,6 +411,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//connect clone wires to the clone items and refresh links between doors and gaps
|
||||
List<Wire> orphanedWires = new List<Wire>();
|
||||
for (int i = 0; i < clones.Count; i++)
|
||||
{
|
||||
if (!(clones[i] is Item cloneItem)) { continue; }
|
||||
@@ -435,11 +440,11 @@ namespace Barotrauma
|
||||
disconnectedFromClone.DisconnectedWires.Add(cloneWire);
|
||||
if (cloneWire.Item.body != null) { cloneWire.Item.body.Enabled = false; }
|
||||
cloneWire.IsActive = false;
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
var connectedItem = originalWire.Connections[n].Item;
|
||||
if (connectedItem == null) { continue; }
|
||||
if (connectedItem == null || !entitiesToClone.Contains(connectedItem)) { continue; }
|
||||
|
||||
//index of the item the wire is connected to
|
||||
int itemIndex = entitiesToClone.IndexOf(connectedItem);
|
||||
@@ -466,6 +471,20 @@ namespace Barotrauma
|
||||
(clones[itemIndex] as Item).Connections[connectionIndex].TryAddLink(cloneWire);
|
||||
cloneWire.Connect((clones[itemIndex] as Item).Connections[connectionIndex], false);
|
||||
}
|
||||
|
||||
if ((cloneWire.Connections[0] == null || cloneWire.Connections[1] == null) && cloneItem.GetComponent<DockingPort>() == null)
|
||||
{
|
||||
if (!clones.Any(c => (c as Item)?.GetComponent<ConnectionPanel>()?.DisconnectedWires.Contains(cloneWire) ?? false))
|
||||
{
|
||||
orphanedWires.Add(cloneWire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var orphanedWire in orphanedWires)
|
||||
{
|
||||
orphanedWire.Item.Remove();
|
||||
clones.Remove(orphanedWire.Item);
|
||||
}
|
||||
|
||||
return clones;
|
||||
@@ -535,59 +554,48 @@ namespace Barotrauma
|
||||
linkedTo.Clear();
|
||||
}
|
||||
}
|
||||
static int tick = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Call Update() on every object in Entity.list
|
||||
/// </summary>
|
||||
public static void UpdateAll(float deltaTime, Camera cam)
|
||||
{
|
||||
tick++;
|
||||
|
||||
if (tick % GameMain.Lua.game.mapEntityUpdateRate == 0)
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
hull.Update(deltaTime, cam);
|
||||
}
|
||||
#if CLIENT
|
||||
Hull.UpdateCheats(deltaTime, cam);
|
||||
#endif
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
hull.Update(deltaTime * GameMain.Lua.game.mapEntityUpdateRate, cam);
|
||||
}
|
||||
|
||||
foreach (Structure structure in Structure.WallList)
|
||||
{
|
||||
structure.Update(deltaTime * GameMain.Lua.game.mapEntityUpdateRate, cam);
|
||||
}
|
||||
|
||||
|
||||
//update gaps in random order, because otherwise in rooms with multiple gaps
|
||||
//the water/air will always tend to flow through the first gap in the list,
|
||||
//which may lead to weird behavior like water draining down only through
|
||||
//one gap in a room even if there are several
|
||||
foreach (Gap gap in Gap.GapList.OrderBy(g => Rand.Int(int.MaxValue)))
|
||||
{
|
||||
gap.Update(deltaTime * GameMain.Lua.game.mapEntityUpdateRate, cam);
|
||||
}
|
||||
|
||||
Powered.UpdatePower(deltaTime * GameMain.Lua.game.mapEntityUpdateRate);
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (GameMain.Lua.game.updatePriorityItems.Contains(item)) continue;
|
||||
|
||||
item.Update(deltaTime * GameMain.Lua.game.mapEntityUpdateRate, cam);
|
||||
}
|
||||
foreach (Structure structure in Structure.WallList)
|
||||
{
|
||||
structure.Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
foreach (var item in GameMain.Lua.game.updatePriorityItems)
|
||||
//update gaps in random order, because otherwise in rooms with multiple gaps
|
||||
//the water/air will always tend to flow through the first gap in the list,
|
||||
//which may lead to weird behavior like water draining down only through
|
||||
//one gap in a room even if there are several
|
||||
gapUpdateTimer++;
|
||||
if (gapUpdateTimer >= GapUpdateInterval)
|
||||
{
|
||||
if (item.Removed) continue;
|
||||
foreach (Gap gap in Gap.GapList.OrderBy(g => Rand.Int(int.MaxValue)))
|
||||
{
|
||||
gap.Update(deltaTime * GapUpdateInterval, cam);
|
||||
}
|
||||
gapUpdateTimer = 0;
|
||||
}
|
||||
|
||||
Powered.UpdatePower(deltaTime);
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
item.Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
if (tick % GameMain.Lua.game.mapEntityUpdateRate == 0)
|
||||
{
|
||||
UpdateAllProjSpecific(deltaTime * GameMain.Lua.game.mapEntityUpdateRate);
|
||||
UpdateAllProjSpecific(deltaTime);
|
||||
|
||||
Spawner?.Update();
|
||||
}
|
||||
Spawner?.Update();
|
||||
}
|
||||
|
||||
static partial void UpdateAllProjSpecific(float deltaTime);
|
||||
@@ -743,11 +751,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (ushort i in e.linkedToID)
|
||||
{
|
||||
if (FindEntityByID(i) is MapEntity linked)
|
||||
if (FindEntityByID(i) is MapEntity linked)
|
||||
{
|
||||
e.linkedTo.Add(linked);
|
||||
}
|
||||
else
|
||||
e.linkedTo.Add(linked);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Linking the entity \"{e.Name}\" to another entity failed. Could not find an entity with the ID \"{i}\".");
|
||||
@@ -788,7 +796,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Gets all linked entities of specific type.
|
||||
/// </summary>
|
||||
private static void GetLinkedEntitiesRecursive<T>(MapEntity mapEntity, HashSet<T> linkedTargets, ref int depth, int? maxDepth = null, Func<T, bool> filter = null)
|
||||
private static void GetLinkedEntitiesRecursive<T>(MapEntity mapEntity, HashSet<T> linkedTargets, ref int depth, int? maxDepth = null, Func<T, bool> filter = null)
|
||||
where T : MapEntity
|
||||
{
|
||||
if (depth > maxDepth) { return; }
|
||||
@@ -806,4 +814,4 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -317,6 +318,11 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MapEntityPrefab GetRandom(Predicate<MapEntityPrefab> predicate, Rand.RandSync sync)
|
||||
{
|
||||
return List.GetRandom(p => predicate(p), sync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a matching map entity prefab
|
||||
/// </summary>
|
||||
@@ -338,6 +344,8 @@ namespace Barotrauma
|
||||
if (target == null) { return false; }
|
||||
if (target is StructurePrefab && AllowedLinks.Contains("structure")) { return true; }
|
||||
if (target is ItemPrefab && AllowedLinks.Contains("item")) { return true; }
|
||||
if (target is LinkedSubmarinePrefab && Tags.Contains("dock")) { return true; }
|
||||
if (this is LinkedSubmarinePrefab && target.Tags.Contains("dock")) { return true; }
|
||||
return AllowedLinks.Contains(target.Identifier) || target.AllowedLinks.Contains(identifier)
|
||||
|| target.Tags.Any(t => AllowedLinks.Contains(t)) || Tags.Any(t => target.AllowedLinks.Contains(t));
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Barotrauma
|
||||
|
||||
private float? maxHealth;
|
||||
|
||||
[Serialize(100.0f, true)]
|
||||
[Serialize(100.0f, true), Editable(MinValueFloat = 0)]
|
||||
public float MaxHealth
|
||||
{
|
||||
get => maxHealth ?? Prefab.Health;
|
||||
@@ -704,7 +704,7 @@ namespace Barotrauma
|
||||
if (BodyWidth > 0.0f) { rectSize.X = BodyWidth; }
|
||||
if (BodyHeight > 0.0f) { rectSize.Y = BodyHeight; }
|
||||
|
||||
Vector2 bodyPos = WorldPosition + BodyOffset;
|
||||
Vector2 bodyPos = WorldPosition + BodyOffset * Scale;
|
||||
|
||||
Vector2 transformedMousePos = MathUtils.RotatePointAroundTarget(position, bodyPos, BodyRotation);
|
||||
|
||||
@@ -876,7 +876,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddDamage(int sectionIndex, float damage, Character attacker = null)
|
||||
public void AddDamage(int sectionIndex, float damage, Character attacker = null, bool emitParticles = true)
|
||||
{
|
||||
if (!Prefab.Body || Prefab.Platform || Indestructible) { return; }
|
||||
|
||||
@@ -885,7 +885,7 @@ namespace Barotrauma
|
||||
var section = Sections[sectionIndex];
|
||||
|
||||
#if CLIENT
|
||||
if (damage > 0)
|
||||
if (damage > 0 && emitParticles)
|
||||
{
|
||||
float dmg = Math.Min(MaxHealth - section.damage, damage);
|
||||
float particleAmount = MathHelper.Lerp(0, 25, MathUtils.InverseLerp(0, 100, dmg * Rand.Range(0.75f, 1.25f)));
|
||||
@@ -898,8 +898,8 @@ namespace Barotrauma
|
||||
{
|
||||
var worldRect = section.WorldRect;
|
||||
Vector2 particlePos = new Vector2(
|
||||
Rand.Range(worldRect.X, worldRect.Right),
|
||||
Rand.Range(worldRect.Y - worldRect.Height, worldRect.Y));
|
||||
Rand.Range(worldRect.X, worldRect.Right + 1),
|
||||
Rand.Range(worldRect.Y - worldRect.Height, worldRect.Y + 1));
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle("shrapnel", particlePos, Rand.Vector(Rand.Range(1.0f, 50.0f)), collisionIgnoreTimer: 1f);
|
||||
if (particle == null) break;
|
||||
@@ -1016,7 +1016,10 @@ namespace Barotrauma
|
||||
damageAmount = attack.GetStructureDamage(deltaTime);
|
||||
AddDamage(i, damageAmount, attacker);
|
||||
#if CLIENT
|
||||
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
||||
if (attack.EmitStructureDamageParticles)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1034,7 +1037,7 @@ namespace Barotrauma
|
||||
|
||||
if (Submarine != null && damageAmount > 0 && attacker != null)
|
||||
{
|
||||
var abilityAttackerSubmarine = new AbilityCharacterSubmarine(attacker, Submarine);
|
||||
var abilityAttackerSubmarine = new AbilityAttackerSubmarine(attacker, Submarine);
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
character.CheckTalents(AbilityEffectType.AfterSubmarineAttacked, abilityAttackerSubmarine);
|
||||
@@ -1529,6 +1532,7 @@ namespace Barotrauma
|
||||
public virtual void Reset()
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, Prefab.ConfigElement);
|
||||
MaxHealth = Prefab.Health;
|
||||
Sprite.ReloadXML();
|
||||
SpriteDepth = Sprite.Depth;
|
||||
NoAITarget = Prefab.NoAITarget;
|
||||
@@ -1542,4 +1546,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AbilityAttackerSubmarine : AbilityObject, IAbilityCharacter, IAbilitySubmarine
|
||||
{
|
||||
public AbilityAttackerSubmarine(Character character, Submarine submarine)
|
||||
{
|
||||
Character = character;
|
||||
Submarine = submarine;
|
||||
}
|
||||
public Character Character { get; set; }
|
||||
public Submarine Submarine { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1535,7 +1535,7 @@ namespace Barotrauma
|
||||
element.Add(new XAttribute("tags", Info.Tags.ToString()));
|
||||
element.Add(new XAttribute("gameversion", GameMain.Version.ToString()));
|
||||
|
||||
Rectangle dimensions = CalculateDimensions();
|
||||
Rectangle dimensions = VisibleBorders;
|
||||
element.Add(new XAttribute("dimensions", XMLExtensions.Vector2ToString(dimensions.Size.ToVector2())));
|
||||
var cargoContainers = GetCargoContainers();
|
||||
element.Add(new XAttribute("cargocapacity", cargoContainers.Sum(c => c.container.Capacity)));
|
||||
@@ -1615,7 +1615,7 @@ namespace Barotrauma
|
||||
Info.CheckSubsLeftBehind(element);
|
||||
}
|
||||
|
||||
public bool SaveAs(string filePath, System.IO.MemoryStream previewImage = null)
|
||||
public bool TrySaveAs(string filePath, System.IO.MemoryStream previewImage = null)
|
||||
{
|
||||
var newInfo = new SubmarineInfo(this)
|
||||
{
|
||||
@@ -1628,8 +1628,19 @@ namespace Barotrauma
|
||||
//remove reference to the preview image from the old info, so we don't dispose it (the new info still uses the texture)
|
||||
Info.PreviewImage = null;
|
||||
#endif
|
||||
Info.Dispose(); Info = newInfo;
|
||||
return newInfo.SaveAs(filePath, previewImage);
|
||||
Info.Dispose();
|
||||
Info = newInfo;
|
||||
|
||||
try
|
||||
{
|
||||
newInfo.SaveAs(filePath, previewImage);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"Saving submarine \"{filePath}\" failed!", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool Unloading
|
||||
@@ -1643,9 +1654,8 @@ namespace Barotrauma
|
||||
Unloading = true;
|
||||
|
||||
#if CLIENT
|
||||
RemoveAllRoundSounds(); //Sound.OnGameEnd();
|
||||
|
||||
if (GameMain.LightManager != null) GameMain.LightManager.ClearLights();
|
||||
RemoveAllRoundSounds();
|
||||
GameMain.LightManager?.ClearLights();
|
||||
#endif
|
||||
|
||||
var _loaded = new List<Submarine>(loaded);
|
||||
@@ -1766,7 +1776,7 @@ namespace Barotrauma
|
||||
if (connectedWp.isObstructed) { continue; }
|
||||
Vector2 start = ConvertUnits.ToSimUnits(wp.WorldPosition);
|
||||
Vector2 end = ConvertUnits.ToSimUnits(connectedWp.WorldPosition);
|
||||
var body = Submarine.PickBody(start, end, null, Physics.CollisionLevel, allowInsideFixture: false);
|
||||
var body = PickBody(start, end, null, Physics.CollisionLevel, allowInsideFixture: false);
|
||||
if (body != null)
|
||||
{
|
||||
connectedWp.isObstructed = true;
|
||||
@@ -1793,7 +1803,7 @@ namespace Barotrauma
|
||||
foreach (var connection in node.connections)
|
||||
{
|
||||
var connectedWp = connection.Waypoint;
|
||||
if (connectedWp.isObstructed) { continue; }
|
||||
if (connectedWp.isObstructed || connectedWp.Ladders != null) { continue; }
|
||||
Vector2 start = ConvertUnits.ToSimUnits(wp.WorldPosition) - otherSub.SimPosition;
|
||||
Vector2 end = ConvertUnits.ToSimUnits(connectedWp.WorldPosition) - otherSub.SimPosition;
|
||||
var body = PickBody(start, end, null, Physics.CollisionWall, allowInsideFixture: true);
|
||||
|
||||
@@ -115,6 +115,8 @@ namespace Barotrauma
|
||||
{
|
||||
this.submarine = sub;
|
||||
|
||||
Vector2 minExtents = Vector2.Zero, maxExtents = Vector2.Zero;
|
||||
Vector2 visibleMinExtents = Vector2.Zero, visibleMaxExtents = Vector2.Zero;
|
||||
Body farseerBody = null;
|
||||
if (!Hull.hullList.Any(h => h.Submarine == sub))
|
||||
{
|
||||
@@ -133,8 +135,6 @@ namespace Barotrauma
|
||||
}
|
||||
HullVertices = convexHull;
|
||||
|
||||
Vector2 minExtents = Vector2.Zero, maxExtents = Vector2.Zero;
|
||||
Vector2 visibleMinExtents = Vector2.Zero, visibleMaxExtents = Vector2.Zero;
|
||||
|
||||
farseerBody = GameMain.World.CreateBody();
|
||||
farseerBody.UserData = this;
|
||||
@@ -142,25 +142,18 @@ namespace Barotrauma
|
||||
{
|
||||
if (mapEntity.Submarine != submarine || !(mapEntity is Structure wall)) { continue; }
|
||||
|
||||
bool hasCollider = wall.HasBody && !wall.IsPlatform && wall.StairDirection == Direction.None;
|
||||
Rectangle rect = wall.Rect;
|
||||
visibleMinExtents.X = Math.Min(rect.X, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(rect.Y - rect.Height, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(rect.Right, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(rect.Y, visibleMaxExtents.Y);
|
||||
|
||||
if (!wall.HasBody || wall.IsPlatform || wall.StairDirection != Direction.None) { continue; }
|
||||
|
||||
farseerBody.CreateRectangle(
|
||||
ConvertUnits.ToSimUnits(wall.BodyWidth),
|
||||
ConvertUnits.ToSimUnits(wall.BodyHeight),
|
||||
50.0f,
|
||||
-wall.BodyRotation,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + wall.BodyOffset)).UserData = wall;
|
||||
|
||||
minExtents.X = Math.Min(visibleMinExtents.X, minExtents.X);
|
||||
minExtents.Y = Math.Min(visibleMinExtents.Y, minExtents.Y);
|
||||
maxExtents.X = Math.Max(visibleMaxExtents.X, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(visibleMaxExtents.Y, maxExtents.Y);
|
||||
SetExtents(new Vector2(rect.X, rect.Y - rect.Height), new Vector2(rect.Right, rect.Y), hasCollider);
|
||||
if (hasCollider)
|
||||
{
|
||||
farseerBody.CreateRectangle(
|
||||
ConvertUnits.ToSimUnits(wall.BodyWidth),
|
||||
ConvertUnits.ToSimUnits(wall.BodyHeight),
|
||||
50.0f,
|
||||
-wall.BodyRotation,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2) + wall.BodyOffset)).UserData = wall;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
@@ -168,21 +161,13 @@ namespace Barotrauma
|
||||
if (hull.Submarine != submarine || hull.IdFreed) { continue; }
|
||||
|
||||
Rectangle rect = hull.Rect;
|
||||
SetExtents(new Vector2(rect.X, rect.Y - rect.Height), new Vector2(rect.Right, rect.Y), hasCollider: true);
|
||||
|
||||
farseerBody.CreateRectangle(
|
||||
ConvertUnits.ToSimUnits(rect.Width),
|
||||
ConvertUnits.ToSimUnits(rect.Height),
|
||||
100.0f,
|
||||
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2, rect.Y - rect.Height / 2))).UserData = hull;
|
||||
|
||||
visibleMinExtents.X = Math.Min(rect.X, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(rect.Y - rect.Height, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(rect.Right, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(rect.Y, visibleMaxExtents.Y);
|
||||
|
||||
minExtents.X = Math.Min(visibleMinExtents.X, minExtents.X);
|
||||
minExtents.Y = Math.Min(visibleMinExtents.Y, minExtents.Y);
|
||||
maxExtents.X = Math.Max(visibleMaxExtents.X, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(visibleMaxExtents.Y, maxExtents.Y);
|
||||
}
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -207,31 +192,21 @@ namespace Barotrauma
|
||||
if (width > 0.0f && height > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simHeight, 5.0f, simPos));
|
||||
|
||||
visibleMinExtents.X = Math.Min(item.Position.X - width / 2, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(item.Position.Y - height / 2, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(item.Position.X + width / 2, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(item.Position.Y + height / 2, visibleMaxExtents.Y);
|
||||
SetExtents(item.Position - new Vector2(width, height) / 2, item.Position + new Vector2(width, height) / 2, hasCollider: true);
|
||||
}
|
||||
else if (radius > 0.0f && width > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simWidth, simRadius * 2, 5.0f, simPos));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos - Vector2.UnitX * simWidth / 2));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos + Vector2.UnitX * simWidth / 2));
|
||||
visibleMinExtents.X = Math.Min(item.Position.X - width / 2 - radius, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(item.Position.Y - radius, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(item.Position.X + width / 2 + radius, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(item.Position.Y + radius, visibleMaxExtents.Y);
|
||||
SetExtents(item.Position - new Vector2(width / 2 + radius, height / 2), item.Position + new Vector2(width / 2 + radius, height / 2), hasCollider: true);
|
||||
}
|
||||
else if (radius > 0.0f && height > 0.0f)
|
||||
{
|
||||
item.StaticFixtures.Add(farseerBody.CreateRectangle(simRadius * 2, height, 5.0f, simPos));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos - Vector2.UnitY * simHeight / 2));
|
||||
item.StaticFixtures.Add(farseerBody.CreateCircle(simRadius, 5.0f, simPos + Vector2.UnitX * simHeight / 2));
|
||||
visibleMinExtents.X = Math.Min(item.Position.X - radius, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(item.Position.Y - height / 2 - radius, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(item.Position.X + radius, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(item.Position.Y + height / 2 + radius, visibleMaxExtents.Y);
|
||||
SetExtents(item.Position - new Vector2(width / 2, height / 2 + radius), item.Position + new Vector2(width / 2, height / 2 + radius), hasCollider: true);
|
||||
}
|
||||
else if (radius > 0.0f)
|
||||
{
|
||||
@@ -240,12 +215,8 @@ namespace Barotrauma
|
||||
visibleMinExtents.Y = Math.Min(item.Position.Y - radius, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(item.Position.X + radius, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(item.Position.Y + radius, visibleMaxExtents.Y);
|
||||
SetExtents(item.Position - new Vector2(radius, radius), item.Position + new Vector2(radius, radius), hasCollider: true);
|
||||
}
|
||||
item.StaticFixtures.ForEach(f => f.UserData = item);
|
||||
minExtents.X = Math.Min(visibleMinExtents.X, minExtents.X);
|
||||
minExtents.Y = Math.Min(visibleMinExtents.Y, minExtents.Y);
|
||||
maxExtents.X = Math.Max(visibleMaxExtents.X, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(visibleMaxExtents.Y, maxExtents.Y);
|
||||
}
|
||||
|
||||
Borders = new Rectangle((int)minExtents.X, (int)maxExtents.Y, (int)(maxExtents.X - minExtents.X), (int)(maxExtents.Y - minExtents.Y));
|
||||
@@ -271,6 +242,21 @@ namespace Barotrauma
|
||||
farseerBody.UserData = submarine;
|
||||
|
||||
Body = new PhysicsBody(farseerBody);
|
||||
|
||||
void SetExtents(Vector2 min, Vector2 max, bool hasCollider)
|
||||
{
|
||||
visibleMinExtents.X = Math.Min(min.X, visibleMinExtents.X);
|
||||
visibleMinExtents.Y = Math.Min(min.Y, visibleMinExtents.Y);
|
||||
visibleMaxExtents.X = Math.Max(max.X, visibleMaxExtents.X);
|
||||
visibleMaxExtents.Y = Math.Max(max.Y, visibleMaxExtents.Y);
|
||||
if (hasCollider)
|
||||
{
|
||||
minExtents.X = Math.Min(min.X, minExtents.X);
|
||||
minExtents.Y = Math.Min(min.Y, minExtents.Y);
|
||||
maxExtents.X = Math.Max(max.X, maxExtents.X);
|
||||
maxExtents.Y = Math.Max(max.Y, maxExtents.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Vector2> GenerateConvexHull()
|
||||
@@ -853,6 +839,8 @@ namespace Barotrauma
|
||||
Vector2 impulse = direction * impact * 0.5f;
|
||||
impulse = impulse.ClampLength(MaxCollisionImpact);
|
||||
|
||||
float impulseMagnitude = impulse.Length();
|
||||
|
||||
if (!MathUtils.IsValid(impulse))
|
||||
{
|
||||
string errorMsg =
|
||||
@@ -919,8 +907,9 @@ namespace Barotrauma
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (item.Submarine != submarine || item.CurrentHull == null || item.body == null || !item.body.Enabled) { continue; }
|
||||
if (item.body.Mass > impulseMagnitude) { continue; }
|
||||
|
||||
item.body.ApplyLinearImpulse(item.body.Mass * impulse, 10.0f);
|
||||
item.body.ApplyLinearImpulse(impulse, 10.0f);
|
||||
item.PositionUpdateInterval = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -401,6 +401,7 @@ namespace Barotrauma
|
||||
|
||||
public bool IsVanillaSubmarine()
|
||||
{
|
||||
if (FilePath == null) { return false; }
|
||||
var vanilla = GameMain.VanillaContent;
|
||||
if (vanilla != null)
|
||||
{
|
||||
@@ -521,7 +522,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//saving/loading ----------------------------------------------------
|
||||
public bool SaveAs(string filePath, System.IO.MemoryStream previewImage = null)
|
||||
public void SaveAs(string filePath, System.IO.MemoryStream previewImage = null)
|
||||
{
|
||||
var newElement = new XElement(
|
||||
SubmarineElement.Name,
|
||||
@@ -543,18 +544,9 @@ namespace Barotrauma
|
||||
{
|
||||
doc.Root.Add(new XAttribute("previewimage", Convert.ToBase64String(previewImage.ToArray())));
|
||||
}
|
||||
try
|
||||
{
|
||||
SaveUtil.CompressStringToFile(filePath, doc.ToString());
|
||||
Md5Hash.RemoveFromCache(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Saving submarine \"" + filePath + "\" failed!", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
SaveUtil.CompressStringToFile(filePath, doc.ToString());
|
||||
Md5Hash.RemoveFromCache(filePath);
|
||||
}
|
||||
|
||||
public static void AddToSavedSubs(SubmarineInfo subInfo)
|
||||
|
||||
Reference in New Issue
Block a user