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