@adatechnology/game-items-three 0.7.0 → 0.7.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.
@@ -89,7 +89,7 @@ var GameItemsThree = (() => {
89
89
  wearableMaterials: () => wearableMaterials
90
90
  });
91
91
 
92
- // ../game-shapes/dist/chunk-IFXQIDSA.js
92
+ // ../game-shapes/dist/chunk-M5N2SHNL.js
93
93
  function canonicalJson(value) {
94
94
  if (value === null) return "null";
95
95
  if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
@@ -1246,13 +1246,13 @@ var GameItemsThree = (() => {
1246
1246
  uvArray.push(x);
1247
1247
  uvArray.push(y);
1248
1248
  };
1249
- const at = (index, axis) => verticesArray[index * 3 + axis];
1249
+ const at2 = (index, axis) => verticesArray[index * 3 + axis];
1250
1250
  const f3 = (a, b, c) => {
1251
1251
  addVertex(a);
1252
1252
  addVertex(b);
1253
1253
  addVertex(c);
1254
1254
  const nextIndex = verticesArray.length / 3;
1255
- for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(at(index, 0), at(index, 1));
1255
+ for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(at2(index, 0), at2(index, 1));
1256
1256
  };
1257
1257
  const f4 = (a, b, c, d) => {
1258
1258
  addVertex(a);
@@ -1266,8 +1266,8 @@ var GameItemsThree = (() => {
1266
1266
  const iB = nextIndex - 3;
1267
1267
  const iC = nextIndex - 2;
1268
1268
  const iD = nextIndex - 1;
1269
- const byX = Math.abs(at(iA, 1) - at(iB, 1)) < Math.abs(at(iA, 0) - at(iB, 0));
1270
- const uv = (index) => [byX ? at(index, 0) : at(index, 1), 1 - at(index, 2)];
1269
+ const byX = Math.abs(at2(iA, 1) - at2(iB, 1)) < Math.abs(at2(iA, 0) - at2(iB, 0));
1270
+ const uv = (index) => [byX ? at2(index, 0) : at2(index, 1), 1 - at2(index, 2)];
1271
1271
  const uvs = [uv(iA), uv(iB), uv(iC), uv(iD)];
1272
1272
  for (const k of [0, 1, 3, 1, 2, 3]) addUV(...uvs[k]);
1273
1273
  };
@@ -1372,8 +1372,8 @@ var GameItemsThree = (() => {
1372
1372
  groups: []
1373
1373
  };
1374
1374
  }
1375
- function make(kind, p) {
1376
- switch (kind) {
1375
+ function make(p) {
1376
+ switch (p.kind) {
1377
1377
  case "box": {
1378
1378
  const size = p.size ?? [1, 1, 1];
1379
1379
  const segments = p.segments ?? [1, 1, 1];
@@ -1402,7 +1402,7 @@ var GameItemsThree = (() => {
1402
1402
  case "mesh":
1403
1403
  return mesh(p);
1404
1404
  default:
1405
- throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
1405
+ throw new Error(`game-shapes: unknown primitive kind "${String(p.kind)}"`);
1406
1406
  }
1407
1407
  }
1408
1408
  var templates = /* @__PURE__ */ new Map();
@@ -1410,7 +1410,7 @@ var GameItemsThree = (() => {
1410
1410
  var stats = { hits: 0, misses: 0 };
1411
1411
  function buildPrimitive(node, options = {}) {
1412
1412
  const parameters = primitiveParameters(node, options);
1413
- if (node.kind === "mesh" || templateLimit === 0) return make(node.kind, parameters);
1413
+ if (node.kind === "mesh" || templateLimit === 0) return make({ ...node, ...parameters });
1414
1414
  const key2 = `${node.kind}:${canonicalJson(parameters)}`;
1415
1415
  const cached = templates.get(key2);
1416
1416
  if (cached) {
@@ -1420,7 +1420,7 @@ var GameItemsThree = (() => {
1420
1420
  return cached;
1421
1421
  }
1422
1422
  stats.misses++;
1423
- const built = make(node.kind, parameters);
1423
+ const built = make({ ...node, ...parameters });
1424
1424
  templates.set(key2, built);
1425
1425
  if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
1426
1426
  return built;
@@ -1518,7 +1518,7 @@ var GameItemsThree = (() => {
1518
1518
  const positions2 = new Float32Array(total * 3);
1519
1519
  const normals = new Float32Array(total * 3);
1520
1520
  const uvs = new Float32Array(total * 2);
1521
- let at = 0;
1521
+ let at2 = 0;
1522
1522
  for (const piece2 of pieces) {
1523
1523
  const e = piece2.matrix;
1524
1524
  const nm = normalMatrix(e);
@@ -1532,15 +1532,15 @@ var GameItemsThree = (() => {
1532
1532
  if (piece2.normals) n[k * 3 + c] = piece2.normals[i * 3 + c];
1533
1533
  }
1534
1534
  if (piece2.uvs) {
1535
- uvs[(at + k) * 2] = piece2.uvs[i * 2];
1536
- uvs[(at + k) * 2 + 1] = piece2.uvs[i * 2 + 1];
1535
+ uvs[(at2 + k) * 2] = piece2.uvs[i * 2];
1536
+ uvs[(at2 + k) * 2 + 1] = piece2.uvs[i * 2 + 1];
1537
1537
  }
1538
1538
  }
1539
1539
  for (let k = 0; k < count; k++) {
1540
1540
  const q = transformPoint(e, p[k * 3], p[k * 3 + 1], p[k * 3 + 2]);
1541
- positions2[(at + k) * 3] = q[0];
1542
- positions2[(at + k) * 3 + 1] = q[1];
1543
- positions2[(at + k) * 3 + 2] = q[2];
1541
+ positions2[(at2 + k) * 3] = q[0];
1542
+ positions2[(at2 + k) * 3 + 1] = q[1];
1543
+ positions2[(at2 + k) * 3 + 2] = q[2];
1544
1544
  const x = n[k * 3];
1545
1545
  const y = n[k * 3 + 1];
1546
1546
  const z = n[k * 3 + 2];
@@ -1548,16 +1548,17 @@ var GameItemsThree = (() => {
1548
1548
  const vy = nm[1] * x + nm[4] * y + nm[7] * z;
1549
1549
  const vz = nm[2] * x + nm[5] * y + nm[8] * z;
1550
1550
  const s = 1 / (Math.sqrt(vx * vx + vy * vy + vz * vz) || 1);
1551
- normals[(at + k) * 3] = vx * s;
1552
- normals[(at + k) * 3 + 1] = vy * s;
1553
- normals[(at + k) * 3 + 2] = vz * s;
1551
+ normals[(at2 + k) * 3] = vx * s;
1552
+ normals[(at2 + k) * 3 + 1] = vy * s;
1553
+ normals[(at2 + k) * 3 + 2] = vz * s;
1554
1554
  }
1555
- at += count;
1555
+ at2 += count;
1556
1556
  }
1557
1557
  return { positions: positions2, normals, uvs };
1558
1558
  }
1559
1559
 
1560
1560
  // ../game-contracts/dist/index.js
1561
+ var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
1561
1562
  var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
1562
1563
  var DEFAULT_IGNITION_RULES = {
1563
1564
  fillCurve: [
@@ -11385,17 +11386,17 @@ var GameItemsThree = (() => {
11385
11386
  const index = geometry2.index ? geometry2.index.array : null;
11386
11387
  const count = index ? index.length : position.count;
11387
11388
  for (let item = 0; item < count; item++) {
11388
- const at = index ? index[item] : item;
11389
- vertex.fromBufferAttribute(position, at).applyMatrix4(matrix);
11389
+ const at2 = index ? index[item] : item;
11390
+ vertex.fromBufferAttribute(position, at2).applyMatrix4(matrix);
11390
11391
  positions2.push(vertex.x, vertex.y, vertex.z);
11391
- if (normalAttribute) normal.fromBufferAttribute(normalAttribute, at).applyMatrix3(normalMatrix2).normalize();
11392
+ if (normalAttribute) normal.fromBufferAttribute(normalAttribute, at2).applyMatrix3(normalMatrix2).normalize();
11392
11393
  else normal.set(0, 1, 0);
11393
11394
  normals.push(normal.x, normal.y, normal.z);
11394
11395
  color2.copy(material2.color || color2.set(1, 1, 1)).convertLinearToSRGB();
11395
11396
  if (sample && uv && material2.map) {
11396
11397
  const repeat = material2.map.repeat;
11397
- const u = (uv.getX(at) * repeat.x % 1 + 1) % 1;
11398
- const v = (uv.getY(at) * repeat.y % 1 + 1) % 1;
11398
+ const u = (uv.getX(at2) * repeat.x % 1 + 1) % 1;
11399
+ const v = (uv.getY(at2) * repeat.y % 1 + 1) % 1;
11399
11400
  const pixelX = Math.min(sample.width - 1, u * sample.width | 0);
11400
11401
  const pixelY = Math.min(sample.height - 1, (1 - v) * sample.height | 0);
11401
11402
  const offset = (pixelY * sample.width + pixelX) * 4;
@@ -12073,8 +12074,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12073
12074
  // was `maquina`
12074
12075
  });
12075
12076
  var OWN_TYPES = Object.freeze({ lamp: true, gas_piped: true });
12077
+ var sourceOf = (result) => result;
12076
12078
  var ADAPTER_VERSION = "0.3.0";
12077
12079
  var r3 = (n) => Math.round(n * 1e3) / 1e3;
12080
+ var at = (it) => ({ x: it.x ?? 0, z: it.z ?? 0, ry: it.ry ?? 0 });
12078
12081
  function mergeRegistry(base, extra) {
12079
12082
  const out = { ...base };
12080
12083
  if (extra) {
@@ -12093,14 +12096,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12093
12096
  });
12094
12097
  function create2(options = {}) {
12095
12098
  const opts = options || {};
12096
- const GI = opts.GameInteractables;
12097
- const HH = opts.GameInteractablesHousehold;
12098
12099
  const locale = opts.locale || "pt-BR";
12099
12100
  const msg = createTranslator(locale, opts.messages);
12100
- if (!GI || !HH) throw new Error(msg("error.missingKit"));
12101
+ if (!opts.GameInteractables || !opts.GameInteractablesHousehold) throw new Error(msg("error.missingKit"));
12102
+ const GI = opts.GameInteractables;
12103
+ const HH = opts.GameInteractablesHousehold;
12101
12104
  const region = opts.region || "br";
12102
12105
  const hh = HH.createHousehold({ locale, region });
12103
12106
  const householdTypes = new Set(hh.types.map((t) => t.id));
12107
+ const recorderApi = () => HH.createRecorder().api;
12104
12108
  const worlds = /* @__PURE__ */ new WeakMap();
12105
12109
  const typeMap = mergeRegistry(TYPE_MAP, opts.typeMap);
12106
12110
  const contentMap = mergeRegistry(CONTENT_MAP, opts.contentMap);
@@ -12136,7 +12140,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12136
12140
  function colorOf(res, color2) {
12137
12141
  if (color2 == null) return void 0;
12138
12142
  if (typeof color2 === "number") return color2;
12139
- const v = res.colors && res.colors[color2];
12143
+ const v = res.colors && res.colors[String(color2)];
12140
12144
  return typeof v === "number" ? v : void 0;
12141
12145
  }
12142
12146
  function paletteOf(res) {
@@ -12165,17 +12169,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12165
12169
  drawerItem: (s) => drawerItems.has(s.itemId)
12166
12170
  };
12167
12171
  const itemOfContent = (c) => {
12168
- const id = contentMap[c.itemId] || (hh.items[c.itemId] ? c.itemId : null) || contentByGroup[stackGroup(c)] || contentFallback;
12172
+ const group = stackGroup(c);
12173
+ const id = contentMap[c.itemId] || (hh.items[c.itemId] ? c.itemId : null) || (group != null ? contentByGroup[group] : void 0) || contentFallback;
12169
12174
  return hh.items[id] ? id : contentFallback;
12170
12175
  };
12171
12176
  const volume = (d) => d.size[0] * d.size[1] * d.size[2];
12172
12177
  const candidates = (id, objectType) => {
12173
12178
  const def = hh.items[id];
12174
- const siblings = Object.values(hh.items).filter((i) => i.category === def.category && i.id !== id).sort((a, b) => volume(a) - volume(b) || (a.id < b.id ? -1 : 1));
12179
+ const siblings = Object.values(hh.items).filter((i) => i.category === def?.category && i.id !== id).sort((a, b) => volume(a) - volume(b) || (a.id < b.id ? -1 : 1));
12175
12180
  return [id].concat(siblings.map((i) => i.id), substitutes[objectType] || []);
12176
12181
  };
12177
12182
  function distribute(type, probeItem, stacks) {
12178
- const spec = hh.build(type, probeItem, HH.createRecorder().api);
12183
+ const spec = hh.build(type, probeItem, recorderApi());
12179
12184
  const conts = spec.containers || [];
12180
12185
  const contents = {};
12181
12186
  for (const c of conts) contents[c.id] = c.slots.map(() => null);
@@ -12206,8 +12211,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12206
12211
  }
12207
12212
  return { contents, rejected };
12208
12213
  }
12209
- function plan(res, popts = {}) {
12210
- popts = popts || {};
12214
+ function plan(source, options2 = {}) {
12215
+ const res = sourceOf(source);
12216
+ const popts = options2 || {};
12211
12217
  const o = { ox: popts.originX || 0, oz: popts.originZ || 0, inw: popts.inw || 1, base: popts.base || 0 };
12212
12218
  const K = conv(o);
12213
12219
  const floorSel = popts.floor;
@@ -12271,7 +12277,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12271
12277
  const item = {
12272
12278
  x: K.x(m.x),
12273
12279
  z: K.z(m.z),
12274
- ry: m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0),
12280
+ ry: m.frontU != null ? K.ry(m.frontU, m.frontV ?? 0) : r3(m.ry || 0),
12275
12281
  w: m.w,
12276
12282
  d: m.d,
12277
12283
  h: m.h,
@@ -12284,7 +12290,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12284
12290
  return item;
12285
12291
  }
12286
12292
  function entry2(id, type, item, origin, floor, extra) {
12287
- return Object.assign({ id, type, item, origin, floor, floorY: floorYOf(res, o, floor), connections: {} }, extra || {});
12293
+ const e = { id, type, item, origin, floor, floorY: floorYOf(res, o, floor), connections: {} };
12294
+ return Object.assign(e, extra || {});
12288
12295
  }
12289
12296
  function store(targets, stacks) {
12290
12297
  let rest2 = stacks || [];
@@ -12297,10 +12304,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12297
12304
  }
12298
12305
  const hidden = [];
12299
12306
  function distRect(c, x, z) {
12300
- const dx = x - c.item.x;
12301
- const dz = z - c.item.z;
12302
- const s = Math.sin(c.item.ry);
12303
- const co = Math.cos(c.item.ry);
12307
+ const ci = at(c.item);
12308
+ const dx = x - ci.x;
12309
+ const dz = z - ci.z;
12310
+ const s = Math.sin(ci.ry);
12311
+ const co = Math.cos(ci.ry);
12304
12312
  const lx = dx * co - dz * s;
12305
12313
  const lz = dx * s + dz * co;
12306
12314
  return Math.hypot(Math.max(Math.abs(lx) - (c.item.w || 0) / 2, 0), Math.max(Math.abs(lz) - (c.item.d || 0) / 2, 0));
@@ -12308,9 +12316,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12308
12316
  function hideCylinders() {
12309
12317
  for (const b of hidden) {
12310
12318
  let target = null;
12319
+ const bi = at(b.item);
12311
12320
  for (const c2 of result.items) {
12312
12321
  if (c2.type !== "kitchen_cabinet_base" || c2.floor !== b.floor) continue;
12313
- const dist = distRect(c2, b.item.x, b.item.z);
12322
+ const dist = distRect(c2, bi.x, bi.z);
12314
12323
  if (!target || dist < target.dist) target = { c: c2, dist };
12315
12324
  }
12316
12325
  if (!target) {
@@ -12318,16 +12327,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12318
12327
  continue;
12319
12328
  }
12320
12329
  const c = target.c;
12321
- const spec = hh.build(c.type, c.item, HH.createRecorder().api);
12322
- const sn = Math.sin(c.item.ry);
12323
- const cs = Math.cos(c.item.ry);
12330
+ const spec = hh.build(c.type, c.item, recorderApi());
12331
+ const ci = at(c.item);
12332
+ const sn = Math.sin(ci.ry);
12333
+ const cs = Math.cos(ci.ry);
12324
12334
  let door = null;
12325
12335
  for (const it of spec.interactions || []) {
12326
- const pt = it.action && it.action.do === "toggle_part" ? (spec.parts || []).find((q) => q.id === it.action.part) : null;
12327
- if (!pt || pt.motion.kind !== "hinge") continue;
12328
- const wx = c.item.x + it.pos[0] * cs + it.pos[2] * sn;
12329
- const wz = c.item.z - it.pos[0] * sn + it.pos[2] * cs;
12330
- const dist = Math.hypot(wx - b.item.x, wz - b.item.z);
12336
+ const action = it.action;
12337
+ const pt = action.do === "toggle_part" ? (spec.parts || []).find((q) => q.id === action.part) : null;
12338
+ if (!pt || !pt.motion || pt.motion.kind !== "hinge") continue;
12339
+ const wx = ci.x + it.pos[0] * cs + it.pos[2] * sn;
12340
+ const wz = ci.z - it.pos[0] * sn + it.pos[2] * cs;
12341
+ const dist = Math.hypot(wx - bi.x, wz - bi.z);
12331
12342
  if (!door || dist < door.dist) door = { id: pt.id, dist };
12332
12343
  }
12333
12344
  if (!door) {
@@ -12357,9 +12368,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12357
12368
  const campCylinder = firstOfType("gas_canister");
12358
12369
  function planFireplace(m, e, item) {
12359
12370
  const def = hh.types.find((t) => t.id === "fireplace");
12360
- const lack = (def.d - m.d) / 2;
12361
- item.x = r3(item.x + Math.sin(item.ry) * lack);
12362
- item.z = r3(item.z + Math.cos(item.ry) * lack);
12371
+ const lack = ((def ? def.d : m.d) - m.d) / 2;
12372
+ const p = at(item);
12373
+ item.x = r3(p.x + Math.sin(p.ry) * lack);
12374
+ item.z = r3(p.z + Math.cos(p.ry) * lack);
12363
12375
  const room = (res.rooms || []).find((c) => c.id === m.room && c.floor === m.floor);
12364
12376
  const f = (res.floors || []).find((x) => x.index === m.floor);
12365
12377
  item.h = r3(room && room.ceiling || f && f.ceiling || 2.6);
@@ -12387,7 +12399,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12387
12399
  e.connections.gas = m.gas || "cylinder";
12388
12400
  e.connections.cylinder = m.cylinder || null;
12389
12401
  }
12390
- if (map.type === "gas_bottle") result.cylinders.push({ id: e.id, stove: m.link || null, place: m.placement || null });
12402
+ if (map.type === "gas_bottle") result.cylinders.push({ id: e.id, stove: typeof m.link === "string" ? m.link : null, place: m.placement || null });
12391
12403
  if (map.type === "gas_canister") {
12392
12404
  result.canisters.push(e.id);
12393
12405
  if (campCylinder && campCylinder.id === m.id && campStove2) result.cylinders.push({ id: e.id, stove: campStove2.id, place: null });
@@ -12411,7 +12423,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12411
12423
  push(e);
12412
12424
  }
12413
12425
  function planCompound(m, kind) {
12414
- const ry = m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0);
12426
+ const ry = m.frontU != null ? K.ry(m.frontU, m.frontV ?? 0) : r3(m.ry || 0);
12415
12427
  const cx = K.x(m.x);
12416
12428
  const cz = K.z(m.z);
12417
12429
  const part = (id, type, w, d, h, y, lx, lz) => {
@@ -12463,11 +12475,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12463
12475
  } else {
12464
12476
  const basin = part(m.id, "sink_bathroom", m.w, m.d, m.h + 0.2, 0, 0, 0);
12465
12477
  list2.push(basin);
12466
- if (contents[m.id]) {
12467
- if (contents[m.id].length) {
12478
+ const own = contents[m.id];
12479
+ if (own) {
12480
+ if (own.length) {
12468
12481
  const cabinet = part(m.id + "#cabinet", "bathroom_cabinet", Math.max(0.45, Math.min(0.6, m.w)), 0.15, 0.75, 1.3, 0, -(m.d / 2) + 0.075);
12469
12482
  list2.push(cabinet);
12470
- store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]], contents[m.id]);
12483
+ store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]], own);
12471
12484
  } else {
12472
12485
  store([["sink_bathroom", basin.item]], []);
12473
12486
  }
@@ -12507,7 +12520,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12507
12520
  result.chairs = [];
12508
12521
  if (opts.chairs !== false && popts.chairs !== false) {
12509
12522
  const blocked = blockedOf(res, { originX: o.ox, originZ: o.oz, inw: o.inw });
12510
- const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && q.aabb;
12523
+ const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && !!q.aabb;
12511
12524
  const placed = [];
12512
12525
  const free = (m, cu, cv, half) => {
12513
12526
  const a = [cu - half + 0.03, cv - half + 0.03, cu + half - 0.03, cv + half - 0.03];
@@ -12523,8 +12536,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12523
12536
  for (const m of res.items || []) {
12524
12537
  const mode = chairTables[m.type];
12525
12538
  if (!mode || !onFloor(m.floor, m.outdoor) || m.frontU == null) continue;
12526
- const f = [m.frontU, m.frontV];
12527
- const pp = [-m.frontV, m.frontU];
12539
+ const fv = m.frontV ?? 0;
12540
+ const f = [m.frontU, fv];
12541
+ const pp = [-fv, m.frontU];
12528
12542
  const seats = [];
12529
12543
  if (mode === "dining") {
12530
12544
  const n = Math.max(1, Math.min(3, Math.floor((m.w - 0.1) / 0.55)));
@@ -12593,8 +12607,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12593
12607
  const item = { x: K.x(s.u), z: K.z(s.v), ry: K.ry(s.frontU, s.frontV), y: s.y, seed: seedOf2(s.id) };
12594
12608
  item.controls = (s.controls || []).map((id) => id + ":lamp");
12595
12609
  const e = entry2(s.id, "wall_switch", item, s.id, s.floor);
12596
- e.connections.controls = (s.controls || []).slice();
12597
- e.lit = e.connections.controls.some((id) => (result.items.find((x) => x.id === id) || {}).lit === true);
12610
+ const controls = (s.controls || []).slice();
12611
+ e.connections.controls = controls;
12612
+ e.lit = controls.some((id) => result.items.find((x) => x.id === id)?.lit === true);
12598
12613
  if (floorSel == null) {
12599
12614
  for (const id of s.controls || []) if (!lights.has(id)) result.warnings.push(msg("warn.switchUnknownLamp", { id: s.id, lamp: id }));
12600
12615
  }
@@ -12634,7 +12649,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12634
12649
  seed: seedOf2("panel"),
12635
12650
  circuits: circuits.map((c) => ({ id: c.id, label: c.room }))
12636
12651
  };
12637
- if (!item.circuits.length) delete item.circuits;
12652
+ if (!item.circuits?.length) delete item.circuits;
12638
12653
  const e = entry2("panel", "electrical_panel", item, "panel", q.floor);
12639
12654
  push(e);
12640
12655
  result.panel = e.id;
@@ -12656,10 +12671,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12656
12671
  }
12657
12672
  }
12658
12673
  const piped = result.items.filter((e) => e.type === "stove" && e.connections.gas === "piped");
12659
- if (piped.length) {
12674
+ const firstPiped = piped[0];
12675
+ if (firstPiped) {
12660
12676
  const med = utilities.gas && utilities.gas.meter;
12661
- const ref = med ? { x: K.x(med.u), z: K.z(med.v), y: med.y || 1 } : { x: piped[0].item.x, z: piped[0].item.z, y: 0.3 };
12662
- const e = entry2("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf2("piped_gas") }, "piped_gas", piped[0].floor);
12677
+ const ref = med ? { x: K.x(med.u), z: K.z(med.v), y: med.y || 1 } : { x: firstPiped.item.x, z: firstPiped.item.z, y: 0.3 };
12678
+ const e = entry2("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf2("piped_gas") }, "piped_gas", firstPiped.floor);
12663
12679
  e.floorY = o.base;
12664
12680
  push(e);
12665
12681
  for (const f of piped) f.connections.fuel = "piped_gas:gas";
@@ -12706,9 +12722,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12706
12722
  for (const dv of spec.devices || []) if (L.outlet && dv.socket === "auto") dv.socket = L.outlet + ":socket";
12707
12723
  } else {
12708
12724
  const sh = L.shower || {};
12709
- const heater = (spec.devices || []).find((d) => d.id === "heater");
12725
+ const devices = spec.devices || [];
12726
+ const heater = devices.find((d) => d.id === "heater");
12710
12727
  if (heater && sh.electric === false) {
12711
- spec.devices = spec.devices.filter((d) => d !== heater);
12728
+ spec.devices = devices.filter((d) => d !== heater);
12712
12729
  for (const f of spec.fixtures || []) if (f.heater === "heater") delete f.heater;
12713
12730
  } else if (heater) {
12714
12731
  if (sh.powerW) heater.watts = sh.powerW;
@@ -12719,7 +12736,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12719
12736
  for (const b of spec.burners || []) if (b.fuel === "auto") b.fuel = L.fuel;
12720
12737
  }
12721
12738
  if (entry2.type === "fireplace" && L.chimneyTop) {
12722
- const it = entry2.item;
12739
+ const it = at(entry2.item);
12723
12740
  const dx = L.chimneyTop[0] - it.x;
12724
12741
  const dz = L.chimneyTop[2] - it.z;
12725
12742
  const lx = Math.cos(it.ry) * dx - Math.sin(it.ry) * dz;
@@ -12738,8 +12755,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12738
12755
  }
12739
12756
  return spec;
12740
12757
  }
12741
- function createWorld(res, copts = {}) {
12742
- copts = copts || {};
12758
+ function createWorld(source, options2 = {}) {
12759
+ const res = sourceOf(source);
12760
+ const copts = options2 || {};
12743
12761
  const info = { points: /* @__PURE__ */ new Map(), water: copts.water || null, lightsOn: copts.lightsOn };
12744
12762
  const electrical = res.utilities && res.utilities.electrical;
12745
12763
  const world = GI.createWorld({
@@ -12767,8 +12785,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12767
12785
  const info = worlds.get(world);
12768
12786
  return info ? info.points.get(fixtureId) : void 0;
12769
12787
  }
12770
- function blockedOf(res, bopts = {}) {
12771
- bopts = bopts || {};
12788
+ function blockedOf(source, options2 = {}) {
12789
+ const res = sourceOf(source);
12790
+ const bopts = options2 || {};
12772
12791
  const ox = bopts.originX || 0;
12773
12792
  const oz = bopts.originZ || 0;
12774
12793
  const inw = bopts.inw || 1;
@@ -12803,33 +12822,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12803
12822
  return false;
12804
12823
  };
12805
12824
  }
12806
- function add(world, planned, aopts = {}) {
12807
- aopts = aopts || {};
12825
+ function add(world, planned, options2 = {}) {
12826
+ const aopts = options2 || {};
12808
12827
  const info = worlds.get(world);
12809
- const build = aopts.build || ((type, item) => hh.build(type, item, HH.createRecorder().api));
12828
+ const build = aopts.build || ((type, item) => hh.build(type, item, recorderApi()));
12810
12829
  const isBlocked = aopts.isBlocked || null;
12811
12830
  const out = { added: 0, parts: [], hinges: {}, moved: {}, warnings: [] };
12812
12831
  const override = aopts.lightsOn !== void 0 ? aopts.lightsOn : info && info.lightsOn;
12813
12832
  if (override !== void 0) {
12814
12833
  for (const e of planned.items) if (e.type === "lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
12815
12834
  for (const e of planned.items) if (e.type === "lantern_lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
12816
- for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) => (planned.items.find((x) => x.id === id) || {}).lit === true);
12835
+ for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) => planned.items.find((x) => x.id === id)?.lit === true);
12817
12836
  }
12818
12837
  for (const e of planned.items) if (e.type === "lantern_lamp") e.item.on = !!e.lit;
12819
12838
  let scratch = null;
12820
- function probe(e, hinge, setback) {
12839
+ function probe(e, hinge, setback, blockedAt) {
12821
12840
  if (!scratch) scratch = GI.createWorld({ locale, strings: hh.strings, items: hh.items, loot: hh.loot, grid: false });
12822
- const it = e.item;
12841
+ const it = at(e.item);
12823
12842
  const x = it.x + Math.sin(it.ry) * setback;
12824
12843
  const z = it.z + Math.cos(it.ry) * setback;
12825
- const spec = hh.build(e.type, Object.assign({}, it, { hinge }), HH.createRecorder().api);
12844
+ const spec = hh.build(e.type, Object.assign({}, e.item, { hinge }), recorderApi());
12826
12845
  scratch.add("__probe", spec, { x, y: e.floorY, z, ry: it.ry });
12827
- const blocks = (px, pz) => isBlocked(px, pz, e.floor);
12846
+ const blocks = (px, pz) => blockedAt(px, pz, e.floor);
12828
12847
  let sum = 0;
12829
12848
  let min = 1;
12830
12849
  let n = 0;
12831
12850
  for (const p of spec.parts || []) {
12832
- if (p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
12851
+ if (!p.motion || p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
12833
12852
  const t = scratch.fitSweep("__probe", p.id, blocks);
12834
12853
  sum += t;
12835
12854
  min = Math.min(min, t);
@@ -12841,12 +12860,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12841
12860
  const better = (a, b) => a.sum > b.sum + 1e-9 || Math.abs(a.sum - b.sum) <= 1e-9 && a.min > b.min + 1e-9;
12842
12861
  function fitDoors(e) {
12843
12862
  if (!isBlocked || !householdTypes.has(e.type)) return;
12844
- const standard = probe(e, void 0, 0);
12863
+ const standard = probe(e, void 0, 0, isBlocked);
12845
12864
  if (!standard.n || standard.min >= 1) return;
12846
12865
  let bestSide;
12847
12866
  let m = standard;
12848
12867
  for (const side of ["left", "right"]) {
12849
- const r = probe(e, side, 0);
12868
+ const r = probe(e, side, 0, isBlocked);
12850
12869
  if (better(r, m)) {
12851
12870
  m = r;
12852
12871
  bestSide = side;
@@ -12859,13 +12878,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12859
12878
  if (m.min >= 1) return;
12860
12879
  let target = { setback: 0, r: m };
12861
12880
  for (const setback of [0.01, 0.02, 0.03, 0.04]) {
12862
- const r = probe(e, bestSide, setback);
12881
+ const r = probe(e, bestSide, setback, isBlocked);
12863
12882
  if (better(r, target.r)) target = { setback, r };
12864
12883
  if (r.min >= 1) break;
12865
12884
  }
12866
12885
  if (target.setback > 0 && target.r.sum > m.sum + 0.2) {
12867
- e.item.x = r3(e.item.x + Math.sin(e.item.ry) * target.setback);
12868
- e.item.z = r3(e.item.z + Math.cos(e.item.ry) * target.setback);
12886
+ const p = at(e.item);
12887
+ e.item.x = r3(p.x + Math.sin(p.ry) * target.setback);
12888
+ e.item.z = r3(p.z + Math.cos(p.ry) * target.setback);
12869
12889
  e.moved = target.setback;
12870
12890
  out.moved[e.id] = target.setback;
12871
12891
  }
@@ -12888,7 +12908,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
12888
12908
  }
12889
12909
  }
12890
12910
  connect(e, spec);
12891
- world.add(e.id, spec, { x: e.item.x, y: e.floorY, z: e.item.z, ry: e.item.ry });
12911
+ const pose = at(e.item);
12912
+ world.add(e.id, spec, { x: pose.x, y: e.floorY, z: pose.z, ry: pose.ry });
12892
12913
  out.added++;
12893
12914
  if (!isBlocked) continue;
12894
12915
  for (const p of spec.parts || []) {
@@ -13251,11 +13272,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
13251
13272
  }
13252
13273
  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] }));
13253
13274
  };
13254
- var severAt = (inp, root, at, gap) => {
13275
+ var severAt = (inp, root, at2, gap) => {
13255
13276
  const dims = root.s;
13256
13277
  const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
13257
13278
  const half = dims[L] / 2;
13258
- const lo = clamp(at - gap / 2, -half, half), hi = clamp(at + gap / 2, -half, half);
13279
+ const lo = clamp(at2 - gap / 2, -half, half), hi = clamp(at2 + gap / 2, -half, half);
13259
13280
  const out = [];
13260
13281
  const stub = (from, to) => {
13261
13282
  if (to - from < 0.02) return;
@@ -15637,7 +15658,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15637
15658
  const typed = listeners.get(e.type);
15638
15659
  if (typed) for (const fn of [...typed]) fn(e);
15639
15660
  };
15640
- const base = (o, source) => source === void 0 ? { object: o.id, time } : { object: o.id, time, source };
15661
+ let blow;
15662
+ const base = (o, source) => ({
15663
+ object: o.id,
15664
+ time,
15665
+ ...source === void 0 ? {} : { source },
15666
+ ...blow === void 0 ? {} : { blow }
15667
+ });
15641
15668
  const pendingCollapse = /* @__PURE__ */ new Map();
15642
15669
  let runDepth = 0;
15643
15670
  const drainBlasts = () => {
@@ -15907,9 +15934,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15907
15934
  const [lo, hi] = contactBox(p, above);
15908
15935
  return toWorld(p.pos, p.q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
15909
15936
  };
15910
- const overSupportAt = (o, p, at, lower) => {
15937
+ const overSupportAt = (o, p, at2, lower) => {
15911
15938
  const g = p.bend;
15912
- const local = toLocal(p.pos, p.q, at);
15939
+ const local = toLocal(p.pos, p.q, at2);
15913
15940
  const depth = g.gravity >= 0 ? g.dims[g.gravity] : Math.min(...g.depthAxes.map((a) => g.dims[a]));
15914
15941
  let best = -1;
15915
15942
  let bestGap = depth;
@@ -16063,10 +16090,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16063
16090
  const incoming = new Array(n).fill(0);
16064
16091
  const bending = new Array(n).fill(0);
16065
16092
  const through = parts.map(() => []);
16066
- const pass = (k, at, mass) => {
16067
- const over = overSupportAt(o, parts[k], at, lowerOf.get(k) ?? []);
16093
+ const pass = (k, at2, mass) => {
16094
+ const over = overSupportAt(o, parts[k], at2, lowerOf.get(k) ?? []);
16068
16095
  if (over < 0) bending[k] += mass;
16069
- else through[k].push({ at, mass, over });
16096
+ else through[k].push({ at: at2, mass, over });
16070
16097
  };
16071
16098
  for (let h = queue.length - 1; h >= 0; h--) {
16072
16099
  const i = queue[h];
@@ -16133,7 +16160,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16133
16160
  const terrain = cfg.terrains.get(cfg.terrain);
16134
16161
  if (!terrain) throw new Error(`unknown wind terrain "${cfg.terrain}"`);
16135
16162
  const inputs = [];
16136
- const at = /* @__PURE__ */ new Map();
16163
+ const at2 = /* @__PURE__ */ new Map();
16137
16164
  const keep = [];
16138
16165
  let ground = Infinity, foundationTop = -Infinity;
16139
16166
  o.parts.forEach((p, i) => {
@@ -16142,7 +16169,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16142
16169
  const role = p.spec.structure?.role;
16143
16170
  const e = p.mat.strength?.elasticGPa;
16144
16171
  const kind = role === "wall" ? "wall" : role === "column" ? "column" : role === "beam" ? "beam" : role === "foundation" ? "foundation" : "other";
16145
- at.set(i, inputs.length);
16172
+ at2.set(i, inputs.length);
16146
16173
  keep.push(i);
16147
16174
  ground = Math.min(ground, box4.min[1]);
16148
16175
  if (kind === "foundation") foundationTop = Math.max(foundationTop, box4.max[1]);
@@ -16153,7 +16180,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16153
16180
  const beams = [];
16154
16181
  for (const j of o.byPart.get(o.parts[i].spec.id)) {
16155
16182
  if (j.st.open) continue;
16156
- const b = at.get(j.ia === i ? j.ib : j.ia);
16183
+ const b = at2.get(j.ia === i ? j.ib : j.ia);
16157
16184
  if (b !== void 0 && inputs[b].kind === "beam") beams.push(b);
16158
16185
  }
16159
16186
  inputs[k].beams = beams;
@@ -16969,7 +16996,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16969
16996
  }
16970
16997
  };
16971
16998
  const tornToEdge = (o) => {
16972
- const { p, cell, a, b, at, crater: crater2, reach, gone } = o;
16999
+ const { p, cell, a, b, at: at2, crater: crater2, reach, gone } = o;
16973
17000
  const half = p.dims[a] / 2;
16974
17001
  const lo = cell.center[a] - cell.size[a] / 2, hi = cell.center[a] + cell.size[a] / 2;
16975
17002
  const free = (side, sign2) => {
@@ -16977,8 +17004,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16977
17004
  const probe = side + sign2 * 1e-3;
16978
17005
  return gridOf(p).some((c, k) => gone(k) && Math.abs(probe - c.center[a]) <= c.size[a] / 2 && Math.abs(cell.center[b] - c.center[b]) <= c.size[b] / 2);
16979
17006
  };
16980
- if (at - lo <= reach && free(lo, -1)) return [lo, Math.max(crater2[1], lo)];
16981
- if (hi - at <= reach && free(hi, 1)) return [Math.min(crater2[0], hi), hi];
17007
+ if (at2 - lo <= reach && free(lo, -1)) return [lo, Math.max(crater2[1], lo)];
17008
+ if (hi - at2 <= reach && free(hi, 1)) return [Math.min(crater2[0], hi), hi];
16982
17009
  return crater2;
16983
17010
  };
16984
17011
  const craterAcross = (energy) => clamp2(0.03 + 12e-4 * Math.sqrt(Math.max(0, energy)), 0.03, 0.14);
@@ -17188,7 +17215,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17188
17215
  return;
17189
17216
  }
17190
17217
  if (ex) {
17191
- emit({ ...base(o, src), type: "explode", part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...ex.lethalRadius !== void 0 ? { lethalRadius: ex.lethalRadius } : {}, ...ex.effect !== void 0 ? { effect: ex.effect } : {} });
17218
+ emit({ ...base(o, src), type: "explode", part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...ex.lethalRadius !== void 0 ? { lethalRadius: ex.lethalRadius } : {}, ...ex.tnt !== void 0 ? { tnt: ex.tnt } : {}, ...ex.effect !== void 0 ? { effect: ex.effect } : {} });
17192
17219
  blasts.push({ point: c, energy: ex.energy, radius: ex.radius, ...ex.lethalRadius !== void 0 ? { lethalRadius: ex.lethalRadius } : {}, source: src });
17193
17220
  }
17194
17221
  partLost(o, p, src);
@@ -17782,7 +17809,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17782
17809
  res.events = cur.slice(start);
17783
17810
  return res;
17784
17811
  };
17785
- const doHit = (o, hit, only) => {
17812
+ const withBlow = (type, fn) => () => {
17813
+ const outer = blow;
17814
+ blow = type;
17815
+ try {
17816
+ return fn();
17817
+ } finally {
17818
+ blow = outer;
17819
+ }
17820
+ };
17821
+ const doHit = (o, hit, only) => withBlow(hit.type, () => resolveHit(o, hit, only))();
17822
+ const resolveHit = (o, hit, only) => {
17786
17823
  let point = hit.point;
17787
17824
  let dir = hit.direction;
17788
17825
  if (hit.space === "local") {
@@ -18221,6 +18258,44 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
18221
18258
  blastProbe() {
18222
18259
  return { ...blastProbe };
18223
18260
  },
18261
+ blastReach(point, target, options2 = {}) {
18262
+ const L = vec.distance(point, target);
18263
+ if (L < 1e-4) return 1;
18264
+ const shelter = { ...SHELTER_DEFAULTS, ...options2.shelter };
18265
+ const ignore = new Set(options2.ignore ?? []);
18266
+ const d = vec.scale(vec.sub(target, point), 1 / L);
18267
+ let t = 1;
18268
+ for (const o of objects.values()) {
18269
+ if (ignore.has(o.id) || raySphereMiss(point, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, L)) continue;
18270
+ for (const p of o.parts) {
18271
+ if (isLost(p) || p.st.stripped) continue;
18272
+ const r = rayPart(o, p, point, d);
18273
+ if (!r) continue;
18274
+ const t0 = Math.max(r.t0, 0);
18275
+ const path = Math.min(r.t1, L) - t0;
18276
+ if (path < shelter.minPath) continue;
18277
+ if (p.st.opening && insideOpening(o, p, toLocal(o.st.position, o.st.rotation, vec.madd(point, d, t0 + path / 2)))) continue;
18278
+ t *= Math.exp(-(p.mat.hpPerKg * p.mat.density * path * (p.mat.damageScale?.shelter ?? 1)) / shelter.k);
18279
+ if (t < 1e-4) return 0;
18280
+ }
18281
+ }
18282
+ for (const im of impls.values()) {
18283
+ if (ignore.has(im.impl.id)) continue;
18284
+ for (const ps of im.impl.describe().parts) {
18285
+ const mat = materials.get(ps.material);
18286
+ if (!mat) continue;
18287
+ const ov = im.poses.get(ps.id);
18288
+ const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), point, d, ov?.pos);
18289
+ if (!r || r.t1 < 0 || r.t0 > L) continue;
18290
+ let path = Math.min(r.t1, L) - Math.max(r.t0, 0);
18291
+ if (ps.thickness !== void 0 && ps.thickness > 0) path = Math.min(path, 2 * ps.thickness);
18292
+ else if (path < shelter.minPath) continue;
18293
+ t *= Math.exp(-(mat.hpPerKg * mat.density * path * (mat.damageScale?.shelter ?? 1)) / shelter.k);
18294
+ if (t < 1e-4) return 0;
18295
+ }
18296
+ }
18297
+ return t;
18298
+ },
18224
18299
  explode(point, energy, radius, source, blast) {
18225
18300
  blastProbe.partsTested = 0;
18226
18301
  blastProbe.partsNear = 0;
@@ -18245,7 +18320,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
18245
18320
  },
18246
18321
  shoot(origin, direction, energy, caliber, source, round3) {
18247
18322
  const extras = typeof round3 === "number" ? { piercing: round3 } : round3 ?? {};
18248
- return withCollapses(run(() => {
18323
+ return withCollapses(run(withBlow("ballistic", () => {
18249
18324
  const results = [];
18250
18325
  const d = vec.normalize(direction);
18251
18326
  const ignore = /* @__PURE__ */ new Set();
@@ -18256,10 +18331,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
18256
18331
  if (!rh) break;
18257
18332
  const im = impls.get(rh.object);
18258
18333
  if (im) {
18259
- const r = implHit(im, { type: "ballistic", point: rh.point, part: rh.part, normal: rh.normal, direction: d, energy: E, caliber, ...extras, ...source !== void 0 ? { source } : {} });
18334
+ const scaled = extras.penetration && E < energy ? { ...extras, penetration: Object.fromEntries(Object.entries(extras.penetration).map(([k, mm]) => [k, mm * (E / energy)])) } : extras;
18335
+ const r = implHit(im, { type: "ballistic", point: rh.point, part: rh.part, normal: rh.normal, direction: d, energy: E, caliber, ...scaled, ...source !== void 0 ? { source } : {} });
18260
18336
  r.part = rh.part;
18261
18337
  r.point = rh.point;
18262
- r.exitEnergy = r.penetrated ? E * 0.5 : 0;
18338
+ const left = r.events.find((e) => e.type === "hole" && e.energyLeft !== void 0);
18339
+ r.exitEnergy = r.penetrated ? left?.energyLeft ?? E * 0.5 : 0;
18263
18340
  results.push(r);
18264
18341
  ignore.add(`${im.impl.id}\0${rh.part}`);
18265
18342
  if (!r.penetrated) break;
@@ -18278,7 +18355,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
18278
18355
  E = out.exitEnergy;
18279
18356
  }
18280
18357
  return results;
18281
- }));
18358
+ })));
18282
18359
  },
18283
18360
  disassemble(objectId, jointId, tool2, dt) {
18284
18361
  const im = impls.get(objectId);
@@ -18586,8 +18663,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
18586
18663
  list: () => defs,
18587
18664
  get,
18588
18665
  register(def) {
18589
- const at = defs.findIndex((a) => a.id === def.id);
18590
- if (at >= 0) defs[at] = def;
18666
+ const at2 = defs.findIndex((a) => a.id === def.id);
18667
+ if (at2 >= 0) defs[at2] = def;
18591
18668
  else defs.push(def);
18592
18669
  },
18593
18670
  part: (assemblyId, options) => buildAssemblyPart(get(assemblyId), assemblyId, options)
@@ -26450,22 +26527,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26450
26527
  A.stats.external = Ne;
26451
26528
  let shadows = 0;
26452
26529
  for (let i = 0; i < N; i++) {
26453
- const g = asg[i], at = slotOf(i), b0 = LZU.uRB0.value, b1 = LZU.uRB1.value, b2 = LZU.uRB2.value, by = LZU.uRBY.value, ex = LZU.uREx.value;
26530
+ const g = asg[i], at2 = slotOf(i), b0 = LZU.uRB0.value, b1 = LZU.uRB1.value, b2 = LZU.uRB2.value, by = LZU.uRBY.value, ex = LZU.uREx.value;
26454
26531
  A.crates[i] = g ? { k: g.k, rects: g.rects, y: g.y, exterior: !!g.exterior, exclusion: g.exclusion || null, d: g.d } : null;
26455
26532
  if (!g) {
26456
26533
  put(i, { intensity: 0 });
26457
- for (const a of [b0, b1, b2, ex]) a.set(EMPTY, at * 4);
26458
- by.set([0, 0], at * 2);
26534
+ for (const a of [b0, b1, b2, ex]) a.set(EMPTY, at2 * 4);
26535
+ by.set([0, 0], at2 * 2);
26459
26536
  continue;
26460
26537
  }
26461
26538
  const lamp = g.exterior ? { intensity: g.lumens, distance: g.dist, decay: g.decay } : { intensity: (7 + g.range * 0.8) * lim(1 + 0.4 * (Math.sqrt(g.n) - 1), 1, 2.2), distance: Math.max(3, g.dm * 1.3 + 0.5), decay: 1.6 };
26462
26539
  put(i, { position: g.pos, color: g.color, ...lamp });
26463
26540
  const rs = g.rects;
26464
- b0.set(rs[0] || EMPTY, at * 4);
26465
- b1.set(rs[1] || EMPTY, at * 4);
26466
- b2.set(rs[2] || EMPTY, at * 4);
26467
- by.set(g.y, at * 2);
26468
- ex.set(g.exclusion || EMPTY, at * 4);
26541
+ b0.set(rs[0] || EMPTY, at2 * 4);
26542
+ b1.set(rs[1] || EMPTY, at2 * 4);
26543
+ b2.set(rs[2] || EMPTY, at2 * 4);
26544
+ by.set(g.y, at2 * 2);
26545
+ ex.set(g.exclusion || EMPTY, at2 * 4);
26469
26546
  if (i < NS) {
26470
26547
  shadows++;
26471
26548
  const s2 = g.house.group.uuid + "|" + g.k + "|" + g.pos.map((v) => v.toFixed(2)).join(",");
@@ -26540,10 +26617,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26540
26617
  for (const p of list2 || []) {
26541
26618
  if (isDoor && !(open.has(p.id) ? open.get(p.id) : !!p.open)) continue;
26542
26619
  const alongU = p.axis === "u", y = house.y0(p.floor) + (isDoor ? 1 : ((p.y0 != null ? p.y0 : 0.9) + (p.y1 != null ? p.y1 : 2)) / 2);
26543
- const at = (side) => _p.set(alongU ? p.at : p.pos + side, y, alongU ? p.pos + side : p.at).applyMatrix4(M).clone();
26544
- if (at(0).distanceTo(P0) > OPENING_REACH) continue;
26620
+ const at2 = (side) => _p.set(alongU ? p.at : p.pos + side, y, alongU ? p.pos + side : p.at).applyMatrix4(M).clone();
26621
+ if (at2(0).distanceTo(P0) > OPENING_REACH) continue;
26545
26622
  for (const side of [-OPENING_SIDE, OPENING_SIDE]) {
26546
- const w = at(side), hit = boxAt(boxes, w.x, w.y, w.z);
26623
+ const w = at2(side), hit = boxAt(boxes, w.x, w.y, w.z);
26547
26624
  if (hit) into.set(hit.c, hit);
26548
26625
  }
26549
26626
  }
@@ -26551,11 +26628,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26551
26628
  reach(house.r.doors, true);
26552
26629
  reach(house.r.windows, false);
26553
26630
  };
26554
- const clear = (at) => {
26555
- for (const key2 of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[key2].value.set(EMPTY, at * 4);
26556
- LZU.uRBY.value.set([0, 0], at * 2);
26631
+ const clear = (at2) => {
26632
+ for (const key2 of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[key2].value.set(EMPTY, at2 * 4);
26633
+ LZU.uRBY.value.set([0, 0], at2 * 2);
26557
26634
  };
26558
- const write = (at, into) => {
26635
+ const write = (at2, into) => {
26559
26636
  const rs = [];
26560
26637
  let lo = 1e9, hi = -1e9;
26561
26638
  for (const q of into.values()) {
@@ -26567,21 +26644,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26567
26644
  const r23 = rs.pop(), r1 = rs[rs.length - 1];
26568
26645
  rs[rs.length - 1] = [Math.min(r1[0], r23[0]), Math.min(r1[1], r23[1]), Math.max(r1[2], r23[2]), Math.max(r1[3], r23[3])];
26569
26646
  }
26570
- LZU.uRB0.value.set(rs[0] || EMPTY, at * 4);
26571
- LZU.uRB1.value.set(rs[1] || EMPTY, at * 4);
26572
- LZU.uRB2.value.set(rs[2] || EMPTY, at * 4);
26573
- LZU.uRBY.value.set([lo, hi], at * 2);
26574
- LZU.uREx.value.set(EMPTY, at * 4);
26647
+ LZU.uRB0.value.set(rs[0] || EMPTY, at2 * 4);
26648
+ LZU.uRB1.value.set(rs[1] || EMPTY, at2 * 4);
26649
+ LZU.uRB2.value.set(rs[2] || EMPTY, at2 * 4);
26650
+ LZU.uRBY.value.set([lo, hi], at2 * 2);
26651
+ LZU.uREx.value.set(EMPTY, at2 * 4);
26575
26652
  };
26576
26653
  const A = {
26577
26654
  /** Once per frame, after the budget's `present`: points the mask of every lit slot that is not the house's at the rooms its light reaches. */
26578
26655
  update(houses) {
26579
26656
  const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses) ? houses : [houses]).filter(Boolean), cache2 = /* @__PURE__ */ new Map();
26580
- for (let at = 0; at < size; at++) {
26581
- if (ours.has(at)) continue;
26582
- const light = budget.group.children[at];
26657
+ for (let at2 = 0; at2 < size; at2++) {
26658
+ if (ours.has(at2)) continue;
26659
+ const light = budget.group.children[at2];
26583
26660
  if (!indoors || !light || !light.isPointLight || !(light.intensity > 0) || !light.visible) {
26584
- clear(at);
26661
+ clear(at2);
26585
26662
  continue;
26586
26663
  }
26587
26664
  const into = /* @__PURE__ */ new Map();
@@ -26596,8 +26673,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26596
26673
  if (here) into.set(here.c, here);
26597
26674
  openingSides(house, M, boxes, into);
26598
26675
  }
26599
- if (into.size) write(at, into);
26600
- else clear(at);
26676
+ if (into.size) write(at2, into);
26677
+ else clear(at2);
26601
26678
  }
26602
26679
  }
26603
26680
  };
@@ -27080,17 +27157,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27080
27157
  for (const { c, part, units: units2, thick, mid } of shown) {
27081
27158
  if (!near(c)) continue;
27082
27159
  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;
27083
- const at = (s, dy, d, colour) => {
27160
+ const at2 = (s, dy, d, colour) => {
27084
27161
  const unit = clipToBox({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour }, view.bounds);
27085
27162
  if (unit) list2.push(unit);
27086
27163
  };
27087
27164
  const base = fragmentMaterial(part.material).color.getHex();
27088
27165
  const n = noise2(centre * 3.1, y * 2.7, 0.07);
27089
27166
  if (units2.mortar === "concrete") {
27090
- at(len, h, thick - 2 * COVER2, tone(base, 0.9 + 0.04 * n));
27167
+ at2(len, h, thick - 2 * COVER2, tone(base, 0.9 + 0.04 * n));
27091
27168
  } else {
27092
- at(len, h, thick - 2 * COVER2 - 0.012, 10327948);
27093
- at(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
27169
+ at2(len, h, thick - 2 * COVER2 - 0.012, 10327948);
27170
+ at2(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
27094
27171
  }
27095
27172
  }
27096
27173
  if (view.units) {
@@ -27404,11 +27481,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27404
27481
  };
27405
27482
  const extract = (it) => {
27406
27483
  const g0 = it.mesh.geometry, src = it.mesh.userData._p0 || g0.attributes.position.array, g = new THREE.BufferGeometry();
27407
- const at = (name, k, arr) => g.setAttribute(name, new THREE.BufferAttribute((arr || g0.attributes[name].array).slice(it.v0 * k, it.v1 * k), k));
27408
- at("position", 3, src);
27409
- at("normal", 3);
27410
- at("color", 3);
27411
- at("uv", 2);
27484
+ const at2 = (name, k, arr) => g.setAttribute(name, new THREE.BufferAttribute((arr || g0.attributes[name].array).slice(it.v0 * k, it.v1 * k), k));
27485
+ at2("position", 3, src);
27486
+ at2("normal", 3);
27487
+ at2("color", 3);
27488
+ at2("uv", 2);
27412
27489
  const ix = g0.index.array.slice(it.i0, it.i1);
27413
27490
  for (let k = 0; k < ix.length; k++) ix[k] -= it.v0;
27414
27491
  g.setIndex(new THREE.BufferAttribute(ix, 1));
@@ -28121,9 +28198,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28121
28198
  shared2.vegMaterials.setActors(focus ? [{ x: focus.x, y: focus.y, z: focus.z, radius: 0.9 }] : []);
28122
28199
  }
28123
28200
  if (focus && cfg.lod !== false) {
28124
- const L = Object.assign({ interior: 45, hide: 220 }, cfg.lod), d = distance2(focus), at = h.lodCurrent;
28201
+ const L = Object.assign({ interior: 45, hide: 220 }, cfg.lod), d = distance2(focus), at2 = h.lodCurrent;
28125
28202
  let n = d > L.hide ? 2 : d > L.interior ? 1 : 0;
28126
- if (n < at) n = d < (at === 2 ? L.hide : L.interior) * 0.92 ? n : at;
28203
+ if (n < at2) n = d < (at2 === 2 ? L.hide : L.interior) * 0.92 ? n : at2;
28127
28204
  applyLod(Math.max(n, h.lodMin));
28128
28205
  }
28129
28206
  },
@@ -28743,8 +28820,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28743
28820
  facadeExtra: (f, rng3, w, d, op) => {
28744
28821
  f.roof = "slab";
28745
28822
  f.finish = rng3() < 0.55 ? "exposed_block" : "partial_plaster";
28746
- f.slab = { exposedRebar: true, waterTank: { u: r22(0.5 + rng3() * (w - 1.5)), v: r22(1 + rng3() * (d - 2)) }, annex: rng3() < 0.55 ? { rect: [0, 0, r22(w * (0.5 + rng3() * 0.3)), r22(d * 0.4)], state: "exposed_brick" } : null };
28747
- if (floorsOf(op) > 1) f.slab.exposedRebar = rng3() < 0.6;
28823
+ const slab = { exposedRebar: true, waterTank: { u: r22(0.5 + rng3() * (w - 1.5)), v: r22(1 + rng3() * (d - 2)) }, annex: rng3() < 0.55 ? { rect: [0, 0, r22(w * (0.5 + rng3() * 0.3)), r22(d * 0.4)], state: "exposed_brick" } : null };
28824
+ f.slab = slab;
28825
+ if (floorsOf(op) > 1) slab.exposedRebar = rng3() < 0.6;
28748
28826
  }
28749
28827
  };
28750
28828
  }
@@ -29456,13 +29534,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29456
29534
  function apartment(strip, floor, k, from, to, plate, ceiling, win) {
29457
29535
  const wide = to - from, depth = strip.depth, facade = r22(depth * 0.56);
29458
29536
  const id = (name) => `apt_${floor}_${strip.id}_${k}_${name}`;
29459
- const at = (f0, f1, b0, b1) => boxOf2(strip, r22(from + wide * f0), r22(from + wide * f1), b0, b1);
29537
+ const at2 = (f0, f1, b0, b1) => boxOf2(strip, r22(from + wide * f0), r22(from + wide * f1), b0, b1);
29460
29538
  const rooms = [
29461
- { id: id("living"), type: "living", label: "living", library: "living_tower", rect: at(0, 0.58, 0, facade) },
29462
- { id: id("bedroom"), type: "bedroom", label: "bedroom", rect: at(0.58, 1, 0, facade) },
29463
- { id: id("kitchen"), type: "kitchen", label: "kitchen", library: "kitchen_integrated", rect: at(0, 0.4, facade, depth) },
29464
- { id: id("hall"), type: "hall", label: "hall", rect: at(0.4, 0.78, facade, depth) },
29465
- { id: id("bath"), type: "bathroom", label: "bathroom", library: "bathroom_wc", rect: at(0.78, 1, facade, depth) }
29539
+ { id: id("living"), type: "living", label: "living", library: "living_tower", rect: at2(0, 0.58, 0, facade) },
29540
+ { id: id("bedroom"), type: "bedroom", label: "bedroom", rect: at2(0.58, 1, 0, facade) },
29541
+ { id: id("kitchen"), type: "kitchen", label: "kitchen", library: "kitchen_integrated", rect: at2(0, 0.4, facade, depth) },
29542
+ { id: id("hall"), type: "hall", label: "hall", rect: at2(0.4, 0.78, facade, depth) },
29543
+ { id: id("bath"), type: "bathroom", label: "bathroom", library: "bathroom_wc", rect: at2(0.78, 1, facade, depth) }
29466
29544
  ];
29467
29545
  const doors = [
29468
29546
  stripDoor(id("hall"), strip, floor, 0.95),
@@ -29495,8 +29573,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29495
29573
  if (strip.id !== "south") return apartments(plan)(strip, context);
29496
29574
  const { floor, plate, ceiling } = context;
29497
29575
  const lobby = `lobby_${floor}_entrance`, concierge = `concierge_${floor}`, bikes = `bike_room_${floor}`;
29498
- const at = (f0, f1) => boxOf2(strip, r22(strip.length * f0), r22(strip.length * f1), 0, strip.depth);
29499
- const [left, middle, right] = [at(0, 0.3), at(0.3, 0.7), at(0.7, 1)];
29576
+ const at2 = (f0, f1) => boxOf2(strip, r22(strip.length * f0), r22(strip.length * f1), 0, strip.depth);
29577
+ const [left, middle, right] = [at2(0, 0.3), at2(0.3, 0.7), at2(0.7, 1)];
29500
29578
  const rooms = [
29501
29579
  { id: concierge, type: "office", label: "concierge", rect: left },
29502
29580
  { id: lobby, type: "hall", label: "lobby_entrance", rect: middle },
@@ -30883,10 +30961,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30883
30961
  run: ({ expect }) => {
30884
30962
  const food = catalog.list().find((item) => item.shelfLife !== void 0 && item.shelfLife > 0);
30885
30963
  if (!food) return expect(false, "the catalog has a food that spoils");
30886
- const at = (storage, days2) => freshness(food, { ageDays: 0, since: 0, storage, storedAt: 0 }, days2, { rules: catalog.rules });
30964
+ const at2 = (storage, days2) => freshness(food, { ageDays: 0, since: 0, storage, storedAt: 0 }, days2, { rules: catalog.rules });
30887
30965
  const days = food.shelfLife * 1.2;
30888
- expect(at("ambient", days) !== "fresh", "at room temperature it is past its best", { food: food.id });
30889
- if ("fridge" in catalog.rules.storage) expect(at("fridge", days) !== at("ambient", days) || at("fridge", days) === "fresh", "in the fridge it keeps better", { food: food.id });
30966
+ expect(at2("ambient", days) !== "fresh", "at room temperature it is past its best", { food: food.id });
30967
+ if ("fridge" in catalog.rules.storage) expect(at2("fridge", days) !== at2("ambient", days) || at2("fridge", days) === "fresh", "in the fridge it keeps better", { food: food.id });
30890
30968
  }
30891
30969
  },
30892
30970
  {