Client LuaCsForBarotrauma
DelayedEffect.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Xml.Linq;
7 using Microsoft.Xna.Framework;
8 
9 namespace Barotrauma
10 {
12  {
13  public readonly DelayedEffect Parent;
14  public readonly Entity Entity;
15  public readonly Vector2? WorldPosition;
16  public readonly Vector2? StartPosition;
17  public readonly List<ISerializableEntity> Targets;
18  public float Delay;
19 
20  public DelayedListElement(DelayedEffect parentEffect, Entity parentEntity, IEnumerable<ISerializableEntity> targets, float delay, Vector2? worldPosition, Vector2? startPosition)
21  {
22  Parent = parentEffect;
23  Entity = parentEntity;
24  Targets = new List<ISerializableEntity>(targets);
25  Delay = delay;
26  WorldPosition = worldPosition;
27  StartPosition = startPosition;
28  }
29  }
31  {
32  public static readonly List<DelayedListElement> DelayList = new List<DelayedListElement>();
33 
34  private enum DelayTypes
35  {
36  Timer = 0,
37  [Obsolete("The delay type is unsupported.")]
38  ReachCursor = 1
39  }
40 
41  private readonly DelayTypes delayType;
42  private readonly float delay;
43 
44  public DelayedEffect(ContentXElement element, string parentDebugName)
45  : base(element, parentDebugName)
46  {
47  delayType = element.GetAttributeEnum("delaytype", DelayTypes.Timer);
48  if (delayType == DelayTypes.ReachCursor)
49  {
50  DebugConsole.AddWarning($"Potential error in {parentDebugName}: the delay type {DelayTypes.ReachCursor} is not supported.", contentPackage: element.ContentPackage);
51  }
52  if (delayType is DelayTypes.Timer)
53  {
54  delay = element.GetAttributeFloat("delay", 1.0f);
55  }
56  }
57 
58  public override void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target, Vector2? worldPosition = null)
59  {
60  if (this.type != type || !HasRequiredItems(entity)) { return; }
61  if (!Stackable)
62  {
63  foreach (var existingEffect in DelayList)
64  {
65  if (existingEffect.Parent == this && existingEffect.Targets.FirstOrDefault() == target) { return; }
66  }
67  }
68  if (!IsValidTarget(target)) { return; }
69 
70  currentTargets.Clear();
71  currentTargets.Add(target);
72  if (!HasRequiredConditions(currentTargets)) { return; }
73 
74  switch (delayType)
75  {
76  case DelayTypes.Timer:
77  DelayList.Add(new DelayedListElement(this, entity, currentTargets, delay, worldPosition, null));
78  break;
79  case DelayTypes.ReachCursor:
80  Projectile projectile = (entity as Item)?.GetComponent<Projectile>();
81  if (projectile == null)
82  {
83  DebugConsole.LogError("Non-projectile using a delaytype of reachcursor");
84  return;
85  }
86 
87  var user =
88  projectile.User ??
89  projectile.Attacker ??
90  projectile.Launcher?.GetRootInventoryOwner() as Character;
91  if (user == null)
92  {
93 #if DEBUG
94  DebugConsole.LogError($"Projectile \"{projectile.Item.Prefab.Identifier}\" missing user");
95 #endif
96  return;
97  }
98 
99  DelayList.Add(new DelayedListElement(this, entity, currentTargets, Vector2.Distance(entity.WorldPosition, projectile.User.CursorWorldPosition), worldPosition, entity.WorldPosition));
100  break;
101  }
102  }
103 
104  public override void Apply(ActionType type, float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Vector2? worldPosition = null)
105  {
106  if (this.type != type) { return; }
107  if (ShouldWaitForInterval(entity, deltaTime)) { return; }
108  if (!HasRequiredItems(entity)) { return; }
109  if (delayType == DelayTypes.ReachCursor && Character.Controlled == null) { return; }
110  if (!Stackable)
111  {
112  foreach (var existingEffect in DelayList)
113  {
114  if (existingEffect.Parent == this && existingEffect.Targets.SequenceEqual(targets)) { return; }
115  }
116  }
117 
118  currentTargets.Clear();
119  foreach (ISerializableEntity target in targets)
120  {
121  if (!IsValidTarget(target)) { continue; }
122  currentTargets.Add(target);
123  }
124 
125  if (!HasRequiredConditions(currentTargets)) { return; }
126 
127  switch (delayType)
128  {
129  case DelayTypes.Timer:
130  DelayList.Add(new DelayedListElement(this, entity, currentTargets, delay, worldPosition, null));
131  break;
132  case DelayTypes.ReachCursor:
133  Projectile projectile = (entity as Item)?.GetComponent<Projectile>();
134  if (projectile == null)
135  {
136 #if DEBUG
137  DebugConsole.LogError("Non-projectile using a delaytype of reachcursor");
138 #endif
139  return;
140  }
141 
142  var user =
143  projectile.User ??
144  projectile.Attacker ??
145  projectile.Launcher?.GetRootInventoryOwner() as Character;
146  if (user == null)
147  {
148 #if DEBUG
149  DebugConsole.LogError($"Projectile \"{projectile.Item.Prefab.Identifier}\" missing user");
150 #endif
151  return;
152  }
153 
154  DelayList.Add(new DelayedListElement(this, entity, currentTargets, Vector2.Distance(entity.WorldPosition, user.CursorWorldPosition), worldPosition, entity.WorldPosition));
155  break;
156  }
157  }
158 
159  public static void Update(float deltaTime)
160  {
161  for (int i = DelayList.Count - 1; i >= 0; i--)
162  {
163  DelayedListElement element = DelayList[i];
164  if (element.Parent.CheckConditionalAlways && !element.Parent.HasRequiredConditions(element.Targets))
165  {
166  DelayList.Remove(element);
167  continue;
168  }
169 
170  switch (element.Parent.delayType)
171  {
172  case DelayTypes.Timer:
173  element.Delay -= deltaTime;
174  if (element.Delay > 0.0f) { continue; }
175  break;
176  case DelayTypes.ReachCursor:
177  if (Vector2.Distance(element.Entity.WorldPosition, element.StartPosition.Value) < element.Delay) { continue; }
178  break;
179  }
180 
181  element.Parent.Apply(deltaTime, element.Entity, element.Targets, element.WorldPosition);
182  DelayList.Remove(element);
183  }
184  }
185  }
186 }
float GetAttributeFloat(string key, float def)
ContentPackage? ContentPackage
override void Apply(ActionType type, float deltaTime, Entity entity, IReadOnlyList< ISerializableEntity > targets, Vector2? worldPosition=null)
static void Update(float deltaTime)
override void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target, Vector2? worldPosition=null)
DelayedEffect(ContentXElement element, string parentDebugName)
static readonly List< DelayedListElement > DelayList
readonly List< ISerializableEntity > Targets
readonly? Vector2 StartPosition
readonly? Vector2 WorldPosition
readonly DelayedEffect Parent
DelayedListElement(DelayedEffect parentEffect, Entity parentEntity, IEnumerable< ISerializableEntity > targets, float delay, Vector2? worldPosition, Vector2? startPosition)
virtual Vector2 WorldPosition
Definition: Entity.cs:49
StatusEffects can be used to execute various kinds of effects: modifying the state of some entity in ...
readonly bool Stackable
Only valid if the effect has a duration or delay. Can the effect be applied on the same target(s) if ...
bool HasRequiredConditions(IReadOnlyList< ISerializableEntity > targets)
readonly bool CheckConditionalAlways
Only applicable for StatusEffects with a duration or delay. Should the conditional checks only be don...
ActionType
ActionTypes define when a StatusEffect is executed.
Definition: Enums.cs:26