Build 0.21.6.0 (1.0 pre-patch)
This commit is contained in:
@@ -18,9 +18,9 @@ namespace Barotrauma
|
||||
|
||||
public const ushort ReservedIDStart = ushort.MaxValue - 3;
|
||||
|
||||
public const ushort MaxEntityCount = ushort.MaxValue - 2; //ushort.MaxValue - 2 because 0 and ushort.MaxValue are reserved values
|
||||
public const ushort MaxEntityCount = ushort.MaxValue - 4; //ushort.MaxValue - 4 because the 4 values above are reserved values
|
||||
|
||||
private static Dictionary<ushort, Entity> dictionary = new Dictionary<ushort, Entity>();
|
||||
private static readonly Dictionary<ushort, Entity> dictionary = new Dictionary<ushort, Entity>();
|
||||
public static IReadOnlyCollection<Entity> GetEntities()
|
||||
{
|
||||
return dictionary.Values;
|
||||
@@ -85,6 +85,28 @@ namespace Barotrauma
|
||||
this.Submarine = submarine;
|
||||
spawnTime = Timing.TotalTime;
|
||||
|
||||
if (dictionary.Count >= MaxEntityCount)
|
||||
{
|
||||
Dictionary<Identifier, int> entityCounts = new Dictionary<Identifier, int>();
|
||||
foreach (var entity in dictionary)
|
||||
{
|
||||
if (entity.Value is MapEntity me)
|
||||
{
|
||||
if (entityCounts.ContainsKey(me.Prefab.Identifier))
|
||||
{
|
||||
entityCounts[me.Prefab.Identifier]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
entityCounts[me.Prefab.Identifier] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
string errorMsg = $"Maximum amount of entities ({MaxEntityCount}) exceeded! Largest numbers of entities: " +
|
||||
string.Join(", ", entityCounts.OrderByDescending(kvp => kvp.Value).Take(10).Select(kvp => $"{kvp.Key}: {kvp.Value}"));
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
|
||||
//give a unique ID
|
||||
ID = DetermineID(id, submarine);
|
||||
|
||||
|
||||
@@ -188,6 +188,12 @@ namespace Barotrauma
|
||||
item.Condition -= item.MaxCondition * EmpStrength * distFactor;
|
||||
}
|
||||
|
||||
var lightComponent = item.GetComponent<LightComponent>();
|
||||
if (lightComponent != null)
|
||||
{
|
||||
lightComponent.TemporaryFlickerTimer = Math.Min(EmpStrength * distFactor, 10.0f);
|
||||
}
|
||||
|
||||
//discharge batteries
|
||||
var powerContainer = item.GetComponent<PowerContainer>();
|
||||
if (powerContainer != null)
|
||||
|
||||
@@ -50,6 +50,12 @@ namespace Barotrauma
|
||||
Description = TextManager.Get($"EntityDescription.{Identifier}");
|
||||
Tags = Enumerable.Empty<Identifier>().ToImmutableHashSet();
|
||||
|
||||
string description = element.GetAttributeString("description", string.Empty);
|
||||
if (!description.IsNullOrEmpty())
|
||||
{
|
||||
Description = Description.Fallback(description);
|
||||
}
|
||||
|
||||
List<ushort> containedItemIDs = new List<ushort>();
|
||||
foreach (XElement entityElement in element.Elements())
|
||||
{
|
||||
|
||||
@@ -860,6 +860,7 @@ namespace Barotrauma
|
||||
(endPath != null && GetDistToTunnel(cell.Center, endPath) < minMainPathWidth) ||
|
||||
(endHole != null && GetDistToTunnel(cell.Center, endHole) < minMainPathWidth)) { continue; }
|
||||
if (cell.Edges.Any(e => e.AdjacentCell(cell)?.CellType != CellType.Path || e.NextToCave)) { continue; }
|
||||
if (PositionsOfInterest.Any(p => cell.IsPointInside(p.Position.ToVector2()))) { continue; }
|
||||
potentialIslands.Add(cell);
|
||||
}
|
||||
for (int i = 0; i < GenerationParams.IslandCount; i++)
|
||||
@@ -1099,6 +1100,7 @@ namespace Barotrauma
|
||||
caveCells.AddRange(cave.Tunnels.SelectMany(t => t.Cells));
|
||||
foreach (var caveCell in caveCells)
|
||||
{
|
||||
if (PositionsOfInterest.Any(p => caveCell.IsPointInside(p.Position.ToVector2()))) { continue; }
|
||||
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient) < destructibleWallRatio * cave.CaveGenerationParams.DestructibleWallRatio)
|
||||
{
|
||||
var chunk = CreateIceChunk(caveCell.Edges, caveCell.Center, health: 50.0f);
|
||||
@@ -3176,7 +3178,7 @@ namespace Barotrauma
|
||||
TryGetInterestingPosition(true, spawnPosType, minDistFromSubs, out Vector2 startPos, filter);
|
||||
|
||||
Vector2 offset = Rand.Vector(Rand.Range(0.0f, randomSpread, Rand.RandSync.ServerAndClient), Rand.RandSync.ServerAndClient);
|
||||
if (!cells.Any(c => c.IsPointInside(startPos + offset)))
|
||||
if (!IsPositionInsideWall(startPos + offset))
|
||||
{
|
||||
startPos += offset;
|
||||
}
|
||||
@@ -3232,10 +3234,9 @@ namespace Barotrauma
|
||||
{
|
||||
suitablePositions.RemoveAll(p => !filter(p));
|
||||
}
|
||||
//avoid floating ice chunks on the main path
|
||||
if (positionType.HasFlag(PositionType.MainPath) || positionType.HasFlag(PositionType.SidePath))
|
||||
{
|
||||
suitablePositions.RemoveAll(p => ExtraWalls.Any(w => w.Cells.Any(c => c.IsPointInside(p.Position.ToVector2()))));
|
||||
suitablePositions.RemoveAll(p => IsPositionInsideWall(p.Position.ToVector2()));
|
||||
}
|
||||
if (!suitablePositions.Any())
|
||||
{
|
||||
@@ -3288,10 +3289,16 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
position = farEnoughPositions[Rand.Int(farEnoughPositions.Count, (useSyncedRand ? Rand.RandSync.ServerAndClient : Rand.RandSync.Unsynced))].Position;
|
||||
position = farEnoughPositions[Rand.Int(farEnoughPositions.Count, useSyncedRand ? Rand.RandSync.ServerAndClient : Rand.RandSync.Unsynced)].Position;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsPositionInsideWall(Vector2 worldPosition)
|
||||
{
|
||||
var closestCell = GetClosestCell(worldPosition);
|
||||
return closestCell != null && closestCell.IsPointInside(worldPosition);
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
LevelObjectManager.Update(deltaTime);
|
||||
@@ -3334,14 +3341,13 @@ namespace Barotrauma
|
||||
|
||||
public Vector2 GetBottomPosition(float xPosition)
|
||||
{
|
||||
int index = (int)Math.Floor(xPosition / Size.X * (bottomPositions.Count - 1));
|
||||
float interval = Size.X / (bottomPositions.Count - 1);
|
||||
|
||||
int index = (int)Math.Floor(xPosition / interval);
|
||||
if (index < 0 || index >= bottomPositions.Count - 1) { return new Vector2(xPosition, BottomPos); }
|
||||
|
||||
float t = (xPosition - bottomPositions[index].X) / (bottomPositions[index + 1].X - bottomPositions[index].X);
|
||||
//t can go slightly outside the 0-1 due to rounding, safe to ignore
|
||||
Debug.Assert(t <= 1.001f && t >= -0.001f);
|
||||
float t = (xPosition - bottomPositions[index].X) / interval;
|
||||
t = MathHelper.Clamp(t, 0.0f, 1.0f);
|
||||
|
||||
float yPos = MathHelper.Lerp(bottomPositions[index].Y, bottomPositions[index + 1].Y, t);
|
||||
|
||||
return new Vector2(xPosition, yPos);
|
||||
|
||||
@@ -112,10 +112,9 @@ namespace Barotrauma
|
||||
(int)MathUtils.Round(generationParams.Height, Level.GridCellSize));
|
||||
}
|
||||
|
||||
public LevelData(XElement element, float? forceDifficulty = null)
|
||||
public LevelData(XElement element, float? forceDifficulty = null, bool clampDifficultyToBiome = false)
|
||||
{
|
||||
Seed = element.GetAttributeString("seed", "");
|
||||
Difficulty = forceDifficulty ?? element.GetAttributeFloat("difficulty", 0.0f);
|
||||
Size = element.GetAttributePoint("size", new Point(1000));
|
||||
Enum.TryParse(element.GetAttributeString("type", "LocationConnection"), out Type);
|
||||
|
||||
@@ -131,10 +130,7 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError($"Error while loading a level. Could not find level generation params with the ID \"{generationParamsId}\".");
|
||||
GenerationParams = LevelGenerationParams.LevelParams.FirstOrDefault(l => l.Type == Type);
|
||||
if (GenerationParams == null)
|
||||
{
|
||||
GenerationParams = LevelGenerationParams.LevelParams.First();
|
||||
}
|
||||
GenerationParams ??= LevelGenerationParams.LevelParams.First();
|
||||
}
|
||||
|
||||
InitialDepth = element.GetAttributeInt("initialdepth", GenerationParams.InitialDepthMin);
|
||||
@@ -147,10 +143,16 @@ namespace Barotrauma
|
||||
Biome = Biome.Prefabs.First();
|
||||
}
|
||||
|
||||
string[] prefabNames = element.GetAttributeStringArray("eventhistory", new string[] { });
|
||||
Difficulty = forceDifficulty ?? element.GetAttributeFloat("difficulty", 0.0f);
|
||||
if (clampDifficultyToBiome)
|
||||
{
|
||||
Difficulty = MathHelper.Clamp(Difficulty, Biome.MinDifficulty, Biome.AdjustedMaxDifficulty);
|
||||
}
|
||||
|
||||
string[] prefabNames = element.GetAttributeStringArray("eventhistory", Array.Empty<string>());
|
||||
EventHistory.AddRange(EventPrefab.Prefabs.Where(p => prefabNames.Any(n => p.Identifier == n)));
|
||||
|
||||
string[] nonRepeatablePrefabNames = element.GetAttributeStringArray("nonrepeatableevents", new string[] { });
|
||||
string[] nonRepeatablePrefabNames = element.GetAttributeStringArray("nonrepeatableevents", Array.Empty<string>());
|
||||
NonRepeatableEvents.AddRange(EventPrefab.Prefabs.Where(p => nonRepeatablePrefabNames.Any(n => p.Identifier == n)));
|
||||
|
||||
EventsExhausted = element.GetAttributeBool(nameof(EventsExhausted).ToLower(), false);
|
||||
|
||||
@@ -559,12 +559,9 @@ namespace Barotrauma
|
||||
killedCharacterIdentifiers = element.GetAttributeIntArray("killedcharacters", Array.Empty<int>()).ToHashSet();
|
||||
|
||||
System.Diagnostics.Debug.Assert(Type != null, $"Could not find the location type \"{locationTypeId}\"!");
|
||||
if (Type == null)
|
||||
{
|
||||
Type = LocationType.Prefabs.First();
|
||||
}
|
||||
Type ??= LocationType.Prefabs.First();
|
||||
|
||||
LevelData = new LevelData(element.Element("Level"));
|
||||
LevelData = new LevelData(element.Element("Level"), clampDifficultyToBiome: true);
|
||||
|
||||
PortraitId = ToolBox.StringToInt(Name);
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
int startLocationindex = element.GetAttributeInt("startlocation", -1);
|
||||
if (startLocationindex > 0 && startLocationindex < Locations.Count)
|
||||
if (startLocationindex >= 0 && startLocationindex < Locations.Count)
|
||||
{
|
||||
StartLocation = Locations[startLocationindex];
|
||||
}
|
||||
@@ -188,7 +188,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
int endLocationindex = element.GetAttributeInt("endlocation", -1);
|
||||
if (endLocationindex > 0 && endLocationindex < Locations.Count)
|
||||
if (endLocationindex >= 0 && endLocationindex < Locations.Count)
|
||||
{
|
||||
EndLocation = Locations[endLocationindex];
|
||||
}
|
||||
|
||||
@@ -174,6 +174,9 @@ namespace Barotrauma
|
||||
|
||||
public abstract Sprite Sprite { get; }
|
||||
|
||||
public virtual bool CanSpriteFlipX { get; } = false;
|
||||
public virtual bool CanSpriteFlipY { get; } = false;
|
||||
|
||||
public abstract string OriginalName { get; }
|
||||
|
||||
public abstract LocalizedString Name { get; }
|
||||
|
||||
@@ -124,9 +124,18 @@ namespace Barotrauma
|
||||
int eventCount = GameMain.Server.EntityEventManager.Events.Count();
|
||||
int uniqueEventCount = GameMain.Server.EntityEventManager.UniqueEvents.Count();
|
||||
#endif
|
||||
List<MapEntity> entities = MapEntity.mapEntityList.FindAll(e => e.Submarine == sub);
|
||||
HashSet<Submarine> connectedSubs = new HashSet<Submarine>() { sub };
|
||||
foreach (Submarine otherSub in Submarine.Loaded)
|
||||
{
|
||||
//remove linked subs too
|
||||
if (otherSub.Submarine == sub) { connectedSubs.Add(otherSub); }
|
||||
}
|
||||
List<MapEntity> entities = MapEntity.mapEntityList.FindAll(e => connectedSubs.Contains(e.Submarine));
|
||||
entities.ForEach(e => e.Remove());
|
||||
sub.Remove();
|
||||
foreach (Submarine otherSub in connectedSubs)
|
||||
{
|
||||
otherSub.Remove();
|
||||
}
|
||||
#if SERVER
|
||||
//remove any events created during the removal of the entities
|
||||
GameMain.Server.EntityEventManager.Events.RemoveRange(eventCount, GameMain.Server.EntityEventManager.Events.Count - eventCount);
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace Barotrauma
|
||||
|
||||
public readonly ContentXElement ConfigElement;
|
||||
|
||||
public readonly bool CanSpriteFlipX;
|
||||
public readonly bool CanSpriteFlipY;
|
||||
public override bool CanSpriteFlipX { get; }
|
||||
public override bool CanSpriteFlipY { get; }
|
||||
|
||||
/// <summary>
|
||||
/// If null, the orientation is determined automatically based on the dimensions of the structure instances
|
||||
|
||||
@@ -1310,7 +1310,7 @@ namespace Barotrauma
|
||||
return new Rectangle((int)bounds.X, (int)bounds.Y, (int)(bounds.Z - bounds.X), (int)(bounds.Y - bounds.W));
|
||||
}
|
||||
|
||||
public Submarine(SubmarineInfo info, bool showWarningMessages = true, Func<Submarine, List<MapEntity>> loadEntities = null, IdRemap linkedRemap = null) : base(null, Entity.NullEntityID)
|
||||
public Submarine(SubmarineInfo info, bool showErrorMessages = true, Func<Submarine, List<MapEntity>> loadEntities = null, IdRemap linkedRemap = null) : base(null, Entity.NullEntityID)
|
||||
{
|
||||
upgradeEventIdentifier = new Identifier($"Submarine{ID}");
|
||||
Loading = true;
|
||||
@@ -1381,65 +1381,65 @@ namespace Barotrauma
|
||||
center.Y -= center.Y % GridSize.Y;
|
||||
|
||||
RepositionEntities(-center, MapEntity.mapEntityList.Where(me => me.Submarine == this));
|
||||
}
|
||||
|
||||
subBody = new SubmarineBody(this, showWarningMessages);
|
||||
Vector2 pos = ConvertUnits.ToSimUnits(HiddenSubPosition);
|
||||
subBody.Body.FarseerBody.SetTransformIgnoreContacts(ref pos, 0.0f);
|
||||
subBody = new SubmarineBody(this, showErrorMessages);
|
||||
Vector2 pos = ConvertUnits.ToSimUnits(HiddenSubPosition);
|
||||
subBody.Body.FarseerBody.SetTransformIgnoreContacts(ref pos, 0.0f);
|
||||
|
||||
if (info.IsOutpost)
|
||||
if (info.IsOutpost)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
TeamID = CharacterTeamType.FriendlyNPC;
|
||||
|
||||
bool indestructible =
|
||||
GameMain.NetworkMember != null &&
|
||||
!GameMain.NetworkMember.ServerSettings.DestructibleOutposts &&
|
||||
!(info.OutpostGenerationParams?.AlwaysDestructible ?? false);
|
||||
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
TeamID = CharacterTeamType.FriendlyNPC;
|
||||
|
||||
bool indestructible =
|
||||
GameMain.NetworkMember != null &&
|
||||
!GameMain.NetworkMember.ServerSettings.DestructibleOutposts &&
|
||||
!(info.OutpostGenerationParams?.AlwaysDestructible ?? false);
|
||||
|
||||
foreach (MapEntity me in MapEntity.mapEntityList)
|
||||
if (me.Submarine != this) { continue; }
|
||||
if (me is Item item)
|
||||
{
|
||||
if (me.Submarine != this) { continue; }
|
||||
if (me is Item item)
|
||||
item.SpawnedInCurrentOutpost = info.OutpostGenerationParams != null;
|
||||
item.AllowStealing = info.OutpostGenerationParams?.AllowStealing ?? true;
|
||||
if (item.GetComponent<Repairable>() != null && indestructible)
|
||||
{
|
||||
item.SpawnedInCurrentOutpost = info.OutpostGenerationParams != null;
|
||||
item.AllowStealing = info.OutpostGenerationParams?.AllowStealing ?? true;
|
||||
if (item.GetComponent<Repairable>() != null && indestructible)
|
||||
item.Indestructible = true;
|
||||
}
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (ic is ConnectionPanel connectionPanel)
|
||||
{
|
||||
item.Indestructible = true;
|
||||
}
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
if (ic is ConnectionPanel connectionPanel)
|
||||
//prevent rewiring
|
||||
if (info.OutpostGenerationParams != null && !info.OutpostGenerationParams.AlwaysRewireable)
|
||||
{
|
||||
//prevent rewiring
|
||||
if (info.OutpostGenerationParams != null && !info.OutpostGenerationParams.AlwaysRewireable)
|
||||
{
|
||||
connectionPanel.Locked = true;
|
||||
}
|
||||
connectionPanel.Locked = true;
|
||||
}
|
||||
else if (ic is Holdable holdable && holdable.Attached && item.GetComponent<LevelResource>() == null)
|
||||
{
|
||||
//prevent deattaching items from walls
|
||||
}
|
||||
else if (ic is Holdable holdable && holdable.Attached && item.GetComponent<LevelResource>() == null)
|
||||
{
|
||||
//prevent deattaching items from walls
|
||||
#if CLIENT
|
||||
if (GameMain.GameSession?.GameMode is TutorialMode) { continue; }
|
||||
#endif
|
||||
holdable.CanBePicked = false;
|
||||
holdable.CanBeSelected = false;
|
||||
}
|
||||
holdable.CanBePicked = false;
|
||||
holdable.CanBeSelected = false;
|
||||
}
|
||||
}
|
||||
else if (me is Structure structure && structure.Prefab.IndestructibleInOutposts && indestructible)
|
||||
{
|
||||
structure.Indestructible = true;
|
||||
}
|
||||
}
|
||||
else if (me is Structure structure && structure.Prefab.IndestructibleInOutposts && indestructible)
|
||||
{
|
||||
structure.Indestructible = true;
|
||||
}
|
||||
}
|
||||
else if (info.IsRuin)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
}
|
||||
}
|
||||
else if (info.IsRuin)
|
||||
{
|
||||
ShowSonarMarker = false;
|
||||
PhysicsBody.FarseerBody.BodyType = BodyType.Static;
|
||||
}
|
||||
|
||||
if (entityGrid != null)
|
||||
@@ -1481,7 +1481,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
//if the sub was made using an older version,
|
||||
//halve the brightness of the lights to make them look (almost) right on the new lighting formula
|
||||
if (showWarningMessages &&
|
||||
if (showErrorMessages &&
|
||||
!string.IsNullOrEmpty(Info.FilePath) &&
|
||||
Screen.Selected != GameMain.SubEditorScreen &&
|
||||
(Info.GameVersion == null || Info.GameVersion < new Version("0.8.9.0")))
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Barotrauma
|
||||
get { return submarine; }
|
||||
}
|
||||
|
||||
public SubmarineBody(Submarine sub, bool showWarningMessages = true)
|
||||
public SubmarineBody(Submarine sub, bool showErrorMessages = true)
|
||||
{
|
||||
this.submarine = sub;
|
||||
|
||||
@@ -119,9 +119,9 @@ namespace Barotrauma
|
||||
if (!Hull.HullList.Any(h => h.Submarine == sub))
|
||||
{
|
||||
farseerBody = GameMain.World.CreateRectangle(1.0f, 1.0f, 1.0f);
|
||||
if (showWarningMessages)
|
||||
if (showErrorMessages)
|
||||
{
|
||||
DebugConsole.ThrowError("WARNING: no hulls found, generating a physics body for the submarine failed.");
|
||||
DebugConsole.ThrowError($"No hulls found in the submarine \"{sub.Info.Name}\". Generating a physics body for the submarine failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -531,11 +531,15 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Calculated from <see cref="SubmarineElement"/>. Can be used when the sub hasn't been loaded and we can't access <see cref="Submarine.RealWorldCrushDepth"/>.
|
||||
/// </summary>
|
||||
public float GetRealWorldCrushDepth()
|
||||
public bool IsCrushDepthDefinedInStructures(out float realWorldCrushDepth)
|
||||
{
|
||||
if (SubmarineElement == null) { return Level.DefaultRealWorldCrushDepth; }
|
||||
if (SubmarineElement == null)
|
||||
{
|
||||
realWorldCrushDepth = Level.DefaultRealWorldCrushDepth;
|
||||
return false;
|
||||
}
|
||||
bool structureCrushDepthsDefined = false;
|
||||
float realWorldCrushDepth = float.PositiveInfinity;
|
||||
realWorldCrushDepth = float.PositiveInfinity;
|
||||
foreach (var structureElement in SubmarineElement.GetChildElements("structure"))
|
||||
{
|
||||
string name = structureElement.Attribute("name")?.Value ?? "";
|
||||
@@ -553,7 +557,7 @@ namespace Barotrauma
|
||||
{
|
||||
realWorldCrushDepth = Level.DefaultRealWorldCrushDepth;
|
||||
}
|
||||
return realWorldCrushDepth;
|
||||
return structureCrushDepthsDefined;
|
||||
}
|
||||
|
||||
//saving/loading ----------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user