3 using System.Collections.Generic;
4 using System.Collections.Immutable;
6 using System.Reflection;
19 public static readonly Dictionary<Identifier, Type>
CoOpMissionClasses =
new Dictionary<Identifier, Type>()
31 {
"ScanAlienRuins".ToIdentifier(), typeof(
ScanMission) },
40 public static readonly Dictionary<Identifier, Type>
PvPMissionClasses =
new Dictionary<Identifier, Type>()
45 public static readonly HashSet<Identifier>
HiddenMissionTypes =
new HashSet<Identifier>() {
"GoTo".ToIdentifier(),
"End".ToIdentifier() };
56 Amount = element.GetAttributeFloat(nameof(
Amount), 0.0f);
61 private readonly ConstructorInfo constructor;
71 public readonly ImmutableHashSet<Identifier>
Tags;
105 public readonly ImmutableArray<LocalizedString>
Headers;
106 public readonly ImmutableArray<LocalizedString>
Messages;
116 public readonly
bool RequireWreck, RequireRuin, RequireBeaconStation, RequireThalamusWreck;
171 public int State {
get;
private set; }
174 public float Delay {
get;
private set; }
185 public readonly List<TriggerEvent>
TriggerEvents =
new List<TriggerEvent>();
204 if (
string.IsNullOrEmpty(textTag))
206 return TextManager.Get($
"{textTagPrefix}.{TextIdentifier}");
212 TextManager.Get(textTag)
214 .
Fallback(TextManager.Get($
"{textTagPrefix}.{TextIdentifier}"))
227 RequireThalamusWreck = element.
GetAttributeBool(nameof(RequireThalamusWreck),
false);
229 RequireBeaconStation = element.
GetAttributeBool(nameof(RequireBeaconStation),
false);
265 SuccessMessage = TextManager.Get($
"MissionSuccess.{TextIdentifier}");
266 if (!
string.IsNullOrEmpty(successMessageTag))
269 .
Fallback(TextManager.Get(successMessageTag))
275 FailureMessage = TextManager.Get($
"MissionFailure.{TextIdentifier}");
276 if (!
string.IsNullOrEmpty(failureMessageTag))
279 .
Fallback(TextManager.Get(failureMessageTag))
286 TextManager.Get($
"MissionSonarLabel.{sonarLabelTag}")
287 .
Fallback(TextManager.Get(sonarLabelTag))
288 .
Fallback(TextManager.Get($
"MissionSonarLabel.{TextIdentifier}"));
289 if (!
string.IsNullOrEmpty(sonarLabelTag))
303 var headers =
new List<LocalizedString>();
304 var messages =
new List<LocalizedString>();
307 for (
int i = 0; i < 100; i++)
309 LocalizedString header = TextManager.Get($
"MissionHeader{i}.{TextIdentifier}");
310 LocalizedString message = TextManager.Get($
"MissionMessage{i}.{TextIdentifier}");
311 if (!message.IsNullOrEmpty())
314 messages.Add(message);
318 List<ReputationReward> reputationRewards =
new List<ReputationReward>();
319 int messageIndex = 0;
320 foreach (var subElement
in element.Elements())
322 switch (subElement.Name.ToString().ToLowerInvariant())
325 if (messageIndex > headers.Count - 1)
327 headers.Add(
string.Empty);
328 messages.Add(
string.Empty);
330 headers[messageIndex] =
331 TextManager.Get($
"MissionHeader{messageIndex}.{TextIdentifier}")
332 .Fallback(TextManager.Get(subElement.GetAttributeString(
"header",
"")))
333 .Fallback(subElement.GetAttributeString(
"header",
""));
334 messages[messageIndex] =
335 TextManager.Get($
"MissionMessage{messageIndex}.{TextIdentifier}")
336 .Fallback(TextManager.Get(subElement.GetAttributeString(
"text",
"")))
337 .Fallback(subElement.GetAttributeString(
"text",
""));
341 case "connectiontype":
342 if (subElement.GetAttribute(
"identifier") !=
null)
349 subElement.GetAttributeIdentifier(
"from",
""),
350 subElement.GetAttributeIdentifier(
"to",
"")));
353 case "locationtypechange":
357 case "reputationreward":
362 string stringValue = subElement.GetAttributeString(
"value",
string.Empty);
363 if (!
string.IsNullOrWhiteSpace(stringValue) && !identifier.IsEmpty)
368 string operatingString = subElement.GetAttributeString(
"operation",
string.Empty);
369 if (!
string.IsNullOrWhiteSpace(operatingString))
382 Headers = headers.ToImmutableArray();
383 Messages = messages.ToImmutableArray();
392 DebugConsole.AddWarning($
"Potential error in mission prefab \"{Identifier}\" - sonar label not set.");
398 DebugConsole.AddWarning($
"Potential error in mission {Identifier}: Disabling submarines is only intended for combat missions taking place in an outpost, and may lead to issues in other types of missions.",
399 contentPackage: element.ContentPackage);
402 constructor = FindMissionConstructor(element,
MissionClass);
403 if (constructor ==
null)
405 DebugConsole.ThrowError($
"Failed to find a constructor for the mission type \"{Type}\"!",
406 contentPackage: element.ContentPackage);
409 InitProjSpecific(element);
416 type = TryGetClass(typeName.RemoveFromEnd(
"Mission"));
424 if (typeNameLegacy ==
"OutpostDestroy" || typeNameLegacy ==
"OutpostRescue")
426 typeNameLegacy =
"AbandonedOutpost".ToIdentifier();
428 else if (typeNameLegacy ==
"clearalienruins")
430 typeNameLegacy =
"EliminateTargets".ToIdentifier();
432 type = TryGetClass(typeNameLegacy) ?? TryGetClass(typeNameLegacy.AppendIfMissing(
"Mission"));
435 DebugConsole.ThrowError($
"Failed to find the mission type \"{typeNameLegacy}\" for the mission {Identifier}.",
445 return coOpMissionClass;
449 return pvpMissionClass;
457 private ConstructorInfo FindMissionConstructor(ContentXElement element,
Type missionClass)
459 ConstructorInfo constructor;
460 if (missionClass ==
null) {
return null; }
461 if (missionClass != typeof(Mission) && !missionClass.IsSubclassOf(typeof(Mission))) {
return null; }
462 constructor = missionClass.GetConstructor(
new Type[] { typeof(
MissionPrefab), typeof(Location[]), typeof(Submarine) });
463 if (constructor ==
null)
465 DebugConsole.ThrowError(
466 $
"Could not find the constructor of the mission type \"{missionClass}\" for the mission {Identifier}",
467 contentPackage: element.ContentPackage);
473 partial
void InitProjSpecific(ContentXElement element);
491 if (fromType ==
"any" ||
495 if (toType ==
"any" ||
514 return constructor?.Invoke(
new object[] {
this, locations, sub }) as
Mission;
517 partial
void DisposeProjectSpecific();
520 DisposeProjectSpecific();
529 List<Identifier> missionTypes =
new List<Identifier>();
530 foreach (var missionPrefab
in Prefabs)
532 if (missionPrefab.Commonness <= 0.0f) {
continue; }
533 if (missionPrefab.SingleplayerOnly) {
continue; }
538 if (!missionTypes.Contains(missionPrefab.Type))
540 missionTypes.Add(missionPrefab.Type);
543 return missionTypes.OrderBy(t => t.Value);
string? GetAttributeString(string key, string? def)
Identifier[] GetAttributeIdentifierArray(Identifier[] def, params string[] keys)
ContentPackage? ContentPackage
Identifier NameAsIdentifier()
bool GetAttributeBool(string key, bool def)
int GetAttributeInt(string key, int def)
string?[] GetAttributeStringArray(string key, string[]? def, bool convertToLowerInvariant=false)
XAttribute? GetAttribute(string name)
Identifier GetAttributeIdentifier(string key, string def)
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
bool IsAnyOutpost
Is this location type considered valid for e.g. events and missions that are should be available in "...
readonly Identifier FactionIdentifier
readonly float AmountForOpposingFaction
ReputationReward(XElement element)
Identifier EventIdentifier
TriggerEvent(XElement element)
readonly Identifier AchievementIdentifier
readonly LocalizedString SonarLabel
readonly ImmutableList< ReputationReward > ReputationRewards
bool IsAllowed(Location from, Location to)
readonly? RespawnMode ForceRespawnMode
readonly? int Difficulty
Displayed difficulty (indicator)
readonly int MaxLevelDifficulty
The actual maximum difficulty of the level allowed for this mission to trigger.
static readonly Dictionary< Identifier, Type > CoOpMissionClasses
The keys here are for backwards compatibility, tying the old mission types to the appropriate class....
static readonly PrefabCollection< MissionPrefab > Prefabs
static readonly Dictionary< Identifier, Type > PvPMissionClasses
The keys here are for backwards compatibility, tying the old mission types to the appropriate class....
readonly Identifier SonarIconIdentifier
readonly bool AllowOtherMissionsInLevel
readonly bool ShowInMenus
static readonly HashSet< Identifier > HiddenMissionTypes
readonly List< TriggerEvent > TriggerEvents
readonly int MaxProgressState
readonly List<(Identifier from, Identifier to)> AllowedConnectionTypes
The mission can only be received when travelling from a location of the first type to a location of t...
readonly bool BlockLocationTypeChanges
If enabled, locations this mission takes place in cannot change their type
readonly int MinLevelDifficulty
The actual minimum difficulty of the level allowed for this mission to trigger.
readonly LocalizedString ProgressBarLabel
readonly ImmutableArray< LocalizedString > Headers
LocationTypeChange LocationTypeChangeOnCompleted
readonly List<(Identifier Identifier, object Value, SetDataAction.OperationType OperationType)> DataRewards
readonly ImmutableHashSet< Identifier > Tags
readonly Identifier RequiredLocationFaction
The mission can only happen in locations owned by this faction. In the mission mode,...
readonly bool RequireWreck
readonly LocalizedString Name
readonly Type MissionClass
readonly LocalizedString Description
readonly ImmutableArray< LocalizedString > Messages
readonly bool MultiplayerOnly
readonly bool IsSideObjective
readonly List< Identifier > AllowedLocationTypes
The mission can only be received in these location types
static IEnumerable< Identifier > GetAllMultiplayerSelectableMissionTypes()
Returns all mission types that can be selected e.g. in the server lobby, excluding any special,...
readonly LocalizedString FailureMessage
readonly bool LoadSubmarines
MissionPrefab(ContentXElement element, MissionsFile file)
readonly LocalizedString SuccessMessage
bool IsAllowedDifficulty(float difficulty)
Inclusive (matching the min an max values is accepted).
readonly List< string > UnhideEntitySubCategories
Show entities belonging to these sub categories when the mission starts
readonly Identifier AllowOutpostSelectionFromTag
If set, the players can choose which outpost is used for the mission (selected from the outposts that...
readonly bool AllowOutpostNPCs
readonly bool ShowProgressBar
readonly Identifier TextIdentifier
readonly bool ShowProgressInNumbers
readonly ContentXElement ConfigElement
readonly bool SpawnBeaconStationInMiddle
readonly Identifier ForceOutpostGenerationParameters
Mission Instantiate(Location[] locations, Submarine sub)
readonly Identifier Identifier
Prefab that has a property serves as a deterministic hash of a prefab's identifier....
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
Sets a campaign metadata value. The metadata can be any arbitrary data you want to save: for example,...
static object ConvertXMLValue(string value)