v1.2.6.0 (Winter Update)
This commit is contained in:
@@ -55,8 +55,17 @@ namespace Barotrauma
|
||||
|
||||
public readonly List<LocationConnection> Connections = new List<LocationConnection>();
|
||||
|
||||
private string baseName;
|
||||
public LocalizedString DisplayName { get; private set; }
|
||||
|
||||
public Identifier NameIdentifier => nameIdentifier;
|
||||
|
||||
private int nameFormatIndex;
|
||||
private Identifier nameIdentifier;
|
||||
|
||||
/// <summary>
|
||||
/// For backwards compatibility: a non-localizable name from the old text files.
|
||||
/// </summary>
|
||||
private string rawName;
|
||||
|
||||
private LocationType addInitialMissionsForType;
|
||||
|
||||
@@ -75,10 +84,6 @@ namespace Barotrauma
|
||||
|
||||
public bool DisallowLocationTypeChanges;
|
||||
|
||||
public string BaseName { get => baseName; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Biome Biome { get; set; }
|
||||
|
||||
public Vector2 MapPosition { get; private set; }
|
||||
@@ -309,7 +314,7 @@ namespace Barotrauma
|
||||
if (!faction.IsEmpty && GameMain.GameSession.Campaign.GetFactionAffiliation(faction) is FactionAffiliation.Positive)
|
||||
{
|
||||
price *= 1f - characters.Max(static c => c.GetStatValue(StatTypes.StoreBuyMultiplierAffiliated, includeSaved: false));
|
||||
price *= 1f - characters.Max(static c => c.Info.GetSavedStatValue(StatTypes.StoreBuyMultiplierAffiliated, new Identifier("all")));
|
||||
price *= 1f - characters.Max(static c => c.Info.GetSavedStatValue(StatTypes.StoreBuyMultiplierAffiliated, Tags.StatIdentifierTargetAll));
|
||||
price *= 1f - characters.Max(c => item.Tags.Sum(tag => c.Info.GetSavedStatValue(StatTypes.StoreBuyMultiplierAffiliated, tag)));
|
||||
}
|
||||
price *= 1f - characters.Max(static c => c.GetStatValue(StatTypes.StoreBuyMultiplier, includeSaved: false));
|
||||
@@ -484,7 +489,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (missionIndex < 0 || missionIndex >= availableMissions.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to select a mission in location \"{Name}\". Mission index out of bounds ({missionIndex}, available missions: {availableMissions.Count})");
|
||||
DebugConsole.ThrowError($"Failed to select a mission in location \"{DisplayName}\". Mission index out of bounds ({missionIndex}, available missions: {availableMissions.Count})");
|
||||
break;
|
||||
}
|
||||
selectedMissions.Add(availableMissions[missionIndex]);
|
||||
@@ -536,15 +541,15 @@ namespace Barotrauma
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Location ({Name ?? "null"})";
|
||||
return $"Location ({DisplayName ?? "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);
|
||||
CreateRandomName(Type, rand, existingLocations);
|
||||
MapPosition = mapPosition;
|
||||
PortraitId = ToolBox.StringToInt(Name);
|
||||
PortraitId = ToolBox.StringToInt(nameIdentifier.Value);
|
||||
Connections = new List<LocationConnection>();
|
||||
}
|
||||
|
||||
@@ -561,9 +566,21 @@ namespace Barotrauma
|
||||
GetTypeOrFallback(originalLocationTypeId, out LocationType originalType);
|
||||
OriginalType = originalType;
|
||||
|
||||
baseName = element.GetAttributeString("basename", "");
|
||||
Name = element.GetAttributeString("name", "");
|
||||
MapPosition = element.GetAttributeVector2("position", Vector2.Zero);
|
||||
nameIdentifier = element.GetAttributeIdentifier(nameof(nameIdentifier), "");
|
||||
if (nameIdentifier.IsEmpty)
|
||||
{
|
||||
//backwards compatibility
|
||||
rawName = element.GetAttributeString("basename", "");
|
||||
nameIdentifier = rawName.ToIdentifier();
|
||||
DisplayName = element.GetAttributeString("name", "");
|
||||
}
|
||||
else
|
||||
{
|
||||
nameFormatIndex = element.GetAttributeInt(nameof(nameFormatIndex), 0);
|
||||
DisplayName = GetName(Type, nameFormatIndex, nameIdentifier);
|
||||
}
|
||||
|
||||
MapPosition = element.GetAttributeVector2("position", Vector2.Zero);
|
||||
|
||||
PriceMultiplier = element.GetAttributeFloat("pricemultiplier", 1.0f);
|
||||
IsGateBetweenBiomes = element.GetAttributeBool("isgatebetweenbiomes", false);
|
||||
@@ -639,9 +656,9 @@ namespace Barotrauma
|
||||
System.Diagnostics.Debug.Assert(Type != null, $"Could not find the location type \"{locationTypeId}\"!");
|
||||
Type ??= LocationType.Prefabs.First();
|
||||
|
||||
LevelData = new LevelData(element.Element("Level"), clampDifficultyToBiome: true);
|
||||
LevelData = new LevelData(element.GetChildElement("Level"), clampDifficultyToBiome: true);
|
||||
|
||||
PortraitId = ToolBox.StringToInt(Name);
|
||||
PortraitId = ToolBox.StringToInt(!rawName.IsNullOrEmpty() ? rawName : nameIdentifier.Value);
|
||||
|
||||
LoadStores(element);
|
||||
LoadMissions(element);
|
||||
@@ -659,15 +676,12 @@ namespace Barotrauma
|
||||
if (type == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Could not find location type \"{identifier}\". Using location type \"None\" instead.");
|
||||
LocationType.Prefabs.TryGet("None".ToIdentifier(), out type);
|
||||
if (type == null)
|
||||
{
|
||||
type = LocationType.Prefabs.First();
|
||||
}
|
||||
LocationType.Prefabs.TryGet("None".ToIdentifier(), out type);
|
||||
type ??= LocationType.Prefabs.First();
|
||||
}
|
||||
if (type != null)
|
||||
{
|
||||
element.SetAttributeValue("type", type.Identifier);
|
||||
element.SetAttributeValue("type", type.Identifier.ToString());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -690,7 +704,7 @@ namespace Barotrauma
|
||||
int locationTypeChangeIndex = subElement.GetAttributeInt("index", 0);
|
||||
if (locationTypeChangeIndex < 0 || locationTypeChangeIndex >= Type.CanChangeTo.Count)
|
||||
{
|
||||
DebugConsole.AddWarning($"Failed to activate a location type change in the location \"{Name}\". Location index out of bounds ({locationTypeChangeIndex}).");
|
||||
DebugConsole.AddWarning($"Failed to activate a location type change in the location \"{DisplayName}\". Location index out of bounds ({locationTypeChangeIndex}).");
|
||||
continue;
|
||||
}
|
||||
PendingLocationTypeChange = (Type.CanChangeTo[locationTypeChangeIndex], timer, null);
|
||||
@@ -701,7 +715,7 @@ namespace Barotrauma
|
||||
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.");
|
||||
DebugConsole.AddWarning($"Failed to activate a location type change from the mission \"{missionIdentifier}\" in location \"{DisplayName}\". Matching mission not found.");
|
||||
continue;
|
||||
}
|
||||
PendingLocationTypeChange = (mission.LocationTypeChangeOnCompleted, timer, mission);
|
||||
@@ -738,14 +752,27 @@ namespace Barotrauma
|
||||
|
||||
if (newType == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to change the type of the location \"{Name}\" to null.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
DebugConsole.ThrowError($"Failed to change the type of the location \"{DisplayName}\" to null.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
DebugConsole.Log("Location " + baseName + " changed it's type from " + Type + " to " + newType);
|
||||
|
||||
Type = newType;
|
||||
Name = Type.NameFormats == null || !Type.NameFormats.Any() ? baseName : Type.NameFormats[nameFormatIndex % Type.NameFormats.Count].Replace("[name]", baseName);
|
||||
if (rawName != null)
|
||||
{
|
||||
DebugConsole.Log($"Location {rawName} changed it's type from {Type} to {newType}");
|
||||
DisplayName =
|
||||
Type.NameFormats == null || !Type.NameFormats.Any() ?
|
||||
rawName :
|
||||
Type.NameFormats[nameFormatIndex % Type.NameFormats.Count].Replace("[name]", rawName);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log($"Location {DisplayName.Value} changed it's type from {Type} to {newType}");
|
||||
DisplayName =
|
||||
Type.NameFormats == null || !Type.NameFormats.Any() ?
|
||||
TextManager.Get(nameIdentifier) :
|
||||
Type.NameFormats[nameFormatIndex % Type.NameFormats.Count].Replace("[name]", TextManager.Get(nameIdentifier).Value);
|
||||
}
|
||||
|
||||
if (Type.HasOutpost && Type.OutpostTeam == CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
@@ -776,11 +803,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (Type.MissionIdentifiers.Any())
|
||||
{
|
||||
UnlockMissionByIdentifier(Type.MissionIdentifiers.GetRandom(randSync));
|
||||
UnlockMissionByIdentifier(Type.MissionIdentifiers.GetRandom(randSync), invokingContentPackage: Type.ContentPackage);
|
||||
}
|
||||
if (Type.MissionTags.Any())
|
||||
{
|
||||
UnlockMissionByTag(Type.MissionTags.GetRandom(randSync));
|
||||
UnlockMissionByTag(Type.MissionTags.GetRandom(randSync), invokingContentPackage: Type.ContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,7 +825,7 @@ namespace Barotrauma
|
||||
AddMission(InstantiateMission(missionPrefab));
|
||||
}
|
||||
|
||||
public Mission UnlockMissionByIdentifier(Identifier identifier)
|
||||
public Mission UnlockMissionByIdentifier(Identifier identifier, ContentPackage invokingContentPackage = null)
|
||||
{
|
||||
if (AvailableMissions.Any(m => m.Prefab.Identifier == identifier)) { return null; }
|
||||
if (AvailableMissions.Any(m => !m.Prefab.AllowOtherMissionsInLevel)) { return null; }
|
||||
@@ -806,7 +833,8 @@ namespace Barotrauma
|
||||
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.");
|
||||
DebugConsole.ThrowError($"Failed to unlock a mission with the identifier \"{identifier}\": matching mission not found.",
|
||||
contentPackage: invokingContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -823,13 +851,13 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
public Mission UnlockMissionByTag(Identifier tag, Random random = null)
|
||||
public Mission UnlockMissionByTag(Identifier tag, Random random = null, ContentPackage invokingContentPackage = null)
|
||||
{
|
||||
if (AvailableMissions.Any(m => !m.Prefab.AllowOtherMissionsInLevel)) { return null; }
|
||||
var matchingMissions = MissionPrefab.Prefabs.Where(mp => mp.Tags.Contains(tag));
|
||||
if (matchingMissions.None())
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to unlock a mission with the tag \"{tag}\": no matching missions found.");
|
||||
DebugConsole.ThrowError($"Failed to unlock a mission with the tag \"{tag}\": no matching missions found.", contentPackage: invokingContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -841,7 +869,16 @@ namespace Barotrauma
|
||||
{
|
||||
suitableMissions = unusedMissions;
|
||||
}
|
||||
|
||||
var filteredMissions = suitableMissions.Where(m => LevelData.Difficulty >= m.MinLevelDifficulty && LevelData.Difficulty <= m.MaxLevelDifficulty);
|
||||
if (filteredMissions.None())
|
||||
{
|
||||
DebugConsole.AddWarning($"No suitable mission matching the level difficulty {LevelData.Difficulty} found with the tag \"{tag}\". Ignoring the restriction.",
|
||||
contentPackage: invokingContentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
suitableMissions = filteredMissions;
|
||||
}
|
||||
MissionPrefab missionPrefab =
|
||||
random != null ?
|
||||
ToolBox.SelectWeightedRandom(suitableMissions.OrderBy(m => m.Identifier), m => m.Commonness, random) :
|
||||
@@ -854,12 +891,13 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
AddMission(mission);
|
||||
DebugConsole.NewMessage($"Unlocked a random mission by \"{tag}\".", debugOnly: true);
|
||||
DebugConsole.NewMessage($"Unlocked a random mission by \"{tag}\": {mission.Prefab.Identifier} (difficulty level: {LevelData.Difficulty})", debugOnly: true);
|
||||
return mission;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.AddWarning($"Failed to unlock a mission with the tag \"{tag}\": all available missions have already been unlocked.");
|
||||
DebugConsole.AddWarning($"Failed to unlock a mission with the tag \"{tag}\": all available missions have already been unlocked.",
|
||||
contentPackage: invokingContentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -988,11 +1026,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (addInitialMissionsForType.MissionIdentifiers.Any())
|
||||
{
|
||||
UnlockMissionByIdentifier(addInitialMissionsForType.MissionIdentifiers.GetRandomUnsynced());
|
||||
UnlockMissionByIdentifier(addInitialMissionsForType.MissionIdentifiers.GetRandomUnsynced(), invokingContentPackage: Type.ContentPackage);
|
||||
}
|
||||
if (addInitialMissionsForType.MissionTags.Any())
|
||||
{
|
||||
UnlockMissionByTag(addInitialMissionsForType.MissionTags.GetRandomUnsynced());
|
||||
UnlockMissionByTag(addInitialMissionsForType.MissionTags.GetRandomUnsynced(), invokingContentPackage: Type.ContentPackage);
|
||||
}
|
||||
addInitialMissionsForType = null;
|
||||
}
|
||||
@@ -1050,12 +1088,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Type.HasHireableCharacters)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + Name + "\" - the location has no hireable characters.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + DisplayName + "\" - the location has no hireable characters.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
if (HireManager == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + Name + "\" - hire manager has not been instantiated.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
DebugConsole.ThrowError("Cannot hire a character from location \"" + DisplayName + "\" - hire manager has not been instantiated.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1078,22 +1116,52 @@ namespace Barotrauma
|
||||
return HireManager.AvailableCharacters;
|
||||
}
|
||||
|
||||
private string RandomName(LocationType type, Random rand, IEnumerable<Location> existingLocations)
|
||||
private void CreateRandomName(LocationType type, Random rand, IEnumerable<Location> existingLocations)
|
||||
{
|
||||
if (!type.ForceLocationName.IsNullOrEmpty())
|
||||
if (!type.ForceLocationName.IsEmpty)
|
||||
{
|
||||
baseName = type.ForceLocationName.Value;
|
||||
return baseName;
|
||||
nameIdentifier = type.ForceLocationName;
|
||||
DisplayName = TextManager.Get(nameIdentifier).Fallback(nameIdentifier.Value);
|
||||
return;
|
||||
}
|
||||
nameIdentifier = type.GetRandomNameId(rand, existingLocations);
|
||||
if (nameIdentifier.IsEmpty)
|
||||
{
|
||||
rawName = type.GetRandomRawName(rand, existingLocations);
|
||||
if (rawName.IsNullOrEmpty())
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to generate a name for a location of the type {type.Identifier}. No names found in localization files or the .txt files.");
|
||||
rawName = "none";
|
||||
}
|
||||
nameIdentifier = rawName.ToIdentifier();
|
||||
DisplayName = rawName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type.NameFormats == null || !type.NameFormats.Any())
|
||||
{
|
||||
DisplayName = TextManager.Get(nameIdentifier).Fallback(nameIdentifier.Value);
|
||||
return;
|
||||
}
|
||||
nameFormatIndex = rand.Next() % type.NameFormats.Count;
|
||||
DisplayName = GetName(Type, nameFormatIndex, nameIdentifier);
|
||||
}
|
||||
baseName = type.GetRandomName(rand, existingLocations);
|
||||
if (type.NameFormats == null || !type.NameFormats.Any()) { return baseName; }
|
||||
nameFormatIndex = rand.Next() % type.NameFormats.Count;
|
||||
return type.NameFormats[nameFormatIndex].Replace("[name]", baseName);
|
||||
}
|
||||
|
||||
public void ForceName(string name)
|
||||
private static LocalizedString GetName(LocationType type, int nameFormatIndex, Identifier nameId)
|
||||
{
|
||||
baseName = Name = name;
|
||||
if (type?.NameFormats == null || !type.NameFormats.Any())
|
||||
{
|
||||
return TextManager.Get(nameId);
|
||||
}
|
||||
return type.NameFormats[nameFormatIndex % type.NameFormats.Count].Replace("[name]", TextManager.Get(nameId).Value);
|
||||
}
|
||||
|
||||
public void ForceName(Identifier nameId)
|
||||
{
|
||||
rawName = string.Empty;
|
||||
nameIdentifier = nameId;
|
||||
DisplayName = TextManager.Get(nameId).Fallback(nameId.Value);
|
||||
}
|
||||
|
||||
public void LoadStores(XElement locationElement)
|
||||
@@ -1117,7 +1185,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = $"Error loading store info for \"{identifier}\" at location {Name} of type \"{Type.Identifier}\": duplicate identifier.";
|
||||
string msg = $"Error loading store info for \"{identifier}\" at location {DisplayName} of type \"{Type.Identifier}\": duplicate identifier.";
|
||||
DebugConsole.ThrowError(msg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Location.LoadStore:DuplicateStoreInfo", GameAnalyticsManager.ErrorSeverity.Error, msg);
|
||||
continue;
|
||||
@@ -1125,7 +1193,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
string msg = $"Error loading store info for \"{identifier}\" at location {Name} of type \"{Type.Identifier}\": location shouldn't contain a store with this identifier.";
|
||||
string msg = $"Error loading store info for \"{identifier}\" at location {DisplayName} of type \"{Type.Identifier}\": location shouldn't contain a store with this identifier.";
|
||||
DebugConsole.ThrowError(msg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Location.LoadStore:IncorrectStoreIdentifier", GameAnalyticsManager.ErrorSeverity.Error, msg);
|
||||
continue;
|
||||
@@ -1436,8 +1504,9 @@ namespace Barotrauma
|
||||
var locationElement = new XElement("location",
|
||||
new XAttribute("type", Type.Identifier),
|
||||
new XAttribute("originaltype", (Type ?? OriginalType).Identifier),
|
||||
new XAttribute("basename", BaseName),
|
||||
new XAttribute("name", Name),
|
||||
/*not used currently (we load the nameIdentifier instead),
|
||||
* but could make sense to include still for backwards compatibility reasons*/
|
||||
new XAttribute("name", DisplayName),
|
||||
new XAttribute("biome", Biome?.Identifier.Value ?? string.Empty),
|
||||
new XAttribute("position", XMLExtensions.Vector2ToString(MapPosition)),
|
||||
new XAttribute("pricemultiplier", PriceMultiplier),
|
||||
@@ -1447,6 +1516,16 @@ namespace Barotrauma
|
||||
new XAttribute(nameof(TurnsInRadiation).ToLower(), TurnsInRadiation),
|
||||
new XAttribute("stepssincespecialsupdated", StepsSinceSpecialsUpdated));
|
||||
|
||||
if (!rawName.IsNullOrEmpty())
|
||||
{
|
||||
locationElement.Add(new XAttribute(nameof(rawName), rawName));
|
||||
}
|
||||
else
|
||||
{
|
||||
locationElement.Add(new XAttribute(nameof(nameIdentifier), nameIdentifier));
|
||||
locationElement.Add(new XAttribute(nameof(nameFormatIndex), nameFormatIndex));
|
||||
}
|
||||
|
||||
if (Faction != null)
|
||||
{
|
||||
locationElement.Add(new XAttribute("faction", Faction.Prefab.Identifier));
|
||||
@@ -1483,7 +1562,7 @@ namespace Barotrauma
|
||||
changeElement.Add(new XAttribute("index", index));
|
||||
if (index == -1)
|
||||
{
|
||||
DebugConsole.AddWarning($"Invalid location type change in the location \"{Name}\". Unknown type change ({PendingLocationTypeChange.Value.typeChange.ChangeToType}).");
|
||||
DebugConsole.AddWarning($"Invalid location type change in the location \"{DisplayName}\". Unknown type change ({PendingLocationTypeChange.Value.typeChange.ChangeToType}).");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -13,7 +14,7 @@ namespace Barotrauma
|
||||
{
|
||||
public static readonly PrefabCollection<LocationType> Prefabs = new PrefabCollection<LocationType>();
|
||||
|
||||
private readonly ImmutableArray<string> names;
|
||||
private readonly ImmutableArray<string> rawNames;
|
||||
private readonly ImmutableArray<Sprite> portraits;
|
||||
|
||||
//<name, commonness>
|
||||
@@ -26,7 +27,7 @@ namespace Barotrauma
|
||||
public readonly LocalizedString Name;
|
||||
public readonly LocalizedString Description;
|
||||
|
||||
public readonly LocalizedString ForceLocationName;
|
||||
public readonly Identifier ForceLocationName;
|
||||
|
||||
public readonly float BeaconStationChance;
|
||||
|
||||
@@ -54,12 +55,20 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
private readonly ImmutableArray<Identifier>? nameIdentifiers = null;
|
||||
|
||||
private LanguageIdentifier nameFormatLanguage;
|
||||
|
||||
private ImmutableArray<string>? nameFormats = null;
|
||||
public IReadOnlyList<string> NameFormats
|
||||
{
|
||||
get
|
||||
{
|
||||
nameFormats ??= TextManager.GetAll($"LocationNameFormat.{Identifier}").ToImmutableArray();
|
||||
if (nameFormats == null || GameSettings.CurrentConfig.Language != nameFormatLanguage)
|
||||
{
|
||||
nameFormats = TextManager.GetAll($"LocationNameFormat.{Identifier}").ToImmutableArray();
|
||||
nameFormatLanguage = GameSettings.CurrentConfig.Language;
|
||||
}
|
||||
return nameFormats;
|
||||
}
|
||||
}
|
||||
@@ -143,29 +152,37 @@ namespace Barotrauma
|
||||
|
||||
if (element.GetAttribute("name") != null)
|
||||
{
|
||||
ForceLocationName = TextManager.Get(element.GetAttributeString("name", string.Empty));
|
||||
ForceLocationName = element.GetAttributeIdentifier("name", string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] rawNamePaths = element.GetAttributeStringArray("namefile", new string[] { "Content/Map/locationNames.txt" });
|
||||
var names = new List<string>();
|
||||
foreach (string rawPath in rawNamePaths)
|
||||
//backwards compatibility for location names defined in a text file
|
||||
string[] rawNamePaths = element.GetAttributeStringArray("namefile", Array.Empty<string>());
|
||||
if (rawNamePaths.Any())
|
||||
{
|
||||
try
|
||||
foreach (string rawPath in rawNamePaths)
|
||||
{
|
||||
var path = ContentPath.FromRaw(element.ContentPackage, rawPath.Trim());
|
||||
names.AddRange(File.ReadAllLines(path.Value).ToList());
|
||||
try
|
||||
{
|
||||
var path = ContentPath.FromRaw(element.ContentPackage, rawPath.Trim());
|
||||
names.AddRange(File.ReadAllLines(path.Value).ToList());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to read name file \"rawPath\" for location type \"{Identifier}\"!", e);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
if (!names.Any())
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to read name file \"rawPath\" for location type \"{Identifier}\"!", e);
|
||||
names.Add("ERROR: No names found");
|
||||
}
|
||||
this.rawNames = names.ToImmutableArray();
|
||||
}
|
||||
if (!names.Any())
|
||||
else
|
||||
{
|
||||
names.Add("ERROR: No names found");
|
||||
nameIdentifiers = element.GetAttributeIdentifierArray("nameidentifiers", new Identifier[] { Identifier }).ToImmutableArray();
|
||||
}
|
||||
this.names = names.ToImmutableArray();
|
||||
}
|
||||
|
||||
string[] commonnessPerZoneStrs = element.GetAttributeStringArray("commonnessperzone", Array.Empty<string>());
|
||||
@@ -259,17 +276,64 @@ namespace Barotrauma
|
||||
return portraits[Math.Abs(randomSeed) % portraits.Length];
|
||||
}
|
||||
|
||||
public string GetRandomName(Random rand, IEnumerable<Location> existingLocations)
|
||||
public Identifier GetRandomNameId(Random rand, IEnumerable<Location> existingLocations)
|
||||
{
|
||||
if (nameIdentifiers == null)
|
||||
{
|
||||
return Identifier.Empty;
|
||||
}
|
||||
List<Identifier> nameIds = new List<Identifier>();
|
||||
foreach (var nameId in nameIdentifiers)
|
||||
{
|
||||
int index = 0;
|
||||
while (true)
|
||||
{
|
||||
Identifier tag = $"LocationName.{nameId}.{index}".ToIdentifier();
|
||||
if (TextManager.ContainsTag(tag, TextManager.DefaultLanguage))
|
||||
{
|
||||
nameIds.Add(tag);
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find any location names for the location type {Identifier}. Name identifier: {nameId}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nameIds.None())
|
||||
{
|
||||
return Identifier.Empty;
|
||||
}
|
||||
if (existingLocations != null)
|
||||
{
|
||||
var unusedNames = names.Where(name => !existingLocations.Any(l => l.BaseName == name)).ToList();
|
||||
var unusedNameIds = nameIds.FindAll(nameId => existingLocations.None(l => l.NameIdentifier == nameId));
|
||||
if (unusedNameIds.Count > 0)
|
||||
{
|
||||
return unusedNameIds[rand.Next() % unusedNameIds.Count];
|
||||
}
|
||||
}
|
||||
return nameIds[rand.Next() % nameIds.Count];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For backwards compatibility. Chooses a random name from the names defined in the .txt name files (<see cref="rawNamePaths"/>).
|
||||
/// </summary>
|
||||
public string GetRandomRawName(Random rand, IEnumerable<Location> existingLocations)
|
||||
{
|
||||
if (rawNames == null || rawNames.None()) { return string.Empty; }
|
||||
if (existingLocations != null)
|
||||
{
|
||||
var unusedNames = rawNames.Where(name => !existingLocations.Any(l => l.DisplayName.Value == name)).ToList();
|
||||
if (unusedNames.Count > 0)
|
||||
{
|
||||
return unusedNames[rand.Next() % unusedNames.Count];
|
||||
}
|
||||
}
|
||||
return names[rand.Next() % names.Length];
|
||||
return rawNames[rand.Next() % rawNames.Length];
|
||||
}
|
||||
|
||||
public static LocationType Random(Random rand, int? zone = null, bool requireOutpost = false, Func<LocationType, bool> predicate = null)
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public readonly bool RequireHuntingGrounds;
|
||||
|
||||
public Requirement(XElement element, LocationTypeChange change)
|
||||
public Requirement(ContentXElement element, LocationTypeChange change)
|
||||
{
|
||||
RequiredLocations = element.GetAttributeIdentifierArray("requiredlocations", element.GetAttributeIdentifierArray("requiredadjacentlocations", Array.Empty<Identifier>())).ToImmutableArray();
|
||||
RequiredProximity = Math.Max(element.GetAttributeInt("requiredproximity", 1), 0);
|
||||
@@ -80,13 +80,15 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.AddWarning(
|
||||
$"Invalid location type change in location type \"{change.CurrentType}\". " +
|
||||
"Probability is configured to increase when near some other type of location, but the RequiredLocations attribute is not set.");
|
||||
"Probability is configured to increase when near some other type of location, but the RequiredLocations attribute is not set.",
|
||||
element.ContentPackage);
|
||||
}
|
||||
if (Probability >= 1.0f)
|
||||
{
|
||||
DebugConsole.AddWarning(
|
||||
$"Invalid location type change in location type \"{change.CurrentType}\". " +
|
||||
"Probability is configured to increase when near some other type of location, but the base probability is already 100%");
|
||||
"Probability is configured to increase when near some other type of location, but the base probability is already 100%",
|
||||
element.ContentPackage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +175,7 @@ namespace Barotrauma
|
||||
|
||||
public readonly Point RequiredDurationRange;
|
||||
|
||||
public LocationTypeChange(Identifier currentType, XElement element, bool requireChangeMessages, float defaultProbability = 0.0f)
|
||||
public LocationTypeChange(Identifier currentType, ContentXElement element, bool requireChangeMessages, float defaultProbability = 0.0f)
|
||||
{
|
||||
CurrentType = currentType;
|
||||
ChangeToType = element.GetAttributeIdentifier("type", element.GetAttributeIdentifier("to", ""));
|
||||
@@ -190,13 +192,13 @@ namespace Barotrauma
|
||||
CooldownAfterChange = Math.Max(element.GetAttributeInt("cooldownafterchange", 0), 0);
|
||||
|
||||
//backwards compatibility
|
||||
if (element.Attribute("requiredlocations") != null)
|
||||
if (element.GetAttribute("requiredlocations") != null)
|
||||
{
|
||||
Requirements.Add(new Requirement(element, this));
|
||||
}
|
||||
|
||||
//backwards compatibility
|
||||
if (element.Attribute("requiredduration") != null)
|
||||
if (element.GetAttribute("requiredduration") != null)
|
||||
{
|
||||
RequiredDurationRange = new Point(element.GetAttributeInt("requiredduration", 0));
|
||||
}
|
||||
|
||||
@@ -262,9 +262,9 @@ namespace Barotrauma
|
||||
foreach (var endLocation in EndLocations)
|
||||
{
|
||||
if (endLocation.Type?.ForceLocationName != null &&
|
||||
!endLocation.Type.ForceLocationName.IsNullOrEmpty())
|
||||
!endLocation.Type.ForceLocationName.IsEmpty)
|
||||
{
|
||||
endLocation.ForceName(endLocation.Type.ForceLocationName.Value);
|
||||
endLocation.ForceName(endLocation.Type.ForceLocationName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1005,10 +1005,10 @@ namespace Barotrauma
|
||||
CurrentLocation.CreateStores();
|
||||
OnLocationChanged?.Invoke(new LocationChangeInfo(prevLocation, CurrentLocation));
|
||||
|
||||
if (GameMain.GameSession is { Campaign: { CampaignMetadata: { } metadata } })
|
||||
if (GameMain.GameSession is { Campaign.CampaignMetadata: { } metadata })
|
||||
{
|
||||
metadata.SetValue("campaign.location.id".ToIdentifier(), CurrentLocationIndex);
|
||||
metadata.SetValue("campaign.location.name".ToIdentifier(), CurrentLocation.Name);
|
||||
metadata.SetValue("campaign.location.name".ToIdentifier(), CurrentLocation.NameIdentifier.Value);
|
||||
metadata.SetValue("campaign.location.biome".ToIdentifier(), CurrentLocation.Biome?.Identifier ?? "null".ToIdentifier());
|
||||
metadata.SetValue("campaign.location.type".ToIdentifier(), CurrentLocation.Type?.Identifier ?? "null".ToIdentifier());
|
||||
}
|
||||
@@ -1077,7 +1077,7 @@ namespace Barotrauma
|
||||
if (SelectedConnection?.Locked ?? false)
|
||||
{
|
||||
string errorMsg =
|
||||
$"A locked connection was selected ({SelectedConnection.Locations[0].Name} -> {SelectedConnection.Locations[1].Name}." +
|
||||
$"A locked connection was selected ({SelectedConnection.Locations[0].DisplayName} -> {SelectedConnection.Locations[1].DisplayName}." +
|
||||
$" Current location: {CurrentLocation}, current display location: {currentDisplayLocation}).\n"
|
||||
+ Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("MapSelectLocation:LockedConnectionSelected", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
@@ -1093,7 +1093,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!Locations.Contains(location))
|
||||
{
|
||||
string errorMsg = "Failed to select a location. " + (location?.Name ?? "null") + " not found in the map.";
|
||||
string errorMsg = $"Failed to select a location. {location?.DisplayName ?? "null"} not found in the map.";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Map.SelectLocation:LocationNotFound", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
@@ -1301,11 +1301,11 @@ namespace Barotrauma
|
||||
|
||||
private bool ChangeLocationType(CampaignMode campaign, Location location, LocationTypeChange change)
|
||||
{
|
||||
string prevName = location.Name;
|
||||
LocalizedString prevName = location.DisplayName;
|
||||
|
||||
if (!LocationType.Prefabs.TryGet(change.ChangeToType, out var newType))
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to change the type of the location \"{location.Name}\". Location type \"{change.ChangeToType}\" not found.");
|
||||
DebugConsole.ThrowError($"Failed to change the type of the location \"{location.DisplayName}\". Location type \"{change.ChangeToType}\" not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1372,7 +1372,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
partial void ChangeLocationTypeProjSpecific(Location location, string prevName, LocationTypeChange change);
|
||||
partial void ChangeLocationTypeProjSpecific(Location location, LocalizedString prevName, LocationTypeChange change);
|
||||
|
||||
partial void ClearAnimQueue();
|
||||
|
||||
@@ -1498,7 +1498,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Identifier locationType = subElement.GetAttributeIdentifier("type", Identifier.Empty);
|
||||
string prevLocationName = location.Name;
|
||||
LocalizedString prevLocationName = location.DisplayName;
|
||||
LocationType prevLocationType = location.Type;
|
||||
LocationType newLocationType = LocationType.Prefabs.Find(lt => lt.Identifier == locationType) ?? LocationType.Prefabs.First();
|
||||
location.ChangeType(campaign, newLocationType);
|
||||
@@ -1619,7 +1619,7 @@ namespace Barotrauma
|
||||
//this should not be possible, you can't enter non-outpost locations (= natural formations)
|
||||
if (CurrentLocation != null && !CurrentLocation.Type.HasOutpost && SelectedConnection == null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error while loading campaign map state. Submarine in a location with no outpost ({CurrentLocation.Name}). Loading the first adjacent connection...");
|
||||
DebugConsole.AddWarning($"Error while loading campaign map state. Submarine in a location with no outpost ({CurrentLocation.DisplayName}). Loading the first adjacent connection...");
|
||||
SelectLocation(CurrentLocation.Connections[0].OtherLocation(CurrentLocation));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user