@adatechnology/game-items-three 0.3.0 → 0.3.2
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 +303 -66
- package/dist/index.global.js.map +1 -1
- package/package.json +8 -8
package/dist/index.global.js
CHANGED
|
@@ -12694,6 +12694,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12694
12694
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
12695
12695
|
};
|
|
12696
12696
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
12697
|
+
var splinterBox = (inp, box4, limit = inp.maxFragments) => {
|
|
12698
|
+
const { rnd } = inp;
|
|
12699
|
+
const dims = box4.s;
|
|
12700
|
+
const [fmin, fmax] = inp.fragmentSize;
|
|
12701
|
+
const g = inp.grain ?? [0, 1, 2].sort((a2, b2) => dims[b2] - dims[a2])[0];
|
|
12702
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== g);
|
|
12703
|
+
const w = Math.max(fmin * 1.5, 0.01);
|
|
12704
|
+
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
12705
|
+
const maxLen = fmax * 4;
|
|
12706
|
+
const cells = bsp(box4, c, [a, b], rnd);
|
|
12707
|
+
const pieces = [];
|
|
12708
|
+
for (const cell of cells) {
|
|
12709
|
+
const extra = rnd() < 0.4 ? 1 : 0;
|
|
12710
|
+
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
12711
|
+
for (const p of bsp(cell, k, [g], rnd)) pieces.push(p);
|
|
12712
|
+
}
|
|
12713
|
+
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] }));
|
|
12714
|
+
};
|
|
12715
|
+
var severAt = (inp, root, at, gap) => {
|
|
12716
|
+
const dims = root.s;
|
|
12717
|
+
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
12718
|
+
const half = dims[L] / 2;
|
|
12719
|
+
const lo = clamp(at - gap / 2, -half, half), hi = clamp(at + gap / 2, -half, half);
|
|
12720
|
+
const out = [];
|
|
12721
|
+
const stub = (from, to) => {
|
|
12722
|
+
if (to - from < 0.02) return;
|
|
12723
|
+
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
12724
|
+
c[L] = (from + to) / 2;
|
|
12725
|
+
sz[L] = to - from;
|
|
12726
|
+
out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight: sz[0] * sz[1] * sz[2] });
|
|
12727
|
+
};
|
|
12728
|
+
stub(-half, lo);
|
|
12729
|
+
stub(hi, half);
|
|
12730
|
+
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
12731
|
+
band.c[L] = (lo + hi) / 2;
|
|
12732
|
+
band.s[L] = Math.max(hi - lo, 0.01);
|
|
12733
|
+
for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
12734
|
+
return out;
|
|
12735
|
+
};
|
|
12736
|
+
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
12737
|
+
const { dims, rnd, maxFragments } = inp;
|
|
12738
|
+
const layers = clamp(Math.ceil(dims[t] / STACK_LAYER), 2, 4);
|
|
12739
|
+
const per = clamp(n, 3, Math.max(3, Math.floor(maxFragments / layers)));
|
|
12740
|
+
const out = [];
|
|
12741
|
+
for (let k = 0; k < layers; k++) {
|
|
12742
|
+
const off = -dims[t] / 2 + (k + 0.5) * dims[t] / layers;
|
|
12743
|
+
for (const b of bsp(root, per, [u, v], rnd)) {
|
|
12744
|
+
if (out.length >= maxFragments) return out;
|
|
12745
|
+
const c = [b.c[0], b.c[1], b.c[2]];
|
|
12746
|
+
c[t] = off;
|
|
12747
|
+
out.push({ center: c, size: [b.s[u], b.s[v], sheet], q: frame(u, v, t, (rnd() - 0.5) * 0.8), shape: "scrap", weight: b.s[u] * b.s[v], inner: out.length % 4 !== 0 });
|
|
12748
|
+
}
|
|
12749
|
+
}
|
|
12750
|
+
return out;
|
|
12751
|
+
};
|
|
12752
|
+
var STACK_LAYER = 0.012;
|
|
12697
12753
|
var planFragments = (inp) => {
|
|
12698
12754
|
const { style, dims, rnd, maxFragments } = inp;
|
|
12699
12755
|
const [fmin, fmax] = inp.fragmentSize;
|
|
@@ -12715,27 +12771,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12715
12771
|
return out;
|
|
12716
12772
|
}
|
|
12717
12773
|
if (style === "splinter") {
|
|
12718
|
-
|
|
12719
|
-
const
|
|
12720
|
-
const w = Math.max(fmin * 1.5, 0.01);
|
|
12721
|
-
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)));
|
|
12722
|
-
const maxLen = fmax * 4;
|
|
12723
|
-
const cells = bsp(root, c, [a, b], rnd);
|
|
12724
|
-
const pieces = [];
|
|
12725
|
-
for (const cell of cells) {
|
|
12726
|
-
let list2 = [cell];
|
|
12727
|
-
const extra = rnd() < 0.4 ? 1 : 0;
|
|
12728
|
-
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
12729
|
-
list2 = bsp(cell, k, [g], rnd);
|
|
12730
|
-
for (const p of list2) pieces.push(p);
|
|
12731
|
-
}
|
|
12732
|
-
for (const p of pieces.slice(0, maxFragments)) {
|
|
12733
|
-
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] });
|
|
12734
|
-
}
|
|
12774
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
12775
|
+
for (const p of splinterBox(inp, root)) out.push(p);
|
|
12735
12776
|
return out;
|
|
12736
12777
|
}
|
|
12737
12778
|
if (style === "tear") {
|
|
12738
12779
|
const n2 = clamp(Math.round(dims[u] * dims[v] / (mean * mean)), 3, maxFragments);
|
|
12780
|
+
const sheet = inp.sheet ?? 0;
|
|
12781
|
+
if (sheet > 0 && dims[t] > sheet * 4) return tearStack(inp, root, t, u, v, n2, sheet);
|
|
12739
12782
|
const th2 = Math.min(inp.thickness, dims[t]);
|
|
12740
12783
|
for (const b of bsp(root, n2, [u, v], rnd)) {
|
|
12741
12784
|
out.push({ center: [b.c[0], b.c[1], b.c[2]], size: [b.s[u], b.s[v], th2], q: frame(u, v, t), shape: "scrap", weight: b.s[u] * b.s[v] });
|
|
@@ -14318,6 +14361,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14318
14361
|
0.03,
|
|
14319
14362
|
0.15
|
|
14320
14363
|
],
|
|
14364
|
+
sheet: 1e-3,
|
|
14321
14365
|
damageScale: {
|
|
14322
14366
|
slash: 3
|
|
14323
14367
|
},
|
|
@@ -14333,7 +14377,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14333
14377
|
smoke: "grey"
|
|
14334
14378
|
},
|
|
14335
14379
|
visual: {
|
|
14336
|
-
charColor: 1709072
|
|
14380
|
+
charColor: 1709072,
|
|
14381
|
+
innerColor: 15524048
|
|
14337
14382
|
},
|
|
14338
14383
|
tags: [
|
|
14339
14384
|
"fabric",
|
|
@@ -14715,9 +14760,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14715
14760
|
var BREACH_AREA = 0.25;
|
|
14716
14761
|
var BREACH_BLAST_REACH = 0.12;
|
|
14717
14762
|
var RESIDUAL_CAPACITY = 0.15;
|
|
14763
|
+
var SEVER_BAND = 0.1;
|
|
14764
|
+
var SEVER_ASPECT = 3;
|
|
14765
|
+
var SEVER_BALLISTIC = 2;
|
|
14718
14766
|
var SUPPORT_TOLERANCE = 0.05;
|
|
14719
14767
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
14720
14768
|
var BREACH_GRID_CAP = 4096;
|
|
14769
|
+
var CHIP_ENERGY = 200;
|
|
14770
|
+
var CHIP_SPLASH = 0.5;
|
|
14721
14771
|
var CUT_SLICE = 1;
|
|
14722
14772
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
14723
14773
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -14761,6 +14811,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14761
14811
|
let windCfg = windOpts ? resolveWind(windOpts) : null;
|
|
14762
14812
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
14763
14813
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
14814
|
+
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
14764
14815
|
const rng3 = createRng(options.seed ?? 1);
|
|
14765
14816
|
const rnd = () => rng3.next();
|
|
14766
14817
|
let time = 0;
|
|
@@ -15134,41 +15185,68 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15134
15185
|
markDamaged(p);
|
|
15135
15186
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
15136
15187
|
};
|
|
15188
|
+
const freeSpan = (p, supports) => {
|
|
15189
|
+
if (supports.length === 0) return Infinity;
|
|
15190
|
+
const d = p.dims;
|
|
15191
|
+
const L = [0, 1, 2].sort((a, b) => d[b] - d[a])[0];
|
|
15192
|
+
const spans = supports.map((k) => contactBox(p, k)).map(([lo, hi]) => [lo[L], hi[L]]);
|
|
15193
|
+
let far = 0;
|
|
15194
|
+
for (let i = 0; i <= 16; i++) {
|
|
15195
|
+
const x = (i / 16 - 0.5) * d[L];
|
|
15196
|
+
let near = Infinity;
|
|
15197
|
+
for (const [lo, hi] of spans) near = Math.min(near, Math.max(lo - x, x - hi, 0));
|
|
15198
|
+
far = Math.max(far, near);
|
|
15199
|
+
}
|
|
15200
|
+
return 2 * far;
|
|
15201
|
+
};
|
|
15137
15202
|
const solveStructure = (o) => {
|
|
15138
15203
|
o.maxStress = 0;
|
|
15139
15204
|
if (!o.hasStructure) return;
|
|
15140
15205
|
const parts = o.parts;
|
|
15141
15206
|
const n = parts.length;
|
|
15142
15207
|
const dist = new Array(n).fill(-1);
|
|
15143
|
-
const queue = [];
|
|
15144
15208
|
const ok = (i) => parts[i].structural && !isLost(parts[i]);
|
|
15145
15209
|
const isPartition = (i) => parts[i].spec.structure?.role === "partition";
|
|
15146
|
-
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
|
|
15150
|
-
|
|
15151
|
-
|
|
15152
|
-
if (
|
|
15153
|
-
|
|
15154
|
-
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15210
|
+
const out = /* @__PURE__ */ new Set();
|
|
15211
|
+
let queue = [];
|
|
15212
|
+
let lowerOf = /* @__PURE__ */ new Map();
|
|
15213
|
+
for (; ; ) {
|
|
15214
|
+
dist.fill(-1);
|
|
15215
|
+
queue = [];
|
|
15216
|
+
for (let i = 0; i < n; i++) if (ok(i) && !out.has(i) && parts[i].anchored) {
|
|
15217
|
+
dist[i] = 0;
|
|
15218
|
+
queue.push(i);
|
|
15219
|
+
}
|
|
15220
|
+
for (let h = 0; h < queue.length; h++) {
|
|
15221
|
+
const s = queue[h];
|
|
15222
|
+
if (isPartition(s)) continue;
|
|
15223
|
+
for (const j of o.byPart.get(parts[s].spec.id)) {
|
|
15224
|
+
if (j.st.open || !j.bears) continue;
|
|
15225
|
+
const r = j.ia === s ? j.ib : j.ia;
|
|
15226
|
+
if (dist[r] >= 0 || !ok(r) || out.has(r) || restsOn(o, j, r) !== s) continue;
|
|
15227
|
+
dist[r] = dist[s] + 1;
|
|
15228
|
+
queue.push(r);
|
|
15229
|
+
}
|
|
15159
15230
|
}
|
|
15160
|
-
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
|
|
15164
|
-
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
|
|
15168
|
-
|
|
15231
|
+
lowerOf = /* @__PURE__ */ new Map();
|
|
15232
|
+
let dropped = false;
|
|
15233
|
+
for (const i of queue) {
|
|
15234
|
+
const lower = [];
|
|
15235
|
+
for (const j of o.byPart.get(parts[i].spec.id)) {
|
|
15236
|
+
if (j.st.open || !j.bears) continue;
|
|
15237
|
+
const k = restsOn(o, j, i);
|
|
15238
|
+
if (k >= 0 && dist[k] >= 0 && dist[k] < dist[i] && !isPartition(k)) lower.push(k);
|
|
15239
|
+
}
|
|
15240
|
+
lowerOf.set(i, lower);
|
|
15241
|
+
const max = parts[i].spec.structure?.maxSpan;
|
|
15242
|
+
if (max !== void 0 && !parts[i].anchored && freeSpan(parts[i], lower.map((k) => parts[k])) > max) {
|
|
15243
|
+
out.add(i);
|
|
15244
|
+
dropped = true;
|
|
15245
|
+
}
|
|
15169
15246
|
}
|
|
15170
|
-
|
|
15247
|
+
if (!dropped) break;
|
|
15171
15248
|
}
|
|
15249
|
+
const incoming = new Array(n).fill(0);
|
|
15172
15250
|
const bending = new Array(n).fill(0);
|
|
15173
15251
|
const through = parts.map(() => []);
|
|
15174
15252
|
const pass = (k, at, mass) => {
|
|
@@ -15680,6 +15758,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15680
15758
|
const r = rayPart(o, p, origin, d);
|
|
15681
15759
|
if (!r || r.t0 < 0 || r.t0 > maxDist) continue;
|
|
15682
15760
|
if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue;
|
|
15761
|
+
if (p.st.chipped && insideChip(p, objLocal(o, vec.madd(origin, d, r.t0)))) continue;
|
|
15683
15762
|
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 };
|
|
15684
15763
|
}
|
|
15685
15764
|
}
|
|
@@ -15943,6 +16022,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15943
16022
|
if (total < (p.spec.breach?.area ?? BREACH_AREA)) return;
|
|
15944
16023
|
openBreach(o, p, [sum[0] / total, sum[1] / total, sum[2] / total], total, energy, dir, src);
|
|
15945
16024
|
};
|
|
16025
|
+
const unitGrids = /* @__PURE__ */ new WeakMap();
|
|
16026
|
+
const gridOf = (p) => {
|
|
16027
|
+
let grid = unitGrids.get(p);
|
|
16028
|
+
if (!grid) unitGrids.set(p, grid = unitGrid(p.dims, p.thin, unitsOf2(p), BREACH_GRID_CAP));
|
|
16029
|
+
return grid;
|
|
16030
|
+
};
|
|
16031
|
+
const insideChip = (p, objectPoint) => {
|
|
16032
|
+
const cells = p.st.chipped;
|
|
16033
|
+
if (!cells?.length) return false;
|
|
16034
|
+
const [u, v] = planeAxes(p.thin);
|
|
16035
|
+
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
16036
|
+
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);
|
|
16037
|
+
};
|
|
16038
|
+
const chipUnits = (o, p, wp, energy, dir, radius, src) => {
|
|
16039
|
+
var _a, _b;
|
|
16040
|
+
if (!p.spec.units || p.spec.reinforcement || !p.staged || chipEnergy <= 0 || energy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
16041
|
+
const [u, v] = planeAxes(p.thin);
|
|
16042
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
16043
|
+
const grid = gridOf(p);
|
|
16044
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
16045
|
+
const out = [];
|
|
16046
|
+
for (let i = 0; i < grid.length; i++) {
|
|
16047
|
+
const cell = grid[i];
|
|
16048
|
+
if (worn[i] === -1) continue;
|
|
16049
|
+
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));
|
|
16050
|
+
if (gap > radius) continue;
|
|
16051
|
+
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
16052
|
+
const total = (worn[i] ?? 0) + energy * share;
|
|
16053
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
16054
|
+
if (total < chipEnergy * mass) {
|
|
16055
|
+
worn[i] = total;
|
|
16056
|
+
continue;
|
|
16057
|
+
}
|
|
16058
|
+
worn[i] = -1;
|
|
16059
|
+
out.push(cell);
|
|
16060
|
+
}
|
|
16061
|
+
if (out.length === 0) return;
|
|
16062
|
+
const { c, q } = partXf(o, p);
|
|
16063
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
16064
|
+
const holes = localHolesOf(p);
|
|
16065
|
+
for (const cell of out) {
|
|
16066
|
+
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
16067
|
+
const center = toWorld(c, q, cell.center);
|
|
16068
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
16069
|
+
const fragments = cellFragments(o, p, [cell], wp, dir, speed, mass, `c${chipped.length}_`);
|
|
16070
|
+
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
16071
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
16072
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
16073
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
16074
|
+
markDamaged(p);
|
|
16075
|
+
setStage(o, p, 1, {}, src);
|
|
16076
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
16077
|
+
debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
16078
|
+
}
|
|
16079
|
+
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
16080
|
+
};
|
|
15946
16081
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
15947
16082
|
const [u, v] = planeAxes(p.thin);
|
|
15948
16083
|
const radius = clamp2(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius);
|
|
@@ -15954,7 +16089,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15954
16089
|
failPart(o, p, worldCenter, dir, energy, 12, src);
|
|
15955
16090
|
return;
|
|
15956
16091
|
}
|
|
15957
|
-
const
|
|
16092
|
+
const worn = p.rt.chips;
|
|
16093
|
+
const cells = cellsWithin(gridOf(p).filter((_, i) => worn?.[i] !== -1), p.thin, lc, radius);
|
|
15958
16094
|
const removed = p.st.mass * cells.reduce((sum, cell) => sum + cell.size[u] * cell.size[v], 0) / (p.dims[u] * p.dims[v]);
|
|
15959
16095
|
const speed = clamp2(Math.sqrt(2 * energy * 0.1 / Math.max(removed, 0.05)), 0.5, 8);
|
|
15960
16096
|
const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, "b");
|
|
@@ -16038,6 +16174,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16038
16174
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
16039
16175
|
const hitLocal = toLocal(c, q, hitW);
|
|
16040
16176
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
16177
|
+
const axis = style === "splinter" ? severAxis(p) : -1;
|
|
16178
|
+
const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
|
|
16041
16179
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
16042
16180
|
style,
|
|
16043
16181
|
dims: p.dims,
|
|
@@ -16046,7 +16184,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16046
16184
|
hit: hitLocal,
|
|
16047
16185
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
16048
16186
|
maxFragments,
|
|
16049
|
-
rnd
|
|
16187
|
+
rnd,
|
|
16188
|
+
sheet: p.mat.sheet,
|
|
16189
|
+
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
16050
16190
|
});
|
|
16051
16191
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
16052
16192
|
const mass = p.st.mass;
|
|
@@ -16070,7 +16210,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16070
16210
|
velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],
|
|
16071
16211
|
angularVelocity: [(rnd() - 0.5) * 12, (rnd() - 0.5) * 12, (rnd() - 0.5) * 12],
|
|
16072
16212
|
mass: mass * f.weight / totW,
|
|
16073
|
-
...marks.length > 0 ? { marks } : {}
|
|
16213
|
+
...marks.length > 0 ? { marks } : {},
|
|
16214
|
+
...f.inner ? { inner: true } : {}
|
|
16074
16215
|
};
|
|
16075
16216
|
});
|
|
16076
16217
|
const reinforcement = p.spec.reinforcement;
|
|
@@ -16104,10 +16245,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16104
16245
|
emit({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
|
|
16105
16246
|
};
|
|
16106
16247
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
16248
|
+
const severAxis = (p) => {
|
|
16249
|
+
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
16250
|
+
const d = p.dims;
|
|
16251
|
+
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
16252
|
+
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
16253
|
+
};
|
|
16254
|
+
const bandOf = (o, p, axis, origin) => {
|
|
16255
|
+
const { c, q } = partXf(o, p);
|
|
16256
|
+
const along = toLocal(c, q, origin)[axis];
|
|
16257
|
+
const L = p.dims[axis];
|
|
16258
|
+
return clamp2(Math.floor((along + L / 2) / SEVER_BAND), 0, Math.ceil(L / SEVER_BAND) - 1);
|
|
16259
|
+
};
|
|
16107
16260
|
const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
|
|
16261
|
+
var _a;
|
|
16108
16262
|
if (isLost(p) || amount <= 0) return 0;
|
|
16109
16263
|
const prev = p.st.hp;
|
|
16110
16264
|
p.st.hp -= amount;
|
|
16265
|
+
const axis = origin && type !== "fire" && type !== "heat" ? severAxis(p) : -1;
|
|
16266
|
+
if (axis >= 0 && p.st.hp > 0) {
|
|
16267
|
+
const band = bandOf(o, p, axis, origin);
|
|
16268
|
+
const cuts = (_a = p.rt).cuts ?? (_a.cuts = {});
|
|
16269
|
+
cuts[band] = (cuts[band] ?? 0) + amount * (type === "ballistic" ? SEVER_BALLISTIC : 1);
|
|
16270
|
+
if (cuts[band] >= p.st.maxHp * SEVER_BAND / p.dims[axis]) {
|
|
16271
|
+
p.rt.cutAt = -p.dims[axis] / 2 + (band + 0.5) * SEVER_BAND;
|
|
16272
|
+
p.st.hp = 0;
|
|
16273
|
+
}
|
|
16274
|
+
}
|
|
16111
16275
|
markDamaged(p);
|
|
16112
16276
|
const trigger = CHAIN_TRIGGER_OF[type];
|
|
16113
16277
|
const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
|
|
@@ -16146,7 +16310,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16146
16310
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round3 = {}) => {
|
|
16147
16311
|
const mat = p.mat;
|
|
16148
16312
|
const piercing = round3.piercing ?? 1;
|
|
16149
|
-
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2))) {
|
|
16313
|
+
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2)) || insideChip(p, objLocal(o, entry2))) {
|
|
16150
16314
|
return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry2, d, Math.min(pathLen, p.thickness)), damage: 0 };
|
|
16151
16315
|
}
|
|
16152
16316
|
const sin = Math.min(1, Math.abs(vec.dot(d, n)));
|
|
@@ -16205,6 +16369,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16205
16369
|
debris(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
16206
16370
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
16207
16371
|
const dmg = applyDamage(o, p, E * DMG_PER_J * scale, "ballistic", entry2, d, E * 0.1, 12, src);
|
|
16372
|
+
chipUnits(o, p, entry2, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
|
|
16208
16373
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
16209
16374
|
};
|
|
16210
16375
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -16232,6 +16397,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16232
16397
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
16233
16398
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
16234
16399
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
16400
|
+
if (kind === "blunt") chipUnits(o, p, point, E, d, Math.max(contactR, 0.03), src);
|
|
16235
16401
|
return done;
|
|
16236
16402
|
};
|
|
16237
16403
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -26250,12 +26416,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26250
26416
|
A.invalidate = () => {
|
|
26251
26417
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
26252
26418
|
};
|
|
26253
|
-
A.update = function(
|
|
26419
|
+
A.update = function(houses2, focus, op) {
|
|
26254
26420
|
op = op || {};
|
|
26255
|
-
|
|
26421
|
+
houses2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean);
|
|
26256
26422
|
_f.set(focus.x, focus.y, focus.z);
|
|
26257
26423
|
const rooms = [], exterior = [];
|
|
26258
|
-
for (const house of
|
|
26424
|
+
for (const house of houses2) {
|
|
26259
26425
|
if (house.group && !house.group.visible) continue;
|
|
26260
26426
|
house.house.updateMatrixWorld(true);
|
|
26261
26427
|
const M = house.house.matrixWorld, by = /* @__PURE__ */ new Map();
|
|
@@ -26634,7 +26800,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26634
26800
|
}
|
|
26635
26801
|
return null;
|
|
26636
26802
|
};
|
|
26637
|
-
|
|
26803
|
+
const local = (p) => {
|
|
26804
|
+
house.updateMatrixWorld(true);
|
|
26805
|
+
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
26806
|
+
return [v.x, v.y, v.z];
|
|
26807
|
+
};
|
|
26808
|
+
function courses(part, units, opening, chips, paint) {
|
|
26638
26809
|
const [u0, v0, u1, v1] = part.aabb;
|
|
26639
26810
|
const alongU = u1 - u0 >= v1 - v0;
|
|
26640
26811
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
@@ -26658,23 +26829,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26658
26829
|
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
26659
26830
|
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
26660
26831
|
const y = part.y0 + (r + 0.5) * rowH;
|
|
26661
|
-
const d = Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]);
|
|
26662
|
-
if (d < opening.radius) continue;
|
|
26663
|
-
|
|
26832
|
+
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
26833
|
+
if (opening && d < opening.radius) continue;
|
|
26834
|
+
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);
|
|
26835
|
+
if (chips.some(gone)) continue;
|
|
26836
|
+
const near = opening && d < opening.radius + 0.25 || chips.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
26837
|
+
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint === null ? edge : paint });
|
|
26664
26838
|
}
|
|
26665
26839
|
}
|
|
26666
26840
|
return list2;
|
|
26667
26841
|
}
|
|
26668
|
-
function
|
|
26669
|
-
if (lod !== 0
|
|
26670
|
-
const part = structure.byId.get(
|
|
26671
|
-
const spec = opts.spec()?.parts?.find((q) => q.id ===
|
|
26842
|
+
function draw2(partId, change) {
|
|
26843
|
+
if (lod !== 0) return false;
|
|
26844
|
+
const part = structure.byId.get(partId);
|
|
26845
|
+
const spec = opts.spec()?.parts?.find((q) => q.id === partId);
|
|
26672
26846
|
if (!part || !spec || !spec.units) return false;
|
|
26673
|
-
|
|
26674
|
-
if (!
|
|
26675
|
-
|
|
26847
|
+
let view = views.get(partId);
|
|
26848
|
+
if (!view) {
|
|
26849
|
+
const items = structure.meshesOf(partId).filter((it) => it.mesh);
|
|
26850
|
+
if (!items.length) return false;
|
|
26851
|
+
view = { mesh: null, saved: null, items, paint: wallColour(items), units: 0, opening: null, chips: [] };
|
|
26852
|
+
}
|
|
26853
|
+
if (change.opening) {
|
|
26854
|
+
if (view.opening) return false;
|
|
26855
|
+
view.opening = { center: local(change.opening.center), radius: change.opening.radius };
|
|
26856
|
+
}
|
|
26857
|
+
if (change.chip) view.chips.push(local(change.chip));
|
|
26858
|
+
const list2 = courses(part, spec.units, view.opening, view.chips, view.paint);
|
|
26859
|
+
if (view.mesh) {
|
|
26860
|
+
view.mesh.removeFromParent();
|
|
26861
|
+
view.mesh.dispose();
|
|
26862
|
+
}
|
|
26676
26863
|
const mesh2 = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
26677
|
-
mesh2.name = "breach:" +
|
|
26864
|
+
mesh2.name = "breach:" + partId;
|
|
26678
26865
|
list2.forEach((u, i) => {
|
|
26679
26866
|
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
26680
26867
|
mesh2.setMatrixAt(i, tmp.m);
|
|
@@ -26686,8 +26873,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26686
26873
|
mesh2.castShadow = true;
|
|
26687
26874
|
mesh2.receiveShadow = true;
|
|
26688
26875
|
house.add(mesh2);
|
|
26689
|
-
|
|
26690
|
-
|
|
26876
|
+
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
26877
|
+
view.mesh = mesh2;
|
|
26878
|
+
view.units = list2.length;
|
|
26879
|
+
views.set(partId, view);
|
|
26691
26880
|
invalidate();
|
|
26692
26881
|
invalidateShadow();
|
|
26693
26882
|
return true;
|
|
@@ -26701,7 +26890,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26701
26890
|
return {
|
|
26702
26891
|
/** Handles a `stage` event of the house's object. Returns true when the wall was redrawn as courses. */
|
|
26703
26892
|
stage(event) {
|
|
26704
|
-
return event.stage === 2 ?
|
|
26893
|
+
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
26894
|
+
},
|
|
26895
|
+
/** Handles a `chip` event: the unit that came out leaves a gap in the courses. Returns true when the wall was redrawn. */
|
|
26896
|
+
chip(event) {
|
|
26897
|
+
return draw2(event.part, { chip: event.center });
|
|
26705
26898
|
},
|
|
26706
26899
|
/** The part broke or fell: the courses go (the plain range stays collapsed, the renderer hides the part). */
|
|
26707
26900
|
drop(partId) {
|
|
@@ -26931,6 +27124,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26931
27124
|
case "stage":
|
|
26932
27125
|
breach.stage(e);
|
|
26933
27126
|
break;
|
|
27127
|
+
case "chip":
|
|
27128
|
+
breach.chip(e);
|
|
27129
|
+
break;
|
|
26934
27130
|
case "collapse":
|
|
26935
27131
|
for (const id of e.parts) {
|
|
26936
27132
|
breach.drop(id);
|
|
@@ -26985,6 +27181,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26985
27181
|
if (D.active && D.world.has(D.id)) D.world.remove(D.id);
|
|
26986
27182
|
D.active = false;
|
|
26987
27183
|
};
|
|
27184
|
+
D.follow = (world, id, spec) => {
|
|
27185
|
+
D.spec = spec;
|
|
27186
|
+
const offFollow = world.on("*", (e) => {
|
|
27187
|
+
if (e.object !== id) return;
|
|
27188
|
+
switch (e.type) {
|
|
27189
|
+
case "stage":
|
|
27190
|
+
breach.stage(e);
|
|
27191
|
+
break;
|
|
27192
|
+
case "chip":
|
|
27193
|
+
breach.chip(e);
|
|
27194
|
+
break;
|
|
27195
|
+
case "fracture":
|
|
27196
|
+
breach.drop(e.part);
|
|
27197
|
+
break;
|
|
27198
|
+
case "collapse":
|
|
27199
|
+
for (const p of e.parts) breach.drop(p);
|
|
27200
|
+
break;
|
|
27201
|
+
default:
|
|
27202
|
+
break;
|
|
27203
|
+
}
|
|
27204
|
+
});
|
|
27205
|
+
return { restore: () => breach.restore(), dispose: () => {
|
|
27206
|
+
offFollow();
|
|
27207
|
+
breach.restore();
|
|
27208
|
+
} };
|
|
27209
|
+
};
|
|
26988
27210
|
D.piece = (id) => D.active ? D.world.part(D.id, id) : null;
|
|
26989
27211
|
D.state = () => D.active ? D.world.state(D.id) : null;
|
|
26990
27212
|
D.reset = () => {
|
|
@@ -27707,6 +27929,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27707
27929
|
return buildApi(K, shared);
|
|
27708
27930
|
}
|
|
27709
27931
|
var WOOD_THIN = 0.035;
|
|
27932
|
+
var SHELF_SPAN = 1.5;
|
|
27933
|
+
var SHELVING = /shelf|bookcase|rack/;
|
|
27934
|
+
function carcass(parts, drawn) {
|
|
27935
|
+
const all = [...drawn.values()];
|
|
27936
|
+
const width = Math.max(...all.map((p) => p.max[0])) - Math.min(...all.map((p) => p.min[0]));
|
|
27937
|
+
for (const part of parts) {
|
|
27938
|
+
if (LOOSE.has(part.material) || part.shape.kind !== "box" || part.rotation) continue;
|
|
27939
|
+
const [x, y, z] = part.shape.size;
|
|
27940
|
+
if (y >= x && y >= z) {
|
|
27941
|
+
if (z < x && x >= 0.6 * width) continue;
|
|
27942
|
+
part.structure = { role: "column" };
|
|
27943
|
+
} else if (y <= x && y <= z) part.structure = { role: "beam", maxSpan: SHELF_SPAN * Math.max(x, z) };
|
|
27944
|
+
}
|
|
27945
|
+
}
|
|
27710
27946
|
var FLOOR_TOUCH = 5e-3;
|
|
27711
27947
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
27712
27948
|
var BASE_MATERIAL = {
|
|
@@ -27822,6 +28058,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27822
28058
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
27823
28059
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
27824
28060
|
}
|
|
28061
|
+
if (opts.carcass) carcass(parts, byId);
|
|
27825
28062
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
27826
28063
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
27827
28064
|
const build = (T3) => {
|
|
@@ -27865,7 +28102,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27865
28102
|
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`);
|
|
27866
28103
|
const o = opts.options ?? {};
|
|
27867
28104
|
const seed = Math.round(opts.seed ?? 1);
|
|
27868
|
-
const plain2 =
|
|
28105
|
+
const plain2 = SHELVING.test(type) ? "paper" : "plastic";
|
|
27869
28106
|
const root = { x: seed, z: 0, ry: 0, w, d, h, y: 0, base: 0, palette: o.palette, seed: `furniture_${type}_${seed}` };
|
|
27870
28107
|
const { K, shared } = renderer.internals;
|
|
27871
28108
|
const before = K.PARTS.length;
|
|
@@ -27884,7 +28121,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27884
28121
|
shared.ctx = saved.ctx;
|
|
27885
28122
|
}
|
|
27886
28123
|
},
|
|
27887
|
-
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs }
|
|
28124
|
+
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs, carcass: SHELVING.test(type) }
|
|
27888
28125
|
);
|
|
27889
28126
|
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]);
|
|
27890
28127
|
K.PARTS.length = before;
|