@adatechnology/game-destruction 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -88,7 +88,7 @@ for 3 mm glass), so a 9 mm shatters a window pane in one shot while a 5 cm block
88
88
  ## Fire, melting and leaks
89
89
 
90
90
  `update(dt)` advances everything that is hot. Burning parts consume fuel (`burnRate * surface`), lose hit points, char and finally turn to ashes
91
- (`fuelFraction >= 0.8`) or stay charred. Heat flows through closed joints by conductivity and to parts of other objects within `fireSpread`. Heat
91
+ (`fuelFraction >= 0.8`) or stay charred. Heat flows through closed joints by conductivity and to parts of other objects within `fireSpread`. With `blastFrontSpeed` (m/s, 340 is the speed of sound; default off) the glass an explosion reaches breaks `distance / speed` seconds later, in `update`, instead of on the spot. Heat
92
92
  only moves towards a source temperature, so a wood fire (800 °C) never melts steel (1450 °C) but melts aluminium and plastic, and a 3000 °C torch
93
93
  melts anything. Melting emits `melt` and `drip`; a melted part is lost and its joints open. Pressurized gas that leaks near fire burns (or explodes
94
94
  when the part has `explodes`). `contains` parts leak through punctures: the `leak` event carries the hole's world point, the outward normal as
package/dist/index.d.ts CHANGED
@@ -102,6 +102,11 @@ interface DestructionOptions {
102
102
  /** Multiplier of the breach area a blast makes over a blow of the same damage: a blast loads the whole crater (default 6). */
103
103
  blastFactor?: number;
104
104
  };
105
+ /**
106
+ * Speed of the blast front in m/s. A glass part at distance `d` from an explosion breaks `d / blastFrontSpeed` seconds later, in `update`
107
+ * (the speed of sound is 340). Default off: every part takes the blast at once.
108
+ */
109
+ blastFrontSpeed?: number;
105
110
  }
106
111
  interface SizeStructureOptions {
107
112
  /** Stress every structural part has at rest after sizing (`load / capacity`), 0..1 (default 0.65). */
@@ -1675,6 +1675,8 @@ var GameDestruction = (() => {
1675
1675
  const listeners = /* @__PURE__ */ new Map();
1676
1676
  let cur = [];
1677
1677
  const blasts = [];
1678
+ const frontQueue = [];
1679
+ const blastFrontSpeed = options.blastFrontSpeed ?? 0;
1678
1680
  const primed = /* @__PURE__ */ new Map();
1679
1681
  let orderCounter = 0;
1680
1682
  const impls = /* @__PURE__ */ new Map();
@@ -2416,7 +2418,7 @@ var GameDestruction = (() => {
2416
2418
  return;
2417
2419
  }
2418
2420
  if (ex) {
2419
- emit({ ...base(o, src), type: "explode", part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius });
2421
+ emit({ ...base(o, src), type: "explode", part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...ex.effect !== void 0 ? { effect: ex.effect } : {} });
2420
2422
  blasts.push({ point: c, energy: ex.energy, radius: ex.radius, source: src });
2421
2423
  }
2422
2424
  partLost(o, p, src);
@@ -2563,8 +2565,13 @@ var GameDestruction = (() => {
2563
2565
  }
2564
2566
  }
2565
2567
  wearJoints(o, p, Ein * 0.5, void 0, 0, src);
2568
+ const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1);
2569
+ if (blastFrontSpeed > 0 && dist > 0 && mat.tags?.includes("glass")) {
2570
+ frontQueue.push({ o, p, due: time + dist / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...src !== void 0 ? { src } : {} });
2571
+ continue;
2572
+ }
2566
2573
  if (Ein > 20 && p.layers.length > 0) spallOuter(o, p, wp, faceOf(o, p, wn), wn, clamp2(0.05 + Math.sqrt(Ein) * 2e-3, 0.05, 0.4), src);
2567
- const dealt = applyDamage(o, p, Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1), "explosive", point, null, Ein * 0.3, 40, src);
2574
+ const dealt = applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
2568
2575
  res.damage += dealt;
2569
2576
  addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
2570
2577
  }
@@ -2889,6 +2896,15 @@ var GameDestruction = (() => {
2889
2896
  }
2890
2897
  time = end;
2891
2898
  };
2899
+ const releaseFront = () => {
2900
+ if (frontQueue.length === 0) return;
2901
+ frontQueue.sort((a, b) => a.due - b.due);
2902
+ while (frontQueue.length > 0 && frontQueue[0].due <= time) {
2903
+ const hit = frontQueue.shift();
2904
+ if (objects.get(hit.o.id) !== hit.o) continue;
2905
+ applyDamage(hit.o, hit.p, hit.amount, "explosive", hit.point, null, hit.fragEnergy, 40, hit.src);
2906
+ }
2907
+ };
2892
2908
  const withCollapses = (r) => {
2893
2909
  const last = r.value[r.value.length - 1];
2894
2910
  if (!last) return r.value;
@@ -3140,6 +3156,7 @@ var GameDestruction = (() => {
3140
3156
  for (const o of [...objects.values()]) if (o.active) stepObject(o, dt, sources);
3141
3157
  if (sources.length) spread2(sources, dt);
3142
3158
  detonatePrimed(time);
3159
+ releaseFront();
3143
3160
  for (const im of [...impls.values()]) {
3144
3161
  if (!im.impl.update) continue;
3145
3162
  for (const e of im.impl.update(dt) ?? []) emit(e.time === void 0 ? { ...e, time } : e);