Build 1.1.4.0

This commit is contained in:
Markus Isberg
2023-03-31 18:40:44 +03:00
parent efba17e0ff
commit 9470edead3
483 changed files with 17487 additions and 8548 deletions
@@ -16,6 +16,11 @@ namespace Barotrauma
{
partial class Level : Entity, IServerSerializable
{
public enum PlacementType
{
Top, Bottom
}
public enum EventType
{
SingleDestructibleWall,
@@ -61,6 +66,7 @@ namespace Barotrauma
[Flags]
public enum PositionType
{
None = 0,
MainPath = 0x1,
SidePath = 0x2,
Cave = 0x4,
@@ -68,7 +74,8 @@ namespace Barotrauma
Wreck = 0x10,
BeaconStation = 0x20,
Abyss = 0x40,
AbyssCave = 0x80
AbyssCave = 0x80,
Outpost = 0x100,
}
public struct InterestingPosition
@@ -413,6 +420,9 @@ namespace Barotrauma
get { return LevelData.Type; }
}
public bool IsEndBiome => LevelData.Biome != null && LevelData.Biome.IsEndBiome;
/// <summary>
/// Is there a loaded level set and is it an outpost?
/// </summary>
@@ -451,6 +461,19 @@ namespace Barotrauma
borders = new Rectangle(Point.Zero, levelData.Size);
}
public bool ShouldSpawnCrewInsideOutpost()
{
if (StartOutpost != null &&
Type == LevelData.LevelType.Outpost &&
(StartOutpost.Info.OutpostGenerationParams?.SpawnCrewInsideOutpost ?? false) &&
StartOutpost.GetConnectedSubs().Any(s => s.Info.Type == SubmarineType.Player))
{
var reputation = GameMain.GameSession?.Campaign?.Map?.CurrentLocation?.Reputation;
return reputation == null || reputation.NormalizedValue >= Reputation.HostileThreshold;
}
return false;
}
public static Level Generate(LevelData levelData, bool mirror, Location startLocation, Location endLocation, SubmarineInfo startOutpost = null, SubmarineInfo endOutpost = null)
{
Debug.Assert(levelData.Biome != null);
@@ -482,11 +505,8 @@ namespace Barotrauma
EntitiesBeforeGenerate = GetEntities().ToList();
EntityCountBeforeGenerate = EntitiesBeforeGenerate.Count();
if (LevelData.ForceOutpostGenerationParams == null)
{
StartLocation = startLocation;
EndLocation = endLocation;
}
StartLocation = startLocation;
EndLocation = endLocation;
GenerateEqualityCheckValue(LevelGenStage.GenStart);
SetEqualityCheckValue(LevelGenStage.LevelGenParams, unchecked((int)GenerationParams.UintIdentifier));
@@ -889,6 +909,12 @@ namespace Barotrauma
// remove unnecessary cells and create some holes at the bottom of the level
//----------------------------------------------------------------------------------
if (GenerationParams.NoLevelGeometry)
{
cells.ForEach(c => c.CellType = CellType.Removed);
cells.Clear();
}
cells = cells.Except(pathCells).ToList();
//remove cells from the edges and bottom of the map because a clean-cut edge of the level looks bad
cells.ForEachMod(c =>
@@ -1687,14 +1713,22 @@ namespace Barotrauma
foreach (VoronoiCell cell in closeCells)
{
bool tooClose = false;
foreach (GraphEdge edge in cell.Edges)
{
if (Vector2.DistanceSquared(edge.Point1, position) < minDistSqr ||
Vector2.DistanceSquared(edge.Point2, position) < minDistSqr ||
MathUtils.LineSegmentToPointDistanceSquared(edge.Point1.ToPoint(), edge.Point2.ToPoint(), position.ToPoint()) < minDistSqr)
if (cell.IsPointInsideAABB(position, margin: minDistance))
{
tooClose = true;
}
else
{
foreach (GraphEdge edge in cell.Edges)
{
tooClose = true;
break;
if (Vector2.DistanceSquared(edge.Point1, position) < minDistSqr ||
Vector2.DistanceSquared(edge.Point2, position) < minDistSqr ||
MathUtils.LineSegmentToPointDistanceSquared(edge.Point1.ToPoint(), edge.Point2.ToPoint(), position.ToPoint()) < minDistSqr)
{
tooClose = true;
break;
}
}
}
if (tooClose) { tooCloseCells.Add(cell); }
@@ -1779,6 +1813,7 @@ namespace Barotrauma
if (AbyssArea.Height < islandSize.Y) { return; }
int createdCaves = 0;
int islandCount = GenerationParams.AbyssIslandCount;
for (int i = 0; i < islandCount; i++)
{
@@ -1808,7 +1843,11 @@ namespace Barotrauma
break;
}
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient) > GenerationParams.AbyssIslandCaveProbability)
bool createCave =
//force at least one abyss cave
(i == islandCount - 1 && createdCaves == 0) ||
Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient) > GenerationParams.AbyssIslandCaveProbability;
if (!createCave)
{
float radiusVariance = Math.Min(islandArea.Width, islandArea.Height) * 0.1f;
var vertices = CaveGenerator.CreateRandomChunk(islandArea.Width - (int)(radiusVariance * 2), islandArea.Height - (int)(radiusVariance * 2), 16, radiusVariance: radiusVariance);
@@ -1867,6 +1906,7 @@ namespace Barotrauma
new Point(islandArea.Center.X, islandArea.Center.Y + (int)(islandArea.Size.Y * (1.0f - caveScaleRelativeToIsland)) / 2),
new Point((int)(islandArea.Size.X * caveScaleRelativeToIsland), (int)(islandArea.Size.Y * caveScaleRelativeToIsland)));
AbyssIslands.Add(new AbyssIsland(islandArea, islandCells));
createdCaves++;
}
}
@@ -2942,13 +2982,13 @@ namespace Barotrauma
}
/// <param name="rotation">Used by clients to set the rotation for the resources</param>
public List<Item> GenerateMissionResources(ItemPrefab prefab, int requiredAmount, PositionType positionType, out float rotation, IEnumerable<Cave> targetCaves = null)
public List<Item> GenerateMissionResources(ItemPrefab prefab, int requiredAmount, PositionType positionType, IEnumerable<Cave> targetCaves = null)
{
var allValidLocations = GetAllValidClusterLocations();
var placedResources = new List<Item>();
rotation = 0.0f;
if (allValidLocations.None()) { return placedResources; } // TODO: WHAT?!
// if there are no valid locations, don't place anything
if (allValidLocations.None()) { return placedResources; }
// Make sure not to pick a spot that already has other level resources
for (int i = allValidLocations.Count - 1; i >= 0; i--)
@@ -2979,10 +3019,12 @@ namespace Barotrauma
if (PositionsOfInterest.None(p => p.PositionType == positionType))
{
DebugConsole.AddWarning($"Failed to find a position of the type \"{positionType}\" for mission resources.");
foreach (var validType in MineralMission.ValidPositionTypes)
{
if (validType != positionType && PositionsOfInterest.Any(p => p.PositionType == validType))
{
DebugConsole.AddWarning($"Placing in \"{validType}\" instead.");
positionType = validType;
break;
}
@@ -3042,7 +3084,6 @@ namespace Barotrauma
}
PlaceResources(prefab, requiredAmount, selectedLocation, out placedResources);
Vector2 edgeNormal = selectedLocation.Edge.GetNormal(selectedLocation.Cell);
rotation = MathHelper.ToDegrees(-MathUtils.VectorToAngle(edgeNormal) + MathHelper.PiOver2);
return placedResources;
static bool IsOnMainPath(ClusterLocation location) => location.Edge.NextToMainPath;
@@ -3151,9 +3192,7 @@ namespace Barotrauma
if (item.GetComponent<Holdable>() is Holdable h)
{
h.AttachToWall();
#if CLIENT
item.Rotation = MathHelper.ToDegrees(-MathUtils.VectorToAngle(edgeNormal) + MathHelper.PiOver2);
#endif
}
else if (item.body != null)
{
@@ -3234,7 +3273,8 @@ namespace Barotrauma
{
suitablePositions.RemoveAll(p => !filter(p));
}
if (positionType.HasFlag(PositionType.MainPath) || positionType.HasFlag(PositionType.SidePath))
if (positionType.HasFlag(PositionType.MainPath) || positionType.HasFlag(PositionType.SidePath) || positionType.HasFlag(PositionType.Abyss) ||
positionType.HasFlag(PositionType.Cave) || positionType.HasFlag(PositionType.AbyssCave))
{
suitablePositions.RemoveAll(p => IsPositionInsideWall(p.Position.ToVector2()));
}
@@ -3399,8 +3439,7 @@ namespace Barotrauma
bool closeEnough = false;
foreach (VoronoiCell cell in wall.Cells)
{
if (Math.Abs(cell.Center.X - worldPos.X) < (searchDepth + 1) * GridCellSize &&
Math.Abs(cell.Center.Y - worldPos.Y) < (searchDepth + 1) * GridCellSize)
if (cell.IsPointInsideAABB(worldPos, margin: (searchDepth + 1) * GridCellSize / 2))
{
closeEnough = true;
break;
@@ -3553,6 +3592,13 @@ namespace Barotrauma
var subDoc = SubmarineInfo.OpenFile(contentFile.Path.Value);
Rectangle subBorders = Submarine.GetBorders(subDoc.Root);
SubmarineInfo info = new SubmarineInfo(contentFile.Path.Value)
{
Type = type
};
//place downwards by default
var placement = info.BeaconStationInfo?.Placement ?? PlacementType.Bottom;
// Add some margin so that the sub doesn't block the path entirely. It's still possible that some larger subs can't pass by.
Point paddedDimensions = new Point(subBorders.Width + 3000, subBorders.Height + 3000);
@@ -3573,7 +3619,7 @@ namespace Barotrauma
attemptsLeft--;
if (TryGetSpawnPoint(out spawnPoint))
{
success = TryPositionSub(subBorders, subName, ref spawnPoint);
success = TryPositionSub(subBorders, subName, placement, ref spawnPoint);
if (success)
{
break;
@@ -3594,10 +3640,6 @@ namespace Barotrauma
{
Debug.WriteLine($"Sub {subName} successfully positioned to {spawnPoint} in {tempSW.ElapsedMilliseconds} (ms)");
tempSW.Restart();
SubmarineInfo info = new SubmarineInfo(contentFile.Path.Value)
{
Type = type
};
Submarine sub = new Submarine(info);
if (type == SubmarineType.Wreck)
{
@@ -3647,10 +3689,10 @@ namespace Barotrauma
return null;
}
bool TryPositionSub(Rectangle subBorders, string subName, ref Vector2 spawnPoint)
{
bool TryPositionSub(Rectangle subBorders, string subName, PlacementType placement, ref Vector2 spawnPoint)
{
positions.Add(spawnPoint);
bool bottomFound = TryRaycastToBottom(subBorders, ref spawnPoint);
bool bottomFound = TryRaycast(subBorders, placement, ref spawnPoint);
positions.Add(spawnPoint);
bool leftSideBlocked = IsSideBlocked(subBorders, false);
@@ -3658,21 +3700,21 @@ namespace Barotrauma
int step = 5;
if (rightSideBlocked && !leftSideBlocked)
{
bottomFound = TryMove(subBorders, ref spawnPoint, -step);
bottomFound = TryMove(subBorders, placement, ref spawnPoint, -step);
}
else if (leftSideBlocked && !rightSideBlocked)
{
bottomFound = TryMove(subBorders, ref spawnPoint, step);
bottomFound = TryMove(subBorders, placement, ref spawnPoint, step);
}
else if (!bottomFound)
{
if (!leftSideBlocked)
{
bottomFound = TryMove(subBorders, ref spawnPoint, -step);
bottomFound = TryMove(subBorders, placement, ref spawnPoint, -step);
}
else if (!rightSideBlocked)
{
bottomFound = TryMove(subBorders, ref spawnPoint, step);
bottomFound = TryMove(subBorders, placement, ref spawnPoint, step);
}
else
{
@@ -3702,14 +3744,14 @@ namespace Barotrauma
}
return !isBlocked && bottomFound;
bool TryMove(Rectangle subBorders, ref Vector2 spawnPoint, float amount)
bool TryMove(Rectangle subBorders, PlacementType placement, ref Vector2 spawnPoint, float amount)
{
float maxMovement = 5000;
float totalAmount = 0;
bool foundBottom = TryRaycastToBottom(subBorders, ref spawnPoint);
bool foundBottom = TryRaycast(subBorders, placement, ref spawnPoint);
while (!IsSideBlocked(subBorders, amount > 0))
{
foundBottom = TryRaycastToBottom(subBorders, ref spawnPoint);
foundBottom = TryRaycast(subBorders, placement, ref spawnPoint);
totalAmount += amount;
spawnPoint = new Vector2(spawnPoint.X + amount, spawnPoint.Y);
if (Math.Abs(totalAmount) > maxMovement)
@@ -3738,7 +3780,7 @@ namespace Barotrauma
return false;
}
bool TryRaycastToBottom(Rectangle subBorders, ref Vector2 spawnPoint)
bool TryRaycast(Rectangle subBorders, PlacementType placement, ref Vector2 spawnPoint)
{
// Shoot five rays and pick the highest hit point.
int rayCount = 5;
@@ -3764,16 +3806,18 @@ namespace Barotrauma
break;
}
var simPos = ConvertUnits.ToSimUnits(rayStart);
var body = Submarine.PickBody(simPos, new Vector2(simPos.X, -1),
customPredicate: f => f.Body?.UserData is VoronoiCell cell && cell.Body.BodyType == BodyType.Static && !ExtraWalls.Any(w => w.Body == f.Body),
var body = Submarine.PickBody(simPos, new Vector2(simPos.X, placement == PlacementType.Bottom ? -1 : Size.Y + 1),
customPredicate: f => f.Body == TopBarrier || f.Body == BottomBarrier || (f.Body?.UserData is VoronoiCell cell && cell.Body.BodyType == BodyType.Static && !ExtraWalls.Any(w => w.Body == f.Body)),
collisionCategory: Physics.CollisionLevel | Physics.CollisionWall);
if (body != null)
{
positions[i] = ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) + new Vector2(0, subBorders.Height / 2);
positions[i] =
ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) +
new Vector2(0, subBorders.Height / 2 * (placement == PlacementType.Bottom ? 1 : -1));
hit = true;
}
}
float highestPoint = positions.Max(p => p.Y);
float highestPoint = placement == PlacementType.Bottom ? positions.Max(p => p.Y) : positions.Min(p => p.Y);
spawnPoint = new Vector2(spawnPoint.X, highestPoint);
return hit;
}
@@ -3953,8 +3997,18 @@ namespace Barotrauma
if (LevelData.OutpostGenerationParamsExist)
{
Location location = i == 0 ? StartLocation : EndLocation;
OutpostGenerationParams outpostGenerationParams = LevelData.ForceOutpostGenerationParams ??
LevelData.GetSuitableOutpostGenerationParams(location).GetRandom(Rand.RandSync.ServerAndClient);
OutpostGenerationParams outpostGenerationParams = null;
if (LevelData.ForceOutpostGenerationParams != null)
{
outpostGenerationParams = LevelData.ForceOutpostGenerationParams;
}
else
{
outpostGenerationParams =
LevelData.ForceOutpostGenerationParams ??
LevelData.GetSuitableOutpostGenerationParams(location, LevelData).GetRandom(Rand.RandSync.ServerAndClient);
}
LocationType locationType = location?.Type;
if (locationType == null)
{
@@ -4030,52 +4084,70 @@ namespace Barotrauma
}
}
DockingPort outpostPort = null;
closestDistance = float.MaxValue;
foreach (DockingPort port in DockingPort.List)
Vector2 spawnPos;
if (GenerationParams.ForceOutpostPosition != Vector2.Zero)
{
if (port.IsHorizontal || port.Docked) { continue; }
if (port.Item.Submarine != outpost) { continue; }
//the outpost port has to be at the bottom of the outpost
if (port.Item.WorldPosition.Y > outpost.WorldPosition.Y) { continue; }
float dist = Math.Abs(port.Item.WorldPosition.X - outpost.WorldPosition.X);
if (dist < closestDistance)
spawnPos = new Vector2(Size.X * GenerationParams.ForceOutpostPosition.X, Size.Y * GenerationParams.ForceOutpostPosition.Y);
}
else
{
DockingPort outpostPort = null;
closestDistance = float.MaxValue;
foreach (DockingPort port in DockingPort.List)
{
outpostPort = port;
closestDistance = dist;
if (port.IsHorizontal || port.Docked) { continue; }
if (port.Item.Submarine != outpost) { continue; }
//the outpost port has to be at the bottom of the outpost
if (port.Item.WorldPosition.Y > outpost.WorldPosition.Y) { continue; }
float dist = Math.Abs(port.Item.WorldPosition.X - outpost.WorldPosition.X);
if (dist < closestDistance)
{
outpostPort = port;
closestDistance = dist;
}
}
}
float subDockingPortOffset = subPort == null ? 0.0f : subPort.Item.WorldPosition.X - Submarine.MainSub.WorldPosition.X;
//don't try to compensate if the port is very far from the sub's center of mass
if (Math.Abs(subDockingPortOffset) > 5000.0f)
{
subDockingPortOffset = MathHelper.Clamp(subDockingPortOffset, -5000.0f, 5000.0f);
string warningMsg = "Docking port very far from the sub's center of mass (submarine: " + Submarine.MainSub.Info.Name + ", dist: " + subDockingPortOffset + "). The level generator may not be able to place the outpost so that docking is possible.";
DebugConsole.NewMessage(warningMsg, Color.Orange);
GameAnalyticsManager.AddErrorEventOnce("Lever.CreateOutposts:DockingPortVeryFar" + Submarine.MainSub.Info.Name, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
}
float? outpostDockingPortOffset = null;
if (outpostPort != null)
{
outpostDockingPortOffset = subPort == null ? 0.0f : outpostPort.Item.WorldPosition.X - outpost.WorldPosition.X;
//don't try to compensate if the port is very far from the outpost's center of mass
if (Math.Abs(outpostDockingPortOffset.Value) > 5000.0f)
float subDockingPortOffset = subPort == null ? 0.0f : subPort.Item.WorldPosition.X - Submarine.MainSub.WorldPosition.X;
//don't try to compensate if the port is very far from the sub's center of mass
if (Math.Abs(subDockingPortOffset) > 5000.0f)
{
outpostDockingPortOffset = MathHelper.Clamp(outpostDockingPortOffset.Value, -5000.0f, 5000.0f);
string warningMsg = "Docking port very far from the outpost's center of mass (outpost: " + outpost.Info.Name + ", dist: " + outpostDockingPortOffset + "). The level generator may not be able to place the outpost so that docking is possible.";
subDockingPortOffset = MathHelper.Clamp(subDockingPortOffset, -5000.0f, 5000.0f);
string warningMsg = "Docking port very far from the sub's center of mass (submarine: " + Submarine.MainSub.Info.Name + ", dist: " + subDockingPortOffset + "). The level generator may not be able to place the outpost so that docking is possible.";
DebugConsole.NewMessage(warningMsg, Color.Orange);
GameAnalyticsManager.AddErrorEventOnce("Lever.CreateOutposts:OutpostDockingPortVeryFar" + outpost.Info.Name, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
GameAnalyticsManager.AddErrorEventOnce("Lever.CreateOutposts:DockingPortVeryFar" + Submarine.MainSub.Info.Name, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
}
float? outpostDockingPortOffset = null;
if (outpostPort != null)
{
outpostDockingPortOffset = subPort == null ? 0.0f : outpostPort.Item.WorldPosition.X - outpost.WorldPosition.X;
//don't try to compensate if the port is very far from the outpost's center of mass
if (Math.Abs(outpostDockingPortOffset.Value) > 5000.0f)
{
outpostDockingPortOffset = MathHelper.Clamp(outpostDockingPortOffset.Value, -5000.0f, 5000.0f);
string warningMsg = "Docking port very far from the outpost's center of mass (outpost: " + outpost.Info.Name + ", dist: " + outpostDockingPortOffset + "). The level generator may not be able to place the outpost so that docking is possible.";
DebugConsole.NewMessage(warningMsg, Color.Orange);
GameAnalyticsManager.AddErrorEventOnce("Lever.CreateOutposts:OutpostDockingPortVeryFar" + outpost.Info.Name, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
}
}
spawnPos = outpost.FindSpawnPos(i == 0 ? StartPosition : EndPosition, minSize, outpostDockingPortOffset != null ? subDockingPortOffset - outpostDockingPortOffset.Value : 0.0f, verticalMoveDir: 1);
if (Type == LevelData.LevelType.Outpost)
{
spawnPos.Y = Math.Min(Size.Y - outpost.Borders.Height * 0.6f, spawnPos.Y + outpost.Borders.Height / 2);
}
}
Vector2 spawnPos = outpost.FindSpawnPos(i == 0 ? StartPosition : EndPosition, minSize, outpostDockingPortOffset != null ? subDockingPortOffset - outpostDockingPortOffset.Value : 0.0f, verticalMoveDir: 1);
if (Type == LevelData.LevelType.Outpost)
{
spawnPos.Y = Math.Min(Size.Y - outpost.Borders.Height * 0.6f, spawnPos.Y + outpost.Borders.Height / 2);
}
outpost.SetPosition(spawnPos, forceUndockFromStaticSubmarines: false);
foreach (WayPoint wp in WayPoint.WayPointList)
{
if (wp.Submarine == outpost && wp.SpawnType != SpawnType.Path)
{
PositionsOfInterest.Add(new InterestingPosition(wp.WorldPosition.ToPoint(), PositionType.Outpost, outpost));
}
}
if ((i == 0) == !Mirrored)
{
StartOutpost = outpost;
@@ -4094,13 +4166,12 @@ namespace Barotrauma
outpost.Info.Name = EndLocation.Name;
}
}
}
}
private void CreateBeaconStation()
{
if (!LevelData.HasBeaconStation) { return; }
if (!LevelData.HasBeaconStation && string.IsNullOrEmpty(GenerationParams.ForceBeaconStation)) { return; }
var beaconStationFiles = ContentPackageManager.EnabledPackages.All
.SelectMany(p => p.GetFiles<BeaconStationFile>())
.OrderBy(f => f.UintIdentifier).ToList();
@@ -4111,27 +4182,40 @@ namespace Barotrauma
}
var beaconInfos = SubmarineInfo.SavedSubmarines.Where(i => i.IsBeacon);
for (int i = beaconStationFiles.Count - 1; i >= 0; i--)
ContentFile contentFile = null;
if (!string.IsNullOrEmpty(GenerationParams.ForceBeaconStation))
{
var beaconStationFile = beaconStationFiles[i];
var matchingInfo = beaconInfos.SingleOrDefault(info => info.FilePath == beaconStationFile.Path.Value);
Debug.Assert(matchingInfo != null);
if (matchingInfo?.BeaconStationInfo is BeaconStationInfo beaconInfo)
contentFile = beaconStationFiles.FirstOrDefault(f => f.Path == GenerationParams.ForceBeaconStation);
if (contentFile == null)
{
if (LevelData.Difficulty < beaconInfo.MinLevelDifficulty || LevelData.Difficulty > beaconInfo.MaxLevelDifficulty)
{
beaconStationFiles.RemoveAt(i);
}
DebugConsole.ThrowError($"Failed to find the beacon station \"{GenerationParams.ForceBeaconStation}\". Using a random one instead...");
}
}
if (beaconStationFiles.None())
{
DebugConsole.ThrowError($"No BeaconStation files found for the level difficulty {LevelData.Difficulty}!");
return;
}
var contentFile = beaconStationFiles.GetRandom(Rand.RandSync.ServerAndClient);
string beaconStationName = System.IO.Path.GetFileNameWithoutExtension(contentFile.Path.Value);
if (contentFile == null)
{
for (int i = beaconStationFiles.Count - 1; i >= 0; i--)
{
var beaconStationFile = beaconStationFiles[i];
var matchingInfo = beaconInfos.SingleOrDefault(info => info.FilePath == beaconStationFile.Path.Value);
Debug.Assert(matchingInfo != null);
if (matchingInfo?.BeaconStationInfo is BeaconStationInfo beaconInfo)
{
if (LevelData.Difficulty < beaconInfo.MinLevelDifficulty || LevelData.Difficulty > beaconInfo.MaxLevelDifficulty)
{
beaconStationFiles.RemoveAt(i);
}
}
}
if (beaconStationFiles.None())
{
DebugConsole.ThrowError($"No BeaconStation files found for the level difficulty {LevelData.Difficulty}!");
return;
}
contentFile = beaconStationFiles.GetRandom(Rand.RandSync.ServerAndClient);
}
string beaconStationName = System.IO.Path.GetFileNameWithoutExtension(contentFile.Path.Value);
BeaconStation = SpawnSubOnPath(beaconStationName, contentFile, SubmarineType.BeaconStation);
if (BeaconStation == null)
{
@@ -4195,7 +4279,7 @@ namespace Barotrauma
{
bool allowDisconnectedWires = true;
bool allowDamagedWalls = true;
if (BeaconStation.Info?.BeaconStationInfo is BeaconStationInfo info)
if (BeaconStation?.Info?.BeaconStationInfo is BeaconStationInfo info)
{
allowDisconnectedWires = info.AllowDisconnectedWires;
allowDamagedWalls = info.AllowDamagedWalls;
@@ -4346,7 +4430,7 @@ namespace Barotrauma
corpse.AnimController.FindHull(worldPos, setSubmarine: true);
corpse.TeamID = CharacterTeamType.None;
corpse.EnableDespawn = false;
selectedPrefab.GiveItems(corpse, wreck);
selectedPrefab.GiveItems(corpse, wreck, sp);
corpse.Kill(CauseOfDeathType.Unknown, causeOfDeathAffliction: null, log: false);
corpse.CharacterHealth.ApplyAffliction(corpse.AnimController.MainLimb, AfflictionPrefab.OxygenLow.Instantiate(200));
bool applyBurns = Rand.Value() < 0.1f;
@@ -4377,7 +4461,6 @@ namespace Barotrauma
}
}
corpse.CharacterHealth.ForceUpdateVisuals();
corpse.GiveIdCardTags(sp);
bool isServerOrSingleplayer = GameMain.IsSingleplayer || GameMain.NetworkMember is { IsServer: true };
if (isServerOrSingleplayer && selectedPrefab.MinMoney >= 0 && selectedPrefab.MaxMoney > 0)