@adatechnology/game-floorplan-structure 1.2.2 → 1.2.3
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.global.js +187 -44
- package/dist/index.global.js.map +1 -1
- package/package.json +5 -5
package/dist/index.global.js
CHANGED
|
@@ -2755,6 +2755,45 @@ var GameFloorplanStructure = (() => {
|
|
|
2755
2755
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
2756
2756
|
};
|
|
2757
2757
|
var clamp3 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
2758
|
+
var splinterBox = (inp, box2, limit = inp.maxFragments) => {
|
|
2759
|
+
const { rnd } = inp;
|
|
2760
|
+
const dims = box2.s;
|
|
2761
|
+
const [fmin, fmax] = inp.fragmentSize;
|
|
2762
|
+
const g = inp.grain ?? [0, 1, 2].sort((a2, b2) => dims[b2] - dims[a2])[0];
|
|
2763
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== g);
|
|
2764
|
+
const w = Math.max(fmin * 1.5, 0.01);
|
|
2765
|
+
const c = clamp3(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
2766
|
+
const maxLen = fmax * 4;
|
|
2767
|
+
const cells = bsp(box2, c, [a, b], rnd);
|
|
2768
|
+
const pieces = [];
|
|
2769
|
+
for (const cell of cells) {
|
|
2770
|
+
const extra = rnd() < 0.4 ? 1 : 0;
|
|
2771
|
+
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
2772
|
+
for (const p of bsp(cell, k, [g], rnd)) pieces.push(p);
|
|
2773
|
+
}
|
|
2774
|
+
return pieces.slice(0, limit).map((p) => ({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] }));
|
|
2775
|
+
};
|
|
2776
|
+
var severAt = (inp, root, at2, gap) => {
|
|
2777
|
+
const dims = root.s;
|
|
2778
|
+
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
2779
|
+
const half = dims[L] / 2;
|
|
2780
|
+
const lo = clamp3(at2 - gap / 2, -half, half), hi = clamp3(at2 + gap / 2, -half, half);
|
|
2781
|
+
const out = [];
|
|
2782
|
+
const stub = (from, to) => {
|
|
2783
|
+
if (to - from < 0.02) return;
|
|
2784
|
+
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
2785
|
+
c[L] = (from + to) / 2;
|
|
2786
|
+
sz[L] = to - from;
|
|
2787
|
+
out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight: sz[0] * sz[1] * sz[2] });
|
|
2788
|
+
};
|
|
2789
|
+
stub(-half, lo);
|
|
2790
|
+
stub(hi, half);
|
|
2791
|
+
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
2792
|
+
band.c[L] = (lo + hi) / 2;
|
|
2793
|
+
band.s[L] = Math.max(hi - lo, 0.01);
|
|
2794
|
+
for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
2795
|
+
return out;
|
|
2796
|
+
};
|
|
2758
2797
|
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
2759
2798
|
const { dims, rnd, maxFragments } = inp;
|
|
2760
2799
|
const layers = clamp3(Math.ceil(dims[t] / STACK_LAYER), 2, 4);
|
|
@@ -2793,23 +2832,8 @@ var GameFloorplanStructure = (() => {
|
|
|
2793
2832
|
return out;
|
|
2794
2833
|
}
|
|
2795
2834
|
if (style === "splinter") {
|
|
2796
|
-
|
|
2797
|
-
const
|
|
2798
|
-
const w = Math.max(fmin * 1.5, 0.01);
|
|
2799
|
-
const c = clamp3(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)));
|
|
2800
|
-
const maxLen = fmax * 4;
|
|
2801
|
-
const cells = bsp(root, c, [a, b], rnd);
|
|
2802
|
-
const pieces = [];
|
|
2803
|
-
for (const cell of cells) {
|
|
2804
|
-
let list = [cell];
|
|
2805
|
-
const extra = rnd() < 0.4 ? 1 : 0;
|
|
2806
|
-
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
2807
|
-
list = bsp(cell, k, [g], rnd);
|
|
2808
|
-
for (const p of list) pieces.push(p);
|
|
2809
|
-
}
|
|
2810
|
-
for (const p of pieces.slice(0, maxFragments)) {
|
|
2811
|
-
out.push({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] });
|
|
2812
|
-
}
|
|
2835
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
2836
|
+
for (const p of splinterBox(inp, root)) out.push(p);
|
|
2813
2837
|
return out;
|
|
2814
2838
|
}
|
|
2815
2839
|
if (style === "tear") {
|
|
@@ -4797,9 +4821,14 @@ var GameFloorplanStructure = (() => {
|
|
|
4797
4821
|
var BREACH_AREA = 0.25;
|
|
4798
4822
|
var BREACH_BLAST_REACH = 0.12;
|
|
4799
4823
|
var RESIDUAL_CAPACITY = 0.15;
|
|
4824
|
+
var SEVER_BAND = 0.1;
|
|
4825
|
+
var SEVER_ASPECT = 3;
|
|
4826
|
+
var SEVER_BALLISTIC = 2;
|
|
4800
4827
|
var SUPPORT_TOLERANCE = 0.05;
|
|
4801
4828
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
4802
4829
|
var BREACH_GRID_CAP = 4096;
|
|
4830
|
+
var CHIP_ENERGY = 200;
|
|
4831
|
+
var CHIP_SPLASH = 0.5;
|
|
4803
4832
|
var CUT_SLICE = 1;
|
|
4804
4833
|
var cutFactorOf = (shape) => clamp22(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
4805
4834
|
var clamp22 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -4843,6 +4872,7 @@ var GameFloorplanStructure = (() => {
|
|
|
4843
4872
|
let windCfg = windOpts ? resolveWind(windOpts) : null;
|
|
4844
4873
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
4845
4874
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
4875
|
+
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
4846
4876
|
const rng = createRng(options.seed ?? 1);
|
|
4847
4877
|
const rnd = () => rng.next();
|
|
4848
4878
|
let time = 0;
|
|
@@ -5216,41 +5246,68 @@ var GameFloorplanStructure = (() => {
|
|
|
5216
5246
|
markDamaged(p);
|
|
5217
5247
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
5218
5248
|
};
|
|
5249
|
+
const freeSpan = (p, supports) => {
|
|
5250
|
+
if (supports.length === 0) return Infinity;
|
|
5251
|
+
const d = p.dims;
|
|
5252
|
+
const L = [0, 1, 2].sort((a, b) => d[b] - d[a])[0];
|
|
5253
|
+
const spans = supports.map((k) => contactBox(p, k)).map(([lo, hi]) => [lo[L], hi[L]]);
|
|
5254
|
+
let far = 0;
|
|
5255
|
+
for (let i = 0; i <= 16; i++) {
|
|
5256
|
+
const x = (i / 16 - 0.5) * d[L];
|
|
5257
|
+
let near = Infinity;
|
|
5258
|
+
for (const [lo, hi] of spans) near = Math.min(near, Math.max(lo - x, x - hi, 0));
|
|
5259
|
+
far = Math.max(far, near);
|
|
5260
|
+
}
|
|
5261
|
+
return 2 * far;
|
|
5262
|
+
};
|
|
5219
5263
|
const solveStructure = (o) => {
|
|
5220
5264
|
o.maxStress = 0;
|
|
5221
5265
|
if (!o.hasStructure) return;
|
|
5222
5266
|
const parts = o.parts;
|
|
5223
5267
|
const n = parts.length;
|
|
5224
5268
|
const dist = new Array(n).fill(-1);
|
|
5225
|
-
const queue = [];
|
|
5226
5269
|
const ok = (i) => parts[i].structural && !isLost(parts[i]);
|
|
5227
5270
|
const isPartition = (i) => parts[i].spec.structure?.role === "partition";
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
if (
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
const r = j.ia === s ? j.ib : j.ia;
|
|
5238
|
-
if (dist[r] >= 0 || !ok(r) || restsOn(o, j, r) !== s) continue;
|
|
5239
|
-
dist[r] = dist[s] + 1;
|
|
5240
|
-
queue.push(r);
|
|
5271
|
+
const out = /* @__PURE__ */ new Set();
|
|
5272
|
+
let queue = [];
|
|
5273
|
+
let lowerOf = /* @__PURE__ */ new Map();
|
|
5274
|
+
for (; ; ) {
|
|
5275
|
+
dist.fill(-1);
|
|
5276
|
+
queue = [];
|
|
5277
|
+
for (let i = 0; i < n; i++) if (ok(i) && !out.has(i) && parts[i].anchored) {
|
|
5278
|
+
dist[i] = 0;
|
|
5279
|
+
queue.push(i);
|
|
5241
5280
|
}
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5281
|
+
for (let h = 0; h < queue.length; h++) {
|
|
5282
|
+
const s = queue[h];
|
|
5283
|
+
if (isPartition(s)) continue;
|
|
5284
|
+
for (const j of o.byPart.get(parts[s].spec.id)) {
|
|
5285
|
+
if (j.st.open || !j.bears) continue;
|
|
5286
|
+
const r = j.ia === s ? j.ib : j.ia;
|
|
5287
|
+
if (dist[r] >= 0 || !ok(r) || out.has(r) || restsOn(o, j, r) !== s) continue;
|
|
5288
|
+
dist[r] = dist[s] + 1;
|
|
5289
|
+
queue.push(r);
|
|
5290
|
+
}
|
|
5251
5291
|
}
|
|
5252
|
-
lowerOf
|
|
5292
|
+
lowerOf = /* @__PURE__ */ new Map();
|
|
5293
|
+
let dropped = false;
|
|
5294
|
+
for (const i of queue) {
|
|
5295
|
+
const lower = [];
|
|
5296
|
+
for (const j of o.byPart.get(parts[i].spec.id)) {
|
|
5297
|
+
if (j.st.open || !j.bears) continue;
|
|
5298
|
+
const k = restsOn(o, j, i);
|
|
5299
|
+
if (k >= 0 && dist[k] >= 0 && dist[k] < dist[i] && !isPartition(k)) lower.push(k);
|
|
5300
|
+
}
|
|
5301
|
+
lowerOf.set(i, lower);
|
|
5302
|
+
const max = parts[i].spec.structure?.maxSpan;
|
|
5303
|
+
if (max !== void 0 && !parts[i].anchored && freeSpan(parts[i], lower.map((k) => parts[k])) > max) {
|
|
5304
|
+
out.add(i);
|
|
5305
|
+
dropped = true;
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
if (!dropped) break;
|
|
5253
5309
|
}
|
|
5310
|
+
const incoming = new Array(n).fill(0);
|
|
5254
5311
|
const bending = new Array(n).fill(0);
|
|
5255
5312
|
const through = parts.map(() => []);
|
|
5256
5313
|
const pass = (k, at2, mass) => {
|
|
@@ -5762,6 +5819,7 @@ var GameFloorplanStructure = (() => {
|
|
|
5762
5819
|
const r = rayPart(o, p, origin, d);
|
|
5763
5820
|
if (!r || r.t0 < 0 || r.t0 > maxDist) continue;
|
|
5764
5821
|
if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue;
|
|
5822
|
+
if (p.st.chipped && insideChip(p, objLocal(o, vec.madd(origin, d, r.t0)))) continue;
|
|
5765
5823
|
if (!best || r.t0 < best.distance) best = { object: o.id, part: p.spec.id, point: vec.madd(origin, d, r.t0), normal: r.n, distance: r.t0, pathLen: r.t1 - r.t0 };
|
|
5766
5824
|
}
|
|
5767
5825
|
}
|
|
@@ -6025,6 +6083,62 @@ var GameFloorplanStructure = (() => {
|
|
|
6025
6083
|
if (total < (p.spec.breach?.area ?? BREACH_AREA)) return;
|
|
6026
6084
|
openBreach(o, p, [sum[0] / total, sum[1] / total, sum[2] / total], total, energy, dir, src);
|
|
6027
6085
|
};
|
|
6086
|
+
const unitGrids = /* @__PURE__ */ new WeakMap();
|
|
6087
|
+
const gridOf = (p) => {
|
|
6088
|
+
let grid = unitGrids.get(p);
|
|
6089
|
+
if (!grid) unitGrids.set(p, grid = unitGrid(p.dims, p.thin, unitsOf2(p), BREACH_GRID_CAP));
|
|
6090
|
+
return grid;
|
|
6091
|
+
};
|
|
6092
|
+
const insideChip = (p, objectPoint) => {
|
|
6093
|
+
const cells = p.st.chipped;
|
|
6094
|
+
if (!cells?.length) return false;
|
|
6095
|
+
const [u, v] = planeAxes(p.thin);
|
|
6096
|
+
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
6097
|
+
return cells.some((c) => Math.abs(lp[u] - c.center[u]) <= c.size[u] / 2 && Math.abs(lp[v] - c.center[v]) <= c.size[v] / 2);
|
|
6098
|
+
};
|
|
6099
|
+
const chipUnits = (o, p, wp, energy, dir, radius, src) => {
|
|
6100
|
+
var _a, _b;
|
|
6101
|
+
if (!p.spec.units || p.spec.reinforcement || !p.staged || chipEnergy <= 0 || energy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
6102
|
+
const [u, v] = planeAxes(p.thin);
|
|
6103
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
6104
|
+
const grid = gridOf(p);
|
|
6105
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
6106
|
+
const out = [];
|
|
6107
|
+
for (let i = 0; i < grid.length; i++) {
|
|
6108
|
+
const cell = grid[i];
|
|
6109
|
+
if (worn[i] === -1) continue;
|
|
6110
|
+
const gap = Math.hypot(Math.max(0, Math.abs(lp[u] - cell.center[u]) - cell.size[u] / 2), Math.max(0, Math.abs(lp[v] - cell.center[v]) - cell.size[v] / 2));
|
|
6111
|
+
if (gap > radius) continue;
|
|
6112
|
+
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
6113
|
+
const total = (worn[i] ?? 0) + energy * share;
|
|
6114
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
6115
|
+
if (total < chipEnergy * mass) {
|
|
6116
|
+
worn[i] = total;
|
|
6117
|
+
continue;
|
|
6118
|
+
}
|
|
6119
|
+
worn[i] = -1;
|
|
6120
|
+
out.push(cell);
|
|
6121
|
+
}
|
|
6122
|
+
if (out.length === 0) return;
|
|
6123
|
+
const { c, q } = partXf(o, p);
|
|
6124
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
6125
|
+
const holes = localHolesOf(p);
|
|
6126
|
+
for (const cell of out) {
|
|
6127
|
+
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
6128
|
+
const center = toWorld(c, q, cell.center);
|
|
6129
|
+
const speed = clamp22(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
6130
|
+
const fragments = cellFragments(o, p, [cell], wp, dir, speed, mass, `c${chipped.length}_`);
|
|
6131
|
+
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
6132
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
6133
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
6134
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
6135
|
+
markDamaged(p);
|
|
6136
|
+
setStage(o, p, 1, {}, src);
|
|
6137
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
6138
|
+
debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
6139
|
+
}
|
|
6140
|
+
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
6141
|
+
};
|
|
6028
6142
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
6029
6143
|
const [u, v] = planeAxes(p.thin);
|
|
6030
6144
|
const radius = clamp22(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius);
|
|
@@ -6036,7 +6150,8 @@ var GameFloorplanStructure = (() => {
|
|
|
6036
6150
|
failPart(o, p, worldCenter, dir, energy, 12, src);
|
|
6037
6151
|
return;
|
|
6038
6152
|
}
|
|
6039
|
-
const
|
|
6153
|
+
const worn = p.rt.chips;
|
|
6154
|
+
const cells = cellsWithin(gridOf(p).filter((_, i) => worn?.[i] !== -1), p.thin, lc, radius);
|
|
6040
6155
|
const removed = p.st.mass * cells.reduce((sum, cell) => sum + cell.size[u] * cell.size[v], 0) / (p.dims[u] * p.dims[v]);
|
|
6041
6156
|
const speed = clamp22(Math.sqrt(2 * energy * 0.1 / Math.max(removed, 0.05)), 0.5, 8);
|
|
6042
6157
|
const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, "b");
|
|
@@ -6120,6 +6235,8 @@ var GameFloorplanStructure = (() => {
|
|
|
6120
6235
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
6121
6236
|
const hitLocal = toLocal(c, q, hitW);
|
|
6122
6237
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
6238
|
+
const axis = style === "splinter" ? severAxis(p) : -1;
|
|
6239
|
+
const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
|
|
6123
6240
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
6124
6241
|
style,
|
|
6125
6242
|
dims: p.dims,
|
|
@@ -6129,7 +6246,8 @@ var GameFloorplanStructure = (() => {
|
|
|
6129
6246
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
6130
6247
|
maxFragments,
|
|
6131
6248
|
rnd,
|
|
6132
|
-
sheet: p.mat.sheet
|
|
6249
|
+
sheet: p.mat.sheet,
|
|
6250
|
+
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
6133
6251
|
});
|
|
6134
6252
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
6135
6253
|
const mass = p.st.mass;
|
|
@@ -6188,10 +6306,33 @@ var GameFloorplanStructure = (() => {
|
|
|
6188
6306
|
emit({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
|
|
6189
6307
|
};
|
|
6190
6308
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
6309
|
+
const severAxis = (p) => {
|
|
6310
|
+
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
6311
|
+
const d = p.dims;
|
|
6312
|
+
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
6313
|
+
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
6314
|
+
};
|
|
6315
|
+
const bandOf = (o, p, axis, origin) => {
|
|
6316
|
+
const { c, q } = partXf(o, p);
|
|
6317
|
+
const along = toLocal(c, q, origin)[axis];
|
|
6318
|
+
const L = p.dims[axis];
|
|
6319
|
+
return clamp22(Math.floor((along + L / 2) / SEVER_BAND), 0, Math.ceil(L / SEVER_BAND) - 1);
|
|
6320
|
+
};
|
|
6191
6321
|
const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
|
|
6322
|
+
var _a;
|
|
6192
6323
|
if (isLost(p) || amount <= 0) return 0;
|
|
6193
6324
|
const prev = p.st.hp;
|
|
6194
6325
|
p.st.hp -= amount;
|
|
6326
|
+
const axis = origin && type !== "fire" && type !== "heat" ? severAxis(p) : -1;
|
|
6327
|
+
if (axis >= 0 && p.st.hp > 0) {
|
|
6328
|
+
const band = bandOf(o, p, axis, origin);
|
|
6329
|
+
const cuts = (_a = p.rt).cuts ?? (_a.cuts = {});
|
|
6330
|
+
cuts[band] = (cuts[band] ?? 0) + amount * (type === "ballistic" ? SEVER_BALLISTIC : 1);
|
|
6331
|
+
if (cuts[band] >= p.st.maxHp * SEVER_BAND / p.dims[axis]) {
|
|
6332
|
+
p.rt.cutAt = -p.dims[axis] / 2 + (band + 0.5) * SEVER_BAND;
|
|
6333
|
+
p.st.hp = 0;
|
|
6334
|
+
}
|
|
6335
|
+
}
|
|
6195
6336
|
markDamaged(p);
|
|
6196
6337
|
const trigger = CHAIN_TRIGGER_OF[type];
|
|
6197
6338
|
const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
|
|
@@ -6230,7 +6371,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6230
6371
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round3 = {}) => {
|
|
6231
6372
|
const mat = p.mat;
|
|
6232
6373
|
const piercing = round3.piercing ?? 1;
|
|
6233
|
-
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2))) {
|
|
6374
|
+
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2)) || insideChip(p, objLocal(o, entry2))) {
|
|
6234
6375
|
return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry2, d, Math.min(pathLen, p.thickness)), damage: 0 };
|
|
6235
6376
|
}
|
|
6236
6377
|
const sin = Math.min(1, Math.abs(vec.dot(d, n)));
|
|
@@ -6289,6 +6430,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6289
6430
|
debris(o, p, mat.hitDebris, entry2, n, clamp22(Math.round(E / 60) + 2, 2, 14), clamp22(Math.sqrt(E) / 6, 1, 8), src);
|
|
6290
6431
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
6291
6432
|
const dmg = applyDamage(o, p, E * DMG_PER_J * scale, "ballistic", entry2, d, E * 0.1, 12, src);
|
|
6433
|
+
chipUnits(o, p, entry2, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
|
|
6292
6434
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
6293
6435
|
};
|
|
6294
6436
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -6316,6 +6458,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6316
6458
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
6317
6459
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
6318
6460
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
6461
|
+
if (kind === "blunt") chipUnits(o, p, point, E, d, Math.max(contactR, 0.03), src);
|
|
6319
6462
|
return done;
|
|
6320
6463
|
};
|
|
6321
6464
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|