Client LuaCsForBarotrauma
NPCOperateItemAction.cs
3 using System.Collections.Generic;
4 using System.Linq;
5 
6 namespace Barotrauma
7 {
12  {
13  [Serialize("", IsPropertySaveable.Yes, description: "Tag of the NPC(s) that should operate the item.")]
14  public Identifier NPCTag { get; set; }
15 
16  [Serialize("", IsPropertySaveable.Yes, description: "Tag of the item to operate. If it's not something AI characters can or know how to operate, such as a cabinet or an engine, the NPC will just select it.")]
17  public Identifier TargetTag { get; set; }
18 
19  [Serialize("Controller", IsPropertySaveable.Yes, description: "Name of the component to operate. For example, the Controller component of a periscope or the Reactor component of a nuclear reactor.")]
20  public Identifier ItemComponentName { get; set; }
21 
22  [Serialize("", IsPropertySaveable.Yes, description: "Identifier of the option, if there are several ways the item can be operated. For example, \"powerup\" or \"shutdown\" when operating a reactor.")]
23  public Identifier OrderOption { get; set; }
24 
25  [Serialize(false, IsPropertySaveable.Yes, description: "Should the character equip the item before attempting to operate it (only valid if the item is equippable).")]
26  public bool RequireEquip { get; set; }
27 
28  [Serialize(true, IsPropertySaveable.Yes, description: "Should the character start or stop operating the item.")]
29  public bool Operate { get; set; }
30 
31  [Serialize(-1, IsPropertySaveable.Yes, description: "Maximum number of NPCs the action can target. For example, you could only make a specific number of security officers man a periscope.")]
32  public int MaxTargets { get; set; }
33 
34  [Serialize(100, IsPropertySaveable.Yes, description: "Priority of operating the item (0-100). Higher values will make the AI prefer operating the item over other orders (priority 60-70) or e.g. reacting to emergencies (priority 90).")]
35  public int Priority { get; set; }
36 
37  [Serialize(true, IsPropertySaveable.Yes, description: "The event actions reset when a GoTo action makes the event jump to a different point. Should the NPC stop operating the item when the event resets?")]
38  public bool AbandonOnReset { get; set; }
39 
40  private bool isFinished = false;
41 
42  public NPCOperateItemAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element) { }
43 
44  private List<Character> affectedNpcs = null;
45  private Item target = null;
46 
47  public override void Update(float deltaTime)
48  {
49  if (isFinished) { return; }
50 
51  var potentialTargets = ParentEvent.GetTargets(TargetTag).OfType<Item>();
52  var nonSelectedItems = potentialTargets.Where(it => it.GetComponent<Controller>()?.User == null);
53 
54  target =
55  nonSelectedItems.Any() ?
56  nonSelectedItems.GetRandomUnsynced() :
57  potentialTargets.GetRandomUnsynced();
58  if (target == null) { return; }
59 
60  int targetCount = 0;
61  affectedNpcs = ParentEvent.GetTargets(NPCTag).Where(c => c is Character).Select(c => c as Character).ToList();
62  foreach (var npc in affectedNpcs)
63  {
64  if (npc.Removed) { continue; }
65  if (npc.AIController is not HumanAIController humanAiController) { continue; }
66 
67  if (Operate)
68  {
69  var itemComponent = target.Components.FirstOrDefault(ic => ItemComponentName == ic.Name);
70  if (itemComponent == null)
71  {
72  DebugConsole.AddWarning($"Error in NPCOperateItemAction: could not find the component \"{ItemComponentName}\" in item \"{target.Name}\".");
73  }
74  else
75  {
76  var newObjective = new AIObjectiveOperateItem(itemComponent, npc, humanAiController.ObjectiveManager, OrderOption, RequireEquip)
77  {
78  OverridePriority = Priority
79  };
80  humanAiController.ObjectiveManager.AddObjective(newObjective);
81  humanAiController.ObjectiveManager.WaitTimer = 0.0f;
82  humanAiController.ObjectiveManager.Objectives.RemoveAll(o => o is AIObjectiveGoTo gotoOjective);
83  }
84  }
85  else
86  {
87  foreach (var objective in humanAiController.ObjectiveManager.Objectives)
88  {
89  if (objective is AIObjectiveOperateItem operateItemObjective && operateItemObjective.Component.Item == target)
90  {
91  objective.Abandon = true;
92  }
93  }
94  }
95  targetCount++;
96  if (MaxTargets > -1 && targetCount >= MaxTargets)
97  {
98  break;
99  }
100  }
101  isFinished = true;
102  }
103 
104  public override bool IsFinished(ref string goTo)
105  {
106  return isFinished;
107  }
108 
109  public override void Reset()
110  {
111  if (affectedNpcs != null && target != null && AbandonOnReset)
112  {
113  foreach (var npc in affectedNpcs)
114  {
115  if (npc.Removed || npc.AIController is not HumanAIController humanAiController) { continue; }
116  foreach (var operateItemObjective in humanAiController.ObjectiveManager.GetActiveObjectives<AIObjectiveOperateItem>())
117  {
118  if (operateItemObjective.Component.Item == target)
119  {
120  operateItemObjective.Abandon = true;
121  }
122  }
123  }
124  target = null;
125  affectedNpcs = null;
126  }
127  isFinished = false;
128  }
129 
130  public override string ToDebugString()
131  {
132  return $"{ToolBox.GetDebugSymbol(isFinished)} {nameof(AIObjectiveOperateItem)} -> (NPCTag: {NPCTag.ColorizeObject()}, TargetTag: {TargetTag.ColorizeObject()}, Operate: {Operate.ColorizeObject()})";
133  }
134  }
135 }
readonly ScriptedEvent ParentEvent
Definition: EventAction.cs:106
Makes an NPC select an item, and operate it if it's something AI characters can operate.
override bool IsFinished(ref string goTo)
Has the action finished.
override string ToDebugString()
Rich test to display in debugdraw
NPCOperateItemAction(ScriptedEvent parentEvent, ContentXElement element)
override void Update(float deltaTime)
IEnumerable< Entity > GetTargets(Identifier tag)