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