Client LuaCsForBarotrauma
EventSet.cs
2 using System;
3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Linq;
6 using System.Xml.Linq;
7 
8 namespace Barotrauma
9 {
10 #if CLIENT
12  {
14 
15  public readonly Sprite Sprite;
16 
17  public EventSprite(ContentXElement element, RandomEventsFile file) : base(file, element.GetAttributeIdentifier("identifier", Identifier.Empty))
18  {
19  Sprite = new Sprite(element);
20  }
21 
22  public override void Dispose() { Sprite?.Remove(); }
23  }
24 #endif
25 
30  sealed class EventSet : Prefab
31  {
32  internal class EventDebugStats
33  {
34  public readonly EventSet RootSet;
35  public readonly Dictionary<Identifier, int> MonsterCounts = new Dictionary<Identifier, int>();
36  public float MonsterStrength;
37 
38  public EventDebugStats(EventSet rootSet)
39  {
40  RootSet = rootSet;
41  }
42  }
43 
45 #if CLIENT
46  public static Sprite GetEventSprite(string identifier)
47  {
48  if (string.IsNullOrWhiteSpace(identifier)) { return null; }
49 
50  if (EventSprite.Prefabs.TryGet(identifier.ToIdentifier(), out EventSprite sprite))
51  {
52  return sprite.Sprite;
53  }
54 
55 #if DEBUG || UNSTABLE
56  DebugConsole.ThrowError($"Could not find the event sprite \"{identifier}\"");
57 #else
58  DebugConsole.AddWarning($"Could not find the event sprite \"{identifier}\"");
59 #endif
60  return null;
61  }
62 #endif
63 
64  public static List<EventPrefab> GetAllEventPrefabs()
65  {
66  List<EventPrefab> eventPrefabs = EventPrefab.Prefabs.ToList();
67  foreach (var eventSet in Prefabs)
68  {
69  AddSetEventPrefabsToList(eventPrefabs, eventSet);
70  }
71  return eventPrefabs;
72  }
73 
74  public static void AddSetEventPrefabsToList(List<EventPrefab> list, EventSet set)
75  {
76  list.AddRange(set.EventPrefabs.SelectMany(ep => ep.EventPrefabs).Where(ep => !list.Contains(ep)));
77  foreach (var childSet in set.ChildSets) { AddSetEventPrefabsToList(list, childSet); }
78  }
79 
80  public static EventPrefab GetEventPrefab(Identifier identifier)
81  {
82  return GetAllEventPrefabs().Find(prefab => prefab.Identifier == identifier);
83  }
84 
88  public readonly bool IsCampaignSet;
89 
93  public readonly float MinLevelDifficulty;
97  public readonly float MaxLevelDifficulty;
98 
102  public readonly Identifier BiomeIdentifier;
103 
107  public readonly LevelData.LevelType LevelType;
108 
112  public readonly Identifier RequiredLayer;
113 
118 
122  public readonly ImmutableArray<Identifier> LocationTypeIdentifiers;
123 
127  public readonly Identifier Faction;
128 
132  public readonly bool ChooseRandom;
133 
137  private readonly int eventCount = 1;
138  public readonly int SubSetCount = 1;
139  private readonly Dictionary<Identifier, int> overrideEventCount = new Dictionary<Identifier, int>();
140 
144  public readonly bool Exhaustible;
145 
149  public readonly float MinDistanceTraveled;
150 
154  public readonly float MinMissionTime;
155 
156  //the events in this set are delayed if the current EventManager intensity is not between these values
157  public readonly float MinIntensity, MaxIntensity;
158 
162  public readonly bool AllowAtStart;
163 
167  public readonly bool IgnoreCoolDown;
168 
172  public readonly bool TriggerEventCooldown;
173 
177  public readonly bool IgnoreIntensity;
178 
182  public readonly bool PerRuin;
183 
187  public readonly bool PerCave;
188 
192  public readonly bool PerWreck;
193 
197  public readonly bool DisableInHuntingGrounds;
198 
202  public readonly bool OncePerLevel;
203 
207  public readonly bool DelayWhenCrewAway;
208 
214  public readonly bool Additive;
215 
221  public readonly bool SelectAlways;
222 
226  public readonly float DefaultCommonness;
227  public readonly ImmutableDictionary<Identifier, float> OverrideCommonness;
228 
232  public readonly float ResetTime;
233 
237  public readonly int ForceAtDiscoveredNr;
238 
242  public readonly int ForceAtVisitedNr;
243 
247  public readonly bool CampaignTutorialOnly;
248 
249  public readonly struct SubEventPrefab
250  {
251  public SubEventPrefab(Either<Identifier[], EventPrefab> prefabOrIdentifiers, float? commonness, float? probability, Identifier factionId)
252  {
253  PrefabOrIdentifier = prefabOrIdentifiers;
254  SelfCommonness = commonness;
255  SelfProbability = probability;
256  Faction = factionId;
257  }
258 
259  public readonly Either<Identifier[], EventPrefab> PrefabOrIdentifier;
260  public IEnumerable<EventPrefab> EventPrefabs
261  {
262  get
263  {
264  if (PrefabOrIdentifier.TryGet(out EventPrefab p))
265  {
266  yield return p;
267  }
268  else
269  {
270  foreach (var id in (Identifier[])PrefabOrIdentifier)
271  {
272  if (EventPrefab.Prefabs.TryGet(id, out EventPrefab prefab))
273  {
274  yield return prefab;
275  }
276  }
277  }
278  }
279  }
280 
281  public readonly float? SelfCommonness;
282  public float Commonness => SelfCommonness ?? EventPrefabs.MaxOrNull(p => p.Commonness) ?? 0.0f;
283 
284  public readonly float? SelfProbability;
285  public float Probability => SelfProbability ?? EventPrefabs.MaxOrNull(p => p.Probability) ?? 0.0f;
286 
287  public readonly Identifier Faction;
288 
289  public void Deconstruct(out IEnumerable<EventPrefab> eventPrefabs, out float commonness, out float probability)
290  {
291  eventPrefabs = EventPrefabs;
292  commonness = Commonness;
293  probability = Probability;
294  }
295 
296  public IEnumerable<Identifier> GetMissingIdentifiers()
297  {
298  if (PrefabOrIdentifier.TryCast<Identifier[]>(out var ids))
299  {
300  foreach (var id in ids)
301  {
302  if (!EventPrefab.Prefabs.ContainsKey(id))
303  {
304  yield return id;
305  }
306  }
307  }
308  }
309  }
310  public readonly ImmutableArray<SubEventPrefab> EventPrefabs;
311 
312  public readonly ImmutableArray<EventSet> ChildSets;
313 
314  private static Identifier DetermineIdentifier(EventSet parent, XElement element, RandomEventsFile file)
315  {
316  Identifier retVal = element.GetAttributeIdentifier("identifier", Identifier.Empty);
317 
318  if (retVal.IsEmpty)
319  {
320  if (parent is null)
321  {
322  if (file.ContentPackage is CorePackage)
323  {
324  throw new Exception($"Error in {file.Path}: All root EventSets in a core package must have identifiers");
325  }
326  else
327  {
328  DebugConsole.AddWarning($"{file.Path}: All root EventSets should have an identifier",
329  file.ContentPackage);
330  }
331  }
332 
333  XElement currElement = element;
334  string siblingIndices = "";
335  while (currElement.Parent != null)
336  {
337  int siblingIndex = currElement.ElementsBeforeSelf().Count();
338  siblingIndices = $"-{siblingIndex}{siblingIndices}";
339  if (parent != null) { break; }
340  currElement = currElement.Parent;
341  }
342 
343  retVal =
344  ((parent != null
345  ? parent.Identifier.Value
346  : $"{file.ContentPackage.Name}-{file.Path}")
347  + siblingIndices)
348  .ToIdentifier();
349  }
350  return retVal;
351  }
352 
353  public EventSet(ContentXElement element, RandomEventsFile file, EventSet parentSet = null)
354  : base(file, DetermineIdentifier(parentSet, element, file))
355  {
356  var eventPrefabs = new List<SubEventPrefab>();
357  var childSets = new List<EventSet>();
358  var overrideCommonness = new Dictionary<Identifier, float>();
359 
360  BiomeIdentifier = element.GetAttributeIdentifier("biome", Barotrauma.Identifier.Empty);
361  MinLevelDifficulty = element.GetAttributeFloat("minleveldifficulty", 0);
362  MaxLevelDifficulty = Math.Max(element.GetAttributeFloat("maxleveldifficulty", 100), MinLevelDifficulty);
363 
364  Additive = element.GetAttributeBool(nameof(Additive), false);
365  SelectAlways = element.GetAttributeBool(nameof(SelectAlways), false);
366 
367  string levelTypeStr = element.GetAttributeString("leveltype", parentSet?.LevelType.ToString() ?? "LocationConnection");
368  if (!Enum.TryParse(levelTypeStr, true, out LevelType))
369  {
370  DebugConsole.ThrowError($"Error in event set \"{Identifier}\". \"{levelTypeStr}\" is not a valid level type.",
371  contentPackage: element.ContentPackage);
372  }
373 
374  Faction = element.GetAttributeIdentifier(nameof(Faction), Identifier.Empty);
375 
376  Identifier[] locationTypeStr = element.GetAttributeIdentifierArray("locationtype", null);
377  if (locationTypeStr != null)
378  {
379  LocationTypeIdentifiers = locationTypeStr.ToImmutableArray();
380  //if (LocationType.List.Any()) { CheckLocationTypeErrors(); } //TODO: perform validation elsewhere
381  }
382 
383  MinIntensity = element.GetAttributeFloat("minintensity", 0.0f);
384  MaxIntensity = Math.Max(element.GetAttributeFloat("maxintensity", 100.0f), MinIntensity);
385 
386  ChooseRandom = element.GetAttributeBool("chooserandom", false);
387  eventCount = element.GetAttributeInt("eventcount", 1);
388  SubSetCount = element.GetAttributeInt("setcount", 1);
389  Exhaustible = element.GetAttributeBool("exhaustible", parentSet?.Exhaustible ?? false);
390  MinDistanceTraveled = element.GetAttributeFloat("mindistancetraveled", 0.0f);
391  MinMissionTime = element.GetAttributeFloat("minmissiontime", 0.0f);
392 
393  AllowAtStart = element.GetAttributeBool("allowatstart", parentSet?.AllowAtStart ?? false);
394  PerRuin = element.GetAttributeBool("perruin", false);
395  PerCave = element.GetAttributeBool("percave", false);
396  PerWreck = element.GetAttributeBool("perwreck", false);
397  DisableInHuntingGrounds = element.GetAttributeBool("disableinhuntinggrounds", parentSet?.DisableInHuntingGrounds ?? false);
398  IgnoreCoolDown = element.GetAttributeBool("ignorecooldown", parentSet?.IgnoreCoolDown ?? (PerRuin || PerCave || PerWreck));
399  IgnoreIntensity = element.GetAttributeBool("ignoreintensity", parentSet?.IgnoreIntensity ?? false);
400  DelayWhenCrewAway = element.GetAttributeBool("delaywhencrewaway", parentSet?.DelayWhenCrewAway ?? (!PerRuin && !PerCave && !PerWreck));
401  OncePerLevel = element.GetAttributeBool("onceperlevel", element.GetAttributeBool("onceperoutpost", parentSet?.OncePerLevel ?? false));
402  TriggerEventCooldown = element.GetAttributeBool("triggereventcooldown", parentSet?.TriggerEventCooldown ?? true);
403  IsCampaignSet = element.GetAttributeBool("campaign", LevelType == LevelData.LevelType.Outpost || (parentSet?.IsCampaignSet ?? false));
404  ResetTime = element.GetAttributeFloat(nameof(ResetTime), parentSet?.ResetTime ?? 0);
405  CampaignTutorialOnly = element.GetAttributeBool(nameof(CampaignTutorialOnly), parentSet?.CampaignTutorialOnly ?? false);
406 
409 
411  ForceAtVisitedNr = element.GetAttributeInt(nameof(ForceAtVisitedNr), -1);
412  if (ForceAtDiscoveredNr >= 0 && ForceAtVisitedNr >= 0)
413  {
414  DebugConsole.ThrowError($"Error with event set \"{Identifier}\" - both ForceAtDiscoveredNr and ForceAtVisitedNr are defined, this could lead to unexpected behavior",
415  contentPackage: element.ContentPackage);
416  }
417 
418  DefaultCommonness = element.GetAttributeFloat("commonness", 1.0f);
419  foreach (var subElement in element.Elements())
420  {
421  switch (subElement.Name.ToString().ToLowerInvariant())
422  {
423  case "commonness":
424  DefaultCommonness = subElement.GetAttributeFloat("commonness", DefaultCommonness);
425  foreach (XElement overrideElement in subElement.Elements())
426  {
427  if (overrideElement.NameAsIdentifier() == "override")
428  {
429  Identifier levelType = overrideElement.GetAttributeIdentifier("leveltype", "");
430  if (!overrideCommonness.ContainsKey(levelType))
431  {
432  overrideCommonness.Add(levelType, overrideElement.GetAttributeFloat("commonness", 0.0f));
433  }
434  }
435  }
436  break;
437  case "eventset":
438  childSets.Add(new EventSet(subElement, file, this));
439  break;
440  case "overrideeventcount":
441  Identifier locationType = subElement.GetAttributeIdentifier("locationtype", "");
442  if (!overrideEventCount.ContainsKey(locationType))
443  {
444  overrideEventCount.Add(locationType, subElement.GetAttributeInt("eventcount", eventCount));
445  }
446  break;
447  default:
448  //an element with just an identifier = reference to an event prefab
449  if (!subElement.HasElements && subElement.Attributes().First().Name.ToString().Equals("identifier", StringComparison.OrdinalIgnoreCase))
450  {
451  Identifier[] identifiers = subElement.GetAttributeIdentifierArray("identifier", Array.Empty<Identifier>());
452  float commonness = subElement.GetAttributeFloat("commonness", -1f);
453  float probability = subElement.GetAttributeFloat("probability", -1f);
454  Identifier factionId = subElement.GetAttributeIdentifier(nameof(Faction), Identifier.Empty);
455  eventPrefabs.Add(new SubEventPrefab(
456  identifiers,
457  commonness >= 0f ? commonness : (float?)null,
458  probability >= 0f ? probability : (float?)null,
459  factionId));
460  }
461  else
462  {
463  var prefab = new EventPrefab(subElement, file, $"{Identifier}-{subElement.ElementsBeforeSelf().Count()}".ToIdentifier());
464  eventPrefabs.Add(new SubEventPrefab(prefab, prefab.Commonness, prefab.Probability, prefab.Faction));
465  }
466  break;
467  }
468  }
469 
470  EventPrefabs = eventPrefabs.ToImmutableArray();
471  ChildSets = childSets.ToImmutableArray();
472  OverrideCommonness = overrideCommonness.ToImmutableDictionary();
473 
474  if ((PerRuin && PerCave) || (PerWreck && PerCave) || (PerRuin && PerWreck))
475  {
476  DebugConsole.AddWarning($"Error in event set \"{Identifier}\". Only one of the settings {nameof(PerRuin)}, {nameof(PerCave)} or {nameof(PerWreck)} can be enabled at the time.");
477  }
478  }
479 
481  {
482  if (LocationTypeIdentifiers == null) { return; }
483  foreach (Identifier locationTypeId in LocationTypeIdentifiers)
484  {
485  if (!LocationType.Prefabs.ContainsKey(locationTypeId))
486  {
487  DebugConsole.ThrowError($"Error in event set \"{Identifier}\". Location type \"{locationTypeId}\" not found.");
488  }
489  }
490  }
491 
492  public float GetCommonness(Level level)
493  {
494  if (level.GenerationParams?.Identifier is { IsEmpty: false } &&
495  OverrideCommonness.TryGetValue(level.GenerationParams.Identifier, out float generationParamsCommonness))
496  {
497  return generationParamsCommonness;
498  }
499  else if (level.StartOutpost?.Info.OutpostGenerationParams?.Identifier is { IsEmpty: false } &&
500  OverrideCommonness.TryGetValue(level.StartOutpost.Info.OutpostGenerationParams.Identifier, out float startOutpostParamsCommonness))
501  {
502  return startOutpostParamsCommonness;
503  }
504  else if (level.EndOutpost?.Info.OutpostGenerationParams?.Identifier is { IsEmpty: false } &&
505  OverrideCommonness.TryGetValue(level.EndOutpost.Info.OutpostGenerationParams.Identifier, out float endOutpostParamsCommonness))
506  {
507  return endOutpostParamsCommonness;
508  }
509  return DefaultCommonness;
510  }
511 
512  public int GetEventCount(Level level)
513  {
514  int finishedEventCount = 0;
515  if (level is not null)
516  {
517  level.LevelData.FinishedEvents.TryGetValue(this, out finishedEventCount);
518  }
519  if (level.StartLocation == null || !overrideEventCount.TryGetValue(level.StartLocation.Type.Identifier, out int count))
520  {
521  return eventCount - finishedEventCount;
522  }
523  return count - finishedEventCount;
524  }
525 
526  public static List<string> GetDebugStatistics(int simulatedRoundCount = 100, Func<MonsterEvent, bool> filter = null, bool fullLog = false)
527  {
528  List<string> debugLines = new List<string>();
529 
530  foreach (var eventSet in Prefabs)
531  {
532  List<EventDebugStats> stats = new List<EventDebugStats>();
533  for (int i = 0; i < simulatedRoundCount; i++)
534  {
535  var newStats = new EventDebugStats(eventSet);
536  CheckEventSet(newStats, eventSet, filter);
537  stats.Add(newStats);
538  }
539  debugLines.Add($"Event stats ({eventSet.Identifier}): ");
540  LogEventStats(stats, debugLines, fullLog);
541  }
542 
543  return debugLines;
544 
545  static void CheckEventSet(EventDebugStats stats, EventSet thisSet, Func<MonsterEvent, bool> filter = null)
546  {
547  if (thisSet.ChooseRandom)
548  {
549  var unusedEvents = thisSet.EventPrefabs.ToList();
550  if (unusedEvents.Any())
551  {
552  for (int i = 0; i < thisSet.eventCount; i++)
553  {
554  var eventPrefab = ToolBox.SelectWeightedRandom(unusedEvents, unusedEvents.Select(e => e.Commonness).ToList(), Rand.RandSync.Unsynced);
555  if (eventPrefab.EventPrefabs.Any(p => p != null))
556  {
557  AddEvents(stats, eventPrefab.EventPrefabs, filter);
558  unusedEvents.Remove(eventPrefab);
559  }
560  }
561  }
562  List<float> values = thisSet.ChildSets
563  .SelectMany(s => s.DefaultCommonness.ToEnumerable().Concat(s.OverrideCommonness.Values))
564  .ToList();
565  EventSet childSet = ToolBox.SelectWeightedRandom(thisSet.ChildSets, values, Rand.RandSync.Unsynced);
566  if (childSet != null)
567  {
568  CheckEventSet(stats, childSet, filter);
569  }
570  }
571  else
572  {
573  foreach (var eventPrefab in thisSet.EventPrefabs)
574  {
575  AddEvents(stats, eventPrefab.EventPrefabs, filter);
576  }
577  foreach (var childSet in thisSet.ChildSets)
578  {
579  CheckEventSet(stats, childSet, filter);
580  }
581  }
582  }
583 
584  static void AddEvents(EventDebugStats stats, IEnumerable<EventPrefab> eventPrefabs, Func<MonsterEvent, bool> filter = null)
585  => eventPrefabs.ForEach(p => AddEvent(stats, p, filter));
586 
587  static void AddEvent(EventDebugStats stats, EventPrefab eventPrefab, Func<MonsterEvent, bool> filter = null)
588  {
589  if (eventPrefab.EventType == typeof(MonsterEvent) &&
590  eventPrefab.TryCreateInstance(GameMain.GameSession?.EventManager?.RandomSeed ?? 0, out MonsterEvent monsterEvent))
591  {
592  if (filter != null && !filter(monsterEvent)) { return; }
593  float spawnProbability = monsterEvent.Prefab?.Probability ?? 0.0f;
594  if (Rand.Value() > spawnProbability) { return; }
595  int count = Rand.Range(monsterEvent.MinAmount, monsterEvent.MaxAmount + 1);
596  if (count <= 0) { return; }
597  Identifier character = monsterEvent.SpeciesName;
598  if (stats.MonsterCounts.TryGetValue(character, out int currentCount))
599  {
600  if (currentCount >= monsterEvent.MaxAmountPerLevel) { return; }
601  }
602  else
603  {
604  stats.MonsterCounts[character] = 0;
605  }
606  stats.MonsterCounts[character] += count;
607 
608  var aiElement = CharacterPrefab.FindBySpeciesName(character)?.ConfigElement?.GetChildElement("ai");
609  if (aiElement != null)
610  {
611  stats.MonsterStrength += aiElement.GetAttributeFloat("combatstrength", 0) * count;
612  }
613  }
614  }
615 
616  static void LogEventStats(List<EventDebugStats> stats, List<string> debugLines, bool fullLog)
617  {
618  if (stats.Count == 0 || stats.All(s => s.MonsterCounts.Values.Sum() == 0))
619  {
620  debugLines.Add(" No monster spawns");
621  debugLines.Add($" ");
622  }
623  else
624  {
625  var allMonsters = new Dictionary<Identifier, int>();
626  foreach (var stat in stats)
627  {
628  foreach (var monster in stat.MonsterCounts)
629  {
630  if (!allMonsters.TryAdd(monster.Key, monster.Value))
631  {
632  allMonsters[monster.Key] += monster.Value;
633  }
634  }
635  }
636  allMonsters = allMonsters.OrderBy(m => m.Key).ToDictionary(m => m.Key, m => m.Value);
637  stats.Sort((s1, s2) => s1.MonsterCounts.Values.Sum().CompareTo(s2.MonsterCounts.Values.Sum()));
638  debugLines.Add($" Average monster count: {StringFormatter.FormatZeroDecimal((float)stats.Average(s => s.MonsterCounts.Values.Sum()))} (Min: {stats.First().MonsterCounts.Values.Sum()}, Max: {stats.Last().MonsterCounts.Values.Sum()})");
639  debugLines.Add($" {LogMonsterCounts(allMonsters, divider: stats.Count)}");
640  if (fullLog)
641  {
642  debugLines.Add($" All samples:");
643  stats.ForEach(s => debugLines.Add($" {LogMonsterCounts(s.MonsterCounts)}"));
644  }
645  stats.Sort((s1, s2) => s1.MonsterStrength.CompareTo(s2.MonsterStrength));
646  debugLines.Add($" Average monster strength: {StringFormatter.FormatZeroDecimal(stats.Average(s => s.MonsterStrength))} (Min: {StringFormatter.FormatZeroDecimal(stats.First().MonsterStrength)}, Max: {StringFormatter.FormatZeroDecimal(stats.Last().MonsterStrength)})");
647  debugLines.Add($" ");
648  }
649  }
650 
651  static string LogMonsterCounts(Dictionary<Identifier, int> stats, float divider = 0)
652  {
653  if (divider > 0)
654  {
655  return string.Join("\n ", stats.Select(mc => mc.Key + " x " + (mc.Value / divider).FormatSingleDecimal()));
656  }
657  else
658  {
659  return string.Join(", ", stats.Select(mc => mc.Key + " x " + mc.Value));
660  }
661  }
662  }
663 
664  public override string ToString()
665  {
666  return $"{base.ToString()} ({Identifier.Value})";
667  }
668 
669  public override void Dispose() { }
670  }
671 }
static CharacterPrefab FindBySpeciesName(Identifier speciesName)
ContentXElement ConfigElement
readonly ContentPackage ContentPackage
Definition: ContentFile.cs:136
string? GetAttributeString(string key, string? def)
Identifier[] GetAttributeIdentifierArray(Identifier[] def, params string[] keys)
float GetAttributeFloat(string key, float def)
ContentPackage? ContentPackage
ContentXElement? GetChildElement(string name)
bool GetAttributeBool(string key, bool def)
int GetAttributeInt(string key, int def)
Identifier GetAttributeIdentifier(string key, string def)
readonly Type EventType
Definition: EventPrefab.cs:14
static readonly PrefabCollection< EventPrefab > Prefabs
Definition: EventPrefab.cs:11
Event sets are sets of random events that occur within a level (most commonly, monster spawns and scr...
Definition: EventSet.cs:31
static EventPrefab GetEventPrefab(Identifier identifier)
Definition: EventSet.cs:80
static Sprite GetEventSprite(string identifier)
Definition: EventSet.cs:46
readonly bool PerWreck
The set is applied once per each wreck in the level. Can be used to ensure there's a consistent amoun...
Definition: EventSet.cs:192
readonly bool DisableInHuntingGrounds
If enabled, this event will not be applied if the level contains hunting grounds.
Definition: EventSet.cs:197
readonly bool ChooseRandom
If set, one event, or a sub event set, is chosen randomly from this set.
Definition: EventSet.cs:132
readonly bool AllowAtStart
If the event is not allowed at start, it won't become active until the submarine has moved at least 5...
Definition: EventSet.cs:162
EventSet(ContentXElement element, RandomEventsFile file, EventSet parentSet=null)
Definition: EventSet.cs:353
readonly bool TriggerEventCooldown
Should this event set trigger the event cooldown (during which no new events are created) when it bec...
Definition: EventSet.cs:172
readonly bool PerCave
The set is applied once per each cave in the level. Can be used to ensure there's a consistent amount...
Definition: EventSet.cs:187
readonly bool PerRuin
The set is applied once per each ruin in the level. Can be used to ensure there's a consistent amount...
Definition: EventSet.cs:182
readonly ImmutableArray< Identifier > LocationTypeIdentifiers
If set, the event set can only be chosen in locations of this type.
Definition: EventSet.cs:122
readonly bool IgnoreIntensity
Normally events can only trigger if the intensity of the situation is low enough (e....
Definition: EventSet.cs:177
readonly LevelData.LevelType LevelType
If set, the event set can only be chosen in this type of level (outpost level or a connection between...
Definition: EventSet.cs:107
readonly ImmutableArray< SubEventPrefab > EventPrefabs
Definition: EventSet.cs:310
readonly float ResetTime
If set, the event set can trigger again after this amount of seconds has passed since it last trigger...
Definition: EventSet.cs:232
readonly int ForceAtVisitedNr
Used to force an event set based on how many other outposts have been visited before this (used for c...
Definition: EventSet.cs:242
void CheckLocationTypeErrors()
Definition: EventSet.cs:480
int GetEventCount(Level level)
Definition: EventSet.cs:512
readonly float MinLevelDifficulty
The difficulty of the current level must be equal to or higher than this for this set to be chosen.
Definition: EventSet.cs:93
static readonly PrefabCollection< EventSet > Prefabs
Definition: EventSet.cs:44
readonly ImmutableArray< EventSet > ChildSets
Definition: EventSet.cs:312
readonly float MinIntensity
Definition: EventSet.cs:157
float GetCommonness(Level level)
Definition: EventSet.cs:492
readonly float MinMissionTime
The event set won't become active until the round has lasted at least this many seconds.
Definition: EventSet.cs:154
readonly float DefaultCommonness
The commonness of the event set (i.e. how likely it is for this specific set to be chosen).
Definition: EventSet.cs:226
readonly float MinDistanceTraveled
The event set won't become active until the submarine has travelled at least this far....
Definition: EventSet.cs:149
readonly bool Additive
Additive sets are important to be aware of when creating custom event sets! If an additive set gets c...
Definition: EventSet.cs:214
readonly int ForceAtDiscoveredNr
Used to force an event set based on how many other locations have been discovered before this (used f...
Definition: EventSet.cs:237
readonly Identifier RequiredSpawnPointTag
If set, this spawn point tag must be present somewhere in the level.
Definition: EventSet.cs:117
readonly ImmutableDictionary< Identifier, float > OverrideCommonness
Definition: EventSet.cs:227
readonly float MaxLevelDifficulty
The difficulty of the current level must be equal to or less than this for this set to be chosen.
Definition: EventSet.cs:97
readonly bool Exhaustible
'Exhaustible' sets won't appear in the same level until after one world step (~10 min,...
Definition: EventSet.cs:144
readonly Identifier RequiredLayer
If set, this layer must be present somewhere in the level.
Definition: EventSet.cs:112
readonly bool IsCampaignSet
If enabled, this set can only be chosen in the campaign mode.
Definition: EventSet.cs:88
static List< EventPrefab > GetAllEventPrefabs()
Definition: EventSet.cs:64
readonly bool CampaignTutorialOnly
If enabled, this set can only occur when the campaign tutorial is enabled (generally used for the tut...
Definition: EventSet.cs:247
static List< string > GetDebugStatistics(int simulatedRoundCount=100, Func< MonsterEvent, bool > filter=null, bool fullLog=false)
Definition: EventSet.cs:526
readonly int SubSetCount
Definition: EventSet.cs:138
readonly bool OncePerLevel
If enabled, events from this set can only occur once in the level.
Definition: EventSet.cs:202
readonly bool DelayWhenCrewAway
Should the event set be delayed if at least half of the crew is away from the submarine?...
Definition: EventSet.cs:207
readonly bool SelectAlways
This will force the game to always choose this event set if it's suitable for the current level....
Definition: EventSet.cs:221
override void Dispose()
Definition: EventSet.cs:669
static void AddSetEventPrefabsToList(List< EventPrefab > list, EventSet set)
Definition: EventSet.cs:74
readonly bool IgnoreCoolDown
Normally an event (such as a monster spawn) triggers a cooldown during which no new events are create...
Definition: EventSet.cs:167
override string ToString()
Definition: EventSet.cs:664
readonly Identifier BiomeIdentifier
If set, the event set can only be chosen in this biome.
Definition: EventSet.cs:102
readonly Identifier Faction
If set, the event set can only be chosen in locations that belong to this faction.
Definition: EventSet.cs:127
readonly Sprite Sprite
Definition: EventSet.cs:15
override void Dispose()
Definition: EventSet.cs:22
EventSprite(ContentXElement element, RandomEventsFile file)
Definition: EventSet.cs:17
static readonly PrefabCollection< EventSprite > Prefabs
Definition: EventSet.cs:13
static GameSession?? GameSession
Definition: GameMain.cs:88
readonly Dictionary< EventSet, int > FinishedEvents
Definition: LevelData.cs:88
LocationType Type
Definition: Location.cs:94
static readonly PrefabCollection< LocationType > Prefabs
Definition: LocationType.cs:15
readonly Identifier Identifier
Definition: Prefab.cs:34
Sprite(ContentXElement element, string path="", string file="", bool lazyLoad=false, float sourceRectScale=1)
IEnumerable< Identifier > GetMissingIdentifiers()
Definition: EventSet.cs:296
readonly Identifier Faction
Definition: EventSet.cs:287
SubEventPrefab(Either< Identifier[], EventPrefab > prefabOrIdentifiers, float? commonness, float? probability, Identifier factionId)
Definition: EventSet.cs:251
IEnumerable< EventPrefab > EventPrefabs
Definition: EventSet.cs:261
void Deconstruct(out IEnumerable< EventPrefab > eventPrefabs, out float commonness, out float probability)
Definition: EventSet.cs:289
readonly Either< Identifier[], EventPrefab > PrefabOrIdentifier
Definition: EventSet.cs:259