Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
SubsystemExplosions.cs
浏览该文件的文档.
1using Engine;
4
5namespace Game {
7 public class SparseSpatialArray<T> {
8 public const int m_bits1 = 4;
9
10 public const int m_bits2 = 4;
11
12 public const int m_mask1 = 15;
13
14 public const int m_mask2 = 15;
15
16 public const int m_diameter = 256;
17
18 public int m_originX;
19
20 public int m_originY;
21
22 public int m_originZ;
23
24 public T[][] m_data;
25
26 public T m_outside;
27
28 public SparseSpatialArray(int centerX, int centerY, int centerZ, T outside) {
29 m_data = new T[4096][];
30 m_originX = centerX - 128;
31 m_originY = centerY - 128;
32 m_originZ = centerZ - 128;
33 m_outside = outside;
34 }
35
36 public T Get(int x, int y, int z) {
37 x -= m_originX;
38 y -= m_originY;
39 z -= m_originZ;
40 if (x >= 0
41 && x < 256
42 && y >= 0
43 && y < 256
44 && z >= 0
45 && z < 256) {
46 int num = x >> 4;
47 int explosionPower = y >> 4;
48 int num3 = z >> 4;
49 int num4 = num + (explosionPower << 4) + (num3 << 4 << 4);
50 T[] array = m_data[num4];
51 if (array != null) {
52 int num5 = x & 0xF;
53 int num6 = y & 0xF;
54 int num7 = z & 0xF;
55 int num8 = num5 + (num6 << 4) + (num7 << 4 << 4);
56 return array[num8];
57 }
58 return default;
59 }
60 return m_outside;
61 }
62
63 public void Set(int x, int y, int z, T value) {
64 x -= m_originX;
65 y -= m_originY;
66 z -= m_originZ;
67 if (x >= 0
68 && x < 256
69 && y >= 0
70 && y < 256
71 && z >= 0
72 && z < 256) {
73 int num = x >> 4;
74 int explosionPower = y >> 4;
75 int num3 = z >> 4;
76 int num4 = num + (explosionPower << 4) + (num3 << 4 << 4);
77 T[] array = m_data[num4];
78 if (array == null) {
79 array = new T[4096];
80 m_data[num4] = array;
81 }
82 int num5 = x & 0xF;
83 int num6 = y & 0xF;
84 int num7 = z & 0xF;
85 int num8 = num5 + (num6 << 4) + (num7 << 4 << 4);
86 array[num8] = value;
87 }
88 }
89
90 public void Clear() {
91 for (int i = 0; i < m_data.Length; i++) {
92 m_data[i] = null;
93 }
94 }
95
96 public Dictionary<Point3, T> ToDictionary() {
97 Dictionary<Point3, T> dictionary = new();
98 for (int i = 0; i < m_data.Length; i++) {
99 T[] array = m_data[i];
100 if (array == null) {
101 continue;
102 }
103 int num = m_originX + ((i & 0xF) << 4);
104 int explosionPower = m_originY + (((i >> 4) & 0xF) << 4);
105 int num3 = m_originZ + (((i >> 8) & 0xF) << 4);
106 for (int j = 0; j < array.Length; j++) {
107 if (!Equals(array[j], default(T))) {
108 int num4 = j & 0xF;
109 int num5 = (j >> 4) & 0xF;
110 int num6 = (j >> 8) & 0xF;
111 dictionary.Add(new Point3(num + num4, explosionPower + num5, num3 + num6), array[j]);
112 }
113 }
114 }
115 return dictionary;
116 }
117 }
118
119 public struct ExplosionData {
120 public ExplosionData() { }
121
122 public int X;
123
124 public int Y;
125
126 public int Z;
127
128 public float Pressure;
129
130 public bool IsIncendiary;
131
132 public bool NoExplosionSound;
133
138 }
139
140 public struct ProcessPoint {
141 public int X;
142
143 public int Y;
144
145 public int Z;
146
147 public int Axis;
148 }
149
151 public float Pressure;
152
153 public bool IsIncendiary;
154 }
155
157
159
161
163
165
167
169
171
173
174 public List<ExplosionData> m_queuedExplosions = [];
175
176 public SparseSpatialArray<float> m_pressureByPoint;
177
178 public SparseSpatialArray<SurroundingPressurePoint> m_surroundingPressureByPoint;
179
181
182 public Dictionary<Projectile, bool> m_generatedProjectiles = [];
183
184 public Random m_random = new();
185
187
189
191
192 public bool TryExplodeBlock(int x, int y, int z, int value) {
193 int num = Terrain.ExtractContents(value);
194 Block obj = BlocksManager.Blocks[num];
195 float explosionPressure = obj.GetExplosionPressure(value);
196 bool explosionIncendiary = obj.GetExplosionIncendiary(value);
197 if (explosionPressure > 0f) {
198 AddExplosion(x, y, z, explosionPressure, explosionIncendiary, false);
199 return true;
200 }
201 return false;
202 }
203
204 public void AddExplosion(int x, int y, int z, float pressure, bool isIncendiary, bool noExplosionSound) {
205 if (pressure > 0f) {
207 new ExplosionData { X = x, Y = y, Z = z, Pressure = pressure, IsIncendiary = isIncendiary, NoExplosionSound = noExplosionSound }
208 );
209 ApplyBodiesShaking(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), pressure);
210 }
211 }
212
213 public virtual void Update(float dt) {
214 if (m_queuedExplosions.Count <= 0) {
215 return;
216 }
217 int x = m_queuedExplosions[0].X;
218 int y = m_queuedExplosions[0].Y;
219 int z = m_queuedExplosions[0].Z;
220 m_pressureByPoint = new SparseSpatialArray<float>(x, y, z, 0f);
221 m_surroundingPressureByPoint = new SparseSpatialArray<SurroundingPressurePoint>(
222 x,
223 y,
224 z,
225 new SurroundingPressurePoint { IsIncendiary = false, Pressure = 0f }
226 );
229 bool flag = false;
230 int num = 0;
231 while (num < m_queuedExplosions.Count) {
232 ExplosionData explosionData = m_queuedExplosions[num];
233 if (MathF.Abs(explosionData.X - x) <= 4
234 && MathF.Abs(explosionData.Y - y) <= 4
235 && MathF.Abs(explosionData.Z - z) <= 4) {
236 m_queuedExplosions.RemoveAt(num);
237 //Task.Run(() => SimulateExplosion(explosionData.X, explosionData.Y, explosionData.Z, explosionData.Pressure, explosionData.IsIncendiary));
238 SimulateExplosion(explosionData.X, explosionData.Y, explosionData.Z, explosionData.Pressure, explosionData.IsIncendiary);
239 flag |= !explosionData.NoExplosionSound;
240 }
241 else {
242 num++;
243 }
244 }
245 /*
246 for (int num1 = 0; num1 < m_queuedExplosions.Count;num1++)
247 {
248 ExplosionData explosionData = m_queuedExplosions[num1];
249 while (!(MathF.Abs(explosionData.X - x) <= 4 && MathF.Abs(explosionData.Y - y) <= 4 && MathF.Abs(explosionData.Z - z) <= 4))
250 {
251 m_queuedExplosions.RemoveAt(num1);
252 SimulateExplosion(explosionData.X, explosionData.Y, explosionData.Z, explosionData.Pressure, explosionData.IsIncendiary);
253 flag |= !explosionData.NoExplosionSound;
254 }
255 }
256 */ /*
257 int m_queuedExplosionsCount = m_queuedExplosions.Count;
258 int[] indices = Enumerable.Range(0, m_queuedExplosionsCount).ToArray();
259
260 // 使用 Parallel.For 并行执行循环
261 Parallel.For(0, m_queuedExplosionsCount, (i, loopState) =>
262 {
263 int num1 = indices[i];
264 ExplosionData explosionData = m_queuedExplosions[num1];
265 if (MathF.Abs(explosionData.X - x) <= 4 && MathF.Abs(explosionData.Y - y) <= 4 && MathF.Abs(explosionData.Z - z) <= 4)
266 {
267 m_queuedExplosions.RemoveAt(num1);
268 SimulateExplosion(explosionData.X, explosionData.Y, explosionData.Z, explosionData.Pressure, explosionData.IsIncendiary);
269 flag |= !explosionData.NoExplosionSound;
270 }
271 });
272 */ /*
273 int index = 0;
274 foreach (var explosionData in m_queuedExplosions)
275 {
276 if (MathF.Abs(explosionData.X - x) <= 4 && MathF.Abs(explosionData.Y - y) <= 4 && MathF.Abs(explosionData.Z - z) <= 4)
277 {
278 m_queuedExplosions.RemoveAt(index);
279 Task.Run(() => SimulateExplosion(explosionData.X, explosionData.Y, explosionData.Z, explosionData.Pressure, explosionData.IsIncendiary));
280 flag |= !explosionData.NoExplosionSound;
281 }
282 else
283 {
284 index++;
285 }
286
287 }
288 */
291 m_pressureByPoint = null;
293 }
294 }
295
296 public override void Load(ValuesDictionary valuesDictionary) {
297 m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(true);
298 m_subsystemParticles = Project.FindSubsystem<SubsystemParticles>(true);
299 m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
300 m_subsystemNoise = Project.FindSubsystem<SubsystemNoise>(true);
301 m_subsystemBodies = Project.FindSubsystem<SubsystemBodies>(true);
302 m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(true);
308 }
309
310 public void SimulateExplosion(int x, int y, int z, float pressure, bool isIncendiary) {
311 int explosionPointValue = m_subsystemTerrain.Terrain.GetCellValue(x, y, z);
312 float num = MathUtils.Max(0.13f * MathF.Pow(pressure, 0.5f), 1f);
313 m_subsystemTerrain.ChangeCell(x, y, z, Terrain.MakeBlockValue(0));
314 SparseSpatialArray<bool> processed = new(x, y, z, true);
315 List<ProcessPoint> list = new();
316 List<ProcessPoint> list2 = new();
317 List<ProcessPoint> list3 = new();
319 x,
320 y,
321 z,
322 -1,
323 pressure,
324 isIncendiary,
325 list,
326 processed
327 );
328 int explosionPower = 0;
329 int num3 = 0;
330 if (Terrain.ExtractContents(explosionPointValue) != 0) {
332 "OnBlockExploded",
333 loader => {
334 loader.OnBlockExploded(m_subsystemTerrain, x, y, z, explosionPointValue);
335 return false;
336 }
337 );
338 }
339 while (list.Count > 0
340 || list2.Count > 0) {
341 explosionPower += list.Count;
342 num3++;
343 float num4 = 5f * MathUtils.Max(num3 - 7, 0);
344 float num5 = pressure / (MathF.Pow(explosionPower, 0.66f) + num4);
345 if (num5 >= num) {
346 foreach (ProcessPoint item in list) {
347 float num6 = m_pressureByPoint.Get(item.X, item.Y, item.Z);
348 float num7 = num5 + num6;
349 m_pressureByPoint.Set(item.X, item.Y, item.Z, num7);
350 if (item.Axis == 0) {
352 item.X - 1,
353 item.Y,
354 item.Z,
355 0,
356 num7,
357 isIncendiary,
358 list3,
359 processed
360 );
362 item.X + 1,
363 item.Y,
364 item.Z,
365 0,
366 num7,
367 isIncendiary,
368 list3,
369 processed
370 );
372 item.X,
373 item.Y - 1,
374 item.Z,
375 -1,
376 num7,
377 isIncendiary,
378 list2,
379 processed
380 );
382 item.X,
383 item.Y + 1,
384 item.Z,
385 -1,
386 num7,
387 isIncendiary,
388 list2,
389 processed
390 );
392 item.X,
393 item.Y,
394 item.Z - 1,
395 -1,
396 num7,
397 isIncendiary,
398 list2,
399 processed
400 );
402 item.X,
403 item.Y,
404 item.Z + 1,
405 -1,
406 num7,
407 isIncendiary,
408 list2,
409 processed
410 );
411 }
412 else if (item.Axis == 1) {
414 item.X - 1,
415 item.Y,
416 item.Z,
417 -1,
418 num7,
419 isIncendiary,
420 list2,
421 processed
422 );
424 item.X + 1,
425 item.Y,
426 item.Z,
427 -1,
428 num7,
429 isIncendiary,
430 list2,
431 processed
432 );
434 item.X,
435 item.Y - 1,
436 item.Z,
437 1,
438 num7,
439 isIncendiary,
440 list3,
441 processed
442 );
444 item.X,
445 item.Y + 1,
446 item.Z,
447 1,
448 num7,
449 isIncendiary,
450 list3,
451 processed
452 );
454 item.X,
455 item.Y,
456 item.Z - 1,
457 -1,
458 num7,
459 isIncendiary,
460 list2,
461 processed
462 );
464 item.X,
465 item.Y,
466 item.Z + 1,
467 -1,
468 num7,
469 isIncendiary,
470 list2,
471 processed
472 );
473 }
474 else if (item.Axis == 2) {
476 item.X - 1,
477 item.Y,
478 item.Z,
479 -1,
480 num7,
481 isIncendiary,
482 list2,
483 processed
484 );
486 item.X + 1,
487 item.Y,
488 item.Z,
489 -1,
490 num7,
491 isIncendiary,
492 list2,
493 processed
494 );
496 item.X,
497 item.Y - 1,
498 item.Z,
499 -1,
500 num7,
501 isIncendiary,
502 list2,
503 processed
504 );
506 item.X,
507 item.Y + 1,
508 item.Z,
509 -1,
510 num7,
511 isIncendiary,
512 list2,
513 processed
514 );
516 item.X,
517 item.Y,
518 item.Z - 1,
519 2,
520 num7,
521 isIncendiary,
522 list3,
523 processed
524 );
526 item.X,
527 item.Y,
528 item.Z + 1,
529 2,
530 num7,
531 isIncendiary,
532 list3,
533 processed
534 );
535 }
536 else {
538 item.X - 1,
539 item.Y,
540 item.Z,
541 0,
542 num7,
543 isIncendiary,
544 list3,
545 processed
546 );
548 item.X + 1,
549 item.Y,
550 item.Z,
551 0,
552 num7,
553 isIncendiary,
554 list3,
555 processed
556 );
558 item.X,
559 item.Y - 1,
560 item.Z,
561 1,
562 num7,
563 isIncendiary,
564 list3,
565 processed
566 );
568 item.X,
569 item.Y + 1,
570 item.Z,
571 1,
572 num7,
573 isIncendiary,
574 list3,
575 processed
576 );
578 item.X,
579 item.Y,
580 item.Z - 1,
581 2,
582 num7,
583 isIncendiary,
584 list3,
585 processed
586 );
588 item.X,
589 item.Y,
590 item.Z + 1,
591 2,
592 num7,
593 isIncendiary,
594 list3,
595 processed
596 );
597 }
598 }
599 }
600 List<ProcessPoint> list4 = list;
601 list4.Clear();
602 list = list2;
603 list2 = list3;
604 list3 = list4;
605 }
606 }
607
608 public void TryAddPoint(int x,
609 int y,
610 int z,
611 int axis,
612 float currentPressure,
613 bool isIncendiary,
614 List<ProcessPoint> toProcess,
615 SparseSpatialArray<bool> processed) {
616 if (processed.Get(x, y, z)) {
617 return;
618 }
619 int cellValue = m_subsystemTerrain.Terrain.GetCellValue(x, y, z);
620 int num = Terrain.ExtractContents(cellValue);
621 if (num != 0) {
622 int explosionPower = (int)(MathUtils.Hash((uint)(x + 913 * y + 217546 * z)) % 100u);
623 float num3 = MathUtils.Lerp(1f, 2f, explosionPower / 100f);
624 if (explosionPower % 8 == 0) {
625 num3 *= 3f;
626 }
627 Block block = BlocksManager.Blocks[num];
628 float num4 = m_pressureByPoint.Get(x - 1, y, z)
629 + m_pressureByPoint.Get(x + 1, y, z)
630 + m_pressureByPoint.Get(x, y - 1, z)
631 + m_pressureByPoint.Get(x, y + 1, z)
632 + m_pressureByPoint.Get(x, y, z - 1)
633 + m_pressureByPoint.Get(x, y, z + 1);
634 float num5 = MathUtils.Max(block.GetExplosionResilience(cellValue) * num3, 1f);
635 float num6 = num4 / num5;
636 if (num6 > 1f) {
637 int newValue = Terrain.MakeBlockValue(0);
638 m_subsystemTerrain.DestroyCell(
639 0,
640 x,
641 y,
642 z,
643 newValue,
644 true,
645 true
646 );
647 bool flag = false;
648 float probability = num6 > 5f ? 0.95f : 0.75f;
649 if (m_random.Bool(probability)) {
650 flag = TryExplodeBlock(x, y, z, cellValue);
651 }
652 if (!flag) {
653 CalculateImpulseAndDamage(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), 60f, 2f * num4, out Vector3 impulse, out float _);
654 bool flag2 = false;
655 List<BlockDropValue> list = new();
656 block.GetDropValues(m_subsystemTerrain, cellValue, newValue, 0, list, out bool _);
658 "OnBlockExploded",
659 loader => {
660 loader.OnBlockExploded(m_subsystemTerrain, x, y, z, cellValue);
661 return false;
662 }
663 );
664 if (list.Count == 0) {
665 list.Add(new BlockDropValue { Value = cellValue, Count = 1 });
666 flag2 = true;
667 }
668 foreach (BlockDropValue item in list) {
669 int num7 = Terrain.ExtractContents(item.Value);
670 Block block2 = BlocksManager.Blocks[num7];
671 if (block2 is FluidBlock) {
672 continue;
673 }
674 float num8 = m_projectilesCount < 40 || block2.ExplosionKeepsPickables ? 1f :
675 m_projectilesCount < 60 ? 0.5f :
676 m_projectilesCount >= 80 ? 0.125f : 0.25f;
677 if (!(m_random.Float(0f, 1f) < num8)) {
678 continue;
679 }
680 Vector3 velocity = impulse + m_random.Vector3(0.05f * impulse.Length());
681 if (m_projectilesCount >= 1) {
682 velocity *= m_random.Float(0.5f, 1f);
683 velocity += m_random.Vector3(0.2f * velocity.Length());
684 }
685 float num9 = flag2 ? 0f :
686 block2.ExplosionKeepsPickables ? 1f : MathUtils.Lerp(1f, 0f, m_projectilesCount / 25f);
687 Projectile projectile = m_subsystemProjectiles.AddProjectile(
688 item.Value,
689 new Vector3(x + 0.5f, y + 0.5f, z + 0.5f),
690 velocity,
691 m_random.Vector3(0f, 20f),
692 null
693 );
694 projectile.ProjectileStoppedAction = !(m_random.Float(0f, 1f) < num9)
696 : ProjectileStoppedAction.TurnIntoPickable;
697 if (m_random.Float(0f, 1f) < 0.5f
698 && m_projectilesCount < 35) {
699 float num10 = num4 > 60f ? m_random.Float(3f, 7f) : m_random.Float(1f, 3f);
700 if (isIncendiary) {
701 num10 += 10f;
702 }
703 m_subsystemProjectiles.AddTrail(
704 projectile,
707 15,
708 m_random.Float(0.75f, 1.5f),
709 num10,
710 isIncendiary ? new Color(255, 140, 192) : Color.White
711 )
712 );
713 projectile.IsIncendiary = isIncendiary;
714 }
715 m_generatedProjectiles.Add(projectile, true);
717 }
718 }
719 }
720 else {
721 m_surroundingPressureByPoint.Set(x, y, z, new SurroundingPressurePoint { Pressure = num4, IsIncendiary = isIncendiary });
722 if (block.IsCollidable_(cellValue)) {
723 return;
724 }
725 }
726 }
727 toProcess.Add(new ProcessPoint { X = x, Y = y, Z = z, Axis = axis });
728 processed.Set(x, y, z, true);
729 }
730
731 public virtual void ApplyBodiesShaking(Vector3 center, float pressure) {
732 foreach (ComponentBody body in m_subsystemBodies.Bodies) {
733 body.UnderExplosionStart(center, pressure);
734 }
735 }
736
737 public virtual void PostprocessExplosions(bool playExplosionSound) {
738 Point3 point = Point3.Zero;
739 float num = float.MaxValue;
740 float pressure = 0f;
741 foreach (KeyValuePair<Point3, float> item in m_pressureByPoint.ToDictionary()) {
742 pressure += item.Value;
743 float num3 = m_subsystemAudio.CalculateListenerDistance(new Vector3(item.Key));
744 if (num3 < num) {
745 num = num3;
746 point = item.Key;
747 }
748 float num4 = 0.001f * MathF.Pow(pressure, 0.5f);
749 float num5 = MathUtils.Saturate(item.Value / 15f - num4) * m_random.Float(0.2f, 1f);
750 if (num5 > 0.1f) {
751 m_explosionParticleSystem.SetExplosionCell(item.Key, num5);
752 }
753 }
755 "CalculateExplosionPower",
756 loader => {
757 loader.CalculateExplosionPower(this, ref pressure);
758 return false;
759 }
760 );
761 foreach (KeyValuePair<Point3, SurroundingPressurePoint> item2 in m_surroundingPressureByPoint.ToDictionary()) {
762 int cellValue = m_subsystemTerrain.Terrain.GetCellValue(item2.Key.X, item2.Key.Y, item2.Key.Z);
763 int num6 = Terrain.ExtractContents(cellValue);
764 SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(cellValue));
765 if (blockBehaviors.Length != 0) {
766 for (int i = 0; i < blockBehaviors.Length; i++) {
767 blockBehaviors[i].OnExplosion(cellValue, item2.Key.X, item2.Key.Y, item2.Key.Z, item2.Value.Pressure);
768 }
769 }
770 float probability = item2.Value.IsIncendiary ? 0.5f : 0.2f;
771 Block block = BlocksManager.Blocks[num6];
772 if (block.GetFireDuration(cellValue) > 0f
773 && item2.Value.Pressure / block.GetExplosionResilience(cellValue) > 0.2f
774 && m_random.Bool(probability)) {
775 m_subsystemFireBlockBehavior.SetCellOnFire(item2.Key.X, item2.Key.Y, item2.Key.Z, item2.Value.IsIncendiary ? 1f : 0.3f);
776 }
777 }
778 foreach (ComponentBody body in m_subsystemBodies.Bodies) {
779 CalculateImpulseAndDamage(body, null, out Vector3 impulse, out float damage);
780 body.UnderExplosion(impulse, damage);
781 }
782 foreach (Pickable pickable in m_subsystemPickables.Pickables) {
783 //Block block2 = BlocksManager.Blocks[Terrain.ExtractContents(pickable.Value)];
785 pickable.Position + new Vector3(0f, 0.5f, 0f),
786 pickable.ExplosionMass,
787 null,
788 out Vector3 impulse2,
789 out float damage2
790 );
791 pickable.Project = Project;
792 pickable.UnderExplosion(impulse2, damage2);
793 }
794 foreach (Projectile projectile2 in m_subsystemProjectiles.Projectiles) {
795 if (!m_generatedProjectiles.ContainsKey(projectile2)) {
797 projectile2.Position + new Vector3(0f, 0.5f, 0f),
798 projectile2.ExplosionMass,
799 null,
800 out Vector3 impulse3,
801 out float damage3
802 );
803 projectile2.UnderExplosion(impulse3, damage3);
804 }
805 }
806 Vector3 position = new(point.X, point.Y, point.Z);
807 float delay = m_subsystemAudio.CalculateDelay(num);
808 if (pressure > 2000000f) {
809 if (playExplosionSound) {
810 m_subsystemAudio.PlaySound("Audio/Explosion7", 1f, m_random.Float(-0.1f, 0.1f), position, 53f, delay);
811 }
812 m_subsystemNoise.MakeNoise(position, 1f, 130f);
813 }
814 else if (pressure > 400000f) {
815 if (playExplosionSound) {
816 m_subsystemAudio.PlaySound("Audio/Explosion6", 1f, m_random.Float(-0.1f, 0.1f), position, 45f, delay);
817 }
818 m_subsystemNoise.MakeNoise(position, 1f, 100f);
819 }
820 else if (pressure > 80000f) {
821 if (playExplosionSound) {
822 m_subsystemAudio.PlaySound("Audio/Explosion5", 1f, m_random.Float(-0.1f, 0.1f), position, 38f, delay);
823 }
824 m_subsystemNoise.MakeNoise(position, 1f, 70f);
825 }
826 else if (pressure > 16000f) {
827 if (playExplosionSound) {
828 m_subsystemAudio.PlaySound("Audio/Explosion4", 1f, m_random.Float(-0.1f, 0.1f), position, 32f, delay);
829 }
830 m_subsystemNoise.MakeNoise(position, 1f, 50f);
831 }
832 else if (pressure > 3500f) {
833 if (playExplosionSound) {
834 m_subsystemAudio.PlaySound("Audio/Explosion3", 1f, m_random.Float(-0.1f, 0.1f), position, 27f, delay);
835 }
836 m_subsystemNoise.MakeNoise(position, 1f, 40f);
837 }
838 else if (pressure > 80f) {
839 if (playExplosionSound) {
840 m_subsystemAudio.PlaySound("Audio/Explosion2", 1f, m_random.Float(-0.1f, 0.1f), position, 23f, delay);
841 }
842 m_subsystemNoise.MakeNoise(position, 1f, 35f);
843 }
844 else if (pressure > 0f) {
845 if (playExplosionSound) {
846 m_subsystemAudio.PlaySound("Audio/Explosion1", 1f, m_random.Float(-0.1f, 0.1f), position, 20f, delay);
847 }
848 m_subsystemNoise.MakeNoise(position, 1f, 30f);
849 }
850 }
851
852 public virtual void CalculateImpulseAndDamage(ComponentBody componentBody, float? obstaclePressure, out Vector3 impulse, out float damage) {
854 0.5f * (componentBody.BoundingBox.Min + componentBody.BoundingBox.Max),
855 componentBody.Mass,
856 obstaclePressure,
857 out impulse,
858 out damage
859 );
860 }
861
862 public virtual void CalculateImpulseAndDamage(Vector3 position, float mass, float? obstaclePressure, out Vector3 impulse, out float damage) {
863 Point3 point = Terrain.ToCell(position);
864 obstaclePressure ??= m_pressureByPoint.Get(point.X, point.Y, point.Z);
865 float num = 0f;
866 Vector3 zero = Vector3.Zero;
867 for (int i = -1; i <= 1; i++) {
868 for (int j = -1; j <= 1; j++) {
869 for (int k = -1; k <= 1; k++) {
870 int pressure = point.X + i;
871 int num3 = point.Y + j;
872 int num4 = point.Z + k;
873 float num5 = m_subsystemTerrain.Terrain.GetCellContents(pressure, num3, num4) != 0
874 ? obstaclePressure.Value
875 : m_pressureByPoint.Get(pressure, num3, num4);
876 if (i != 0
877 || j != 0
878 || k != 0) {
879 zero += num5 * Vector3.Normalize(new Vector3(point.X - pressure, point.Y - num3, point.Z - num4));
880 }
881 num += num5;
882 }
883 }
884 }
885 float num6 = MathUtils.Max(MathF.Pow(mass, 0.5f), 1f);
886 impulse = 5.5555553f * Vector3.Normalize(zero) * MathF.Sqrt(zero.Length()) / num6;
887 damage = 2.59259248f * MathF.Sqrt(num) / num6;
888 }
889 }
890}
Engine.Vector3 Vector3
static int Hash(int key)
static float Saturate(float x)
static int Max(int x1, int x2)
static float Lerp(float x1, float x2, float f)
virtual void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List< BlockDropValue > dropValues, out bool showDebris)
virtual bool GetExplosionIncendiary(int value)
virtual float GetExplosionResilience(int value)
virtual float GetExplosionPressure(int value)
virtual bool IsCollidable_(int value)
virtual float GetFireDuration(int value)
virtual BoundingBox BoundingBox
virtual void UnderExplosionStart(Vector3 explosionCenter, float explosionPressure)
virtual void UnderExplosion(Vector3 impulse, float damage)
override void UnderExplosion(Vector3 impulse, float damage)
override void UnderExplosion(Vector3 impulse, float damage)
virtual void OnExplosion(int value, int x, int y, int z, float damage)
SparseSpatialArray(int centerX, int centerY, int centerZ, T outside)
SubsystemProjectiles m_subsystemProjectiles
override void Load(ValuesDictionary valuesDictionary)
SparseSpatialArray< float > m_pressureByPoint
SubsystemBlockBehaviors m_subsystemBlockBehaviors
void TryAddPoint(int x, int y, int z, int axis, float currentPressure, bool isIncendiary, List< ProcessPoint > toProcess, SparseSpatialArray< bool > processed)
virtual void CalculateImpulseAndDamage(ComponentBody componentBody, float? obstaclePressure, out Vector3 impulse, out float damage)
virtual void CalculateImpulseAndDamage(Vector3 position, float mass, float? obstaclePressure, out Vector3 impulse, out float damage)
SparseSpatialArray< SurroundingPressurePoint > m_surroundingPressureByPoint
ExplosionParticleSystem m_explosionParticleSystem
void SimulateExplosion(int x, int y, int z, float pressure, bool isIncendiary)
void AddExplosion(int x, int y, int z, float pressure, bool isIncendiary, bool noExplosionSound)
bool TryExplodeBlock(int x, int y, int z, int value)
Dictionary< Projectile, bool > m_generatedProjectiles
virtual void PostprocessExplosions(bool playExplosionSound)
virtual void ApplyBodiesShaking(Vector3 center, float pressure)
SubsystemFireBlockBehavior m_subsystemFireBlockBehavior
List< ExplosionData > m_queuedExplosions
static int ExtractContents(int value)
static int ToCell(float x)
static int MakeBlockValue(int contents)
ValuesDictionary ValuesDictionary
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
static Color White
static readonly Point3 Zero
static Vector3 Normalize(Vector3 v)
static readonly Vector3 Zero
ValuesDictionary ValuesDictionaryForMods
模组如果需要添加或使用额外信息,可以在这个ValuesDictionary读写元素