@adatechnology/game-items-three 0.3.1 → 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 +278 -64
- package/dist/index.global.js.map +1 -1
- package/package.json +8 -8
package/dist/index.global.js
CHANGED
|
@@ -12694,6 +12694,45 @@ 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
|
+
};
|
|
12697
12736
|
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
12698
12737
|
const { dims, rnd, maxFragments } = inp;
|
|
12699
12738
|
const layers = clamp(Math.ceil(dims[t] / STACK_LAYER), 2, 4);
|
|
@@ -12732,23 +12771,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12732
12771
|
return out;
|
|
12733
12772
|
}
|
|
12734
12773
|
if (style === "splinter") {
|
|
12735
|
-
|
|
12736
|
-
const
|
|
12737
|
-
const w = Math.max(fmin * 1.5, 0.01);
|
|
12738
|
-
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)));
|
|
12739
|
-
const maxLen = fmax * 4;
|
|
12740
|
-
const cells = bsp(root, c, [a, b], rnd);
|
|
12741
|
-
const pieces = [];
|
|
12742
|
-
for (const cell of cells) {
|
|
12743
|
-
let list2 = [cell];
|
|
12744
|
-
const extra = rnd() < 0.4 ? 1 : 0;
|
|
12745
|
-
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
12746
|
-
list2 = bsp(cell, k, [g], rnd);
|
|
12747
|
-
for (const p of list2) pieces.push(p);
|
|
12748
|
-
}
|
|
12749
|
-
for (const p of pieces.slice(0, maxFragments)) {
|
|
12750
|
-
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] });
|
|
12751
|
-
}
|
|
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);
|
|
12752
12776
|
return out;
|
|
12753
12777
|
}
|
|
12754
12778
|
if (style === "tear") {
|
|
@@ -14736,9 +14760,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14736
14760
|
var BREACH_AREA = 0.25;
|
|
14737
14761
|
var BREACH_BLAST_REACH = 0.12;
|
|
14738
14762
|
var RESIDUAL_CAPACITY = 0.15;
|
|
14763
|
+
var SEVER_BAND = 0.1;
|
|
14764
|
+
var SEVER_ASPECT = 3;
|
|
14765
|
+
var SEVER_BALLISTIC = 2;
|
|
14739
14766
|
var SUPPORT_TOLERANCE = 0.05;
|
|
14740
14767
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
14741
14768
|
var BREACH_GRID_CAP = 4096;
|
|
14769
|
+
var CHIP_ENERGY = 200;
|
|
14770
|
+
var CHIP_SPLASH = 0.5;
|
|
14742
14771
|
var CUT_SLICE = 1;
|
|
14743
14772
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
14744
14773
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -14782,6 +14811,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14782
14811
|
let windCfg = windOpts ? resolveWind(windOpts) : null;
|
|
14783
14812
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
14784
14813
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
14814
|
+
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
14785
14815
|
const rng3 = createRng(options.seed ?? 1);
|
|
14786
14816
|
const rnd = () => rng3.next();
|
|
14787
14817
|
let time = 0;
|
|
@@ -15155,41 +15185,68 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15155
15185
|
markDamaged(p);
|
|
15156
15186
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
15157
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
|
+
};
|
|
15158
15202
|
const solveStructure = (o) => {
|
|
15159
15203
|
o.maxStress = 0;
|
|
15160
15204
|
if (!o.hasStructure) return;
|
|
15161
15205
|
const parts = o.parts;
|
|
15162
15206
|
const n = parts.length;
|
|
15163
15207
|
const dist = new Array(n).fill(-1);
|
|
15164
|
-
const queue = [];
|
|
15165
15208
|
const ok = (i) => parts[i].structural && !isLost(parts[i]);
|
|
15166
15209
|
const isPartition = (i) => parts[i].spec.structure?.role === "partition";
|
|
15167
|
-
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15173
|
-
if (
|
|
15174
|
-
|
|
15175
|
-
|
|
15176
|
-
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
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
|
+
}
|
|
15180
15230
|
}
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
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
|
+
}
|
|
15190
15246
|
}
|
|
15191
|
-
|
|
15247
|
+
if (!dropped) break;
|
|
15192
15248
|
}
|
|
15249
|
+
const incoming = new Array(n).fill(0);
|
|
15193
15250
|
const bending = new Array(n).fill(0);
|
|
15194
15251
|
const through = parts.map(() => []);
|
|
15195
15252
|
const pass = (k, at, mass) => {
|
|
@@ -15701,6 +15758,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15701
15758
|
const r = rayPart(o, p, origin, d);
|
|
15702
15759
|
if (!r || r.t0 < 0 || r.t0 > maxDist) continue;
|
|
15703
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;
|
|
15704
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 };
|
|
15705
15763
|
}
|
|
15706
15764
|
}
|
|
@@ -15964,6 +16022,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15964
16022
|
if (total < (p.spec.breach?.area ?? BREACH_AREA)) return;
|
|
15965
16023
|
openBreach(o, p, [sum[0] / total, sum[1] / total, sum[2] / total], total, energy, dir, src);
|
|
15966
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
|
+
};
|
|
15967
16081
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
15968
16082
|
const [u, v] = planeAxes(p.thin);
|
|
15969
16083
|
const radius = clamp2(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius);
|
|
@@ -15975,7 +16089,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15975
16089
|
failPart(o, p, worldCenter, dir, energy, 12, src);
|
|
15976
16090
|
return;
|
|
15977
16091
|
}
|
|
15978
|
-
const
|
|
16092
|
+
const worn = p.rt.chips;
|
|
16093
|
+
const cells = cellsWithin(gridOf(p).filter((_, i) => worn?.[i] !== -1), p.thin, lc, radius);
|
|
15979
16094
|
const removed = p.st.mass * cells.reduce((sum, cell) => sum + cell.size[u] * cell.size[v], 0) / (p.dims[u] * p.dims[v]);
|
|
15980
16095
|
const speed = clamp2(Math.sqrt(2 * energy * 0.1 / Math.max(removed, 0.05)), 0.5, 8);
|
|
15981
16096
|
const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, "b");
|
|
@@ -16059,6 +16174,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16059
16174
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
16060
16175
|
const hitLocal = toLocal(c, q, hitW);
|
|
16061
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);
|
|
16062
16179
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
16063
16180
|
style,
|
|
16064
16181
|
dims: p.dims,
|
|
@@ -16068,7 +16185,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16068
16185
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
16069
16186
|
maxFragments,
|
|
16070
16187
|
rnd,
|
|
16071
|
-
sheet: p.mat.sheet
|
|
16188
|
+
sheet: p.mat.sheet,
|
|
16189
|
+
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
16072
16190
|
});
|
|
16073
16191
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
16074
16192
|
const mass = p.st.mass;
|
|
@@ -16127,10 +16245,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16127
16245
|
emit({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
|
|
16128
16246
|
};
|
|
16129
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
|
+
};
|
|
16130
16260
|
const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
|
|
16261
|
+
var _a;
|
|
16131
16262
|
if (isLost(p) || amount <= 0) return 0;
|
|
16132
16263
|
const prev = p.st.hp;
|
|
16133
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
|
+
}
|
|
16134
16275
|
markDamaged(p);
|
|
16135
16276
|
const trigger = CHAIN_TRIGGER_OF[type];
|
|
16136
16277
|
const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
|
|
@@ -16169,7 +16310,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16169
16310
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round3 = {}) => {
|
|
16170
16311
|
const mat = p.mat;
|
|
16171
16312
|
const piercing = round3.piercing ?? 1;
|
|
16172
|
-
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))) {
|
|
16173
16314
|
return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry2, d, Math.min(pathLen, p.thickness)), damage: 0 };
|
|
16174
16315
|
}
|
|
16175
16316
|
const sin = Math.min(1, Math.abs(vec.dot(d, n)));
|
|
@@ -16228,6 +16369,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16228
16369
|
debris(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
16229
16370
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
16230
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);
|
|
16231
16373
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
16232
16374
|
};
|
|
16233
16375
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -16255,6 +16397,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16255
16397
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
16256
16398
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
16257
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);
|
|
16258
16401
|
return done;
|
|
16259
16402
|
};
|
|
16260
16403
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -26273,12 +26416,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26273
26416
|
A.invalidate = () => {
|
|
26274
26417
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
26275
26418
|
};
|
|
26276
|
-
A.update = function(
|
|
26419
|
+
A.update = function(houses2, focus, op) {
|
|
26277
26420
|
op = op || {};
|
|
26278
|
-
|
|
26421
|
+
houses2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean);
|
|
26279
26422
|
_f.set(focus.x, focus.y, focus.z);
|
|
26280
26423
|
const rooms = [], exterior = [];
|
|
26281
|
-
for (const house of
|
|
26424
|
+
for (const house of houses2) {
|
|
26282
26425
|
if (house.group && !house.group.visible) continue;
|
|
26283
26426
|
house.house.updateMatrixWorld(true);
|
|
26284
26427
|
const M = house.house.matrixWorld, by = /* @__PURE__ */ new Map();
|
|
@@ -26657,7 +26800,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26657
26800
|
}
|
|
26658
26801
|
return null;
|
|
26659
26802
|
};
|
|
26660
|
-
|
|
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) {
|
|
26661
26809
|
const [u0, v0, u1, v1] = part.aabb;
|
|
26662
26810
|
const alongU = u1 - u0 >= v1 - v0;
|
|
26663
26811
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
@@ -26681,23 +26829,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26681
26829
|
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
26682
26830
|
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
26683
26831
|
const y = part.y0 + (r + 0.5) * rowH;
|
|
26684
|
-
const d = Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]);
|
|
26685
|
-
if (d < opening.radius) continue;
|
|
26686
|
-
|
|
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 });
|
|
26687
26838
|
}
|
|
26688
26839
|
}
|
|
26689
26840
|
return list2;
|
|
26690
26841
|
}
|
|
26691
|
-
function
|
|
26692
|
-
if (lod !== 0
|
|
26693
|
-
const part = structure.byId.get(
|
|
26694
|
-
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);
|
|
26695
26846
|
if (!part || !spec || !spec.units) return false;
|
|
26696
|
-
|
|
26697
|
-
if (!
|
|
26698
|
-
|
|
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
|
+
}
|
|
26699
26863
|
const mesh2 = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
26700
|
-
mesh2.name = "breach:" +
|
|
26864
|
+
mesh2.name = "breach:" + partId;
|
|
26701
26865
|
list2.forEach((u, i) => {
|
|
26702
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));
|
|
26703
26867
|
mesh2.setMatrixAt(i, tmp.m);
|
|
@@ -26709,8 +26873,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26709
26873
|
mesh2.castShadow = true;
|
|
26710
26874
|
mesh2.receiveShadow = true;
|
|
26711
26875
|
house.add(mesh2);
|
|
26712
|
-
|
|
26713
|
-
|
|
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);
|
|
26714
26880
|
invalidate();
|
|
26715
26881
|
invalidateShadow();
|
|
26716
26882
|
return true;
|
|
@@ -26724,7 +26890,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26724
26890
|
return {
|
|
26725
26891
|
/** Handles a `stage` event of the house's object. Returns true when the wall was redrawn as courses. */
|
|
26726
26892
|
stage(event) {
|
|
26727
|
-
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 });
|
|
26728
26898
|
},
|
|
26729
26899
|
/** The part broke or fell: the courses go (the plain range stays collapsed, the renderer hides the part). */
|
|
26730
26900
|
drop(partId) {
|
|
@@ -26954,6 +27124,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26954
27124
|
case "stage":
|
|
26955
27125
|
breach.stage(e);
|
|
26956
27126
|
break;
|
|
27127
|
+
case "chip":
|
|
27128
|
+
breach.chip(e);
|
|
27129
|
+
break;
|
|
26957
27130
|
case "collapse":
|
|
26958
27131
|
for (const id of e.parts) {
|
|
26959
27132
|
breach.drop(id);
|
|
@@ -27008,6 +27181,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27008
27181
|
if (D.active && D.world.has(D.id)) D.world.remove(D.id);
|
|
27009
27182
|
D.active = false;
|
|
27010
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
|
+
};
|
|
27011
27210
|
D.piece = (id) => D.active ? D.world.part(D.id, id) : null;
|
|
27012
27211
|
D.state = () => D.active ? D.world.state(D.id) : null;
|
|
27013
27212
|
D.reset = () => {
|
|
@@ -27730,6 +27929,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27730
27929
|
return buildApi(K, shared);
|
|
27731
27930
|
}
|
|
27732
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
|
+
}
|
|
27733
27946
|
var FLOOR_TOUCH = 5e-3;
|
|
27734
27947
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
27735
27948
|
var BASE_MATERIAL = {
|
|
@@ -27845,6 +28058,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27845
28058
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
27846
28059
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
27847
28060
|
}
|
|
28061
|
+
if (opts.carcass) carcass(parts, byId);
|
|
27848
28062
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
27849
28063
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
27850
28064
|
const build = (T3) => {
|
|
@@ -27888,7 +28102,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27888
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`);
|
|
27889
28103
|
const o = opts.options ?? {};
|
|
27890
28104
|
const seed = Math.round(opts.seed ?? 1);
|
|
27891
|
-
const plain2 =
|
|
28105
|
+
const plain2 = SHELVING.test(type) ? "paper" : "plastic";
|
|
27892
28106
|
const root = { x: seed, z: 0, ry: 0, w, d, h, y: 0, base: 0, palette: o.palette, seed: `furniture_${type}_${seed}` };
|
|
27893
28107
|
const { K, shared } = renderer.internals;
|
|
27894
28108
|
const before = K.PARTS.length;
|
|
@@ -27907,7 +28121,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27907
28121
|
shared.ctx = saved.ctx;
|
|
27908
28122
|
}
|
|
27909
28123
|
},
|
|
27910
|
-
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs }
|
|
28124
|
+
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs, carcass: SHELVING.test(type) }
|
|
27911
28125
|
);
|
|
27912
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]);
|
|
27913
28127
|
K.PARTS.length = before;
|