4 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
12 private readonly Identifier[] targetItemIdentifiers;
13 private readonly Identifier[] targetEnemyIdentifiers;
14 private readonly
int minEnemyCount;
15 private readonly HashSet<Entity> existingTargets =
new HashSet<Entity>();
16 private readonly HashSet<Character> spawnedTargets =
new HashSet<Character>();
17 private readonly HashSet<Entity> allTargets =
new HashSet<Entity>();
19 private Ruin TargetRuin {
get;
set; }
28 .Where(t => (t is
Item i && !IsItemDestroyed(i)) || (t is
Character c && !IsEnemyDefeated(c)))
29 .Select(t => (
Prefab.SonarLabel, t.WorldPosition));
47 existingTargets.Clear();
48 spawnedTargets.Clear();
51 TargetRuin =
Level.
Loaded?.
Ruins?.GetRandom(randSync: Rand.RandSync.ServerAndClient);
52 if (TargetRuin ==
null)
54 DebugConsole.ThrowError($
"Failed to initialize an Alien Ruin mission (\"{Prefab.Identifier}\"): level contains no alien ruins",
58 if (targetItemIdentifiers.Length < 1 && targetEnemyIdentifiers.Length < 1)
60 DebugConsole.ThrowError($
"Failed to initialize an Alien Ruin mission (\"{Prefab.Identifier}\"): no target identifiers set in the mission definition",
66 if (!targetItemIdentifiers.Contains(item.Prefab.Identifier)) {
continue; }
67 if (item.Submarine != TargetRuin.
Submarine) {
continue; }
68 existingTargets.Add(item);
71 int existingEnemyCount = 0;
74 if (character.SpeciesName.IsEmpty) {
continue; }
75 if (!targetEnemyIdentifiers.Contains(character.SpeciesName)) {
continue; }
76 if (character.Submarine != TargetRuin.
Submarine) {
continue; }
77 existingTargets.Add(character);
78 allTargets.Add(character);
81 if (existingEnemyCount < minEnemyCount)
83 var enemyPrefabs =
new HashSet<CharacterPrefab>();
84 foreach (Identifier identifier
in targetEnemyIdentifiers)
89 enemyPrefabs.Add(prefab);
93 DebugConsole.ThrowError($
"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): could not find a character prefab with the species \"{identifier}\"",
97 if (enemyPrefabs.None())
99 DebugConsole.ThrowError($
"Error in an Alien Ruin mission (\"{Prefab.Identifier}\"): no enemy species defined that could be used to spawn more ({minEnemyCount - existingEnemyCount}) enemies",
103 for (
int i = 0; i < (minEnemyCount - existingEnemyCount); i++)
105 var prefab = enemyPrefabs.GetRandomUnsynced();
106 var spawnPos = TargetRuin.
Submarine.
GetWaypoints(
false).GetRandomUnsynced(w => w.CurrentHull !=
null)?.WorldPosition;
107 if (!spawnPos.HasValue)
109 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",
113 var newEnemy =
Character.
Create(prefab.Identifier, spawnPos.Value, ToolBox.RandomSeed(8), createNetworkEvent:
false);
114 spawnedTargets.Add(newEnemy);
115 allTargets.Add(newEnemy);
119 DebugConsole.NewMessage(
"********** CLEAR RUIN MISSION INFO **********");
120 DebugConsole.NewMessage($
"Existing item targets: {existingTargets.Count - existingEnemyCount}");
121 DebugConsole.NewMessage($
"Existing enemy targets: {existingEnemyCount}");
122 DebugConsole.NewMessage($
"Spawned enemy targets: {spawnedTargets.Count}");
132 if (!AllTargetsEliminated()) {
return; }
138 private bool AllTargetsEliminated()
140 foreach (var target
in allTargets)
142 if (target is
Item targetItem)
144 if (!IsItemDestroyed(targetItem))
149 else if (target is Character targetEnemy)
151 if (!IsEnemyDefeated(targetEnemy))
159 DebugConsole.ThrowError($
"Error in Alien Ruin mission (\"{Prefab.Identifier}\"): unexpected target of type {target?.GetType()?.ToString()}",
167 private static bool IsItemDestroyed(Item item) => item ==
null || item.Removed || item.Condition <= 0.0f;
169 private static bool IsEnemyDefeated(Character enemy) => enemy ==
null ||enemy.Removed || enemy.IsDead;
177 return State > 0 && exitingLevel;
override IEnumerable<(LocalizedString Label, Vector2 Position)> SonarLabels
AlienRuinMission(MissionPrefab prefab, Location[] locations, Submarine sub)
override void EndMissionSpecific(bool completed)
override void StartMissionSpecific(Level level)
override void UpdateMissionSpecific(float deltaTime)
override bool DetermineCompleted()
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)
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)