4 using Microsoft.Xna.Framework;
43 float coopMultiplier = 1;
49 if (c.IsPlayer) {
continue; }
54 if (fixLeak.Leak ==
Leak)
63 coopMultiplier = 0.1f;
82 float distanceFactor =
isPriority || xDist < 200 && yDist < 100 ? 1 : MathHelper.Lerp(1, 0.1f, MathUtils.InverseLerp(0, 3000, xDist + yDist * 3.0f));
90 Priority = MathHelper.Lerp(0, maxPriority, MathHelper.Clamp(devotion + (severity * distanceFactor *
PriorityModifier * coopMultiplier), 0, 1));
95 protected override void Act(
float deltaTime)
98 var repairTool = weldingTool?.GetComponent<
RepairTool>();
99 if (weldingTool ==
null)
104 if (character.IsOnPlayerTeam && objectiveManager.IsCurrentOrder<AIObjectiveFixLeaks>())
106 character.Speak(TextManager.Get(
"dialogcannotfindweldingequipment").Value, null, 0.0f,
"dialogcannotfindweldingequipment".ToIdentifier(), 10.0f);
110 onCompleted: () => RemoveSubObjective(ref getWeldingTool));
115 if (repairTool ==
null)
118 DebugConsole.ThrowError($
"{character.Name}: AIObjectiveFixLeak failed - the item \"{weldingTool}\" has no RepairTool component but is tagged as a welding tool");
123 if (weldingTool.OwnInventory ==
null && repairTool.RequiredItems.Any(r => r.Key == RelatedItem.RelationType.Contained))
126 DebugConsole.ThrowError($
"{character.Name}: AIObjectiveFixLeak failed - the item \"{weldingTool}\" has no proper inventory");
131 if (weldingTool.OwnInventory !=
null && weldingTool.OwnInventory.AllItems.None(i => i.HasTag(Tags.WeldingFuel) && i.Condition > 0.0f))
135 RemoveExisting = true
140 ReportWeldingFuelTankCount();
144 RemoveSubObjective(ref refuelObjective);
145 ReportWeldingFuelTankCount();
148 void ReportWeldingFuelTankCount()
151 int remainingOxygenTanks =
Submarine.MainSub.GetItems(
false).Count(i => i.HasTag(Tags.WeldingFuel) && i.Condition > 1);
152 if (remainingOxygenTanks == 0)
154 character.
Speak(TextManager.Get(
"DialogOutOfWeldingFuel").Value,
null, 0.0f,
"outofweldingfuel".ToIdentifier(), 30.0f);
156 else if (remainingOxygenTanks < 4)
158 character.
Speak(TextManager.Get(
"DialogLowOnWeldingFuel").Value,
null, 0.0f,
"lowonweldingfuel".ToIdentifier(), 30.0f);
172 bool canOperate = toLeak.LengthSquared() < reach * reach;
178 EndNodeFilter = n => true
180 onAbandon: () =>
Abandon =
true,
183 if (CheckObjectiveState()) { IsCompleted = true; }
193 TryAddSubObjective(ref gotoObjective, () =>
new AIObjectiveGoTo(Leak, character, objectiveManager)
195 UseDistanceRelativeToAimSourcePos =
true,
197 DialogueIdentifier = Leak.FlowTargetHull !=
null ?
"dialogcannotreachleak".ToIdentifier() : Identifier.Empty,
198 TargetName = Leak.FlowTargetHull?.DisplayName,
199 requiredCondition = () =>
200 Leak.Submarine == character.Submarine &&
201 Leak.linkedTo.Any(e => e is Hull h && (character.CurrentHull == h || h.linkedTo.Contains(character.CurrentHull))),
202 endNodeFilter = IsSuitableEndNode,
205 SpeakCannotReachCondition = () => isPriority && !CheckObjectiveState()
209 if (CheckObjectiveState()) { IsCompleted =
true; }
210 else if ((Leak.WorldPosition - character.AnimController.AimSourceWorldPos).LengthSquared() > MathUtils.Pow(reach * 2, 2))
218 RemoveSubObjective(ref gotoObjective);
221 onCompleted: () => RemoveSubObjective(ref gotoObjective));
223 bool IsSuitableEndNode(PathNode n)
225 if (n.Waypoint.CurrentHull is
null) {
return false; }
226 if (n.Waypoint.CurrentHull.ConnectedGaps.Contains(Leak)) {
return true; }
228 return Leak.linkedTo.Any(e => e is Hull h && h.linkedTo.Contains(n.Waypoint.CurrentHull));
236 getWeldingTool =
null;
237 refuelObjective =
null;
238 gotoObjective =
null;
239 operateObjective =
null;
248 return repairTool.
Range + armLength * 2;
override bool AllowInFriendlySubs
static float CalculateReach(RepairTool repairTool, Character character)
AIObjectiveFixLeak(Gap leak, Character character, AIObjectiveManager objectiveManager, float priorityModifier=1, bool isPriority=false)
override float GetPriority()
override bool AllowWhileHandcuffed
override bool AllowInAnySub
override Identifier Identifier
override void Act(float deltaTime)
override bool CheckObjectiveState()
Should return whether the objective is completed or not.
override bool KeepDivingGearOn
static float GetLeakSeverity(Gap leak)
float Priority
Final priority value after all calculations.
readonly Character character
HumanAIController HumanAIController
readonly List< AIObjective > subObjectives
readonly AIObjectiveManager objectiveManager
const float LowestOrderPriority
Maximum priority of an order given to the character (rightmost order in the crew list)
Vector2 AimSourceWorldPos
void Speak(string message, ChatMessageType? messageType=null, float delay=0.0f, Identifier identifier=default, float minDurationBetweenSimilar=0.0f)
static readonly List< Character > CharacterList
CharacterInventory Inventory
readonly AnimController AnimController
virtual Vector2 WorldPosition
HumanoidAnimController AnimController
static bool IsActive(Character c)
Item FindItemByTag(Identifier tag, bool recursive=false)
readonly List< MapEntity > linkedTo