Client LuaCsForBarotrauma
AIObjectiveFindThieves.cs
1 #nullable enable
2 using Microsoft.Xna.Framework;
3 using System.Collections.Generic;
4 using System.Linq;
6 
7 namespace Barotrauma
8 {
10  {
11  public override Identifier Identifier { get; set; } = "find thieves".ToIdentifier();
12  protected override float IgnoreListClearInterval => 30;
13  public override bool IgnoreUnsafeHulls => true;
14 
15  protected override float TargetUpdateTimeMultiplier => 1.0f;
16 
21  private const float DelayOnRoundStart = 30.0f;
22 
23  private const float DefaultInspectDistance = 200.0f;
27  private const float ExtendedInspectDistance = 400.0f;
31  private const float CriminalInspectDistance = 500.0f;
32 
33  private const float CriminalInspectProbability = 1.0f;
34 
39  private float inspectDistance = DefaultInspectDistance;
40 
41  private float? overrideInspectProbability;
46  public float InspectProbability
47  {
48  get
49  {
50  if (overrideInspectProbability.HasValue)
51  {
52  return overrideInspectProbability.Value;
53  }
54  if (GameMain.GameSession?.Campaign is { } campaign)
55  {
56  if (campaign.Map?.CurrentLocation?.Reputation is { } reputation)
57  {
58  return MathHelper.Lerp(
59  campaign.Settings.PatdownProbabilityMax,
60  campaign.Settings.PatdownProbabilityMin,
61  reputation.NormalizedValue);
62  }
63  }
64 
65  return 0.2f;
66  }
67  }
68 
72  private static readonly Dictionary<Character, double> lastInspectionTimes = new Dictionary<Character, double>();
73 
74  private const float NormalInspectionInterval = 120.0f;
75  private const float CriminalInspectionInterval = 30.0f;
76 
77  public AIObjectiveFindThieves(Character character, AIObjectiveManager objectiveManager, float priorityModifier = 1)
78  : base(character, objectiveManager, priorityModifier) { }
79 
80  protected override bool IsValidTarget(Character target)
81  {
82  if (GameMain.GameSession is not { RoundDuration: > DelayOnRoundStart })
83  {
84  return false;
85  }
86  if (!IsValidTarget(target, character)) { return false; }
87  float inspectDist = target.IsCriminal ? CriminalInspectDistance : inspectDistance;
88  if (Vector2.DistanceSquared(target.WorldPosition, character.WorldPosition) > inspectDist * inspectDist) { return false; }
89  if (lastInspectionTimes.TryGetValue(target, out double lastInspectionTime))
90  {
91  float inspectionInterval = target.IsCriminal ? CriminalInspectionInterval : NormalInspectionInterval;
92  if (Timing.TotalTime < lastInspectionTime + inspectionInterval)
93  {
94  return false;
95  }
96  }
97  return true;
98  }
99 
100  protected override IEnumerable<Character> GetList() => Character.CharacterList;
101 
102  protected override float GetTargetPriority()
103  {
104  if (character.IsClimbing)
105  {
106  // Don't inspect while climbing, because cannot grab while holding the ladders.
107  // Can lead to abandoning the objective when we need to climb the ladders to get to the target, but I think that's acceptable.
108  return 0;
109  }
110  return subObjectives.Any() ? 50 : 0;
111  }
112 
113  public void InspectEveryone()
114  {
115  lastInspectionTimes.Clear();
116  overrideInspectProbability = 1.0f;
117  inspectDistance = ExtendedInspectDistance;
118  }
119 
120  protected override AIObjective ObjectiveConstructor(Character target)
121  {
122  var checkStolenItemsObjective = new AIObjectiveCheckStolenItems(character, target, objectiveManager);
123  float probabity = target.IsCriminal ? CriminalInspectProbability : InspectProbability;
124  if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Unsynced) >= probabity)
125  {
126  checkStolenItemsObjective.ForceComplete();
127  lastInspectionTimes[target] = Timing.TotalTime;
128  }
129  return checkStolenItemsObjective;
130  }
131 
132  private float checkVisibleStolenItemsTimer;
133  private const float CheckVisibleStolenItemsInterval = 5.0f;
134 
135  public override void Update(float deltaTime)
136  {
137  base.Update(deltaTime);
138  if (checkVisibleStolenItemsTimer > 0.0f || character.IsClimbing)
139  {
140  checkVisibleStolenItemsTimer -= deltaTime;
141  return;
142  }
143  if (character.SelectedSecondaryItem?.GetComponent<Controller>() != null)
144  {
145  // Might be e.g. sitting on a chair.
146  character.SelectedSecondaryItem = null;
147  }
148  foreach (var target in Character.CharacterList)
149  {
150  if (!IsValidTarget(target, character)) { continue; }
151  //if we spot someone wearing or holding stolen items, immediately check them (with 100% chance of spotting the stolen items)
152  if (target.Inventory.AllItems.Any(it => it.Illegitimate && target.HasEquippedItem(it)) &&
153  character.CanSeeTarget(target, seeThroughWindows: true))
154  {
155  AIObjectiveCheckStolenItems? existingObjective =
156  objectiveManager.GetActiveObjectives<AIObjectiveCheckStolenItems>().FirstOrDefault(o => o.Target == target);
157  if (existingObjective == null)
158  {
159  objectiveManager.AddObjective(new AIObjectiveCheckStolenItems(character, target, objectiveManager));
160  lastInspectionTimes[target] = Timing.TotalTime;
161  }
162  }
163  }
164  checkVisibleStolenItemsTimer = CheckVisibleStolenItemsInterval;
165  }
166 
167  private bool IsValidTarget(Character target, Character character)
168  {
169  if (target == null || target.Removed) { return false; }
170  if (target.IsIncapacitated) { return false; }
171  if (target == character) { return false; }
172  if (target.Submarine == null) { return false; }
173  if (character.Submarine == null) { return false; }
174  if (target.CurrentHull == null) { return false; }
175  if (target.Submarine != character.Submarine) { return false; }
176  //only player's crew can steal, ignore other teams
177  if (!target.IsOnPlayerTeam) { return false; }
178  if (target.IsHandcuffed) { return false; }
179  //ignore thieves in the same team
180  if (character.OriginalTeamID == target.TeamID || character.TeamID == target.TeamID) { return false; }
181  // Ignore targets that are climbing, because might need to use ladders to get to them.
182  if (target.IsClimbing) { return false; }
183  if (HumanAIController.IsTrueForAnyBotInTheCrew(bot =>
184  bot != HumanAIController &&
185  ((bot.ObjectiveManager.GetActiveObjective() is AIObjectiveCheckStolenItems checkObj && checkObj.Target == target) ||
186  (bot.ObjectiveManager.GetActiveObjective() is AIObjectiveCombat combatObj && combatObj.Enemy == target))))
187  {
188  // Already being inspected by someone or fighting with someone in our team.
189  return false;
190  }
191  return true;
192  }
193 
194  protected override void OnObjectiveCompleted(AIObjective objective, Character target)
195  {
196  lastInspectionTimes[target] = Timing.TotalTime;
197  }
198 
199  public override void OnDeselected()
200  {
201  base.OnDeselected();
202  character.DeselectCharacter();
203  }
204  }
205 }
override void Update(float deltaTime)
override float GetTargetPriority()
Returns a priority value based on the current targets (e.g. high prio when there's lots of severe fir...
float??? InspectProbability
Chance of inspecting a valid target. The NPC won't try to inspect that target again for NormalInspect...
override bool IsValidTarget(Character target)
override AIObjective ObjectiveConstructor(Character target)
override void OnObjectiveCompleted(AIObjective objective, Character target)
AIObjectiveFindThieves(Character character, AIObjectiveManager objectiveManager, float priorityModifier=1)
override IEnumerable< Character > GetList()
List of all possible items of the specified type. Used for filtering the removed objectives.
An objective that creates specific kinds of subobjectives for specific types of targets,...
bool IsCriminal
Do the outpost security officers treat the character as a criminal? Triggers when the character has e...
virtual Vector2 WorldPosition
Definition: Entity.cs:49
Submarine Submarine
Definition: Entity.cs:53
static GameSession?? GameSession
Definition: GameMain.cs:88