2 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
5 using System.Globalization;
21 public readonly
string Seed;
52 public readonly Point
Size;
67 public readonly List<Identifier>
EventHistory =
new List<Identifier>();
74 public readonly Dictionary<EventSet, int>
FinishedEvents =
new Dictionary<EventSet, int>();
110 Seed = seed ??
throw new ArgumentException(
"Seed was null");
111 Biome = biome ??
throw new ArgumentException(
"Biome was null");
112 GenerationParams = generationParams ??
throw new ArgumentException(
"Level generation parameters were null");
116 sizeFactor = MathHelper.Clamp(sizeFactor, 0.0f, 1.0f);
117 int width = (int)MathHelper.Lerp(generationParams.
MinWidth, generationParams.
MaxWidth, sizeFactor);
126 public LevelData(XElement element,
float? forceDifficulty =
null,
bool clampDifficultyToBiome =
false)
128 Seed = element.GetAttributeString(
"seed",
"");
129 Size = element.GetAttributePoint(
"size",
new Point(1000));
130 Enum.TryParse(element.GetAttributeString(
"type",
"LocationConnection"), out
Type);
133 IsBeaconActive = element.GetAttributeBool(
"isbeaconactive",
false);
136 OriginallyHadHuntingGrounds = element.GetAttributeBool(
"originallyhadhuntinggrounds",
HasHuntingGrounds);
138 string generationParamsId = element.GetAttributeString(
"generationparams",
"");
142 DebugConsole.ThrowError($
"Error while loading a level. Could not find level generation params with the ID \"{generationParamsId}\".");
149 string biomeIdentifier = element.GetAttributeString(
"biome",
"");
150 Biome =
Biome.
Prefabs.FirstOrDefault(b => b.Identifier == biomeIdentifier || (!b.OldIdentifier.IsEmpty && b.OldIdentifier == biomeIdentifier));
153 DebugConsole.ThrowError($
"Error in level data: could not find the biome \"{biomeIdentifier}\".");
157 Difficulty = forceDifficulty ?? element.GetAttributeFloat(
"difficulty", 0.0f);
158 if (clampDifficultyToBiome)
163 string[] prefabNames = element.GetAttributeStringArray(
"eventhistory", Array.Empty<
string>());
166 string[] nonRepeatablePrefabNames = element.GetAttributeStringArray(
"nonrepeatableevents", Array.Empty<
string>());
170 if (element.GetChildElement(finishedEventsName) is { } finishedEventsElement)
172 foreach (var childElement
in finishedEventsElement.GetChildElements(finishedEventsName))
174 Identifier eventSetIdentifier = childElement.GetAttributeIdentifier(
"set", Identifier.Empty);
175 if (eventSetIdentifier.IsEmpty) {
continue; }
180 if (FindSetRecursive(prefab, eventSetIdentifier) is { } foundSet)
187 if (eventSet is
null) {
continue; }
188 int count = childElement.GetAttributeInt(
"count", 0);
189 if (count < 1) {
continue; }
193 static EventSet FindSetRecursive(
EventSet parentSet, Identifier setIdentifier)
195 foreach (var childSet
in parentSet.
ChildSets)
197 if (childSet.Identifier == setIdentifier)
201 if (FindSetRecursive(childSet, setIdentifier) is { } foundSet)
224 float sizeFactor = MathUtils.InverseLerp(
227 locationConnection.
Length);
269 if (
string.IsNullOrEmpty(seed))
271 seed = Rand.Range(0,
int.MaxValue, Rand.RandSync.ServerAndClient).ToString();
274 Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
276 LevelType type = generationParams ==
null ?
278 generationParams.
Type;
280 float selectedDifficulty = difficulty ?? Rand.Range(30.0f, 80.0f, Rand.RandSync.ServerAndClient);
284 Biome.
Prefabs.FirstOrDefault(b => generationParams?.AllowedBiomeIdentifiers.Contains(b.Identifier) ??
false) ??
290 Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient),
293 if (type ==
LevelType.LocationConnection)
295 float beaconRng = Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient);
296 levelData.HasBeaconStation = beaconRng < 0.5f;
297 levelData.IsBeaconActive = beaconRng > 0.25f;
318 .Where(p => p.LevelType ==
null || levelData.
Type == p.LevelType)
319 .Where(p => location ==
null || p.AllowedLocationTypes.Contains(location.
Type.
Identifier));
320 if (!suitableParams.Any())
323 .Where(p => p.LevelType ==
null || levelData.
Type == p.LevelType)
324 .Where(p => location ==
null || !p.AllowedLocationTypes.Any());
325 if (!suitableParams.Any())
327 DebugConsole.ThrowError($
"No suitable outpost generation parameters found for the location type \"{location.Type.Identifier}\". Selecting random parameters.");
331 return suitableParams;
334 public void Save(XElement parentElement)
336 var newElement =
new XElement(
"Level",
337 new XAttribute(
"seed",
Seed),
339 new XAttribute(
"type",
Type.ToString()),
340 new XAttribute(
"difficulty",
Difficulty.ToString(
"G", CultureInfo.InvariantCulture)),
341 new XAttribute(
"size", XMLExtensions.PointToString(
Size)),
356 new XAttribute(
"hashuntinggrounds",
true));
361 new XAttribute(
"originallyhadhuntinggrounds",
true));
368 newElement.Add(
new XAttribute(
"eventhistory",
string.Join(
',',
EventHistory)));
372 newElement.Add(
new XAttribute(
"nonrepeatableevents",
string.Join(
',',
NonRepeatableEvents)));
380 new XAttribute(
"set",
set.Identifier),
381 new XAttribute(
"count", count));
382 finishedEventsElement.Add(element);
384 newElement.Add(finishedEventsElement);
388 parentElement.Add(newElement);
static readonly PrefabCollection< Biome > Prefabs
readonly float MinDifficulty
float AdjustedMaxDifficulty
static readonly PrefabCollection< EventPrefab > Prefabs
Event sets are sets of random events that occur within a level (most commonly, monster spawns and scr...
static readonly PrefabCollection< EventSet > Prefabs
readonly ImmutableArray< EventSet > ChildSets
static GameSession?? GameSession
virtual IEnumerable< Mission > Missions
int? MinMainPathWidth
Determined during level generation based on the size of the submarine. Null if the level hasn't been ...
const float MaxHuntingGroundsProbability
Probability of hunting grounds appearing in 100% difficulty levels.
static LevelData CreateRandom(string seed="", float? difficulty=null, LevelGenerationParams generationParams=null, bool requireOutpost=false)
bool EventsExhausted
'Exhaustible' sets won't appear in the same level until after one world step (~10 min,...
SubmarineInfo ForceBeaconStation
float CrushDepth
The crush depth of a non-upgraded submarine in in-game coordinates. Note that this can be above the t...
OutpostGenerationParams ForceOutpostGenerationParams
LevelData(XElement element, float? forceDifficulty=null, bool clampDifficultyToBiome=false)
LevelGenerationParams GenerationParams
float RealWorldCrushDepth
The crush depth of a non-upgraded submarine in "real world units" (meters from the surface of Europa)...
readonly Dictionary< EventSet, int > FinishedEvents
readonly List< Identifier > EventHistory
Events that have previously triggered in this level. Used for making events the player hasn't seen ye...
readonly float Difficulty
LevelData(LocationConnection locationConnection)
Instantiates level data using the properties of the connection (seed, size, difficulty)
bool IsAllowedDifficulty(float minDifficulty, float maxDifficulty)
Inclusive (matching the min an max values is accepted).
readonly int InitialDepth
The depth at which the level starts at, in in-game coordinates. E.g. if this was set to 100 000 (= 10...
LevelData(string seed, float difficulty, float sizeFactor, LevelGenerationParams generationParams, Biome biome)
void Save(XElement parentElement)
void ReassignGenerationParams(string seed)
readonly List< Identifier > NonRepeatableEvents
Events that have already triggered in this level and can never trigger again. EventSet....
const float HuntingGroundsDifficultyThreshold
Minimum difficulty of the level before hunting grounds can appear.
static IEnumerable< OutpostGenerationParams > GetSuitableOutpostGenerationParams(Location location, LevelData levelData)
LevelData(Location location, Map map, float difficulty)
Instantiates level data using the properties of the location
bool OutpostGenerationParamsExist
static readonly PrefabCollection< LevelGenerationParams > LevelParams
static LevelGenerationParams GetRandom(string seed, LevelData.LevelType type, float difficulty, Identifier biomeId=default)
const float DefaultRealWorldCrushDepth
Identifier NameIdentifier
Mersenne Twister based random
float SmallLevelConnectionLength
static MapGenerationParams Instance
float LargeLevelConnectionLength
List< Location > Locations
virtual void AdjustLevelData(LevelData levelData)
static readonly PrefabCollection< OutpostGenerationParams > OutpostParams
readonly Identifier Identifier