@adatechnology/game-weapons-three 0.10.0 → 0.10.1
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 +278 -64
- package/dist/index.global.js.map +1 -1
- package/package.json +11 -11
package/dist/index.global.js
CHANGED
|
@@ -19681,6 +19681,45 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19681
19681
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
19682
19682
|
};
|
|
19683
19683
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
19684
|
+
var splinterBox = (inp, box5, limit = inp.maxFragments) => {
|
|
19685
|
+
const { rnd: rnd2 } = inp;
|
|
19686
|
+
const dims = box5.s;
|
|
19687
|
+
const [fmin, fmax] = inp.fragmentSize;
|
|
19688
|
+
const g = inp.grain ?? [0, 1, 2].sort((a2, b2) => dims[b2] - dims[a2])[0];
|
|
19689
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== g);
|
|
19690
|
+
const w = Math.max(fmin * 1.5, 0.01);
|
|
19691
|
+
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
19692
|
+
const maxLen = fmax * 4;
|
|
19693
|
+
const cells = bsp(box5, c, [a, b], rnd2);
|
|
19694
|
+
const pieces = [];
|
|
19695
|
+
for (const cell of cells) {
|
|
19696
|
+
const extra = rnd2() < 0.4 ? 1 : 0;
|
|
19697
|
+
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
19698
|
+
for (const p of bsp(cell, k, [g], rnd2)) pieces.push(p);
|
|
19699
|
+
}
|
|
19700
|
+
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] }));
|
|
19701
|
+
};
|
|
19702
|
+
var severAt = (inp, root, at3, gap) => {
|
|
19703
|
+
const dims = root.s;
|
|
19704
|
+
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
19705
|
+
const half = dims[L] / 2;
|
|
19706
|
+
const lo = clamp(at3 - gap / 2, -half, half), hi = clamp(at3 + gap / 2, -half, half);
|
|
19707
|
+
const out = [];
|
|
19708
|
+
const stub = (from, to) => {
|
|
19709
|
+
if (to - from < 0.02) return;
|
|
19710
|
+
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
19711
|
+
c[L] = (from + to) / 2;
|
|
19712
|
+
sz[L] = to - from;
|
|
19713
|
+
out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight: sz[0] * sz[1] * sz[2] });
|
|
19714
|
+
};
|
|
19715
|
+
stub(-half, lo);
|
|
19716
|
+
stub(hi, half);
|
|
19717
|
+
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
19718
|
+
band.c[L] = (lo + hi) / 2;
|
|
19719
|
+
band.s[L] = Math.max(hi - lo, 0.01);
|
|
19720
|
+
for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
19721
|
+
return out;
|
|
19722
|
+
};
|
|
19684
19723
|
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
19685
19724
|
const { dims, rnd: rnd2, maxFragments } = inp;
|
|
19686
19725
|
const layers = clamp(Math.ceil(dims[t] / STACK_LAYER), 2, 4);
|
|
@@ -19719,23 +19758,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19719
19758
|
return out;
|
|
19720
19759
|
}
|
|
19721
19760
|
if (style === "splinter") {
|
|
19722
|
-
|
|
19723
|
-
const
|
|
19724
|
-
const w = Math.max(fmin * 1.5, 0.01);
|
|
19725
|
-
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)));
|
|
19726
|
-
const maxLen = fmax * 4;
|
|
19727
|
-
const cells = bsp(root, c, [a, b], rnd2);
|
|
19728
|
-
const pieces = [];
|
|
19729
|
-
for (const cell of cells) {
|
|
19730
|
-
let list2 = [cell];
|
|
19731
|
-
const extra = rnd2() < 0.4 ? 1 : 0;
|
|
19732
|
-
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
19733
|
-
list2 = bsp(cell, k, [g], rnd2);
|
|
19734
|
-
for (const p of list2) pieces.push(p);
|
|
19735
|
-
}
|
|
19736
|
-
for (const p of pieces.slice(0, maxFragments)) {
|
|
19737
|
-
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] });
|
|
19738
|
-
}
|
|
19761
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
19762
|
+
for (const p of splinterBox(inp, root)) out.push(p);
|
|
19739
19763
|
return out;
|
|
19740
19764
|
}
|
|
19741
19765
|
if (style === "tear") {
|
|
@@ -21723,9 +21747,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21723
21747
|
var BREACH_AREA = 0.25;
|
|
21724
21748
|
var BREACH_BLAST_REACH = 0.12;
|
|
21725
21749
|
var RESIDUAL_CAPACITY = 0.15;
|
|
21750
|
+
var SEVER_BAND = 0.1;
|
|
21751
|
+
var SEVER_ASPECT = 3;
|
|
21752
|
+
var SEVER_BALLISTIC = 2;
|
|
21726
21753
|
var SUPPORT_TOLERANCE = 0.05;
|
|
21727
21754
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
21728
21755
|
var BREACH_GRID_CAP = 4096;
|
|
21756
|
+
var CHIP_ENERGY = 200;
|
|
21757
|
+
var CHIP_SPLASH = 0.5;
|
|
21729
21758
|
var CUT_SLICE = 1;
|
|
21730
21759
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
21731
21760
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -21769,6 +21798,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21769
21798
|
let windCfg = windOpts ? resolveWind(windOpts) : null;
|
|
21770
21799
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
21771
21800
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
21801
|
+
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
21772
21802
|
const rng2 = createRng2(options.seed ?? 1);
|
|
21773
21803
|
const rnd2 = () => rng2.next();
|
|
21774
21804
|
let time = 0;
|
|
@@ -22142,41 +22172,68 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22142
22172
|
markDamaged(p);
|
|
22143
22173
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
22144
22174
|
};
|
|
22175
|
+
const freeSpan = (p, supports) => {
|
|
22176
|
+
if (supports.length === 0) return Infinity;
|
|
22177
|
+
const d = p.dims;
|
|
22178
|
+
const L = [0, 1, 2].sort((a, b) => d[b] - d[a])[0];
|
|
22179
|
+
const spans = supports.map((k) => contactBox(p, k)).map(([lo, hi]) => [lo[L], hi[L]]);
|
|
22180
|
+
let far = 0;
|
|
22181
|
+
for (let i = 0; i <= 16; i++) {
|
|
22182
|
+
const x = (i / 16 - 0.5) * d[L];
|
|
22183
|
+
let near = Infinity;
|
|
22184
|
+
for (const [lo, hi] of spans) near = Math.min(near, Math.max(lo - x, x - hi, 0));
|
|
22185
|
+
far = Math.max(far, near);
|
|
22186
|
+
}
|
|
22187
|
+
return 2 * far;
|
|
22188
|
+
};
|
|
22145
22189
|
const solveStructure = (o) => {
|
|
22146
22190
|
o.maxStress = 0;
|
|
22147
22191
|
if (!o.hasStructure) return;
|
|
22148
22192
|
const parts = o.parts;
|
|
22149
22193
|
const n = parts.length;
|
|
22150
22194
|
const dist2 = new Array(n).fill(-1);
|
|
22151
|
-
const queue = [];
|
|
22152
22195
|
const ok = (i) => parts[i].structural && !isLost(parts[i]);
|
|
22153
22196
|
const isPartition = (i) => parts[i].spec.structure?.role === "partition";
|
|
22154
|
-
|
|
22155
|
-
|
|
22156
|
-
|
|
22157
|
-
|
|
22158
|
-
|
|
22159
|
-
|
|
22160
|
-
if (
|
|
22161
|
-
|
|
22162
|
-
|
|
22163
|
-
|
|
22164
|
-
|
|
22165
|
-
|
|
22166
|
-
|
|
22197
|
+
const out = /* @__PURE__ */ new Set();
|
|
22198
|
+
let queue = [];
|
|
22199
|
+
let lowerOf = /* @__PURE__ */ new Map();
|
|
22200
|
+
for (; ; ) {
|
|
22201
|
+
dist2.fill(-1);
|
|
22202
|
+
queue = [];
|
|
22203
|
+
for (let i = 0; i < n; i++) if (ok(i) && !out.has(i) && parts[i].anchored) {
|
|
22204
|
+
dist2[i] = 0;
|
|
22205
|
+
queue.push(i);
|
|
22206
|
+
}
|
|
22207
|
+
for (let h = 0; h < queue.length; h++) {
|
|
22208
|
+
const s = queue[h];
|
|
22209
|
+
if (isPartition(s)) continue;
|
|
22210
|
+
for (const j of o.byPart.get(parts[s].spec.id)) {
|
|
22211
|
+
if (j.st.open || !j.bears) continue;
|
|
22212
|
+
const r = j.ia === s ? j.ib : j.ia;
|
|
22213
|
+
if (dist2[r] >= 0 || !ok(r) || out.has(r) || restsOn(o, j, r) !== s) continue;
|
|
22214
|
+
dist2[r] = dist2[s] + 1;
|
|
22215
|
+
queue.push(r);
|
|
22216
|
+
}
|
|
22167
22217
|
}
|
|
22168
|
-
|
|
22169
|
-
|
|
22170
|
-
|
|
22171
|
-
|
|
22172
|
-
|
|
22173
|
-
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22218
|
+
lowerOf = /* @__PURE__ */ new Map();
|
|
22219
|
+
let dropped = false;
|
|
22220
|
+
for (const i of queue) {
|
|
22221
|
+
const lower = [];
|
|
22222
|
+
for (const j of o.byPart.get(parts[i].spec.id)) {
|
|
22223
|
+
if (j.st.open || !j.bears) continue;
|
|
22224
|
+
const k = restsOn(o, j, i);
|
|
22225
|
+
if (k >= 0 && dist2[k] >= 0 && dist2[k] < dist2[i] && !isPartition(k)) lower.push(k);
|
|
22226
|
+
}
|
|
22227
|
+
lowerOf.set(i, lower);
|
|
22228
|
+
const max2 = parts[i].spec.structure?.maxSpan;
|
|
22229
|
+
if (max2 !== void 0 && !parts[i].anchored && freeSpan(parts[i], lower.map((k) => parts[k])) > max2) {
|
|
22230
|
+
out.add(i);
|
|
22231
|
+
dropped = true;
|
|
22232
|
+
}
|
|
22177
22233
|
}
|
|
22178
|
-
|
|
22234
|
+
if (!dropped) break;
|
|
22179
22235
|
}
|
|
22236
|
+
const incoming = new Array(n).fill(0);
|
|
22180
22237
|
const bending = new Array(n).fill(0);
|
|
22181
22238
|
const through = parts.map(() => []);
|
|
22182
22239
|
const pass = (k, at3, mass) => {
|
|
@@ -22688,6 +22745,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22688
22745
|
const r = rayPart(o, p, origin, d);
|
|
22689
22746
|
if (!r || r.t0 < 0 || r.t0 > maxDist) continue;
|
|
22690
22747
|
if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue;
|
|
22748
|
+
if (p.st.chipped && insideChip(p, objLocal(o, vec.madd(origin, d, r.t0)))) continue;
|
|
22691
22749
|
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 };
|
|
22692
22750
|
}
|
|
22693
22751
|
}
|
|
@@ -22951,6 +23009,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22951
23009
|
if (total < (p.spec.breach?.area ?? BREACH_AREA)) return;
|
|
22952
23010
|
openBreach(o, p, [sum2[0] / total, sum2[1] / total, sum2[2] / total], total, energy, dir, src);
|
|
22953
23011
|
};
|
|
23012
|
+
const unitGrids = /* @__PURE__ */ new WeakMap();
|
|
23013
|
+
const gridOf = (p) => {
|
|
23014
|
+
let grid = unitGrids.get(p);
|
|
23015
|
+
if (!grid) unitGrids.set(p, grid = unitGrid(p.dims, p.thin, unitsOf2(p), BREACH_GRID_CAP));
|
|
23016
|
+
return grid;
|
|
23017
|
+
};
|
|
23018
|
+
const insideChip = (p, objectPoint) => {
|
|
23019
|
+
const cells = p.st.chipped;
|
|
23020
|
+
if (!cells?.length) return false;
|
|
23021
|
+
const [u, v] = planeAxes(p.thin);
|
|
23022
|
+
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
23023
|
+
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);
|
|
23024
|
+
};
|
|
23025
|
+
const chipUnits = (o, p, wp, energy, dir, radius, src) => {
|
|
23026
|
+
var _a, _b;
|
|
23027
|
+
if (!p.spec.units || p.spec.reinforcement || !p.staged || chipEnergy <= 0 || energy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
23028
|
+
const [u, v] = planeAxes(p.thin);
|
|
23029
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
23030
|
+
const grid = gridOf(p);
|
|
23031
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
23032
|
+
const out = [];
|
|
23033
|
+
for (let i = 0; i < grid.length; i++) {
|
|
23034
|
+
const cell = grid[i];
|
|
23035
|
+
if (worn[i] === -1) continue;
|
|
23036
|
+
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));
|
|
23037
|
+
if (gap > radius) continue;
|
|
23038
|
+
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
23039
|
+
const total = (worn[i] ?? 0) + energy * share;
|
|
23040
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
23041
|
+
if (total < chipEnergy * mass) {
|
|
23042
|
+
worn[i] = total;
|
|
23043
|
+
continue;
|
|
23044
|
+
}
|
|
23045
|
+
worn[i] = -1;
|
|
23046
|
+
out.push(cell);
|
|
23047
|
+
}
|
|
23048
|
+
if (out.length === 0) return;
|
|
23049
|
+
const { c, q } = partXf(o, p);
|
|
23050
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
23051
|
+
const holes = localHolesOf(p);
|
|
23052
|
+
for (const cell of out) {
|
|
23053
|
+
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
23054
|
+
const center = toWorld(c, q, cell.center);
|
|
23055
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
23056
|
+
const fragments = cellFragments(o, p, [cell], wp, dir, speed, mass, `c${chipped.length}_`);
|
|
23057
|
+
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
23058
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
23059
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
23060
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
23061
|
+
markDamaged(p);
|
|
23062
|
+
setStage(o, p, 1, {}, src);
|
|
23063
|
+
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
23064
|
+
debris2(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
23065
|
+
}
|
|
23066
|
+
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
23067
|
+
};
|
|
22954
23068
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
22955
23069
|
const [u, v] = planeAxes(p.thin);
|
|
22956
23070
|
const radius = clamp2(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius);
|
|
@@ -22962,7 +23076,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22962
23076
|
failPart(o, p, worldCenter, dir, energy, 12, src);
|
|
22963
23077
|
return;
|
|
22964
23078
|
}
|
|
22965
|
-
const
|
|
23079
|
+
const worn = p.rt.chips;
|
|
23080
|
+
const cells = cellsWithin(gridOf(p).filter((_, i) => worn?.[i] !== -1), p.thin, lc, radius);
|
|
22966
23081
|
const removed = p.st.mass * cells.reduce((sum2, cell) => sum2 + cell.size[u] * cell.size[v], 0) / (p.dims[u] * p.dims[v]);
|
|
22967
23082
|
const speed = clamp2(Math.sqrt(2 * energy * 0.1 / Math.max(removed, 0.05)), 0.5, 8);
|
|
22968
23083
|
const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, "b");
|
|
@@ -23046,6 +23161,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23046
23161
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
23047
23162
|
const hitLocal = toLocal(c, q, hitW);
|
|
23048
23163
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
23164
|
+
const axis2 = style === "splinter" ? severAxis(p) : -1;
|
|
23165
|
+
const cutAt2 = axis2 < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis2] : void 0);
|
|
23049
23166
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
23050
23167
|
style,
|
|
23051
23168
|
dims: p.dims,
|
|
@@ -23055,7 +23172,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23055
23172
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
23056
23173
|
maxFragments,
|
|
23057
23174
|
rnd: rnd2,
|
|
23058
|
-
sheet: p.mat.sheet
|
|
23175
|
+
sheet: p.mat.sheet,
|
|
23176
|
+
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
23059
23177
|
});
|
|
23060
23178
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
23061
23179
|
const mass = p.st.mass;
|
|
@@ -23114,10 +23232,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23114
23232
|
emit2({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
|
|
23115
23233
|
};
|
|
23116
23234
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
23235
|
+
const severAxis = (p) => {
|
|
23236
|
+
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
23237
|
+
const d = p.dims;
|
|
23238
|
+
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
23239
|
+
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
23240
|
+
};
|
|
23241
|
+
const bandOf = (o, p, axis2, origin) => {
|
|
23242
|
+
const { c, q } = partXf(o, p);
|
|
23243
|
+
const along = toLocal(c, q, origin)[axis2];
|
|
23244
|
+
const L = p.dims[axis2];
|
|
23245
|
+
return clamp2(Math.floor((along + L / 2) / SEVER_BAND), 0, Math.ceil(L / SEVER_BAND) - 1);
|
|
23246
|
+
};
|
|
23117
23247
|
const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
|
|
23248
|
+
var _a;
|
|
23118
23249
|
if (isLost(p) || amount <= 0) return 0;
|
|
23119
23250
|
const prev = p.st.hp;
|
|
23120
23251
|
p.st.hp -= amount;
|
|
23252
|
+
const axis2 = origin && type !== "fire" && type !== "heat" ? severAxis(p) : -1;
|
|
23253
|
+
if (axis2 >= 0 && p.st.hp > 0) {
|
|
23254
|
+
const band = bandOf(o, p, axis2, origin);
|
|
23255
|
+
const cuts = (_a = p.rt).cuts ?? (_a.cuts = {});
|
|
23256
|
+
cuts[band] = (cuts[band] ?? 0) + amount * (type === "ballistic" ? SEVER_BALLISTIC : 1);
|
|
23257
|
+
if (cuts[band] >= p.st.maxHp * SEVER_BAND / p.dims[axis2]) {
|
|
23258
|
+
p.rt.cutAt = -p.dims[axis2] / 2 + (band + 0.5) * SEVER_BAND;
|
|
23259
|
+
p.st.hp = 0;
|
|
23260
|
+
}
|
|
23261
|
+
}
|
|
23121
23262
|
markDamaged(p);
|
|
23122
23263
|
const trigger = CHAIN_TRIGGER_OF[type];
|
|
23123
23264
|
const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
|
|
@@ -23156,7 +23297,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23156
23297
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round5 = {}) => {
|
|
23157
23298
|
const mat = p.mat;
|
|
23158
23299
|
const piercing = round5.piercing ?? 1;
|
|
23159
|
-
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2))) {
|
|
23300
|
+
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2)) || insideChip(p, objLocal(o, entry2))) {
|
|
23160
23301
|
return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry2, d, Math.min(pathLen, p.thickness)), damage: 0 };
|
|
23161
23302
|
}
|
|
23162
23303
|
const sin2 = Math.min(1, Math.abs(vec.dot(d, n)));
|
|
@@ -23215,6 +23356,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23215
23356
|
debris2(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
23216
23357
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
23217
23358
|
const dmg = applyDamage(o, p, E * DMG_PER_J * scale, "ballistic", entry2, d, E * 0.1, 12, src);
|
|
23359
|
+
chipUnits(o, p, entry2, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
|
|
23218
23360
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
23219
23361
|
};
|
|
23220
23362
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -23242,6 +23384,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23242
23384
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
23243
23385
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
23244
23386
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
23387
|
+
if (kind === "blunt") chipUnits(o, p, point, E, d, Math.max(contactR, 0.03), src);
|
|
23245
23388
|
return done;
|
|
23246
23389
|
};
|
|
23247
23390
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -33260,12 +33403,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33260
33403
|
A.invalidate = () => {
|
|
33261
33404
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
33262
33405
|
};
|
|
33263
|
-
A.update = function(
|
|
33406
|
+
A.update = function(houses2, focus, op) {
|
|
33264
33407
|
op = op || {};
|
|
33265
|
-
|
|
33408
|
+
houses2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean);
|
|
33266
33409
|
_f.set(focus.x, focus.y, focus.z);
|
|
33267
33410
|
const rooms = [], exterior = [];
|
|
33268
|
-
for (const house of
|
|
33411
|
+
for (const house of houses2) {
|
|
33269
33412
|
if (house.group && !house.group.visible) continue;
|
|
33270
33413
|
house.house.updateMatrixWorld(true);
|
|
33271
33414
|
const M = house.house.matrixWorld, by = /* @__PURE__ */ new Map();
|
|
@@ -33644,7 +33787,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33644
33787
|
}
|
|
33645
33788
|
return null;
|
|
33646
33789
|
};
|
|
33647
|
-
|
|
33790
|
+
const local2 = (p) => {
|
|
33791
|
+
house.updateMatrixWorld(true);
|
|
33792
|
+
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
33793
|
+
return [v.x, v.y, v.z];
|
|
33794
|
+
};
|
|
33795
|
+
function courses(part, units, opening, chips2, paint2) {
|
|
33648
33796
|
const [u0, v0, u1, v1] = part.aabb;
|
|
33649
33797
|
const alongU = u1 - u0 >= v1 - v0;
|
|
33650
33798
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
@@ -33668,23 +33816,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33668
33816
|
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
33669
33817
|
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
33670
33818
|
const y = part.y0 + (r + 0.5) * rowH;
|
|
33671
|
-
const d = Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]);
|
|
33672
|
-
if (d < opening.radius) continue;
|
|
33673
|
-
|
|
33819
|
+
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
33820
|
+
if (opening && d < opening.radius) continue;
|
|
33821
|
+
const gone = (c) => Math.abs(c[1] - y) <= rowH / 2 && (alongU ? c[0] >= u0 + a && c[0] <= u0 + b : c[2] >= v0 + a && c[2] <= v0 + b);
|
|
33822
|
+
if (chips2.some(gone)) continue;
|
|
33823
|
+
const near = opening && d < opening.radius + 0.25 || chips2.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
33824
|
+
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint2 === null ? edge : paint2 });
|
|
33674
33825
|
}
|
|
33675
33826
|
}
|
|
33676
33827
|
return list2;
|
|
33677
33828
|
}
|
|
33678
|
-
function
|
|
33679
|
-
if (lod !== 0
|
|
33680
|
-
const part = structure.byId.get(
|
|
33681
|
-
const spec = opts.spec()?.parts?.find((q) => q.id ===
|
|
33829
|
+
function draw2(partId, change) {
|
|
33830
|
+
if (lod !== 0) return false;
|
|
33831
|
+
const part = structure.byId.get(partId);
|
|
33832
|
+
const spec = opts.spec()?.parts?.find((q) => q.id === partId);
|
|
33682
33833
|
if (!part || !spec || !spec.units) return false;
|
|
33683
|
-
|
|
33684
|
-
if (!
|
|
33685
|
-
|
|
33834
|
+
let view = views.get(partId);
|
|
33835
|
+
if (!view) {
|
|
33836
|
+
const items = structure.meshesOf(partId).filter((it) => it.mesh);
|
|
33837
|
+
if (!items.length) return false;
|
|
33838
|
+
view = { mesh: null, saved: null, items, paint: wallColour(items), units: 0, opening: null, chips: [] };
|
|
33839
|
+
}
|
|
33840
|
+
if (change.opening) {
|
|
33841
|
+
if (view.opening) return false;
|
|
33842
|
+
view.opening = { center: local2(change.opening.center), radius: change.opening.radius };
|
|
33843
|
+
}
|
|
33844
|
+
if (change.chip) view.chips.push(local2(change.chip));
|
|
33845
|
+
const list2 = courses(part, spec.units, view.opening, view.chips, view.paint);
|
|
33846
|
+
if (view.mesh) {
|
|
33847
|
+
view.mesh.removeFromParent();
|
|
33848
|
+
view.mesh.dispose();
|
|
33849
|
+
}
|
|
33686
33850
|
const mesh3 = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
33687
|
-
mesh3.name = "breach:" +
|
|
33851
|
+
mesh3.name = "breach:" + partId;
|
|
33688
33852
|
list2.forEach((u, i) => {
|
|
33689
33853
|
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
33690
33854
|
mesh3.setMatrixAt(i, tmp.m);
|
|
@@ -33696,8 +33860,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33696
33860
|
mesh3.castShadow = true;
|
|
33697
33861
|
mesh3.receiveShadow = true;
|
|
33698
33862
|
house.add(mesh3);
|
|
33699
|
-
|
|
33700
|
-
|
|
33863
|
+
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
33864
|
+
view.mesh = mesh3;
|
|
33865
|
+
view.units = list2.length;
|
|
33866
|
+
views.set(partId, view);
|
|
33701
33867
|
invalidate();
|
|
33702
33868
|
invalidateShadow();
|
|
33703
33869
|
return true;
|
|
@@ -33711,7 +33877,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33711
33877
|
return {
|
|
33712
33878
|
/** Handles a `stage` event of the house's object. Returns true when the wall was redrawn as courses. */
|
|
33713
33879
|
stage(event) {
|
|
33714
|
-
return event.stage === 2 ?
|
|
33880
|
+
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
33881
|
+
},
|
|
33882
|
+
/** Handles a `chip` event: the unit that came out leaves a gap in the courses. Returns true when the wall was redrawn. */
|
|
33883
|
+
chip(event) {
|
|
33884
|
+
return draw2(event.part, { chip: event.center });
|
|
33715
33885
|
},
|
|
33716
33886
|
/** The part broke or fell: the courses go (the plain range stays collapsed, the renderer hides the part). */
|
|
33717
33887
|
drop(partId) {
|
|
@@ -33941,6 +34111,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33941
34111
|
case "stage":
|
|
33942
34112
|
breach.stage(e);
|
|
33943
34113
|
break;
|
|
34114
|
+
case "chip":
|
|
34115
|
+
breach.chip(e);
|
|
34116
|
+
break;
|
|
33944
34117
|
case "collapse":
|
|
33945
34118
|
for (const id of e.parts) {
|
|
33946
34119
|
breach.drop(id);
|
|
@@ -33995,6 +34168,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33995
34168
|
if (D.active && D.world.has(D.id)) D.world.remove(D.id);
|
|
33996
34169
|
D.active = false;
|
|
33997
34170
|
};
|
|
34171
|
+
D.follow = (world, id, spec) => {
|
|
34172
|
+
D.spec = spec;
|
|
34173
|
+
const offFollow = world.on("*", (e) => {
|
|
34174
|
+
if (e.object !== id) return;
|
|
34175
|
+
switch (e.type) {
|
|
34176
|
+
case "stage":
|
|
34177
|
+
breach.stage(e);
|
|
34178
|
+
break;
|
|
34179
|
+
case "chip":
|
|
34180
|
+
breach.chip(e);
|
|
34181
|
+
break;
|
|
34182
|
+
case "fracture":
|
|
34183
|
+
breach.drop(e.part);
|
|
34184
|
+
break;
|
|
34185
|
+
case "collapse":
|
|
34186
|
+
for (const p of e.parts) breach.drop(p);
|
|
34187
|
+
break;
|
|
34188
|
+
default:
|
|
34189
|
+
break;
|
|
34190
|
+
}
|
|
34191
|
+
});
|
|
34192
|
+
return { restore: () => breach.restore(), dispose: () => {
|
|
34193
|
+
offFollow();
|
|
34194
|
+
breach.restore();
|
|
34195
|
+
} };
|
|
34196
|
+
};
|
|
33998
34197
|
D.piece = (id) => D.active ? D.world.part(D.id, id) : null;
|
|
33999
34198
|
D.state = () => D.active ? D.world.state(D.id) : null;
|
|
34000
34199
|
D.reset = () => {
|
|
@@ -34717,6 +34916,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34717
34916
|
return buildApi(K, shared);
|
|
34718
34917
|
}
|
|
34719
34918
|
var WOOD_THIN = 0.035;
|
|
34919
|
+
var SHELF_SPAN = 1.5;
|
|
34920
|
+
var SHELVING = /shelf|bookcase|rack/;
|
|
34921
|
+
function carcass(parts, drawn) {
|
|
34922
|
+
const all = [...drawn.values()];
|
|
34923
|
+
const width = Math.max(...all.map((p) => p.max[0])) - Math.min(...all.map((p) => p.min[0]));
|
|
34924
|
+
for (const part of parts) {
|
|
34925
|
+
if (LOOSE.has(part.material) || part.shape.kind !== "box" || part.rotation) continue;
|
|
34926
|
+
const [x, y, z] = part.shape.size;
|
|
34927
|
+
if (y >= x && y >= z) {
|
|
34928
|
+
if (z < x && x >= 0.6 * width) continue;
|
|
34929
|
+
part.structure = { role: "column" };
|
|
34930
|
+
} else if (y <= x && y <= z) part.structure = { role: "beam", maxSpan: SHELF_SPAN * Math.max(x, z) };
|
|
34931
|
+
}
|
|
34932
|
+
}
|
|
34720
34933
|
var FLOOR_TOUCH = 5e-3;
|
|
34721
34934
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
34722
34935
|
var BASE_MATERIAL = {
|
|
@@ -34832,6 +35045,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34832
35045
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
34833
35046
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
34834
35047
|
}
|
|
35048
|
+
if (opts.carcass) carcass(parts, byId);
|
|
34835
35049
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
34836
35050
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
34837
35051
|
const build = (T3) => {
|
|
@@ -34875,7 +35089,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34875
35089
|
if (w === void 0 || d === void 0 || h === void 0) throw new Error(`game-floorplan-three: furniture type "${type}" is not in the catalogue, so give w, d and h`);
|
|
34876
35090
|
const o = opts.options ?? {};
|
|
34877
35091
|
const seed = Math.round(opts.seed ?? 1);
|
|
34878
|
-
const plain2 =
|
|
35092
|
+
const plain2 = SHELVING.test(type) ? "paper" : "plastic";
|
|
34879
35093
|
const root = { x: seed, z: 0, ry: 0, w, d, h, y: 0, base: 0, palette: o.palette, seed: `furniture_${type}_${seed}` };
|
|
34880
35094
|
const { K, shared } = renderer.internals;
|
|
34881
35095
|
const before = K.PARTS.length;
|
|
@@ -34894,7 +35108,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34894
35108
|
shared.ctx = saved.ctx;
|
|
34895
35109
|
}
|
|
34896
35110
|
},
|
|
34897
|
-
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs }
|
|
35111
|
+
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs, carcass: SHELVING.test(type) }
|
|
34898
35112
|
);
|
|
34899
35113
|
const spouts = K.PARTS.slice(before).filter((p) => p.type === "water_tap").map((p) => [p.pos[0] - root.x, p.pos[1], p.pos[2] - root.z]);
|
|
34900
35114
|
K.PARTS.length = before;
|