4 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
10 [TypePreviouslyKnownAs(
"AlienRuinMission")]
13 private readonly Identifier[] targetItemIdentifiers;
14 private readonly Identifier[] targetEnemyIdentifiers;
15 private readonly
int minEnemyCount;
16 private readonly HashSet<Entity> existingTargets =
new HashSet<Entity>();
17 private readonly HashSet<Character> spawnedTargets =
new HashSet<Character>();
18 private readonly HashSet<Entity> allTargets =
new HashSet<Entity>();
32 .Where(t => (t is
Item i && !IsItemDestroyed(i)) || (t is
Character c && !IsEnemyDefeated(c)))
33 .Select(t => (
Prefab.SonarLabel, t.WorldPosition));
53 existingTargets.Clear();
54 spawnedTargets.Clear();
69 if (wrecks ==
null || wrecks.None()) {
return null; }
73 var thalamusWrecks = wrecks.Where(w => w.WreckAI !=
null).ToArray();
74 if (thalamusWrecks.Any())
76 return thalamusWrecks.GetRandom(Rand.RandSync.ServerAndClient);
80 return wrecks.GetRandom(Rand.RandSync.ServerAndClient);
83 if (TargetSub ==
null)
85 DebugConsole.ThrowError($
"Failed to initialize an {nameof(EliminateTargetsMission)} mission (\"{Prefab.Identifier}\"): level contains no submarines",
89 if (targetItemIdentifiers.Length < 1 && targetEnemyIdentifiers.Length < 1)
91 DebugConsole.ThrowError($
"Failed to initialize an {nameof(EliminateTargetsMission)} mission (\"{Prefab.Identifier}\"): no target identifiers set in the mission definition",
97 if (!targetItemIdentifiers.Contains(item.Prefab.Identifier)) {
continue; }
98 if (item.Submarine != TargetSub) {
continue; }
99 existingTargets.Add(item);
100 allTargets.Add(item);
102 int existingEnemyCount = 0;
105 if (character.SpeciesName.IsEmpty) {
continue; }
106 if (!targetEnemyIdentifiers.Contains(character.SpeciesName)) {
continue; }
107 if (character.Submarine != TargetSub) {
continue; }
108 existingTargets.Add(character);
109 allTargets.Add(character);
110 existingEnemyCount++;
112 if (existingEnemyCount < minEnemyCount)
114 var enemyPrefabs =
new HashSet<CharacterPrefab>();
115 foreach (Identifier identifier
in targetEnemyIdentifiers)
120 enemyPrefabs.Add(prefab);
124 DebugConsole.ThrowError($
"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): could not find a character prefab with the species \"{identifier}\"",
128 if (enemyPrefabs.None())
130 DebugConsole.ThrowError($
"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no enemy species defined that could be used to spawn more ({minEnemyCount - existingEnemyCount}) enemies",
134 for (
int i = 0; i < (minEnemyCount - existingEnemyCount); i++)
136 var prefab = enemyPrefabs.GetRandomUnsynced();
137 var spawnPos = TargetSub.
GetWaypoints(
false).GetRandomUnsynced(w => w.CurrentHull !=
null)?.WorldPosition;
138 if (!spawnPos.HasValue)
140 DebugConsole.ThrowError($
"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no valid spawn positions could be found for the additional ({minEnemyCount - existingEnemyCount}) enemies to be spawned",
144 var newEnemy =
Character.
Create(prefab.Identifier, spawnPos.Value, ToolBox.RandomSeed(8), createNetworkEvent:
false);
145 spawnedTargets.Add(newEnemy);
146 allTargets.Add(newEnemy);
150 DebugConsole.NewMessage(
"********** CLEAR RUIN MISSION INFO **********");
151 DebugConsole.NewMessage($
"Existing item targets: {existingTargets.Count - existingEnemyCount}");
152 DebugConsole.NewMessage($
"Existing enemy targets: {existingEnemyCount}");
153 DebugConsole.NewMessage($
"Spawned enemy targets: {spawnedTargets.Count}");
163 if (!AllTargetsEliminated()) {
return; }
169 private bool AllTargetsEliminated()
171 foreach (var target
in allTargets)
173 if (target is
Item targetItem)
175 if (!IsItemDestroyed(targetItem))
180 else if (target is Character targetEnemy)
182 if (!IsEnemyDefeated(targetEnemy))
190 DebugConsole.ThrowError($
"Error in Alien Ruin mission (\"{Prefab.Identifier}\"): unexpected target of type {target?.GetType()?.ToString()}",
198 private static bool IsItemDestroyed(Item item) => item ==
null || item.Removed || item.Condition <= 0.0f;
200 private static bool IsEnemyDefeated(Character enemy) => enemy ==
null ||enemy.Removed || enemy.IsDead;
208 return State > 0 && exitingLevel;
TransitionType GetAvailableTransition(out LevelData nextLevel, out Submarine leavingSub)
Which type of transition between levels is currently possible (if any)
static Character Create(CharacterInfo characterInfo, Vector2 position, string seed, ushort id=Entity.NullEntityID, bool isRemotePlayer=false, bool hasAi=true, RagdollParams ragdoll=null, bool spawnInitialItems=true)
Create a new character
static readonly List< Character > CharacterList
static CharacterPrefab FindBySpeciesName(Identifier speciesName)
Identifier[] GetAttributeIdentifierArray(Identifier[] def, params string[] keys)
int GetAttributeInt(string key, int def)
readonly bool PrioritizeThalamus
override void StartMissionSpecific(Level level)
override void UpdateMissionSpecific(float deltaTime)
readonly SubmarineType TargetSubType
override bool DetermineCompleted()
override void EndMissionSpecific(bool completed)
override IEnumerable<(LocalizedString Label, Vector2 Position)> SonarLabels
EliminateTargetsMission(MissionPrefab prefab, Location[] locations, Submarine sub)
static GameSession?? GameSession
static readonly List< Item > ItemList
Defines a point in the event that GoTo actions can jump to.
readonly MissionPrefab Prefab
readonly ContentXElement ConfigElement
ContentPackage? ContentPackage
List< WayPoint > GetWaypoints(bool alsoFromConnectedSubs)