@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.
package/dist/index.js CHANGED
@@ -3024,23 +3024,42 @@ var penetrationOf = (mat, table) => {
3024
3024
  const v = table[mat.penetrationClass ?? mat.id] ?? table[mat.id];
3025
3025
  return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
3026
3026
  };
3027
- var capacityScale = (p) => {
3027
+ var BURIED_BLAST_REACH = 0.5;
3028
+ var GIVE_AT_CUT_HP = 0.5;
3029
+ var capacityScale = (p, borne, through) => {
3028
3030
  const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
3029
3031
  if (p.st.stripped) return residual;
3030
- const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, 1 - sectionLoss(p));
3032
+ const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, sectionKept(p, residual, borne, through));
3031
3033
  return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
3032
3034
  };
3033
- var sectionLoss = (p) => {
3035
+ var sectionKept = (p, residual, borne, through) => {
3036
+ let kept = 1;
3037
+ forEachSection(p, borne, (c, along, gone) => {
3038
+ const share = through?.(c.center, along) ?? 1;
3039
+ if (share <= 0) return;
3040
+ kept = Math.min(kept, Math.max(p.spec.reinforcement ? residual : 0, 1 - gone) / share);
3041
+ });
3042
+ return kept;
3043
+ };
3044
+ var sectionLoss = (p, borne) => {
3045
+ let worst = 0;
3046
+ forEachSection(p, borne, (_c, _along, gone) => {
3047
+ worst = Math.max(worst, gone);
3048
+ });
3049
+ return Math.min(1, worst);
3050
+ };
3051
+ var forEachSection = (p, borne, visit) => {
3034
3052
  const cells = p.st.chipped;
3035
- if (!cells?.length) return 0;
3053
+ if (!cells?.length) return;
3036
3054
  const [u, v] = planeAxes(p.thin);
3037
3055
  const role = p.spec.structure?.role;
3038
3056
  const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
3039
3057
  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;
3040
3058
  const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
3041
3059
  const across = along === u ? v : u;
3042
- let worst = 0;
3060
+ const lying = along !== upright || upright < 0;
3043
3061
  for (const c of cells) {
3062
+ if (lying && borne?.(c.center, along)) continue;
3044
3063
  const spans = [];
3045
3064
  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]);
3046
3065
  spans.sort((a, b) => a[0] - b[0]);
@@ -3050,9 +3069,8 @@ var sectionLoss = (p) => {
3050
3069
  gone += b - Math.max(a, end);
3051
3070
  end = b;
3052
3071
  }
3053
- worst = Math.max(worst, gone / Math.max(p.dims[across], 1e-6));
3072
+ visit(c, along, Math.min(1, gone / Math.max(p.dims[across], 1e-6)));
3054
3073
  }
3055
- return Math.min(1, worst);
3056
3074
  };
3057
3075
  var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
3058
3076
  var clone = (v) => structuredClone(v);
@@ -3363,6 +3381,26 @@ var createDestruction = (options = {}) => {
3363
3381
  byTouching.set(support, { version: poseVersion, box });
3364
3382
  return box;
3365
3383
  };
