#nullable enable using Microsoft.Xna.Framework; using System.Collections.Generic; using System.Collections.Immutable; namespace Barotrauma { public enum FactionAffiliation { Positive, Neutral, Negative } class Faction { public Reputation Reputation { get; } public FactionPrefab Prefab { get; } public Faction(CampaignMetadata? metadata, FactionPrefab prefab) { Prefab = prefab; Reputation = new Reputation(metadata, this, prefab.MinReputation, prefab.MaxReputation, prefab.InitialReputation); } /// /// Get what kind of affiliation this faction has towards the player depending on who they chose to side with via talents /// /// public static FactionAffiliation GetPlayerAffiliationStatus(Faction faction) { if (GameMain.GameSession?.Campaign?.Factions is not { } factions) { return FactionAffiliation.Neutral; } bool isHighest = true; foreach (Faction otherFaction in factions) { if (otherFaction == faction || otherFaction.Reputation.Value < faction.Reputation.Value) { continue; } isHighest = false; break; } return isHighest ? FactionAffiliation.Positive : FactionAffiliation.Negative; } public override string ToString() { return $"{base.ToString()} ({Prefab?.Identifier.ToString() ?? "null"})"; } } internal class FactionPrefab : Prefab { public readonly static PrefabCollection Prefabs = new PrefabCollection(); public LocalizedString Name { get; } public LocalizedString Description { get; } public LocalizedString ShortDescription { get; } public Identifier OpposingFaction { 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 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 AutomaticMissions; public bool StartOutpost { get; } public int MenuOrder { get; } /// /// How low the reputation can drop on this faction /// public int MinReputation { get; } /// /// Maximum reputation level you can gain on this faction /// public int MaxReputation { get; } /// /// What reputation does this faction start with /// 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; } 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(""); OpposingFaction = element.GetAttributeIdentifier(nameof(OpposingFaction), Identifier.Empty); List hireableCharacters = new List(); List automaticMissions = new List(); foreach (var subElement in element.Elements()) { var subElementId = subElement.NameAsIdentifier(); if (subElementId == "icon") { IconColor = subElement.GetAttributeColor("color", Color.White); #if CLIENT Icon = new Sprite(subElement); #endif } 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())); } } HireableCharacters = hireableCharacters.ToImmutableArray(); AutomaticMissions = automaticMissions.ToImmutableArray(); } public override string ToString() { return $"{base.ToString()} ({Identifier})"; } public override void Dispose() { #if CLIENT Icon?.Remove(); Icon = null; #endif } } }