3 using System.Collections.Generic;
11 public override string DebugTag => $
"{Identifier} ({gearTag})";
21 private Item targetItem;
22 private int? oxygenSourceSlotIndex;
31 gearTag = needsDivingSuit ? Tags.HeavyDivingGear : Tags.LightDivingGear;
34 protected override void Act(
float deltaTime)
37 if (targetItem ==
null && gearTag == Tags.LightDivingGear)
42 if (targetItem ==
null ||
44 targetItem.
ContainedItems.Any(it => IsSuitableContainedOxygenSource(it)))
46 bool mustFindMorePressureProtection =
50 TryAddSubObjective(ref getDivingGear, () =>
54 character.Speak(TextManager.Get(
"DialogGetDivingGear").Value, null, 0.0f,
"getdivinggear".ToIdentifier(), 30.0f);
59 AllowToFindDivingGear =
false,
60 AllowDangerousPressure =
true,
64 if (gearTag == Tags.HeavyDivingGear)
66 if (mustFindMorePressureProtection)
70 getItemObjective.ItemFilter = it => IsSuitablePressureProtection(it, gearTag, character);
76 getItemObjective.GetItemPriority = it => IsSuitablePressureProtection(it, gearTag, character) ? 1000.0f : 1.0f;
78 getItemObjective.GetItemPriority = it =>
80 if (IsSuitablePressureProtection(it, gearTag, character))
89 return mustFindMorePressureProtection ? 0.0f : 1.0f;
93 return getItemObjective;
102 RemoveSubObjective(ref getDivingGear);
105 foreach (Item mask
in masks)
107 if (mask != targetItem)
117 float min = GetMinOxygen(character);
120 TryAddSubObjective(ref getOxygen, () =>
122 if (character.IsOnPlayerTeam)
124 if (HumanAIController.HasItem(character, Tags.OxygenSource, out _, conditionPercentage: min))
126 character.Speak(TextManager.Get(
"dialogswappingoxygentank").Value, null, 0,
"swappingoxygentank".ToIdentifier(), 30.0f);
127 if (character.Inventory.FindAllItems(i => i.HasTag(Tags.OxygenSource) && i.Condition > min, recursive: true).Count == 1)
129 character.Speak(TextManager.Get(
"dialoglastoxygentank").Value, null, 0.0f,
"dialoglastoxygentank".ToIdentifier(), 30.0f);
134 character.Speak(TextManager.Get(
"DialogGetOxygenTank").Value, null, 0,
"getoxygentank".ToIdentifier(), 30.0f);
138 var objective =
new AIObjectiveContainItem(character, Tags.OxygenSource, container, objectiveManager, spawnItemIfNotFound: character.TeamID ==
CharacterTeamType.FriendlyNPC)
140 AllowToFindDivingGear =
false,
141 AllowDangerousPressure =
true,
142 ConditionLevel = MIN_OXYGEN,
143 RemoveExistingWhenNecessary =
true,
144 TargetSlot = oxygenSourceSlotIndex
146 if (container.HasSubContainers)
151 objective.RemoveExistingPredicate = i => objective.IsInTargetSlot(i);
157 int remainingTanks = ReportOxygenTankCount();
159 TryAddSubObjective(ref getOxygen, () =>
161 return new AIObjectiveContainItem(character, Tags.OxygenSource, targetItem.GetComponent<
ItemContainer>(), objectiveManager, spawnItemIfNotFound: character.TeamID ==
CharacterTeamType.FriendlyNPC)
163 AllowToFindDivingGear =
false,
164 AllowDangerousPressure =
true,
165 RemoveExisting =
true
171 if (remainingTanks > 0 && !HumanAIController.HasItem(character, Tags.OxygenSource, out _, conditionPercentage: 0.01f))
173 character.Speak(TextManager.Get(
"dialogcantfindtoxygen").Value,
null, 0,
"cantfindoxygen".ToIdentifier(), 30.0f);
176 onCompleted: () => RemoveSubObjective(ref getOxygen));
180 RemoveSubObjective(ref getOxygen);
181 ReportOxygenTankCount();
184 int ReportOxygenTankCount()
186 if (character.Submarine !=
Submarine.MainSub) {
return 1; }
187 int remainingOxygenTanks =
Submarine.MainSub.GetItems(
false).Count(i => i.HasTag(Tags.OxygenSource) && i.Condition > 1);
188 if (remainingOxygenTanks == 0)
190 character.Speak(TextManager.Get(
"DialogOutOfOxygenTanks").Value,
null, 0.0f,
"outofoxygentanks".ToIdentifier(), 30.0f);
192 else if (remainingOxygenTanks < 10)
194 character.Speak(TextManager.Get(
"DialogLowOnOxygenTanks").Value,
null, 0.0f,
"lowonoxygentanks".ToIdentifier(), 30.0f);
196 return remainingOxygenTanks;
204 if (tag == Tags.HeavyDivingGear)
216 private bool IsSuitableContainedOxygenSource(
Item item)
220 item.
HasTag(Tags.OxygenSource) &&
225 private void TrySetTargetItem(Item item)
227 if (targetItem == item) {
return; }
229 if (targetItem !=
null)
231 oxygenSourceSlotIndex = targetItem.GetComponent<
ItemContainer>()?.FindSuitableSubContainerIndex(Tags.OxygenSource);
235 oxygenSourceSlotIndex =
null;
242 getDivingGear =
null;
245 oxygenSourceSlotIndex =
null;
255 if (minOxygen > min && character.
Inventory.
AllItems.Any(i => i.HasTag(Tags.OxygenSource) && i.ConditionPercentage >= minOxygen))
override bool AllowWhileHandcuffed
static float GetMinOxygen(Character character)
AIObjectiveFindDivingGear(Character character, bool needsDivingSuit, AIObjectiveManager objectiveManager, float priorityModifier=1)
override void Act(float deltaTime)
override Identifier Identifier
static bool IsSuitablePressureProtection(Item item, Identifier tag, Character character)
override bool CheckObjectiveSpecific()
Should return whether the objective is completed or not.
override bool KeepDivingGearOn
override bool AbandonWhenCannotCompleteSubObjectives
readonly Character character
HumanAIController HumanAIController
readonly AIObjectiveManager objectiveManager
bool FailedToFindDivingGearForDepth
bool HasEquippedItem(Item item, InvSlotType? slotType=null, Func< InvSlotType, bool > predicate=null)
CharacterInventory Inventory
override bool TryPutItem(Item item, Character user, IEnumerable< InvSlotType > allowedSlots=null, bool createNetworkEvent=true, bool ignoreCondition=false)
If there is room, puts the item in the inventory and returns true, otherwise returns false
virtual Vector2 WorldPosition
static bool HasItem(Character character, Identifier tagOrIdentifier, out IEnumerable< Item > items, Identifier containedTag=default, float conditionPercentage=0, bool requireEquipped=false, bool recursive=true, Func< Item, bool > predicate=null)
Note: uses a single list for matching items. The item is reused each time when the method is called....
bool NeedsDivingGear(Hull hull, out bool needsSuit)
Item FindItem(Func< Item, bool > predicate, bool recursive)
virtual IEnumerable< Item > AllItems
All items contained in the inventory. Stacked items are returned as individual instances....
bool IsInSlot(Item item, int index)
ItemInventory OwnInventory
Inventory ParentInventory
bool HasTag(Identifier tag)
IEnumerable< Item > ContainedItems
int? FindSuitableSubContainerIndex(Identifier itemTagOrIdentifier)
Returns the index of the first slot whose restrictions match the specified tag or identifier
const float PressureWarningThreshold
How many units before crush depth the pressure warning is shown
readonly float PressureProtection
How deep down does the item protect from pressure? Determined by status effects.
float GetRealWorldDepth(float worldPositionY)
Calculate the "real" depth in meters from the surface of Europa (the value you see on the nav termina...