3384
+ const throughOf = (p) => {
3385
+ const load = p.st.load ?? 0;
3386
+ if (load <= 0) return void 0;
3387
+ const above = Math.max(0, load - p.st.mass);
3388
+ const up = rotateVec(p.q, [0, 1, 0]);
3389
+ return (local, along) => {
3390
+ const axis = [0, 0, 0];
3391
+ axis[along] = 1;
3392
+ const sign = Math.sign(rotateVec(p.q, axis)[1]);
3393
+ if (Math.abs(up[1]) < 0.7 && Math.abs(rotateVec(p.q, axis)[1]) < 0.7) return 1;
3394
+ const half = p.dims[along] / 2;
3395
+ const share = clamp2((half - sign * local[along]) / Math.max(p.dims[along], 1e-6), 0, 1);
3396
+ return (above + p.st.mass * share) / load;
3397
+ };
3398
+ };
3399
+ const borneOn = (p, supports) => {
3400
+ if (supports.length === 0) return void 0;
3401
+ const boxes = supports.map((support) => contactBox(p, support));
3402
+ return (local, along) => boxes.some(([lo, hi]) => local[along] >= lo[along] - SUPPORT_TOLERANCE && local[along] <= hi[along] + SUPPORT_TOLERANCE);
3403
+ };
3366
3404
  const measureContact = (p, support) => {
3367
3405
  const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
3368
3406
  const lo = [0, 0, 0], hi = [0, 0, 0];
@@ -3570,7 +3608,7 @@ var createDestruction = (options = {}) => {
3570
3608
  o.unsup[i] = o.anyAnchor && !isLost(p) && !p.orphan;
3571
3609
  continue;
3572
3610
  }
3573
- p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p));
3611
+ p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p, borneOn(p, (lowerOf.get(i) ?? []).map((k) => parts[k])), throughOf(p)));
3574
3612
  if (p.bend) {
3575
3613
  p.bendLoad = p.st.mass + bending[i];
3576
3614
  const bent = restFlexure(o, p, lowerOf.get(i) ?? []);
@@ -4660,6 +4698,27 @@ var createDestruction = (options = {}) => {
4660
4698
  debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
4661
4699
  return loose.length;
4662
4700
  };
4701
+ const giveAtCut = (o, p, src) => {
4702
+ if (!p.spec.reinforcement || !p.spec.units || !p.st.chipped?.length || sectionLoss(p) <= 0) return false;
4703
+ const opened = [];
4704
+ for (const j of o.byPart.get(p.spec.id) ?? []) {
4705
+ if (j.st.open) continue;
4706
+ const onIt = j.bears === "a_on_b" && j.spec.b === p.spec.id || j.bears === "b_on_a" && j.spec.a === p.spec.id;
4707
+ if (!onIt) continue;
4708
+ j.st.open = true;
4709
+ j.st.openedBy = "break";
4710
+ opened.push(j);
4711
+ }
4712
+ if (opened.length === 0) return false;
4713
+ p.st.hp = Math.max(p.st.hp, p.st.maxHp * GIVE_AT_CUT_HP);
4714
+ markDamaged(p);
4715
+ solveStructure(o);
4716
+ recomputeGroups(o);
4717
+ detachEvents(o, opened, "break", src);
4718
+ exposeRebar(o, p, src);
4719
+ collapseCheck(o, src);
4720
+ return true;
4721
+ };
4663
4722
  const stripPart = (o, p, reinforcement, src) => {
4664
4723
  const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
4665
4724
  p.st.stripped = true;
@@ -4717,6 +4776,7 @@ var createDestruction = (options = {}) => {
4717
4776
  hingeDrop(o, p, src);
4718
4777
  return;
4719
4778
  }
4779
+ if (!force && giveAtCut(o, p, src)) return;
4720
4780
  const ex = p.spec.explodes;
4721
4781
  const style = force ?? (p.snap ? "snap" : p.mat.fracture === "none" ? "snap" : p.mat.fracture);
4722
4782
  const { c, q } = partXf(o, p);
@@ -5063,7 +5123,9 @@ var createDestruction = (options = {}) => {
5063
5123
  const dx = local[0] - p.pos[0];
5064
5124
  const dy = local[1] - p.pos[1];
5065
5125
  const dz = local[2] - p.pos[2];
5066
- if (dx * dx + dy * dy + dz * dz < reach * reach) near.push(p);
5126
+ if (dx * dx + dy * dy + dz * dz >= reach * reach) continue;
5127
+ if (p.spec.anchored && p.spec.structure?.role === "foundation" && distToPart(o, p, point) > BURIED_BLAST_REACH) continue;
5128
+ near.push(p);
5067
5129
  }
5068
5130
  blastProbe.partsTested += o.parts.length;
5069
5131
  blastProbe.partsNear += near.length;