Client LuaCsForBarotrauma
AIObjectiveContainItem.cs
3 using System;
4 using System.Collections.Generic;
5 using System.Collections.Immutable;
6 using System.Linq;
7 using Microsoft.Xna.Framework;
8 
9 namespace Barotrauma
10 {
12  {
13  public override Identifier Identifier { get; set; } = "contain item".ToIdentifier();
14  protected override bool AllowWhileHandcuffed => false;
15 
16  public Func<Item, float> GetItemPriority;
17 
18  public ImmutableHashSet<Identifier> ignoredContainerIdentifiers;
19  public bool checkInventory = true;
20 
21  //if the item can't be found, spawn it in the character's inventory (used by outpost NPCs and in some cases also enemy NPCs, like pirates)
22  private readonly bool spawnItemIfNotFound;
23 
24  //can either be a tag or an identifier
25  public readonly ImmutableHashSet<Identifier> itemIdentifiers;
26  public readonly ItemContainer container;
27  private readonly Item item;
28  public Item ItemToContain { get; private set; }
29 
30  public int? TargetSlot;
31 
32  private AIObjectiveGetItem getItemObjective;
33  private AIObjectiveGoTo goToObjective;
34 
35  private readonly HashSet<Item> containedItems = new HashSet<Item>();
36 
37  public bool AllowToFindDivingGear { get; set; } = true;
38  public bool AllowDangerousPressure { get; set; }
39  public float ConditionLevel { get; set; } = 1;
40  public bool Equip { get; set; }
41  public bool RemoveEmpty { get; set; } = true;
42  public bool RemoveExisting { get; set; }
46  public bool RemoveExistingWhenNecessary { get; set; }
47  public Func<Item, bool> RemoveExistingPredicate { get; set; }
48  public int? RemoveMax { get; set; }
49 
50  public bool MoveWholeStack { get; set; }
51 
52  private int _itemCount = 1;
53  public int ItemCount
54  {
55  get { return _itemCount; }
56  set
57  {
58  _itemCount = Math.Max(value, 1);
59  }
60  }
61 
63  : base(character, objectiveManager, priorityModifier)
64  {
65  this.container = container;
66  this.item = item;
67  }
68 
69  public AIObjectiveContainItem(Character character, Identifier itemIdentifier, ItemContainer container, AIObjectiveManager objectiveManager, float priorityModifier = 1, bool spawnItemIfNotFound = false)
70  : this(character, itemIdentifier.ToEnumerable().ToImmutableHashSet(), container, objectiveManager, priorityModifier, spawnItemIfNotFound) { }
71 
72  public AIObjectiveContainItem(Character character, ImmutableHashSet<Identifier> itemIdentifiers, ItemContainer container, AIObjectiveManager objectiveManager, float priorityModifier = 1, bool spawnItemIfNotFound = false)
73  : base(character, objectiveManager, priorityModifier)
74  {
75  this.itemIdentifiers = itemIdentifiers;
76  this.spawnItemIfNotFound = spawnItemIfNotFound;
77  this.container = container;
78  }
79 
80  protected override bool CheckObjectiveState()
81  {
82  if (container?.Item == null || !container.Item.HasAccess(character))
83  {
84  Abandon = true;
85  return false;
86  }
87  if (item != null)
88  {
89  return container.Inventory.Contains(item);
90  }
91  else
92  {
93  return CountItems();
94  }
95  }
96 
97  private bool CountItems()
98  {
99  int containedItemCount = 0;
100  foreach (Item it in container.Inventory.AllItems)
101  {
102  if (CheckItem(it) && IsInTargetSlot(it))
103  {
104  containedItemCount++;
105  }
106  }
107  return containedItemCount >= ItemCount;
108  }
109 
110  private bool CheckItem(Item item)
111  {
112  return item.HasIdentifierOrTags(itemIdentifiers) && item.ConditionPercentage >= ConditionLevel && item.HasAccess(character) && container.ShouldBeContained(item, out _);
113  }
114 
115  protected override void Act(float deltaTime)
116  {
117  if (container?.Item == null)
118  {
119  Abandon = true;
120  return;
121  }
122  ItemToContain = item ?? character.Inventory.FindItem(it =>
123  CheckItem(it) &&
124  //ignore items already in the container, unless we're trying to place to a specific slot, and the item's not in it
125  (it.Container != container.Item || (TargetSlot.HasValue && it.Container.OwnInventory.FindIndex(it) != TargetSlot)),
126  recursive: true);
127  if (ItemToContain != null)
128  {
129  if (!character.CanInteractWith(ItemToContain, checkLinked: false))
130  {
131  Abandon = true;
132  return;
133  }
134  if (character.CanInteractWith(container.Item, checkLinked: false))
135  {
136  static bool CanBePut(Inventory inventory, int? targetSlot, Item itemToContain)
137  {
138  if (targetSlot.HasValue)
139  {
140  return inventory.CanBePutInSlot(itemToContain, targetSlot.Value);
141  }
142  else
143  {
144  return inventory.CanBePut(itemToContain);
145  }
146  }
147 
149  {
151  }
152  else if (RemoveEmpty)
153  {
155  }
156  Inventory originalInventory = ItemToContain.ParentInventory;
157  var slots = originalInventory?.FindIndices(ItemToContain);
158 
159  bool TryPutItem(Inventory inventory, int? targetSlot, Item itemToContain)
160  {
161  if (targetSlot.HasValue)
162  {
163  return inventory.TryPutItem(itemToContain, targetSlot.Value, allowSwapping: false, allowCombine: false, user: character);
164  }
165  else
166  {
167  return inventory.TryPutItem(itemToContain, user: character);
168  }
169  }
170 
171  if (TryPutItem(container.Inventory, TargetSlot, ItemToContain))
172  {
173  if (MoveWholeStack && slots != null)
174  {
175  foreach (int slot in slots)
176  {
177  foreach (Item item in originalInventory.GetItemsAt(slot).ToList())
178  {
179  TryPutItem(container.Inventory, TargetSlot, item);
180  }
181  }
182  }
183  IsCompleted = item != null || CountItems();
184  }
185  else
186  {
188  {
190  }
191  Abandon = true;
192  }
193  }
194  else
195  {
196  TryAddSubObjective(ref goToObjective, () => new AIObjectiveGoTo(container.Item, character, objectiveManager, getDivingGearIfNeeded: AllowToFindDivingGear)
197  {
198  TargetName = container.Item.Name,
199  AbortCondition = obj =>
200  container?.Item == null || container.Item.Removed || !container.Item.HasAccess(character) ||
201  (container.Item.RootContainer?.OwnInventory?.Locked ?? false) ||
202  ItemToContain == null || ItemToContain.Removed ||
203  !ItemToContain.IsOwnedBy(character) || container.Item.GetRootInventoryOwner() is Character c && c != character,
204  SpeakIfFails = !objectiveManager.IsCurrentOrder<AIObjectiveCleanupItems>(),
205  endNodeFilter = n => Vector2.DistanceSquared(n.Waypoint.WorldPosition, container.Item.WorldPosition) <= MathUtils.Pow2(AIObjectiveGetItem.MaxReach)
206  },
207  onAbandon: () => Abandon = true,
208  onCompleted: () => RemoveSubObjective(ref goToObjective));
209  }
210  }
211  else
212  {
213  if (character.Submarine == null)
214  {
215  Abandon = true;
216  }
217  else
218  {
219  // No matching items in the inventory, try to get an item
220  TryAddSubObjective(ref getItemObjective, () =>
221  new AIObjectiveGetItem(character, itemIdentifiers, objectiveManager, equip: Equip, checkInventory: checkInventory, spawnItemIfNotFound: spawnItemIfNotFound)
222  {
225  ignoredItems = containedItems,
228  TargetCondition = ConditionLevel,
229  ItemFilter = (Item potentialItem) =>
230  {
231  return (RemoveEmpty ? container.CanBeContained(potentialItem) : container.Inventory.CanBePut(potentialItem)) && container.ShouldBeContained(potentialItem, out _);
232  },
234  TakeWholeStack = MoveWholeStack
235  }, onAbandon: () =>
236  {
237  Abandon = true;
238  }, onCompleted: () =>
239  {
240  if (getItemObjective?.TargetItem != null)
241  {
242  containedItems.Add(getItemObjective.TargetItem);
243  }
244  RemoveSubObjective(ref getItemObjective);
245  });
246  }
247  }
248  }
249 
250  public bool IsInTargetSlot(Item item)
251  {
252  if (TargetSlot == null) { return true; }
253  if (container?.Inventory is ItemInventory inventory)
254  {
255  return inventory.IsInSlot(item, (int)TargetSlot);
256  }
257  return false;
258  }
259 
260  public override void Reset()
261  {
262  base.Reset();
263  getItemObjective = null;
264  goToObjective = null;
265  containedItems.Clear();
266  }
267  }
268 }
void UnequipContainedItems(Item parentItem, Func< Item, bool > predicate=null, bool avoidDroppingInSea=true, int? unequipMax=null)
void UnequipEmptyItems(Item parentItem, bool avoidDroppingInSea=true)
AIObjectiveContainItem(Character character, Item item, ItemContainer container, AIObjectiveManager objectiveManager, float priorityModifier=1)
override bool CheckObjectiveState()
Should return whether the objective is completed or not.
AIObjectiveContainItem(Character character, Identifier itemIdentifier, ItemContainer container, AIObjectiveManager objectiveManager, float priorityModifier=1, bool spawnItemIfNotFound=false)
AIObjectiveContainItem(Character character, ImmutableHashSet< Identifier > itemIdentifiers, ItemContainer container, AIObjectiveManager objectiveManager, float priorityModifier=1, bool spawnItemIfNotFound=false)
ImmutableHashSet< Identifier > ignoredContainerIdentifiers
override void Act(float deltaTime)
readonly ImmutableHashSet< Identifier > itemIdentifiers
bool RemoveExistingWhenNecessary
Only remove existing items when the contain target can't be put in the inventory
bool CanInteractWith(Character c, float maxDist=200.0f, bool checkVisibility=true, bool skipDistanceCheck=false)
Submarine Submarine
Definition: Entity.cs:53
virtual bool CanBePutInSlot(Item item, int i, bool ignoreCondition=false)
Can the item be put in the specified slot.
virtual 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
bool Contains(Item item)
Is the item contained in this inventory. Does not recursively check items inside items.
List< int > FindIndices(Item item)
Find the indices of all the slots the item is contained in (two-hand items for example can be in mult...
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....
int FindIndex(Item item)
Find the index of the first slot the item is contained in.
IEnumerable< Item > GetItemsAt(int index)
Get all the item stored in the specified inventory slot. Can return more than one item if the slot co...
bool CanBePut(Item item)
Can the item be put in the inventory (i.e. is there a suitable free slot or a stack the item can be p...
void Drop(Character dropper, bool createNetworkEvent=true, bool setTransform=true)
bool HasAccess(Character character)
Used by the AI to check whether they can (in principle) and are allowed (in practice) to interact wit...
bool ShouldBeContained(string[] identifiersOrTags, out bool isRestrictionsDefined)