@adatechnology/game-weapons-three 0.10.2 → 0.10.4
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 +328 -73
- package/dist/index.global.js.map +1 -1
- package/package.json +11 -11
package/dist/index.global.js
CHANGED
|
@@ -21142,6 +21142,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21142
21142
|
},
|
|
21143
21143
|
hitDebris: "chips",
|
|
21144
21144
|
breakDebris: "dust",
|
|
21145
|
+
visual: { innerColor: 10197652 },
|
|
21145
21146
|
thermal: {
|
|
21146
21147
|
conductivity: 0.15,
|
|
21147
21148
|
heatCapacity: 2.5
|
|
@@ -21172,6 +21173,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21172
21173
|
],
|
|
21173
21174
|
hitDebris: "chips",
|
|
21174
21175
|
breakDebris: "dust",
|
|
21176
|
+
visual: { innerColor: 12085567 },
|
|
21175
21177
|
thermal: {
|
|
21176
21178
|
conductivity: 0.15,
|
|
21177
21179
|
heatCapacity: 2.5
|
|
@@ -21202,6 +21204,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21202
21204
|
],
|
|
21203
21205
|
hitDebris: "dust",
|
|
21204
21206
|
breakDebris: "dust",
|
|
21207
|
+
visual: { innerColor: 14999507 },
|
|
21205
21208
|
thermal: {
|
|
21206
21209
|
conductivity: 0.1,
|
|
21207
21210
|
heatCapacity: 1.5
|
|
@@ -21227,6 +21230,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21227
21230
|
],
|
|
21228
21231
|
hitDebris: "chips",
|
|
21229
21232
|
breakDebris: "dust",
|
|
21233
|
+
visual: { innerColor: 9407364 },
|
|
21230
21234
|
thermal: {
|
|
21231
21235
|
conductivity: 0.2,
|
|
21232
21236
|
heatCapacity: 2.5
|
|
@@ -21984,6 +21988,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21984
21988
|
var CHIP_ENERGY = 200;
|
|
21985
21989
|
var CHIP_SPLASH = 0.5;
|
|
21986
21990
|
var BAR_BOW = 0.08;
|
|
21991
|
+
var BULLET_JOINT_SPAN = 0.3;
|
|
21987
21992
|
var CUT_SLICE = 1;
|
|
21988
21993
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
21989
21994
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -23110,7 +23115,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23110
23115
|
emit2({ ...base(o, src), type: "crack", part: p.spec.id, crack, worldPoint: wp });
|
|
23111
23116
|
setStage(o, p, 1, {}, src);
|
|
23112
23117
|
};
|
|
23113
|
-
const debris2 = (o, p, kind, point, normal, count, speed, src) => emit2({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed });
|
|
23118
|
+
const debris2 = (o, p, kind, point, normal, count, speed, src, material) => emit2({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed, ...material && material !== p.spec.material ? { material } : {} });
|
|
23114
23119
|
const holeRate = (hole, pressurized) => (pressurized ? 0.5 : 0.1) * (hole.diameter / 9e-3);
|
|
23115
23120
|
const detachEvents = (o, opened, by, src) => {
|
|
23116
23121
|
for (const j of opened) emit2({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
|
|
@@ -23151,7 +23156,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23151
23156
|
const small = pa.dims[0] * pa.dims[1] * pa.dims[2] <= pb.dims[0] * pb.dims[1] * pb.dims[2] ? pa : pb;
|
|
23152
23157
|
return Math.max(0.06, 0.5 * Math.min(small.dims[0], small.dims[1], small.dims[2]));
|
|
23153
23158
|
};
|
|
23154
|
-
const
|
|
23159
|
+
const jointLength = (o, j) => {
|
|
23160
|
+
const A = partWorldAabb(o, o.parts[j.ia]), B = partWorldAabb(o, o.parts[j.ib]);
|
|
23161
|
+
let len = 0;
|
|
23162
|
+
for (let k = 0; k < 3; k++) len = Math.max(len, Math.min(A.max[k], B.max[k]) - Math.max(A.min[k], B.min[k]));
|
|
23163
|
+
return len;
|
|
23164
|
+
};
|
|
23165
|
+
const wearJoints = (o, p, amount, near, radius = 0.06, src, split = false, span) => {
|
|
23155
23166
|
if (amount <= 0) return;
|
|
23156
23167
|
const mine = (o.byPart.get(p.spec.id) ?? []).filter((j) => !j.st.open);
|
|
23157
23168
|
if (split && mine.length) amount /= mine.length;
|
|
@@ -23159,7 +23170,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23159
23170
|
if (j.st.open) continue;
|
|
23160
23171
|
if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
|
|
23161
23172
|
if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
|
|
23162
|
-
j.st.hp -= amount;
|
|
23173
|
+
j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
23163
23174
|
if (j.st.hp <= 0) {
|
|
23164
23175
|
j.st.hp = 0;
|
|
23165
23176
|
j.st.open = true;
|
|
@@ -23188,7 +23199,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23188
23199
|
if (spalls.length > MAX_SPALLS) spalls.shift();
|
|
23189
23200
|
markDamaged(p);
|
|
23190
23201
|
emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer: layer2.index, point: wp, area: Math.PI * radius * radius });
|
|
23191
|
-
debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src);
|
|
23202
|
+
debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src, layer2.mat.id);
|
|
23192
23203
|
setStage(o, p, 1, {}, src);
|
|
23193
23204
|
};
|
|
23194
23205
|
const crater = (o, p, wp, normal, radius, src) => {
|
|
@@ -23675,7 +23686,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23675
23686
|
if (mat.fracture !== "shatter") addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
23676
23687
|
} else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
23677
23688
|
debris2(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
23678
|
-
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
23689
|
+
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
|
|
23679
23690
|
const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
|
|
23680
23691
|
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry2, d, absorbed * 0.1, 12, src);
|
|
23681
23692
|
if (!isLost(p)) tearAt(o, p, "ballistic", entry2, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
@@ -34131,6 +34142,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34131
34142
|
pos.array.set(saved, v0 * 3);
|
|
34132
34143
|
pos.needsUpdate = true;
|
|
34133
34144
|
}
|
|
34145
|
+
function noise2(x, y, cell) {
|
|
34146
|
+
const h = (i2, j2) => {
|
|
34147
|
+
const s = Math.sin(i2 * 127.1 + j2 * 311.7) * 43758.5453;
|
|
34148
|
+
return s - Math.floor(s);
|
|
34149
|
+
};
|
|
34150
|
+
const fx = x / cell, fy = y / cell, i = Math.floor(fx), j = Math.floor(fy), u = fx - i, v = fy - j;
|
|
34151
|
+
const su = u * u * (3 - 2 * u), sv = v * v * (3 - 2 * v);
|
|
34152
|
+
return (h(i, j) * (1 - su) + h(i + 1, j) * su) * (1 - sv) + (h(i, j + 1) * (1 - su) + h(i + 1, j + 1) * su) * sv;
|
|
34153
|
+
}
|
|
34154
|
+
var MASK_TEXEL = 0.02;
|
|
34155
|
+
var SPALL_MIN = 0.025;
|
|
34156
|
+
var SPALL_RAGGED = 0.045;
|
|
34157
|
+
var COVER2 = 0.015;
|
|
34134
34158
|
function installDestructionBreach(K, _shared) {
|
|
34135
34159
|
const { THREE, fragmentMaterial, invalidate, invalidateShadow } = K;
|
|
34136
34160
|
function createBreachView(opts) {
|
|
@@ -34140,55 +34164,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34140
34164
|
const unitMaterial = new THREE.MeshLambertMaterial({ color: 16777215 });
|
|
34141
34165
|
const unitGeometry = new THREE.BoxGeometry(1, 1, 1);
|
|
34142
34166
|
const tmp = { m: new THREE.Matrix4(), q: new THREE.Quaternion(), p: new THREE.Vector3(), s: new THREE.Vector3(), c: new THREE.Color() };
|
|
34143
|
-
const wallColour = (items) => {
|
|
34144
|
-
for (const it of items) {
|
|
34145
|
-
if (!it.mesh) continue;
|
|
34146
|
-
const c = it.mesh.geometry.attributes.color;
|
|
34147
|
-
if (!c) continue;
|
|
34148
|
-
const a = c.array;
|
|
34149
|
-
tmp.c.setRGB(a[it.v0 * 3], a[it.v0 * 3 + 1], a[it.v0 * 3 + 2]);
|
|
34150
|
-
return tmp.c.getHex();
|
|
34151
|
-
}
|
|
34152
|
-
return null;
|
|
34153
|
-
};
|
|
34154
34167
|
const local2 = (p) => {
|
|
34155
34168
|
house.updateMatrixWorld(true);
|
|
34156
34169
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
34157
34170
|
return [v.x, v.y, v.z];
|
|
34158
34171
|
};
|
|
34159
|
-
function
|
|
34172
|
+
function cells(part, units) {
|
|
34160
34173
|
const [u0, v0, u1, v1] = part.aabb;
|
|
34161
34174
|
const alongU = u1 - u0 >= v1 - v0;
|
|
34162
34175
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
34163
|
-
const thick = alongU ? v1 - v0 : u1 - u0;
|
|
34164
34176
|
const [ul, uh] = units.size;
|
|
34165
34177
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
34166
34178
|
const rowH = (part.y1 - part.y0) / rows;
|
|
34167
34179
|
const per = Math.max(1, Math.round(len / ul));
|
|
34168
34180
|
const w = len / per;
|
|
34169
|
-
const
|
|
34170
|
-
const list2 = [];
|
|
34181
|
+
const out = [];
|
|
34171
34182
|
for (let r = 0; r < rows; r++) {
|
|
34172
34183
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
34173
|
-
|
|
34174
|
-
|
|
34175
|
-
|
|
34176
|
-
a = Math.max(0, a);
|
|
34177
|
-
b = Math.min(len, b);
|
|
34178
|
-
if (b - a < 1e-3) continue;
|
|
34179
|
-
const mid = (a + b) / 2;
|
|
34180
|
-
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
34181
|
-
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
34182
|
-
const y = part.y0 + (r + 0.5) * rowH;
|
|
34183
|
-
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
34184
|
-
if (opening && d < opening.radius) continue;
|
|
34185
|
-
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);
|
|
34186
|
-
if (chips2.some(gone)) continue;
|
|
34187
|
-
const near = opening && d < opening.radius + 0.25 || chips2.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
34188
|
-
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint2 === null ? edge : paint2 });
|
|
34184
|
+
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
34185
|
+
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
34186
|
+
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
34189
34187
|
}
|
|
34190
34188
|
}
|
|
34191
|
-
return
|
|
34189
|
+
return out;
|
|
34192
34190
|
}
|
|
34193
34191
|
const specOf = (id) => opts.spec()?.parts?.find((q) => q.id === id);
|
|
34194
34192
|
const same = (a, b) => a.every((x, k) => Math.abs(x - b[k]) < 1e-3);
|
|
@@ -34202,6 +34200,137 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34202
34200
|
return null;
|
|
34203
34201
|
}
|
|
34204
34202
|
const riders = (hostId) => structure.parts.filter((q) => q.id !== hostId && specOf(q.id)?.units && hostOf(q.id) === hostId && !structure.meshesOf(q.id).some((it) => it.mesh)).map((q) => q.id);
|
|
34203
|
+
function shell(it, mask) {
|
|
34204
|
+
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
34205
|
+
const src = it.mesh.userData._p0 || g0.attributes.position.array;
|
|
34206
|
+
for (const [name, attr] of Object.entries(g0.attributes)) {
|
|
34207
|
+
const k = attr.itemSize;
|
|
34208
|
+
g.setAttribute(name, new THREE.BufferAttribute((name === "position" ? src : attr.array).slice(it.v0 * k, it.v1 * k), k));
|
|
34209
|
+
}
|
|
34210
|
+
if (g0.index) {
|
|
34211
|
+
const ix = g0.index.array.slice(it.i0, it.i1);
|
|
34212
|
+
for (let k = 0; k < ix.length; k++) ix[k] -= it.v0;
|
|
34213
|
+
g.setIndex(new THREE.BufferAttribute(ix, 1));
|
|
34214
|
+
}
|
|
34215
|
+
g.computeBoundingBox();
|
|
34216
|
+
g.computeBoundingSphere();
|
|
34217
|
+
const base = it.mesh.material;
|
|
34218
|
+
const material = base.clone();
|
|
34219
|
+
const toHouse = { value: new THREE.Matrix4() };
|
|
34220
|
+
material.onBeforeCompile = (sh) => {
|
|
34221
|
+
base.onBeforeCompile?.(sh);
|
|
34222
|
+
sh.uniforms.uToHouse = toHouse;
|
|
34223
|
+
sh.uniforms.uMask = { value: mask.texture };
|
|
34224
|
+
sh.uniforms.uMaskRect = { value: mask.rect };
|
|
34225
|
+
sh.uniforms.uMaskAlongX = { value: mask.alongU ? 1 : 0 };
|
|
34226
|
+
sh.vertexShader = sh.vertexShader.replace("void main() {", "uniform mat4 uToHouse;\nvarying vec3 vHousePos;\nvoid main() {").replace("#include <begin_vertex>", "#include <begin_vertex>\nvHousePos = (uToHouse * vec4(transformed, 1.0)).xyz;");
|
|
34227
|
+
sh.fragmentShader = sh.fragmentShader.replace("void main() {", "uniform sampler2D uMask;\nuniform vec4 uMaskRect;\nuniform float uMaskAlongX;\nvarying vec3 vHousePos;\nvoid main() {\n vec2 mUv = vec2(((uMaskAlongX > 0.5 ? vHousePos.x : vHousePos.z) - uMaskRect.x) / uMaskRect.z, (vHousePos.y - uMaskRect.y) / uMaskRect.w);\n if (mUv.x >= 0.0 && mUv.x <= 1.0 && mUv.y >= 0.0 && mUv.y <= 1.0 && texture2D(uMask, mUv).r > 0.5) discard;");
|
|
34228
|
+
};
|
|
34229
|
+
material.customProgramCacheKey = () => "breachMask" + (base.customProgramCacheKey?.() ?? "");
|
|
34230
|
+
const mesh3 = new THREE.Mesh(g, material);
|
|
34231
|
+
mesh3.name = "breach-shell";
|
|
34232
|
+
mesh3.userData.breachMask = mask;
|
|
34233
|
+
mesh3.position.copy(it.mesh.position);
|
|
34234
|
+
mesh3.quaternion.copy(it.mesh.quaternion);
|
|
34235
|
+
mesh3.scale.copy(it.mesh.scale);
|
|
34236
|
+
mesh3.castShadow = it.mesh.castShadow;
|
|
34237
|
+
mesh3.receiveShadow = it.mesh.receiveShadow;
|
|
34238
|
+
mesh3.renderOrder = it.mesh.renderOrder;
|
|
34239
|
+
mesh3.onBeforeRender = () => {
|
|
34240
|
+
house.updateMatrixWorld();
|
|
34241
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh3.matrixWorld);
|
|
34242
|
+
};
|
|
34243
|
+
it.mesh.parent.add(mesh3);
|
|
34244
|
+
mesh3.updateMatrixWorld(true);
|
|
34245
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh3.matrixWorld);
|
|
34246
|
+
return mesh3;
|
|
34247
|
+
}
|
|
34248
|
+
function maskOf(hostId, parts) {
|
|
34249
|
+
const host = structure.byId.get(hostId);
|
|
34250
|
+
const [u0, v0, u1, v1] = host.aabb;
|
|
34251
|
+
const alongU = u1 - u0 >= v1 - v0;
|
|
34252
|
+
const y0 = Math.min(...parts.map((id) => structure.byId.get(id).y0)), y1 = Math.max(...parts.map((id) => structure.byId.get(id).y1));
|
|
34253
|
+
const len = alongU ? u1 - u0 : v1 - v0;
|
|
34254
|
+
const w = Math.max(2, Math.min(2048, Math.ceil(len / MASK_TEXEL))), h = Math.max(2, Math.min(1024, Math.ceil((y1 - y0) / MASK_TEXEL)));
|
|
34255
|
+
const data = new Uint8Array(w * h);
|
|
34256
|
+
const texture = new THREE.DataTexture(data, w, h, THREE.RedFormat);
|
|
34257
|
+
texture.magFilter = THREE.LinearFilter;
|
|
34258
|
+
texture.minFilter = THREE.LinearFilter;
|
|
34259
|
+
texture.needsUpdate = true;
|
|
34260
|
+
return { data, texture, w, h, alongU, start: alongU ? u0 : v0, len, y0, height: y1 - y0, rect: new THREE.Vector4(alongU ? u0 : v0, y0, len, y1 - y0) };
|
|
34261
|
+
}
|
|
34262
|
+
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
34263
|
+
function paint2(view) {
|
|
34264
|
+
const { mask } = view;
|
|
34265
|
+
const along = (p) => (mask.alongU ? p[0] : p[2]) - mask.start;
|
|
34266
|
+
const holes = [];
|
|
34267
|
+
const discs = [];
|
|
34268
|
+
const shown = [];
|
|
34269
|
+
for (const id of view.parts) {
|
|
34270
|
+
const part = structure.byId.get(id), units2 = specOf(id).units, chips2 = view.chips.get(id), opening = view.openings.get(id);
|
|
34271
|
+
const all = cells(part, units2);
|
|
34272
|
+
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
34273
|
+
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
34274
|
+
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
34275
|
+
const gone = (c) => chips2.some((p) => p[1] >= c.y0 && p[1] <= c.y1 && along(p) >= c.a && along(p) <= c.b) || opening && Math.hypot((c.a + c.b) / 2 - along(opening.center), (c.y0 + c.y1) / 2 - opening.center[1]) < opening.radius;
|
|
34276
|
+
const kept = [];
|
|
34277
|
+
for (const c of all) (gone(c) ? holes : kept).push(c);
|
|
34278
|
+
for (const c of kept) shown.push({ c, part, units: units2, thick, mid });
|
|
34279
|
+
}
|
|
34280
|
+
const reach = SPALL_MIN + SPALL_RAGGED;
|
|
34281
|
+
mask.data.fill(0);
|
|
34282
|
+
const stamp = (s0, s1, y0, y1, inside2) => {
|
|
34283
|
+
const i0 = Math.max(0, Math.floor((s0 - reach) / mask.len * mask.w)), i1 = Math.min(mask.w - 1, Math.ceil((s1 + reach) / mask.len * mask.w));
|
|
34284
|
+
const j0 = Math.max(0, Math.floor((y0 - reach - mask.y0) / mask.height * mask.h)), j1 = Math.min(mask.h - 1, Math.ceil((y1 + reach - mask.y0) / mask.height * mask.h));
|
|
34285
|
+
for (let j = j0; j <= j1; j++) {
|
|
34286
|
+
const y = mask.y0 + (j + 0.5) / mask.h * mask.height;
|
|
34287
|
+
for (let i = i0; i <= i1; i++) {
|
|
34288
|
+
const s = (i + 0.5) / mask.w * mask.len;
|
|
34289
|
+
const edge = SPALL_MIN + SPALL_RAGGED * (0.6 * noise2(s, y, 0.03) + 0.4 * noise2(s + 7.3, y - 3.1, 0.011));
|
|
34290
|
+
if (inside2(s, y) <= edge) mask.data[j * mask.w + i] = 255;
|
|
34291
|
+
}
|
|
34292
|
+
}
|
|
34293
|
+
};
|
|
34294
|
+
for (const c of holes) stamp(c.a, c.b, c.y0, c.y1, (s, y) => boxDistance(s, y, c.a, c.b, c.y0, c.y1));
|
|
34295
|
+
for (const d of discs) stamp(d.s - d.r, d.s + d.r, d.y - d.r, d.y + d.r, (s, y) => Math.max(0, Math.hypot(s - d.s, y - d.y) - d.r));
|
|
34296
|
+
mask.texture.needsUpdate = true;
|
|
34297
|
+
const near = (c) => holes.some((h) => boxDistance((c.a + c.b) / 2, (c.y0 + c.y1) / 2, h.a - (c.b - c.a) / 2, h.b + (c.b - c.a) / 2, h.y0 - (c.y1 - c.y0) / 2, h.y1 + (c.y1 - c.y0) / 2) <= reach) || discs.some((d) => boxDistance(d.s, d.y, c.a, c.b, c.y0, c.y1) <= d.r + reach);
|
|
34298
|
+
const list2 = [];
|
|
34299
|
+
const tone = (hex2, k) => tmp.c.setHex(hex2).multiplyScalar(k).getHex();
|
|
34300
|
+
for (const { c, part, units: units2, thick, mid } of shown) {
|
|
34301
|
+
if (!near(c)) continue;
|
|
34302
|
+
const centre = mask.start + (c.a + c.b) / 2, y = (c.y0 + c.y1) / 2, len = c.b - c.a, h = c.y1 - c.y0;
|
|
34303
|
+
const at3 = (s, dy, d, colour) => list2.push({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour });
|
|
34304
|
+
const base = fragmentMaterial(part.material).color.getHex();
|
|
34305
|
+
const n = noise2(centre * 3.1, y * 2.7, 0.07);
|
|
34306
|
+
if (units2.mortar === "concrete") {
|
|
34307
|
+
at3(len, h, thick - 2 * COVER2 - 0.03 * n, tone(base, 0.86 + 0.2 * n));
|
|
34308
|
+
} else {
|
|
34309
|
+
at3(len, h, thick - 2 * COVER2 - 0.012, 10327948);
|
|
34310
|
+
at3(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
|
|
34311
|
+
}
|
|
34312
|
+
}
|
|
34313
|
+
if (view.units) {
|
|
34314
|
+
view.units.removeFromParent();
|
|
34315
|
+
view.units.dispose();
|
|
34316
|
+
}
|
|
34317
|
+
const units = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
34318
|
+
units.name = "breach:" + view.host;
|
|
34319
|
+
list2.forEach((u, i) => {
|
|
34320
|
+
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
34321
|
+
units.setMatrixAt(i, tmp.m);
|
|
34322
|
+
units.setColorAt(i, tmp.c.setHex(u.colour));
|
|
34323
|
+
});
|
|
34324
|
+
units.count = list2.length;
|
|
34325
|
+
units.instanceMatrix.needsUpdate = true;
|
|
34326
|
+
if (units.instanceColor) units.instanceColor.needsUpdate = true;
|
|
34327
|
+
units.castShadow = true;
|
|
34328
|
+
units.receiveShadow = true;
|
|
34329
|
+
units.visible = lod === 0;
|
|
34330
|
+
house.add(units);
|
|
34331
|
+
view.units = units;
|
|
34332
|
+
view.gone = holes.length;
|
|
34333
|
+
}
|
|
34205
34334
|
function draw2(partId, change) {
|
|
34206
34335
|
if (lod !== 0) return false;
|
|
34207
34336
|
const hostId = hostOf(partId);
|
|
@@ -34211,37 +34340,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34211
34340
|
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
34212
34341
|
if (!items.length) return false;
|
|
34213
34342
|
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
34214
|
-
|
|
34343
|
+
if (!parts.includes(partId)) return false;
|
|
34344
|
+
const mask = maskOf(hostId, parts);
|
|
34345
|
+
view = { host: hostId, parts, items, mask, shells: [], saved: null, units: null, gone: 0, chips: new Map(parts.map((id) => [id, []])), openings: /* @__PURE__ */ new Map() };
|
|
34215
34346
|
}
|
|
34216
34347
|
if (!view.chips.has(partId)) return false;
|
|
34217
34348
|
if (change.opening) {
|
|
34218
34349
|
if (view.openings.has(partId)) return false;
|
|
34219
34350
|
view.openings.set(partId, { center: local2(change.opening.center), radius: change.opening.radius });
|
|
34220
|
-
if (partId === hostId) view.opening = view.openings.get(partId);
|
|
34221
34351
|
}
|
|
34222
34352
|
if (change.chip) view.chips.get(partId).push(local2(change.chip));
|
|
34223
|
-
|
|
34224
|
-
|
|
34225
|
-
|
|
34226
|
-
view.mesh.removeFromParent();
|
|
34227
|
-
view.mesh.dispose();
|
|
34353
|
+
if (!view.saved) {
|
|
34354
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
34355
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
34228
34356
|
}
|
|
34229
|
-
|
|
34230
|
-
mesh3.name = "breach:" + hostId;
|
|
34231
|
-
list2.forEach((u, i) => {
|
|
34232
|
-
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
34233
|
-
mesh3.setMatrixAt(i, tmp.m);
|
|
34234
|
-
mesh3.setColorAt(i, tmp.c.setHex(u.colour));
|
|
34235
|
-
});
|
|
34236
|
-
mesh3.count = list2.length;
|
|
34237
|
-
mesh3.instanceMatrix.needsUpdate = true;
|
|
34238
|
-
if (mesh3.instanceColor) mesh3.instanceColor.needsUpdate = true;
|
|
34239
|
-
mesh3.castShadow = true;
|
|
34240
|
-
mesh3.receiveShadow = true;
|
|
34241
|
-
house.add(mesh3);
|
|
34242
|
-
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
34243
|
-
view.mesh = mesh3;
|
|
34244
|
-
view.units = list2.length;
|
|
34357
|
+
paint2(view);
|
|
34245
34358
|
views.set(hostId, view);
|
|
34246
34359
|
invalidate();
|
|
34247
34360
|
invalidateShadow();
|
|
@@ -34253,30 +34366,40 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34253
34366
|
else s.data = collapseRange(s.it.mesh, s.v0, s.it.v1);
|
|
34254
34367
|
}
|
|
34255
34368
|
}
|
|
34369
|
+
function dispose(view) {
|
|
34370
|
+
view.units.removeFromParent();
|
|
34371
|
+
view.units.dispose();
|
|
34372
|
+
for (const m of view.shells) {
|
|
34373
|
+
m.removeFromParent();
|
|
34374
|
+
m.geometry.dispose();
|
|
34375
|
+
m.material.dispose();
|
|
34376
|
+
}
|
|
34377
|
+
view.mask.texture.dispose();
|
|
34378
|
+
}
|
|
34256
34379
|
return {
|
|
34257
|
-
/** Handles a `stage` event of the house's object. Returns true when the wall was
|
|
34380
|
+
/** Handles a `stage` event of the house's object. Returns true when the wall was cut. */
|
|
34258
34381
|
stage(event) {
|
|
34259
34382
|
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
34260
34383
|
},
|
|
34261
|
-
/** Handles a `chip` event: the unit that came out leaves a
|
|
34384
|
+
/** Handles a `chip` event: the unit that came out leaves a hole in the wall where it was. Returns true when the wall was cut. */
|
|
34262
34385
|
chip(event) {
|
|
34263
34386
|
return draw2(event.part, { chip: event.center });
|
|
34264
34387
|
},
|
|
34265
|
-
/** The part broke or fell:
|
|
34388
|
+
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
34266
34389
|
drop(partId) {
|
|
34267
34390
|
const v = views.get(partId);
|
|
34268
34391
|
if (!v) return;
|
|
34269
|
-
v
|
|
34270
|
-
v.mesh.dispose();
|
|
34392
|
+
dispose(v);
|
|
34271
34393
|
views.delete(partId);
|
|
34272
34394
|
},
|
|
34273
|
-
/** LOD 0 draws the
|
|
34395
|
+
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
34274
34396
|
setLod(level) {
|
|
34275
34397
|
const was = lod;
|
|
34276
34398
|
lod = level;
|
|
34277
34399
|
if (was === 0 === (level === 0)) return;
|
|
34278
34400
|
for (const v of views.values()) {
|
|
34279
|
-
v.
|
|
34401
|
+
v.units.visible = level === 0;
|
|
34402
|
+
for (const m of v.shells) m.visible = level === 0;
|
|
34280
34403
|
plain2(v, level !== 0);
|
|
34281
34404
|
}
|
|
34282
34405
|
invalidate();
|
|
@@ -34285,17 +34408,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34285
34408
|
/** Everything back to what it was (after `world.reset`). */
|
|
34286
34409
|
restore() {
|
|
34287
34410
|
for (const v of views.values()) {
|
|
34288
|
-
v
|
|
34289
|
-
v.mesh.dispose();
|
|
34411
|
+
dispose(v);
|
|
34290
34412
|
if (lod === 0) plain2(v, true);
|
|
34291
34413
|
}
|
|
34292
34414
|
views.clear();
|
|
34293
34415
|
},
|
|
34294
|
-
/** The wall
|
|
34416
|
+
/** The wall has damage drawn. */
|
|
34295
34417
|
has(partId) {
|
|
34296
34418
|
return views.has(partId);
|
|
34297
34419
|
},
|
|
34298
|
-
|
|
34420
|
+
/** Walls with damage drawn, units out of them, and units laid bare at the edge of the cuts. */
|
|
34421
|
+
statistics: () => ({
|
|
34422
|
+
walls: views.size,
|
|
34423
|
+
gone: [...views.values()].reduce((n, v) => n + v.gone, 0),
|
|
34424
|
+
units: [...views.values()].reduce((n, v) => n + v.units.count, 0)
|
|
34425
|
+
})
|
|
34299
34426
|
};
|
|
34300
34427
|
}
|
|
34301
34428
|
Object.assign(K, { createBreachView });
|
|
@@ -39098,8 +39225,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39098
39225
|
bedHeight = roadY * 1e3 + z * 14 - (x - params.roadSlopeAnchorX) * 5;
|
|
39099
39226
|
roughness = 0.55;
|
|
39100
39227
|
}
|
|
39101
|
-
const
|
|
39102
|
-
bed[index] = bedHeight + (
|
|
39228
|
+
const noise3 = valueNoise(column * 0.35, row * 0.35) * 0.6 + valueNoise(column * 1.3, row * 1.3) * 0.4;
|
|
39229
|
+
bed[index] = bedHeight + (noise3 - 0.5) * roughness * 2;
|
|
39103
39230
|
vertical[index] = region === 0 || region === 2 ? 0.95 : 1;
|
|
39104
39231
|
pin[index] = 0.62 + 0.76 * (valueNoise(column * 0.21 + 40, row * 0.21) * 0.5 + hashCell(column, row) * 0.5) * (region === 3 ? 1.25 : 1);
|
|
39105
39232
|
}
|
|
@@ -39574,6 +39701,55 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39574
39701
|
ends: 22e-5
|
|
39575
39702
|
}
|
|
39576
39703
|
}
|
|
39704
|
+
},
|
|
39705
|
+
plastic_bottle: {
|
|
39706
|
+
models: [
|
|
39707
|
+
"water_bottle",
|
|
39708
|
+
"water_jug_5l",
|
|
39709
|
+
"dirty_water",
|
|
39710
|
+
"sports_drink",
|
|
39711
|
+
"coconut_water",
|
|
39712
|
+
"cooking_oil",
|
|
39713
|
+
"alcohol_70",
|
|
39714
|
+
"fuel_jerrycan"
|
|
39715
|
+
],
|
|
39716
|
+
rule: {
|
|
39717
|
+
hollow: true,
|
|
39718
|
+
welded: true,
|
|
39719
|
+
skinTags: [
|
|
39720
|
+
"paper",
|
|
39721
|
+
"food"
|
|
39722
|
+
],
|
|
39723
|
+
materials: {
|
|
39724
|
+
glass: "plastic"
|
|
39725
|
+
}
|
|
39726
|
+
}
|
|
39727
|
+
},
|
|
39728
|
+
glass_bottle: {
|
|
39729
|
+
models: [
|
|
39730
|
+
"cachaca",
|
|
39731
|
+
"communion_wine",
|
|
39732
|
+
"honey_jar",
|
|
39733
|
+
"home_preserves"
|
|
39734
|
+
],
|
|
39735
|
+
rule: {
|
|
39736
|
+
hollow: true,
|
|
39737
|
+
welded: true,
|
|
39738
|
+
skinTags: [
|
|
39739
|
+
"paper",
|
|
39740
|
+
"food"
|
|
39741
|
+
]
|
|
39742
|
+
}
|
|
39743
|
+
},
|
|
39744
|
+
drink_carton: {
|
|
39745
|
+
models: [
|
|
39746
|
+
"juice_box",
|
|
39747
|
+
"milk_carton"
|
|
39748
|
+
],
|
|
39749
|
+
rule: {
|
|
39750
|
+
hollow: true,
|
|
39751
|
+
welded: true
|
|
39752
|
+
}
|
|
39577
39753
|
}
|
|
39578
39754
|
},
|
|
39579
39755
|
contents: {
|
|
@@ -39589,6 +39765,67 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39589
39765
|
liquid: "soda",
|
|
39590
39766
|
fill: 0.95
|
|
39591
39767
|
},
|
|
39768
|
+
water_bottle: {
|
|
39769
|
+
liquid: "water",
|
|
39770
|
+
fill: 0.95
|
|
39771
|
+
},
|
|
39772
|
+
water_jug_5l: {
|
|
39773
|
+
liquid: "water",
|
|
39774
|
+
fill: 0.95,
|
|
39775
|
+
box: true
|
|
39776
|
+
},
|
|
39777
|
+
dirty_water: {
|
|
39778
|
+
liquid: "water",
|
|
39779
|
+
fill: 0.9
|
|
39780
|
+
},
|
|
39781
|
+
sports_drink: {
|
|
39782
|
+
liquid: "juice",
|
|
39783
|
+
fill: 0.95
|
|
39784
|
+
},
|
|
39785
|
+
coconut_water: {
|
|
39786
|
+
liquid: "water",
|
|
39787
|
+
fill: 0.9,
|
|
39788
|
+
box: true
|
|
39789
|
+
},
|
|
39790
|
+
juice_box: {
|
|
39791
|
+
liquid: "juice",
|
|
39792
|
+
fill: 0.95,
|
|
39793
|
+
box: true
|
|
39794
|
+
},
|
|
39795
|
+
milk_carton: {
|
|
39796
|
+
liquid: "milk",
|
|
39797
|
+
fill: 0.95,
|
|
39798
|
+
box: true
|
|
39799
|
+
},
|
|
39800
|
+
cachaca: {
|
|
39801
|
+
liquid: "spirits",
|
|
39802
|
+
fill: 0.9
|
|
39803
|
+
},
|
|
39804
|
+
communion_wine: {
|
|
39805
|
+
liquid: "wine",
|
|
39806
|
+
fill: 0.9
|
|
39807
|
+
},
|
|
39808
|
+
cooking_oil: {
|
|
39809
|
+
liquid: "cooking_oil",
|
|
39810
|
+
fill: 0.9
|
|
39811
|
+
},
|
|
39812
|
+
alcohol_70: {
|
|
39813
|
+
liquid: "spirits",
|
|
39814
|
+
fill: 0.9
|
|
39815
|
+
},
|
|
39816
|
+
honey_jar: {
|
|
39817
|
+
liquid: "honey",
|
|
39818
|
+
fill: 0.85
|
|
39819
|
+
},
|
|
39820
|
+
home_preserves: {
|
|
39821
|
+
liquid: "water",
|
|
39822
|
+
fill: 0.5
|
|
39823
|
+
},
|
|
39824
|
+
fuel_jerrycan: {
|
|
39825
|
+
liquid: "fuel",
|
|
39826
|
+
fill: 0.85,
|
|
39827
|
+
box: true
|
|
39828
|
+
},
|
|
39592
39829
|
canned_beans: {
|
|
39593
39830
|
liquid: "juice",
|
|
39594
39831
|
fill: 0.4
|
|
@@ -56211,6 +56448,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
56211
56448
|
for (const decal2 of this.decals) decal2.on = false;
|
|
56212
56449
|
this.count = 0;
|
|
56213
56450
|
}
|
|
56451
|
+
/**
|
|
56452
|
+
* Takes away the marks inside a box: world `center`, `half` extents along the axes of the world `rotation` (a quaternion, x y z w; none means the
|
|
56453
|
+
* world axes). The surface they were on is gone (a brick came out of a wall with its bullet holes). Returns how many went.
|
|
56454
|
+
*/
|
|
56455
|
+
clearInside(center, half, rotation = [0, 0, 0, 1]) {
|
|
56456
|
+
const qx = -rotation[0], qy = -rotation[1], qz = -rotation[2], qw = rotation[3];
|
|
56457
|
+
let gone = 0;
|
|
56458
|
+
for (const decal2 of this.decals) {
|
|
56459
|
+
if (!decal2.on) continue;
|
|
56460
|
+
const vx2 = decal2.x - center[0], vy2 = decal2.y - center[1], vz2 = decal2.z - center[2];
|
|
56461
|
+
const tx = 2 * (qy * vz2 - qz * vy2), ty = 2 * (qz * vx2 - qx * vz2), tz = 2 * (qx * vy2 - qy * vx2);
|
|
56462
|
+
const lx = vx2 + qw * tx + (qy * tz - qz * ty), ly = vy2 + qw * ty + (qz * tx - qx * tz), lz = vz2 + qw * tz + (qx * ty - qy * tx);
|
|
56463
|
+
if (Math.abs(lx) > half[0] || Math.abs(ly) > half[1] || Math.abs(lz) > half[2]) continue;
|
|
56464
|
+
decal2.on = false;
|
|
56465
|
+
gone++;
|
|
56466
|
+
}
|
|
56467
|
+
return gone;
|
|
56468
|
+
}
|
|
56214
56469
|
update(dt) {
|
|
56215
56470
|
this.count = 0;
|
|
56216
56471
|
for (const decal2 of this.decals) {
|