@adatechnology/game-destruction 0.3.2 → 0.4.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/dist/index.js CHANGED
@@ -1,3 +1,22 @@
1
+ // src/chain.ts
2
+ var FIRE_PRIME_C = 300;
3
+ var drawChainDelay = (delay, random) => {
4
+ if (typeof delay === "number") return delay;
5
+ const [min, max] = delay;
6
+ return min + random() * (max - min);
7
+ };
8
+ var chainDelayOf = (spec, trigger) => spec.explodes?.chain?.[trigger];
9
+ var shotDamageFractionOf = (spec) => spec.explodes?.chain?.shotDamageFraction ?? 0;
10
+ var explosivePart = (explosive, part, options = {}) => ({
11
+ ...part,
12
+ explodes: {
13
+ energy: explosive.energy,
14
+ radius: explosive.injuryRadius,
15
+ ...options.atC !== void 0 ? { atC: options.atC } : {},
16
+ ...explosive.chain ? { chain: { ...explosive.chain } } : {}
17
+ }
18
+ });
19
+
1
20
  // src/math.ts
2
21
  var EPS = 1e-9;
3
22
  var vec = {
@@ -1441,6 +1460,8 @@ var createDestruction = (options = {}) => {
1441
1460
  const listeners = /* @__PURE__ */ new Map();
1442
1461
  let cur = [];
1443
1462
  const blasts = [];
1463
+ const primed = /* @__PURE__ */ new Map();
1464
+ let orderCounter = 0;
1444
1465
  const impls = /* @__PURE__ */ new Map();
1445
1466
  const taken = (id) => objects.has(id) || impls.has(id);
1446
1467
  const emit = (e) => {
@@ -1454,6 +1475,9 @@ var createDestruction = (options = {}) => {
1454
1475
  const base = (o, source) => source === void 0 ? { object: o.id, time } : { object: o.id, time, source };
1455
1476
  const pendingCollapse = /* @__PURE__ */ new Map();
1456
1477
  let runDepth = 0;
1478
+ const drainBlasts = () => {
1479
+ for (let blast = blasts.shift(); blast; blast = blasts.shift()) blastWorld(blast.point, blast.energy, blast.radius, blast.source);
1480
+ };
1457
1481
  const run = (fn) => {
1458
1482
  const prev = cur;
1459
1483
  const mine = [];
@@ -1461,11 +1485,7 @@ var createDestruction = (options = {}) => {
1461
1485
  runDepth++;
1462
1486
  try {
1463
1487
  const value = fn();
1464
- let guard = 0;
1465
- while (blasts.length && guard++ < 64) {
1466
- const b = blasts.shift();
1467
- blastWorld(b.point, b.energy, b.radius, b.source);
1468
- }
1488
+ drainBlasts();
1469
1489
  if (runDepth === 1) flushCollapse();
1470
1490
  return { value, events: mine };
1471
1491
  } finally {
@@ -1525,7 +1545,8 @@ var createDestruction = (options = {}) => {
1525
1545
  maxStress: 0,
1526
1546
  collapsed: new Set(carry?.collapsed ?? []),
1527
1547
  unsup: [],
1528
- anyAnchor: false
1548
+ anyAnchor: false,
1549
+ order: ++orderCounter
1529
1550
  };
1530
1551
  for (const ps of spec.parts) {
1531
1552
  if (o.byId.has(ps.id)) throw new Error(`duplicate part id "${ps.id}"`);
@@ -1572,6 +1593,7 @@ var createDestruction = (options = {}) => {
1572
1593
  cap: ps.structure ? partCapacity(ps, mat) : 0
1573
1594
  };
1574
1595
  if (p.structural) o.hasStructure = true;
1596
+ if (p.rt.chainDue !== void 0 && !isLost(p)) primed.set(p, o);
1575
1597
  o.idx.set(ps.id, o.parts.length);
1576
1598
  o.parts.push(p);
1577
1599
  o.byId.set(ps.id, p);
@@ -2009,15 +2031,29 @@ var createDestruction = (options = {}) => {
2009
2031
  }
2010
2032
  partLost(o, p, src);
2011
2033
  };
2034
+ const prime = (o, p, trigger, src) => {
2035
+ const spec = chainDelayOf(p.spec, trigger);
2036
+ if (spec === void 0 || isLost(p) || p.rt.chainDue !== void 0) return;
2037
+ const delay = drawChainDelay(spec, rnd);
2038
+ p.rt.chainDue = time + delay;
2039
+ primed.set(p, o);
2040
+ o.active = true;
2041
+ emit({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
2042
+ };
2043
+ const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
2012
2044
  const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
2013
2045
  if (isLost(p) || amount <= 0) return 0;
2014
2046
  const prev = p.st.hp;
2015
2047
  p.st.hp -= amount;
2016
2048
  markDamaged(p);
2049
+ const trigger = CHAIN_TRIGGER_OF[type];
2050
+ const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
2051
+ if (chained && p.st.hp <= 0 && p.rt.chainDue === void 0) p.st.hp = Math.min(prev, 1);
2017
2052
  if (p.st.hp <= 0 && p.mat.fracture === "none" && !p.spec.explodes) p.st.hp = Math.min(prev, 1);
2018
2053
  const done = prev - p.st.hp;
2019
2054
  if (done > 0) emit({ ...base(o, src), type: "damage", part: p.spec.id, amount: done, hp: Math.max(0, p.st.hp), damageType: type });
2020
2055
  if (p.st.hp <= 0) failPart(o, p, origin, dir, fragEnergy, cap, src);
2056
+ else if (chained && (trigger === "explosion" || 1 - p.st.hp / p.st.maxHp >= shotDamageFractionOf(p.spec))) prime(o, p, trigger, src);
2021
2057
  return done;
2022
2058
  };
2023
2059
  const ballistic = (o, p, entry, n, d, E, caliber, pathLen, src) => {
@@ -2318,7 +2354,9 @@ var createDestruction = (options = {}) => {
2318
2354
  if (isLost(p)) continue;
2319
2355
  checkIgnite(o, p);
2320
2356
  const ex = p.spec.explodes;
2321
- if (ex && ex.atC !== void 0 && s.temperature >= ex.atC) {
2357
+ if (ex && chainDelayOf(p.spec, "fire") !== void 0) {
2358
+ if (s.temperature >= (ex.atC ?? FIRE_PRIME_C)) prime(o, p, "fire");
2359
+ } else if (ex && ex.atC !== void 0 && s.temperature >= ex.atC) {
2322
2360
  failPart(o, p, null, null, 0, 40);
2323
2361
  continue;
2324
2362
  }
@@ -2330,6 +2368,10 @@ var createDestruction = (options = {}) => {
2330
2368
  s.liters = Math.max(0, (s.liters ?? 0) - rate * dt);
2331
2369
  hot = true;
2332
2370
  if (FLAMMABLE_FLUIDS.includes(cont.fluid) && s.temperature >= 350 && !p.rt.jet) {
2371
+ if (ex && chainDelayOf(p.spec, "fire") !== void 0) {
2372
+ prime(o, p, "fire");
2373
+ continue;
2374
+ }
2333
2375
  if (ex) {
2334
2376
  failPart(o, p, null, null, 0, 40);
2335
2377
  continue;
@@ -2413,6 +2455,34 @@ var createDestruction = (options = {}) => {
2413
2455
  }
2414
2456
  }
2415
2457
  };
2458
+ const nextPrimed = (until) => {
2459
+ let best = null;
2460
+ for (const [p, o] of primed) {
2461
+ if (objects.get(o.id) !== o || isLost(p)) {
2462
+ primed.delete(p);
2463
+ continue;
2464
+ }
2465
+ const due = p.rt.chainDue;
2466
+ if (due > until) continue;
2467
+ if (!best) best = { o, p };
2468
+ else {
2469
+ const bestDue = best.p.rt.chainDue;
2470
+ if (due < bestDue || due === bestDue && (o.order < best.o.order || o.order === best.o.order && (o.idx.get(p.spec.id) ?? 0) < (best.o.idx.get(best.p.spec.id) ?? 0))) best = { o, p };
2471
+ }
2472
+ }
2473
+ return best;
2474
+ };
2475
+ const detonatePrimed = (until) => {
2476
+ const end = time;
2477
+ for (let next = nextPrimed(until); next; next = nextPrimed(until)) {
2478
+ primed.delete(next.p);
2479
+ time = Math.max(0, Math.min(end, next.p.rt.chainDue));
2480
+ next.p.rt.chainDue = void 0;
2481
+ failPart(next.o, next.p, null, null, 0, 40);
2482
+ drainBlasts();
2483
+ }
2484
+ time = end;
2485
+ };
2416
2486
  const withCollapses = (r) => {
2417
2487
  const last = r.value[r.value.length - 1];
2418
2488
  if (!last) return r.value;
@@ -2663,6 +2733,7 @@ var createDestruction = (options = {}) => {
2663
2733
  const sources = [];
2664
2734
  for (const o of [...objects.values()]) if (o.active) stepObject(o, dt, sources);
2665
2735
  if (sources.length) spread(sources, dt);
2736
+ detonatePrimed(time);
2666
2737
  for (const im of [...impls.values()]) {
2667
2738
  if (!im.impl.update) continue;
2668
2739
  for (const e of im.impl.update(dt) ?? []) emit(e.time === void 0 ? { ...e, time } : e);
@@ -2956,6 +3027,7 @@ var locales = {
2956
3027
  drip: "dripping",
2957
3028
  leak: "leak",
2958
3029
  explode: "exploded",
3030
+ primed: "about to explode",
2959
3031
  stress: "overload",
2960
3032
  collapse: "collapsed",
2961
3033
  destroyed: "destroyed"
@@ -3037,6 +3109,7 @@ var locales = {
3037
3109
  drip: "pingando",
3038
3110
  leak: "vazamento",
3039
3111
  explode: "explodiu",
3112
+ primed: "prestes a explodir",
3040
3113
  stress: "sobrecarga",
3041
3114
  collapse: "desabou",
3042
3115
  destroyed: "destru\xEDdo"
@@ -3055,6 +3128,7 @@ var checkDestructible = (impl, options = {}) => {
3055
3128
  return check(impl, contractOptions);
3056
3129
  };
3057
3130
  export {
3131
+ FIRE_PRIME_C,
3058
3132
  IMPACT_CONTRACT,
3059
3133
  JOINT_BY_MATERIALS,
3060
3134
  JOINT_DEFAULTS,
@@ -3063,6 +3137,7 @@ export {
3063
3137
  checkDestructible,
3064
3138
  checkHit,
3065
3139
  createDestruction,
3140
+ explosivePart,
3066
3141
  fragility,
3067
3142
  guessMaterial,
3068
3143
  inferJoints,