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 { Timer = 0, ReachCursor = 1 }
35 
36  private readonly DelayTypes delayType;
37  private readonly float delay;
38 
39  public DelayedEffect(ContentXElement element, string parentDebugName)
40  : base(element, parentDebugName)
41  {
42  DelayTypes delayTypeAttr = element.GetAttributeEnum("delaytype", DelayTypes.Timer);
43  if (delayTypeAttr is DelayTypes.Timer)
44  {
45  delay = element.GetAttributeFloat("delay", 1.0f);
46  }
47  }
48 
49  public override void Apply(ActionType type, float deltaTime, Entity entity, ISerializableEntity target, Vector2? worldPosition = null)
50  {
51  if (this.type != type || !HasRequiredItems(entity)) { return; }
52  if (!Stackable)
53  {
54  foreach (var existingEffect in DelayList)
55  {
56  if (existingEffect.Parent == this && existingEffect.Targets.FirstOrDefault() == target) { return; }
57  }
58  }
59  if (!IsValidTarget(target)) { return; }
60 
61  currentTargets.Clear();
62  currentTargets.Add(target);
63  if (!HasRequiredConditions(currentTargets)) { return; }
64 
65  switch (delayType)
66  {
67  case DelayTypes.Timer:
68  DelayList.Add(new DelayedListElement(this, entity, currentTargets, delay, worldPosition, null));
69  break;
70  case DelayTypes.ReachCursor:
71  Projectile projectile = (entity as Item)?.GetComponent<Projectile>();
72  if (projectile == null)
73  {
74  DebugConsole.LogError("Non-projectile using a delaytype of reachcursor");
75  return;
76  }
77 
78  if (projectile.User == null)
79  {
80  DebugConsole.LogError("Projectile: '" + projectile.Name + "' missing user to determine distance");
81  return;
82  }
83 
84  DelayList.Add(new DelayedListElement(this, entity, currentTargets, Vector2.Distance(entity.WorldPosition, projectile.User.CursorWorldPosition), worldPosition, entity.WorldPosition));
85  break;
86  }
87  }
88 
89  public override void Apply(ActionType type, float deltaTime, Entity entity, IReadOnlyList<ISerializableEntity> targets, Vector2? worldPosition = null)
90  {
91  if (this.type != type) { return; }
92  if (ShouldWaitForInterval(entity, deltaTime)) { return; }
93  if (!HasRequiredItems(entity)) { return; }
94  if (delayType == DelayTypes.ReachCursor && Character.Controlled == null) { return; }
95  if (!Stackable)
96  {
97  foreach (var existingEffect in DelayList)
98  {
99  if (existingEffect.Parent == this && existingEffect.Targets.SequenceEqual(targets)) { return; }
100  }
101  }
102 
103  currentTargets.Clear();
104  foreach (ISerializableEntity target in targets)
105  {
106  if (!IsValidTarget(target)) { continue; }
107  currentTargets.Add(target);
108  }
109 
110  if (!HasRequiredConditions(currentTargets)) { return; }
111 
112  switch (delayType)
113  {
114  case DelayTypes.Timer:
115  DelayList.Add(new DelayedListElement(this, entity, targets, delay, worldPosition, null));
116  break;
117  case DelayTypes.ReachCursor:
118  Projectile projectile = (entity as Item)?.GetComponent<Projectile>();
119  if (projectile == null)
120  {
121 #if DEBUG
122  DebugConsole.LogError("Non-projectile using a delaytype of reachcursor");
123 #endif
124  return;
125  }
126 
127  if (projectile.User == null)
128  {
129 #if DEBUG
130  DebugConsole.LogError("Projectile " + projectile.Name + "missing user");
131 #endif
132  return;
133  }
134 
135  DelayList.Add(new DelayedListElement(this, entity, targets, Vector2.Distance(entity.WorldPosition, projectile.User.CursorWorldPosition), worldPosition, entity.WorldPosition));
136  break;
137  }
138  }
139 
140  public static void Update(float deltaTime)
141  {
142  for (int i = DelayList.Count - 1; i >= 0; i--)
143  {
144  DelayedListElement element = DelayList[i];
145  if (element.Parent.CheckConditionalAlways && !element.Parent.HasRequiredConditions(element.Targets))
146  {
147  DelayList.Remove(element);
148  continue;
149  }
150 
151  switch (element.Parent.delayType)
152  {
153  case DelayTypes.Timer:
154  element.Delay -= deltaTime;
155  if (element.Delay > 0.0f) { continue; }
156  break;
157  case DelayTypes.ReachCursor:
158  if (Vector2.Distance(element.Entity.WorldPosition, element.StartPosition.Value) < element.Delay) { continue; }
159  break;
160  }
161 
162  element.Parent.Apply(deltaTime, element.Entity, element.Targets, element.WorldPosition);
163  DelayList.Remove(element);
164  }
165  }
166  }
167 }
float GetAttributeFloat(string key, float def)
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:19