v0.10.5.1
This commit is contained in:
@@ -23,8 +23,9 @@ namespace Barotrauma
|
||||
private readonly float screenColorRange, screenColorDuration;
|
||||
|
||||
private bool sparks, shockwave, flames, smoke, flash, underwaterBubble;
|
||||
private float flashDuration;
|
||||
private float? flashRange;
|
||||
private bool applyFireEffects;
|
||||
private readonly float flashDuration;
|
||||
private readonly float? flashRange;
|
||||
private readonly string decal;
|
||||
private readonly float decalSize;
|
||||
|
||||
@@ -57,6 +58,8 @@ namespace Barotrauma
|
||||
underwaterBubble = element.GetAttributeBool("underwaterbubble", true);
|
||||
smoke = element.GetAttributeBool("smoke", true);
|
||||
|
||||
applyFireEffects = element.GetAttributeBool("applyfireeffects", flames);
|
||||
|
||||
flash = element.GetAttributeBool("flash", true);
|
||||
flashDuration = element.GetAttributeFloat("flashduration", 0.05f);
|
||||
if (element.Attribute("flashrange") != null) { flashRange = element.GetAttributeFloat("flashrange", 100.0f); }
|
||||
@@ -64,7 +67,7 @@ namespace Barotrauma
|
||||
EmpStrength = element.GetAttributeFloat("empstrength", 0.0f);
|
||||
|
||||
decal = element.GetAttributeString("decal", "");
|
||||
decalSize = element.GetAttributeFloat("decalSize", 1.0f);
|
||||
decalSize = element.GetAttributeFloat(1.0f, "decalSize", "decalsize");
|
||||
|
||||
cameraShake = element.GetAttributeFloat("camerashake", attack.Range * 0.1f);
|
||||
cameraShakeRange = element.GetAttributeFloat("camerashakerange", attack.Range);
|
||||
@@ -98,9 +101,13 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Hull hull = Hull.FindHull(worldPosition);
|
||||
|
||||
ExplodeProjSpecific(worldPosition, hull);
|
||||
|
||||
if (hull != null && !string.IsNullOrWhiteSpace(decal) && decalSize > 0.0f)
|
||||
{
|
||||
hull.AddDecal(decal, worldPosition, decalSize, true);
|
||||
}
|
||||
|
||||
float displayRange = attack.Range;
|
||||
|
||||
Vector2 cameraPos = Character.Controlled != null ? Character.Controlled.WorldPosition : GameMain.GameScreen.Cam.Position;
|
||||
@@ -161,7 +168,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (item.Condition <= 0.0f) { continue; }
|
||||
if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.5f) { continue; }
|
||||
if (flames && !item.FireProof)
|
||||
if (applyFireEffects && !item.FireProof)
|
||||
{
|
||||
//don't apply OnFire effects if the item is inside a fireproof container
|
||||
//(or if it's inside a container that's inside a fireproof container, etc)
|
||||
@@ -231,8 +238,11 @@ namespace Barotrauma
|
||||
|
||||
Dictionary<Limb, float> distFactors = new Dictionary<Limb, float>();
|
||||
Dictionary<Limb, float> damages = new Dictionary<Limb, float>();
|
||||
List<Affliction> modifiedAfflictions = new List<Affliction>();
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
if (limb.IsSevered || limb.ignoreCollisions) { continue; }
|
||||
|
||||
float dist = Vector2.Distance(limb.WorldPosition, worldPosition);
|
||||
|
||||
//calculate distance from the "outer surface" of the physics body
|
||||
@@ -244,19 +254,49 @@ namespace Barotrauma
|
||||
|
||||
float distFactor = 1.0f - dist / attack.Range;
|
||||
|
||||
//solid obstacles between the explosion and the limb reduce the effect of the explosion by 90%
|
||||
if (Submarine.CheckVisibility(limb.SimPosition, explosionPos) != null)
|
||||
//solid obstacles between the explosion and the limb reduce the effect of the explosion
|
||||
var obstacles = Submarine.PickBodies(limb.SimPosition, explosionPos, collisionCategory: Physics.CollisionItem | Physics.CollisionItemBlocking | Physics.CollisionWall);
|
||||
foreach (var body in obstacles)
|
||||
{
|
||||
distFactor *= 0.1f;
|
||||
if (body.UserData is Item item)
|
||||
{
|
||||
var door = item.GetComponent<Door>();
|
||||
if (door != null && !door.IsBroken) { distFactor *= 0.01f; }
|
||||
}
|
||||
else if (body.UserData is Structure structure)
|
||||
{
|
||||
int sectionIndex = structure.FindSectionIndex(worldPosition, world: true, clamp: true);
|
||||
if (structure.SectionBodyDisabled(sectionIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (structure.SectionIsLeaking(sectionIndex))
|
||||
{
|
||||
distFactor *= 0.1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
distFactor *= 0.01f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
distFactor *= 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
if (distFactor <= 0.05f) { continue; }
|
||||
|
||||
distFactors.Add(limb, distFactor);
|
||||
|
||||
List<Affliction> modifiedAfflictions = new List<Affliction>();
|
||||
int limbCount = c.AnimController.Limbs.Count(l => !l.IsSevered && !l.ignoreCollisions);
|
||||
|
||||
modifiedAfflictions.Clear();
|
||||
foreach (Affliction affliction in attack.Afflictions.Keys)
|
||||
{
|
||||
modifiedAfflictions.Add(affliction.CreateMultiplied(distFactor / limbCount));
|
||||
//previously the damage would be divided by the number of limbs (the intention was to prevent characters with more limbs taking more damage from explosions)
|
||||
//that didn't work well on large characters like molochs and endworms: the explosions tend to only damage one or two of their limbs, and since the characters
|
||||
//have lots of limbs, they tended to only take a fraction of the damage they should
|
||||
|
||||
//now we just divide by 10, which keeps the damage to normal-sized characters roughly the same as before and fixes the large characters
|
||||
modifiedAfflictions.Add(affliction.CreateMultiplied(distFactor / 10));
|
||||
}
|
||||
c.LastDamageSource = damageSource;
|
||||
if (attacker == null)
|
||||
@@ -273,7 +313,8 @@ namespace Barotrauma
|
||||
|
||||
//use a position slightly from the limb's position towards the explosion
|
||||
//ensures that the attack hits the correct limb and that the direction of the hit can be determined correctly in the AddDamage methods
|
||||
Vector2 hitPos = limb.WorldPosition + (worldPosition - limb.WorldPosition) / dist * 0.01f;
|
||||
Vector2 dir = worldPosition - limb.WorldPosition;
|
||||
Vector2 hitPos = limb.WorldPosition + (dir.LengthSquared() <= 0.001f ? Rand.Vector(1.0f) : Vector2.Normalize(dir)) * 0.01f;
|
||||
AttackResult attackResult = c.AddDamage(hitPos, modifiedAfflictions, attack.Stun * distFactor, false, attacker: attacker);
|
||||
damages.Add(limb, attackResult.Damage);
|
||||
|
||||
|
||||
@@ -29,9 +29,7 @@ namespace Barotrauma
|
||||
|
||||
protected bool removed;
|
||||
|
||||
#if CLIENT
|
||||
private List<Decal> burnDecals = new List<Decal>();
|
||||
#endif
|
||||
private readonly List<Decal> burnDecals = new List<Decal>();
|
||||
|
||||
public Vector2 Position
|
||||
{
|
||||
@@ -136,10 +134,8 @@ namespace Barotrauma
|
||||
- leftEdge;
|
||||
|
||||
fireSources[j].position.X = leftEdge;
|
||||
#if CLIENT
|
||||
fireSources[j].burnDecals.AddRange(fireSources[i].burnDecals);
|
||||
fireSources[j].burnDecals.Sort((d1, d2) => { return Math.Sign(d1.WorldPosition.X - d2.WorldPosition.X); });
|
||||
#endif
|
||||
fireSources[i].Remove();
|
||||
}
|
||||
}
|
||||
@@ -179,7 +175,33 @@ namespace Barotrauma
|
||||
|
||||
LimitSize();
|
||||
|
||||
if (size.X > 256.0f)
|
||||
{
|
||||
if (burnDecals.Count == 0)
|
||||
{
|
||||
var newDecal = hull.AddDecal("burnt", WorldPosition + size / 2, 1f, true);
|
||||
if (newDecal != null) { burnDecals.Add(newDecal); }
|
||||
}
|
||||
else if (WorldPosition.X < burnDecals[0].WorldPosition.X - 256.0f)
|
||||
{
|
||||
var newDecal = hull.AddDecal("burnt", WorldPosition, 1f, true);
|
||||
if (newDecal != null) { burnDecals.Insert(0, newDecal); }
|
||||
}
|
||||
else if (WorldPosition.X + size.X > burnDecals[burnDecals.Count - 1].WorldPosition.X + 256.0f)
|
||||
{
|
||||
var newDecal = hull.AddDecal("burnt", WorldPosition + Vector2.UnitX * size.X, 1f, true);
|
||||
if (newDecal != null) { burnDecals.Add(newDecal); }
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Decal d in burnDecals)
|
||||
{
|
||||
//prevent the decals from fading out as long as the firesource is alive
|
||||
d.ForceRefreshFadeTimer(Math.Min(d.FadeTimer, d.FadeInTime));
|
||||
}
|
||||
|
||||
UpdateProjSpecific(growModifier);
|
||||
|
||||
|
||||
if (size.X < 1.0f && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer))
|
||||
{
|
||||
@@ -366,12 +388,11 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
lightSource?.Remove();
|
||||
lightSource = null;
|
||||
|
||||
#endif
|
||||
foreach (Decal d in burnDecals)
|
||||
{
|
||||
d.StopFadeIn();
|
||||
}
|
||||
#endif
|
||||
hull?.RemoveFire(this);
|
||||
removed = true;
|
||||
}
|
||||
|
||||
@@ -160,9 +160,15 @@ namespace Barotrauma
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
DebugConsole.ThrowError($"Attempted to move a gap by an invalid amount ({amount})\n{Environment.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
base.Move(amount);
|
||||
|
||||
if (!DisableHullRechecks) FindHulls();
|
||||
if (!DisableHullRechecks) { FindHulls(); }
|
||||
}
|
||||
|
||||
public static void UpdateHulls()
|
||||
|
||||
@@ -4,11 +4,100 @@ using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class BackgroundSection
|
||||
{
|
||||
public Rectangle Rect;
|
||||
public int Index;
|
||||
public int RowIndex;
|
||||
|
||||
private Vector4 colorVector4;
|
||||
private Color color;
|
||||
|
||||
public readonly Vector2 Noise;
|
||||
public readonly Color DirtColor;
|
||||
|
||||
public float ColorStrength
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get { return color; }
|
||||
protected set
|
||||
{
|
||||
color = value;
|
||||
colorVector4 = new Vector4(value.R / 255.0f, value.G / 255.0f, value.B / 255.0f, value.A / 255.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public BackgroundSection(Rectangle rect, int index, int rowIndex)
|
||||
{
|
||||
Rect = rect;
|
||||
Index = index;
|
||||
ColorStrength = 0.0f;
|
||||
RowIndex = rowIndex;
|
||||
|
||||
Noise = new Vector2(
|
||||
PerlinNoise.GetPerlin(Rect.X / 1000.0f, Rect.Y / 1000.0f),
|
||||
PerlinNoise.GetPerlin(Rect.Y / 1000.0f + 0.5f, Rect.X / 1000.0f + 0.5f));
|
||||
|
||||
Color = DirtColor = Color.Lerp(new Color(10, 10, 10, 100), new Color(54, 57, 28, 200), Noise.X);
|
||||
}
|
||||
|
||||
public BackgroundSection(Rectangle rect, int index, float colorStrength, Color color, int rowIndex)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(rect.Width > 0 && rect.Height > 0);
|
||||
|
||||
Rect = rect;
|
||||
Index = index;
|
||||
ColorStrength = colorStrength;
|
||||
Color = color;
|
||||
RowIndex = rowIndex;
|
||||
|
||||
Noise = new Vector2(
|
||||
PerlinNoise.GetPerlin(Rect.X / 1000.0f, Rect.Y / 1000.0f),
|
||||
PerlinNoise.GetPerlin(Rect.Y / 1000.0f + 0.5f, Rect.X / 1000.0f + 0.5f));
|
||||
|
||||
Color = DirtColor = Color.Lerp(new Color(10, 10, 10, 100), new Color(54, 57, 28, 200), Noise.X);
|
||||
}
|
||||
|
||||
public bool SetColor(Color color)
|
||||
{
|
||||
if (Color == color) { return false; }
|
||||
Color = color;
|
||||
return true;
|
||||
}
|
||||
|
||||
public float SetColorStrength(float colorStrength)
|
||||
{
|
||||
if (ColorStrength == colorStrength) { return -1f; }
|
||||
float previous = ColorStrength;
|
||||
ColorStrength = colorStrength;
|
||||
return previous;
|
||||
}
|
||||
|
||||
public bool LerpColor(Color to, float amount)
|
||||
{
|
||||
if (Color == to) { return false; }
|
||||
colorVector4 = Vector4.Lerp(colorVector4, to.ToVector4(), amount);
|
||||
color = new Color(colorVector4);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Color GetStrengthAdjustedColor()
|
||||
{
|
||||
return Color * ColorStrength;
|
||||
}
|
||||
}
|
||||
|
||||
partial class Hull : MapEntity, ISerializableEntity, IServerSerializable
|
||||
{
|
||||
public static List<Hull> hullList = new List<Hull>();
|
||||
@@ -29,7 +118,11 @@ namespace Barotrauma
|
||||
//how much excess water the room can contain, relative to the volume of the room.
|
||||
//needed to make it possible for pressure to "push" water up through U-shaped hull configurations
|
||||
public const float MaxCompress = 1.05f;
|
||||
|
||||
|
||||
public const int BackgroundSectionSize = 16;
|
||||
|
||||
public const int BackgroundSectionsPerNetworkEvent = 16;
|
||||
|
||||
public readonly Dictionary<string, SerializableProperty> properties;
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
@@ -54,6 +147,11 @@ namespace Barotrauma
|
||||
private float[] leftDelta;
|
||||
private float[] rightDelta;
|
||||
|
||||
public const int MaxDecalsPerHull = 10;
|
||||
|
||||
private readonly List<Decal> decals = new List<Decal>();
|
||||
|
||||
|
||||
public readonly List<Gap> ConnectedGaps = new List<Gap>();
|
||||
|
||||
public override string Name
|
||||
@@ -140,6 +238,8 @@ namespace Barotrauma
|
||||
OxygenPercentage = prevOxygenPercentage;
|
||||
surface = drawSurface = rect.Y - rect.Height + WaterVolume / rect.Width;
|
||||
Pressure = surface;
|
||||
|
||||
CreateBackgroundSections();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +286,8 @@ namespace Barotrauma
|
||||
get { return Submarine == null ? surface : surface + Submarine.Position.Y; }
|
||||
}
|
||||
|
||||
private float dirtiedVolume = 0.0f;
|
||||
|
||||
public float WaterVolume
|
||||
{
|
||||
get { return waterVolume; }
|
||||
@@ -193,8 +295,25 @@ namespace Barotrauma
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
waterVolume = MathHelper.Clamp(value, 0.0f, Volume * MaxCompress);
|
||||
if (waterVolume < Volume) Pressure = rect.Y - rect.Height + waterVolume / rect.Width;
|
||||
if (waterVolume > 0.0f) update = true;
|
||||
if (waterVolume < Volume) { Pressure = rect.Y - rect.Height + waterVolume / rect.Width; }
|
||||
if (waterVolume > 0.0f)
|
||||
{
|
||||
update = true;
|
||||
if (BackgroundSections != null)
|
||||
{
|
||||
float volumeMultiplier = Math.Clamp(waterVolume / Volume, 0f, 1f);
|
||||
if (Math.Abs(volumeMultiplier - dirtiedVolume) > 0.075f)
|
||||
{
|
||||
RefreshSubmergedSections(new Rectangle(new Point(0, -rect.Height), new Point(rect.Width, (int)(rect.Height * volumeMultiplier))));
|
||||
dirtiedVolume = volumeMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
submergedSections.Clear();
|
||||
dirtiedVolume = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +357,36 @@ namespace Barotrauma
|
||||
get { return waveVel; }
|
||||
}
|
||||
|
||||
// sections of a decorative background that can be painted
|
||||
public List<BackgroundSection> BackgroundSections
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private readonly HashSet<int> pendingSectionUpdates = new HashSet<int>();
|
||||
|
||||
private readonly List<BackgroundSection> submergedSections = new List<BackgroundSection>();
|
||||
|
||||
public int xBackgroundMax, yBackgroundMax;
|
||||
|
||||
public bool SupportsPaintedColors
|
||||
{
|
||||
get
|
||||
{
|
||||
return BackgroundSections != null;
|
||||
}
|
||||
}
|
||||
|
||||
private const int sectorWidth = 4;
|
||||
private const int sectorHeight = 4;
|
||||
|
||||
private const float minColorStrength = 0.0f;
|
||||
private const float maxColorStrength = 0.7f;
|
||||
|
||||
private bool networkUpdatePending;
|
||||
private float networkUpdateTimer;
|
||||
|
||||
public List<FireSource> FireSources { get; private set; }
|
||||
|
||||
public Hull(MapEntityPrefab prefab, Rectangle rectangle)
|
||||
@@ -250,6 +399,8 @@ namespace Barotrauma
|
||||
: base (prefab, submarine)
|
||||
{
|
||||
rect = rectangle;
|
||||
|
||||
if (BackgroundSections == null) { CreateBackgroundSections(); }
|
||||
|
||||
OxygenPercentage = 100.0f;
|
||||
|
||||
@@ -284,6 +435,8 @@ namespace Barotrauma
|
||||
Gap.UpdateHulls();
|
||||
}
|
||||
|
||||
CreateBackgroundSections();
|
||||
|
||||
WaterVolume = 0.0f;
|
||||
|
||||
InsertToList();
|
||||
@@ -399,6 +552,12 @@ namespace Barotrauma
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
DebugConsole.ThrowError($"Attempted to move a hull by an invalid amount ({amount})\n{Environment.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
rect.X += (int)amount.X;
|
||||
rect.Y += (int)amount.Y;
|
||||
|
||||
@@ -471,6 +630,48 @@ namespace Barotrauma
|
||||
FireSources.Add(fireSource);
|
||||
}
|
||||
|
||||
public Decal AddDecal(UInt32 decalId, Vector2 worldPosition, float scale, bool isNetworkEvent)
|
||||
{
|
||||
//clients are only allowed to create decals when the server says so
|
||||
if (!isNetworkEvent && GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var decal = GameMain.DecalManager.Prefabs.Find(p => p.UIntIdentifier == decalId);
|
||||
if (decal == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find a decal prefab with the UInt identifier {decalId}!");
|
||||
return null;
|
||||
}
|
||||
return AddDecal(decal.Name, worldPosition, scale, isNetworkEvent);
|
||||
}
|
||||
|
||||
|
||||
public Decal AddDecal(string decalName, Vector2 worldPosition, float scale, bool isNetworkEvent)
|
||||
{
|
||||
//clients are only allowed to create decals when the server says so
|
||||
if (!isNetworkEvent && GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (decals.Count >= MaxDecalsPerHull) { return null; }
|
||||
|
||||
var decal = GameMain.DecalManager.CreateDecal(decalName, scale, worldPosition, this);
|
||||
if (decal != null)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { false });
|
||||
}
|
||||
decals.Add(decal);
|
||||
}
|
||||
|
||||
return decal;
|
||||
}
|
||||
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
@@ -480,6 +681,13 @@ namespace Barotrauma
|
||||
|
||||
FireSource.UpdateAll(FireSources, deltaTime);
|
||||
|
||||
foreach (Decal decal in decals)
|
||||
{
|
||||
decal.Update(deltaTime);
|
||||
}
|
||||
decals.RemoveAll(d => d.FadeTimer >= d.LifeTime || d.BaseAlpha <= 0.001f);
|
||||
|
||||
|
||||
if (aiTarget != null)
|
||||
{
|
||||
aiTarget.SightRange = Submarine == null ? aiTarget.MinSightRange : Submarine.Velocity.Length() / 2 * aiTarget.MaxSightRange;
|
||||
@@ -596,6 +804,12 @@ 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)
|
||||
{
|
||||
DirtySections(submergedSections, 0.01f);
|
||||
}
|
||||
|
||||
if (waterVolume < Volume)
|
||||
{
|
||||
LethalPressure -= 10.0f * deltaTime;
|
||||
@@ -906,9 +1120,180 @@ namespace Barotrauma
|
||||
return "RoomName.Sub" + roomPos.ToString();
|
||||
}
|
||||
|
||||
#region BackgroundSections
|
||||
private void CreateBackgroundSections()
|
||||
{
|
||||
int sectionWidth, sectionHeight;
|
||||
|
||||
sectionWidth = sectionHeight = BackgroundSectionSize;
|
||||
|
||||
xBackgroundMax = rect.Width / sectionWidth;
|
||||
yBackgroundMax = rect.Height / sectionHeight;
|
||||
|
||||
BackgroundSections = new List<BackgroundSection>(xBackgroundMax * yBackgroundMax);
|
||||
|
||||
int sections = xBackgroundMax * yBackgroundMax;
|
||||
float xSectors = xBackgroundMax / (float)sectorWidth;
|
||||
|
||||
for (int y = 0; y < yBackgroundMax; y++)
|
||||
{
|
||||
for (int x = 0; x < xBackgroundMax; x++)
|
||||
{
|
||||
int index = BackgroundSections.Count;
|
||||
int sector = (int)Math.Floor(index / (float)sectorWidth - xSectors * y) + y / sectorHeight * (int)Math.Ceiling(xSectors);
|
||||
BackgroundSections.Add(new BackgroundSection(new Rectangle(x * sectionWidth, y * -sectionHeight, sectionWidth, sectionHeight), index, y));
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
minimumPaintAmountToDraw = maxColorStrength / BackgroundSections.Count;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Hull GetCleanTarget(Vector2 worldPosition)
|
||||
{
|
||||
foreach (Hull hull in hullList)
|
||||
{
|
||||
Rectangle worldRect = hull.WorldRect;
|
||||
if (worldPosition.X < worldRect.X || worldPosition.X > worldRect.Right) { continue; }
|
||||
if (worldPosition.Y > worldRect.Y || worldPosition.Y < worldRect.Y - worldRect.Height) { continue; }
|
||||
return hull;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BackgroundSection GetBackgroundSection(Vector2 worldPosition)
|
||||
{
|
||||
if (!SupportsPaintedColors) { return null; }
|
||||
|
||||
Vector2 subOffset = Submarine == null ? Vector2.Zero : Submarine.Position;
|
||||
Vector2 relativePosition = new Vector2(worldPosition.X - subOffset.X - rect.X, worldPosition.Y - subOffset.Y - rect.Y);
|
||||
|
||||
int xIndex = (int)Math.Floor(relativePosition.X / BackgroundSectionSize);
|
||||
if (xIndex < 0 || xIndex >= xBackgroundMax) { return null; }
|
||||
int yIndex = (int)Math.Floor(-relativePosition.Y / BackgroundSectionSize);
|
||||
if (yIndex < 0 || yIndex >= yBackgroundMax) { return null; }
|
||||
|
||||
return BackgroundSections[xIndex + yIndex * xBackgroundMax];
|
||||
}
|
||||
|
||||
public IEnumerable<BackgroundSection> GetBackgroundSectionsViaContaining(Rectangle rectArea)
|
||||
{
|
||||
if (BackgroundSections == null || BackgroundSections.Count == 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int xMin = Math.Max(rectArea.X / BackgroundSectionSize, 0);
|
||||
if (xMin >= xBackgroundMax) { yield break; }
|
||||
int xMax = Math.Min(rectArea.Right / BackgroundSectionSize, xBackgroundMax - 1);
|
||||
if (xMax < 0) { yield break; }
|
||||
|
||||
int yMin = Math.Max(-rectArea.Bottom / BackgroundSectionSize, 0);
|
||||
if (yMin >= yBackgroundMax) { yield break; }
|
||||
int yMax = Math.Min(-rectArea.Y / BackgroundSectionSize, yBackgroundMax - 1);
|
||||
if (yMax < 0) { yield break; }
|
||||
|
||||
for (int x = xMin; x <= xMax; x++)
|
||||
{
|
||||
for (int y = yMin; y <= yMax; y++)
|
||||
{
|
||||
yield return BackgroundSections[x + y * xBackgroundMax];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshSubmergedSections(Rectangle waterArea)
|
||||
{
|
||||
if (BackgroundSections == null) { return; }
|
||||
|
||||
submergedSections.Clear();
|
||||
foreach (var section in GetBackgroundSectionsViaContaining(waterArea))
|
||||
{
|
||||
submergedSections.Add(section);
|
||||
}
|
||||
}
|
||||
|
||||
public bool DoesSectionMatch(int index, int row)
|
||||
{
|
||||
return index >= 0 && row >= 0 && BackgroundSections.Count > index && BackgroundSections[index] != null && BackgroundSections[index].RowIndex == row;
|
||||
}
|
||||
|
||||
public void SetSectionColorOrStrength(BackgroundSection section, Color? color, float? strength, bool requiresUpdate, bool isCleaning)
|
||||
{
|
||||
bool sectionUpdated = isCleaning;
|
||||
if (color != null)
|
||||
{
|
||||
if (section.Color != color.Value && strength.HasValue)
|
||||
{
|
||||
//already painted with a different color -> interpolate towards the new one
|
||||
|
||||
//an ad-hoc formula that makes the color changes faster when the current strength is low
|
||||
//(-> a barely dirty wall gets recolored almost immediately, while a more heavily colored one takes a while)
|
||||
float changeSpeed = strength.Value / Math.Max(section.ColorStrength * section.ColorStrength, 0.001f) * 0.1f;
|
||||
if (section.LerpColor(color.Value, changeSpeed)) { sectionUpdated = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (section.SetColor(color.Value)) { sectionUpdated = true; }
|
||||
}
|
||||
}
|
||||
|
||||
if (strength != null)
|
||||
{
|
||||
float previous = section.SetColorStrength(Math.Max(minColorStrength, Math.Min(maxColorStrength, section.ColorStrength + strength.Value)));
|
||||
if (previous != -1f)
|
||||
{
|
||||
#if CLIENT
|
||||
paintAmount = Math.Max(0, paintAmount + (section.ColorStrength - previous) / BackgroundSections.Count);
|
||||
#endif
|
||||
sectionUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (sectionUpdated && GameMain.NetworkMember != null && requiresUpdate)
|
||||
{
|
||||
networkUpdatePending = true;
|
||||
pendingSectionUpdates.Add((int)Math.Floor(section.Index / (float)BackgroundSectionsPerNetworkEvent));
|
||||
#if CLIENT
|
||||
serverUpdateDelay = 0.5f;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public void DirtySections(List<BackgroundSection> sections, float dirtyVal)
|
||||
{
|
||||
if (sections == null) { return; }
|
||||
for (int i = 0; i < sections.Count; i++)
|
||||
{
|
||||
float sectionDirtyVal = dirtyVal;
|
||||
SetSectionColorOrStrength(sections[i], sections[i].DirtColor, sectionDirtyVal, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanSection(BackgroundSection section, float cleanVal, bool updateRequired)
|
||||
{
|
||||
bool decalsCleaned = false;
|
||||
for (int i = 0; i < decals.Count; i++)
|
||||
{
|
||||
Decal decal = decals[i];
|
||||
if (decal.AffectsSection(section))
|
||||
{
|
||||
decal.Clean(cleanVal);
|
||||
decalsCleaned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (section.ColorStrength == 0 && !decalsCleaned) { return; }
|
||||
SetSectionColorOrStrength(section, null, cleanVal, updateRequired, true);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static Hull Load(XElement element, Submarine submarine)
|
||||
{
|
||||
Rectangle rect = Rectangle.Empty;
|
||||
Rectangle rect;
|
||||
if (element.Attribute("rect") != null)
|
||||
{
|
||||
rect = element.GetAttributeRect("rect", Rectangle.Empty);
|
||||
@@ -947,6 +1332,41 @@ namespace Barotrauma
|
||||
hull.OriginalAmbientLight = XMLExtensions.ParseColor(originalAmbientLight, false);
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "decal":
|
||||
string id = subElement.GetAttributeString("id", "");
|
||||
Vector2 pos = subElement.GetAttributeVector2("pos", Vector2.Zero);
|
||||
float scale = subElement.GetAttributeFloat("scale", 1.0f);
|
||||
float timer = subElement.GetAttributeFloat("timer", 1.0f);
|
||||
var decal = hull.AddDecal(id, pos + hull.WorldRect.Location.ToVector2(), scale, true);
|
||||
if (decal != null)
|
||||
{
|
||||
decal.FadeTimer = timer;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string backgroundSectionStr = element.GetAttributeString("backgroundsections", "");
|
||||
if (!string.IsNullOrEmpty(backgroundSectionStr))
|
||||
{
|
||||
string[] backgroundSectionStrSplit = backgroundSectionStr.Split(';');
|
||||
foreach (string str in backgroundSectionStrSplit)
|
||||
{
|
||||
string[] backgroundSectionData = str.Split(':');
|
||||
if (backgroundSectionData.Length != 3) { continue; }
|
||||
Color color = XMLExtensions.ParseColor(backgroundSectionData[1]);
|
||||
if (int.TryParse(backgroundSectionData[0], out int index) &&
|
||||
float.TryParse(backgroundSectionData[2], NumberStyles.Any, CultureInfo.InvariantCulture, out float strength))
|
||||
{
|
||||
hull.SetSectionColorOrStrength(hull.BackgroundSections[index], color, strength, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SerializableProperty.DeserializeProperties(hull, element);
|
||||
if (element.Attribute("oxygen") == null) { hull.Oxygen = hull.Volume; }
|
||||
|
||||
@@ -976,7 +1396,7 @@ namespace Barotrauma
|
||||
|
||||
if (linkedTo != null && linkedTo.Count > 0)
|
||||
{
|
||||
var saveableLinked = linkedTo.Where(l => l.ShouldBeSaved && !l.Removed).ToList();
|
||||
var saveableLinked = linkedTo.Where(l => l.ShouldBeSaved && (l.Removed == Removed)).ToList();
|
||||
element.Add(new XAttribute("linked", string.Join(",", saveableLinked.Select(l => l.ID.ToString()))));
|
||||
}
|
||||
|
||||
@@ -985,6 +1405,25 @@ namespace Barotrauma
|
||||
element.Add(new XAttribute("originalambientlight", XMLExtensions.ColorToString(OriginalAmbientLight.Value)));
|
||||
}
|
||||
|
||||
if (BackgroundSections != null && BackgroundSections.Count > 0)
|
||||
{
|
||||
element.Add(
|
||||
new XAttribute(
|
||||
"backgroundsections",
|
||||
string.Join(';', BackgroundSections.Where(b => b.ColorStrength > 0.01f).Select(b => b.Index + ":" + XMLExtensions.ColorToString(b.Color) + ":" + b.ColorStrength.ToString("G", CultureInfo.InvariantCulture)))));
|
||||
}
|
||||
|
||||
foreach (Decal decal in decals)
|
||||
{
|
||||
element.Add(
|
||||
new XElement("decal",
|
||||
new XAttribute("id", decal.Prefab.Identifier),
|
||||
new XAttribute("pos", XMLExtensions.Vector2ToString(decal.NonClampedPosition)),
|
||||
new XAttribute("scale", decal.Scale.ToString("G", CultureInfo.InvariantCulture)),
|
||||
new XAttribute("timer", decal.FadeTimer.ToString("G", CultureInfo.InvariantCulture))
|
||||
));
|
||||
}
|
||||
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
parentElement.Add(element);
|
||||
return element;
|
||||
|
||||
@@ -42,9 +42,15 @@ namespace Barotrauma
|
||||
XDocument doc = XMLExtensions.TryLoadXml(filePath);
|
||||
if (doc == null) { return; }
|
||||
|
||||
originalName = doc.Root.GetAttributeString("name", "");
|
||||
identifier = doc.Root.GetAttributeString("identifier", null) ?? originalName.ToLowerInvariant().Replace(" ", "");
|
||||
configElement = doc.Root;
|
||||
XElement element = doc.Root;
|
||||
if (element.IsOverride())
|
||||
{
|
||||
element = element.Elements().First();
|
||||
}
|
||||
|
||||
originalName = element.GetAttributeString("name", "");
|
||||
identifier = element.GetAttributeString("identifier", null) ?? originalName.ToLowerInvariant().Replace(" ", "");
|
||||
configElement = element;
|
||||
|
||||
Category = MapEntityCategory.ItemAssembly;
|
||||
|
||||
@@ -54,7 +60,7 @@ namespace Barotrauma
|
||||
Description = TextManager.Get("EntityDescription." + identifier, returnNull: true) ?? Description;
|
||||
|
||||
List<ushort> containedItemIDs = new List<ushort>();
|
||||
foreach (XElement entityElement in doc.Root.Elements())
|
||||
foreach (XElement entityElement in element.Elements())
|
||||
{
|
||||
var containerElement = entityElement.Elements().FirstOrDefault(e => e.Name.LocalName.Equals("itemcontainer", StringComparison.OrdinalIgnoreCase));
|
||||
if (containerElement == null) { continue; }
|
||||
@@ -66,7 +72,7 @@ namespace Barotrauma
|
||||
int minX = int.MaxValue, minY = int.MaxValue;
|
||||
int maxX = int.MinValue, maxY = int.MinValue;
|
||||
DisplayEntities = new List<Pair<MapEntityPrefab, Rectangle>>();
|
||||
foreach (XElement entityElement in doc.Root.Elements())
|
||||
foreach (XElement entityElement in element.Elements())
|
||||
{
|
||||
ushort id = (ushort)entityElement.GetAttributeInt("ID", 0);
|
||||
if (id > 0 && containedItemIDs.Contains(id)) { continue; }
|
||||
@@ -94,7 +100,7 @@ namespace Barotrauma
|
||||
new Rectangle(0, 0, 1, 1) :
|
||||
new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
||||
|
||||
Prefabs.Add(this, false);
|
||||
Prefabs.Add(this, doc.Root.IsOverride());
|
||||
}
|
||||
|
||||
public static void Remove(string filePath)
|
||||
@@ -110,17 +116,17 @@ namespace Barotrauma
|
||||
public List<MapEntity> CreateInstance(Vector2 position, Submarine sub, bool selectPrefabs = false)
|
||||
{
|
||||
List<MapEntity> entities = MapEntity.LoadAll(sub, configElement, FilePath);
|
||||
if (entities.Count == 0) return entities;
|
||||
if (entities.Count == 0) { return entities; }
|
||||
|
||||
Vector2 offset = sub == null ? Vector2.Zero : sub.HiddenSubPosition;
|
||||
|
||||
foreach (MapEntity me in entities)
|
||||
{
|
||||
me.Move(position);
|
||||
Item item = me as Item;
|
||||
if (item == null) continue;
|
||||
me.Submarine = sub;
|
||||
if (!(me is Item item)) { continue; }
|
||||
Wire wire = item.GetComponent<Wire>();
|
||||
if (wire != null) wire.MoveNodes(position - offset);
|
||||
if (wire != null) { wire.MoveNodes(position - offset); }
|
||||
}
|
||||
|
||||
MapEntity.MapLoaded(entities, true);
|
||||
@@ -171,7 +177,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//find assembly files in selected content packages
|
||||
foreach (ContentPackage cp in GameMain.Config.SelectedContentPackages)
|
||||
foreach (ContentPackage cp in GameMain.Config.AllEnabledPackages)
|
||||
{
|
||||
foreach (string filePath in cp.GetFilesOfType(ContentType.ItemAssembly))
|
||||
{
|
||||
|
||||
@@ -445,8 +445,11 @@ namespace Barotrauma
|
||||
if (mainPathCellCount > tunnel.Count / 2) continue;
|
||||
|
||||
var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders);
|
||||
PositionsOfInterest.Add(new InterestingPosition(tunnel.Last(), PositionType.Cave));
|
||||
if (tunnel.Count > 4) PositionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count / 2], PositionType.Cave));
|
||||
if (newPathCells.Any())
|
||||
{
|
||||
PositionsOfInterest.Add(new InterestingPosition(newPathCells.Last().Center.ToPoint(), PositionType.Cave));
|
||||
if (newPathCells.Count > 4) { PositionsOfInterest.Add(new InterestingPosition(newPathCells[newPathCells.Count / 2].Center.ToPoint(), PositionType.Cave)); }
|
||||
}
|
||||
validTunnels.Add(tunnel);
|
||||
pathCells.AddRange(newPathCells);
|
||||
}
|
||||
@@ -574,7 +577,7 @@ namespace Barotrauma
|
||||
Ruins = new List<Ruin>();
|
||||
for (int i = 0; i < GenerationParams.RuinCount; i++)
|
||||
{
|
||||
GenerateRuin(mainPath, this, mirror);
|
||||
GenerateRuin(mainPath, mirror);
|
||||
}
|
||||
|
||||
EqualityCheckValues.Add(Rand.Int(int.MaxValue, Rand.RandSync.Server));
|
||||
@@ -1054,7 +1057,7 @@ namespace Barotrauma
|
||||
return tunnelNodes;
|
||||
}
|
||||
|
||||
private void GenerateRuin(List<VoronoiCell> mainPath, Level level, bool mirror)
|
||||
private void GenerateRuin(List<VoronoiCell> mainPath, bool mirror)
|
||||
{
|
||||
var ruinGenerationParams = RuinGenerationParams.GetRandom();
|
||||
|
||||
@@ -1075,14 +1078,19 @@ namespace Barotrauma
|
||||
ruinPos.Y = Math.Min(ruinPos.Y, borders.Y + borders.Height - ruinSize.Y / 2);
|
||||
ruinPos.Y = Math.Max(ruinPos.Y, SeaFloorTopPos + ruinSize.Y / 2);
|
||||
|
||||
double minDist = ruinRadius * 2;
|
||||
double minDistSqr = minDist * minDist;
|
||||
double minMainPathDist = ruinRadius * 2;
|
||||
double minMainPathDistSqr = minMainPathDist * minMainPathDist;
|
||||
|
||||
double minOutpostDist = Math.Min(Math.Min(10000.0f, Size.X / 3), Size.Y / 3);
|
||||
double minOutpostDistSqr = minOutpostDist * minOutpostDist;
|
||||
|
||||
int iter = 0;
|
||||
while (mainPath.Any(p => MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, p.Site.Coord.X, p.Site.Coord.Y) < minDistSqr) ||
|
||||
while (mainPath.Any(p => MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, p.Site.Coord.X, p.Site.Coord.Y) < minMainPathDistSqr) ||
|
||||
Ruins.Any(r => r.Area.Intersects(new Rectangle(ruinPos - new Point(ruinSize.X / 2, ruinSize.Y / 2), ruinSize)) ||
|
||||
MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, StartPosition.X, StartPosition.Y) < minDistSqr ||
|
||||
MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, EndPosition.X, EndPosition.Y) < minDistSqr))
|
||||
MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, StartPosition.X, StartPosition.Y) < minOutpostDistSqr ||
|
||||
MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, StartPosition.X, Size.Y) < minOutpostDistSqr ||
|
||||
MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, EndPosition.X, EndPosition.Y) < minOutpostDistSqr) ||
|
||||
MathUtils.DistanceSquared(ruinPos.X, ruinPos.Y, EndPosition.X, Size.Y) < minOutpostDistSqr)
|
||||
{
|
||||
double weighedPathPosX = ruinPos.X;
|
||||
double weighedPathPosY = ruinPos.Y;
|
||||
@@ -1094,11 +1102,11 @@ namespace Barotrauma
|
||||
double diffY = i == 0 ? ruinPos.Y - StartPosition.Y : ruinPos.Y - StartPosition.Y;
|
||||
|
||||
double distSqr = diffX * diffX + diffY * diffY;
|
||||
if (distSqr < minDistSqr)
|
||||
if (distSqr < minMainPathDistSqr)
|
||||
{
|
||||
double dist = Math.Sqrt(distSqr);
|
||||
double moveAmountX = minDist * diffX / dist;
|
||||
double moveAmountY = minDist * diffY / dist;
|
||||
double moveAmountX = minMainPathDist * diffX / dist;
|
||||
double moveAmountY = minMainPathDist * diffY / dist;
|
||||
weighedPathPosX += moveAmountX;
|
||||
weighedPathPosY += moveAmountY;
|
||||
weighedPathPosY = Math.Min(borders.Y + borders.Height - ruinSize.Y / 2, weighedPathPosY);
|
||||
@@ -1315,7 +1323,7 @@ namespace Barotrauma
|
||||
{
|
||||
holdable.AttachToWall();
|
||||
#if CLIENT
|
||||
item.SpriteRotation = -MathUtils.VectorToAngle(edgeNormal) + MathHelper.PiOver2;
|
||||
item.Rotation = MathHelper.ToDegrees(-MathUtils.VectorToAngle(edgeNormal) + MathHelper.PiOver2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1337,7 +1345,11 @@ namespace Barotrauma
|
||||
{
|
||||
Loaded.TryGetInterestingPosition(true, spawnPosType, minDistFromSubs, out Vector2 startPos);
|
||||
|
||||
startPos += Rand.Vector(Rand.Range(0.0f, randomSpread, Rand.RandSync.Server), Rand.RandSync.Server);
|
||||
Vector2 offset = Rand.Vector(Rand.Range(0.0f, randomSpread, Rand.RandSync.Server), Rand.RandSync.Server);
|
||||
if (!cells.Any(c => c.IsPointInside(startPos + offset)))
|
||||
{
|
||||
startPos += offset;
|
||||
}
|
||||
|
||||
Vector2 endPos = startPos - Vector2.UnitY * Size.Y;
|
||||
|
||||
@@ -1533,7 +1545,7 @@ namespace Barotrauma
|
||||
var totalSW = new Stopwatch();
|
||||
var tempSW = new Stopwatch();
|
||||
totalSW.Start();
|
||||
var wreckFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Wreck).ToList();
|
||||
var wreckFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.Wreck).ToList();
|
||||
if (wreckFiles.None())
|
||||
{
|
||||
DebugConsole.ThrowError("No wreck files found in the selected content packages!");
|
||||
@@ -1827,7 +1839,7 @@ namespace Barotrauma
|
||||
|
||||
private void CreateOutposts()
|
||||
{
|
||||
var outpostFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Outpost).ToList();
|
||||
var outpostFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.Outpost).ToList();
|
||||
if (!outpostFiles.Any() && !OutpostGenerationParams.Params.Any() && LevelData.ForceOutpostGenerationParams == null)
|
||||
{
|
||||
DebugConsole.ThrowError("No outpost files found in the selected content packages");
|
||||
@@ -2080,7 +2092,7 @@ namespace Barotrauma
|
||||
job ??= selectedPrefab.GetJobPrefab();
|
||||
if (job == null) { continue; }
|
||||
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job);
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: job, randSync: Rand.RandSync.Server);
|
||||
var corpse = Character.Create(CharacterPrefab.HumanConfigFile, worldPos, ToolBox.RandomSeed(8), characterInfo, hasAi: true, createNetworkEvent: true);
|
||||
corpse.AnimController.FindHull(worldPos, true);
|
||||
corpse.TeamID = Character.TeamType.None;
|
||||
@@ -2128,6 +2140,11 @@ namespace Barotrauma
|
||||
StartLocation = newStartLocation;
|
||||
}
|
||||
|
||||
public void DebugSetEndLocation(Location newEndLocation)
|
||||
{
|
||||
EndLocation = newEndLocation;
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
base.Remove();
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace Barotrauma
|
||||
public readonly Point Size;
|
||||
|
||||
public readonly List<EventPrefab> EventHistory = new List<EventPrefab>();
|
||||
public readonly List<EventPrefab> NonRepeatableEvents = new List<EventPrefab>();
|
||||
|
||||
public LevelData(string seed, float difficulty, float sizeFactor, LevelGenerationParams generationParams, Biome biome)
|
||||
{
|
||||
@@ -77,6 +78,10 @@ namespace Barotrauma
|
||||
|
||||
string[] prefabNames = element.GetAttributeStringArray("eventhistory", new string[] { });
|
||||
EventHistory.AddRange(EventSet.PrefabList.Where(p => prefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase))));
|
||||
|
||||
string[] nonRepeatablePrefabNames = element.GetAttributeStringArray("nonrepeatableevents", new string[] { });
|
||||
NonRepeatableEvents.AddRange(EventSet.PrefabList.Where(p => prefabNames.Any(n => p.Identifier.Equals(n, StringComparison.InvariantCultureIgnoreCase))));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -153,11 +158,17 @@ namespace Barotrauma
|
||||
new XAttribute("size", XMLExtensions.PointToString(Size)),
|
||||
new XAttribute("generationparams", GenerationParams.Identifier));
|
||||
|
||||
if (Type == LevelType.Outpost && EventHistory.Any())
|
||||
if (Type == LevelType.Outpost)
|
||||
{
|
||||
newElement.Add(new XAttribute("eventhistory", string.Join(',', EventHistory.Select(p => p.Identifier))));
|
||||
if (EventHistory.Any())
|
||||
{
|
||||
newElement.Add(new XAttribute("eventhistory", string.Join(',', EventHistory.Select(p => p.Identifier))));
|
||||
}
|
||||
if (NonRepeatableEvents.Any())
|
||||
{
|
||||
newElement.Add(new XAttribute("nonrepeatableevents", string.Join(',', NonRepeatableEvents.Select(p => p.Identifier))));
|
||||
}
|
||||
}
|
||||
|
||||
parentElement.Add(newElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Barotrauma
|
||||
private string filePath;
|
||||
|
||||
private bool loadSub;
|
||||
public bool LoadSub => loadSub;
|
||||
private Submarine sub;
|
||||
|
||||
private ushort originalMyPortID;
|
||||
@@ -47,6 +48,7 @@ namespace Barotrauma
|
||||
//the ID of the docking port the sub was docked to in the original sub file
|
||||
//(needed when replacing a lost sub)
|
||||
private ushort originalLinkedToID;
|
||||
public ushort OriginalLinkedToID => originalLinkedToID;
|
||||
private DockingPort originalLinkedPort;
|
||||
|
||||
private bool purchasedLostShuttles;
|
||||
@@ -160,6 +162,7 @@ namespace Barotrauma
|
||||
wallVertices = MathUtils.GiftWrap(points);
|
||||
}
|
||||
|
||||
// LinkedSubmarine.Load() is called from MapEntity.LoadAll()
|
||||
public static LinkedSubmarine Load(XElement element, Submarine submarine)
|
||||
{
|
||||
Vector2 pos = element.GetAttributeVector2("pos", Vector2.Zero);
|
||||
@@ -172,17 +175,16 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
string levelSeed = element.GetAttributeString("location", "");
|
||||
LevelData levelData = GameMain.GameSession.Campaign?.NextLevel ?? GameMain.GameSession.Level?.LevelData;
|
||||
linkedSub = new LinkedSubmarine(submarine)
|
||||
{
|
||||
purchasedLostShuttles = GameMain.GameSession.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles,
|
||||
saveElement = element
|
||||
};
|
||||
|
||||
linkedSub.purchasedLostShuttles = GameMain.GameSession.GameMode is CampaignMode campaign && campaign.PurchasedLostShuttles;
|
||||
string levelSeed = element.GetAttributeString("location", "");
|
||||
if (!string.IsNullOrWhiteSpace(levelSeed) &&
|
||||
GameMain.GameSession.Level != null &&
|
||||
GameMain.GameSession.Level.Seed != levelSeed &&
|
||||
!linkedSub.purchasedLostShuttles)
|
||||
if (!string.IsNullOrWhiteSpace(levelSeed) && levelData != null &&
|
||||
levelData.Seed != levelSeed && !linkedSub.purchasedLostShuttles)
|
||||
{
|
||||
linkedSub.loadSub = false;
|
||||
}
|
||||
@@ -217,12 +219,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
if (!loadSub) { return; }
|
||||
|
||||
SubmarineInfo info = new SubmarineInfo(Submarine.Info.FilePath, "", saveElement);
|
||||
if (!info.SubmarineElement.HasElements)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to load a linked submarine (empty XML element). The save file may be corrupted.");
|
||||
return;
|
||||
}
|
||||
|
||||
sub = Submarine.Load(info, false);
|
||||
|
||||
Vector2 worldPos = saveElement.GetAttributeVector2("worldpos", Vector2.Zero);
|
||||
@@ -294,9 +301,9 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
Vector2 portDiff = myPort.Item.WorldPosition - sub.WorldPosition;
|
||||
Vector2 offset = (myPort.IsHorizontal ?
|
||||
Vector2.UnitX * Math.Sign(linkedPort.Item.WorldPosition.X - myPort.Item.WorldPosition.X) :
|
||||
Vector2.UnitY * Math.Sign(linkedPort.Item.WorldPosition.Y - myPort.Item.WorldPosition.Y));
|
||||
Vector2 offset = myPort.IsHorizontal ?
|
||||
Vector2.UnitX * myPort.GetDir(linkedPort) :
|
||||
Vector2.UnitY * myPort.GetDir(linkedPort);
|
||||
offset *= myPort.DockedDistance;
|
||||
|
||||
sub.SetPosition((linkedPort.Item.WorldPosition - portDiff) - offset);
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Barotrauma
|
||||
{
|
||||
get
|
||||
{
|
||||
availableMissions.RemoveAll(m => m.Completed);
|
||||
availableMissions.RemoveAll(m => m.Completed || m.Failed);
|
||||
return availableMissions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Globalization;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -207,6 +208,16 @@ namespace Barotrauma
|
||||
{
|
||||
List.Clear();
|
||||
var locationTypeFiles = GameMain.Instance.GetFilesOfType(ContentType.LocationTypes);
|
||||
if (!locationTypeFiles.Any())
|
||||
{
|
||||
DebugConsole.ThrowError("No location types configured in any of the selected content packages. Attempting to load from the vanilla content package...");
|
||||
locationTypeFiles = ContentPackage.GetFilesOfType(GameMain.VanillaContent.ToEnumerable(), ContentType.LocationTypes);
|
||||
if (!locationTypeFiles.Any())
|
||||
{
|
||||
throw new Exception("No location types configured in any of the selected content packages. Please try uninstalling mods or reinstalling the game.");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ContentFile file in locationTypeFiles)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
|
||||
@@ -8,7 +8,9 @@ using Voronoi2;
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Map
|
||||
{
|
||||
{
|
||||
public bool AllowDebugTeleport;
|
||||
|
||||
private readonly MapGenerationParams generationParams;
|
||||
|
||||
private Location furthestDiscoveredLocation;
|
||||
@@ -112,7 +114,15 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error while loading the map (start location index out of bounds).");
|
||||
DebugConsole.AddWarning($"Error while loading the map. Start location index out of bounds (index: {startLocationindex}, location count: {Locations.Count}).");
|
||||
foreach (Location location in Locations)
|
||||
{
|
||||
if (!location.Type.HasOutpost) { continue; }
|
||||
if (StartLocation == null || location.MapPosition.X < StartLocation.MapPosition.X)
|
||||
{
|
||||
StartLocation = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
int endLocationindex = element.GetAttributeInt("endlocation", -1);
|
||||
if (endLocationindex > 0 && endLocationindex < Locations.Count)
|
||||
@@ -121,7 +131,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error while loading the map (end location index out of bounds).");
|
||||
DebugConsole.AddWarning($"Error while loading the map. End location index out of bounds (index: {endLocationindex}, location count: {Locations.Count}).");
|
||||
foreach (Location location in Locations)
|
||||
{
|
||||
if (EndLocation == null || location.MapPosition.X > EndLocation.MapPosition.X)
|
||||
@@ -166,6 +176,7 @@ namespace Barotrauma
|
||||
CurrentLocation = StartLocation = furthestDiscoveredLocation = location;
|
||||
}
|
||||
}
|
||||
System.Diagnostics.Debug.Assert(StartLocation != null, "Start location not assigned after level generation.");
|
||||
|
||||
CurrentLocation.CreateStore();
|
||||
CurrentLocation.Discovered = true;
|
||||
@@ -640,7 +651,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ProgressWorld()
|
||||
public void ProgressWorld(CampaignMode.TransitionType transitionType, float roundDuration)
|
||||
{
|
||||
//one step per 10 minutes of play time
|
||||
int steps = (int)Math.Floor(roundDuration / (60.0f * 10.0f));
|
||||
if (transitionType == CampaignMode.TransitionType.ProgressToNextLocation ||
|
||||
transitionType == CampaignMode.TransitionType.ProgressToNextEmptyLocation)
|
||||
{
|
||||
//at least one step when progressing to the next location, regardless of how long the round took
|
||||
steps = Math.Max(1, steps);
|
||||
}
|
||||
steps = Math.Min(steps, 5);
|
||||
for (int i = 0; i < steps; i++)
|
||||
{
|
||||
ProgressWorld();
|
||||
}
|
||||
}
|
||||
|
||||
private void ProgressWorld()
|
||||
{
|
||||
foreach (Location location in Locations)
|
||||
{
|
||||
@@ -651,6 +679,8 @@ namespace Barotrauma
|
||||
furthestDiscoveredLocation = location;
|
||||
}
|
||||
|
||||
if (location == CurrentLocation || location == SelectedLocation) { continue; }
|
||||
|
||||
//find which types of locations this one can change to
|
||||
List<LocationTypeChange> allowedTypeChanges = new List<LocationTypeChange>();
|
||||
List<LocationTypeChange> readyTypeChanges = new List<LocationTypeChange>();
|
||||
@@ -844,6 +874,15 @@ namespace Barotrauma
|
||||
{
|
||||
SelectLocation(Connections[currentLocationConnection].OtherLocation(CurrentLocation));
|
||||
}
|
||||
else
|
||||
{
|
||||
//this should not be possible, you can't enter non-outpost locations (= natural formations)
|
||||
if (CurrentLocation != null && !CurrentLocation.Type.HasOutpost && SelectedConnection == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error while loading campaign map state. Submarine in a location with no outpost ({CurrentLocation.Name}). Loading the first adjacent connection...");
|
||||
SelectLocation(CurrentLocation.Connections[0].OtherLocation(CurrentLocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(XElement element)
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace Barotrauma
|
||||
public static void Init()
|
||||
{
|
||||
|
||||
var files = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.MapGenerationParameters);
|
||||
var files = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.MapGenerationParameters);
|
||||
if (!files.Any())
|
||||
{
|
||||
DebugConsole.ThrowError("No map generation parameters found in the selected content packages!");
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -68,7 +67,7 @@ namespace Barotrauma
|
||||
|
||||
private static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, Location location, bool onlyEntrance = false)
|
||||
{
|
||||
var outpostModuleFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.OutpostModule);
|
||||
var outpostModuleFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.OutpostModule);
|
||||
|
||||
//load the infos of the outpost module files
|
||||
List<SubmarineInfo> outpostModules = new List<SubmarineInfo>();
|
||||
@@ -110,7 +109,7 @@ namespace Barotrauma
|
||||
|
||||
selectedModules.Clear();
|
||||
//select which module types the outpost should consist of
|
||||
var pendingModuleFlags = onlyEntrance ? new List<string>() : SelectModules(outpostModules, generationParams);
|
||||
var pendingModuleFlags = onlyEntrance ? new List<string>() { generationParams.ModuleCounts.First().Key } : SelectModules(outpostModules, generationParams);
|
||||
foreach (string flag in pendingModuleFlags.Distinct().ToList())
|
||||
{
|
||||
if (flag.Equals("none", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
@@ -132,13 +131,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//the first airlock is forced to spawn manually, remove it from the list of pending modules
|
||||
if (pendingModuleFlags.Contains("airlock"))
|
||||
{
|
||||
pendingModuleFlags.Remove("airlock");
|
||||
}
|
||||
//the first module is spawned separately, remove it from the list of pending modules
|
||||
string initialModuleFlag = pendingModuleFlags.FirstOrDefault() ?? "airlock";
|
||||
pendingModuleFlags.Remove(initialModuleFlag);
|
||||
|
||||
var initialModule = GetRandomModule(outpostModules, "airlock", locationType);
|
||||
var initialModule = GetRandomModule(outpostModules, initialModuleFlag, locationType);
|
||||
if (initialModule == null)
|
||||
{
|
||||
throw new Exception("Failed to generate an outpost (no airlock modules found).");
|
||||
@@ -155,7 +152,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
selectedModules.Add(new PlacedModule(initialModule, null, OutpostModuleInfo.GapPosition.None));
|
||||
selectedModules.Last().FulfilledModuleTypes.Add("airlock");
|
||||
selectedModules.Last().FulfilledModuleTypes.Add(initialModuleFlag);
|
||||
AppendToModule(selectedModules.Last(), outpostModules.ToList(), pendingModuleFlags, selectedModules, locationType);
|
||||
if (pendingModuleFlags.Any(flag => !flag.Equals("none", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
@@ -202,7 +199,7 @@ namespace Barotrauma
|
||||
|
||||
DebugConsole.NewMessage("Failed to generate an outpost without overlapping modules. Trying to use a pre-built outpost instead...");
|
||||
|
||||
var outpostFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Outpost);
|
||||
var outpostFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.Outpost);
|
||||
if (!outpostFiles.Any())
|
||||
{
|
||||
throw new Exception("Failed to generate an outpost. Could not generate an outpost from the available outpost modules and there are no pre-built outposts available.");
|
||||
@@ -354,6 +351,9 @@ namespace Barotrauma
|
||||
int totalModuleCount = generationParams.TotalModuleCount;
|
||||
var pendingModuleFlags = new List<string>();
|
||||
bool availableModulesFound = true;
|
||||
|
||||
string initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Key;
|
||||
pendingModuleFlags.Add(initialModuleFlag);
|
||||
while (pendingModuleFlags.Count < totalModuleCount && availableModulesFound)
|
||||
{
|
||||
availableModulesFound = false;
|
||||
@@ -378,8 +378,13 @@ namespace Barotrauma
|
||||
//don't place "none" modules at the end because
|
||||
// a. "filler rooms" at the end of a hallway are pointless
|
||||
// b. placing the unnecessary filler rooms first give more options for the placement of the more important modules
|
||||
pendingModuleFlags.Insert(Rand.Int(pendingModuleFlags.Count - 1, Rand.RandSync.Server),"none");
|
||||
pendingModuleFlags.Insert(Rand.Int(pendingModuleFlags.Count - 1, Rand.RandSync.Server), "none");
|
||||
}
|
||||
|
||||
//make sure the initial module is inserted first
|
||||
pendingModuleFlags.Remove(initialModuleFlag);
|
||||
pendingModuleFlags.Insert(0, initialModuleFlag);
|
||||
|
||||
return pendingModuleFlags;
|
||||
}
|
||||
|
||||
@@ -615,7 +620,7 @@ namespace Barotrauma
|
||||
Vector2 moveDir = GetMoveDir(module.ThisGapPosition);
|
||||
Vector2 moveStep = moveDir * 50.0f;
|
||||
Vector2 currentMove = Vector2.Zero;
|
||||
float maxMoveAmount = 1500.0f;
|
||||
float maxMoveAmount = 2000.0f;
|
||||
|
||||
List<PlacedModule> subsequentModules2 = new List<PlacedModule>();
|
||||
GetSubsequentModules(module, movableModules, ref subsequentModules2);
|
||||
@@ -1342,7 +1347,7 @@ namespace Barotrauma
|
||||
Dictionary<HumanPrefab, CharacterInfo> selectedCharacters = new Dictionary<HumanPrefab, CharacterInfo>();
|
||||
foreach (HumanPrefab humanPrefab in outpost.Info.OutpostGenerationParams.GetHumanPrefabs(Rand.RandSync.Server))
|
||||
{
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: humanPrefab.GetJobPrefab(Rand.RandSync.Server));
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: humanPrefab.GetJobPrefab(Rand.RandSync.Server), randSync: Rand.RandSync.Server);
|
||||
if (location != null && location.KilledCharacterIdentifiers.Contains(characterInfo.GetIdentifier()))
|
||||
{
|
||||
killedCharacters.Add(humanPrefab);
|
||||
@@ -1357,7 +1362,7 @@ namespace Barotrauma
|
||||
int tries = 0;
|
||||
while (tries < 100)
|
||||
{
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: killedCharacter.GetJobPrefab(Rand.RandSync.Server));
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: killedCharacter.GetJobPrefab(Rand.RandSync.Server), randSync: Rand.RandSync.Server);
|
||||
if (!location.KilledCharacterIdentifiers.Contains(characterInfo.GetIdentifier()))
|
||||
{
|
||||
selectedCharacters.Add(killedCharacter, characterInfo);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Barotrauma
|
||||
public Rectangle rect;
|
||||
public float damage;
|
||||
public Gap gap;
|
||||
|
||||
|
||||
public WallSection(Rectangle rect)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(rect.Width > 0 && rect.Height > 0);
|
||||
@@ -58,7 +58,7 @@ namespace Barotrauma
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
|
||||
public override Sprite Sprite
|
||||
{
|
||||
@@ -215,6 +215,7 @@ namespace Barotrauma
|
||||
set { textureOffset = value; }
|
||||
}
|
||||
|
||||
|
||||
private Rectangle defaultRect;
|
||||
/// <summary>
|
||||
/// Unscaled rect
|
||||
@@ -309,6 +310,12 @@ namespace Barotrauma
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
if (!MathUtils.IsValid(amount))
|
||||
{
|
||||
DebugConsole.ThrowError($"Attempted to move a structure by an invalid amount ({amount})\n{Environment.StackTrace}");
|
||||
return;
|
||||
}
|
||||
|
||||
base.Move(amount);
|
||||
|
||||
for (int i = 0; i < Sections.Length; i++)
|
||||
@@ -397,7 +404,7 @@ namespace Barotrauma
|
||||
if (StairDirection != Direction.None)
|
||||
{
|
||||
CreateStairBodies();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,7 +480,7 @@ namespace Barotrauma
|
||||
{
|
||||
int xsections = 1, ysections = 1;
|
||||
int width = rect.Width, height = rect.Height;
|
||||
|
||||
|
||||
if (!HasBody)
|
||||
{
|
||||
if (FlippedX && IsHorizontal)
|
||||
@@ -623,11 +630,11 @@ namespace Barotrauma
|
||||
|
||||
if (StairDirection == Direction.Left)
|
||||
{
|
||||
return MathUtils.LineToPointDistance(new Vector2(WorldRect.X, WorldRect.Y), new Vector2(WorldRect.Right, WorldRect.Y - WorldRect.Height), position) < 40.0f;
|
||||
return MathUtils.LineToPointDistanceSquared(new Vector2(WorldRect.X, WorldRect.Y), new Vector2(WorldRect.Right, WorldRect.Y - WorldRect.Height), position) < 1600.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MathUtils.LineToPointDistance(new Vector2(WorldRect.X, WorldRect.Y - rect.Height), new Vector2(WorldRect.Right, WorldRect.Y), position) < 40.0f;
|
||||
return MathUtils.LineToPointDistanceSquared(new Vector2(WorldRect.X, WorldRect.Y - rect.Height), new Vector2(WorldRect.Right, WorldRect.Y), position) < 1600.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -726,7 +733,7 @@ namespace Barotrauma
|
||||
return Sections[sectionIndex];
|
||||
|
||||
}
|
||||
|
||||
|
||||
public bool SectionBodyDisabled(int sectionIndex)
|
||||
{
|
||||
if (sectionIndex < 0 || sectionIndex >= Sections.Length) return false;
|
||||
|
||||
@@ -289,7 +289,6 @@ namespace Barotrauma
|
||||
public WreckAI WreckAI { get; private set; }
|
||||
public bool CreateWreckAI()
|
||||
{
|
||||
MakeWreck();
|
||||
WreckAI = new WreckAI(this);
|
||||
return WreckAI != null;
|
||||
}
|
||||
@@ -946,9 +945,29 @@ namespace Barotrauma
|
||||
{
|
||||
if (item.Submarine != this) { continue; }
|
||||
var steering = item.GetComponent<Steering>();
|
||||
if (steering == null) { continue; }
|
||||
if (steering == null || item.Connections == null) { continue; }
|
||||
|
||||
//find all the engines and pumps the nav terminal is connected to
|
||||
List<Item> connectedItems = new List<Item>();
|
||||
foreach (Connection c in item.Connections)
|
||||
{
|
||||
if (c.IsPower) { continue; }
|
||||
connectedItems.AddRange(item.GetConnectedComponentsRecursive<Engine>(c).Select(engine => engine.Item));
|
||||
connectedItems.AddRange(item.GetConnectedComponentsRecursive<Pump>(c).Select(pump => pump.Item));
|
||||
}
|
||||
|
||||
//if more than 50% of the connected engines/pumps are in another sub,
|
||||
//assume this terminal is used to remotely control something and don't automatically enable autopilot
|
||||
if (connectedItems.Count(it => it.Submarine != item.Submarine) > connectedItems.Count / 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
steering.MaintainPos = true;
|
||||
steering.AutoPilot = true;
|
||||
#if SERVER
|
||||
steering.UnsentChanges = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1369,8 +1388,17 @@ namespace Barotrauma
|
||||
|
||||
foreach (MapEntity e in MapEntity.mapEntityList.OrderBy(e => e.ID))
|
||||
{
|
||||
if (e.Submarine != this || !e.ShouldBeSaved) continue;
|
||||
if (e is Item item && item.FindParentInventory(inv => inv is CharacterInventory) != null) continue;
|
||||
if (!e.ShouldBeSaved) { continue; }
|
||||
if (e is Item item)
|
||||
{
|
||||
if (item.FindParentInventory(inv => inv is CharacterInventory) != null) { continue; }
|
||||
if (e.Submarine != this && item.GetRootContainer()?.Submarine != this) { continue; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Submarine != this) { continue; }
|
||||
}
|
||||
|
||||
e.Save(element);
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Barotrauma
|
||||
this.submarine = sub;
|
||||
|
||||
Body farseerBody = null;
|
||||
if (!Hull.hullList.Any())
|
||||
if (!Hull.hullList.Any(h => h.Submarine == sub))
|
||||
{
|
||||
farseerBody = GameMain.World.CreateRectangle(1.0f, 1.0f, 1.0f);
|
||||
if (showWarningMessages)
|
||||
|
||||
@@ -2,7 +2,11 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
#if DEBUG
|
||||
using System.IO;
|
||||
#else
|
||||
using Barotrauma.IO;
|
||||
#endif
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -149,7 +153,7 @@ namespace Barotrauma
|
||||
get
|
||||
{
|
||||
if (requiredContentPackagesInstalled.HasValue) { return requiredContentPackagesInstalled.Value; }
|
||||
return RequiredContentPackages.All(cp => GameMain.SelectedPackages.Any(cp2 => cp2.Name == cp));
|
||||
return RequiredContentPackages.All(cp => GameMain.Config.AllEnabledPackages.Any(cp2 => cp2.Name == cp));
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -512,7 +516,7 @@ namespace Barotrauma
|
||||
public static void RefreshSavedSubs()
|
||||
{
|
||||
var contentPackageSubs = ContentPackage.GetFilesOfType(
|
||||
GameMain.Config.SelectedContentPackages,
|
||||
GameMain.Config.AllEnabledPackages,
|
||||
ContentType.Submarine, ContentType.Outpost, ContentType.OutpostModule, ContentType.Wreck);
|
||||
|
||||
for (int i = savedSubmarines.Count - 1; i >= 0; i--)
|
||||
|
||||
@@ -707,7 +707,7 @@ namespace Barotrauma
|
||||
int i = 0;
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
if (!e.ShouldBeSaved || e.Removed) { continue; }
|
||||
if (!e.ShouldBeSaved || (e.Removed != Removed)) { continue; }
|
||||
if (e.Submarine?.Info.Type != Submarine?.Info.Type) { continue; }
|
||||
element.Add(new XAttribute("linkedto" + i, e.ID));
|
||||
i += 1;
|
||||
|
||||
Reference in New Issue
Block a user