Unstable 0.16.0.0

This commit is contained in:
Markus Isberg
2022-01-14 01:28:24 +09:00
parent d9baeaa2e1
commit 7d6421a548
237 changed files with 6430 additions and 2205 deletions
@@ -794,7 +794,7 @@ namespace Barotrauma.MapCreatures.Behavior
if (parent != null)
{
if (otherBranch.BlockedSides.IsBitSet(connectingSide))
if (otherBranch.BlockedSides.HasFlag(connectingSide))
{
branch.BlockedSides |= oppositeSide;
continue;
@@ -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))
{
@@ -1233,7 +1233,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)
@@ -574,9 +574,9 @@ 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);
@@ -613,8 +613,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 +628,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 +1035,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);
@@ -2897,6 +2921,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 +2937,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));
@@ -3627,10 +3652,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)");
@@ -433,6 +433,31 @@ 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 separatingEntity)
{
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 != fixture && contactEdge.Contact.FixtureB != fixture)
{
if (GetEntity(contactEdge.Contact.FixtureB) == separatingEntity || GetEntity(contactEdge.Contact.FixtureA) == separatingEntity) { 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 +497,6 @@ namespace Barotrauma
{
if (ParentTrigger != null && !ParentTrigger.IsTriggered) { return; }
triggerers.RemoveWhere(t => t.Removed);
RemoveDistantTriggerers(PhysicsBody, triggerers, WorldPosition);
bool isNotClient = true;
#if CLIENT
@@ -583,15 +605,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,7 +684,7 @@ 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);
}
}
}
@@ -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
@@ -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)
{
@@ -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; }
}
}
}
@@ -20,14 +20,14 @@ namespace Barotrauma
protected List<ushort> linkedToID;
public List<ushort> unresolvedLinkedToID;
/// <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 +101,7 @@ namespace Barotrauma
return !DrawBelowWater;
}
}
public virtual bool Linkable
{
get { return false; }
@@ -231,6 +231,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 +245,7 @@ namespace Barotrauma
{
get { return ""; }
}
public MapEntity(MapEntityPrefab prefab, Submarine submarine, ushort id) : base(submarine, id)
{
this.prefab = prefab;
@@ -303,7 +306,7 @@ namespace Barotrauma
{
return GetUpgrade(identifier) != null;
}
public Upgrade GetUpgrade(string identifier)
{
return Upgrades.Find(upgrade => upgrade.Identifier == identifier);
@@ -329,7 +332,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>
@@ -435,7 +438,7 @@ 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;
@@ -552,7 +555,7 @@ namespace Barotrauma
}
//update gaps in random order, because otherwise in rooms with multiple gaps
//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
@@ -725,11 +728,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}\".");
@@ -770,7 +773,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; }
@@ -338,6 +338,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]
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)));
@@ -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);
@@ -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;
}
@@ -521,7 +521,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 +543,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)