Unstable 0.17.0.0
This commit is contained in:
@@ -1,93 +1,37 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal class NPCSet : IDisposable
|
||||
internal class NPCSet : Prefab
|
||||
{
|
||||
private static List<NPCSet>? Sets { get; set; }
|
||||
public readonly static PrefabCollection<NPCSet> Sets = new PrefabCollection<NPCSet>();
|
||||
|
||||
private string Identifier { get; }
|
||||
|
||||
private readonly List<HumanPrefab> Humans = new List<HumanPrefab>();
|
||||
private readonly ImmutableArray<HumanPrefab> Humans;
|
||||
|
||||
private bool Disposed { get; set; }
|
||||
|
||||
private NPCSet(XElement element, string filePath)
|
||||
public NPCSet(ContentXElement element, NPCSetsFile file) : base(file, element.GetAttributeIdentifier("identifier", ""))
|
||||
{
|
||||
Identifier = element.GetAttributeString("identifier", string.Empty);
|
||||
|
||||
foreach (XElement npcElement in element.Elements())
|
||||
{
|
||||
Humans.Add(new HumanPrefab(npcElement, filePath));
|
||||
}
|
||||
Humans = element.Elements().Select(npcElement => new HumanPrefab(npcElement, file)).ToImmutableArray();
|
||||
}
|
||||
|
||||
public static HumanPrefab? Get(string identifier, string npcidentifier)
|
||||
public static HumanPrefab? Get(Identifier setIdentifier, Identifier npcidentifier)
|
||||
{
|
||||
HumanPrefab prefab = Sets.Where(set => set.Identifier == identifier).SelectMany(npcSet => npcSet.Humans.Where(npcSetHuman => npcSetHuman.Identifier == npcidentifier)).FirstOrDefault();
|
||||
HumanPrefab? prefab = Sets.Where(set => set.Identifier == setIdentifier).SelectMany(npcSet => npcSet.Humans.Where(npcSetHuman => npcSetHuman.Identifier == npcidentifier)).FirstOrDefault();
|
||||
|
||||
if (prefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find human prefab \"{npcidentifier}\" from \"{identifier}\".");
|
||||
DebugConsole.ThrowError($"Could not find human prefab \"{npcidentifier}\" from \"{setIdentifier}\".");
|
||||
return null;
|
||||
}
|
||||
return new HumanPrefab(prefab.Element, prefab.FilePath);
|
||||
}
|
||||
|
||||
public static void LoadSets()
|
||||
{
|
||||
Sets?.ForEach(set => set.Dispose());
|
||||
Sets = new List<NPCSet>();
|
||||
IEnumerable<ContentFile> files = GameMain.Instance.GetFilesOfType(ContentType.NPCSets);
|
||||
foreach (ContentFile file in files)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
XElement? rootElement = doc?.Root;
|
||||
|
||||
if (doc == null || rootElement == null) { continue; }
|
||||
|
||||
if (doc.Root.IsOverride())
|
||||
{
|
||||
Sets.Clear();
|
||||
DebugConsole.NewMessage($"Overriding all NPC sets with '{file.Path}'", Color.Yellow);
|
||||
}
|
||||
|
||||
foreach (XElement element in rootElement.Elements())
|
||||
{
|
||||
bool isOverride = element.IsOverride();
|
||||
XElement sourceElement = isOverride ? element.FirstElement() : element;
|
||||
string elementName = sourceElement.Name.ToString().ToLowerInvariant();
|
||||
string identifier = sourceElement.GetAttributeString("identifier", null);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(identifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"No identifier defined for the NPC set config '{elementName}' in file '{file.Path}'");
|
||||
continue;
|
||||
}
|
||||
|
||||
var existingParams = Sets.Find(set => set.Identifier == identifier);
|
||||
if (existingParams != null)
|
||||
{
|
||||
if (isOverride)
|
||||
{
|
||||
DebugConsole.NewMessage($"Overriding NPC set config '{identifier}' using the file '{file.Path}'", Color.Yellow);
|
||||
Sets.Remove(existingParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Duplicate NPC set config: '{identifier}' defined in {elementName} of '{file.Path}'");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Sets.Add(new NPCSet(element, file.Path));
|
||||
}
|
||||
}
|
||||
return prefab;
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
@@ -103,7 +47,7 @@ namespace Barotrauma
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
+102
-101
@@ -1,164 +1,209 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class OutpostGenerationParams : ISerializableEntity
|
||||
class OutpostGenerationParams : PrefabWithUintIdentifier, ISerializableEntity
|
||||
{
|
||||
public static List<OutpostGenerationParams> Params { get; private set; }
|
||||
|
||||
public readonly static PrefabCollection<OutpostGenerationParams> OutpostParams = new PrefabCollection<OutpostGenerationParams>();
|
||||
|
||||
public virtual string Name { get; private set; }
|
||||
|
||||
public string Identifier { get; private set; }
|
||||
|
||||
private readonly List<string> allowedLocationTypes = new List<string>();
|
||||
|
||||
private readonly HashSet<Identifier> allowedLocationTypes = new HashSet<Identifier>();
|
||||
|
||||
/// <summary>
|
||||
/// Identifiers of the location types this outpost can appear in. If empty, can appear in all types of locations.
|
||||
/// </summary>
|
||||
public IEnumerable<string> AllowedLocationTypes
|
||||
public IEnumerable<Identifier> AllowedLocationTypes
|
||||
{
|
||||
get { return allowedLocationTypes; }
|
||||
}
|
||||
|
||||
[Serialize(10, isSaveable: true), Editable(MinValueInt = 1, MaxValueInt = 50)]
|
||||
[Serialize(10, IsPropertySaveable.Yes), Editable(MinValueInt = 1, MaxValueInt = 50)]
|
||||
public int TotalModuleCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(200.0f, isSaveable: true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
|
||||
[Serialize(200.0f, IsPropertySaveable.Yes), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
|
||||
public float MinHallwayLength
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, isSaveable: true), Editable]
|
||||
[Serialize(false, IsPropertySaveable.Yes), Editable]
|
||||
public bool AlwaysDestructible
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, isSaveable: true), Editable]
|
||||
[Serialize(false, IsPropertySaveable.Yes), Editable]
|
||||
public bool AlwaysRewireable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, isSaveable: true), Editable]
|
||||
[Serialize(false, IsPropertySaveable.Yes), Editable]
|
||||
public bool AllowStealing
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(true, isSaveable: true), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes), Editable]
|
||||
public bool SpawnCrewInsideOutpost
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(true, isSaveable: true), Editable]
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes), Editable]
|
||||
public bool LockUnusedDoors
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(true, isSaveable: true), Editable]
|
||||
[Serialize(true, IsPropertySaveable.Yes), Editable]
|
||||
public bool RemoveUnusedGaps
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, isSaveable: true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
[Serialize(0.0f, IsPropertySaveable.Yes), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
public float MinWaterPercentage
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, isSaveable: true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
[Serialize(0.0f, IsPropertySaveable.Yes), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
|
||||
public float MaxWaterPercentage
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("", isSaveable: true), Editable]
|
||||
[Serialize("", IsPropertySaveable.Yes), Editable]
|
||||
public string ReplaceInRadiation { get; set; }
|
||||
|
||||
private readonly Dictionary<string, int> moduleCounts = new Dictionary<string, int>();
|
||||
private readonly Dictionary<Identifier, int> moduleCounts = new Dictionary<Identifier, int>();
|
||||
|
||||
public IEnumerable<KeyValuePair<string, int>> ModuleCounts
|
||||
public IReadOnlyDictionary<Identifier, int> ModuleCounts
|
||||
{
|
||||
get { return moduleCounts; }
|
||||
}
|
||||
|
||||
private readonly List<List<HumanPrefab>> humanPrefabLists = new List<List<HumanPrefab>>();
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties { get; private set; }
|
||||
|
||||
protected OutpostGenerationParams(XElement element, string filePath)
|
||||
private class NpcCollection : IReadOnlyList<HumanPrefab>
|
||||
{
|
||||
Identifier = element.GetAttributeString("identifier", "");
|
||||
Name = element.GetAttributeString("name", Identifier);
|
||||
allowedLocationTypes = element.GetAttributeStringArray("allowedlocationtypes", Array.Empty<string>()).ToList();
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
private class Entry
|
||||
{
|
||||
private readonly HumanPrefab humanPrefab = null;
|
||||
private readonly Identifier setIdentifier = Identifier.Empty;
|
||||
private readonly Identifier npcIdentifier = Identifier.Empty;
|
||||
|
||||
public Entry(HumanPrefab humanPrefab)
|
||||
{
|
||||
this.humanPrefab = humanPrefab;
|
||||
}
|
||||
|
||||
if (element == null) { return; }
|
||||
foreach (XElement subElement in element.Elements())
|
||||
public Entry(Identifier setIdentifier, Identifier npcIdentifier)
|
||||
{
|
||||
this.setIdentifier = setIdentifier;
|
||||
this.npcIdentifier = npcIdentifier;
|
||||
}
|
||||
|
||||
public HumanPrefab HumanPrefab
|
||||
=> humanPrefab ?? NPCSet.Get(setIdentifier, npcIdentifier);
|
||||
}
|
||||
|
||||
private readonly List<Entry> entries = new List<Entry>();
|
||||
|
||||
public void Add(HumanPrefab humanPrefab)
|
||||
=> entries.Add(new Entry(humanPrefab));
|
||||
|
||||
|
||||
public void Add(Identifier setIdentifier, Identifier npcIdentifier)
|
||||
=> entries.Add(new Entry(setIdentifier, npcIdentifier));
|
||||
|
||||
public IEnumerator<HumanPrefab> GetEnumerator()
|
||||
{
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
yield return entry.HumanPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
public int Count => entries.Count;
|
||||
|
||||
public HumanPrefab this[int index] => entries[index].HumanPrefab;
|
||||
}
|
||||
|
||||
private readonly ImmutableArray<IReadOnlyList<HumanPrefab>> humanPrefabCollections;
|
||||
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; }
|
||||
|
||||
#warning TODO: this shouldn't really accept any ContentFile, issue is that RuinConfigFile and OutpostConfigFile are separate derived classes
|
||||
public OutpostGenerationParams(ContentXElement element, ContentFile file) : base(file, element.GetAttributeIdentifier("identifier", ""))
|
||||
{
|
||||
Name = element.GetAttributeString("name", Identifier.Value);
|
||||
allowedLocationTypes = element.GetAttributeIdentifierArray("allowedlocationtypes", Array.Empty<Identifier>()).ToHashSet();
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
var humanPrefabCollections = new List<IReadOnlyList<HumanPrefab>>();
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "modulecount":
|
||||
string moduleFlag = (subElement.GetAttributeString("flag", null) ?? subElement.GetAttributeString("moduletype", "")).ToLowerInvariant();
|
||||
Identifier moduleFlag = subElement.GetAttributeIdentifier("flag", subElement.GetAttributeIdentifier("moduletype", ""));
|
||||
moduleCounts[moduleFlag] = subElement.GetAttributeInt("count", 0);
|
||||
break;
|
||||
case "npcs":
|
||||
humanPrefabLists.Add(new List<HumanPrefab>());
|
||||
foreach (XElement npcElement in subElement.Elements())
|
||||
var newCollection = new NpcCollection();
|
||||
foreach (var npcElement in subElement.Elements())
|
||||
{
|
||||
string from = npcElement.GetAttributeString("from", string.Empty);
|
||||
|
||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||
if (!string.IsNullOrWhiteSpace(from))
|
||||
Identifier from = npcElement.GetAttributeIdentifier("from", Identifier.Empty);
|
||||
|
||||
if (from != Identifier.Empty)
|
||||
{
|
||||
HumanPrefab prefab = NPCSet.Get(from, npcElement.GetAttributeString("identifier", string.Empty));
|
||||
if (prefab != null)
|
||||
{
|
||||
humanPrefabLists.Last().Add(prefab);
|
||||
}
|
||||
newCollection.Add(from, npcElement.GetAttributeIdentifier("identifier", Identifier.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
humanPrefabLists.Last().Add(new HumanPrefab(npcElement, filePath));
|
||||
newCollection.Add(new HumanPrefab(npcElement, file));
|
||||
}
|
||||
}
|
||||
humanPrefabCollections.Add(newCollection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.humanPrefabCollections = humanPrefabCollections.ToImmutableArray();
|
||||
}
|
||||
|
||||
public int GetModuleCount(string moduleFlag)
|
||||
public int GetModuleCount(Identifier moduleFlag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(moduleFlag) || moduleFlag == "none") { return int.MaxValue; }
|
||||
if (moduleFlag == Identifier.Empty || moduleFlag == "none") { return int.MaxValue; }
|
||||
return moduleCounts.ContainsKey(moduleFlag) ? moduleCounts[moduleFlag] : 0;
|
||||
}
|
||||
|
||||
public void SetModuleCount(string moduleFlag, int count)
|
||||
public void SetModuleCount(Identifier moduleFlag, int count)
|
||||
{
|
||||
if (string.IsNullOrEmpty(moduleFlag) || moduleFlag == "none") { return; }
|
||||
if (moduleFlag == Identifier.Empty || moduleFlag == "none") { return; }
|
||||
if (count <= 0)
|
||||
{
|
||||
moduleCounts.Remove(moduleFlag);
|
||||
@@ -169,66 +214,22 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAllowedLocationTypes(IEnumerable<string> allowedLocationTypes)
|
||||
public void SetAllowedLocationTypes(IEnumerable<Identifier> allowedLocationTypes)
|
||||
{
|
||||
this.allowedLocationTypes.Clear();
|
||||
foreach (string locationType in allowedLocationTypes)
|
||||
foreach (Identifier locationType in allowedLocationTypes)
|
||||
{
|
||||
if (locationType.Equals("any", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (locationType == "any") { continue; }
|
||||
this.allowedLocationTypes.Add(locationType);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<HumanPrefab> GetHumanPrefabs(Rand.RandSync randSync)
|
||||
public IReadOnlyList<HumanPrefab> GetHumanPrefabs(Rand.RandSync randSync)
|
||||
{
|
||||
if (humanPrefabLists == null || !humanPrefabLists.Any()) { return Enumerable.Empty<HumanPrefab>(); }
|
||||
return humanPrefabLists.GetRandom(randSync);
|
||||
if (!humanPrefabCollections.Any()) { return Array.Empty<HumanPrefab>(); }
|
||||
return humanPrefabCollections.GetRandom(randSync);
|
||||
}
|
||||
|
||||
public static void LoadPresets()
|
||||
{
|
||||
Params = new List<OutpostGenerationParams>();
|
||||
var files = GameMain.Instance.GetFilesOfType(ContentType.OutpostConfig);
|
||||
foreach (ContentFile file in files)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
|
||||
if (doc?.Root == null) { continue; }
|
||||
var mainElement = doc.Root;
|
||||
if (doc.Root.IsOverride())
|
||||
{
|
||||
Params.Clear();
|
||||
DebugConsole.NewMessage($"Overriding all outpost generation parameters with '{file.Path}'", Color.Yellow);
|
||||
}
|
||||
|
||||
foreach (XElement element in mainElement.Elements())
|
||||
{
|
||||
bool isOverride = element.IsOverride();
|
||||
XElement sourceElement = isOverride ? element.FirstElement() : element;
|
||||
string elementName = sourceElement.Name.ToString().ToLowerInvariant();
|
||||
string identifier = sourceElement.GetAttributeString("identifier", null);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(identifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"No identifier defined for the outpost config '{elementName}' in file '{file.Path}'");
|
||||
continue;
|
||||
}
|
||||
var existingParams = Params.Find(p => p.Identifier == identifier);
|
||||
if (existingParams != null)
|
||||
{
|
||||
if (isOverride)
|
||||
{
|
||||
DebugConsole.NewMessage($"Overriding outpost config '{identifier}' using the file '{file.Path}'", Color.Yellow);
|
||||
Params.Remove(existingParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Duplicate outpost config: '{identifier}' defined in {elementName} of '{file.Path}'");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Params.Add(new OutpostGenerationParams(element, file.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void Dispose() { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -26,7 +28,7 @@ namespace Barotrauma
|
||||
|
||||
public OutpostModuleInfo.GapPosition UsedGapPositions = 0;
|
||||
|
||||
public readonly HashSet<string> FulfilledModuleTypes = new HashSet<string>();
|
||||
public readonly HashSet<Identifier> FulfilledModuleTypes = new HashSet<Identifier>();
|
||||
|
||||
public Vector2 Offset;
|
||||
|
||||
@@ -67,10 +69,18 @@ namespace Barotrauma
|
||||
|
||||
private static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, Location location, bool onlyEntrance = false)
|
||||
{
|
||||
var outpostModuleFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.OutpostModule);
|
||||
var outpostModuleFiles = ContentPackageManager.EnabledPackages.All
|
||||
.SelectMany(p => p.GetFiles<OutpostModuleFile>())
|
||||
.OrderBy(f => f.UintIdentifier).ToArray();
|
||||
var uintIdDupes = outpostModuleFiles.Where(f1 =>
|
||||
outpostModuleFiles.Any(f2 => f1 != f2 && f1.UintIdentifier == f2.UintIdentifier)).ToArray();
|
||||
if (uintIdDupes.Any())
|
||||
{
|
||||
throw new Exception($"OutpostModuleFile UintIdentifier duplicates found: {uintIdDupes.Select(f => f.Path)}");
|
||||
}
|
||||
if (location != null)
|
||||
{
|
||||
if (location.IsCriticallyRadiated() && OutpostGenerationParams.Params.FirstOrDefault(p => p.Identifier.Equals(generationParams.ReplaceInRadiation, StringComparison.OrdinalIgnoreCase)) is { } newParams)
|
||||
if (location.IsCriticallyRadiated() && OutpostGenerationParams.OutpostParams.FirstOrDefault(p => p.Identifier == generationParams.ReplaceInRadiation) is { } newParams)
|
||||
{
|
||||
generationParams = newParams;
|
||||
}
|
||||
@@ -80,21 +90,21 @@ namespace Barotrauma
|
||||
|
||||
//load the infos of the outpost module files
|
||||
List<SubmarineInfo> outpostModules = new List<SubmarineInfo>();
|
||||
foreach (ContentFile outpostModuleFile in outpostModuleFiles)
|
||||
foreach (var outpostModuleFile in outpostModuleFiles)
|
||||
{
|
||||
var subInfo = new SubmarineInfo(outpostModuleFile.Path);
|
||||
var subInfo = new SubmarineInfo(outpostModuleFile.Path.Value);
|
||||
if (subInfo.OutpostModuleInfo != null)
|
||||
{
|
||||
if (generationParams is RuinGeneration.RuinGenerationParams)
|
||||
{
|
||||
//if the module doesn't have the ruin flag or any other flag used in the generation params, don't use it in ruins
|
||||
if (!subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin") &&
|
||||
if (!subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin".ToIdentifier()) &&
|
||||
!generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Key)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin"))
|
||||
else if (subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin".ToIdentifier()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -131,14 +141,23 @@ namespace Barotrauma
|
||||
|
||||
selectedModules.Clear();
|
||||
//select which module types the outpost should consist of
|
||||
var pendingModuleFlags = onlyEntrance ? new List<string>() { generationParams.ModuleCounts.First().Key } : SelectModules(outpostModules, generationParams);
|
||||
foreach (string flag in pendingModuleFlags.Distinct().ToList())
|
||||
List<Identifier> pendingModuleFlags;
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
if (flag.Equals("none", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
#warning TODO: cursed
|
||||
pendingModuleFlags = onlyEntrance
|
||||
? generationParams.ModuleCounts
|
||||
.Keys.OrderBy(k => ToolBox.IdentifierToUint32Hash(k, md5))
|
||||
.First().ToEnumerable().ToList()
|
||||
: SelectModules(outpostModules, generationParams);
|
||||
}
|
||||
foreach (Identifier flag in pendingModuleFlags)
|
||||
{
|
||||
if (flag == "none") { continue; }
|
||||
int pendingCount = pendingModuleFlags.Count(f => f == flag);
|
||||
int availableModuleCount =
|
||||
outpostModules
|
||||
.Where(m => m.OutpostModuleInfo.ModuleFlags.Any(f => f.Equals(flag, StringComparison.OrdinalIgnoreCase)))
|
||||
.Where(m => m.OutpostModuleInfo.ModuleFlags.Any(f => f == flag))
|
||||
.Select(m => m.OutpostModuleInfo.MaxCount)
|
||||
.DefaultIfEmpty(0)
|
||||
.Sum();
|
||||
@@ -154,7 +173,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//the first module is spawned separately, remove it from the list of pending modules
|
||||
string initialModuleFlag = pendingModuleFlags.FirstOrDefault() ?? "airlock";
|
||||
Identifier initialModuleFlag = pendingModuleFlags.FirstOrDefault().IfEmpty("airlock".ToIdentifier());
|
||||
pendingModuleFlags.Remove(initialModuleFlag);
|
||||
|
||||
var initialModule = GetRandomModule(outpostModules, initialModuleFlag, locationType);
|
||||
@@ -162,9 +181,9 @@ namespace Barotrauma
|
||||
{
|
||||
throw new Exception("Failed to generate an outpost (no airlock modules found).");
|
||||
}
|
||||
foreach (string initialFlag in initialModule.OutpostModuleInfo.ModuleFlags)
|
||||
foreach (Identifier initialFlag in initialModule.OutpostModuleInfo.ModuleFlags)
|
||||
{
|
||||
if (pendingModuleFlags.Contains("initialFlag")) { pendingModuleFlags.Remove(initialFlag); }
|
||||
if (pendingModuleFlags.Contains("initialFlag".ToIdentifier())) { pendingModuleFlags.Remove(initialFlag); }
|
||||
}
|
||||
|
||||
if (remainingTries == 1)
|
||||
@@ -176,7 +195,7 @@ namespace Barotrauma
|
||||
selectedModules.Add(new PlacedModule(initialModule, null, OutpostModuleInfo.GapPosition.None));
|
||||
selectedModules.Last().FulfilledModuleTypes.Add(initialModuleFlag);
|
||||
AppendToModule(selectedModules.Last(), outpostModules.ToList(), pendingModuleFlags, selectedModules, locationType, allowExtendBelowInitialModule: generationParams is RuinGeneration.RuinGenerationParams);
|
||||
if (pendingModuleFlags.Any(flag => !flag.Equals("none", StringComparison.OrdinalIgnoreCase)))
|
||||
if (pendingModuleFlags.Any(flag => flag != "none"))
|
||||
{
|
||||
remainingTries--;
|
||||
if (remainingTries <= 0)
|
||||
@@ -196,7 +215,7 @@ namespace Barotrauma
|
||||
sub.Info.OutpostGenerationParams = generationParams;
|
||||
if (!generationFailed)
|
||||
{
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
foreach (Hull hull in Hull.HullList)
|
||||
{
|
||||
if (hull.Submarine != sub) { continue; }
|
||||
if (string.IsNullOrEmpty(hull.RoomName) ||
|
||||
@@ -223,12 +242,14 @@ 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.AllEnabledPackages, ContentType.Outpost);
|
||||
var outpostFiles = ContentPackageManager.EnabledPackages.All
|
||||
.SelectMany(p => p.GetFiles<OutpostFile>())
|
||||
.OrderBy(f => f.UintIdentifier).ToArray();
|
||||
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.");
|
||||
}
|
||||
var prebuiltOutpostInfo = new SubmarineInfo(outpostFiles.GetRandom(Rand.RandSync.Server).Path)
|
||||
var prebuiltOutpostInfo = new SubmarineInfo(outpostFiles.GetRandom(Rand.RandSync.ServerAndClient).Path.Value)
|
||||
{
|
||||
Type = SubmarineType.Outpost
|
||||
};
|
||||
@@ -386,7 +407,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
hull.WaterVolume = hull.Volume * Rand.Range(generationParams.MinWaterPercentage, generationParams.MaxWaterPercentage, Rand.RandSync.Server) * 0.01f;
|
||||
hull.WaterVolume = hull.Volume * Rand.Range(generationParams.MinWaterPercentage, generationParams.MaxWaterPercentage, Rand.RandSync.ServerAndClient) * 0.01f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,13 +421,13 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Select the number and types of the modules to use in the outpost
|
||||
/// </summary>
|
||||
private static List<string> SelectModules(IEnumerable<SubmarineInfo> modules, OutpostGenerationParams generationParams)
|
||||
private static List<Identifier> SelectModules(IEnumerable<SubmarineInfo> modules, OutpostGenerationParams generationParams)
|
||||
{
|
||||
int totalModuleCount = generationParams.TotalModuleCount;
|
||||
var pendingModuleFlags = new List<string>();
|
||||
var pendingModuleFlags = new List<Identifier>();
|
||||
bool availableModulesFound = true;
|
||||
|
||||
string initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Key;
|
||||
Identifier initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Key;
|
||||
pendingModuleFlags.Add(initialModuleFlag);
|
||||
while (pendingModuleFlags.Count < totalModuleCount && availableModulesFound)
|
||||
{
|
||||
@@ -426,13 +447,17 @@ namespace Barotrauma
|
||||
pendingModuleFlags.Add(moduleFlag.Key);
|
||||
}
|
||||
}
|
||||
pendingModuleFlags.Shuffle(Rand.RandSync.Server);
|
||||
using (MD5 md5 = MD5.Create())
|
||||
{
|
||||
pendingModuleFlags.Sort((i1, i2) => (int)ToolBox.StringToUInt32Hash(i1.Value.ToLowerInvariant(), md5) - (int)ToolBox.StringToUInt32Hash(i2.Value.ToLowerInvariant(), md5));
|
||||
}
|
||||
pendingModuleFlags.Shuffle(Rand.RandSync.ServerAndClient);
|
||||
while (pendingModuleFlags.Count < totalModuleCount)
|
||||
{
|
||||
//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.ServerAndClient), "none".ToIdentifier());
|
||||
}
|
||||
|
||||
//make sure the initial module is inserted first
|
||||
@@ -452,7 +477,7 @@ namespace Barotrauma
|
||||
/// <param name="selectedModules">The modules we've already selected to be used in the outpost.</param>
|
||||
private static bool AppendToModule(PlacedModule currentModule,
|
||||
List<SubmarineInfo> availableModules,
|
||||
List<string> pendingModuleFlags,
|
||||
List<Identifier> pendingModuleFlags,
|
||||
List<PlacedModule> selectedModules,
|
||||
LocationType locationType,
|
||||
bool retry = true,
|
||||
@@ -461,7 +486,7 @@ namespace Barotrauma
|
||||
if (pendingModuleFlags.Count == 0) { return true; }
|
||||
|
||||
List<PlacedModule> placedModules = new List<PlacedModule>();
|
||||
foreach (OutpostModuleInfo.GapPosition gapPosition in GapPositions().Randomize(Rand.RandSync.Server))
|
||||
foreach (OutpostModuleInfo.GapPosition gapPosition in GapPositions.Randomize(Rand.RandSync.ServerAndClient))
|
||||
{
|
||||
if (currentModule.UsedGapPositions.HasFlag(gapPosition)) { continue; }
|
||||
if (!allowExtendBelowInitialModule)
|
||||
@@ -526,15 +551,15 @@ namespace Barotrauma
|
||||
PlacedModule currentModule,
|
||||
OutpostModuleInfo.GapPosition gapPosition,
|
||||
List<SubmarineInfo> availableModules,
|
||||
List<string> pendingModuleFlags,
|
||||
List<Identifier> pendingModuleFlags,
|
||||
List<PlacedModule> selectedModules,
|
||||
LocationType locationType)
|
||||
{
|
||||
if (pendingModuleFlags.Count == 0) { return null; }
|
||||
|
||||
string flagToPlace = "none";
|
||||
Identifier flagToPlace = "none".ToIdentifier();
|
||||
SubmarineInfo nextModule = null;
|
||||
foreach (string moduleFlag in pendingModuleFlags)
|
||||
foreach (Identifier moduleFlag in pendingModuleFlags)
|
||||
{
|
||||
flagToPlace = moduleFlag;
|
||||
nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType);
|
||||
@@ -547,7 +572,7 @@ namespace Barotrauma
|
||||
{
|
||||
Offset = currentModule.Offset + GetMoveDir(gapPosition),
|
||||
};
|
||||
foreach (string moduleFlag in nextModule.OutpostModuleInfo.ModuleFlags)
|
||||
foreach (Identifier moduleFlag in nextModule.OutpostModuleInfo.ModuleFlags)
|
||||
{
|
||||
if (!pendingModuleFlags.Contains(moduleFlag)) { continue; }
|
||||
if (moduleFlag != "none" || flagToPlace == "none")
|
||||
@@ -711,19 +736,19 @@ namespace Barotrauma
|
||||
return solutionFound;
|
||||
}
|
||||
|
||||
private static SubmarineInfo GetRandomModule(IEnumerable<SubmarineInfo> modules, string moduleFlag, LocationType locationType)
|
||||
private static SubmarineInfo GetRandomModule(IEnumerable<SubmarineInfo> modules, Identifier moduleFlag, LocationType locationType)
|
||||
{
|
||||
IEnumerable<SubmarineInfo> availableModules = null;
|
||||
if (string.IsNullOrEmpty(moduleFlag) || moduleFlag.Equals("none"))
|
||||
if (moduleFlag.IsEmpty || moduleFlag == "none")
|
||||
{
|
||||
availableModules = modules.Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || m.OutpostModuleInfo.ModuleFlags.Contains("none"));
|
||||
availableModules = modules.Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || m.OutpostModuleInfo.ModuleFlags.Contains("none".ToIdentifier()));
|
||||
}
|
||||
else
|
||||
{
|
||||
availableModules = modules.Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag));
|
||||
if (moduleFlag != "hallwayhorizontal" && moduleFlag != "hallwayvertical")
|
||||
{
|
||||
availableModules = availableModules.Where(m => !m.OutpostModuleInfo.ModuleFlags.Contains("hallwayhorizontal") && !m.OutpostModuleInfo.ModuleFlags.Contains("hallwayvertical"));
|
||||
availableModules = availableModules.Where(m => !m.OutpostModuleInfo.ModuleFlags.Contains("hallwayhorizontal".ToIdentifier()) && !m.OutpostModuleInfo.ModuleFlags.Contains("hallwayvertical".ToIdentifier()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,7 +756,7 @@ namespace Barotrauma
|
||||
|
||||
//try to search for modules made specifically for this location type first
|
||||
var modulesSuitableForLocationType =
|
||||
availableModules.Where(m => m.OutpostModuleInfo.AllowedLocationTypes.Contains(locationType.Identifier.ToLowerInvariant()));
|
||||
availableModules.Where(m => m.OutpostModuleInfo.AllowedLocationTypes.Contains(locationType.Identifier));
|
||||
|
||||
//if not found, search for modules suitable for any location type
|
||||
if (!modulesSuitableForLocationType.Any())
|
||||
@@ -742,21 +767,21 @@ namespace Barotrauma
|
||||
if (!modulesSuitableForLocationType.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Could not find a suitable module for the location type {locationType}. Module flag: {moduleFlag}.", Color.Orange);
|
||||
return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.Server);
|
||||
return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToolBox.SelectWeightedRandom(modulesSuitableForLocationType.ToList(), modulesSuitableForLocationType.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.Server);
|
||||
return ToolBox.SelectWeightedRandom(modulesSuitableForLocationType.ToList(), modulesSuitableForLocationType.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
}
|
||||
|
||||
private static SubmarineInfo GetRandomModule(OutpostModuleInfo prevModule, IEnumerable<SubmarineInfo> modules, string moduleFlag, OutpostModuleInfo.GapPosition gapPosition, LocationType locationType)
|
||||
private static SubmarineInfo GetRandomModule(OutpostModuleInfo prevModule, IEnumerable<SubmarineInfo> modules, Identifier moduleFlag, OutpostModuleInfo.GapPosition gapPosition, LocationType locationType)
|
||||
{
|
||||
IEnumerable<SubmarineInfo> availableModules = null;
|
||||
if (string.IsNullOrEmpty(moduleFlag) || moduleFlag.Equals("none"))
|
||||
if (moduleFlag.IsEmpty || moduleFlag.Equals("none"))
|
||||
{
|
||||
availableModules = modules
|
||||
.Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || (m.OutpostModuleInfo.ModuleFlags.Count() == 1 && m.OutpostModuleInfo.ModuleFlags.Contains("none")) && m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition));
|
||||
.Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || (m.OutpostModuleInfo.ModuleFlags.Count() == 1 && m.OutpostModuleInfo.ModuleFlags.Contains("none".ToIdentifier())) && m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -772,7 +797,7 @@ namespace Barotrauma
|
||||
|
||||
//try to search for modules made specifically for this location type first
|
||||
var modulesSuitableForLocationType =
|
||||
availableModules.Where(m => m.OutpostModuleInfo.AllowedLocationTypes.Contains(locationType.Identifier.ToLowerInvariant()));
|
||||
availableModules.Where(m => m.OutpostModuleInfo.AllowedLocationTypes.Contains(locationType.Identifier));
|
||||
|
||||
//if not found, search for modules suitable for any location type
|
||||
if (!modulesSuitableForLocationType.Any())
|
||||
@@ -783,11 +808,11 @@ namespace Barotrauma
|
||||
if (!modulesSuitableForLocationType.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Could not find a suitable module for the location type {locationType}. Module flag: {moduleFlag}.", Color.Orange);
|
||||
return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.Server);
|
||||
return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToolBox.SelectWeightedRandom(modulesSuitableForLocationType.ToList(), modulesSuitableForLocationType.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.Server);
|
||||
return ToolBox.SelectWeightedRandom(modulesSuitableForLocationType.ToList(), modulesSuitableForLocationType.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,13 +832,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<OutpostModuleInfo.GapPosition> GapPositions()
|
||||
private readonly static OutpostModuleInfo.GapPosition[] GapPositions = new[]
|
||||
{
|
||||
yield return OutpostModuleInfo.GapPosition.Right;
|
||||
yield return OutpostModuleInfo.GapPosition.Left;
|
||||
yield return OutpostModuleInfo.GapPosition.Top;
|
||||
yield return OutpostModuleInfo.GapPosition.Bottom;
|
||||
}
|
||||
OutpostModuleInfo.GapPosition.Right,
|
||||
OutpostModuleInfo.GapPosition.Left,
|
||||
OutpostModuleInfo.GapPosition.Top,
|
||||
OutpostModuleInfo.GapPosition.Bottom
|
||||
};
|
||||
|
||||
private static OutpostModuleInfo.GapPosition GetOpposingGapPosition(OutpostModuleInfo.GapPosition thisGapPosition)
|
||||
{
|
||||
@@ -824,7 +849,7 @@ namespace Barotrauma
|
||||
OutpostModuleInfo.GapPosition.Bottom => OutpostModuleInfo.GapPosition.Top,
|
||||
OutpostModuleInfo.GapPosition.Top => OutpostModuleInfo.GapPosition.Bottom,
|
||||
OutpostModuleInfo.GapPosition.None => OutpostModuleInfo.GapPosition.None,
|
||||
_ => throw new InvalidOperationException()
|
||||
_ => throw new ArgumentException()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -837,7 +862,7 @@ namespace Barotrauma
|
||||
OutpostModuleInfo.GapPosition.Bottom => Vector2.UnitY,
|
||||
OutpostModuleInfo.GapPosition.Top => -Vector2.UnitY,
|
||||
OutpostModuleInfo.GapPosition.None => Vector2.Zero,
|
||||
_ => throw new InvalidOperationException()
|
||||
_ => throw new ArgumentException()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -885,7 +910,7 @@ namespace Barotrauma
|
||||
|
||||
private static bool CanAttachTo(OutpostModuleInfo from, OutpostModuleInfo to)
|
||||
{
|
||||
if (!from.AllowAttachToModules.Any() || from.AllowAttachToModules.All(s => s.Equals("any", StringComparison.OrdinalIgnoreCase))) { return true; }
|
||||
if (!from.AllowAttachToModules.Any() || from.AllowAttachToModules.All(s => s == "any")) { return true; }
|
||||
return from.AllowAttachToModules.Any(s => to.ModuleFlags.Contains(s));
|
||||
}
|
||||
|
||||
@@ -915,7 +940,7 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < thisJunctionBox.Connections.Count && i < previousJunctionBox.Connections.Count; i++)
|
||||
{
|
||||
var wirePrefab = MapEntityPrefab.Find(name: null, identifier: thisJunctionBox.Connections[i].IsPower ? "redwire" : "bluewire") as ItemPrefab;
|
||||
var wirePrefab = MapEntityPrefab.FindByIdentifier((thisJunctionBox.Connections[i].IsPower ? "redwire" : "bluewire").ToIdentifier()) as ItemPrefab;
|
||||
var wire = new Item(wirePrefab, thisJunctionBox.Item.Position, sub).GetComponent<Wire>();
|
||||
|
||||
if (!thisJunctionBox.Connections[i].TryAddLink(wire))
|
||||
@@ -1021,9 +1046,9 @@ namespace Barotrauma
|
||||
{
|
||||
suitableModules = availableModules.Where(m =>
|
||||
!m.OutpostModuleInfo.AllowAttachToModules.Any() ||
|
||||
m.OutpostModuleInfo.AllowAttachToModules.All(s => s.Equals("any", StringComparison.OrdinalIgnoreCase)));
|
||||
m.OutpostModuleInfo.AllowAttachToModules.All(s => s == "any"));
|
||||
}
|
||||
var hallwayInfo = GetRandomModule(suitableModules, isHorizontal ? "hallwayhorizontal" : "hallwayvertical", locationType);
|
||||
var hallwayInfo = GetRandomModule(suitableModules, (isHorizontal ? "hallwayhorizontal" : "hallwayvertical").ToIdentifier(), locationType);
|
||||
if (hallwayInfo == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Generating hallways between outpost modules failed. No {(isHorizontal ? "horizontal" : "vertical")} hallway modules suitable for use between the modules \"{module.Info.DisplayName}\" and \"{module.PreviousModule.Info.DisplayName}\".");
|
||||
@@ -1442,50 +1467,47 @@ namespace Barotrauma
|
||||
if (outpost?.Info?.OutpostGenerationParams == null) { return; }
|
||||
|
||||
List<HumanPrefab> killedCharacters = new List<HumanPrefab>();
|
||||
Dictionary<HumanPrefab, CharacterInfo> selectedCharacters = new Dictionary<HumanPrefab, CharacterInfo>();
|
||||
foreach (HumanPrefab humanPrefab in outpost.Info.OutpostGenerationParams.GetHumanPrefabs(Rand.RandSync.Server))
|
||||
List<(HumanPrefab HumanPrefab, CharacterInfo CharacterInfo)> selectedCharacters
|
||||
= new List<(HumanPrefab HumanPrefab, CharacterInfo CharacterInfo)>();
|
||||
foreach (HumanPrefab humanPrefab in outpost.Info.OutpostGenerationParams.GetHumanPrefabs(Rand.RandSync.ServerAndClient))
|
||||
{
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: humanPrefab.GetJobPrefab(Rand.RandSync.Server), randSync: Rand.RandSync.Server);
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: humanPrefab.GetJobPrefab(Rand.RandSync.ServerAndClient), randSync: Rand.RandSync.ServerAndClient);
|
||||
if (location != null && location.KilledCharacterIdentifiers.Contains(characterInfo.GetIdentifier()))
|
||||
{
|
||||
killedCharacters.Add(humanPrefab);
|
||||
continue;
|
||||
}
|
||||
selectedCharacters.Add(humanPrefab, characterInfo);
|
||||
selectedCharacters.Add((humanPrefab, characterInfo));
|
||||
}
|
||||
|
||||
//replace killed characters with new ones
|
||||
foreach (HumanPrefab killedCharacter in killedCharacters)
|
||||
{
|
||||
int tries = 0;
|
||||
while (tries < 100)
|
||||
for (int tries = 0; tries < 100; tries++)
|
||||
{
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: killedCharacter.GetJobPrefab(Rand.RandSync.Server), randSync: Rand.RandSync.Server);
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: killedCharacter.GetJobPrefab(Rand.RandSync.ServerAndClient), randSync: Rand.RandSync.ServerAndClient);
|
||||
if (!location.KilledCharacterIdentifiers.Contains(characterInfo.GetIdentifier()))
|
||||
{
|
||||
selectedCharacters.Add(killedCharacter, characterInfo);
|
||||
selectedCharacters.Add((killedCharacter, characterInfo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var selectedCharacter in selectedCharacters)
|
||||
foreach ((var humanPrefab, var characterInfo) in selectedCharacters)
|
||||
{
|
||||
HumanPrefab humanPrefab = selectedCharacter.Key;
|
||||
CharacterInfo characterInfo = selectedCharacter.Value;
|
||||
|
||||
Rand.SetSyncedSeed(ToolBox.StringToInt(characterInfo.Name));
|
||||
|
||||
ISpatialEntity gotoTarget = SpawnAction.GetSpawnPos(SpawnAction.SpawnLocationType.Outpost, SpawnType.Human, humanPrefab.GetModuleFlags(), humanPrefab.GetSpawnPointTags());
|
||||
if (gotoTarget == null)
|
||||
{
|
||||
gotoTarget = outpost.GetHulls(true).GetRandom(Rand.RandSync.Server);
|
||||
gotoTarget = outpost.GetHulls(true).GetRandom(Rand.RandSync.ServerAndClient);
|
||||
}
|
||||
characterInfo.TeamID = CharacterTeamType.FriendlyNPC;
|
||||
var npc = Character.Create(CharacterPrefab.HumanConfigFile, SpawnAction.OffsetSpawnPos(gotoTarget.WorldPosition, 100.0f), ToolBox.RandomSeed(8), characterInfo, hasAi: true, createNetworkEvent: true);
|
||||
var npc = Character.Create(CharacterPrefab.HumanSpeciesName, SpawnAction.OffsetSpawnPos(gotoTarget.WorldPosition, 100.0f), ToolBox.RandomSeed(8), characterInfo, hasAi: true, createNetworkEvent: true);
|
||||
npc.AnimController.FindHull(gotoTarget.WorldPosition, setSubmarine: true);
|
||||
npc.TeamID = CharacterTeamType.FriendlyNPC;
|
||||
npc.Prefab = humanPrefab;
|
||||
npc.HumanPrefab = humanPrefab;
|
||||
if (!outpost.Info.OutpostNPCs.ContainsKey(humanPrefab.Identifier))
|
||||
{
|
||||
outpost.Info.OutpostNPCs.Add(humanPrefab.Identifier, new List<Character>());
|
||||
@@ -1499,7 +1521,7 @@ namespace Barotrauma
|
||||
{
|
||||
npc.AddStaticHealthMultiplier(humanPrefab.HealthMultiplier);
|
||||
}
|
||||
humanPrefab.GiveItems(npc, outpost, Rand.RandSync.Server);
|
||||
humanPrefab.GiveItems(npc, outpost, Rand.RandSync.ServerAndClient);
|
||||
foreach (Item item in npc.Inventory.FindAllItems(it => it != null, recursive: true))
|
||||
{
|
||||
item.AllowStealing = outpost.Info.OutpostGenerationParams.AllowStealing;
|
||||
|
||||
@@ -18,46 +18,46 @@ namespace Barotrauma
|
||||
Bottom = 8
|
||||
}
|
||||
|
||||
private readonly HashSet<string> moduleFlags = new HashSet<string>();
|
||||
public IEnumerable<string> ModuleFlags
|
||||
private readonly HashSet<Identifier> moduleFlags = new HashSet<Identifier>();
|
||||
public IEnumerable<Identifier> ModuleFlags
|
||||
{
|
||||
get { return moduleFlags; }
|
||||
}
|
||||
|
||||
private readonly HashSet<string> allowAttachToModules = new HashSet<string>();
|
||||
public IEnumerable<string> AllowAttachToModules
|
||||
private readonly HashSet<Identifier> allowAttachToModules = new HashSet<Identifier>();
|
||||
public IEnumerable<Identifier> AllowAttachToModules
|
||||
{
|
||||
get { return allowAttachToModules; }
|
||||
}
|
||||
|
||||
private readonly HashSet<string> allowedLocationTypes = new HashSet<string>();
|
||||
public IEnumerable<string> AllowedLocationTypes
|
||||
private readonly HashSet<Identifier> allowedLocationTypes = new HashSet<Identifier>();
|
||||
public IEnumerable<Identifier> AllowedLocationTypes
|
||||
{
|
||||
get { return allowedLocationTypes; }
|
||||
}
|
||||
|
||||
[Serialize(100, isSaveable: true, description: "How many instances of this module can be used in one outpost."), Editable]
|
||||
[Serialize(100, IsPropertySaveable.Yes, description: "How many instances of this module can be used in one outpost."), Editable]
|
||||
public int MaxCount { get; set; }
|
||||
|
||||
[Serialize(10.0f, isSaveable: true, description: "How likely it is for the module to get picked when selecting from a set of modules during the outpost generation."), Editable]
|
||||
[Serialize(10.0f, IsPropertySaveable.Yes, description: "How likely it is for the module to get picked when selecting from a set of modules during the outpost generation."), Editable]
|
||||
public float Commonness { get; set; }
|
||||
|
||||
[Serialize(GapPosition.None, isSaveable: true, description: "Which sides of the module have gaps on them (i.e. from which sides the module can be attached to other modules). Center = no gaps available.")]
|
||||
[Serialize(GapPosition.None, IsPropertySaveable.Yes, description: "Which sides of the module have gaps on them (i.e. from which sides the module can be attached to other modules). Center = no gaps available.")]
|
||||
public GapPosition GapPositions { get; set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties { get; private set; }
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; }
|
||||
|
||||
public OutpostModuleInfo(SubmarineInfo submarineInfo, XElement element)
|
||||
{
|
||||
Name = $"OutpostModuleInfo ({submarineInfo.Name})";
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
SetFlags(
|
||||
element.GetAttributeStringArray("flags", null, convertToLowerInvariant: true) ??
|
||||
element.GetAttributeStringArray("moduletypes", new string[0], convertToLowerInvariant: true));
|
||||
SetAllowAttachTo(element.GetAttributeStringArray("allowattachto", new string[0], convertToLowerInvariant: true));
|
||||
allowedLocationTypes = new HashSet<string>(element.GetAttributeStringArray("allowedlocationtypes", new string[0], convertToLowerInvariant: true));
|
||||
element.GetAttributeIdentifierArray("flags", null) ??
|
||||
element.GetAttributeIdentifierArray("moduletypes", Array.Empty<Identifier>()));
|
||||
SetAllowAttachTo(element.GetAttributeIdentifierArray("allowattachto", Array.Empty<Identifier>()));
|
||||
allowedLocationTypes = new HashSet<Identifier>(element.GetAttributeIdentifierArray("allowedlocationtypes", Array.Empty<Identifier>()));
|
||||
}
|
||||
|
||||
public OutpostModuleInfo(SubmarineInfo submarineInfo)
|
||||
@@ -68,12 +68,12 @@ namespace Barotrauma
|
||||
public OutpostModuleInfo(OutpostModuleInfo original)
|
||||
{
|
||||
Name = original.Name;
|
||||
moduleFlags = new HashSet<string>(original.moduleFlags);
|
||||
allowAttachToModules = new HashSet<string>(original.allowAttachToModules);
|
||||
allowedLocationTypes = new HashSet<string>(original.allowedLocationTypes);
|
||||
SerializableProperties = new Dictionary<string, SerializableProperty>();
|
||||
moduleFlags = new HashSet<Identifier>(original.moduleFlags);
|
||||
allowAttachToModules = new HashSet<Identifier>(original.allowAttachToModules);
|
||||
allowedLocationTypes = new HashSet<Identifier>(original.allowedLocationTypes);
|
||||
SerializableProperties = new Dictionary<Identifier, SerializableProperty>();
|
||||
GapPositions = original.GapPositions;
|
||||
foreach (KeyValuePair<string, SerializableProperty> kvp in original.SerializableProperties)
|
||||
foreach (KeyValuePair<Identifier, SerializableProperty> kvp in original.SerializableProperties)
|
||||
{
|
||||
SerializableProperties.Add(kvp.Key, kvp.Value);
|
||||
if (SerializableProperty.GetSupportedTypeName(kvp.Value.PropertyType) != null)
|
||||
@@ -83,51 +83,51 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFlags(IEnumerable<string> newFlags)
|
||||
public void SetFlags(IEnumerable<Identifier> newFlags)
|
||||
{
|
||||
moduleFlags.Clear();
|
||||
if (newFlags.Contains("hallwayhorizontal"))
|
||||
if (newFlags.Contains("hallwayhorizontal".ToIdentifier()))
|
||||
{
|
||||
moduleFlags.Add("hallwayhorizontal");
|
||||
if (newFlags.Contains("ruin")) { moduleFlags.Add("ruin"); }
|
||||
moduleFlags.Add("hallwayhorizontal".ToIdentifier());
|
||||
if (newFlags.Contains("ruin".ToIdentifier())) { moduleFlags.Add("ruin".ToIdentifier()); }
|
||||
return;
|
||||
}
|
||||
if (newFlags.Contains("hallwayvertical"))
|
||||
if (newFlags.Contains("hallwayvertical".ToIdentifier()))
|
||||
{
|
||||
moduleFlags.Add("hallwayvertical");
|
||||
if (newFlags.Contains("ruin")) { moduleFlags.Add("ruin"); }
|
||||
moduleFlags.Add("hallwayvertical".ToIdentifier());
|
||||
if (newFlags.Contains("ruin".ToIdentifier())) { moduleFlags.Add("ruin".ToIdentifier()); }
|
||||
return;
|
||||
}
|
||||
if (!newFlags.Any())
|
||||
{
|
||||
moduleFlags.Add("none");
|
||||
moduleFlags.Add("none".ToIdentifier());
|
||||
}
|
||||
foreach (string flag in newFlags)
|
||||
foreach (Identifier flag in newFlags)
|
||||
{
|
||||
if (flag == "none" && newFlags.Count() > 1) { continue; }
|
||||
moduleFlags.Add(flag.ToLowerInvariant());
|
||||
moduleFlags.Add(flag);
|
||||
}
|
||||
}
|
||||
public void SetAllowAttachTo(IEnumerable<string> allowAttachTo)
|
||||
public void SetAllowAttachTo(IEnumerable<Identifier> allowAttachTo)
|
||||
{
|
||||
allowAttachToModules.Clear();
|
||||
if (!allowAttachTo.Any())
|
||||
{
|
||||
allowAttachToModules.Add("any");
|
||||
allowAttachToModules.Add("any".ToIdentifier());
|
||||
}
|
||||
foreach (string flag in allowAttachTo)
|
||||
foreach (Identifier flag in allowAttachTo)
|
||||
{
|
||||
if (flag == "any" && allowAttachTo.Count() > 1) { continue; }
|
||||
allowAttachToModules.Add(flag);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAllowedLocationTypes(IEnumerable<string> allowedLocationTypes)
|
||||
public void SetAllowedLocationTypes(IEnumerable<Identifier> allowedLocationTypes)
|
||||
{
|
||||
this.allowedLocationTypes.Clear();
|
||||
foreach (string locationType in allowedLocationTypes)
|
||||
foreach (Identifier locationType in allowedLocationTypes)
|
||||
{
|
||||
if (locationType.Equals("any", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
if (locationType == "any") { continue; }
|
||||
this.allowedLocationTypes.Add(locationType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user