3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
21 private const float PriorityIncrease = 100;
22 private const float PriorityDecrease = 10;
23 private const float SearchHullInterval = 3.0f;
25 private float currentHullSafety;
27 private float searchHullTimer;
37 private bool resetPriority;
94 public override void Update(
float deltaTime)
98 retryTimer -= deltaTime;
107 resetPriority =
false;
112 currentHullSafety = 0;
119 Priority -= PriorityDecrease * deltaTime;
128 float dangerFactor = (100 - currentHullSafety) / 100;
129 Priority += dangerFactor * PriorityIncrease * deltaTime;
135 private Hull currentSafeHull;
136 private Hull previousSafeHull;
137 private bool cannotFindSafeHull;
138 private bool cannotFindDivingGear;
139 private readonly
int findDivingGearAttempts = 2;
140 private int retryCounter;
141 private readonly
float retryResetTime = 5;
142 private float retryTimer;
143 protected override void Act(
float deltaTime)
145 if (resetPriority) {
return; }
149 if (!
character.
LockHands && (!dangerousPressure || shouldActOnSuffocation || cannotFindSafeHull))
152 bool needsEquipment = shouldActOnSuffocation;
157 else if (needsDivingGear)
163 if (cannotFindDivingGear && retryCounter < findDivingGearAttempts)
165 retryTimer = retryResetTime;
167 needsDivingSuit = !needsDivingSuit;
168 RemoveSubObjective(ref divingGearObjective);
170 if (divingGearObjective ==
null)
172 cannotFindDivingGear =
false;
173 RemoveSubObjective(ref goToObjective);
174 TryAddSubObjective(ref divingGearObjective,
178 searchHullTimer = Math.Min(1, searchHullTimer);
179 cannotFindDivingGear =
true;
184 resetPriority =
true;
185 searchHullTimer = Math.Min(1, searchHullTimer);
186 RemoveSubObjective(ref divingGearObjective);
191 if (divingGearObjective ==
null || !divingGearObjective.
CanBeCompleted)
195 searchHullTimer = Math.Min(1, searchHullTimer);
197 if (searchHullTimer > 0.0f)
199 searchHullTimer -= deltaTime;
209 searchHullTimer = SearchHullInterval * Rand.Range(0.9f, 1.1f);
210 previousSafeHull = currentSafeHull;
211 currentSafeHull = potentialSafeHull;
212 cannotFindSafeHull = currentSafeHull ==
null || NeedMoreDivingGear(currentSafeHull);
213 currentSafeHull ??= previousSafeHull;
214 if (currentSafeHull !=
null && currentSafeHull != currentHull)
216 if (goToObjective?.
Target != currentSafeHull)
218 RemoveSubObjective(ref goToObjective);
220 TryAddSubObjective(ref goToObjective,
223 SpeakIfFails =
false,
235 resetPriority =
true;
236 searchHullTimer = Math.Min(1, searchHullTimer);
238 RemoveSubObjective(ref goToObjective);
239 if (cannotFindDivingGear)
242 RemoveSubObjective(ref divingGearObjective);
250 if (goToObjective !=
null)
252 if (goToObjective.Target is
Hull hull)
260 RemoveSubObjective(ref goToObjective);
265 RemoveSubObjective(ref goToObjective);
286 Vector2 escapeVel = Vector2.Zero;
294 float distMultiplier = MathHelper.Clamp(100.0f / Vector2.Distance(fireSource.
Position,
character.
Position), 0.1f, 10.0f);
295 escapeVel +=
new Vector2(Math.Sign(dir.X) * distMultiplier, !
character.
IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
305 escapeVel +=
new Vector2(Math.Sign(dir.X) * distMultiplier, !
character.
IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
309 if (escapeVel != Vector2.Zero)
337 private readonly List<Hull> hulls =
new List<Hull>();
338 private int hullSearchIndex = -1;
339 float bestHullValue = 0;
340 bool bestHullIsAirlock =
false;
341 Hull potentialBestHull;
349 if (hullSearchIndex == -1)
352 potentialBestHull =
null;
353 bestHullIsAirlock =
false;
358 if (hull.
Submarine ==
null) {
continue; }
363 if (ignoredHulls !=
null && ignoredHulls.Contains(hull)) {
continue; }
365 if (connectedSubs !=
null && !connectedSubs.Contains(hull.
Submarine)) {
continue; }
370 float hullSuitability = EstimateHullSuitability(
character, hull);
377 for (
int i = 0; i < hulls.Count; i++)
379 if (hullSuitability > EstimateHullSuitability(
character, hulls[i]))
381 hulls.Insert(i, hull);
400 float suitability = -dist;
403 suitability -= 10000.0f;
408 Hull potentialHull = hulls[hullSearchIndex];
410 float hullSafety = 0;
411 bool hullIsAirlock =
false;
413 if (isCharacterInside)
417 hullSafety *= distanceFactor;
420 if (hullSafety > bestHullValue)
423 if (allowChangingSubmarine || !potentialHull.
OutpostModuleTags.Any(t => t ==
"airlock"))
427 if (path.Unreachable)
437 hullSafety /= 1 + unsafeNodes;
456 hullIsAirlock =
true;
465 hullSafety *= distanceFactor;
473 if (hullSafety > bestHullValue || (!isCharacterInside && hullIsAirlock && !bestHullIsAirlock))
475 potentialBestHull = potentialHull;
476 bestHullValue = hullSafety;
477 bestHullIsAirlock = hullIsAirlock;
480 bestHull = potentialBestHull;
483 if (hullSearchIndex >= hulls.Count)
485 hullSearchIndex = -1;
494 goToObjective =
null;
495 divingGearObjective =
null;
496 currentSafeHull =
null;
497 previousSafeHull =
null;
499 cannotFindDivingGear =
false;
500 cannotFindSafeHull =
false;
503 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 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 CheckObjectiveSpecific()
Should return whether the objective is completed or not.
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)