3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Collections.Immutable;
14 public virtual string Name {
get;
private set; }
16 private readonly HashSet<Identifier> allowedLocationTypes =
new HashSet<Identifier>();
23 get {
return allowedLocationTypes; }
27 [
Serialize(-1,
IsPropertySaveable.Yes, description:
"Should this type of outpost be forced to the locations at the end of the campaign map? 0 = first end level, 1 = second end level, and so on."),
Editable(MinValueInt = -1, MaxValueInt = 10)]
34 [
Serialize(-1,
IsPropertySaveable.Yes, description:
"The closer to the current level difficulty this value is, the higher the probability of choosing these generation params are. Defaults to -1, which means we use the current difficulty."),
Editable(MinValueInt = 1, MaxValueInt = 50)]
48 [
Serialize(
true,
IsPropertySaveable.Yes, description:
"Should the generator append generic (module flag \"none\") modules to the outpost to reach the total module count."),
Editable]
55 [
Serialize(200.0f,
IsPropertySaveable.Yes, description:
"Minimum length of the hallways between modules. If 0, the generator will place the modules directly against each other assuming it can be done without making any modules overlap."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
104 [
Serialize(
false,
IsPropertySaveable.Yes, description:
"Should the whole outpost render behind submarines? Only set this to true if the submarine is intended to go inside the outpost."),
Editable]
131 [
Serialize(
"",
IsPropertySaveable.Yes, description:
"Identifier of the outpost generation parameters that should be used if this outpost has become critically irradiated."),
Editable]
134 [
Serialize(
false,
IsPropertySaveable.Yes, description:
"By default, sonar only shows the outline of the sub/outpost from the outside. Enable this if you want to see each structure individually."),
Editable]
167 private readonly List<ModuleCount> moduleCounts =
new List<ModuleCount>();
171 get {
return moduleCounts; }
174 private class NpcCollection : IReadOnlyList<HumanPrefab>
186 this.humanPrefab = humanPrefab;
187 this.FactionIdentifier = factionIdentifier;
192 this.setIdentifier = setIdentifier;
193 this.npcIdentifier = npcIdentifier;
194 this.FactionIdentifier = factionIdentifier;
197 public HumanPrefab HumanPrefab
198 => humanPrefab ?? NPCSet.Get(setIdentifier, npcIdentifier);
201 private readonly List<Entry> entries =
new List<Entry>();
203 public void Add(HumanPrefab humanPrefab,
Identifier factionIdentifier)
204 => entries.Add(
new Entry(humanPrefab, factionIdentifier));
208 => entries.Add(
new Entry(setIdentifier, npcIdentifier, factionIdentifier));
210 public IEnumerator<HumanPrefab> GetEnumerator()
212 foreach (var entry
in entries)
214 if (entry ==
null) {
continue; }
215 yield
return entry.HumanPrefab;
219 IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
221 public IEnumerable<HumanPrefab> GetByFaction(IEnumerable<FactionPrefab> factions)
223 foreach (var entry
in entries)
225 if (entry.FactionIdentifier ==
Identifier.Empty || factions.Any(f => f.Identifier == entry.FactionIdentifier))
227 yield
return entry.HumanPrefab;
232 public int Count => entries.Count;
234 public HumanPrefab
this[
int index] => entries[index].HumanPrefab;
237 private readonly ImmutableArray<NpcCollection> humanPrefabCollections;
241 private ImmutableHashSet<Identifier> StoreIdentifiers {
get;
set; }
243 #warning TODO: this shouldn't really accept any ContentFile, issue is that RuinConfigFile and OutpostConfigFile are separate derived classes
259 DebugConsole.ThrowError($
"Error in outpost generation parameters \"{Identifier}\". \"{levelTypeStr}\" is not a valid level type.", contentPackage: element.
ContentPackage);
265 var humanPrefabCollections =
new List<NpcCollection>();
266 foreach (var subElement
in element.Elements())
268 switch (subElement.Name.ToString().ToLowerInvariant())
274 var newCollection =
new NpcCollection();
275 foreach (var npcElement
in subElement.Elements())
281 newCollection.Add(from, npcElement.GetAttributeIdentifier(
"identifier",
Identifier.Empty), faction);
285 newCollection.Add(
new HumanPrefab(npcElement, file, npcSetIdentifier: from), faction);
288 humanPrefabCollections.Add(newCollection);
293 this.humanPrefabCollections = humanPrefabCollections.ToImmutableArray();
298 if (moduleFlag ==
Identifier.Empty || moduleFlag ==
"none") {
return int.MaxValue; }
299 return moduleCounts.FirstOrDefault(m => m.Identifier == moduleFlag)?.Count ?? 0;
304 if (moduleFlag ==
Identifier.Empty || moduleFlag ==
"none") {
return; }
307 moduleCounts.RemoveAll(m => m.Identifier == moduleFlag);
311 var moduleCount = moduleCounts.FirstOrDefault(m => m.Identifier == moduleFlag);
312 if (moduleCount ==
null)
314 moduleCounts.Add(
new ModuleCount(moduleFlag, count));
318 moduleCount.Count = count;
325 this.allowedLocationTypes.Clear();
326 foreach (
Identifier locationType
in allowedLocationTypes)
328 if (locationType ==
"any") {
continue; }
329 this.allowedLocationTypes.Add(locationType);
333 public IReadOnlyList<HumanPrefab>
GetHumanPrefabs(IEnumerable<FactionPrefab> factions, Rand.RandSync randSync)
335 if (!humanPrefabCollections.Any()) {
return Array.Empty<
HumanPrefab>(); }
337 var collection = humanPrefabCollections.GetRandom(randSync);
338 return collection.GetByFaction(factions).ToImmutableList();
343 foreach (var collection
in humanPrefabCollections)
345 foreach (var prefab
in collection)
347 if (prefab !=
null && prefab.CampaignInteractionType == interactionType)
358 if (StoreIdentifiers ==
null)
360 var storeIdentifiers =
new HashSet<Identifier>();
361 foreach (var collection
in humanPrefabCollections)
363 foreach (var prefab
in collection)
367 storeIdentifiers.Add(prefab.Identifier);
371 StoreIdentifiers = storeIdentifiers.ToImmutableHashSet();
373 return StoreIdentifiers;
Base class for content file types, which are loaded from filelist.xml via reflection....
string? GetAttributeString(string key, string? def)
Identifier[] GetAttributeIdentifierArray(Identifier[] def, params string[] keys)
ContentPackage? ContentPackage
ContentPath? GetAttributeContentPath(string key)
int GetAttributeInt(string key, int def)
XAttribute? GetAttribute(string name)
Identifier GetAttributeIdentifier(string key, string def)
ModuleCount(Identifier id, int count)
ModuleCount(ContentXElement element)
Identifier RequiredFaction
OutpostGenerationParams(ContentXElement element, ContentFile file)
IReadOnlyList< HumanPrefab > GetHumanPrefabs(IEnumerable< FactionPrefab > factions, Rand.RandSync randSync)
ContentPath OutpostFilePath
static readonly PrefabCollection< OutpostGenerationParams > OutpostParams
string ReplaceInRadiation
int ForceToEndLocationIndex
bool AlwaysShowStructuresOnSonar
bool CanHaveCampaignInteraction(CampaignMode.InteractionType interactionType)
bool AppendToReachTotalModuleCount
IReadOnlyList< ModuleCount > ModuleCounts
void SetModuleCount(Identifier moduleFlag, int count)
void SetAllowedLocationTypes(IEnumerable< Identifier > allowedLocationTypes)
LevelData.? LevelType LevelType
bool SpawnCrewInsideOutpost
ImmutableHashSet< Identifier > GetStoreIdentifiers()
int GetModuleCount(Identifier moduleFlag)
Dictionary< Identifier, SerializableProperty > SerializableProperties
IEnumerable< Identifier > AllowedLocationTypes
Identifiers of the location types this outpost can appear in. If empty, can appear in all types of lo...
readonly Identifier Identifier
Prefab that has a property serves as a deterministic hash of a prefab's identifier....
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)