@adatechnology/game-floorplan-three 0.10.3 → 0.11.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/{chunk-JZQA7G63.js → chunk-PJ4WEP6U.js} +33 -10
- package/dist/chunk-PJ4WEP6U.js.map +1 -0
- package/dist/index.d.ts +27 -3
- package/dist/index.global.js +193 -23
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/{testing-DWLAejq6.d.ts → testing-Db8KbfLm.d.ts} +6 -0
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +13 -13
- package/dist/chunk-JZQA7G63.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RoomRects, T as Three, H as HouseRendererOptions, a as HouseRenderer, b as HouseRecord } from './testing-
|
|
2
|
-
export { A as AreaContext, B as BuildOptions, D as DEFAULT_SPECIMENS, c as Damageable, F as FLOORPLAN_AREA_ID, d as FloorplanEngineLike, e as FloorplanTestOptions, f as House, g as HouseBoxCollider, h as HouseFurnitureCollider, i as HouseInteractable, j as HouseInteractives, k as HousePart, l as HousePlan, m as HousePoint, n as HouseTargetOptions, L as LightingOptions, M as Messages, S as SPECIMEN_AT, o as SpecimenDef, p as TemplateGroup, q as Translate, r as buildSpecimenMeshes, s as createFloorplanTestModule, t as createHouseScenarios, u as createTranslator, v as en, w as locales, x as ptBR, y as specimenSpec } from './testing-
|
|
1
|
+
import { R as RoomRects, T as Three, H as HouseRendererOptions, a as HouseRenderer, b as HouseRecord } from './testing-Db8KbfLm.js';
|
|
2
|
+
export { A as AreaContext, B as BuildOptions, D as DEFAULT_SPECIMENS, c as Damageable, F as FLOORPLAN_AREA_ID, d as FloorplanEngineLike, e as FloorplanTestOptions, f as House, g as HouseBoxCollider, h as HouseFurnitureCollider, i as HouseInteractable, j as HouseInteractives, k as HousePart, l as HousePlan, m as HousePoint, n as HouseTargetOptions, L as LightingOptions, M as Messages, S as SPECIMEN_AT, o as SpecimenDef, p as TemplateGroup, q as Translate, r as buildSpecimenMeshes, s as createFloorplanTestModule, t as createHouseScenarios, u as createTranslator, v as en, w as locales, x as ptBR, y as specimenSpec } from './testing-Db8KbfLm.js';
|
|
3
3
|
import { DestructionEvent, DestructionWorld } from '@adatechnology/game-destruction';
|
|
4
4
|
import { DestructibleSpec, WarmUpProbes } from '@adatechnology/game-contracts';
|
|
5
5
|
import * as THREE_NS from 'three';
|
|
@@ -397,4 +397,28 @@ declare function wallPlan(options: WallPieceOptions): WallPlan;
|
|
|
397
397
|
*/
|
|
398
398
|
declare function wallPiece(THREE: Three, options: WallPieceOptions): WallPiece;
|
|
399
399
|
|
|
400
|
-
|
|
400
|
+
/**
|
|
401
|
+
* The outer baseboard is a band of glazed ceramic tiles (cerâmica esmaltada, 8 mm, on 4 mm of tile adhesive: 12 mm out of the plaster), the usual barrado of a
|
|
402
|
+
* facade, which takes the splashes of rain and the knocks at foot height. Each tile is a piece of its own (`baseboard:<wall>:<side>:<n>`, `length` long with a
|
|
403
|
+
* `joint` of grout between tiles), glued to the wall: a shot craters the tile it hits, more shots or a kick crack and shatter that tile and the wall shows
|
|
404
|
+
* behind it, a blast breaks the tiles it reaches, and a tile comes off when its wall goes. `BuildOptions.baseboard: 'band'` draws it as one strip per face
|
|
405
|
+
* (the Visor de casas 3D's drawing), still ceramic.
|
|
406
|
+
*/
|
|
407
|
+
declare const BASEBOARD_TILES: {
|
|
408
|
+
readonly length: 0.6;
|
|
409
|
+
readonly joint: 0.003;
|
|
410
|
+
readonly material: "ceramic";
|
|
411
|
+
readonly density: 2300;
|
|
412
|
+
};
|
|
413
|
+
/**
|
|
414
|
+
* The protective sidewalk around the walls is cast concrete (4.5 cm on the ground, 60 cm wide) cut by expansion joints every `length` metres: each slab is a
|
|
415
|
+
* piece resting on the ground, so a blast cracks, chips and breaks the slabs it reaches and a shot marks the one it hits.
|
|
416
|
+
*/
|
|
417
|
+
declare const SIDEWALK_SLABS: {
|
|
418
|
+
readonly length: 1.2;
|
|
419
|
+
readonly joint: 0.01;
|
|
420
|
+
readonly material: "concrete";
|
|
421
|
+
readonly density: 2400;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
export { BASEBOARD_TILES, type DestructibleHouse, type FloorNavigator, type FurnitureCatalogEntry, type FurnitureSpecOptions, type FurnitureSpecResult, HouseRenderer, HouseRendererOptions, type NavFlight, type NavFloor, type NavHouse, type NavHouseDef, type NavRect, type NavResult, type NavShape, type NavStair, type NavigableHouse, type NavigationDefOptions, type NavigatorBinding, OPEN_ROOM_TYPES, SIDEWALK_SLABS, type TapSpecOptions, type TapSpecResult, VERSION, type WallPiece, type WallPieceOptions, bindNavigator, create, createFloorNavigator, create as createHouseRenderer, furnitureSpec, isOpenArea, navigationDefOf, planLod, rectsOf, tapSpec, wallPiece, wallPlan };
|
package/dist/index.global.js
CHANGED
|
@@ -23,9 +23,11 @@ var GameFloorplanThree = (() => {
|
|
|
23
23
|
// src/index.ts
|
|
24
24
|
var index_exports = {};
|
|
25
25
|
__export(index_exports, {
|
|
26
|
+
BASEBOARD_TILES: () => BASEBOARD_TILES,
|
|
26
27
|
DEFAULT_SPECIMENS: () => DEFAULT_SPECIMENS,
|
|
27
28
|
FLOORPLAN_AREA_ID: () => FLOORPLAN_AREA_ID,
|
|
28
29
|
OPEN_ROOM_TYPES: () => OPEN_ROOM_TYPES,
|
|
30
|
+
SIDEWALK_SLABS: () => SIDEWALK_SLABS,
|
|
29
31
|
SPECIMEN_AT: () => SPECIMEN_AT,
|
|
30
32
|
VERSION: () => VERSION,
|
|
31
33
|
bindNavigator: () => bindNavigator,
|
|
@@ -1545,6 +1547,26 @@ var GameFloorplanThree = (() => {
|
|
|
1545
1547
|
|
|
1546
1548
|
// ../game-contracts/dist/index.js
|
|
1547
1549
|
var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
|
|
1550
|
+
var NEAREST = 0.3;
|
|
1551
|
+
function sideOnImpulse(tnt, distance2) {
|
|
1552
|
+
if (!(tnt > 0)) return 0;
|
|
1553
|
+
const w3 = Math.cbrt(tnt);
|
|
1554
|
+
const z = Math.max(distance2, NEAREST) / w3;
|
|
1555
|
+
const scaled = 0.067 * Math.sqrt(1 + (z / 0.23) ** 4) / (z * z * Math.cbrt(1 + (z / 1.55) ** 3));
|
|
1556
|
+
return scaled * w3 * 100;
|
|
1557
|
+
}
|
|
1558
|
+
var ATMOSPHERE = 101325;
|
|
1559
|
+
function sideOnOverpressure(tnt, distance2) {
|
|
1560
|
+
if (!(tnt > 0)) return 0;
|
|
1561
|
+
const z = Math.max(distance2, NEAREST) / Math.cbrt(tnt);
|
|
1562
|
+
const ratio = 808 * (1 + (z / 4.5) ** 2) / (Math.sqrt(1 + (z / 0.048) ** 2) * Math.sqrt(1 + (z / 0.32) ** 2) * Math.sqrt(1 + (z / 1.35) ** 2));
|
|
1563
|
+
return ratio * ATMOSPHERE;
|
|
1564
|
+
}
|
|
1565
|
+
function bodyImpulse(tnt, distance2) {
|
|
1566
|
+
if (!(tnt > 0)) return 0;
|
|
1567
|
+
const z = Math.max(distance2, NEAREST) / Math.cbrt(tnt);
|
|
1568
|
+
return sideOnImpulse(tnt, distance2) * (2 + 4 / (1 + z * z));
|
|
1569
|
+
}
|
|
1548
1570
|
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
1549
1571
|
var DEFAULT_IGNITION_RULES = {
|
|
1550
1572
|
fillCurve: [
|
|
@@ -6563,8 +6585,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6563
6585
|
}
|
|
6564
6586
|
|
|
6565
6587
|
// src/house/baseboard.ts
|
|
6588
|
+
var BASEBOARD_TILES = { length: 0.6, joint: 3e-3, material: "ceramic", density: 2300 };
|
|
6589
|
+
var SIDEWALK_SLABS = { length: 1.2, joint: 0.01, material: "concrete", density: 2400 };
|
|
6566
6590
|
function installHouseBaseboard(K, shared) {
|
|
6567
|
-
const { Y0, bx, cursor, sideOf } = K;
|
|
6591
|
+
const { Y0, bx, cursor, pieceRecord, sideOf } = K;
|
|
6568
6592
|
const sh = (...a) => K.sh(...a);
|
|
6569
6593
|
function baseboardAndSidewalk() {
|
|
6570
6594
|
const R = shared.ctx.r, W = 0.6, t = 0.012, ht = 0.35, color2 = sh(shared.ctx.colors.facade != null ? shared.ctx.colors.facade : 14209216, 0.62), y0 = Y0(0), cal = 13947078;
|
|
@@ -6586,15 +6610,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6586
6610
|
};
|
|
6587
6611
|
for (const A of ws) for (const [side, sd] of [[A.w.sides[0], -1], [A.w.sides[1], 1]]) {
|
|
6588
6612
|
if (!sideOf(side, false).exterior) continue;
|
|
6589
|
-
const strip = (k, y1, y2, o0, o1, mat, c,
|
|
6613
|
+
const strip = (k, y1, y2, o0, o1, mat, c, piece2, laid = BASEBOARD_TILES) => {
|
|
6590
6614
|
const ea = junction(A, A.a, sd) > 0 ? A.th / 2 + k : junction(A, A.a, sd) < 0 ? -A.th / 2 : 0, eb = junction(A, A.b, sd) > 0 ? A.th / 2 + k : junction(A, A.b, sd) < 0 ? -A.th / 2 : 0;
|
|
6591
6615
|
const s0 = A.a - ea, s1 = A.b + eb, f0 = A.L + sd * (A.th / 2 + o0), f1 = A.L + sd * (A.th / 2 + o1), lo = Math.min(f0, f1), hi = Math.max(f0, f1);
|
|
6592
6616
|
if (s1 - s0 < 1e-3) return;
|
|
6593
|
-
|
|
6594
|
-
|
|
6617
|
+
const box3 = (a, b) => {
|
|
6618
|
+
if (A.au) bx(mat, a, y1, lo, b, y2, hi, c);
|
|
6619
|
+
else bx(mat, lo, y1, a, hi, y2, b, c);
|
|
6620
|
+
};
|
|
6621
|
+
const tag = laid === BASEBOARD_TILES ? "baseboard" : "sidewalk";
|
|
6622
|
+
const tile = (id, a, b) => {
|
|
6623
|
+
cursor.pc = pieceRecord(id, laid.material, null, { floor: 0, mass: Math.round((b - a) * (y2 - y1) * (hi - lo) * laid.density * 100) / 100, tags: [tag] });
|
|
6624
|
+
box3(a, b);
|
|
6625
|
+
};
|
|
6626
|
+
if (!piece2) box3(s0, s1);
|
|
6627
|
+
else if (shared.ctx.baseboardBand) tile(piece2, s0, s1);
|
|
6628
|
+
else {
|
|
6629
|
+
const n = Math.max(1, Math.round((s1 - s0) / laid.length)), w = (s1 - s0) / n, j = laid.joint / 2;
|
|
6630
|
+
for (let i = 0; i < n; i++) tile(`${piece2}:${i}`, s0 + i * w + (i > 0 ? j : 0), s0 + (i + 1) * w - (i < n - 1 ? j : 0));
|
|
6631
|
+
}
|
|
6632
|
+
cursor.pc = null;
|
|
6595
6633
|
};
|
|
6596
|
-
strip(t, y0, y0 + ht, 0, t, "plaster", color2);
|
|
6597
|
-
strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal);
|
|
6634
|
+
strip(t, y0, y0 + ht, 0, t, "plaster", color2, A.w.id ? `baseboard:${A.w.id}:${sd < 0 ? 0 : 1}` : void 0);
|
|
6635
|
+
strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal, A.w.id ? `sidewalk:${A.w.id}:${sd < 0 ? 0 : 1}` : void 0, SIDEWALK_SLABS);
|
|
6598
6636
|
}
|
|
6599
6637
|
}
|
|
6600
6638
|
const defined = { baseboardAndSidewalk };
|
|
@@ -14182,9 +14220,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14182
14220
|
var BREACH_AREA = 0.25;
|
|
14183
14221
|
var BREACH_BLAST_REACH = 0.12;
|
|
14184
14222
|
var MEMBER_CUT_REACH = 0.5;
|
|
14223
|
+
var FAR_MEMBER_HP_FLOOR = 0.25;
|
|
14185
14224
|
var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
|
|
14186
14225
|
var BLAST_EDGE_RAGGED = 0.3;
|
|
14187
14226
|
var BLAST_EDGE_LOOSE = 1.35;
|
|
14227
|
+
var PANEL_PRESSURE = 7e4;
|
|
14228
|
+
var PANEL_IMPULSE = 150;
|
|
14229
|
+
var PANEL_PI = 6e6;
|
|
14230
|
+
var PANEL_POINTS = [[0, 0], [-0.3, 0], [0.3, 0], [0, -0.3], [0, 0.3]];
|
|
14231
|
+
var PANEL_POINTS_LOADED = 4;
|
|
14188
14232
|
var BLAST_EDGE_WEAR = 0.6;
|
|
14189
14233
|
var RESIDUAL_CAPACITY = 0.15;
|
|
14190
14234
|
var SEVER_BAND = 0.1;
|
|
@@ -14209,23 +14253,42 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14209
14253
|
const v = table[mat.penetrationClass ?? mat.id] ?? table[mat.id];
|
|
14210
14254
|
return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
|
|
14211
14255
|
};
|
|
14212
|
-
var
|
|
14256
|
+
var BURIED_BLAST_REACH = 0.5;
|
|
14257
|
+
var GIVE_AT_CUT_HP = 0.5;
|
|
14258
|
+
var capacityScale = (p, borne, through) => {
|
|
14213
14259
|
const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
|
|
14214
14260
|
if (p.st.stripped) return residual;
|
|
14215
|
-
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1,
|
|
14261
|
+
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, sectionKept(p, residual, borne, through));
|
|
14216
14262
|
return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
|
|
14217
14263
|
};
|
|
14218
|
-
var
|
|
14264
|
+
var sectionKept = (p, residual, borne, through) => {
|
|
14265
|
+
let kept = 1;
|
|
14266
|
+
forEachSection(p, borne, (c, along, gone) => {
|
|
14267
|
+
const share = through?.(c.center, along) ?? 1;
|
|
14268
|
+
if (share <= 0) return;
|
|
14269
|
+
kept = Math.min(kept, Math.max(p.spec.reinforcement ? residual : 0, 1 - gone) / share);
|
|
14270
|
+
});
|
|
14271
|
+
return kept;
|
|
14272
|
+
};
|
|
14273
|
+
var sectionLoss = (p, borne) => {
|
|
14274
|
+
let worst = 0;
|
|
14275
|
+
forEachSection(p, borne, (_c, _along, gone) => {
|
|
14276
|
+
worst = Math.max(worst, gone);
|
|
14277
|
+
});
|
|
14278
|
+
return Math.min(1, worst);
|
|
14279
|
+
};
|
|
14280
|
+
var forEachSection = (p, borne, visit) => {
|
|
14219
14281
|
const cells = p.st.chipped;
|
|
14220
|
-
if (!cells?.length) return
|
|
14282
|
+
if (!cells?.length) return;
|
|
14221
14283
|
const [u, v] = planeAxes(p.thin);
|
|
14222
14284
|
const role = p.spec.structure?.role;
|
|
14223
14285
|
const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
|
|
14224
14286
|
const upright = Math.abs(up[1]) > 0.7 ? v : Math.abs(rotateVec(p.q, [0, 0, 0].map((_, k) => k === u ? 1 : 0))[1]) > 0.7 ? u : -1;
|
|
14225
14287
|
const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
|
|
14226
14288
|
const across = along === u ? v : u;
|
|
14227
|
-
|
|
14289
|
+
const lying = along !== upright || upright < 0;
|
|
14228
14290
|
for (const c of cells) {
|
|
14291
|
+
if (lying && borne?.(c.center, along)) continue;
|
|
14229
14292
|
const spans = [];
|
|
14230
14293
|
for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) spans.push([d.center[across] - d.size[across] / 2, d.center[across] + d.size[across] / 2]);
|
|
14231
14294
|
spans.sort((a, b) => a[0] - b[0]);
|
|
@@ -14235,9 +14298,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14235
14298
|
gone += b - Math.max(a, end);
|
|
14236
14299
|
end = b;
|
|
14237
14300
|
}
|
|
14238
|
-
|
|
14301
|
+
visit(c, along, Math.min(1, gone / Math.max(p.dims[across], 1e-6)));
|
|
14239
14302
|
}
|
|
14240
|
-
return Math.min(1, worst);
|
|
14241
14303
|
};
|
|
14242
14304
|
var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
|
|
14243
14305
|
var clone = (v) => structuredClone(v);
|
|
@@ -14548,6 +14610,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14548
14610
|
byTouching.set(support, { version: poseVersion, box: box3 });
|
|
14549
14611
|
return box3;
|
|
14550
14612
|
};
|
|
14613
|
+
const throughOf = (p) => {
|
|
14614
|
+
const load = p.st.load ?? 0;
|
|
14615
|
+
if (load <= 0) return void 0;
|
|
14616
|
+
const above = Math.max(0, load - p.st.mass);
|
|
14617
|
+
const up = rotateVec(p.q, [0, 1, 0]);
|
|
14618
|
+
return (local, along) => {
|
|
14619
|
+
const axis = [0, 0, 0];
|
|
14620
|
+
axis[along] = 1;
|
|
14621
|
+
const sign2 = Math.sign(rotateVec(p.q, axis)[1]);
|
|
14622
|
+
if (Math.abs(up[1]) < 0.7 && Math.abs(rotateVec(p.q, axis)[1]) < 0.7) return 1;
|
|
14623
|
+
const half = p.dims[along] / 2;
|
|
14624
|
+
const share = clamp2((half - sign2 * local[along]) / Math.max(p.dims[along], 1e-6), 0, 1);
|
|
14625
|
+
return (above + p.st.mass * share) / load;
|
|
14626
|
+
};
|
|
14627
|
+
};
|
|
14628
|
+
const borneOn = (p, supports) => {
|
|
14629
|
+
if (supports.length === 0) return void 0;
|
|
14630
|
+
const boxes = supports.map((support) => contactBox(p, support));
|
|
14631
|
+
return (local, along) => boxes.some(([lo, hi]) => local[along] >= lo[along] - SUPPORT_TOLERANCE && local[along] <= hi[along] + SUPPORT_TOLERANCE);
|
|
14632
|
+
};
|
|
14551
14633
|
const measureContact = (p, support) => {
|
|
14552
14634
|
const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
|
|
14553
14635
|
const lo = [0, 0, 0], hi = [0, 0, 0];
|
|
@@ -14755,7 +14837,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14755
14837
|
o.unsup[i] = o.anyAnchor && !isLost(p) && !p.orphan;
|
|
14756
14838
|
continue;
|
|
14757
14839
|
}
|
|
14758
|
-
p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p));
|
|
14840
|
+
p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p, borneOn(p, (lowerOf.get(i) ?? []).map((k) => parts[k])), throughOf(p)));
|
|
14759
14841
|
if (p.bend) {
|
|
14760
14842
|
p.bendLoad = p.st.mass + bending[i];
|
|
14761
14843
|
const bent = restFlexure(o, p, lowerOf.get(i) ?? []);
|
|
@@ -15740,7 +15822,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15740
15822
|
return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
|
|
15741
15823
|
};
|
|
15742
15824
|
const blastUnits = (o, p, wp, energy, dist, src) => {
|
|
15743
|
-
var _a
|
|
15825
|
+
var _a;
|
|
15744
15826
|
if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
|
|
15745
15827
|
const reach = blastReachOf(p, energy);
|
|
15746
15828
|
if (dist >= reach) return false;
|
|
@@ -15770,6 +15852,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15770
15852
|
}
|
|
15771
15853
|
}
|
|
15772
15854
|
if (out.length === 0) return false;
|
|
15855
|
+
return knockOutUnits(o, p, wp, energy, out, src);
|
|
15856
|
+
};
|
|
15857
|
+
const blastPanel = (o, p, point, energy, src) => {
|
|
15858
|
+
var _a;
|
|
15859
|
+
if (!p.staged || p.st.stripped || isLost(p) || !p.spec.units || p.spec.units.mortar === p.spec.material || p.spec.reinforcement) return false;
|
|
15860
|
+
const [u, v] = planeAxes(p.thin);
|
|
15861
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, point));
|
|
15862
|
+
const half = p.dims[u] / 2;
|
|
15863
|
+
const posts = [];
|
|
15864
|
+
for (const m of o.parts) {
|
|
15865
|
+
if (m === p || !m.spec.reinforcement || isLost(m) || m.spec.shape.kind !== "box") continue;
|
|
15866
|
+
const mp = toLocal(p.pos, p.q, m.pos);
|
|
15867
|
+
if (Math.abs(mp[p.thin]) > p.dims[p.thin] + 0.15 || Math.abs(mp[u]) > half + 0.15 || m.dims[v] < p.dims[v] * 0.5) continue;
|
|
15868
|
+
posts.push(mp[u]);
|
|
15869
|
+
}
|
|
15870
|
+
let from = -half, to = half;
|
|
15871
|
+
for (const x of posts) {
|
|
15872
|
+
if (x <= lp[u] && x > from) from = x;
|
|
15873
|
+
if (x >= lp[u] && x < to) to = x;
|
|
15874
|
+
}
|
|
15875
|
+
if (to - from < 0.2) return false;
|
|
15876
|
+
const tnt = energy * DEFAULT_BLAST_IMPULSE.tntPerJoule;
|
|
15877
|
+
const centre = objLocal(o, point);
|
|
15878
|
+
const span = to - from, height = p.dims[v];
|
|
15879
|
+
let loaded = 0;
|
|
15880
|
+
for (const [fu, fv] of PANEL_POINTS) {
|
|
15881
|
+
const at2 = [0, 0, 0];
|
|
15882
|
+
at2[u] = (from + to) / 2 + fu * span;
|
|
15883
|
+
at2[v] = fv * height;
|
|
15884
|
+
at2[p.thin] = Math.sign(lp[p.thin]) * p.dims[p.thin] / 2;
|
|
15885
|
+
const r = vec.distance(toWorld(p.pos, p.q, at2), centre);
|
|
15886
|
+
const side = sideOnOverpressure(tnt, r);
|
|
15887
|
+
const reflected = 2 * side + 6 * side * side / (side + 7 * 101325);
|
|
15888
|
+
const impulse = bodyImpulse(tnt, r);
|
|
15889
|
+
if (reflected > PANEL_PRESSURE && impulse > PANEL_IMPULSE && (reflected - PANEL_PRESSURE) * (impulse - PANEL_IMPULSE) >= PANEL_PI) loaded++;
|
|
15890
|
+
}
|
|
15891
|
+
if (loaded < PANEL_POINTS_LOADED) return false;
|
|
15892
|
+
const grid = gridOf(p);
|
|
15893
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
15894
|
+
const out = [];
|
|
15895
|
+
for (let i = 0; i < grid.length; i++) {
|
|
15896
|
+
const cell = grid[i];
|
|
15897
|
+
if (worn[i] === -1) continue;
|
|
15898
|
+
if (cell.center[u] - cell.size[u] / 2 >= from - 1e-6 && cell.center[u] + cell.size[u] / 2 <= to + 1e-6) out.push(i);
|
|
15899
|
+
}
|
|
15900
|
+
if (out.length === 0) return false;
|
|
15901
|
+
for (const i of out) worn[i] = -1;
|
|
15902
|
+
return knockOutUnits(o, p, point, energy, out, src);
|
|
15903
|
+
};
|
|
15904
|
+
const knockOutUnits = (o, p, wp, energy, out, src) => {
|
|
15905
|
+
var _a, _b;
|
|
15906
|
+
const [u, v] = planeAxes(p.thin);
|
|
15907
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
15908
|
+
const grid = gridOf(p);
|
|
15909
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
15910
|
+
for (const i of out) worn[i] = -1;
|
|
15773
15911
|
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
|
|
15774
15912
|
for (const i of loose) worn[i] = -1;
|
|
15775
15913
|
const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
|
|
@@ -15845,6 +15983,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15845
15983
|
debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
|
|
15846
15984
|
return loose.length;
|
|
15847
15985
|
};
|
|
15986
|
+
const giveAtCut = (o, p, src) => {
|
|
15987
|
+
if (!p.spec.reinforcement || !p.spec.units || !p.st.chipped?.length || sectionLoss(p) <= 0) return false;
|
|
15988
|
+
const opened = [];
|
|
15989
|
+
for (const j of o.byPart.get(p.spec.id) ?? []) {
|
|
15990
|
+
if (j.st.open) continue;
|
|
15991
|
+
const onIt = j.bears === "a_on_b" && j.spec.b === p.spec.id || j.bears === "b_on_a" && j.spec.a === p.spec.id;
|
|
15992
|
+
if (!onIt) continue;
|
|
15993
|
+
j.st.open = true;
|
|
15994
|
+
j.st.openedBy = "break";
|
|
15995
|
+
opened.push(j);
|
|
15996
|
+
}
|
|
15997
|
+
if (opened.length === 0) return false;
|
|
15998
|
+
p.st.hp = Math.max(p.st.hp, p.st.maxHp * GIVE_AT_CUT_HP);
|
|
15999
|
+
markDamaged(p);
|
|
16000
|
+
solveStructure(o);
|
|
16001
|
+
recomputeGroups(o);
|
|
16002
|
+
detachEvents(o, opened, "break", src);
|
|
16003
|
+
exposeRebar(o, p, src);
|
|
16004
|
+
collapseCheck(o, src);
|
|
16005
|
+
return true;
|
|
16006
|
+
};
|
|
15848
16007
|
const stripPart = (o, p, reinforcement, src) => {
|
|
15849
16008
|
const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
|
|
15850
16009
|
p.st.stripped = true;
|
|
@@ -15902,6 +16061,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15902
16061
|
hingeDrop(o, p, src);
|
|
15903
16062
|
return;
|
|
15904
16063
|
}
|
|
16064
|
+
if (!force && giveAtCut(o, p, src)) return;
|
|
15905
16065
|
const ex = p.spec.explodes;
|
|
15906
16066
|
const style = force ?? (p.snap ? "snap" : p.mat.fracture === "none" ? "snap" : p.mat.fracture);
|
|
15907
16067
|
const { c, q } = partXf(o, p);
|
|
@@ -16230,12 +16390,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16230
16390
|
return reach;
|
|
16231
16391
|
}
|
|
16232
16392
|
if (Ein > 20 && p.layers.length > 0) spallOuter(o, p, wp, faceOf(o, p, wn), wn, clamp2(0.05 + Math.sqrt(Ein) * 2e-3, 0.05, 0.4), src);
|
|
16233
|
-
const
|
|
16393
|
+
const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
|
|
16394
|
+
const farMember = Boolean(p.spec.reinforcement && p.spec.units) && dist > MEMBER_CUT_REACH * breachReach;
|
|
16395
|
+
const dealt = farMember ? applyDamage(o, p, Math.min(amount, Math.max(0, p.st.hp - p.st.maxHp * FAR_MEMBER_HP_FLOOR)), "explosive", null, null, Ein * 0.3, 40, src) : applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
|
|
16234
16396
|
res.damage += dealt;
|
|
16235
16397
|
if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
|
|
16398
|
+
if (p.spec.units && p.spec.units.mortar !== p.spec.material) {
|
|
16399
|
+
blastPanel(o, p, point, energy, src);
|
|
16400
|
+
if (!isLost(p)) blastUnits(o, p, wp, energy, dist, src);
|
|
16401
|
+
} else if (farMember) blastUnits(o, p, wp, energy, dist, src);
|
|
16239
16402
|
else if (dist <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
16240
16403
|
return reach;
|
|
16241
16404
|
};
|
|
@@ -16248,7 +16411,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16248
16411
|
const dx = local[0] - p.pos[0];
|
|
16249
16412
|
const dy = local[1] - p.pos[1];
|
|
16250
16413
|
const dz = local[2] - p.pos[2];
|
|
16251
|
-
if (dx * dx + dy * dy + dz * dz
|
|
16414
|
+
if (dx * dx + dy * dy + dz * dz >= reach * reach) continue;
|
|
16415
|
+
if (p.spec.anchored && p.spec.structure?.role === "foundation" && distToPart(o, p, point) > BURIED_BLAST_REACH) continue;
|
|
16416
|
+
near.push(p);
|
|
16252
16417
|
}
|
|
16253
16418
|
blastProbe.partsTested += o.parts.length;
|
|
16254
16419
|
blastProbe.partsNear += near.length;
|
|
@@ -20670,7 +20835,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20670
20835
|
if (!b) continue;
|
|
20671
20836
|
const vol = Math.max(1e-6, (b[3] - b[0]) * (b[4] - b[1]) * (b[5] - b[2]));
|
|
20672
20837
|
const p = { id, role: "none", material: pc.mat, aabb: [b[0], b[2], b[3], b[5]], y0: b[1], y1: b[4], floor: pc.floor != null ? pc.floor : floorAtY(b[1] + 0.1), mass: pc.mass != null ? pc.mass : Math.max(0.5, vol * (DENSITY[pc.mat] || 800) * (pc.fill != null ? pc.fill : 0.15)), meshes: meshes.get(id).length, extra: true };
|
|
20673
|
-
for (const k of ["contains", "explodes", "tags", "form", "thickness", "fill"]) if (pc[k] != null) p[k] = pc[k];
|
|
20838
|
+
for (const k of ["contains", "explodes", "tags", "form", "thickness", "fill", "units"]) if (pc[k] != null) p[k] = pc[k];
|
|
20674
20839
|
parts.push(p);
|
|
20675
20840
|
byId.set(id, p);
|
|
20676
20841
|
}
|
|
@@ -20679,7 +20844,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20679
20844
|
return cx >= q.aabb[0] - m && cx <= q.aabb[2] + m && cz >= q.aabb[1] - m && cz <= q.aabb[3] + m && cy >= q.y0 - m && cy <= q.y1 + m;
|
|
20680
20845
|
};
|
|
20681
20846
|
for (const p of parts.slice(base)) {
|
|
20682
|
-
if (
|
|
20847
|
+
if (/^sidewalk:/.test(p.id)) {
|
|
20848
|
+
supports.push({ part: p.id, on: "ground", joint: "mortar", extra: true });
|
|
20849
|
+
continue;
|
|
20850
|
+
}
|
|
20851
|
+
if (!/^(window|window_pane|door|jamb|pipe|water_tank|baseboard)/.test(p.id)) continue;
|
|
20683
20852
|
const target = /^water_tank/.test(p.id) ? ["slab"] : ["wall", "partition"];
|
|
20684
20853
|
let m = null, md = 1e9;
|
|
20685
20854
|
for (const q of parts.slice(0, base)) {
|
|
@@ -20690,7 +20859,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20690
20859
|
m = q;
|
|
20691
20860
|
}
|
|
20692
20861
|
}
|
|
20693
|
-
if (m) supports.push({ part: p.id, on: m.id, joint: /^(window|jamb)/.test(p.id) ? "glue" : "clip", bears: false, extra: true });
|
|
20862
|
+
if (m) supports.push({ part: p.id, on: m.id, joint: /^(window|jamb|baseboard)/.test(p.id) ? "glue" : "clip", bears: false, extra: true });
|
|
20694
20863
|
}
|
|
20695
20864
|
const specParts = parts.slice(), specSupports = supports.slice();
|
|
20696
20865
|
if (view.panels.length) {
|
|
@@ -21792,6 +21961,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21792
21961
|
cursor.separate = opts.pieces === "meshes";
|
|
21793
21962
|
cursor.pc = null;
|
|
21794
21963
|
shared.ctx.showPillars = opts.pillars !== "hidden";
|
|
21964
|
+
shared.ctx.baseboardBand = opts.baseboard === "band";
|
|
21795
21965
|
shared.ctx.apartment = r.template === "apartment_modern";
|
|
21796
21966
|
shared.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
|
|
21797
21967
|
shared.ctx.pf = Math.max(1, Math.min(shared.ctx.pa, pr.floor != null ? pr.floor : 3));
|