Client LuaCsForBarotrauma
AIObjectiveCleanupItems.cs
3 using System.Collections.Generic;
4 using System.Linq;
5 
6 namespace Barotrauma
7 {
9  {
10  public override Identifier Identifier { get; set; } = "cleanup items".ToIdentifier();
11  public override bool KeepDivingGearOn => true;
12  public override bool AllowAutomaticItemUnequipping => false;
13  protected override bool ForceOrderPriority => false;
14 
15  public readonly List<Item> prioritizedItems = new List<Item>();
16 
17  protected override int MaxTargets => 100;
18 
19  public AIObjectiveCleanupItems(Character character, AIObjectiveManager objectiveManager, Item prioritizedItem = null, float priorityModifier = 1)
20  : base(character, objectiveManager, priorityModifier)
21  {
22  if (prioritizedItem != null)
23  {
24  prioritizedItems.Add(prioritizedItem);
25  }
26  }
27 
28  public AIObjectiveCleanupItems(Character character, AIObjectiveManager objectiveManager, IEnumerable<Item> prioritizedItems, float priorityModifier = 1)
29  : base(character, objectiveManager, priorityModifier)
30  {
31  this.prioritizedItems.AddRange(prioritizedItems.Where(i => i != null));
32  }
33 
34  protected override float GetTargetPriority()
35  {
36  if (Targets.None()) { return 0; }
37  if (objectiveManager.IsOrder(this))
38  {
39  float prio = objectiveManager.GetOrderPriority(this);
40  if (subObjectives.All(so => so.SubObjectives.None()))
41  {
42  // If none of the subobjectives have subobjectives, no valid container was found. Don't allow running.
43  ForceWalk = true;
44  }
45  return prio;
46  }
47  return AIObjectiveManager.RunPriority - 0.5f;
48  }
49 
50  protected override bool IsValidTarget(Item target)
51  {
52  System.Diagnostics.Debug.Assert(target.GetComponent<Pickable>() is { } pickable && !pickable.IsAttached, "Invalid target in AIObjectiveCleanUpItems - the the objective should only be checking pickable, non-attached items.");
53  System.Diagnostics.Debug.Assert(target.Prefab.PreferredContainers.Any(), "Invalid target in AIObjectiveCleanUpItems - the the objective should only be checking items that have preferred containers defined.");
54 
55  // If the target was selected as a valid target, we'll have to accept it so that the objective can be completed.
56  // The validity changes when a character picks the item up.
57  if (!IsValidTarget(target, character, checkInventory: true)) { return Objectives.ContainsKey(target) && IsItemInsideValidSubmarine(target, character); }
58  if (target.CurrentHull.FireSources.Count > 0) { return false; }
59  foreach (Character c in Character.CharacterList)
60  {
61  if (c == character || !HumanAIController.IsActive(c)) { continue; }
62  if (c.CurrentHull == target.CurrentHull && !HumanAIController.IsFriendly(c))
63  {
64  // Don't clean up items in rooms that have enemies inside.
65  return false;
66  }
67  }
68  return true;
69  }
70 
71  protected override IEnumerable<Item> GetList() => Item.CleanableItems;
72 
73  protected override AIObjective ObjectiveConstructor(Item item)
74  => new AIObjectiveCleanupItem(item, character, objectiveManager, priorityModifier: PriorityModifier)
75  {
76  IsPriority = prioritizedItems.Contains(item)
77  };
78 
79  protected override void OnObjectiveCompleted(AIObjective objective, Item target)
80  => HumanAIController.RemoveTargets<AIObjectiveCleanupItems, Item>(character, target);
81 
82  public static bool IsItemInsideValidSubmarine(Item item, Character character)
83  {
84  if (item == null || item.Removed) { return false; }
85  if (character == null || character.Removed) { return false; }
86  if (item.CurrentHull == null) { return false; }
87  if (item.Submarine == null) { return false; }
88  if (item.Submarine.TeamID != character.TeamID) { return false; }
89  if (character.Submarine != null && !character.Submarine.IsConnectedTo(item.Submarine)) { return false; }
90  return true;
91  }
92 
93  public static bool IsValidContainer(Item container, Character character) =>
94  container.HasTag(Tags.AllowCleanup) &&
95  container.HasAccess(character) &&
96  container.ParentInventory == null && container.OwnInventory != null && container.OwnInventory.AllItems.Any() &&
97  container.GetComponent<ItemContainer>() != null &&
98  IsItemInsideValidSubmarine(container, character) &&
99  !container.IsClaimedByBallastFlora;
100 
101  public static bool IsValidTarget(Item item, Character character, bool checkInventory, bool allowUnloading = true, bool requireValidContainer = true, bool ignoreItemsMarkedForDeconstruction = true)
102  {
103  if (item == null) { return false; }
104  if (item.DontCleanUp) { return false; }
105  if (item.Illegitimate == character.IsOnPlayerTeam) { return false; }
106  if (item.ParentInventory != null)
107  {
108  if (item.Container == null)
109  {
110  // In a character inventory
111  return false;
112  }
113  if (!allowUnloading) { return false; }
114  if (requireValidContainer && !IsValidContainer(item.Container, character)) { return false; }
115  }
116  if (ignoreItemsMarkedForDeconstruction && Item.DeconstructItems.Contains(item)) { return false; }
117  if (!item.HasAccess(character)) { return false; }
118  if (character != null && !IsItemInsideValidSubmarine(item, character)) { return false; }
119  if (item.HasBallastFloraInHull) { return false; }
120  //something (e.g. a pet) was eating the item within the last second - don't clean up
121  if (item.LastEatenTime > Timing.TotalTimeUnpaused - 1.0) { return false; }
122  var wire = item.GetComponent<Wire>();
123  if (wire != null)
124  {
125  if (wire.Connections.Any(c => c != null)) { return false; }
126  }
127  else
128  {
129  var connectionPanel = item.GetComponent<ConnectionPanel>();
130  if (connectionPanel != null && connectionPanel.Connections.Any(c => c.Wires.Count > 0))
131  {
132  return false;
133  }
134  }
135  if (item.GetComponent<Rope>() is { IsActive: true, Snapped: false })
136  {
137  // Don't clean up spears with an active rope component.
138  return false;
139  }
140  if (!checkInventory)
141  {
142  return true;
143  }
144  return CanPutInInventory(character, item, allowWearing: false);
145  }
146 
147  public override void OnDeselected()
148  {
149  base.OnDeselected();
150  foreach (var subObjective in SubObjectives)
151  {
152  if (subObjective is AIObjectiveCleanupItem cleanUpObjective)
153  {
154  cleanUpObjective.DropTarget();
155  }
156  }
157  }
158  }
159 }
static bool IsValidTarget(Item item, Character character, bool checkInventory, bool allowUnloading=true, bool requireValidContainer=true, bool ignoreItemsMarkedForDeconstruction=true)
override AIObjective ObjectiveConstructor(Item item)
static bool IsValidContainer(Item container, Character character)
static bool IsItemInsideValidSubmarine(Item item, Character character)
AIObjectiveCleanupItems(Character character, AIObjectiveManager objectiveManager, Item prioritizedItem=null, float priorityModifier=1)
override float GetTargetPriority()
Returns a priority value based on the current targets (e.g. high prio when there's lots of severe fir...
override bool IsValidTarget(Item target)
override IEnumerable< Item > GetList()
List of all possible items of the specified type. Used for filtering the removed objectives.
override void OnObjectiveCompleted(AIObjective objective, Item target)
AIObjectiveCleanupItems(Character character, AIObjectiveManager objectiveManager, IEnumerable< Item > prioritizedItems, float priorityModifier=1)
An objective that creates specific kinds of subobjectives for specific types of targets,...
Dictionary< T, AIObjective > Objectives
const float RunPriority
Objectives with a priority equal to or higher than this make the character run.
Submarine Submarine
Definition: Entity.cs:53
static bool IsActive(Character c)
static bool IsFriendly(Character me, Character other, bool onlySameTeam=false)
static IReadOnlyCollection< Item > CleanableItems
Items that may potentially need to be cleaned up (pickable, not attached to a wall,...
bool Illegitimate
Item shouldn't be in the player's inventory. If the guards find it, they will consider it as a theft.
float LastEatenTime
Timing.TotalTimeUnpaused when some character was last eating the item
bool DontCleanUp
Can be set by status effects to prevent bots from cleaning up the item
static HashSet< Item > DeconstructItems
Items that have been marked for deconstruction
bool HasAccess(Character character)
Used by the AI to check whether they can (in principle) and are allowed (in practice) to interact wit...
ImmutableArray< PreferredContainer > PreferredContainers
bool IsConnectedTo(Submarine otherSub)
Returns true if the sub is same as the other, or connected to it via docking ports.