Unstable 0.17.0.0

This commit is contained in:
Markus Isberg
2022-02-26 02:43:01 +09:00
parent a83f375681
commit 3974067915
913 changed files with 32472 additions and 32364 deletions
@@ -16,10 +16,10 @@ namespace Barotrauma
{
public readonly ushort OriginalID;
public readonly ushort ModuleIndex;
public readonly string Identifier;
public readonly Identifier Identifier;
public readonly int OriginalContainerIndex;
public TakenItem(string identifier, UInt16 originalID, int originalContainerIndex, ushort moduleIndex)
public TakenItem(Identifier identifier, UInt16 originalID, int originalContainerIndex, ushort moduleIndex)
{
OriginalID = originalID;
OriginalContainerIndex = originalContainerIndex;
@@ -34,7 +34,7 @@ namespace Barotrauma
OriginalContainerIndex = item.OriginalContainerIndex;
OriginalID = item.ID;
ModuleIndex = (ushort) item.OriginalModuleIndex;
Identifier = item.prefab.Identifier;
Identifier = ((MapEntity)item).Prefab.Identifier;
}
public bool IsEqual(TakenItem obj)
@@ -46,11 +46,11 @@ namespace Barotrauma
{
if (item.OriginalContainerIndex != Entity.NullEntityID)
{
return item.OriginalContainerIndex == OriginalContainerIndex && item.OriginalModuleIndex == ModuleIndex && item.prefab.Identifier == Identifier;
return item.OriginalContainerIndex == OriginalContainerIndex && item.OriginalModuleIndex == ModuleIndex && ((MapEntity)item).Prefab.Identifier == Identifier;
}
else
{
return item.ID == OriginalID && item.OriginalModuleIndex == ModuleIndex && item.prefab.Identifier == Identifier;
return item.ID == OriginalID && item.OriginalModuleIndex == ModuleIndex && ((MapEntity)item).Prefab.Identifier == Identifier;
}
}
}
@@ -252,7 +252,7 @@ namespace Barotrauma
return $"Location ({Name ?? "null"})";
}
public Location(Vector2 mapPosition, int? zone, Random rand, bool requireOutpost = false, LocationType? forceLocationType = null, IEnumerable<Location> existingLocations = null)
public Location(Vector2 mapPosition, int? zone, Random rand, bool requireOutpost = false, LocationType forceLocationType = null, IEnumerable<Location> existingLocations = null)
{
Type = OriginalType = forceLocationType ?? LocationType.Random(rand, zone, requireOutpost);
Name = RandomName(Type, rand, existingLocations);
@@ -263,22 +263,21 @@ namespace Barotrauma
public Location(XElement element)
{
string locationType = element.GetAttributeString("type", "");
Type = LocationType.List.Find(lt => lt.Identifier.Equals(locationType, StringComparison.OrdinalIgnoreCase));
Identifier locationType = element.GetAttributeIdentifier("type", "");
Type = LocationType.Prefabs[locationType];
bool typeNotFound = false;
if (Type == null)
{
//turn lairs into abandoned outposts
if (locationType.Equals("lair", StringComparison.OrdinalIgnoreCase))
if (locationType == "lair")
{
Type ??= LocationType.List.Find(lt => lt.Identifier.Equals("Abandoned", StringComparison.OrdinalIgnoreCase));
Type ??= LocationType.Prefabs["Abandoned"];
addInitialMissionsForType = Type;
}
if (Type == null)
{
DebugConsole.AddWarning($"Could not find location type \"{locationType}\". Using location type \"None\" instead.");
Type ??= LocationType.List.Find(lt => lt.Identifier.Equals("None", StringComparison.OrdinalIgnoreCase));
Type ??= LocationType.List.First();
Type ??= LocationType.Prefabs["None"] ?? LocationType.Prefabs.First();
}
if (Type != null)
{
@@ -287,8 +286,8 @@ namespace Barotrauma
typeNotFound = true;
}
string originalLocationType = element.GetAttributeString("originaltype", locationType);
OriginalType = LocationType.List.Find(lt => lt.Identifier.Equals(locationType, StringComparison.OrdinalIgnoreCase));
Identifier originalLocationType = element.GetAttributeIdentifier("originaltype", locationType);
OriginalType = LocationType.Prefabs[locationType];
baseName = element.GetAttributeString("basename", "");
Name = element.GetAttributeString("name", "");
@@ -312,7 +311,7 @@ namespace Barotrauma
LoadLocationTypeChange(element);
}
string[] takenItemStr = element.GetAttributeStringArray("takenitems", new string[0]);
string[] takenItemStr = element.GetAttributeStringArray("takenitems", Array.Empty<string>());
foreach (string takenItem in takenItemStr)
{
string[] takenItemSplit = takenItem.Split(';');
@@ -336,15 +335,15 @@ namespace Barotrauma
DebugConsole.ThrowError($"Error in saved location: could not parse taken item module index \"{takenItemSplit[3]}\"");
continue;
}
takenItems.Add(new TakenItem(takenItemSplit[0], id, containerIndex, moduleIndex));
takenItems.Add(new TakenItem(takenItemSplit[0].ToIdentifier(), id, containerIndex, moduleIndex));
}
killedCharacterIdentifiers = element.GetAttributeIntArray("killedcharacters", new int[0]).ToHashSet();
killedCharacterIdentifiers = element.GetAttributeIntArray("killedcharacters", Array.Empty<int>()).ToHashSet();
System.Diagnostics.Debug.Assert(Type != null, $"Could not find the location type \"{locationType}\"!");
if (Type == null)
{
Type = LocationType.List.First();
Type = LocationType.Prefabs.First();
}
LevelData = new LevelData(element.Element("Level"));
@@ -359,7 +358,7 @@ namespace Barotrauma
{
TimeSinceLastTypeChange = locationElement.GetAttributeInt("timesincelasttypechange", 0);
LocationTypeChangeCooldown = locationElement.GetAttributeInt("locationtypechangecooldown", 0);
foreach (XElement subElement in locationElement.Elements())
foreach (var subElement in locationElement.Elements())
{
switch (subElement.Name.ToString())
{
@@ -377,8 +376,8 @@ namespace Barotrauma
}
else
{
string missionIdentifier = subElement.GetAttributeString("missionidentifier", "");
var mission = MissionPrefab.List.Find(mp => mp.Identifier.Equals(missionIdentifier, StringComparison.OrdinalIgnoreCase));
Identifier missionIdentifier = subElement.GetAttributeIdentifier("missionidentifier", "");
var mission = MissionPrefab.Prefabs[missionIdentifier];
if (mission == null)
{
DebugConsole.AddWarning($"Failed to activate a location type change from the mission \"{missionIdentifier}\" in location \"{Name}\". Matching mission not found.");
@@ -400,7 +399,7 @@ namespace Barotrauma
{
var id = childElement.GetAttributeString("prefabid", null);
if (string.IsNullOrWhiteSpace(id)) { continue; }
var prefab = MissionPrefab.List.Find(p => p.Identifier.Equals(id, StringComparison.OrdinalIgnoreCase));
var prefab = MissionPrefab.Prefabs.Find(p => p.Identifier == id);
if (prefab == null) { continue; }
var destination = childElement.GetAttributeInt("destinationindex", -1);
var selected = childElement.GetAttributeBool("selected", false);
@@ -410,7 +409,7 @@ namespace Barotrauma
}
public static Location CreateRandom(Vector2 position, int? zone, Random rand, bool requireOutpost, LocationType? forceLocationType = null, IEnumerable<Location> existingLocations = null)
public static Location CreateRandom(Vector2 position, int? zone, Random rand, bool requireOutpost, LocationType forceLocationType = null, IEnumerable<Location> existingLocations = null)
{
return new Location(position, zone, rand, requireOutpost, forceLocationType, existingLocations);
}
@@ -432,11 +431,11 @@ namespace Barotrauma
if (Type.MissionIdentifiers.Any())
{
UnlockMissionByIdentifier(Type.MissionIdentifiers.GetRandom());
UnlockMissionByIdentifier(Type.MissionIdentifiers.GetRandomUnsynced());
}
if (Type.MissionTags.Any())
{
UnlockMissionByTag(Type.MissionTags.GetRandom());
UnlockMissionByTag(Type.MissionTags.GetRandomUnsynced());
}
CreateStore(force: true);
@@ -446,11 +445,11 @@ namespace Barotrauma
{
if (Type.MissionIdentifiers.Any())
{
UnlockMissionByIdentifier(Type.MissionIdentifiers.GetRandom(Rand.RandSync.Server));
UnlockMissionByIdentifier(Type.MissionIdentifiers.GetRandom(Rand.RandSync.ServerAndClient));
}
if (Type.MissionTags.Any())
{
UnlockMissionByTag(Type.MissionTags.GetRandom(Rand.RandSync.Server));
UnlockMissionByTag(Type.MissionTags.GetRandom(Rand.RandSync.ServerAndClient));
}
}
@@ -474,11 +473,11 @@ namespace Barotrauma
#endif
}
public MissionPrefab UnlockMissionByIdentifier(string identifier)
public MissionPrefab UnlockMissionByIdentifier(Identifier identifier)
{
if (AvailableMissions.Any(m => m.Prefab.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase))) { return null; }
if (AvailableMissions.Any(m => m.Prefab.Identifier == identifier)) { return null; }
var missionPrefab = MissionPrefab.List.Find(mp => mp.Identifier.Equals(identifier, StringComparison.OrdinalIgnoreCase));
var missionPrefab = MissionPrefab.Prefabs.Find(mp => mp.Identifier == identifier);
if (missionPrefab == null)
{
DebugConsole.ThrowError($"Failed to unlock a mission with the identifier \"{identifier}\": matching mission not found.");
@@ -500,9 +499,9 @@ namespace Barotrauma
return null;
}
public MissionPrefab UnlockMissionByTag(string tag)
public MissionPrefab UnlockMissionByTag(Identifier tag)
{
var matchingMissions = MissionPrefab.List.FindAll(mp => mp.Tags.Any(t => t.Equals(tag, StringComparison.OrdinalIgnoreCase)));
var matchingMissions = MissionPrefab.Prefabs.Where(mp => mp.Tags.Any(t => t == tag));
if (!matchingMissions.Any())
{
DebugConsole.ThrowError($"Failed to unlock a mission with the tag \"{tag}\": no matching missions not found.");
@@ -623,11 +622,11 @@ namespace Barotrauma
{
if (addInitialMissionsForType.MissionIdentifiers.Any())
{
UnlockMissionByIdentifier(addInitialMissionsForType.MissionIdentifiers.GetRandom());
UnlockMissionByIdentifier(addInitialMissionsForType.MissionIdentifiers.GetRandomUnsynced());
}
if (addInitialMissionsForType.MissionTags.Any())
{
UnlockMissionByTag(addInitialMissionsForType.MissionTags.GetRandom());
UnlockMissionByTag(addInitialMissionsForType.MissionTags.GetRandomUnsynced());
}
addInitialMissionsForType = null;
}
@@ -661,7 +660,7 @@ namespace Barotrauma
public LocationType GetLocationType()
{
if (IsCriticallyRadiated() && LocationType.List.FirstOrDefault(lt => lt.Identifier.Equals(Type.ReplaceInRadiation, StringComparison.OrdinalIgnoreCase)) is { } newLocationType)
if (IsCriticallyRadiated() && LocationType.Prefabs[Type.ReplaceInRadiation] is { } newLocationType)
{
return newLocationType;
}
@@ -757,8 +756,8 @@ namespace Barotrauma
List<ItemPrefab> specials = new List<ItemPrefab>();
foreach (var childElement in element.GetChildElements("item"))
{
var id = childElement.GetAttributeString("id", null);
if (string.IsNullOrWhiteSpace(id)) { continue; }
var id = childElement.GetAttributeIdentifier("id", Identifier.Empty);
if (id.IsEmpty) { continue; }
var prefab = ItemPrefab.Find(null, id);
if (prefab == null) { continue; }
specials.Add(prefab);
@@ -1045,9 +1044,9 @@ namespace Barotrauma
RequestedGoods.Clear();
for (int i = 0; i < RequestedGoodsCount; i++)
{
var item = ItemPrefab.Prefabs.GetRandom(p =>
var item = ItemPrefab.Prefabs.GetRandom<ItemPrefab>(p =>
p.CanBeSold && !RequestedGoods.Contains(p) &&
p.GetPriceInfo(this) is PriceInfo pi && pi.CanBeSpecial);
p.GetPriceInfo(this) is PriceInfo pi && pi.CanBeSpecial, Rand.RandSync.Unsynced);
if (item == null) { break; }
RequestedGoods.Add(item);
}
@@ -7,23 +7,24 @@ using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
using System.Collections.Immutable;
namespace Barotrauma
{
class LocationType
class LocationType : PrefabWithUintIdentifier
{
public static readonly List<LocationType> List = new List<LocationType>();
public static readonly PrefabCollection<LocationType> Prefabs = new PrefabCollection<LocationType>();
private readonly List<string> names;
private readonly List<Sprite> portraits = new List<Sprite>();
//<name, commonness>
private readonly List<Tuple<JobPrefab, float>> hireableJobs;
private readonly ImmutableArray<(Identifier Name, float Commonness)> hireableJobs;
private readonly float totalHireableWeight;
public Dictionary<int, float> CommonnessPerZone = new Dictionary<int, float>();
public readonly string Identifier;
public readonly string Name;
public readonly LocalizedString Name;
public readonly float BeaconStationChance;
@@ -31,8 +32,8 @@ namespace Barotrauma
public readonly List<LocationTypeChange> CanChangeTo = new List<LocationTypeChange>();
public readonly List<string> MissionIdentifiers = new List<string>();
public readonly List<string> MissionTags = new List<string>();
public readonly ImmutableArray<Identifier> MissionIdentifiers;
public readonly ImmutableArray<Identifier> MissionTags;
public readonly List<string> HideEntitySubcategories = new List<string>();
@@ -44,7 +45,15 @@ namespace Barotrauma
private set;
}
public List<string> NameFormats { get; private set; }
private ImmutableArray<string>? nameFormats = null;
public IReadOnlyList<string> NameFormats
{
get
{
nameFormats ??= TextManager.GetAll($"LocationNameFormat.{Identifier}").ToImmutableArray();
return nameFormats;
}
}
public bool HasHireableCharacters
{
@@ -104,32 +113,30 @@ namespace Barotrauma
return $"LocationType (" + Identifier + ")";
}
private LocationType(XElement element)
public LocationType(ContentXElement element, LocationTypesFile file) : base(file, element.GetAttributeIdentifier("identifier", element.Name.LocalName))
{
Identifier = element.GetAttributeString("identifier", element.Name.ToString());
Name = TextManager.Get("LocationName." + Identifier, fallBackTag: "unknown");
Name = TextManager.Get("LocationName." + Identifier, "unknown");
BeaconStationChance = element.GetAttributeFloat("beaconstationchance", 0.0f);
NameFormats = TextManager.GetAll("LocationNameFormat." + Identifier);
UseInMainMenu = element.GetAttributeBool("useinmainmenu", false);
HasOutpost = element.GetAttributeBool("hasoutpost", true);
IsEnterable = element.GetAttributeBool("isenterable", HasOutpost);
MissionIdentifiers = element.GetAttributeStringArray("missionidentifiers", new string[0]).ToList();
MissionTags = element.GetAttributeStringArray("missiontags", new string[0]).ToList();
MissionIdentifiers = element.GetAttributeIdentifierArray("missionidentifiers", Array.Empty<Identifier>()).ToImmutableArray();
MissionTags = element.GetAttributeIdentifierArray("missiontags", Array.Empty<Identifier>()).ToImmutableArray();
HideEntitySubcategories = element.GetAttributeStringArray("hideentitysubcategories", new string[0]).ToList();
HideEntitySubcategories = element.GetAttributeStringArray("hideentitysubcategories", Array.Empty<string>()).ToList();
ReplaceInRadiation = element.GetAttributeString(nameof(ReplaceInRadiation).ToLower(), "");
string teamStr = element.GetAttributeString("outpostteam", "FriendlyNPC");
Enum.TryParse(teamStr, out OutpostTeam);
string nameFile = element.GetAttributeString("namefile", "Content/Map/locationNames.txt");
ContentPath nameFile = element.GetAttributeContentPath("namefile") ?? ContentPath.FromRaw(null, "Content/Map/locationNames.txt");
try
{
names = File.ReadAllLines(nameFile).ToList();
names = File.ReadAllLines(nameFile.Value).ToList();
}
catch (Exception e)
{
@@ -151,31 +158,16 @@ namespace Barotrauma
CommonnessPerZone[zoneIndex] = zoneCommonness;
}
hireableJobs = new List<Tuple<JobPrefab, float>>();
foreach (XElement subElement in element.Elements())
var hireableJobs = new List<(Identifier, float)>();
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "hireable":
string jobIdentifier = subElement.GetAttributeString("identifier", "");
JobPrefab jobPrefab = null;
if (jobIdentifier == "")
{
DebugConsole.ThrowError("Error in location type \""+ Identifier + "\" - hireable jobs should be configured using identifiers instead of names.");
}
else
{
jobPrefab = JobPrefab.Get(jobIdentifier.ToLowerInvariant());
}
if (jobPrefab == null)
{
DebugConsole.ThrowError("Error in in location type " + Identifier + " - could not find a job with the identifier \"" + jobIdentifier + "\".");
continue;
}
Identifier jobIdentifier = subElement.GetAttributeIdentifier("identifier", Identifier.Empty);
float jobCommonness = subElement.GetAttributeFloat("commonness", 1.0f);
totalHireableWeight += jobCommonness;
Tuple<JobPrefab, float> hireableJob = new Tuple<JobPrefab, float>(jobPrefab, jobCommonness);
hireableJobs.Add(hireableJob);
hireableJobs.Add((jobIdentifier, jobCommonness));
break;
case "symbol":
Sprite = new Sprite(subElement, lazyLoad: true);
@@ -216,16 +208,17 @@ namespace Barotrauma
break;
}
}
this.hireableJobs = hireableJobs.ToImmutableArray();
}
public JobPrefab GetRandomHireable()
{
float randFloat = Rand.Range(0.0f, totalHireableWeight, Rand.RandSync.Server);
float randFloat = Rand.Range(0.0f, totalHireableWeight, Rand.RandSync.ServerAndClient);
foreach (Tuple<JobPrefab, float> hireable in hireableJobs)
foreach ((Identifier jobIdentifier, float commonness) in hireableJobs)
{
if (randFloat < hireable.Item2) return hireable.Item1;
randFloat -= hireable.Item2;
if (randFloat < commonness) { return JobPrefab.Prefabs[jobIdentifier]; }
randFloat -= commonness;
}
return null;
@@ -252,12 +245,13 @@ namespace Barotrauma
public static LocationType Random(Random rand, int? zone = null, bool requireOutpost = false)
{
Debug.Assert(List.Count > 0, "LocationType.list.Count == 0, you probably need to initialize LocationTypes");
Debug.Assert(Prefabs.Any(), "LocationType.list.Count == 0, you probably need to initialize LocationTypes");
List<LocationType> allowedLocationTypes =
List.FindAll(lt => (!zone.HasValue || lt.CommonnessPerZone.ContainsKey(zone.Value)) && (!requireOutpost || lt.HasOutpost));
LocationType[] allowedLocationTypes =
Prefabs.Where(lt => (!zone.HasValue || lt.CommonnessPerZone.ContainsKey(zone.Value)) && (!requireOutpost || lt.HasOutpost))
.OrderBy(p => p.UintIdentifier).ToArray();
if (allowedLocationTypes.Count == 0)
if (allowedLocationTypes.Length == 0)
{
DebugConsole.ThrowError("Could not generate a random location type - no location types for the zone " + zone + " found!");
}
@@ -266,82 +260,15 @@ namespace Barotrauma
{
return ToolBox.SelectWeightedRandom(
allowedLocationTypes,
allowedLocationTypes.Select(a => a.CommonnessPerZone[zone.Value]).ToList(),
allowedLocationTypes.Select(a => a.CommonnessPerZone[zone.Value]).ToArray(),
rand);
}
else
{
return allowedLocationTypes[rand.Next() % allowedLocationTypes.Count];
return allowedLocationTypes[rand.Next() % allowedLocationTypes.Length];
}
}
public static void Init()
{
List.Clear();
var locationTypeFiles = GameMain.Instance.GetFilesOfType(ContentType.LocationTypes);
if (!locationTypeFiles.Any())
{
DebugConsole.ThrowError("No location types configured in any of the selected content packages. Attempting to load from the vanilla content package...");
locationTypeFiles = ContentPackage.GetFilesOfType(GameMain.VanillaContent.ToEnumerable(), ContentType.LocationTypes);
if (!locationTypeFiles.Any())
{
throw new Exception("No location types configured in any of the selected content packages. Please try uninstalling mods or reinstalling the game.");
}
}
foreach (ContentFile file in locationTypeFiles)
{
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc == null) { continue; }
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
mainElement = doc.Root.FirstElement();
DebugConsole.NewMessage($"Overriding all location types with '{file.Path}'", Color.Yellow);
List.Clear();
}
else if (List.Any())
{
DebugConsole.NewMessage($"Loading additional location types from file '{file.Path}'");
}
foreach (XElement sourceElement in mainElement.Elements())
{
var element = sourceElement;
bool allowOverriding = false;
if (sourceElement.IsOverride())
{
element = sourceElement.FirstElement();
allowOverriding = true;
}
string identifier = element.GetAttributeString("identifier", null);
if (string.IsNullOrWhiteSpace(identifier))
{
DebugConsole.ThrowError($"Error in '{file.Path}': No identifier defined for {element.Name.ToString()}");
continue;
}
var duplicate = List.FirstOrDefault(l => l.Identifier == identifier);
if (duplicate != null)
{
if (allowOverriding)
{
List.Remove(duplicate);
DebugConsole.NewMessage($"Overriding the location type with the identifier '{identifier}' with '{file.Path}'", Color.Yellow);
}
else
{
DebugConsole.ThrowError($"Error in '{file.Path}': Duplicate identifier defined with the identifier '{identifier}'");
continue;
}
}
LocationType locationType = new LocationType(element);
List.Add(locationType);
}
}
foreach (EventSet eventSet in EventSet.List)
{
eventSet.CheckLocationTypeErrors();
}
}
public override void Dispose() { }
}
}
@@ -1,8 +1,10 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -21,7 +23,7 @@ namespace Barotrauma
/// <summary>
/// The change can only happen if there's at least one of the given types of locations near this one
/// </summary>
public readonly List<string> RequiredLocations;
public readonly ImmutableArray<Identifier> RequiredLocations;
/// <summary>
/// How close the location needs to be to one of the RequiredLocations for the change to occur
@@ -55,7 +57,7 @@ namespace Barotrauma
public Requirement(XElement element, LocationTypeChange change)
{
RequiredLocations = element.GetAttributeStringArray("requiredlocations", element.GetAttributeStringArray("requiredadjacentlocations", new string[0])).ToList();
RequiredLocations = element.GetAttributeIdentifierArray("requiredlocations", element.GetAttributeIdentifierArray("requiredadjacentlocations", Array.Empty<Identifier>())).ToImmutableArray();
RequiredProximity = Math.Max(element.GetAttributeInt("requiredproximity", 1), 1);
ProximityProbabilityIncrease = element.GetAttributeFloat("proximityprobabilityincrease", 0.0f);
RequiredProximityForProbabilityIncrease = element.GetAttributeInt("requiredproximityforprobabilityincrease", -1);
@@ -124,9 +126,9 @@ namespace Barotrauma
}
}
public readonly string CurrentType;
public readonly Identifier CurrentType;
public readonly string ChangeToType;
public readonly Identifier ChangeToType;
/// <summary>
/// Base probability per turn for the location to change if near one of the RequiredLocations
@@ -137,12 +139,33 @@ namespace Barotrauma
public List<Requirement> Requirements = new List<Requirement>();
public List<string> Messages = new List<string>();
private readonly bool requireChangeMessages;
private readonly string messageTag;
private ImmutableArray<string>? messages = null;
public IReadOnlyList<string> Messages
{
get
{
if (!messages.HasValue)
{
messages = TextManager.GetAll(messageTag).ToImmutableArray();
if (messages.Value.None())
{
if (requireChangeMessages)
{
DebugConsole.ThrowError($"No messages defined for the location type change {CurrentType} -> {ChangeToType}");
}
}
}
return messages.Value;
}
}
/// <summary>
/// The change can't happen if there's one or more of the given types of locations near this one
/// </summary>
public readonly List<string> DisallowedAdjacentLocations;
public readonly ImmutableArray<Identifier> DisallowedAdjacentLocations;
/// <summary>
/// How close the location needs to be to one of the DisallowedAdjacentLocations for the change to be disabled
@@ -156,14 +179,14 @@ namespace Barotrauma
public readonly Point RequiredDurationRange;
public LocationTypeChange(string currentType, XElement element, bool requireChangeMessages, float defaultProbability = 0.0f)
public LocationTypeChange(Identifier currentType, XElement element, bool requireChangeMessages, float defaultProbability = 0.0f)
{
CurrentType = currentType;
ChangeToType = element.GetAttributeString("type", element.GetAttributeString("to", ""));
ChangeToType = element.GetAttributeIdentifier("type", element.GetAttributeIdentifier("to", ""));
RequireDiscovered = element.GetAttributeBool("requirediscovered", false);
DisallowedAdjacentLocations = element.GetAttributeStringArray("disallowedadjacentlocations", new string[0]).ToList();
DisallowedAdjacentLocations = element.GetAttributeIdentifierArray("disallowedadjacentlocations", Array.Empty<Identifier>()).ToImmutableArray();
DisallowedProximity = Math.Max(element.GetAttributeInt("disallowedproximity", 1), 1);
RequiredDurationRange = element.GetAttributePoint("requireddurationrange", Point.Zero);
@@ -184,19 +207,10 @@ namespace Barotrauma
RequiredDurationRange = new Point(element.GetAttributeInt("requiredduration", 0));
}
string messageTag = element.GetAttributeString("messagetag", "LocationChange." + currentType + ".ChangeTo." + ChangeToType);
this.requireChangeMessages = requireChangeMessages;
messageTag = element.GetAttributeString("messagetag", "LocationChange." + currentType + ".ChangeTo." + ChangeToType);
Messages = TextManager.GetAll(messageTag);
if (Messages == null)
{
if (requireChangeMessages)
{
DebugConsole.ThrowError("No messages defined for the location type change " + currentType + " -> " + ChangeToType);
}
Messages = new List<string>();
}
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
if (subElement.Name.ToString().Equals("requirement", StringComparison.OrdinalIgnoreCase))
{
@@ -88,7 +88,7 @@ namespace Barotrauma
bool lairsFound = false;
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -112,11 +112,11 @@ namespace Barotrauma
System.Diagnostics.Debug.Assert(!Locations.Contains(null));
for (int i = 0; i < Locations.Count; i++)
{
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, Locations[i], $"location.{i}", -100, 100, Rand.Range(-10, 11, Rand.RandSync.Server));
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, Locations[i], $"location.{i}".ToIdentifier(), -100, 100, Rand.Range(-10, 11, Rand.RandSync.ServerAndClient));
}
List<XElement> connectionElements = new List<XElement>();
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -133,10 +133,10 @@ namespace Barotrauma
Locations[locationIndices.Y].Connections.Add(connection);
connection.LevelData = new LevelData(subElement.Element("Level"));
string biomeId = subElement.GetAttributeString("biome", "");
connection.Biome =
LevelGenerationParams.GetBiomes().FirstOrDefault(b => b.Identifier == biomeId) ??
LevelGenerationParams.GetBiomes().FirstOrDefault(b => b.OldIdentifier == biomeId) ??
LevelGenerationParams.GetBiomes().First();
connection.Biome =
Biome.Prefabs.FirstOrDefault(b => b.Identifier == biomeId) ??
Biome.Prefabs.FirstOrDefault(b => !b.OldIdentifier.IsEmpty && b.OldIdentifier == biomeId) ??
Biome.Prefabs.First();
Connections.Add(connection);
connectionElements.Add(subElement);
break;
@@ -214,13 +214,13 @@ namespace Barotrauma
for (int i = 0; i < Locations.Count; i++)
{
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, Locations[i], $"location.{i}", -100, 100, Rand.Range(-10, 11, Rand.RandSync.Server));
Locations[i].Reputation ??= new Reputation(campaign.CampaignMetadata, Locations[i], $"location.{i}".ToIdentifier(), -100, 100, Rand.Range(-10, 11, Rand.RandSync.ServerAndClient));
}
foreach (Location location in Locations)
{
if (!location.Type.Identifier.Equals("city", StringComparison.OrdinalIgnoreCase) &&
!location.Type.Identifier.Equals("outpost", StringComparison.OrdinalIgnoreCase))
if (location.Type.Identifier != "city" &&
location.Type.Identifier != "outpost")
{
continue;
}
@@ -252,8 +252,8 @@ namespace Barotrauma
for (float y = 10.0f; y < Height - 10.0f; y += generationParams.VoronoiSiteInterval.Y)
{
voronoiSites.Add(new Vector2(
x + generationParams.VoronoiSiteVariance.X * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server),
y + generationParams.VoronoiSiteVariance.Y * Rand.Range(-0.5f, 0.5f, Rand.RandSync.Server)));
x + generationParams.VoronoiSiteVariance.X * Rand.Range(-0.5f, 0.5f, Rand.RandSync.ServerAndClient),
y + generationParams.VoronoiSiteVariance.Y * Rand.Range(-0.5f, 0.5f, Rand.RandSync.ServerAndClient)));
}
}
@@ -297,12 +297,12 @@ namespace Barotrauma
Vector2[] points = new Vector2[] { edge.Point1, edge.Point2 };
int positionIndex = Rand.Int(1, Rand.RandSync.Server);
int positionIndex = Rand.Int(1, Rand.RandSync.ServerAndClient);
Vector2 position = points[positionIndex];
if (newLocations[1 - i] != null && newLocations[1 - i].MapPosition == position) { position = points[1 - positionIndex]; }
int zone = GetZoneIndex(position.X);
newLocations[i] = Location.CreateRandom(position, zone, Rand.GetRNG(Rand.RandSync.Server), requireOutpost: false, existingLocations: Locations);
newLocations[i] = Location.CreateRandom(position, zone, Rand.GetRNG(Rand.RandSync.ServerAndClient), requireOutpost: false, existingLocations: Locations);
Locations.Add(newLocations[i]);
}
@@ -394,7 +394,7 @@ namespace Barotrauma
connectionsBetweenZones[i] = new List<LocationConnection>();
}
var shuffledConnections = Connections.ToList();
shuffledConnections.Shuffle(Rand.RandSync.Server);
shuffledConnections.Shuffle(Rand.RandSync.ServerAndClient);
foreach (var connection in shuffledConnections)
{
int zone1 = GetZoneIndex(connection.Locations[0].MapPosition.X);
@@ -447,9 +447,10 @@ namespace Barotrauma
Connections[i].Locations[0].MapPosition.X < Connections[i].Locations[1].MapPosition.X ?
Connections[i].Locations[0] :
Connections[i].Locations[1];
if (!leftMostLocation.Type.HasOutpost || leftMostLocation.Type.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase))
if (!leftMostLocation.Type.HasOutpost || leftMostLocation.Type.Identifier == "abandoned")
{
leftMostLocation.ChangeType(LocationType.List.First(lt => lt.HasOutpost && !lt.Identifier.Equals("abandoned", StringComparison.OrdinalIgnoreCase)));
#warning TODO: determinism?
leftMostLocation.ChangeType(LocationType.Prefabs.First(lt => lt.HasOutpost && lt.Identifier != "abandoned"));
}
leftMostLocation.IsGateBetweenBiomes = true;
Connections[i].Locked = true;
@@ -473,10 +474,10 @@ namespace Barotrauma
foreach (LocationConnection connection in Connections)
{
//float difficulty = GetLevelDifficulty(connection.CenterPos.X / Width);
//connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-10.0f, 0.0f, Rand.RandSync.Server), 1.2f, 100.0f);
//connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-10.0f, 0.0f, Rand.RandSync.ServerAndClient), 1.2f, 100.0f);
float difficulty = connection.CenterPos.X / Width * 100;
float random = difficulty > 10 ? 5 : 0;
connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-random, random, Rand.RandSync.Server), 1.0f, 100.0f);
connection.Difficulty = MathHelper.Clamp(difficulty + Rand.Range(-random, random, Rand.RandSync.ServerAndClient), 1.0f, 100.0f);
}
AssignBiomes();
@@ -522,21 +523,13 @@ namespace Barotrauma
{
float zoneWidth = Width / generationParams.DifficultyZones;
int zoneIndex = (int)Math.Floor(xPos / zoneWidth) + 1;
if (zoneIndex < 1)
{
return LevelGenerationParams.GetBiomes().First();
}
else if (zoneIndex >= generationParams.DifficultyZones)
{
return LevelGenerationParams.GetBiomes().Last();
}
return LevelGenerationParams.GetBiomes().FirstOrDefault(b => b.AllowedZones.Contains(zoneIndex));
zoneIndex = Math.Clamp(zoneIndex, 1, generationParams.DifficultyZones - 1);
return Biome.Prefabs.FirstOrDefault(b => b.AllowedZones.Contains(zoneIndex));
}
private void AssignBiomes()
{
var biomes = LevelGenerationParams.GetBiomes();
var biomes = Biome.Prefabs;
float zoneWidth = Width / generationParams.DifficultyZones;
List<Biome> allowedBiomes = new List<Biome>(10);
@@ -550,7 +543,7 @@ namespace Barotrauma
{
if (location.MapPosition.X < zoneX)
{
location.Biome = allowedBiomes[Rand.Range(0, allowedBiomes.Count, Rand.RandSync.Server)];
location.Biome = allowedBiomes[Rand.Range(0, allowedBiomes.Count, Rand.RandSync.ServerAndClient)];
}
}
}
@@ -692,10 +685,10 @@ namespace Barotrauma
if (GameMain.GameSession is { Campaign: { CampaignMetadata: { } metadata } })
{
metadata.SetValue("campaign.location.id", CurrentLocationIndex);
metadata.SetValue("campaign.location.name", CurrentLocation.Name);
metadata.SetValue("campaign.location.biome", CurrentLocation.Biome?.Identifier ?? "null");
metadata.SetValue("campaign.location.type", CurrentLocation.Type?.Identifier ?? "null");
metadata.SetValue("campaign.location.id".ToIdentifier(), CurrentLocationIndex);
metadata.SetValue("campaign.location.name".ToIdentifier(), CurrentLocation.Name);
metadata.SetValue("campaign.location.biome".ToIdentifier(), CurrentLocation.Biome?.Identifier ?? "null".ToIdentifier());
metadata.SetValue("campaign.location.type".ToIdentifier(), CurrentLocation.Type?.Identifier ?? "null".ToIdentifier());
}
}
@@ -999,7 +992,7 @@ namespace Barotrauma
{
string prevName = location.Name;
var newType = LocationType.List.Find(lt => lt.Identifier.Equals(change.ChangeToType, StringComparison.OrdinalIgnoreCase));
var newType = LocationType.Prefabs[change.ChangeToType];
if (newType == null)
{
DebugConsole.ThrowError($"Failed to change the type of the location \"{location.Name}\". Location type \"{change.ChangeToType}\" not found.");
@@ -1053,7 +1046,7 @@ namespace Barotrauma
return;
}
foreach (XElement subElement in element.Elements())
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -1083,14 +1076,14 @@ namespace Barotrauma
}
}
string locationType = subElement.GetAttributeString("type", "");
Identifier locationType = subElement.GetAttributeIdentifier("type", Identifier.Empty);
string prevLocationName = location.Name;
LocationType prevLocationType = location.Type;
LocationType newLocationType = LocationType.List.Find(lt => lt.Identifier.Equals(locationType, StringComparison.OrdinalIgnoreCase)) ?? LocationType.List.First();
LocationType newLocationType = LocationType.Prefabs.Find(lt => lt.Identifier == locationType) ?? LocationType.Prefabs.First();
location.ChangeType(newLocationType);
if (showNotifications && prevLocationType != location.Type)
{
var change = prevLocationType.CanChangeTo.Find(c => c.ChangeToType.Equals(location.Type.Identifier, StringComparison.OrdinalIgnoreCase));
var change = prevLocationType.CanChangeTo.Find(c => c.ChangeToType == location.Type.Identifier);
if (change != null)
{
ChangeLocationTypeProjSpecific(location, prevLocationName, change);
@@ -1,30 +1,31 @@
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
class MapGenerationParams : ISerializableEntity
class MapGenerationParams : Prefab, ISerializableEntity
{
private static MapGenerationParams instance;
private static string loadedFile;
public static readonly PrefabSelector<MapGenerationParams> Params = new PrefabSelector<MapGenerationParams>();
public static MapGenerationParams Instance
{
get
{
return instance;
return Params.ActivePrefab;
}
}
#if DEBUG
[Serialize(true, true), Editable]
[Serialize(true, IsPropertySaveable.Yes), Editable]
public bool ShowLocations { get; set; }
[Serialize(true, true), Editable]
[Serialize(true, IsPropertySaveable.Yes), Editable]
public bool ShowLevelTypeNames { get; set; }
[Serialize(true, true), Editable]
[Serialize(true, IsPropertySaveable.Yes), Editable]
public bool ShowOverlay { get; set; }
#else
public readonly bool ShowLocations = true;
@@ -32,70 +33,70 @@ namespace Barotrauma
public readonly bool ShowOverlay = true;
#endif
[Serialize(6, true)]
[Serialize(6, IsPropertySaveable.Yes)]
public int DifficultyZones { get; set; } //Number of difficulty zones
[Serialize(8000, true), Editable]
[Serialize(8000, IsPropertySaveable.Yes), Editable]
public int Width { get; set; }
[Serialize(500, true), Editable]
[Serialize(500, IsPropertySaveable.Yes), Editable]
public int Height { get; set; }
[Serialize(20.0f, true, description: "Connections with a length smaller or equal to this generate the smallest possible levels (using the MinWidth parameter in the level generation paramaters)."), Editable(0.0f, 5000.0f)]
[Serialize(20.0f, IsPropertySaveable.Yes, description: "Connections with a length smaller or equal to this generate the smallest possible levels (using the MinWidth parameter in the level generation paramaters)."), Editable(0.0f, 5000.0f)]
public float SmallLevelConnectionLength { get; set; }
[Serialize(200.0f, true, description: "Connections with a length larger or equal to this generate the largest possible levels (using the MaxWidth parameter in the level generation paramaters)."), Editable(0.0f, 5000.0f)]
[Serialize(200.0f, IsPropertySaveable.Yes, description: "Connections with a length larger or equal to this generate the largest possible levels (using the MaxWidth parameter in the level generation paramaters)."), Editable(0.0f, 5000.0f)]
public float LargeLevelConnectionLength { get; set; }
[Serialize("20,20", true, description: "How far from each other voronoi sites are placed. " +
[Serialize("20,20", IsPropertySaveable.Yes, description: "How far from each other voronoi sites are placed. " +
"Sites determine shape of the voronoi graph. Locations are placed at the vertices of the voronoi cells. " +
"(Decreasing this value causes the number of sites, and the complexity of the map, to increase exponentially - be careful when adjusting)"), Editable]
public Point VoronoiSiteInterval { get; set; }
[Serialize("5,5", true), Editable]
[Serialize("5,5", IsPropertySaveable.Yes), Editable]
public Point VoronoiSiteVariance { get; set; }
[Serialize(10.0f, true, description: "Connections smaller than this are removed."), Editable(0.0f, 500.0f)]
[Serialize(10.0f, IsPropertySaveable.Yes, description: "Connections smaller than this are removed."), Editable(0.0f, 500.0f)]
public float MinConnectionDistance { get; set; }
[Serialize(5.0f, true, description: "Locations that are closer than this to another location are removed."), Editable(0.0f, 100.0f)]
[Serialize(5.0f, IsPropertySaveable.Yes, description: "Locations that are closer than this to another location are removed."), Editable(0.0f, 100.0f)]
public float MinLocationDistance { get; set; }
[Serialize(0.1f, true, description: "ConnectionIterationMultiplier for the UI indicator lines between locations."), Editable(0.0f, 10.0f, DecimalCount = 2)]
[Serialize(0.1f, IsPropertySaveable.Yes, description: "ConnectionIterationMultiplier for the UI indicator lines between locations."), Editable(0.0f, 10.0f, DecimalCount = 2)]
public float ConnectionIndicatorIterationMultiplier { get; set; }
[Serialize(0.1f, true, description: "ConnectionDisplacementMultiplier for the UI indicator lines between locations."), Editable(0.0f, 10.0f, DecimalCount = 2)]
[Serialize(0.1f, IsPropertySaveable.Yes, description: "ConnectionDisplacementMultiplier for the UI indicator lines between locations."), Editable(0.0f, 10.0f, DecimalCount = 2)]
public float ConnectionIndicatorDisplacementMultiplier { get; set; }
public int[] GateCount { get; private set; }
public readonly ImmutableArray<int> GateCount;
#if CLIENT
[Serialize(0.75f, true), Editable(DecimalCount = 2)]
[Serialize(0.75f, IsPropertySaveable.Yes), Editable(DecimalCount = 2)]
public float MinZoom { get; set; }
[Serialize(1.5f, true), Editable(DecimalCount = 2)]
[Serialize(1.5f, IsPropertySaveable.Yes), Editable(DecimalCount = 2)]
public float MaxZoom { get; set; }
[Serialize(1.0f, true), Editable(DecimalCount = 2)]
[Serialize(1.0f, IsPropertySaveable.Yes), Editable(DecimalCount = 2)]
public float MapTileScale { get; set; }
[Serialize(15.0f, true, description: "Size of the location icons in pixels when at 100% zoom."), Editable(1.0f, 1000.0f)]
[Serialize(15.0f, IsPropertySaveable.Yes, description: "Size of the location icons in pixels when at 100% zoom."), Editable(1.0f, 1000.0f)]
public float LocationIconSize { get; set; }
[Serialize(5.0f, true, description: "Width of the connections between locations, in pixels when at 100% zoom."), Editable(1.0f, 1000.0f)]
[Serialize(5.0f, IsPropertySaveable.Yes, description: "Width of the connections between locations, in pixels when at 100% zoom."), Editable(1.0f, 1000.0f)]
public float LocationConnectionWidth { get; set; }
[Serialize("220,220,100,255", true, description: "The color used to display the indicators (current location, selected location, etc)."), Editable()]
[Serialize("220,220,100,255", IsPropertySaveable.Yes, description: "The color used to display the indicators (current location, selected location, etc)."), Editable()]
public Color IndicatorColor { get; set; }
[Serialize("150,150,150,255", true, description: "The color used to display the connections between locations."), Editable()]
[Serialize("150,150,150,255", IsPropertySaveable.Yes, description: "The color used to display the connections between locations."), Editable()]
public Color ConnectionColor { get; set; }
[Serialize("150,150,150,255", true, description: "The color used to display the connections between locations when they're highlighted."), Editable()]
[Serialize("150,150,150,255", IsPropertySaveable.Yes, description: "The color used to display the connections between locations when they're highlighted."), Editable()]
public Color HighlightedConnectionColor { get; set; }
[Serialize("150,150,150,255", true, description: "The color used to display the connections the player hasn't travelled through."), Editable()]
[Serialize("150,150,150,255", IsPropertySaveable.Yes, description: "The color used to display the connections the player hasn't travelled through."), Editable()]
public Color UnvisitedConnectionColor { get; set; }
public Sprite ConnectionSprite { get; private set; }
@@ -110,110 +111,36 @@ namespace Barotrauma
public Sprite CurrentLocationIndicator { get; private set; }
public Sprite SelectedLocationIndicator { get; private set; }
private readonly Dictionary<string, List<Sprite>> mapTiles = new Dictionary<string, List<Sprite>>();
public Dictionary<string, List<Sprite>> MapTiles
{
get { return mapTiles; }
}
public readonly ImmutableDictionary<Identifier, ImmutableArray<Sprite>> MapTiles;
#endif
public string Name
{
get { return GetType().ToString(); }
}
public string Name => GetType().ToString();
public Dictionary<string, SerializableProperty> SerializableProperties
public Dictionary<Identifier, SerializableProperty> SerializableProperties
{
get; private set;
}
public RadiationParams RadiationParams;
public static void Init()
{
var files = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.MapGenerationParameters);
if (!files.Any())
{
DebugConsole.ThrowError("No map generation parameters found in the selected content packages!");
return;
}
// Let's not actually load the parameters until we have solved which file is the last, because loading the parameters takes some resources that would also need to be released.
XElement selectedElement = null;
string selectedFile = null;
foreach (ContentFile file in files)
{
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc == null) { continue; }
var mainElement = doc.Root;
if (doc.Root.IsOverride())
{
mainElement = doc.Root.FirstElement();
if (selectedElement != null)
{
DebugConsole.NewMessage($"Overriding the map generation parameters with '{file.Path}'", Color.Yellow);
}
}
else if (selectedElement != null)
{
DebugConsole.ThrowError($"Error in {file.Path}: Another map generation parameter file already loaded! Use <override></override> tags to override it.");
break;
}
selectedElement = mainElement;
selectedFile = file.Path;
}
if (selectedFile == loadedFile) { return; }
#if CLIENT
if (instance != null)
{
instance?.ConnectionSprite?.Remove();
instance?.PassedConnectionSprite?.Remove();
instance?.SelectedLocationIndicator?.Remove();
instance?.CurrentLocationIndicator?.Remove();
instance?.DecorativeGraphSprite?.Remove();
instance?.MissionIcon?.Remove();
instance?.TypeChangeIcon?.Remove();
instance?.FogOfWarSprite?.Remove();
foreach (List<Sprite> spriteList in instance.mapTiles.Values)
{
foreach (Sprite sprite in spriteList)
{
sprite.Remove();
}
}
instance.mapTiles.Clear();
}
#endif
instance = null;
if (selectedElement == null)
{
DebugConsole.ThrowError("Could not find a valid element in the map generation parameter files!");
}
else
{
instance = new MapGenerationParams(selectedElement);
loadedFile = selectedFile;
}
}
private MapGenerationParams(XElement element)
public MapGenerationParams(ContentXElement element, MapGenerationParametersFile file) : base(file, file.Path.Value.ToIdentifier())
{
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
GateCount = element.GetAttributeIntArray("gatecount", null) ?? element.GetAttributeIntArray("GateCount", null);
if (GateCount == null)
var gateCount = element.GetAttributeIntArray("gatecount", null) ?? element.GetAttributeIntArray("GateCount", null);
if (gateCount == null)
{
GateCount = new int[DifficultyZones];
gateCount = new int[DifficultyZones];
for (int i = 0; i < DifficultyZones; i++)
{
GateCount[i] = 1;
gateCount[i] = 1;
}
}
GateCount = gateCount.ToImmutableArray();
foreach (XElement subElement in element.Elements())
Dictionary<Identifier, List<Sprite>> mapTiles = new Dictionary<Identifier, List<Sprite>>();
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -225,7 +152,7 @@ namespace Barotrauma
PassedConnectionSprite = new Sprite(subElement);
break;
case "maptile":
string biome = subElement.GetAttributeString("biome", "");
Identifier biome = subElement.GetAttributeIdentifier("biome", "");
if (!mapTiles.ContainsKey(biome))
{
mapTiles[biome] = new List<Sprite>();
@@ -257,6 +184,30 @@ namespace Barotrauma
break;
}
}
#if CLIENT
MapTiles = mapTiles.Select(kvp => (kvp.Key, kvp.Value.ToImmutableArray())).ToImmutableDictionary();
#endif
}
public override void Dispose()
{
#if CLIENT
ConnectionSprite?.Remove();
PassedConnectionSprite?.Remove();
SelectedLocationIndicator?.Remove();
CurrentLocationIndicator?.Remove();
DecorativeGraphSprite?.Remove();
MissionIcon?.Remove();
TypeChangeIcon?.Remove();
FogOfWarSprite?.Remove();
foreach (ImmutableArray<Sprite> spriteList in MapTiles.Values)
{
foreach (Sprite sprite in spriteList)
{
sprite.Remove();
}
}
#endif
}
}
}
@@ -12,18 +12,18 @@ namespace Barotrauma
{
public string Name => nameof(Radiation);
[Serialize(defaultValue: 0f, isSaveable: true)]
[Serialize(defaultValue: 0f, isSaveable: IsPropertySaveable.Yes)]
public float Amount { get; set; }
[Serialize(defaultValue: true, isSaveable: true)]
[Serialize(defaultValue: true, isSaveable: IsPropertySaveable.Yes)]
public bool Enabled { get; set; }
public Dictionary<string, SerializableProperty> SerializableProperties { get; }
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; }
public readonly Map Map;
public readonly RadiationParams Params;
private Affliction radiationAffliction;
private Affliction? radiationAffliction;
private float radiationTimer;
@@ -7,39 +7,39 @@ namespace Barotrauma
internal class RadiationParams: ISerializableEntity
{
public string Name => nameof(RadiationParams);
public Dictionary<string, SerializableProperty> SerializableProperties { get; }
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; }
[Serialize(defaultValue: -100f, isSaveable: false, "How much radiation the world starts with.")]
[Serialize(defaultValue: -100f, isSaveable: IsPropertySaveable.No, "How much radiation the world starts with.")]
public float StartingRadiation { get; set; }
[Serialize(defaultValue: 100f, isSaveable: false, "How much radiation is added on each step.")]
[Serialize(defaultValue: 100f, isSaveable: IsPropertySaveable.No, "How much radiation is added on each step.")]
public float RadiationStep { get; set; }
[Serialize(defaultValue: 10, isSaveable: false, "How many turns in radiation does it take for an outpost to be removed from the map.")]
[Serialize(defaultValue: 10, isSaveable: IsPropertySaveable.No, "How many turns in radiation does it take for an outpost to be removed from the map.")]
public int CriticalRadiationThreshold { get; set; }
[Serialize(defaultValue: 3, isSaveable: false, "Minimum amount of outposts in the level that cannot be removed due to radiation.")]
[Serialize(defaultValue: 3, isSaveable: IsPropertySaveable.No, "Minimum amount of outposts in the level that cannot be removed due to radiation.")]
public int MinimumOutpostAmount { get; set; }
[Serialize(defaultValue: 3f, isSaveable: false, "How fast the radiation increase animation goes.")]
[Serialize(defaultValue: 3f, isSaveable: IsPropertySaveable.No, "How fast the radiation increase animation goes.")]
public float AnimationSpeed { get; set; }
[Serialize(defaultValue: 10f, isSaveable: false, "How long it takes to apply more radiation damage while in a radiated zone.")]
[Serialize(defaultValue: 10f, isSaveable: IsPropertySaveable.No, "How long it takes to apply more radiation damage while in a radiated zone.")]
public float RadiationDamageDelay { get; set; }
[Serialize(defaultValue: 1f, isSaveable: false, "How much is the radiation affliction increased by while in a radiated zone.")]
[Serialize(defaultValue: 1f, isSaveable: IsPropertySaveable.No, "How much is the radiation affliction increased by while in a radiated zone.")]
public float RadiationDamageAmount { get; set; }
[Serialize(defaultValue: -1.0f, isSaveable: false, "Maximum amount of radiation.")]
[Serialize(defaultValue: -1.0f, isSaveable: IsPropertySaveable.No, "Maximum amount of radiation.")]
public float MaxRadiation { get; set; }
[Serialize(defaultValue: "139,0,0,85", isSaveable: false, "The color of the radiated area.")]
[Serialize(defaultValue: "139,0,0,85", isSaveable: IsPropertySaveable.No, "The color of the radiated area.")]
public Color RadiationAreaColor { get; set; }
[Serialize(defaultValue: "255,0,0,255", isSaveable: false, "The tint of the radiation border sprites.")]
[Serialize(defaultValue: "255,0,0,255", isSaveable: IsPropertySaveable.No, "The tint of the radiation border sprites.")]
public Color RadiationBorderTint { get; set; }
[Serialize(defaultValue: 16.66f, isSaveable: false, "Speed of the border spritesheet animation.")]
[Serialize(defaultValue: 16.66f, isSaveable: IsPropertySaveable.No, "Speed of the border spritesheet animation.")]
public float BorderAnimationSpeed { get; set; }
public RadiationParams(XElement element)