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.CurrentHull == null) { return false; }
85  if (item.Submarine == null) { return false; }
86  if (item.Submarine.TeamID != character.TeamID) { return false; }
87  if (character.Submarine != null && !character.Submarine.IsConnectedTo(item.Submarine)) { return false; }
88  return true;
89  }
90 
91  public static bool IsValidContainer(Item container, Character character) =>
92  container.HasTag(Tags.AllowCleanup) &&
93  container.HasAccess(character) &&
94  container.ParentInventory == null && container.OwnInventory != null && container.OwnInventory.AllItems.Any() &&
95  container.GetComponent<ItemContainer>() != null &&
96  IsItemInsideValidSubmarine(container, character) &&
97  !container.IsClaimedByBallastFlora;
98 
99  public static bool IsValidTarget(Item item, Character character, bool checkInventory, bool allowUnloading = true, bool requireValidContainer = true, bool ignoreItemsMarkedForDeconstruction = true)
100  {
101  if (item == null) { return false; }
102  if (item.DontCleanUp) { return false; }
103  if (item.Illegitimate == character.IsOnPlayerTeam) { return false; }
104  if (item.ParentInventory != null)
105  {
106  if (item.Container == null)
107  {
108  // In a character inventory
109  return false;
110  }
111  if (!allowUnloading) { return false; }
112  if (requireValidContainer && !IsValidContainer(item.Container, character)) { return false; }
113  }
114  if (ignoreItemsMarkedForDeconstruction && Item.DeconstructItems.Contains(item)) { return false; }
115  if (!item.HasAccess(character)) { return false; }
116  if (character != null && !IsItemInsideValidSubmarine(item, character)) { return false; }
117  if (item.HasBallastFloraInHull) { return false; }
118  //something (e.g. a pet) was eating the item within the last second - don't clean up
119  if (item.LastEatenTime > Timing.TotalTimeUnpaused - 1.0) { return false; }
120  var wire = item.GetComponent<Wire>();
121  if (wire != null)
122  {
123  if (wire.Connections.Any(c => c != null)) { return false; }
124  }
125  else
126  {
127  var connectionPanel = item.GetComponent<ConnectionPanel>();
128  if (connectionPanel != null && connectionPanel.Connections.Any(c => c.Wires.Count > 0))
129  {
130  return false;
131  }
132  }
133  if (item.GetComponent<Rope>() is { IsActive: true, Snapped: false })
134  {
135  // Don't clean up spears with an active rope component.
136  return false;
137  }
138  if (!checkInventory)
139  {
140  return true;
141  }
142  return CanPutInInventory(character, item, allowWearing: false);
143  }
144 
145  public override void OnDeselected()
146  {
147  base.OnDeselected();
148  foreach (var subObjective in SubObjectives)
149  {
150  if (subObjective is AIObjectiveCleanupItem cleanUpObjective)
151  {
152  cleanUpObjective.DropTarget();
153  }
154  }
155  }
156  }
157 }
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.