3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
6 using System.Diagnostics;
22 private const float PriorityIncrease = 100;
23 private const float PriorityDecrease = 10;
24 private const float SearchHullInterval = 3.0f;
26 private float currentHullSafety;
28 private float searchHullTimer;
38 private bool resetPriority;
95 public override void Update(
float deltaTime)
99 retryTimer -= deltaTime;
108 resetPriority =
false;
113 currentHullSafety = 0;
120 Priority -= PriorityDecrease * deltaTime;
129 float dangerFactor = (100 - currentHullSafety) / 100;
130 Priority += dangerFactor * PriorityIncrease * deltaTime;
136 private Hull currentSafeHull;
137 private Hull previousSafeHull;
138 private bool cannotFindSafeHull;
139 private bool cannotFindDivingGear;
140 private readonly
int findDivingGearAttempts = 2;
141 private int retryCounter;
142 private readonly
float retryResetTime = 5;
143 private float retryTimer;
144 protected override void Act(
float deltaTime)
146 if (resetPriority) {
return; }
150 if (!
character.
LockHands && (!dangerousPressure || shouldActOnSuffocation || cannotFindSafeHull))
153 bool needsEquipment = shouldActOnSuffocation;
158 else if (needsDivingGear)
164 if (cannotFindDivingGear && retryCounter < findDivingGearAttempts)
166 retryTimer = retryResetTime;
168 needsDivingSuit = !needsDivingSuit;
169 RemoveSubObjective(ref divingGearObjective);
171 if (divingGearObjective ==
null)
173 cannotFindDivingGear =
false;
174 RemoveSubObjective(ref goToObjective);
175 TryAddSubObjective(ref divingGearObjective,
179 searchHullTimer = Math.Min(1, searchHullTimer);
180 cannotFindDivingGear =
true;
185 resetPriority =
true;
186 searchHullTimer = Math.Min(1, searchHullTimer);
187 RemoveSubObjective(ref divingGearObjective);
192 if (divingGearObjective ==
null || !divingGearObjective.
CanBeCompleted)
196 searchHullTimer = Math.Min(1, searchHullTimer);
198 if (searchHullTimer > 0.0f)
200 searchHullTimer -= deltaTime;
210 searchHullTimer = SearchHullInterval * Rand.Range(0.9f, 1.1f);
211 previousSafeHull = currentSafeHull;
212 currentSafeHull = potentialSafeHull;
213 cannotFindSafeHull = currentSafeHull ==
null || NeedMoreDivingGear(currentSafeHull);
214 currentSafeHull ??= previousSafeHull;
215 if (currentSafeHull !=
null && currentSafeHull != currentHull)
217 if (goToObjective?.
Target != currentSafeHull)
219 RemoveSubObjective(ref goToObjective);
221 TryAddSubObjective(ref goToObjective,
224 SpeakIfFails =
false,
236 resetPriority =
true;
237 searchHullTimer = Math.Min(1, searchHullTimer);
239 RemoveSubObjective(ref goToObjective);
240 if (cannotFindDivingGear)
243 RemoveSubObjective(ref divingGearObjective);
251 if (goToObjective !=
null)
253 if (goToObjective.Target is
Hull hull)
261 RemoveSubObjective(ref goToObjective);
266 RemoveSubObjective(ref goToObjective);
287 Vector2 escapeVel = Vector2.Zero;
295 float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.
Position,
character.
Position), 0.1f, 10.0f);
296 escapeVel +=
new Vector2(Math.Sign(dir.X) * distMultiplier, !
character.
IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
306 escapeVel +=
new Vector2(Math.Sign(dir.X) * distMultiplier, !
character.
IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
310 if (escapeVel != Vector2.Zero)
338 private readonly List<Hull> hulls =
new List<Hull>();
339 private int hullSearchIndex = -1;
340 float bestHullValue = 0;
341 bool bestHullIsAirlock =
false;
342 Hull potentialBestHull;
345 private readonly Stopwatch stopWatch =
new Stopwatch();
354 if (hullSearchIndex == -1)
357 potentialBestHull =
null;
358 bestHullIsAirlock =
false;
366 if (hull.
Submarine ==
null) {
continue; }
371 if (ignoredHulls !=
null && ignoredHulls.Contains(hull)) {
continue; }
373 if (connectedSubs !=
null && !connectedSubs.Contains(hull.
Submarine)) {
continue; }
385 float hullSuitability = EstimateHullSuitability(hull);
386 for (
int i = 0; i < hulls.Count; i++)
388 Hull otherHull = hulls[i];
389 float otherHullSuitability = EstimateHullSuitability(otherHull);
390 if (hullSuitability > otherHullSuitability)
392 hulls.Insert(i, hull);
403 float EstimateHullSuitability(
Hull h)
411 float dist = distX + distY;
412 float suitability = -dist;
413 const float suitabilityReduction = 10000.0f;
416 suitability -= suitabilityReduction;
422 suitability -= suitabilityReduction;
426 suitability -= suitabilityReduction;
430 suitability -= suitabilityReduction;
444 DebugConsole.NewMessage($
"({character.DisplayName}) Sorted hulls by suitability in {stopWatch.ElapsedMilliseconds} ms", debugOnly:
true);
448 Hull potentialHull = hulls[hullSearchIndex];
450 float hullSafety = 0;
451 bool hullIsAirlock =
false;
453 if (isCharacterInside)
457 hullSafety *= distanceFactor;
460 if (hullSafety > bestHullValue)
463 if (allowChangingSubmarine || potentialHull.
OutpostModuleTags.All(t => t !=
"airlock"))
467 if (path.Unreachable)
477 hullSafety /= 1 + unsafeNodes;
496 hullIsAirlock =
true;
505 hullSafety *= distanceFactor;
513 if (hullSafety > bestHullValue || (!isCharacterInside && hullIsAirlock && !bestHullIsAirlock))
515 potentialBestHull = potentialHull;
516 bestHullValue = hullSafety;
517 bestHullIsAirlock = hullIsAirlock;
520 bestHull = potentialBestHull;
523 if (hullSearchIndex >= hulls.Count)
525 hullSearchIndex = -1;
534 goToObjective =
null;
535 divingGearObjective =
null;
536 currentSafeHull =
null;
537 previousSafeHull =
null;
539 cannotFindDivingGear =
false;
540 cannotFindSafeHull =
false;
543 private bool NeedMoreDivingGear(
Hull targetHull,
float minOxygen = 0)
IEnumerable< Hull > VisibleHulls
Returns hulls that are visible to the character, including the current hull. Note that this is not an...
SteeringManager SteeringManager
static float GetMinOxygen(Character character)
override void Update(float deltaTime)
HullSearchStatus FindBestHull(out Hull bestHull, IEnumerable< Hull > ignoredHulls=null, bool allowChangingSubmarine=true)
Tries to find the best (safe, nearby) hull the character can find a path to. Checks one hull at a tim...
override Identifier Identifier
override bool CheckObjectiveState()
Should return whether the objective is completed or not.
override bool KeepDivingGearOn
void UpdateSimpleEscape(float deltaTime)
AIObjectiveFindSafety(Character character, AIObjectiveManager objectiveManager, float priorityModifier=1)
override bool CanBeCompleted
override bool ConcurrentObjectives
override float GetPriority()
override bool AllowOutsideSubmarine
override bool IgnoreUnsafeHulls
override bool AbandonWhenCannotCompleteSubObjectives
override bool AllowInAnySub
override void Act(float deltaTime)
virtual bool CanBeCompleted
float Priority
Final priority value after all calculations.
readonly Character character
IndoorsSteeringManager PathSteering
HumanAIController HumanAIController
readonly List< AIObjective > subObjectives
readonly AIObjectiveManager objectiveManager
static float GetDistanceFactor(Vector2 selfPos, Vector2 targetWorldPos, float factorAtMaxDistance, float verticalDistanceMultiplier=3, float maxDistance=10000.0f, float factorAtMinDistance=1.0f)
Get a normalized value representing how close the target position is. The value is a rough estimation...
const float EmergencyObjectivePriority
Priority of objectives such as finding safety, rescuing someone in a critical state or defending agai...
List< AIObjective > Objectives
Excluding the current order.
void AddObjective(AIObjective objective)
bool FailedToFindDivingGearForDepth
const float MaxObjectivePriority
Highest possible priority for any objective. Used in certain cases where the character needs to react...
virtual AIController AIController
override Vector2? SimPosition
static readonly List< Character > CharacterList
Vector2 GetRelativeSimPosition(ISpatialEntity target, Vector2? worldPos=null)
static bool IsOnFriendlyTeam(CharacterTeamType myTeam, CharacterTeamType otherTeam)
override Vector2 Position
void ReleaseSecondaryItem()
readonly AnimController AnimController
bool IsProtectedFromPressure
Is the character currently protected from the pressure by immunity/ability or a status effect (e....
virtual Vector2 WorldPosition
IEnumerable< Identifier > OutpostModuleTags
Inherited flags from outpost generation.
bool LeadsOutside(Character character)
Does this hull have any doors leading outside?
static readonly List< Hull > HullList
IEnumerable< Hull > GetConnectedHulls(bool includingThis, int? searchDepth=null, bool ignoreClosedGaps=false)
List< FireSource > FireSources
const float HULL_SAFETY_THRESHOLD
static bool HasDivingSuit(Character character, float conditionPercentage=0, bool requireOxygenTank=true, bool requireSuitablePressureProtection=true)
Check whether the character has a diving suit in usable condition, suitable pressure protection for t...
static bool HasDivingGear(Character character, float conditionPercentage=0, bool requireOxygenTank=true)
readonly HashSet< Hull > UnreachableHulls
static bool IsActive(Character c)
float GetHullSafety(Hull hull, Character character, IEnumerable< Hull > visibleHulls=null)
bool NeedsDivingGear(Hull hull, out bool needsSuit)
static bool IsFriendly(Character me, Character other, bool onlySameTeam=false)
readonly HashSet< Hull > UnsafeHulls
static bool HasDivingMask(Character character, float conditionPercentage=0, bool requireOxygenTank=true)
Check whether the character has a diving mask in usable condition plus some oxygen.
static readonly PrefabCollection< OrderPrefab > Prefabs
SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub=null, string errorMsgStr=null, float minGapSize=0, Func< PathNode, bool > startNodeFilter=null, Func< PathNode, bool > endNodeFilter=null, Func< PathNode, bool > nodeFilter=null, bool checkVisibility=true)
float ColliderHeightFromFloor
In sim units. Joint scale applied.
void SteeringManual(float deltaTime, Vector2 velocity)
static readonly Submarine[] MainSubs
IEnumerable< Submarine > GetConnectedSubs()
Returns a list of all submarines that are connected to this one via docking ports,...
bool IsEntityFoundOnThisSub(MapEntity entity, bool includingConnectedSubs, bool allowDifferentTeam=false, bool allowDifferentType=false)