Merge branch 'faction-test'

# Conflicts:
#	Barotrauma/BarotraumaClient/ClientSource/Characters/Character.cs
#	Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs
#	Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs
#	Barotrauma/BarotraumaClient/ClientSource/Characters/Limb.cs
#	Barotrauma/BarotraumaClient/ClientSource/DebugConsole.cs
#	Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs
#	Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs
#	Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs
#	Barotrauma/BarotraumaClient/ClientSource/GUI/TalentMenu.cs
#	Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs
#	Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs
#	Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/SinglePlayerCampaign.cs
#	Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs
#	Barotrauma/BarotraumaClient/ClientSource/Items/Components/LightComponent.cs
#	Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Fabricator.cs
#	Barotrauma/BarotraumaClient/ClientSource/Items/ItemPrefab.cs
#	Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs
#	Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs
#	Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs
#	Barotrauma/BarotraumaClient/ClientSource/Particles/ParticleEmitter.cs
#	Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/CampaignSetupUI.cs
#	Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs
#	Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs
#	Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs
#	Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs
#	Barotrauma/BarotraumaClient/ClientSource/Screens/TestScreen.cs
#	Barotrauma/BarotraumaClient/LinuxClient.csproj
#	Barotrauma/BarotraumaClient/MacClient.csproj
#	Barotrauma/BarotraumaClient/WindowsClient.csproj
#	Barotrauma/BarotraumaServer/LinuxServer.csproj
#	Barotrauma/BarotraumaServer/MacServer.csproj
#	Barotrauma/BarotraumaServer/ServerSource/DebugConsole.cs
#	Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs
#	Barotrauma/BarotraumaServer/ServerSource/GameSession/MedicalClinic.cs
#	Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs
#	Barotrauma/BarotraumaServer/WindowsServer.csproj
#	Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/AI/HumanAIController.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFightIntruders.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFindSafety.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Attack.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/Affliction.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionData/AbilityConditionMission.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionHasPermanentStat.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityUnlockApprenticeshipTalentTree.cs
#	Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/TalentTree.cs
#	Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs
#	Barotrauma/BarotraumaShared/SharedSource/Enums.cs
#	Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/NPCChangeTeamAction.cs
#	Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs
#	Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/TagAction.cs
#	Barotrauma/BarotraumaShared/SharedSource/Events/EventManager.cs
#	Barotrauma/BarotraumaShared/SharedSource/Events/Missions/AbandonedOutpostMission.cs
#	Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs
#	Barotrauma/BarotraumaShared/SharedSource/Extensions/IEnumerableExtensions.cs
#	Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Factions.cs
#	Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Reputation.cs
#	Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs
#	Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs
#	Barotrauma/BarotraumaShared/SharedSource/GameSession/MedicalClinic.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Door.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RangedWeapon.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Throwable.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemComponent.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Repairable.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Components/Turret.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs
#	Barotrauma/BarotraumaShared/SharedSource/Items/RelatedItem.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Explosion.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Biome.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Map/LocationType.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerationParams.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/PriceInfo.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/Submarine.cs
#	Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs
#	Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabCollection.cs
#	Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs
#	Barotrauma/BarotraumaShared/SharedSource/Steam/Workshop.cs
#	Barotrauma/BarotraumaShared/SharedSource/SteamAchievementManager.cs
#	Barotrauma/BarotraumaShared/SharedSource/Upgrades/UpgradePrefab.cs
#	Barotrauma/BarotraumaShared/SharedSource/Utils/Option/Option.cs
#	Barotrauma/BarotraumaShared/SharedSource/Utils/SerializableDateTime.cs
#	Barotrauma/BarotraumaShared/changelog.txt
#	Barotrauma/BarotraumaTest/SerializableDateTimeTests.cs
This commit is contained in:
Regalis11
2023-03-13 18:26:50 +02:00
335 changed files with 11054 additions and 5179 deletions
@@ -8,19 +8,15 @@ namespace Barotrauma
{
internal partial class CampaignMetadata
{
public CampaignMode Campaign { get; }
private readonly Dictionary<Identifier, object> data = new Dictionary<Identifier, object>();
public CampaignMetadata(CampaignMode campaign)
public CampaignMetadata()
{
Campaign = campaign;
}
public CampaignMetadata(CampaignMode campaign, XElement element)
public void Load(XElement element)
{
Campaign = campaign;
data.Clear();
foreach (var subElement in element.Elements())
{
if (string.Equals(subElement.Name.ToString(), "data", StringComparison.InvariantCultureIgnoreCase))
@@ -59,6 +55,8 @@ namespace Barotrauma
{
DebugConsole.Log($"Set the value \"{identifier}\" to {value}");
SteamAchievementManager.OnCampaignMetadataSet(identifier, value, unlockClients: true);
if (!data.ContainsKey(identifier))
{
data.Add(identifier, value);
@@ -1,13 +1,16 @@
#nullable enable
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Barotrauma
{
public enum FactionAffiliation
{
Affiliated,
Neutral
Positive,
Neutral,
Negative
}
class Faction
@@ -25,21 +28,25 @@ namespace Barotrauma
/// Get what kind of affiliation this faction has towards the player depending on who they chose to side with via talents
/// </summary>
/// <returns></returns>
public FactionAffiliation GetPlayerAffiliationStatus()
public static FactionAffiliation GetPlayerAffiliationStatus(Faction faction)
{
float affiliation = 1f;
foreach (Character character in GameSession.GetSessionCrewCharacters(CharacterType.Both))
{
if (character.Info is not { } info) { continue; }
if (GameMain.GameSession?.Campaign?.Factions is not { } factions) { return FactionAffiliation.Neutral; }
affiliation *= 1f + info.GetSavedStatValue(StatTypes.Affiliation, Prefab.Identifier);
bool isHighest = true;
foreach (Faction otherFaction in factions)
{
if (otherFaction == faction || otherFaction.Reputation.Value < faction.Reputation.Value) { continue; }
isHighest = false;
break;
}
return affiliation switch
{
>= 1f => FactionAffiliation.Affiliated,
_ => FactionAffiliation.Neutral
};
return isHighest ? FactionAffiliation.Positive : FactionAffiliation.Negative;
}
public override string ToString()
{
return $"{base.ToString()} ({Prefab?.Identifier.ToString() ?? "null"})";
}
}
@@ -52,6 +59,54 @@ namespace Barotrauma
public LocalizedString Description { get; }
public LocalizedString ShortDescription { get; }
public class HireableCharacter
{
public readonly Identifier NPCSetIdentifier;
public readonly Identifier NPCIdentifier;
public readonly float MinReputation;
public HireableCharacter(ContentXElement element)
{
NPCSetIdentifier = element.GetAttributeIdentifier("from", element.GetAttributeIdentifier("npcsetidentifier", Identifier.Empty));
NPCIdentifier = element.GetAttributeIdentifier("identifier", element.GetAttributeIdentifier("npcidentifier", Identifier.Empty));
MinReputation = element.GetAttributeFloat("minreputation", 0.0f);
}
}
public ImmutableArray<HireableCharacter> HireableCharacters;
public class AutomaticMission
{
public readonly Identifier MissionTag;
public readonly LevelData.LevelType LevelType;
public readonly float MinReputation, MaxReputation;
public readonly float MinProbability, MaxProbability;
public readonly int MaxDistanceFromFactionOutpost;
public readonly bool DisallowBetweenOtherFactionOutposts;
public AutomaticMission(ContentXElement element, string parentDebugName)
{
MissionTag = element.GetAttributeIdentifier("missiontag", Identifier.Empty);
LevelType = element.GetAttributeEnum("leveltype", LevelData.LevelType.LocationConnection);
MinReputation = element.GetAttributeFloat("minreputation", 0.0f);
MaxReputation = element.GetAttributeFloat("maxreputation", 0.0f);
if (MinReputation > MaxReputation)
{
DebugConsole.ThrowError($"Error in faction prefab \"{parentDebugName}\": MinReputation cannot be larger than MaxReputation.");
}
float probability = element.GetAttributeFloat("probability", 0.0f);
MinProbability = element.GetAttributeFloat("minprobability", probability);
MaxProbability = element.GetAttributeFloat("maxprobability", probability);
MaxDistanceFromFactionOutpost = element.GetAttributeInt(nameof(MaxDistanceFromFactionOutpost), int.MaxValue);
DisallowBetweenOtherFactionOutposts = element.GetAttributeBool(nameof(DisallowBetweenOtherFactionOutposts), false);
}
}
public ImmutableArray<AutomaticMission> AutomaticMissions;
public bool StartOutpost { get; }
public int MenuOrder { get; }
/// <summary>
@@ -69,38 +124,73 @@ namespace Barotrauma
/// </summary>
public int InitialReputation { get; }
public float ControlledOutpostPercentage { get; }
public float SecondaryControlledOutpostPercentage { get; }
#if CLIENT
public Sprite? Icon { get; private set; }
public Sprite? IconSmall { get; private set; }
public Sprite? BackgroundPortrait { get; private set; }
#endif
public Color IconColor { get; }
#endif
public FactionPrefab(ContentXElement element, FactionsFile file) : base(file, element.GetAttributeIdentifier("identifier", string.Empty))
{
MenuOrder = element.GetAttributeInt("menuorder", 0);
StartOutpost = element.GetAttributeBool("startoutpost", false);
MinReputation = element.GetAttributeInt("minreputation", -100);
MaxReputation = element.GetAttributeInt("maxreputation", 100);
InitialReputation = element.GetAttributeInt("initialreputation", 0);
ControlledOutpostPercentage = element.GetAttributeFloat("controlledoutpostpercentage", 0);
SecondaryControlledOutpostPercentage = element.GetAttributeFloat("secondarycontrolledoutpostpercentage", 0);
Name = element.GetAttributeString("name", null) ?? TextManager.Get($"faction.{Identifier}").Fallback("Unnamed");
Description = element.GetAttributeString("description", null) ?? TextManager.Get($"faction.{Identifier}.description").Fallback("");
ShortDescription = element.GetAttributeString("shortdescription", null) ?? TextManager.Get($"faction.{Identifier}.shortdescription").Fallback("");
#if CLIENT
List<HireableCharacter> hireableCharacters = new List<HireableCharacter>();
List<AutomaticMission> automaticMissions = new List<AutomaticMission>();
foreach (var subElement in element.Elements())
{
if (subElement.Name.ToString().Equals("icon", StringComparison.OrdinalIgnoreCase))
var subElementId = subElement.NameAsIdentifier();
if (subElementId == "icon")
{
IconColor = subElement.GetAttributeColor("color", Color.White);
#if CLIENT
Icon = new Sprite(subElement);
#endif
}
else if (subElement.Name.ToString().Equals("portrait", StringComparison.OrdinalIgnoreCase))
else if (subElementId == "iconsmall")
{
#if CLIENT
IconSmall = new Sprite(subElement);
#endif
}
else if (subElementId == "portrait")
{
#if CLIENT
BackgroundPortrait = new Sprite(subElement);
#endif
}
else if (subElementId == "hireable")
{
hireableCharacters.Add(new HireableCharacter(subElement));
}
else if (subElementId == "mission" || subElementId == "automaticmission")
{
automaticMissions.Add(new AutomaticMission(subElement, Identifier.ToString()));
}
}
#endif
HireableCharacters = hireableCharacters.ToImmutableArray();
AutomaticMissions = automaticMissions.ToImmutableArray();
}
public override string ToString()
{
return $"{base.ToString()} ({Identifier})";
}
public override void Dispose()
@@ -1,17 +1,16 @@
using Microsoft.Xna.Framework;
using System;
using System.Linq;
namespace Barotrauma
{
class Reputation
{
public const float HostileThreshold = 0.2f;
public const float ReputationLossPerNPCDamage = 0.1f;
public const float ReputationLossPerStolenItemPrice = 0.01f;
public const float ReputationLossPerWallDamage = 0.1f;
public const float MinReputationLossPerStolenItem = 0.5f;
public const float MaxReputationLossPerStolenItem = 10.0f;
public const float ReputationLossPerNPCDamage = 0.05f;
public const float ReputationLossPerWallDamage = 0.05f;
public const float ReputationLossPerStolenItemPrice = 0.005f;
public const float MinReputationLossPerStolenItem = 0.05f;
public const float MaxReputationLossPerStolenItem = 1.0f;
public Identifier Identifier { get; }
public int MinReputation { get; }
@@ -59,27 +58,34 @@ namespace Barotrauma
Value = newReputation;
}
public void AddReputation(float reputationChange)
public float GetReputationChangeMultiplier(float reputationChange)
{
if (reputationChange > 0f)
{
float reputationGainMultiplier = 1f;
foreach (Character character in GameSession.GetSessionCrewCharacters(CharacterType.Both))
{
reputationGainMultiplier += character.GetStatValue(StatTypes.ReputationGainMultiplier);
reputationGainMultiplier *= 1f + character.GetStatValue(StatTypes.ReputationGainMultiplier, includeSaved: false);
reputationGainMultiplier *= 1f + character.Info?.GetSavedStatValue(StatTypes.ReputationGainMultiplier, Identifier) ?? 0;
}
reputationChange *= reputationGainMultiplier;
return reputationGainMultiplier;
}
else if (reputationChange < 0f)
{
float reputationLossMultiplier = 1f;
foreach (Character character in GameSession.GetSessionCrewCharacters(CharacterType.Both))
{
reputationLossMultiplier += character.GetStatValue(StatTypes.ReputationLossMultiplier);
reputationLossMultiplier *= 1f + character.GetStatValue(StatTypes.ReputationLossMultiplier, includeSaved: false);
reputationLossMultiplier *= 1f + character.Info?.GetSavedStatValue(StatTypes.ReputationLossMultiplier, Identifier) ?? 0;
}
reputationChange *= reputationLossMultiplier;
return reputationLossMultiplier;
}
Value += reputationChange;
return 1.0f;
}
public void AddReputation(float reputationChange)
{
Value += reputationChange * GetReputationChangeMultiplier(reputationChange);
}
public readonly NamedEvent<Reputation> OnReputationValueChanged = new NamedEvent<Reputation>();
@@ -69,7 +69,7 @@ namespace Barotrauma
public Option<int> RewardDistributionChanged;
public Option<int> BalanceChanged;
public WalletChangedData MergeInto(WalletChangedData other)
public readonly WalletChangedData MergeInto(WalletChangedData other)
{
other.BalanceChanged = AddOptionalInt(other.BalanceChanged, BalanceChanged);
other.RewardDistributionChanged = AddOptionalInt(other.RewardDistributionChanged, RewardDistributionChanged);
@@ -80,32 +80,20 @@ namespace Barotrauma
static Option<int> AddOptionalInt(Option<int> a, Option<int> b)
{
return a switch
{
Some<int> some1 => b switch
{
Some<int> some2 => Option<int>.Some(some1.Value + some2.Value),
None<int> _ => Option<int>.Some(some1.Value),
_ => throw new ArgumentOutOfRangeException(nameof(b))
},
None<int> _ => b switch
{
Some<int> some1 => Option<int>.Some(some1.Value),
None<int> _ => Option<int>.None(),
_ => throw new ArgumentOutOfRangeException(nameof(b))
},
_ => throw new ArgumentOutOfRangeException(nameof(a))
};
bool hasValue1 = a.TryUnwrap(out var value1);
bool hasValue2 = b.TryUnwrap(out var value2);
return hasValue1
? hasValue2
? Option.Some(value1 + value2)
: Option.Some(value1)
: hasValue2
? Option.Some(value2)
: Option.None;
}
static Option<int> TurnToNoneIfZero(Option<int> option)
{
return option switch
{
Some<int> s => s.Value == 0 ? Option<int>.None() : option,
None<int> _ => option,
_ => throw new ArgumentOutOfRangeException(nameof(option))
};
return option.Bind(i => i == 0 ? Option.None : Option.Some(i));
}
}
}
@@ -223,12 +211,8 @@ namespace Barotrauma
};
}
public string GetOwnerLogName() => Owner switch
{
Some<Character> { Value: var character } => character.Name,
None<Character> _ => "the bank",
_ => throw new ArgumentOutOfRangeException(nameof(Owner))
};
public string GetOwnerLogName()
=> Owner.TryUnwrap(out var character) ? character.Name : "the bank";
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged);