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