2 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
5 using System.Globalization;
22 public readonly
string Seed;
66 public readonly Point
Size;
81 public readonly List<Identifier>
EventHistory =
new List<Identifier>();
88 public readonly Dictionary<EventSet, int>
FinishedEvents =
new Dictionary<EventSet, int>();
124 Seed = seed ??
throw new ArgumentException(
"Seed was null");
125 Biome = biome ??
throw new ArgumentException(
"Biome was null");
126 GenerationParams = generationParams ??
throw new ArgumentException(
"Level generation parameters were null");
130 sizeFactor = MathHelper.Clamp(sizeFactor, 0.0f, 1.0f);
131 int width = (int)MathHelper.Lerp(generationParams.
MinWidth, generationParams.
MaxWidth, sizeFactor);
140 public LevelData(XElement element,
float? forceDifficulty =
null,
bool clampDifficultyToBiome =
false)
142 Seed = element.GetAttributeString(
"seed",
"");
143 Size = element.GetAttributePoint(
"size",
new Point(1000));
144 Enum.TryParse(element.GetAttributeString(
"type",
"LocationConnection"), out
Type);
147 IsBeaconActive = element.GetAttributeBool(
"isbeaconactive",
false);
150 OriginallyHadHuntingGrounds = element.GetAttributeBool(
"originallyhadhuntinggrounds",
HasHuntingGrounds);
152 string generationParamsId = element.GetAttributeString(
"generationparams",
"");
156 DebugConsole.ThrowError($
"Error while loading a level. Could not find level generation params with the ID \"{generationParamsId}\".");
163 string biomeIdentifier = element.GetAttributeString(
"biome",
"");
164 Biome =
Biome.
Prefabs.FirstOrDefault(b => b.Identifier == biomeIdentifier || (!b.OldIdentifier.IsEmpty && b.OldIdentifier == biomeIdentifier));
167 DebugConsole.ThrowError($
"Error in level data: could not find the biome \"{biomeIdentifier}\".");
171 Difficulty = forceDifficulty ?? element.GetAttributeFloat(
"difficulty", 0.0f);
172 if (clampDifficultyToBiome)
177 string[] prefabNames = element.GetAttributeStringArray(
"eventhistory", Array.Empty<
string>());
180 string[] nonRepeatablePrefabNames = element.GetAttributeStringArray(
"nonrepeatableevents", Array.Empty<
string>());
184 if (element.GetChildElement(finishedEventsName) is { } finishedEventsElement)
186 foreach (var childElement
in finishedEventsElement.GetChildElements(finishedEventsName))
188 Identifier eventSetIdentifier = childElement.GetAttributeIdentifier(
"set", Identifier.Empty);
189 if (eventSetIdentifier.IsEmpty) {
continue; }
194 if (FindSetRecursive(prefab, eventSetIdentifier) is { } foundSet)
201 if (eventSet is
null) {
continue; }
202 int count = childElement.GetAttributeInt(
"count", 0);
203 if (count < 1) {
continue; }
207 static EventSet FindSetRecursive(
EventSet parentSet, Identifier setIdentifier)
209 foreach (var childSet
in parentSet.
ChildSets)
211 if (childSet.Identifier == setIdentifier)
215 if (FindSetRecursive(childSet, setIdentifier) is { } foundSet)
239 float sizeFactor = MathUtils.InverseLerp(
242 locationConnection.
Length);
284 if (
string.IsNullOrEmpty(seed))
286 seed = Rand.Range(0,
int.MaxValue, Rand.RandSync.ServerAndClient).ToString();
289 Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
296 float selectedDifficulty = difficulty ?? Rand.Range(30.0f, 80.0f, Rand.RandSync.ServerAndClient);
299 if (!biomeId.IsEmpty && biomeId !=
"Random")
306 Biome.
Prefabs.FirstOrDefault(b => generationParams?.AllowedBiomeIdentifiers.Contains(b.Identifier) ??
false) ??
312 Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient),
315 if (type ==
LevelType.LocationConnection)
317 float beaconRng = Rand.Range(0.0f, 1.0f, Rand.RandSync.ServerAndClient);
318 levelData.HasBeaconStation = beaconRng < 0.5f;
319 levelData.IsBeaconActive = beaconRng > 0.25f;
340 .Where(p => p.LevelType ==
null || levelData.
Type == p.LevelType)
341 .Where(p => location ==
null || p.AllowedLocationTypes.Contains(location.
Type.
Identifier));
342 if (!suitableParams.Any())
345 .Where(p => p.LevelType ==
null || levelData.
Type == p.LevelType)
346 .Where(p => location ==
null || !p.AllowedLocationTypes.Any());
347 if (!suitableParams.Any())
349 DebugConsole.ThrowError($
"No suitable outpost generation parameters found for the location type \"{location.Type.Identifier}\". Selecting random parameters.");
353 return suitableParams;
356 public void Save(XElement parentElement)
358 var newElement =
new XElement(
"Level",
359 new XAttribute(
"seed",
Seed),
361 new XAttribute(
"type",
Type.ToString()),
362 new XAttribute(
"difficulty",
Difficulty.ToString(
"G", CultureInfo.InvariantCulture)),
363 new XAttribute(
"size", XMLExtensions.PointToString(
Size)),
378 new XAttribute(
"hashuntinggrounds",
true));
383 new XAttribute(
"originallyhadhuntinggrounds",
true));
390 newElement.Add(
new XAttribute(
"eventhistory",
string.Join(
',',
EventHistory)));
394 newElement.Add(
new XAttribute(
"nonrepeatableevents",
string.Join(
',',
NonRepeatableEvents)));
402 new XAttribute(
"set",
set.Identifier),
403 new XAttribute(
"count", count));
404 finishedEventsElement.Add(element);
406 newElement.Add(finishedEventsElement);
410 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.
bool EventsExhausted
'Exhaustible' sets won't appear in the same level until after one world step (~10 min,...
SubmarineInfo ForceBeaconStation
static LevelData CreateRandom(string seed="", float? difficulty=null, LevelGenerationParams generationParams=null, Identifier biomeId=default, bool requireOutpost=false, bool pvpOnly=false)
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)
static SubmarineInfo ConsoleForceWreck
LevelGenerationParams GenerationParams
float RealWorldCrushDepth
The crush depth of a non-upgraded submarine in "real world units" (meters from the surface of Europa)...
RuinGenerationParams ForceRuinGenerationParams
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)
static ThalamusSpawn ForceThalamus
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 SubmarineInfo ConsoleForceBeaconStation
static readonly PrefabCollection< LevelGenerationParams > LevelParams
static LevelGenerationParams GetRandom(string seed, LevelData.LevelType type, float difficulty, Identifier biomeId=default, bool pvpOnly=false, bool biomeTransition=false)
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