@adatechnology/game-items-three 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.global.js +200 -73
- package/dist/index.global.js.map +1 -1
- package/package.json +9 -9
package/dist/index.global.js
CHANGED
|
@@ -2640,8 +2640,8 @@ var GameItemsThree = (() => {
|
|
|
2640
2640
|
bedHeight = roadY * 1e3 + z * 14 - (x - params.roadSlopeAnchorX) * 5;
|
|
2641
2641
|
roughness = 0.55;
|
|
2642
2642
|
}
|
|
2643
|
-
const
|
|
2644
|
-
bed[index] = bedHeight + (
|
|
2643
|
+
const noise3 = valueNoise(column * 0.35, row * 0.35) * 0.6 + valueNoise(column * 1.3, row * 1.3) * 0.4;
|
|
2644
|
+
bed[index] = bedHeight + (noise3 - 0.5) * roughness * 2;
|
|
2645
2645
|
vertical[index] = region === 0 || region === 2 ? 0.95 : 1;
|
|
2646
2646
|
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);
|
|
2647
2647
|
}
|
|
@@ -14207,6 +14207,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14207
14207
|
},
|
|
14208
14208
|
hitDebris: "chips",
|
|
14209
14209
|
breakDebris: "dust",
|
|
14210
|
+
visual: { innerColor: 10197652 },
|
|
14210
14211
|
thermal: {
|
|
14211
14212
|
conductivity: 0.15,
|
|
14212
14213
|
heatCapacity: 2.5
|
|
@@ -14237,6 +14238,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14237
14238
|
],
|
|
14238
14239
|
hitDebris: "chips",
|
|
14239
14240
|
breakDebris: "dust",
|
|
14241
|
+
visual: { innerColor: 12085567 },
|
|
14240
14242
|
thermal: {
|
|
14241
14243
|
conductivity: 0.15,
|
|
14242
14244
|
heatCapacity: 2.5
|
|
@@ -14267,6 +14269,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14267
14269
|
],
|
|
14268
14270
|
hitDebris: "dust",
|
|
14269
14271
|
breakDebris: "dust",
|
|
14272
|
+
visual: { innerColor: 14999507 },
|
|
14270
14273
|
thermal: {
|
|
14271
14274
|
conductivity: 0.1,
|
|
14272
14275
|
heatCapacity: 1.5
|
|
@@ -14292,6 +14295,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14292
14295
|
],
|
|
14293
14296
|
hitDebris: "chips",
|
|
14294
14297
|
breakDebris: "dust",
|
|
14298
|
+
visual: { innerColor: 9407364 },
|
|
14295
14299
|
thermal: {
|
|
14296
14300
|
conductivity: 0.2,
|
|
14297
14301
|
heatCapacity: 2.5
|
|
@@ -15049,6 +15053,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15049
15053
|
var CHIP_ENERGY = 200;
|
|
15050
15054
|
var CHIP_SPLASH = 0.5;
|
|
15051
15055
|
var BAR_BOW = 0.08;
|
|
15056
|
+
var BULLET_JOINT_SPAN = 0.3;
|
|
15052
15057
|
var CUT_SLICE = 1;
|
|
15053
15058
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
15054
15059
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -16175,7 +16180,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16175
16180
|
emit({ ...base(o, src), type: "crack", part: p.spec.id, crack, worldPoint: wp });
|
|
16176
16181
|
setStage(o, p, 1, {}, src);
|
|
16177
16182
|
};
|
|
16178
|
-
const debris = (o, p, kind, point, normal, count, speed, src) => emit({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed });
|
|
16183
|
+
const debris = (o, p, kind, point, normal, count, speed, src, material) => emit({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed, ...material && material !== p.spec.material ? { material } : {} });
|
|
16179
16184
|
const holeRate = (hole, pressurized) => (pressurized ? 0.5 : 0.1) * (hole.diameter / 9e-3);
|
|
16180
16185
|
const detachEvents = (o, opened, by, src) => {
|
|
16181
16186
|
for (const j of opened) emit({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
|
|
@@ -16216,7 +16221,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16216
16221
|
const small = pa.dims[0] * pa.dims[1] * pa.dims[2] <= pb.dims[0] * pb.dims[1] * pb.dims[2] ? pa : pb;
|
|
16217
16222
|
return Math.max(0.06, 0.5 * Math.min(small.dims[0], small.dims[1], small.dims[2]));
|
|
16218
16223
|
};
|
|
16219
|
-
const
|
|
16224
|
+
const jointLength = (o, j) => {
|
|
16225
|
+
const A = partWorldAabb(o, o.parts[j.ia]), B = partWorldAabb(o, o.parts[j.ib]);
|
|
16226
|
+
let len = 0;
|
|
16227
|
+
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]));
|
|
16228
|
+
return len;
|
|
16229
|
+
};
|
|
16230
|
+
const wearJoints = (o, p, amount, near, radius = 0.06, src, split = false, span) => {
|
|
16220
16231
|
if (amount <= 0) return;
|
|
16221
16232
|
const mine = (o.byPart.get(p.spec.id) ?? []).filter((j) => !j.st.open);
|
|
16222
16233
|
if (split && mine.length) amount /= mine.length;
|
|
@@ -16224,7 +16235,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16224
16235
|
if (j.st.open) continue;
|
|
16225
16236
|
if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
|
|
16226
16237
|
if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
|
|
16227
|
-
j.st.hp -= amount;
|
|
16238
|
+
j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
16228
16239
|
if (j.st.hp <= 0) {
|
|
16229
16240
|
j.st.hp = 0;
|
|
16230
16241
|
j.st.open = true;
|
|
@@ -16253,7 +16264,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16253
16264
|
if (spalls.length > MAX_SPALLS) spalls.shift();
|
|
16254
16265
|
markDamaged(p);
|
|
16255
16266
|
emit({ ...base(o, src), type: "spall", part: p.spec.id, layer: layer.index, point: wp, area: Math.PI * radius * radius });
|
|
16256
|
-
debris(o, p, layer.mat.hitDebris, wp, normal, 5, 2, src);
|
|
16267
|
+
debris(o, p, layer.mat.hitDebris, wp, normal, 5, 2, src, layer.mat.id);
|
|
16257
16268
|
setStage(o, p, 1, {}, src);
|
|
16258
16269
|
};
|
|
16259
16270
|
const crater = (o, p, wp, normal, radius, src) => {
|
|
@@ -16740,7 +16751,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16740
16751
|
if (mat.fracture !== "shatter") addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
16741
16752
|
} else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
16742
16753
|
debris(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
16743
|
-
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
16754
|
+
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
|
|
16744
16755
|
const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
|
|
16745
16756
|
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry2, d, absorbed * 0.1, 12, src);
|
|
16746
16757
|
if (!isLost(p)) tearAt(o, p, "ballistic", entry2, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
@@ -27196,6 +27207,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27196
27207
|
pos.array.set(saved, v0 * 3);
|
|
27197
27208
|
pos.needsUpdate = true;
|
|
27198
27209
|
}
|
|
27210
|
+
function noise2(x, y, cell) {
|
|
27211
|
+
const h = (i2, j2) => {
|
|
27212
|
+
const s = Math.sin(i2 * 127.1 + j2 * 311.7) * 43758.5453;
|
|
27213
|
+
return s - Math.floor(s);
|
|
27214
|
+
};
|
|
27215
|
+
const fx = x / cell, fy = y / cell, i = Math.floor(fx), j = Math.floor(fy), u = fx - i, v = fy - j;
|
|
27216
|
+
const su = u * u * (3 - 2 * u), sv = v * v * (3 - 2 * v);
|
|
27217
|
+
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;
|
|
27218
|
+
}
|
|
27219
|
+
var MASK_TEXEL = 0.02;
|
|
27220
|
+
var SPALL_MIN = 0.025;
|
|
27221
|
+
var SPALL_RAGGED = 0.045;
|
|
27222
|
+
var COVER2 = 0.015;
|
|
27199
27223
|
function installDestructionBreach(K, _shared) {
|
|
27200
27224
|
const { THREE, fragmentMaterial, invalidate, invalidateShadow } = K;
|
|
27201
27225
|
function createBreachView(opts) {
|
|
@@ -27205,55 +27229,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27205
27229
|
const unitMaterial = new THREE.MeshLambertMaterial({ color: 16777215 });
|
|
27206
27230
|
const unitGeometry = new THREE.BoxGeometry(1, 1, 1);
|
|
27207
27231
|
const tmp = { m: new THREE.Matrix4(), q: new THREE.Quaternion(), p: new THREE.Vector3(), s: new THREE.Vector3(), c: new THREE.Color() };
|
|
27208
|
-
const wallColour = (items) => {
|
|
27209
|
-
for (const it of items) {
|
|
27210
|
-
if (!it.mesh) continue;
|
|
27211
|
-
const c = it.mesh.geometry.attributes.color;
|
|
27212
|
-
if (!c) continue;
|
|
27213
|
-
const a = c.array;
|
|
27214
|
-
tmp.c.setRGB(a[it.v0 * 3], a[it.v0 * 3 + 1], a[it.v0 * 3 + 2]);
|
|
27215
|
-
return tmp.c.getHex();
|
|
27216
|
-
}
|
|
27217
|
-
return null;
|
|
27218
|
-
};
|
|
27219
27232
|
const local = (p) => {
|
|
27220
27233
|
house.updateMatrixWorld(true);
|
|
27221
27234
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
27222
27235
|
return [v.x, v.y, v.z];
|
|
27223
27236
|
};
|
|
27224
|
-
function
|
|
27237
|
+
function cells(part, units) {
|
|
27225
27238
|
const [u0, v0, u1, v1] = part.aabb;
|
|
27226
27239
|
const alongU = u1 - u0 >= v1 - v0;
|
|
27227
27240
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
27228
|
-
const thick = alongU ? v1 - v0 : u1 - u0;
|
|
27229
27241
|
const [ul, uh] = units.size;
|
|
27230
27242
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
27231
27243
|
const rowH = (part.y1 - part.y0) / rows;
|
|
27232
27244
|
const per = Math.max(1, Math.round(len / ul));
|
|
27233
27245
|
const w = len / per;
|
|
27234
|
-
const
|
|
27235
|
-
const list2 = [];
|
|
27246
|
+
const out = [];
|
|
27236
27247
|
for (let r = 0; r < rows; r++) {
|
|
27237
27248
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
27238
|
-
|
|
27239
|
-
|
|
27240
|
-
|
|
27241
|
-
a = Math.max(0, a);
|
|
27242
|
-
b = Math.min(len, b);
|
|
27243
|
-
if (b - a < 1e-3) continue;
|
|
27244
|
-
const mid = (a + b) / 2;
|
|
27245
|
-
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
27246
|
-
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
27247
|
-
const y = part.y0 + (r + 0.5) * rowH;
|
|
27248
|
-
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
27249
|
-
if (opening && d < opening.radius) continue;
|
|
27250
|
-
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);
|
|
27251
|
-
if (chips.some(gone)) continue;
|
|
27252
|
-
const near = opening && d < opening.radius + 0.25 || chips.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
27253
|
-
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint === null ? edge : paint });
|
|
27249
|
+
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
27250
|
+
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
27251
|
+
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
27254
27252
|
}
|
|
27255
27253
|
}
|
|
27256
|
-
return
|
|
27254
|
+
return out;
|
|
27257
27255
|
}
|
|
27258
27256
|
const specOf = (id) => opts.spec()?.parts?.find((q) => q.id === id);
|
|
27259
27257
|
const same = (a, b) => a.every((x, k) => Math.abs(x - b[k]) < 1e-3);
|
|
@@ -27267,6 +27265,137 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27267
27265
|
return null;
|
|
27268
27266
|
}
|
|
27269
27267
|
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);
|
|
27268
|
+
function shell(it, mask) {
|
|
27269
|
+
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
27270
|
+
const src = it.mesh.userData._p0 || g0.attributes.position.array;
|
|
27271
|
+
for (const [name, attr] of Object.entries(g0.attributes)) {
|
|
27272
|
+
const k = attr.itemSize;
|
|
27273
|
+
g.setAttribute(name, new THREE.BufferAttribute((name === "position" ? src : attr.array).slice(it.v0 * k, it.v1 * k), k));
|
|
27274
|
+
}
|
|
27275
|
+
if (g0.index) {
|
|
27276
|
+
const ix = g0.index.array.slice(it.i0, it.i1);
|
|
27277
|
+
for (let k = 0; k < ix.length; k++) ix[k] -= it.v0;
|
|
27278
|
+
g.setIndex(new THREE.BufferAttribute(ix, 1));
|
|
27279
|
+
}
|
|
27280
|
+
g.computeBoundingBox();
|
|
27281
|
+
g.computeBoundingSphere();
|
|
27282
|
+
const base = it.mesh.material;
|
|
27283
|
+
const material = base.clone();
|
|
27284
|
+
const toHouse = { value: new THREE.Matrix4() };
|
|
27285
|
+
material.onBeforeCompile = (sh) => {
|
|
27286
|
+
base.onBeforeCompile?.(sh);
|
|
27287
|
+
sh.uniforms.uToHouse = toHouse;
|
|
27288
|
+
sh.uniforms.uMask = { value: mask.texture };
|
|
27289
|
+
sh.uniforms.uMaskRect = { value: mask.rect };
|
|
27290
|
+
sh.uniforms.uMaskAlongX = { value: mask.alongU ? 1 : 0 };
|
|
27291
|
+
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;");
|
|
27292
|
+
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;");
|
|
27293
|
+
};
|
|
27294
|
+
material.customProgramCacheKey = () => "breachMask" + (base.customProgramCacheKey?.() ?? "");
|
|
27295
|
+
const mesh2 = new THREE.Mesh(g, material);
|
|
27296
|
+
mesh2.name = "breach-shell";
|
|
27297
|
+
mesh2.userData.breachMask = mask;
|
|
27298
|
+
mesh2.position.copy(it.mesh.position);
|
|
27299
|
+
mesh2.quaternion.copy(it.mesh.quaternion);
|
|
27300
|
+
mesh2.scale.copy(it.mesh.scale);
|
|
27301
|
+
mesh2.castShadow = it.mesh.castShadow;
|
|
27302
|
+
mesh2.receiveShadow = it.mesh.receiveShadow;
|
|
27303
|
+
mesh2.renderOrder = it.mesh.renderOrder;
|
|
27304
|
+
mesh2.onBeforeRender = () => {
|
|
27305
|
+
house.updateMatrixWorld();
|
|
27306
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh2.matrixWorld);
|
|
27307
|
+
};
|
|
27308
|
+
it.mesh.parent.add(mesh2);
|
|
27309
|
+
mesh2.updateMatrixWorld(true);
|
|
27310
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh2.matrixWorld);
|
|
27311
|
+
return mesh2;
|
|
27312
|
+
}
|
|
27313
|
+
function maskOf(hostId, parts) {
|
|
27314
|
+
const host = structure.byId.get(hostId);
|
|
27315
|
+
const [u0, v0, u1, v1] = host.aabb;
|
|
27316
|
+
const alongU = u1 - u0 >= v1 - v0;
|
|
27317
|
+
const y0 = Math.min(...parts.map((id) => structure.byId.get(id).y0)), y1 = Math.max(...parts.map((id) => structure.byId.get(id).y1));
|
|
27318
|
+
const len = alongU ? u1 - u0 : v1 - v0;
|
|
27319
|
+
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)));
|
|
27320
|
+
const data = new Uint8Array(w * h);
|
|
27321
|
+
const texture = new THREE.DataTexture(data, w, h, THREE.RedFormat);
|
|
27322
|
+
texture.magFilter = THREE.LinearFilter;
|
|
27323
|
+
texture.minFilter = THREE.LinearFilter;
|
|
27324
|
+
texture.needsUpdate = true;
|
|
27325
|
+
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) };
|
|
27326
|
+
}
|
|
27327
|
+
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
27328
|
+
function paint(view) {
|
|
27329
|
+
const { mask } = view;
|
|
27330
|
+
const along = (p) => (mask.alongU ? p[0] : p[2]) - mask.start;
|
|
27331
|
+
const holes = [];
|
|
27332
|
+
const discs = [];
|
|
27333
|
+
const shown = [];
|
|
27334
|
+
for (const id of view.parts) {
|
|
27335
|
+
const part = structure.byId.get(id), units2 = specOf(id).units, chips = view.chips.get(id), opening = view.openings.get(id);
|
|
27336
|
+
const all = cells(part, units2);
|
|
27337
|
+
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
27338
|
+
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
27339
|
+
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
27340
|
+
const gone = (c) => chips.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;
|
|
27341
|
+
const kept = [];
|
|
27342
|
+
for (const c of all) (gone(c) ? holes : kept).push(c);
|
|
27343
|
+
for (const c of kept) shown.push({ c, part, units: units2, thick, mid });
|
|
27344
|
+
}
|
|
27345
|
+
const reach = SPALL_MIN + SPALL_RAGGED;
|
|
27346
|
+
mask.data.fill(0);
|
|
27347
|
+
const stamp = (s0, s1, y0, y1, inside2) => {
|
|
27348
|
+
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));
|
|
27349
|
+
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));
|
|
27350
|
+
for (let j = j0; j <= j1; j++) {
|
|
27351
|
+
const y = mask.y0 + (j + 0.5) / mask.h * mask.height;
|
|
27352
|
+
for (let i = i0; i <= i1; i++) {
|
|
27353
|
+
const s = (i + 0.5) / mask.w * mask.len;
|
|
27354
|
+
const edge = SPALL_MIN + SPALL_RAGGED * (0.6 * noise2(s, y, 0.03) + 0.4 * noise2(s + 7.3, y - 3.1, 0.011));
|
|
27355
|
+
if (inside2(s, y) <= edge) mask.data[j * mask.w + i] = 255;
|
|
27356
|
+
}
|
|
27357
|
+
}
|
|
27358
|
+
};
|
|
27359
|
+
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));
|
|
27360
|
+
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));
|
|
27361
|
+
mask.texture.needsUpdate = true;
|
|
27362
|
+
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);
|
|
27363
|
+
const list2 = [];
|
|
27364
|
+
const tone = (hex3, k) => tmp.c.setHex(hex3).multiplyScalar(k).getHex();
|
|
27365
|
+
for (const { c, part, units: units2, thick, mid } of shown) {
|
|
27366
|
+
if (!near(c)) continue;
|
|
27367
|
+
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;
|
|
27368
|
+
const at = (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 });
|
|
27369
|
+
const base = fragmentMaterial(part.material).color.getHex();
|
|
27370
|
+
const n = noise2(centre * 3.1, y * 2.7, 0.07);
|
|
27371
|
+
if (units2.mortar === "concrete") {
|
|
27372
|
+
at(len, h, thick - 2 * COVER2 - 0.03 * n, tone(base, 0.86 + 0.2 * n));
|
|
27373
|
+
} else {
|
|
27374
|
+
at(len, h, thick - 2 * COVER2 - 0.012, 10327948);
|
|
27375
|
+
at(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
|
|
27376
|
+
}
|
|
27377
|
+
}
|
|
27378
|
+
if (view.units) {
|
|
27379
|
+
view.units.removeFromParent();
|
|
27380
|
+
view.units.dispose();
|
|
27381
|
+
}
|
|
27382
|
+
const units = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
27383
|
+
units.name = "breach:" + view.host;
|
|
27384
|
+
list2.forEach((u, i) => {
|
|
27385
|
+
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
27386
|
+
units.setMatrixAt(i, tmp.m);
|
|
27387
|
+
units.setColorAt(i, tmp.c.setHex(u.colour));
|
|
27388
|
+
});
|
|
27389
|
+
units.count = list2.length;
|
|
27390
|
+
units.instanceMatrix.needsUpdate = true;
|
|
27391
|
+
if (units.instanceColor) units.instanceColor.needsUpdate = true;
|
|
27392
|
+
units.castShadow = true;
|
|
27393
|
+
units.receiveShadow = true;
|
|
27394
|
+
units.visible = lod === 0;
|
|
27395
|
+
house.add(units);
|
|
27396
|
+
view.units = units;
|
|
27397
|
+
view.gone = holes.length;
|
|
27398
|
+
}
|
|
27270
27399
|
function draw2(partId, change) {
|
|
27271
27400
|
if (lod !== 0) return false;
|
|
27272
27401
|
const hostId = hostOf(partId);
|
|
@@ -27276,37 +27405,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27276
27405
|
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
27277
27406
|
if (!items.length) return false;
|
|
27278
27407
|
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
27279
|
-
|
|
27408
|
+
if (!parts.includes(partId)) return false;
|
|
27409
|
+
const mask = maskOf(hostId, parts);
|
|
27410
|
+
view = { host: hostId, parts, items, mask, shells: [], saved: null, units: null, gone: 0, chips: new Map(parts.map((id) => [id, []])), openings: /* @__PURE__ */ new Map() };
|
|
27280
27411
|
}
|
|
27281
27412
|
if (!view.chips.has(partId)) return false;
|
|
27282
27413
|
if (change.opening) {
|
|
27283
27414
|
if (view.openings.has(partId)) return false;
|
|
27284
27415
|
view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
|
|
27285
|
-
if (partId === hostId) view.opening = view.openings.get(partId);
|
|
27286
27416
|
}
|
|
27287
27417
|
if (change.chip) view.chips.get(partId).push(local(change.chip));
|
|
27288
|
-
|
|
27289
|
-
|
|
27290
|
-
|
|
27291
|
-
view.mesh.removeFromParent();
|
|
27292
|
-
view.mesh.dispose();
|
|
27418
|
+
if (!view.saved) {
|
|
27419
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
27420
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
27293
27421
|
}
|
|
27294
|
-
|
|
27295
|
-
mesh2.name = "breach:" + hostId;
|
|
27296
|
-
list2.forEach((u, i) => {
|
|
27297
|
-
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
27298
|
-
mesh2.setMatrixAt(i, tmp.m);
|
|
27299
|
-
mesh2.setColorAt(i, tmp.c.setHex(u.colour));
|
|
27300
|
-
});
|
|
27301
|
-
mesh2.count = list2.length;
|
|
27302
|
-
mesh2.instanceMatrix.needsUpdate = true;
|
|
27303
|
-
if (mesh2.instanceColor) mesh2.instanceColor.needsUpdate = true;
|
|
27304
|
-
mesh2.castShadow = true;
|
|
27305
|
-
mesh2.receiveShadow = true;
|
|
27306
|
-
house.add(mesh2);
|
|
27307
|
-
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
27308
|
-
view.mesh = mesh2;
|
|
27309
|
-
view.units = list2.length;
|
|
27422
|
+
paint(view);
|
|
27310
27423
|
views.set(hostId, view);
|
|
27311
27424
|
invalidate();
|
|
27312
27425
|
invalidateShadow();
|
|
@@ -27318,30 +27431,40 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27318
27431
|
else s.data = collapseRange(s.it.mesh, s.v0, s.it.v1);
|
|
27319
27432
|
}
|
|
27320
27433
|
}
|
|
27434
|
+
function dispose(view) {
|
|
27435
|
+
view.units.removeFromParent();
|
|
27436
|
+
view.units.dispose();
|
|
27437
|
+
for (const m of view.shells) {
|
|
27438
|
+
m.removeFromParent();
|
|
27439
|
+
m.geometry.dispose();
|
|
27440
|
+
m.material.dispose();
|
|
27441
|
+
}
|
|
27442
|
+
view.mask.texture.dispose();
|
|
27443
|
+
}
|
|
27321
27444
|
return {
|
|
27322
|
-
/** Handles a `stage` event of the house's object. Returns true when the wall was
|
|
27445
|
+
/** Handles a `stage` event of the house's object. Returns true when the wall was cut. */
|
|
27323
27446
|
stage(event) {
|
|
27324
27447
|
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
27325
27448
|
},
|
|
27326
|
-
/** Handles a `chip` event: the unit that came out leaves a
|
|
27449
|
+
/** 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. */
|
|
27327
27450
|
chip(event) {
|
|
27328
27451
|
return draw2(event.part, { chip: event.center });
|
|
27329
27452
|
},
|
|
27330
|
-
/** The part broke or fell:
|
|
27453
|
+
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
27331
27454
|
drop(partId) {
|
|
27332
27455
|
const v = views.get(partId);
|
|
27333
27456
|
if (!v) return;
|
|
27334
|
-
v
|
|
27335
|
-
v.mesh.dispose();
|
|
27457
|
+
dispose(v);
|
|
27336
27458
|
views.delete(partId);
|
|
27337
27459
|
},
|
|
27338
|
-
/** LOD 0 draws the
|
|
27460
|
+
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
27339
27461
|
setLod(level) {
|
|
27340
27462
|
const was = lod;
|
|
27341
27463
|
lod = level;
|
|
27342
27464
|
if (was === 0 === (level === 0)) return;
|
|
27343
27465
|
for (const v of views.values()) {
|
|
27344
|
-
v.
|
|
27466
|
+
v.units.visible = level === 0;
|
|
27467
|
+
for (const m of v.shells) m.visible = level === 0;
|
|
27345
27468
|
plain2(v, level !== 0);
|
|
27346
27469
|
}
|
|
27347
27470
|
invalidate();
|
|
@@ -27350,17 +27473,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27350
27473
|
/** Everything back to what it was (after `world.reset`). */
|
|
27351
27474
|
restore() {
|
|
27352
27475
|
for (const v of views.values()) {
|
|
27353
|
-
v
|
|
27354
|
-
v.mesh.dispose();
|
|
27476
|
+
dispose(v);
|
|
27355
27477
|
if (lod === 0) plain2(v, true);
|
|
27356
27478
|
}
|
|
27357
27479
|
views.clear();
|
|
27358
27480
|
},
|
|
27359
|
-
/** The wall
|
|
27481
|
+
/** The wall has damage drawn. */
|
|
27360
27482
|
has(partId) {
|
|
27361
27483
|
return views.has(partId);
|
|
27362
27484
|
},
|
|
27363
|
-
|
|
27485
|
+
/** Walls with damage drawn, units out of them, and units laid bare at the edge of the cuts. */
|
|
27486
|
+
statistics: () => ({
|
|
27487
|
+
walls: views.size,
|
|
27488
|
+
gone: [...views.values()].reduce((n, v) => n + v.gone, 0),
|
|
27489
|
+
units: [...views.values()].reduce((n, v) => n + v.units.count, 0)
|
|
27490
|
+
})
|
|
27364
27491
|
};
|
|
27365
27492
|
}
|
|
27366
27493
|
Object.assign(K, { createBreachView });
|