Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Map/Levels/DestructibleLevelWall.cs
1 using FarseerPhysics;
2 using FarseerPhysics.Dynamics;
3 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
5 using System.Linq;
6 using Voronoi2;
7 
8 namespace Barotrauma
9 {
11  {
12  public bool NetworkUpdatePending;
13 
14  public float Damage
15  {
16  get;
17  private set;
18  }
19 
20  public float MaxHealth
21  {
22  get;
23  private set;
24  } = 1000.0f;
25 
26  public bool Destroyed
27  {
28  get;
29  private set;
30  }
31 
32  public float FadeOutDuration
33  {
34  get;
35  private set;
36  }
37 
38  public float FadeOutTimer
39  {
40  get;
41  private set;
42  }
43 
44  public Vector2 SimPosition
45  {
46  get { return Body.Position; }
47  }
48 
49  public Vector2 WorldPosition
50  {
51  get { return ConvertUnits.ToDisplayUnits(Body.Position); }
52  }
53 
54  public float Health
55  {
56  get { return MaxHealth - Damage; }
57  }
58 
59  public DestructibleLevelWall(List<Vector2> vertices, Color color, Level level, float? health = null, bool giftWrap = false)
60  : base (vertices, color, level, giftWrap)
61  {
62  MaxHealth = health ?? MathHelper.Clamp(Body.Mass * 0.5f, 50.0f, 1000.0f);
63  Cells.ForEach(c => c.IsDestructible = true);
64  }
65 
66  public override void Update(float deltaTime)
67  {
68  base.Update(deltaTime);
69  if (FadeOutDuration > 0.0f)
70  {
71  FadeOutTimer += deltaTime;
72  if (FadeOutTimer > FadeOutDuration && (GameMain.NetworkMember == null || GameMain.NetworkMember.IsClient)) { Destroy(); }
73  }
74  }
75 
76  public void AddDamage(float damage, Vector2 worldPosition)
77  {
78  AddDamageProjSpecific(damage, worldPosition);
79 
80  if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
81  if (Destroyed) { return; }
82  if (!MathUtils.NearlyEqual(damage, 0.0f)) { NetworkUpdatePending = true; }
83  Damage += damage;
84  if (Damage >= MaxHealth)
85  {
86  CreateFragments();
87  Destroy();
88  }
89  }
90 
91  partial void AddDamageProjSpecific(float damage, Vector2 worldPosition);
92 
93 
94  public AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, Vector2 impulseDirection, float deltaTime, bool playSound = true)
95  {
96  AddDamage(attack.StructureDamage, worldPosition);
97  return new AttackResult(attack.StructureDamage);
98  }
99 
100  private void CreateFragments()
101  {
102 #if CLIENT
103  SoundPlayer.PlaySound("icebreak", WorldPosition);
104 #endif
105  Vector2 center = Vector2.Zero;
106  //generate initial triangles (one triangle from each edge to the center of the cell)
107  List<List<Vector2>> triangles = new List<List<Vector2>>();
108  foreach (var cell in Cells)
109  {
110  foreach (GraphEdge edge in cell.Edges)
111  {
112  List<Vector2> triangleVerts = new List<Vector2>
113  {
114  edge.Point1 + cell.Translation,
115  edge.Point2 + cell.Translation,
116  cell.Center
117  };
118  triangles.Add(triangleVerts);
119  }
120  center += cell.Center;
121  }
122  if (Cells.Any())
123  {
124  center /= Cells.Count;
125  }
126 
127  //split triangles that have edges more than 1000 units long
128  Pair<int, int> longestEdge = new Pair<int, int>(-1, -1);
129  float longestEdgeLength = 0.0f;
130  do
131  {
132  longestEdge.First = -1;
133  longestEdge.Second = -1;
134  longestEdgeLength = 0.0f;
135  for (int i = 0; i < triangles.Count; i++)
136  {
137  for (int edge = 0; edge < 3; edge++)
138  {
139  float edgeLength = Vector2.Distance(triangles[i][edge], triangles[i][(edge + 1) % 3]);
140  if (edgeLength > longestEdgeLength)
141  {
142  longestEdge.First = i;
143  longestEdge.Second = edge;
144  longestEdgeLength = edgeLength;
145  }
146  }
147  }
148  if (longestEdgeLength < 1000.0f)
149  {
150  break;
151  }
152  Vector2 p0 = triangles[longestEdge.First][longestEdge.Second];
153  Vector2 p1 = triangles[longestEdge.First][(longestEdge.Second + 1) % 3];
154  Vector2 p2 = triangles[longestEdge.First][(longestEdge.Second + 2) % 3];
155  triangles[longestEdge.First] = new List<Vector2> { p0, (p0 + p1) / 2, p2 };
156  triangles.Add(new List<Vector2> { (p0 + p1) / 2, p1, p2 });
157 
158 
159  } while (triangles.Count < 32);
160 
161  //generate fragments
162  foreach (var triangle in triangles)
163  {
164  Vector2 triangleCenter = (triangle[0] + triangle[1]+ triangle[2]) / 3;
165  triangle[0] -= triangleCenter;
166  triangle[1] -= triangleCenter;
167  triangle[2] -= triangleCenter;
168  Vector2 simTriangleCenter = ConvertUnits.ToSimUnits(triangleCenter);
169 
170  DestructibleLevelWall fragment = new DestructibleLevelWall(triangle, Color.White, Level.Loaded, giftWrap: true);
171  fragment.Damage = fragment.MaxHealth;
172  fragment.Body.Position = simTriangleCenter;
173  fragment.Body.BodyType = BodyType.Dynamic;
174  fragment.Body.FixedRotation = false;
175  fragment.Body.LinearDamping = Rand.Range(0.2f, 0.3f);
176  fragment.Body.AngularDamping = Rand.Range(0.1f, 0.2f);
177  fragment.Body.GravityScale = 0.1f;
178  fragment.Body.Mass *= 10.0f;
179  fragment.Body.CollisionCategories = Physics.CollisionNone;
180  fragment.Body.CollidesWith = Physics.CollisionWall;
181  fragment.FadeOutDuration = 20.0f;
182 
183  Vector2 bodyDiff = simTriangleCenter - Body.Position;
184  fragment.Body.LinearVelocity = (bodyDiff + Rand.Vector(0.5f)).ClampLength(15.0f);
185  fragment.Body.AngularVelocity = Rand.Range(-0.5f, 0.5f);
186 
187  Level.Loaded.UnsyncedExtraWalls.Add(fragment);
188 
189 #if CLIENT
190  for (int i = 0; i < 5; i++)
191  {
192  int startEdgeIndex = Rand.Int(3);
193  Vector2 pos1 = triangle[startEdgeIndex];
194  Vector2 pos2 = triangle[(startEdgeIndex + 1) % 3];
195 
196  var particle = GameMain.ParticleManager.CreateParticle("iceexplosion",
197  triangleCenter + Vector2.Lerp(pos1, pos2, Rand.Range(0.0f, 1.0f)),
198  velocity: (Rand.Vector(Rand.Range(50.0f, 1000.0f)) + fragment.Body.LinearVelocity * 100.0f));
199  if (particle != null)
200  {
201  particle.Size *= Rand.Range(1.0f, 5.0f);
202  particle.ColorMultiplier *= Rand.Range(0.7f, 1.0f);
203  }
204  }
205 #endif
206  }
207  }
208 
209  public void Destroy()
210  {
211  if (Destroyed) { return; }
212  Destroyed = true;
213  level?.UnsyncedExtraWalls?.Remove(this);
214  foreach (var cell in Cells)
215  {
216  cell.CellType = CellType.Removed;
217  cell.OnDestroyed?.Invoke();
218  cell.OnDestroyed = null;
219  }
220  GameMain.World.Remove(Body);
221  Dispose();
222  }
223 
224  }
225 }
Attacks are used to deal damage to characters, structures and items. They can be defined in the weapo...
DestructibleLevelWall(List< Vector2 > vertices, Color color, Level level, float? health=null, bool giftWrap=false)
AttackResult AddDamage(Character attacker, Vector2 worldPosition, Attack attack, Vector2 impulseDirection, float deltaTime, bool playSound=true)
static World World
Definition: GameMain.cs:105
static NetworkMember NetworkMember
Definition: GameMain.cs:190