Merge remote-tracking branch 'upstream/master' into develop

This commit is contained in:
EvilFactory
2024-04-24 12:20:11 -03:00
397 changed files with 15250 additions and 6473 deletions
@@ -147,6 +147,8 @@ namespace Barotrauma
public bool DivingSuitWarningShown;
public bool ItemsRelocatedToMainSub;
private static bool AnyOneAllowedToManageCampaign(ClientPermissions permissions)
{
if (GameMain.NetworkMember == null) { return true; }
@@ -878,7 +880,7 @@ namespace Barotrauma
}
}
foreach (CharacterInfo ci in CrewManager.CharacterInfos.ToList())
foreach (CharacterInfo ci in CrewManager.GetCharacterInfos().ToList())
{
if (ci.CauseOfDeath != null)
{
@@ -979,7 +981,7 @@ namespace Barotrauma
Preset?.Identifier.Value ?? "none");
string eventId = "FinishCampaign:";
GameAnalyticsManager.AddDesignEvent(eventId + "Submarine:" + (Submarine.MainSub?.Info?.Name ?? "none"));
GameAnalyticsManager.AddDesignEvent(eventId + "CrewSize:" + (CrewManager?.CharacterInfos?.Count() ?? 0));
GameAnalyticsManager.AddDesignEvent(eventId + "CrewSize:" + (CrewManager?.GetCharacterInfos()?.Count() ?? 0));
GameAnalyticsManager.AddDesignEvent(eventId + "Money", Bank.Balance);
GameAnalyticsManager.AddDesignEvent(eventId + "Playtime", TotalPlayTime);
GameAnalyticsManager.AddDesignEvent(eventId + "PassedLevels", TotalPassedLevels);
@@ -1024,7 +1026,7 @@ namespace Barotrauma
return ToolBox.SelectWeightedRandom(factionsList, weights, random);
}
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, Character hirer, Client client = null)
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, bool takeMoney = true, Client client = null)
{
if (characterInfo == null) { return false; }
if (characterInfo.MinReputationToHire.factionId != Identifier.Empty)
@@ -1034,8 +1036,8 @@ namespace Barotrauma
return false;
}
}
if (takeMoney && !TryPurchase(client, HireManager.GetSalaryFor(characterInfo))) { return false; }
if (!TryPurchase(client, HireManager.GetSalaryFor(characterInfo))) { return false; }
characterInfo.IsNewHire = true;
characterInfo.Title = null;
location.RemoveHireableCharacter(characterInfo);
@@ -1047,7 +1049,6 @@ namespace Barotrauma
private void NPCInteract(Character npc, Character interactor)
{
if (!npc.AllowCustomInteract) { return; }
GameAnalyticsManager.AddDesignEvent("CampaignInteraction:" + Preset.Identifier + ":" + npc.CampaignInteractionType);
NPCInteractProjSpecific(npc, interactor);
string coroutineName = "DoCharacterWait." + (npc?.ID ?? Entity.NullEntityID);
if (!CoroutineManager.IsCoroutineRunning(coroutineName))
@@ -8,7 +8,7 @@ namespace Barotrauma
internal static class CampaignModePresets
{
public static readonly ImmutableArray<CampaignSettings> List;
public static readonly ImmutableDictionary<Identifier, CampaignSettingDefinitions> Definitions;
private static readonly ImmutableDictionary<Identifier, CampaignSettingDefinitions> definitions;
private static readonly string fileListPath = Path.Combine("Data", "campaignsettings.xml");
@@ -20,73 +20,58 @@ namespace Barotrauma
return;
}
List<CampaignSettings> list = new List<CampaignSettings>();
Dictionary<Identifier, CampaignSettingDefinitions> definitions = new Dictionary<Identifier, CampaignSettingDefinitions>();
List<CampaignSettings> presetList = new List<CampaignSettings>();
Dictionary<Identifier, CampaignSettingDefinitions> tempDefinitions = new Dictionary<Identifier, CampaignSettingDefinitions>();
foreach (XElement element in docRoot.Elements())
{
Identifier name = element.NameAsIdentifier();
// The campaign setting presets
if (name == CampaignSettings.LowerCaseSaveElementName)
{
list.Add(new CampaignSettings(element));
presetList.Add(new CampaignSettings(element));
}
// All the definitions for the setting value options
else if (name == nameof(CampaignSettingDefinitions))
{
// The single definitions that the settings may refer to (eg. PatdownProbabilityMin)
foreach (XElement subElement in element.Elements())
{
definitions.Add(subElement.NameAsIdentifier(), new CampaignSettingDefinitions(subElement));
tempDefinitions.Add(subElement.NameAsIdentifier(), new CampaignSettingDefinitions(subElement));
}
}
}
List = list.ToImmutableArray();
Definitions = definitions.ToImmutableDictionary();
List = presetList.ToImmutableArray();
definitions = tempDefinitions.ToImmutableDictionary();
}
public static bool TryGetAttribute(Identifier propertyName, Identifier attributeName, out XAttribute attribute)
{
attribute = null;
if (definitions.TryGetValue(propertyName, out CampaignSettingDefinitions definition))
{
if (definition.Attributes.TryGetValue(attributeName, out XAttribute att))
{
attribute = att;
return true;
}
}
return false;
}
}
internal readonly struct CampaignSettingDefinitions
{
// Definitely not the best way to do this
private readonly ImmutableDictionary<Identifier, Either<int, float>> values;
public readonly ImmutableDictionary<Identifier, XAttribute> Attributes;
public CampaignSettingDefinitions(XElement element)
{
var definitions = new Dictionary<Identifier, Either<int, float>>();
foreach (XAttribute attribute in element.Attributes())
{
Identifier name = attribute.NameAsIdentifier();
if (attribute.Value.Contains('.'))
{
definitions.Add(name, element.GetAttributeFloat(name.Value, 0));
}
else
{
definitions.Add(name, element.GetAttributeInt(name.Value, 0));
}
}
values = definitions.ToImmutableDictionary();
}
public float GetFloat(Identifier identifier)
{
float range = 0;
if (!values.TryGetValue(identifier, out Either<int, float> value) || !value.TryGet(out range))
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {identifier}");
}
return range;
}
public int GetInt(Identifier identifier)
{
int integer = 0;
if (!values.TryGetValue(identifier, out Either<int, float> value) || !value.TryGet(out integer))
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {identifier}");
}
return integer;
Attributes = element.Attributes().ToImmutableDictionary(
a => a.NameAsIdentifier(),
a => a
);
}
}
}
@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using Microsoft.Xna.Framework;
using System.Collections.Generic;
@@ -27,6 +27,10 @@ namespace Barotrauma
[Serialize(false, IsPropertySaveable.Yes), NetworkSerialize]
public bool RadiationEnabled { get; set; }
public const int DefaultMaxMissionCount = 2;
public const int MaxMissionCountLimit = 10;
public const int MinMissionCountLimit = 1;
private int maxMissionCount;
[Serialize(DefaultMaxMissionCount, IsPropertySaveable.Yes), NetworkSerialize(MinValueInt = MinMissionCountLimit, MaxValueInt = MaxMissionCountLimit)]
@@ -38,60 +42,200 @@ namespace Barotrauma
public int TotalMaxMissionCount => MaxMissionCount + GetAddedMissionCount();
[Serialize(StartingBalanceAmount.Medium, IsPropertySaveable.Yes), NetworkSerialize]
public StartingBalanceAmount StartingBalanceAmount { get; set; }
[Serialize(GameDifficulty.Medium, IsPropertySaveable.Yes), NetworkSerialize]
public GameDifficulty Difficulty { get; set; }
[Serialize(WorldHostilityOption.Medium, IsPropertySaveable.Yes), NetworkSerialize]
public WorldHostilityOption WorldHostility { get; set; }
[Serialize("normal", IsPropertySaveable.Yes), NetworkSerialize]
public Identifier StartItemSet { get; set; }
[Serialize(StartingBalanceAmountOption.Medium, IsPropertySaveable.Yes), NetworkSerialize]
public StartingBalanceAmountOption StartingBalanceAmount { get; set; }
private int? _initialMoney;
public const int DefaultInitialMoney = 8000;
public int InitialMoney
{
get
{
if (CampaignModePresets.Definitions.TryGetValue(nameof(StartingBalanceAmount).ToIdentifier(), out var definition))
if (_initialMoney is int alreadyCachedValue)
{
return definition.GetInt(StartingBalanceAmount.ToIdentifier());
return alreadyCachedValue;
}
else
{
_initialMoney = DefaultInitialMoney;
Identifier settingDefinitionIdentifier = nameof(StartingBalanceAmount).ToIdentifier();
Identifier attributeIdentifier = StartingBalanceAmount.ToIdentifier();
if (CampaignModePresets.TryGetAttribute(settingDefinitionIdentifier, attributeIdentifier, out XAttribute? attribute))
{
_initialMoney = attribute.GetAttributeInt(DefaultInitialMoney);
}
else
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {attributeIdentifier} in {settingDefinitionIdentifier}");
}
return _initialMoney ?? DefaultInitialMoney;
}
return 8000;
}
}
private float? _extraEventManagerDifficulty;
private const float defaultExtraEventManagerDifficulty = 0;
public float ExtraEventManagerDifficulty
{
get
{
if (CampaignModePresets.Definitions.TryGetValue(nameof(ExtraEventManagerDifficulty).ToIdentifier(), out var definition))
if (_extraEventManagerDifficulty is float alreadyCachedValue)
{
return definition.GetFloat(Difficulty.ToIdentifier());
return alreadyCachedValue;
}
else
{
_extraEventManagerDifficulty = defaultExtraEventManagerDifficulty;
Identifier settingDefinitionIdentifier = nameof(ExtraEventManagerDifficulty).ToIdentifier();
Identifier attributeIdentifier = WorldHostility.ToIdentifier();
if (CampaignModePresets.TryGetAttribute(settingDefinitionIdentifier, attributeIdentifier, out XAttribute? attribute))
{
_extraEventManagerDifficulty = attribute.GetAttributeFloat(defaultExtraEventManagerDifficulty);
}
else
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {attributeIdentifier} in {settingDefinitionIdentifier}");
}
return _extraEventManagerDifficulty ?? defaultExtraEventManagerDifficulty;
}
return 0;
}
}
private float? _levelDifficultyMultiplier;
private const float defaultLevelDifficultyMultiplier = 1.0f;
public float LevelDifficultyMultiplier
{
get
{
if (CampaignModePresets.Definitions.TryGetValue(nameof(LevelDifficultyMultiplier).ToIdentifier(), out var definition))
if (_levelDifficultyMultiplier is float alreadyCachedValue)
{
return definition.GetFloat(Difficulty.ToIdentifier());
return alreadyCachedValue;
}
else
{
_levelDifficultyMultiplier = defaultLevelDifficultyMultiplier;
Identifier settingDefinitionIdentifier = nameof(LevelDifficultyMultiplier).ToIdentifier();
Identifier attributeIdentifier = WorldHostility.ToIdentifier();
if (CampaignModePresets.TryGetAttribute(settingDefinitionIdentifier, attributeIdentifier, out XAttribute? attribute))
{
_levelDifficultyMultiplier = attribute.GetAttributeFloat(defaultLevelDifficultyMultiplier);
}
else
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {attributeIdentifier} in {settingDefinitionIdentifier}");
}
return _levelDifficultyMultiplier ?? defaultLevelDifficultyMultiplier;
}
return 1.0f;
}
}
[Serialize(0.2f, IsPropertySaveable.Yes, description: "How likely it is for security to inspect player characters for stolen items when your reputation is high?")]
public float MinStolenItemInspectionProbability { get; set; }
private static readonly Dictionary<string, MultiplierSettings> _multiplierSettings = new Dictionary<string, MultiplierSettings>
{
{ "default", new MultiplierSettings { Min = 0.2f, Max = 2.0f, Step = 0.1f } },
{ nameof(CrewVitalityMultiplier), new MultiplierSettings { Min = 0.5f, Max = 2.0f, Step = 0.1f } },
{ nameof(NonCrewVitalityMultiplier),new MultiplierSettings { Min = 0.5f, Max = 3.0f, Step = 0.1f } },
{ nameof(MissionRewardMultiplier), new MultiplierSettings { Min = 0.5f, Max = 2.0f, Step = 0.1f } },
{ nameof(RepairFailMultiplier), new MultiplierSettings { Min = 0.5f, Max = 5.0f, Step = 0.5f } },
{ nameof(ShopPriceMultiplier), new MultiplierSettings { Min = 0.1f, Max = 3.0f, Step = 0.1f } },
{ nameof(ShipyardPriceMultiplier), new MultiplierSettings { Min = 0.1f, Max = 3.0f, Step = 0.1f } }
// Add overrides for default values here
};
[Serialize(0.9f, IsPropertySaveable.Yes, description: "How likely it is for security to inspect player characters for stolen items when your reputation is low?")]
public float MaxStolenItemInspectionProbability { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float CrewVitalityMultiplier { get; set; }
public const int DefaultMaxMissionCount = 2;
public const int MaxMissionCountLimit = 10;
public const int MinMissionCountLimit = 1;
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float NonCrewVitalityMultiplier { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float OxygenMultiplier { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float FuelMultiplier { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float MissionRewardMultiplier { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float ShopPriceMultiplier { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float ShipyardPriceMultiplier { get; set; }
[Serialize(1.0f, IsPropertySaveable.Yes), NetworkSerialize]
public float RepairFailMultiplier { get; set; }
[Serialize(true, IsPropertySaveable.Yes), NetworkSerialize]
public bool ShowHuskWarning { get; set; }
[Serialize(PatdownProbabilityOption.Medium, IsPropertySaveable.Yes), NetworkSerialize]
public PatdownProbabilityOption PatdownProbability { get; set; }
private float? _minPatdownProbability;
private float? _maxPatdownProbability;
public const float DefaultMinPatdownProbability = 0.2f;
public const float DefaultMaxPatdownProbability = 0.9f;
public float PatdownProbabilityMin
{
get
{
if (_minPatdownProbability is float alreadyCachedValue)
{
return alreadyCachedValue;
}
else
{
_minPatdownProbability = DefaultMinPatdownProbability;
Identifier settingDefinitionIdentifier = nameof(PatdownProbabilityMin).ToIdentifier();
Identifier attributeIdentifier = PatdownProbability.ToIdentifier();
if (CampaignModePresets.TryGetAttribute(settingDefinitionIdentifier, attributeIdentifier, out XAttribute? attribute))
{
_minPatdownProbability = attribute.GetAttributeFloat(DefaultMinPatdownProbability);
}
else
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {attributeIdentifier} in {settingDefinitionIdentifier}");
}
return _minPatdownProbability ?? DefaultMinPatdownProbability;
}
}
}
public float PatdownProbabilityMax
{
get
{
if (_maxPatdownProbability is float alreadyCachedValue)
{
return alreadyCachedValue;
}
else
{
_maxPatdownProbability = DefaultMaxPatdownProbability;
Identifier settingDefinitionIdentifier = nameof(PatdownProbabilityMax).ToIdentifier();
Identifier attributeIdentifier = PatdownProbability.ToIdentifier();
if (CampaignModePresets.TryGetAttribute(settingDefinitionIdentifier, attributeIdentifier, out XAttribute? attribute))
{
_maxPatdownProbability = attribute.GetAttributeFloat(DefaultMaxPatdownProbability);
}
else
{
DebugConsole.ThrowError($"CampaignSettings: Can't find value for {attributeIdentifier} in {settingDefinitionIdentifier}");
}
return _maxPatdownProbability ?? DefaultMaxPatdownProbability;
}
}
}
public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; private set; }
@@ -119,5 +263,22 @@ namespace Barotrauma
if (!characters.Any()) { return 0; }
return characters.Max(static character => (int)character.GetStatValue(StatTypes.ExtraMissionCount));
}
public struct MultiplierSettings
{
public float Min { get; set; }
public float Max { get; set; }
public float Step { get; set; }
}
public static MultiplierSettings GetMultiplierSettings(string multiplierName)
{
if (_multiplierSettings.TryGetValue(multiplierName, out MultiplierSettings value))
{
return value;
}
return _multiplierSettings["default"];
}
}
}