Client LuaCsForBarotrauma
CountTargetsAction.cs
1 #nullable enable
2 
3 using System.Collections.Generic;
4 using System.Linq;
5 
6 namespace Barotrauma
7 {
12  {
13  [Serialize("", IsPropertySaveable.Yes, description: "Tag of the entities to check.")]
14  public Identifier TargetTag { get; set; }
15 
16  [Serialize("", IsPropertySaveable.Yes, description: "Optional second tag. Can be used if the target must have two different tags.")]
17  public Identifier SecondRequiredTargetTag { get; set; }
18 
19  [Serialize("", IsPropertySaveable.Yes, description: "Optional tag of a hull the target must be inside.")]
20  public Identifier HullTag { get; set; }
21 
22  [Serialize(-1, IsPropertySaveable.Yes, description: "Minimum number of matching entities for the check to succeed. If omitted or negative, there is no minimum amount.")]
23  public int MinAmount { get; set; }
24 
25  [Serialize(-1, IsPropertySaveable.Yes, description: "Maximum number of matching entities for the check to succeed. If omitted or negative, there is no maximum amount.")]
26  public int MaxAmount { get; set; }
27 
28  [Serialize("", IsPropertySaveable.Yes, description: "Tag of some other entities to compare the number of targets to. E.g. you could compare the number of entities tagged as \"discoveredhull\" to entities tagged as \"anyhull\". The minimum/maximum amount of entities there must be relative to the other entities is configured using MinPercentageRelativeToTarget and MaxPercentageRelativeToTarget.")]
29  public Identifier CompareToTarget { get; set; }
30 
31  [Serialize(-1.0f, IsPropertySaveable.Yes, description: "Minimum amount of targets, as a percentage of the number of entities tagged with CompareToTarget. E.g. you could compare the number of entities tagged as \"discoveredhull\" to entities tagged as \"anyhull\" to require 50% of hulls to be discovered.")]
32  public float MinPercentageRelativeToTarget { get; set; }
33 
34  [Serialize(-1.0f, IsPropertySaveable.Yes, description: "Maximum amount of targets, as a percentage of the number of entities tagged with CompareToTarget. E.g. you could compare the number of entities tagged as \"floodedhull\" to entities tagged as \"anyhull\" to require less than 50% of hulls to be flooded.")]
35  public float MaxPercentageRelativeToTarget { get; set; }
36 
37  private readonly IReadOnlyList<PropertyConditional> conditionals;
38 
39  public CountTargetsAction(ScriptedEvent parentEvent, ContentXElement element) : base(parentEvent, element)
40  {
41  var conditionalList = new List<PropertyConditional>();
42  foreach (ContentXElement subElement in element.GetChildElements("conditional"))
43  {
44  conditionalList.AddRange(PropertyConditional.FromXElement(subElement!));
45  }
46  conditionals = conditionalList;
47 
48  if (CompareToTarget.IsEmpty)
49  {
50  int amount = element.GetAttributeInt("amount", -1);
51  if (amount > -1)
52  {
53  MinAmount = MaxAmount = amount;
54  }
55  if (MinAmount > MaxAmount && MaxAmount > -1)
56  {
57  DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". {MinAmount} is larger than {MaxAmount} in {nameof(CountTargetsAction)}.",
58  contentPackage: element.ContentPackage);
59  }
60  }
61  else
62  {
64  {
65  DebugConsole.ThrowError($"Error in event \"{ParentEvent.Prefab.Identifier}\". Comparing to another target, but neither {nameof(MinPercentageRelativeToTarget)} or {nameof(MaxPercentageRelativeToTarget)} is set.",
66  contentPackage: element.ContentPackage);
67  }
68  }
69  }
70 
71  protected override bool? DetermineSuccess()
72  {
73  var potentialTargets = ParentEvent.GetTargets(TargetTag);
74 
75  if (!SecondRequiredTargetTag.IsEmpty)
76  {
77  potentialTargets = potentialTargets.Where(t => ParentEvent.GetTargets(SecondRequiredTargetTag).Contains(t));
78  }
79  if (!HullTag.IsEmpty)
80  {
81  var hulls = ParentEvent.GetTargets(HullTag).OfType<Hull>();
82  potentialTargets = potentialTargets.Where(t =>
83  (t is Item it && hulls.Contains(it.CurrentHull)) ||
84  (t is Character c && hulls.Contains(c.CurrentHull)));
85  }
86 
87  if (conditionals.Any())
88  {
89  potentialTargets = potentialTargets.Where(t => conditionals.Any(c => c.Matches(t as ISerializableEntity)));
90  }
91 
92  int targetCount = potentialTargets.Count();
93 
94  if (CompareToTarget.IsEmpty)
95  {
96  if (MinAmount > -1 && targetCount < MinAmount) { return false; }
97  if (MaxAmount > -1 && targetCount > MaxAmount) { return false; }
98  }
99  else
100  {
101  int compareToTargetCount = ParentEvent.GetTargets(CompareToTarget).Count();
102  float percentage = MathUtils.Percentage(targetCount, compareToTargetCount);
103  if (MinPercentageRelativeToTarget > -1 && percentage < MinPercentageRelativeToTarget) { return false; }
104  if (MaxPercentageRelativeToTarget > -1 && percentage > MaxPercentageRelativeToTarget) { return false; }
105  }
106  return true;
107  }
108 
109  public override string ToDebugString()
110  {
111  return $"{ToolBox.GetDebugSymbol(HasBeenDetermined())} {nameof(CountTargetsAction)} -> (TargetTag: {TargetTag.ColorizeObject()}, " +
112  $"Succeeded: {succeeded.ColorizeObject()})";
113  }
114  }
115 }
IEnumerable< ContentXElement > GetChildElements(string name)
Check whether there's at least / at most some number of entities matching some specific criteria.
override string ToDebugString()
Rich test to display in debugdraw
CountTargetsAction(ScriptedEvent parentEvent, ContentXElement element)
readonly ScriptedEvent ParentEvent
Definition: EventAction.cs:106
Conditionals are used by some in-game mechanics to require one or more conditions to be met for those...
static IEnumerable< PropertyConditional > FromXElement(ContentXElement element, Predicate< XAttribute >? predicate=null)
IEnumerable< Entity > GetTargets(Identifier tag)