v1.5.7.0 (Summer Update)

This commit is contained in:
Regalis11
2024-06-18 16:49:51 +03:00
parent 4a63dacbce
commit 230d1b6e78
263 changed files with 7792 additions and 2845 deletions
@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Voronoi2;
namespace Barotrauma
@@ -430,6 +431,11 @@ namespace Barotrauma
{
get { return ForcedDifficulty ?? LevelData.Difficulty; }
}
/// <summary>
/// Inclusive (matching the min an max values is accepted).
/// </summary>
public bool IsAllowedDifficulty(float minDifficulty, float maxDifficulty) => LevelData.IsAllowedDifficulty(minDifficulty, maxDifficulty);
public LevelData.LevelType Type
{
@@ -3718,7 +3724,7 @@ namespace Barotrauma
return MathUtils.LineSegmentToPointDistanceSquared(endPosition, endExitPosition, position) < minDist * minDist;
}
private Submarine SpawnSubOnPath(string subName, ContentFile contentFile, SubmarineType type)
private Submarine SpawnSubOnPath(string subName, ContentFile contentFile, SubmarineType type, bool forceThalamus = false)
{
var tempSW = new Stopwatch();
@@ -3801,7 +3807,7 @@ namespace Barotrauma
}
}
// Only spawn thalamus when the wreck has some thalamus items defined.
if (Rand.Value(Rand.RandSync.ServerAndClient) <= Loaded.GenerationParams.ThalamusProbability && sub.GetItems(false).Any(i => i.Prefab.HasSubCategory("thalamus")))
if ((forceThalamus || Rand.Value(Rand.RandSync.ServerAndClient) <= Loaded.GenerationParams.ThalamusProbability) && sub.GetItems(false).Any(i => i.Prefab.HasSubCategory("thalamus")))
{
if (!sub.CreateWreckAI())
{
@@ -4039,72 +4045,114 @@ namespace Barotrauma
private readonly Dictionary<Submarine, List<Vector2>> wreckPositions = new Dictionary<Submarine, List<Vector2>>();
private readonly Dictionary<Submarine, List<Rectangle>> blockedRects = new Dictionary<Submarine, List<Rectangle>>();
private readonly record struct PlaceableWreck(WreckFile WreckFile, WreckInfo WreckInfo)
{
public static Option<PlaceableWreck> TryCreate(WreckFile wreckFile)
{
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(i => i.FilePath == wreckFile.Path.Value);
if (matchingSub?.WreckInfo is null)
{
DebugConsole.ThrowError($"No matching submarine info found for the wreck file {wreckFile.Path.Value}");
return Option.None;
}
return Option.Some(new PlaceableWreck(wreckFile, matchingSub.WreckInfo));
}
}
private void CreateWrecks()
{
var totalSW = new Stopwatch();
totalSW.Start();
var wreckFiles = ContentPackageManager.EnabledPackages.All
var placeableWrecks = ContentPackageManager.EnabledPackages.All
.SelectMany(p => p.GetFiles<WreckFile>())
.OrderBy(f => f.UintIdentifier).ToList();
.OrderBy(f => f.UintIdentifier)
.Select(PlaceableWreck.TryCreate)
.Where(w => w.IsSome())
.Select(o => o.TryUnwrap(out var w) ? w : throw new InvalidOperationException())
.ToList();
for (int i = wreckFiles.Count - 1; i >= 0; i--)
for (int i = placeableWrecks.Count - 1; i >= 0; i--)
{
var wreckFile = wreckFiles[i];
var wreckInfos = SubmarineInfo.SavedSubmarines.Where(i => i.IsWreck);
var matchingInfo = wreckInfos.SingleOrDefault(info => info.FilePath == wreckFile.Path.Value);
Debug.Assert(matchingInfo != null);
if (matchingInfo?.WreckInfo is WreckInfo wreckInfo)
var wreckInfo = placeableWrecks[i].WreckInfo;
if (!IsAllowedDifficulty(wreckInfo.MinLevelDifficulty, wreckInfo.MaxLevelDifficulty))
{
if (Difficulty < wreckInfo.MinLevelDifficulty || Difficulty > wreckInfo.MaxLevelDifficulty)
{
wreckFiles.RemoveAt(i);
}
placeableWrecks.RemoveAt(i);
}
}
if (wreckFiles.None())
if (placeableWrecks.None())
{
DebugConsole.ThrowError($"No wreck files found for the level difficulty {LevelData.Difficulty}!");
Wrecks = new List<Submarine>();
return;
}
wreckFiles.Shuffle(Rand.RandSync.ServerAndClient);
placeableWrecks.Shuffle(Rand.RandSync.ServerAndClient);
int minWreckCount = Math.Min(Loaded.GenerationParams.MinWreckCount, wreckFiles.Count);
int maxWreckCount = Math.Min(Loaded.GenerationParams.MaxWreckCount, wreckFiles.Count);
int minWreckCount = Math.Min(Loaded.GenerationParams.MinWreckCount, placeableWrecks.Count);
int maxWreckCount = Math.Min(Loaded.GenerationParams.MaxWreckCount, placeableWrecks.Count);
int wreckCount = Rand.Range(minWreckCount, maxWreckCount + 1, Rand.RandSync.ServerAndClient);
bool requireThalamus = false;
if (GameMain.GameSession?.GameMode?.Missions.Any(m => m.Prefab.RequireWreck) ?? false)
{
wreckCount = Math.Max(wreckCount, 1);
}
if (GameMain.GameSession?.GameMode?.Missions.Any(static m => m.Prefab.RequireThalamusWreck) ?? false)
{
requireThalamus = true;
}
if (LevelData.ForceWreck != null)
{
//force the desired wreck to be chosen first
var matchingFile = wreckFiles.FirstOrDefault(w => w.Path == LevelData.ForceWreck.FilePath);
if (matchingFile != null)
var matchingFile = placeableWrecks.FirstOrDefault(w => w.WreckFile.Path == LevelData.ForceWreck.FilePath);
if (matchingFile.WreckFile != null)
{
wreckFiles.Remove(matchingFile);
wreckFiles.Insert(0, matchingFile);
placeableWrecks.Remove(matchingFile);
placeableWrecks.Insert(0, matchingFile);
}
wreckCount = Math.Max(wreckCount, 1);
}
if (requireThalamus)
{
var thalamusWrecks = placeableWrecks
.Where(static w => w.WreckInfo.WreckContainsThalamus == WreckInfo.HasThalamus.Yes)
.ToList();
if (thalamusWrecks.Any())
{
thalamusWrecks.Shuffle(Rand.RandSync.ServerAndClient);
foreach (var wreck in thalamusWrecks)
{
placeableWrecks.Remove(wreck);
placeableWrecks.Insert(0, wreck);
}
}
}
Wrecks = new List<Submarine>(wreckCount);
for (int i = 0; i < wreckCount; i++)
{
//how many times we'll try placing another sub before giving up
const int MaxSubsToTry = 2;
int attempts = 0;
while (wreckFiles.Any() && attempts < MaxSubsToTry)
while (placeableWrecks.Any() && attempts < MaxSubsToTry)
{
ContentFile contentFile = wreckFiles.First();
wreckFiles.RemoveAt(0);
if (contentFile == null) { continue; }
string wreckName = System.IO.Path.GetFileNameWithoutExtension(contentFile.Path.Value);
if (SpawnSubOnPath(wreckName, contentFile, SubmarineType.Wreck) != null)
var placeableWreck = placeableWrecks.First();
var wreckFile = placeableWreck.WreckFile;
placeableWrecks.RemoveAt(0);
if (wreckFile == null) { continue; }
string wreckName = System.IO.Path.GetFileNameWithoutExtension(wreckFile.Path.Value);
if (SpawnSubOnPath(wreckName, wreckFile, SubmarineType.Wreck, forceThalamus: requireThalamus) is { } wreck)
{
if (wreck.WreckAI is not null)
{
requireThalamus = false;
}
//placed successfully
break;
}
@@ -4223,7 +4271,7 @@ namespace Barotrauma
{
foreach (MapEntity entityToHide in MapEntity.MapEntityList.Where(me => me.Submarine == outpost && (me.Prefab?.HasSubCategory(categoryToHide) ?? false)))
{
entityToHide.HiddenInGame = true;
entityToHide.IsLayerHidden = true;
}
}
}
@@ -4489,72 +4537,97 @@ namespace Barotrauma
else if (GameMain.NetworkMember is not { IsClient: true })
{
bool allowDisconnectedWires = true;
bool allowDamagedDevices = true;
bool allowDamagedWalls = true;
if (BeaconStation?.Info?.BeaconStationInfo is BeaconStationInfo info)
{
allowDisconnectedWires = info.AllowDisconnectedWires;
allowDamagedWalls = info.AllowDamagedWalls;
allowDamagedDevices = info.AllowDamagedDevices;
}
//remove wires
float removeWireMinDifficulty = 20.0f;
float removeWireProbability = MathUtils.InverseLerp(removeWireMinDifficulty, 100.0f, LevelData.Difficulty) * 0.5f;
if (removeWireProbability > 0.0f && allowDisconnectedWires)
float disconnectWireMinDifficulty = 20.0f;
float disconnectWireProbability = MathUtils.InverseLerp(disconnectWireMinDifficulty, 100.0f, LevelData.Difficulty) * 0.5f;
if (disconnectWireProbability > 0.0f && allowDisconnectedWires)
{
foreach (Item item in beaconItems.Where(it => it.GetComponent<Wire>() != null).ToList())
{
if (item.NonInteractable || item.InvulnerableToDamage) { continue; }
Wire wire = item.GetComponent<Wire>();
if (wire.Locked) { continue; }
if (wire.Connections[0] != null && (wire.Connections[0].Item.NonInteractable || wire.Connections[0].Item.GetComponent<ConnectionPanel>().Locked))
{
continue;
}
if (wire.Connections[1] != null && (wire.Connections[1].Item.NonInteractable || wire.Connections[1].Item.GetComponent<ConnectionPanel>().Locked))
{
continue;
}
if (Rand.Range(0f, 1.0f, Rand.RandSync.Unsynced) < removeWireProbability)
{
foreach (Connection connection in wire.Connections)
{
if (connection != null)
{
connection.ConnectionPanel.DisconnectedWires.Add(wire);
wire.RemoveConnection(connection.Item);
#if SERVER
connection.ConnectionPanel.Item.CreateServerEvent(connection.ConnectionPanel);
wire.CreateNetworkEvent();
#endif
}
}
}
}
DisconnectBeaconStationWires(disconnectWireProbability);
}
if (allowDamagedDevices)
{
DamageBeaconStationDevices(breakDeviceProbability: 0.5f);
}
if (allowDamagedWalls)
{
//break powered items
foreach (Item item in beaconItems.Where(it => it.Components.Any(c => c is Powered) && it.Components.Any(c => c is Repairable)))
DamageBeaconStationWalls(damageWallProbability: 0.25f);
}
}
SetLinkedSubCrushDepth(BeaconStation);
}
public void DisconnectBeaconStationWires(float disconnectWireProbability)
{
if (disconnectWireProbability <= 0.0f) { return; }
List<Item> beaconItems = Item.ItemList.FindAll(it => it.Submarine == BeaconStation);
foreach (Item item in beaconItems.Where(it => it.GetComponent<Wire>() != null).ToList())
{
if (item.NonInteractable || item.InvulnerableToDamage) { continue; }
Wire wire = item.GetComponent<Wire>();
if (wire.Locked) { continue; }
if (wire.Connections[0] != null && (wire.Connections[0].Item.NonInteractable || wire.Connections[0].Item.GetComponent<ConnectionPanel>().Locked))
{
continue;
}
if (wire.Connections[1] != null && (wire.Connections[1].Item.NonInteractable || wire.Connections[1].Item.GetComponent<ConnectionPanel>().Locked))
{
continue;
}
if (Rand.Range(0f, 1.0f, Rand.RandSync.Unsynced) < disconnectWireProbability)
{
foreach (Connection connection in wire.Connections)
{
if (item.NonInteractable || item.InvulnerableToDamage) { continue; }
if (Rand.Range(0f, 1f, Rand.RandSync.Unsynced) < 0.5f)
if (connection != null)
{
item.Condition *= Rand.Range(0.6f, 0.8f, Rand.RandSync.Unsynced);
}
}
//poke holes in the walls
foreach (Structure structure in Structure.WallList.Where(s => s.Submarine == BeaconStation))
{
if (Rand.Range(0f, 1f, Rand.RandSync.Unsynced) < 0.25f)
{
int sectionIndex = Rand.Range(0, structure.SectionCount - 1, Rand.RandSync.Unsynced);
structure.AddDamage(sectionIndex, Rand.Range(structure.MaxHealth * 0.2f, structure.MaxHealth, Rand.RandSync.Unsynced));
connection.ConnectionPanel.DisconnectedWires.Add(wire);
wire.RemoveConnection(connection.Item);
#if SERVER
connection.ConnectionPanel.Item.CreateServerEvent(connection.ConnectionPanel);
wire.CreateNetworkEvent();
#endif
}
}
}
}
SetLinkedSubCrushDepth(BeaconStation);
}
public void DamageBeaconStationDevices(float breakDeviceProbability)
{
if (breakDeviceProbability <= 0.0f) { return; }
//break powered items
List<Item> beaconItems = Item.ItemList.FindAll(it => it.Submarine == BeaconStation);
foreach (Item item in beaconItems.Where(it => it.Components.Any(c => c is Powered) && it.Components.Any(c => c is Repairable)))
{
if (item.NonInteractable || item.InvulnerableToDamage) { continue; }
if (Rand.Range(0f, 1f, Rand.RandSync.Unsynced) < breakDeviceProbability)
{
item.Condition *= Rand.Range(0.6f, 0.8f, Rand.RandSync.Unsynced);
}
}
}
public void DamageBeaconStationWalls(float damageWallProbability)
{
if (damageWallProbability <= 0.0f) { return; }
//poke holes in the walls
foreach (Structure structure in Structure.WallList.Where(s => s.Submarine == BeaconStation))
{
if (Rand.Range(0f, 1f, Rand.RandSync.Unsynced) < damageWallProbability)
{
int sectionIndex = Rand.Range(0, structure.SectionCount - 1, Rand.RandSync.Unsynced);
structure.AddDamage(sectionIndex, Rand.Range(structure.MaxHealth * 0.2f, structure.MaxHealth, Rand.RandSync.Unsynced));
}
}
}
public bool CheckBeaconActive()