@adatechnology/game-destruction 0.18.2 → 0.19.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.
@@ -3416,23 +3416,42 @@ var GameDestruction = (() => {
3416
3416
  const v = table[mat.penetrationClass ?? mat.id] ?? table[mat.id];
3417
3417
  return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
3418
3418
  };
3419
- var capacityScale = (p) => {
3419
+ var BURIED_BLAST_REACH = 0.5;
3420
+ var GIVE_AT_CUT_HP = 0.5;
3421
+ var capacityScale = (p, borne, through) => {
3420
3422
  const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
3421
3423
  if (p.st.stripped) return residual;
3422
- const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, 1 - sectionLoss(p));
3424
+ const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, sectionKept(p, residual, borne, through));
3423
3425
  return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
3424
3426
  };
3425
- var sectionLoss = (p) => {
3427
+ var sectionKept = (p, residual, borne, through) => {
3428
+ let kept = 1;
3429
+ forEachSection(p, borne, (c, along, gone) => {
3430
+ const share = through?.(c.center, along) ?? 1;
3431
+ if (share <= 0) return;
3432
+ kept = Math.min(kept, Math.max(p.spec.reinforcement ? residual : 0, 1 - gone) / share);
3433
+ });
3434
+ return kept;
3435
+ };
3436
+ var sectionLoss = (p, borne) => {
3437
+ let worst = 0;
3438
+ forEachSection(p, borne, (_c, _along, gone) => {
3439
+ worst = Math.max(worst, gone);
3440
+ });
3441
+ return Math.min(1, worst);
3442
+ };
3443
+ var forEachSection = (p, borne, visit) => {
3426
3444
  const cells = p.st.chipped;
3427
- if (!cells?.length) return 0;
3445
+ if (!cells?.length) return;
3428
3446
  const [u, v] = planeAxes(p.thin);
3429
3447
  const role = p.spec.structure?.role;
3430
3448
  const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
3431
3449
  const upright = Math.abs(up[1]) > 0.7 ? v : Math.abs(rotateVec(p.q, [0, 0, 0].map((_, k) => k === u ? 1 : 0))[1]) > 0.7 ? u : -1;
3432
3450
  const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
3433
3451
  const across = along === u ? v : u;
3434
- let worst = 0;
3452
+ const lying = along !== upright || upright < 0;
3435
3453
  for (const c of cells) {
3454
+ if (lying && borne?.(c.center, along)) continue;
3436
3455
  const spans = [];
3437
3456
  for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) spans.push([d.center[across] - d.size[across] / 2, d.center[across] + d.size[across] / 2]);
3438
3457
  spans.sort((a, b) => a[0] - b[0]);
@@ -3442,9 +3461,8 @@ var GameDestruction = (() => {
3442
3461
  gone += b - Math.max(a, end);
3443
3462
  end = b;
3444
3463
  }
3445
- worst = Math.max(worst, gone / Math.max(p.dims[across], 1e-6));
3464
+ visit(c, along, Math.min(1, gone / Math.max(p.dims[across], 1e-6)));
3446
3465
  }
3447
- return Math.min(1, worst);
3448
3466
  };
3449
3467
  var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
3450
3468
  var clone = (v) => structuredClone(v);
@@ -3755,6 +3773,26 @@ var GameDestruction = (() => {
3755
3773
  byTouching.set(support, { version: poseVersion, box });
3756
3774
  return box;
3757
3775
  };
3776
+ const throughOf = (p) => {
3777
+ const load = p.st.load ?? 0;
3778
+ if (load <= 0) return void 0;
3779
+ const above = Math.max(0, load - p.st.mass);
3780
+ const up = rotateVec(p.q, [0, 1, 0]);
3781
+ return (local, along) => {
3782
+ const axis = [0, 0, 0];
3783
+ axis[along] = 1;
3784
+ const sign = Math.sign(rotateVec(p.q, axis)[1]);
3785
+ if (Math.abs(up[1]) < 0.7 && Math.abs(rotateVec(p.q, axis)[1]) < 0.7) return 1;
3786
+ const half = p.dims[along] / 2;
3787
+ const share = clamp2((half - sign * local[along]) / Math.max(p.dims[along], 1e-6), 0, 1);
3788
+ return (above + p.st.mass * share) / load;
3789
+ };
3790
+ };
3791
+ const borneOn = (p, supports) => {
3792
+ if (supports.length === 0) return void 0;
3793
+ const boxes = supports.map((support) => contactBox(p, support));
3794
+ return (local, along) => boxes.some(([lo, hi]) => local[along] >= lo[along] - SUPPORT_TOLERANCE && local[along] <= hi[along] + SUPPORT_TOLERANCE);
3795
+ };
3758
3796
  const measureContact = (p, support) => {
3759
3797
  const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
3760
3798
  const lo = [0, 0, 0], hi = [0, 0, 0];
@@ -3962,7 +4000,7 @@ var GameDestruction = (() => {
3962
4000
  o.unsup[i] = o.anyAnchor && !isLost(p) && !p.orphan;
3963
4001
  continue;
3964
4002
  }
3965
- p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p));
4003
+ p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p, borneOn(p, (lowerOf.get(i) ?? []).map((k) => parts[k])), throughOf(p)));
3966
4004
  if (p.bend) {
3967
4005
  p.bendLoad = p.st.mass + bending[i];
3968
4006
  const bent = restFlexure(o, p, lowerOf.get(i) ?? []);
@@ -5052,6 +5090,27 @@ var GameDestruction = (() => {
5052
5090
  debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
5053
5091
  return loose.length;
5054
5092
  };
5093
+ const giveAtCut = (o, p, src) => {
5094
+ if (!p.spec.reinforcement || !p.spec.units || !p.st.chipped?.length || sectionLoss(p) <= 0) return false;
5095
+ const opened = [];
5096
+ for (const j of o.byPart.get(p.spec.id) ?? []) {
5097
+ if (j.st.open) continue;
5098
+ const onIt = j.bears === "a_on_b" && j.spec.b === p.spec.id || j.bears === "b_on_a" && j.spec.a === p.spec.id;
5099
+ if (!onIt) continue;
5100
+ j.st.open = true;
5101
+ j.st.openedBy = "break";
5102
+ opened.push(j);
5103
+ }
5104
+ if (opened.length === 0) return false;
5105
+ p.st.hp = Math.max(p.st.hp, p.st.maxHp * GIVE_AT_CUT_HP);
5106
+ markDamaged(p);
5107
+ solveStructure(o);
5108
+ recomputeGroups(o);
5109
+ detachEvents(o, opened, "break", src);
5110
+ exposeRebar(o, p, src);
5111
+ collapseCheck(o, src);
5112
+ return true;
5113
+ };
5055
5114
  const stripPart = (o, p, reinforcement, src) => {
5056
5115
  const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
5057
5116
  p.st.stripped = true;
@@ -5109,6 +5168,7 @@ var GameDestruction = (() => {
5109
5168
  hingeDrop(o, p, src);
5110
5169
  return;
5111
5170
  }
5171
+ if (!force && giveAtCut(o, p, src)) return;
5112
5172
  const ex = p.spec.explodes;
5113
5173
  const style = force ?? (p.snap ? "snap" : p.mat.fracture === "none" ? "snap" : p.mat.fracture);
5114
5174
  const { c, q } = partXf(o, p);
@@ -5455,7 +5515,9 @@ var GameDestruction = (() => {
5455
5515
  const dx = local[0] - p.pos[0];
5456
5516
  const dy = local[1] - p.pos[1];
5457
5517
  const dz = local[2] - p.pos[2];
5458
- if (dx * dx + dy * dy + dz * dz < reach * reach) near.push(p);
5518
+ if (dx * dx + dy * dy + dz * dz >= reach * reach) continue;
5519
+ if (p.spec.anchored && p.spec.structure?.role === "foundation" && distToPart(o, p, point) > BURIED_BLAST_REACH) continue;
5520
+ near.push(p);
5459
5521
  }
5460
5522
  blastProbe.partsTested += o.parts.length;
5461
5523
  blastProbe.partsNear += near.length;