@adatechnology/game-destruction 0.19.0 → 0.20.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.
@@ -3068,6 +3068,26 @@ var GameDestruction = (() => {
3068
3068
 
3069
3069
  // ../game-contracts/dist/index.js
3070
3070
  var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
3071
+ var NEAREST = 0.3;
3072
+ function sideOnImpulse(tnt, distance) {
3073
+ if (!(tnt > 0)) return 0;
3074
+ const w3 = Math.cbrt(tnt);
3075
+ const z = Math.max(distance, NEAREST) / w3;
3076
+ const scaled = 0.067 * Math.sqrt(1 + (z / 0.23) ** 4) / (z * z * Math.cbrt(1 + (z / 1.55) ** 3));
3077
+ return scaled * w3 * 100;
3078
+ }
3079
+ var ATMOSPHERE = 101325;
3080
+ function sideOnOverpressure(tnt, distance) {
3081
+ if (!(tnt > 0)) return 0;
3082
+ const z = Math.max(distance, NEAREST) / Math.cbrt(tnt);
3083
+ const ratio = 808 * (1 + (z / 4.5) ** 2) / (Math.sqrt(1 + (z / 0.048) ** 2) * Math.sqrt(1 + (z / 0.32) ** 2) * Math.sqrt(1 + (z / 1.35) ** 2));
3084
+ return ratio * ATMOSPHERE;
3085
+ }
3086
+ function bodyImpulse(tnt, distance) {
3087
+ if (!(tnt > 0)) return 0;
3088
+ const z = Math.max(distance, NEAREST) / Math.cbrt(tnt);
3089
+ return sideOnImpulse(tnt, distance) * (2 + 4 / (1 + z * z));
3090
+ }
3071
3091
  var DEFAULT_COST_READS = 1e4;
3072
3092
  var DEFAULT_COST_CEILING_MS = 50;
3073
3093
  var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
@@ -3389,9 +3409,15 @@ var GameDestruction = (() => {
3389
3409
  var BREACH_AREA = 0.25;
3390
3410
  var BREACH_BLAST_REACH = 0.12;
3391
3411
  var MEMBER_CUT_REACH = 0.5;
3412
+ var FAR_MEMBER_HP_FLOOR = 0.25;
3392
3413
  var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
3393
3414
  var BLAST_EDGE_RAGGED = 0.3;
3394
3415
  var BLAST_EDGE_LOOSE = 1.35;
3416
+ var PANEL_PRESSURE = 7e4;
3417
+ var PANEL_IMPULSE = 150;
3418
+ var PANEL_PI = 6e6;
3419
+ var PANEL_POINTS = [[0, 0], [-0.3, 0], [0.3, 0], [0, -0.3], [0, 0.3]];
3420
+ var PANEL_POINTS_LOADED = 4;
3395
3421
  var BLAST_EDGE_WEAR = 0.6;
3396
3422
  var RESIDUAL_CAPACITY = 0.15;
3397
3423
  var SEVER_BAND = 0.1;
@@ -4985,7 +5011,7 @@ var GameDestruction = (() => {
4985
5011
  return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
4986
5012
  };
4987
5013
  const blastUnits = (o, p, wp, energy, dist, src) => {
4988
- var _a, _b;
5014
+ var _a;
4989
5015
  if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
4990
5016
  const reach = blastReachOf(p, energy);
4991
5017
  if (dist >= reach) return false;
@@ -5015,6 +5041,62 @@ var GameDestruction = (() => {
5015
5041
  }
5016
5042
  }
5017
5043
  if (out.length === 0) return false;
5044
+ return knockOutUnits(o, p, wp, energy, out, src);
5045
+ };
5046
+ const blastPanel = (o, p, point, energy, src) => {
5047
+ var _a;
5048
+ if (!p.staged || p.st.stripped || isLost(p) || !p.spec.units || p.spec.units.mortar === p.spec.material || p.spec.reinforcement) return false;
5049
+ const [u, v] = planeAxes(p.thin);
5050
+ const lp = toLocal(p.pos, p.q, objLocal(o, point));
5051
+ const half = p.dims[u] / 2;
5052
+ const posts = [];
5053
+ for (const m of o.parts) {
5054
+ if (m === p || !m.spec.reinforcement || isLost(m) || m.spec.shape.kind !== "box") continue;
5055
+ const mp = toLocal(p.pos, p.q, m.pos);
5056
+ if (Math.abs(mp[p.thin]) > p.dims[p.thin] + 0.15 || Math.abs(mp[u]) > half + 0.15 || m.dims[v] < p.dims[v] * 0.5) continue;
5057
+ posts.push(mp[u]);
5058
+ }
5059
+ let from = -half, to = half;
5060
+ for (const x of posts) {
5061
+ if (x <= lp[u] && x > from) from = x;
5062
+ if (x >= lp[u] && x < to) to = x;
5063
+ }
5064
+ if (to - from < 0.2) return false;
5065
+ const tnt = energy * DEFAULT_BLAST_IMPULSE.tntPerJoule;
5066
+ const centre = objLocal(o, point);
5067
+ const span = to - from, height = p.dims[v];
5068
+ let loaded = 0;
5069
+ for (const [fu, fv] of PANEL_POINTS) {
5070
+ const at = [0, 0, 0];
5071
+ at[u] = (from + to) / 2 + fu * span;
5072
+ at[v] = fv * height;
5073
+ at[p.thin] = Math.sign(lp[p.thin]) * p.dims[p.thin] / 2;
5074
+ const r = vec.distance(toWorld(p.pos, p.q, at), centre);
5075
+ const side = sideOnOverpressure(tnt, r);
5076
+ const reflected = 2 * side + 6 * side * side / (side + 7 * 101325);
5077
+ const impulse = bodyImpulse(tnt, r);
5078
+ if (reflected > PANEL_PRESSURE && impulse > PANEL_IMPULSE && (reflected - PANEL_PRESSURE) * (impulse - PANEL_IMPULSE) >= PANEL_PI) loaded++;
5079
+ }
5080
+ if (loaded < PANEL_POINTS_LOADED) return false;
5081
+ const grid = gridOf(p);
5082
+ const worn = (_a = p.rt).chips ?? (_a.chips = {});
5083
+ const out = [];
5084
+ for (let i = 0; i < grid.length; i++) {
5085
+ const cell = grid[i];
5086
+ if (worn[i] === -1) continue;
5087
+ if (cell.center[u] - cell.size[u] / 2 >= from - 1e-6 && cell.center[u] + cell.size[u] / 2 <= to + 1e-6) out.push(i);
5088
+ }
5089
+ if (out.length === 0) return false;
5090
+ for (const i of out) worn[i] = -1;
5091
+ return knockOutUnits(o, p, point, energy, out, src);
5092
+ };
5093
+ const knockOutUnits = (o, p, wp, energy, out, src) => {
5094
+ var _a, _b;
5095
+ const [u, v] = planeAxes(p.thin);
5096
+ const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
5097
+ const grid = gridOf(p);
5098
+ const worn = (_a = p.rt).chips ?? (_a.chips = {});
5099
+ for (const i of out) worn[i] = -1;
5018
5100
  const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
5019
5101
  for (const i of loose) worn[i] = -1;
5020
5102
  const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
@@ -5497,12 +5579,15 @@ var GameDestruction = (() => {
5497
5579
  return reach;
5498
5580
  }
5499
5581
  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);
5500
- const dealt = applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
5582
+ const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
5583
+ const farMember = Boolean(p.spec.reinforcement && p.spec.units) && dist > MEMBER_CUT_REACH * breachReach;
5584
+ const dealt = farMember ? applyDamage(o, p, Math.min(amount, Math.max(0, p.st.hp - p.st.maxHp * FAR_MEMBER_HP_FLOOR)), "explosive", null, null, Ein * 0.3, 40, src) : applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
5501
5585
  res.damage += dealt;
5502
5586
  if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
5503
- const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
5504
- if (p.spec.units && p.spec.units.mortar !== p.spec.material) blastUnits(o, p, wp, energy, dist, src);
5505
- else if (p.spec.reinforcement && p.spec.units && dist > MEMBER_CUT_REACH * breachReach) blastUnits(o, p, wp, energy, dist, src);
5587
+ if (p.spec.units && p.spec.units.mortar !== p.spec.material) {
5588
+ blastPanel(o, p, point, energy, src);
5589
+ if (!isLost(p)) blastUnits(o, p, wp, energy, dist, src);
5590
+ } else if (farMember) blastUnits(o, p, wp, energy, dist, src);
5506
5591
  else if (dist <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
5507
5592
  return reach;
5508
5593
  };