Unstable 0.17.0.0
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user