Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Map/Map/Radiation.cs
1 #nullable enable
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Xml.Linq;
7 using Microsoft.Xna.Framework;
8 
9 namespace Barotrauma
10 {
11  internal partial class Radiation : ISerializableEntity
12  {
13  public string Name => nameof(Radiation);
14 
15  [Serialize(defaultValue: 0f, isSaveable: IsPropertySaveable.Yes)]
16  public float Amount { get; set; }
17 
18  [Serialize(defaultValue: true, isSaveable: IsPropertySaveable.Yes)]
19  public bool Enabled { get; set; }
20 
21  public Dictionary<Identifier, SerializableProperty> SerializableProperties { get; }
22 
23  public readonly Map Map;
24  public readonly RadiationParams Params;
25 
26  private Affliction? radiationAffliction;
27 
28  private float radiationTimer;
29 
30  private float increasedAmount;
31  private float lastIncrease;
32 
33  public Radiation(Map map, RadiationParams radiationParams, XElement? element = null)
34  {
35  SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
36  Map = map;
37  Params = radiationParams;
38  radiationTimer = Params.RadiationDamageDelay;
39  if (element == null)
40  {
41  Amount = Params.StartingRadiation;
42  }
43  }
44 
49  public void OnStep(float steps = 1)
50  {
51  if (!Enabled) { return; }
52  if (steps <= 0) { return; }
53 
54  float increaseAmount = Params.RadiationStep * steps;
55 
56  if (Params.MaxRadiation > 0 && Params.MaxRadiation < Amount + increaseAmount)
57  {
58  increaseAmount = Params.MaxRadiation - Amount;
59  }
60 
61  IncreaseRadiation(increaseAmount);
62 
63  int amountOfOutposts = Map.Locations.Count(location => location.Type.HasOutpost && !location.IsCriticallyRadiated());
64 
65  foreach (Location location in Map.Locations.Where(Contains))
66  {
67  if (location.IsGateBetweenBiomes)
68  {
69  location.Connections.ForEach(c => c.Locked = false);
70  continue;
71  }
72 
73  if (amountOfOutposts <= Params.MinimumOutpostAmount) { break; }
74 
75  if (Map.CurrentLocation is { } currLocation)
76  {
77  // Don't advance on nearby locations to avoid buggy behavior
78  if (currLocation == location || currLocation.Connections.Any(lc => lc.OtherLocation(currLocation) == location)) { continue; }
79  }
80 
81  bool wasCritical = location.IsCriticallyRadiated();
82 
83  location.TurnsInRadiation++;
84 
85  if (location.Type.HasOutpost && !wasCritical && location.IsCriticallyRadiated())
86  {
87  location.ClearMissions();
88  amountOfOutposts--;
89  }
90  }
91  }
92 
93  public void IncreaseRadiation(float amount)
94  {
95  Amount += amount;
96  increasedAmount = lastIncrease = amount;
97  }
98 
99 
100 
101  public void UpdateRadiation(float deltaTime)
102  {
103  if (!(GameMain.GameSession?.IsCurrentLocationRadiated() ?? false)) { return; }
104 
105  if (GameMain.NetworkMember is { IsClient: true }) { return; }
106 
107  if (radiationTimer > 0)
108  {
109  radiationTimer -= deltaTime;
110  return;
111  }
112 
113  if (radiationAffliction == null)
114  {
115  float radiationStrengthChange = AfflictionPrefab.RadiationSickness.Effects.FirstOrDefault()?.StrengthChange ?? 0.0f;
116  radiationAffliction = new Affliction(
117  AfflictionPrefab.RadiationSickness,
118  (Params.RadiationDamageAmount - radiationStrengthChange) * Params.RadiationDamageDelay);
119  }
120 
121  radiationTimer = Params.RadiationDamageDelay;
122 
123  foreach (Character character in Character.CharacterList)
124  {
125  if (character.IsDead || character.Removed || !(character.CharacterHealth is { } health)) { continue; }
126 
127  if (IsEntityRadiated(character))
128  {
129  var limb = character.AnimController.MainLimb;
130  AttackResult attackResult = limb.AddDamage(limb.SimPosition, radiationAffliction.ToEnumerable(), playSound: false);
131  character.CharacterHealth.ApplyDamage(limb, attackResult);
132  }
133  }
134  }
135 
136  public bool Contains(Location location)
137  {
138  return Contains(location.MapPosition);
139  }
140 
141  public bool Contains(Vector2 pos)
142  {
143  return pos.X < Amount;
144  }
145 
146  public bool IsEntityRadiated(Entity entity)
147  {
148  if (!Enabled) { return false; }
149  if (Level.Loaded is { Type: LevelData.LevelType.LocationConnection, StartLocation: { } startLocation, EndLocation: { } endLocation } level)
150  {
151  if (Contains(startLocation) && Contains(endLocation)) { return true; }
152 
153  float distance = MathHelper.Clamp((entity.WorldPosition.X - level.StartPosition.X) / (level.EndPosition.X - level.StartPosition.X), 0.0f, 1.0f);
154  var (startX, startY) = startLocation.MapPosition;
155  var (endX, endY) = endLocation.MapPosition;
156  Vector2 mapPos = new Vector2(startX + (endX - startX), startY + (endY - startY)) * distance;
157 
158  return Contains(mapPos);
159  }
160 
161  return false;
162  }
163 
164  public XElement Save()
165  {
166  XElement element = new XElement(nameof(Radiation));
167  SerializableProperty.SerializeProperties(this, element, saveIfDefault: true);
168  return element;
169  }
170  }
171 }