Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs
3 using Microsoft.Xna.Framework;
4 using System;
5 using System.Globalization;
6 using System.Linq;
7 
9 {
11  {
12  private float flowPercentage;
13  private float maxFlow;
14 
15  public float? TargetLevel;
16 
17  private bool hijacked;
18  public bool Hijacked
19  {
20  get { return hijacked; }
21  set
22  {
23  if (value == hijacked) { return; }
24  hijacked = value;
25 #if SERVER
26  if (!Submarine.Unloading)
27  {
28  item.CreateServerEvent(this);
29  }
30 #endif
31  }
32  }
33 
34  public float CurrentBrokenVolume
35  {
36  get
37  {
38  if (item.ConditionPercentage > 10.0f || !IsActive) { return 0.0f; }
39  return (1.0f - item.ConditionPercentage / 10.0f) * 100.0f;
40  }
41  }
42 
43  private float pumpSpeedLockTimer, isActiveLockTimer;
44 
45  [Serialize(0.0f, IsPropertySaveable.Yes, description: "How fast the item is currently pumping water (-100 = full speed out, 100 = full speed in). Intended to be used by StatusEffect conditionals (setting this value in XML has no effect).")]
46  public float FlowPercentage
47  {
48  get { return flowPercentage; }
49  set
50  {
51  if (!MathUtils.IsValid(flowPercentage)) { return; }
52  flowPercentage = MathHelper.Clamp(value, -100.0f, 100.0f);
53  flowPercentage = MathF.Round(flowPercentage);
54  }
55  }
56 
57  [Editable, Serialize(80.0f, IsPropertySaveable.No, description: "How fast the item pumps water in/out when operating at 100%.", alwaysUseInstanceValues: true)]
58  public float MaxFlow
59  {
60  get => maxFlow;
61  set => maxFlow = value;
62  }
63 
64  [Editable, Serialize(true, IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
65  public bool IsOn
66  {
67  get { return IsActive; }
68  set { IsActive = value; }
69  }
70 
71  private float currFlow;
72  public float CurrFlow
73  {
74  get
75  {
76  if (!IsActive) { return 0.0f; }
77  return Math.Abs(currFlow);
78  }
79  }
80 
81  public bool HasPower => IsActive && Voltage >= MinVoltage;
82  public bool IsAutoControlled => pumpSpeedLockTimer > 0.0f || isActiveLockTimer > 0.0f;
83 
84  private const float TinkeringSpeedIncrease = 4.0f;
85 
86  public override bool UpdateWhenInactive => true;
87 
88  public float CurrentStress => Math.Abs(flowPercentage / 100.0f);
89 
90  public Pump(Item item, ContentXElement element)
91  : base(item, element)
92  {
93  InitProjSpecific(element);
94  }
95 
96  partial void InitProjSpecific(ContentXElement element);
97 
98  public override void Update(float deltaTime, Camera cam)
99  {
100  pumpSpeedLockTimer -= deltaTime;
101  isActiveLockTimer -= deltaTime;
102 
103  if (!IsActive)
104  {
105  return;
106  }
107 
108  currFlow = 0.0f;
109 
110  if (TargetLevel != null)
111  {
112  float hullPercentage = 0.0f;
113  if (item.CurrentHull != null)
114  {
115  float hullWaterVolume = item.CurrentHull.WaterVolume;
116  float totalHullVolume = item.CurrentHull.Volume;
117  foreach (var linked in item.CurrentHull.linkedTo)
118  {
119  if ((linked is Hull linkedHull))
120  {
121  hullWaterVolume += linkedHull.WaterVolume;
122  totalHullVolume += linkedHull.Volume;
123  }
124  }
125  hullPercentage = hullWaterVolume / totalHullVolume * 100.0f;
126  }
127  FlowPercentage = ((float)TargetLevel - hullPercentage) * 10.0f;
128  }
129 
130  if (!HasPower)
131  {
132  return;
133  }
134 
135  UpdateProjSpecific(deltaTime);
136 
137  ApplyStatusEffects(ActionType.OnActive, deltaTime);
138 
139  if (item.CurrentHull == null) { return; }
140 
141  float powerFactor = Math.Min(currPowerConsumption <= 0.0f || MinVoltage <= 0.0f ? 1.0f : Voltage, MaxOverVoltageFactor);
142 
143  currFlow = flowPercentage / 100.0f * item.StatManager.GetAdjustedValueMultiplicative(ItemTalentStats.PumpMaxFlow, MaxFlow) * powerFactor;
144 
145  if (item.GetComponent<Repairable>() is { IsTinkering: true } repairable)
146  {
147  currFlow *= 1f + repairable.TinkeringStrength * TinkeringSpeedIncrease;
148  }
149 
150  currFlow = item.StatManager.GetAdjustedValueMultiplicative(ItemTalentStats.PumpSpeed, currFlow);
151 
152  //less effective when in a bad condition
153  currFlow *= MathHelper.Lerp(0.5f, 1.0f, item.Condition / item.MaxCondition);
154 
155  item.CurrentHull.WaterVolume += currFlow * deltaTime * Timing.FixedUpdateRate;
156  if (item.CurrentHull.WaterVolume > item.CurrentHull.Volume) { item.CurrentHull.Pressure += 30.0f * deltaTime; }
157  }
158 
159  public void InfectBallast(Identifier identifier, bool allowMultiplePerShip = false)
160  {
161  Hull hull = item.CurrentHull;
162  if (hull == null) { return; }
163 
164  if (!allowMultiplePerShip)
165  {
166  // if the ship is already infected then do nothing
167  if (Hull.HullList.Where(h => h.Submarine == hull.Submarine).Any(h => h.BallastFlora != null)) { return; }
168  }
169 
170  if (hull.BallastFlora != null) { return; }
171 
172  var ballastFloraPrefab = BallastFloraPrefab.Find(identifier);
173  if (ballastFloraPrefab == null)
174  {
175  DebugConsole.ThrowError($"Failed to infect a ballast pump (could not find a ballast flora prefab with the identifier \"{identifier}\").\n" + Environment.StackTrace);
176  return;
177  }
178 
179  Vector2 offset = item.WorldPosition - hull.WorldPosition;
180  hull.BallastFlora = new BallastFloraBehavior(hull, ballastFloraPrefab, offset, firstGrowth: true);
181 
182 #if SERVER
183  hull.BallastFlora.CreateNetworkMessage(new BallastFloraBehavior.SpawnEventData());
184 #endif
185  }
186 
190  public override float GetCurrentPowerConsumption(Connection connection = null)
191  {
192  //There shouldn't be other power connections to this
193  if (connection != this.powerIn || !IsActive)
194  {
195  return 0;
196  }
197 
198  currPowerConsumption = powerConsumption * Math.Abs(flowPercentage / 100.0f);
199  //pumps consume more power when in a bad condition
200  item.GetComponent<Repairable>()?.AdjustPowerConsumption(ref currPowerConsumption);
201 
202  return currPowerConsumption;
203  }
204 
205  partial void UpdateProjSpecific(float deltaTime);
206 
207  public override void ReceiveSignal(Signal signal, Connection connection)
208  {
209  if (Hijacked) { return; }
210 
211  if (connection.Name == "toggle")
212  {
213  IsActive = !IsActive;
214  isActiveLockTimer = 0.1f;
215  }
216  else if (connection.Name == "set_active")
217  {
218  IsActive = signal.value != "0";
219  isActiveLockTimer = 0.1f;
220  }
221  else if (connection.Name == "set_speed")
222  {
223  if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
224  {
225  flowPercentage = MathHelper.Clamp(tempSpeed, -100.0f, 100.0f);
226  TargetLevel = null;
227  pumpSpeedLockTimer = 0.1f;
228  }
229  }
230  else if (connection.Name == "set_targetlevel")
231  {
232  if (float.TryParse(signal.value, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempTarget))
233  {
234  TargetLevel = MathUtils.InverseLerp(-100.0f, 100.0f, tempTarget) * 100.0f;
235  pumpSpeedLockTimer = 0.1f;
236  }
237  }
238  }
239 
240  public override bool CrewAIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
241  {
242 #if CLIENT
243  if (GameMain.Client != null) { return false; }
244 #endif
245 
246  switch (objective.Option.Value.ToLowerInvariant())
247  {
248  case "pumpout":
249 #if SERVER
250  if (objective.Override || !IsActive || FlowPercentage > -100.0f)
251  {
252  item.CreateServerEvent(this);
253  }
254 #endif
255  IsActive = true;
256  FlowPercentage = -100.0f;
257  break;
258  case "pumpin":
259 #if SERVER
260  if (objective.Override || !IsActive || FlowPercentage < 100.0f)
261  {
262  item.CreateServerEvent(this);
263  }
264 #endif
265  IsActive = true;
266  FlowPercentage = 100.0f;
267  break;
268  case "stoppumping":
269 #if SERVER
270  if (objective.Override || FlowPercentage > 0.0f)
271  {
272  item.CreateServerEvent(this);
273  }
274 #endif
275  IsActive = false;
276  FlowPercentage = 0.0f;
277  break;
278  }
279  return true;
280  }
281  }
282 }
static BallastFloraPrefab Find(Identifier identifier)
virtual Vector2 WorldPosition
Definition: Entity.cs:49
Submarine Submarine
Definition: Entity.cs:53
static GameClient Client
Definition: GameMain.cs:188
static readonly List< Hull > HullList
void ApplyStatusEffects(ActionType type, float deltaTime, Character character=null, Limb targetLimb=null, Entity useTarget=null, Character user=null, Vector2? worldPosition=null, float afflictionMultiplier=1.0f)
const float MaxOverVoltageFactor
Maximum voltage factor when the device is being overvolted. I.e. how many times more effectively the ...
float powerConsumption
The maximum amount of power the item can draw from connected items
float currPowerConsumption
The amount of power currently consumed by the item. Negative values mean that the item is providing p...
override bool CrewAIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
true if the operation was completed
void InfectBallast(Identifier identifier, bool allowMultiplePerShip=false)
override void ReceiveSignal(Signal signal, Connection connection)
override float GetCurrentPowerConsumption(Connection connection=null)
Power consumption of the Pump. Only consume power when active and adjust consumption based on conditi...
Interface for entities that the clients can send events to the server
Interface for entities that the server can send events to the clients
ActionType
ActionTypes define when a StatusEffect is executed.
Definition: Enums.cs:19