@adatechnology/game-floorplan-three 0.1.1 → 0.2.0
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/MIGRATION.md +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.global.js +1366 -27
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
package/dist/index.global.js
CHANGED
|
@@ -27,10 +27,10 @@ var GameFloorplanThree = (() => {
|
|
|
27
27
|
VERSION: () => VERSION,
|
|
28
28
|
bindNavigator: () => bindNavigator,
|
|
29
29
|
buildSpecimenMeshes: () => buildSpecimenMeshes,
|
|
30
|
-
create: () =>
|
|
30
|
+
create: () => create3,
|
|
31
31
|
createFloorNavigator: () => createFloorNavigator,
|
|
32
32
|
createFloorplanTestModule: () => createFloorplanTestModule,
|
|
33
|
-
createHouseRenderer: () =>
|
|
33
|
+
createHouseRenderer: () => create3,
|
|
34
34
|
createHouseScenarios: () => createHouseScenarios,
|
|
35
35
|
createTranslator: () => createTranslator,
|
|
36
36
|
en: () => en,
|
|
@@ -1795,7 +1795,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1795
1795
|
"what.fridge": "fridge",
|
|
1796
1796
|
"what.pantry": "pantry",
|
|
1797
1797
|
"what.cabinet": "cabinet",
|
|
1798
|
-
"warn.interactablesIncomplete": "floorplan-three: cfg.interactives is incomplete (GameInteractables, GameInteractablesHousehold, GameInteractablesThree
|
|
1798
|
+
"warn.interactablesIncomplete": "floorplan-three: cfg.interactives is incomplete (GameInteractables, GameInteractablesHousehold, GameInteractablesThree)",
|
|
1799
1799
|
"message.locked": "Locked.",
|
|
1800
1800
|
"message.boarded": "Locked: the door is boarded up.",
|
|
1801
1801
|
"message.pickedUp": "Picked up: {name}{qty}",
|
|
@@ -1820,7 +1820,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1820
1820
|
"what.fridge": "geladeira",
|
|
1821
1821
|
"what.pantry": "despensa",
|
|
1822
1822
|
"what.cabinet": "arm\xE1rio",
|
|
1823
|
-
"warn.interactablesIncomplete": "floorplan-three: cfg.interactives incompleto (GameInteractables, GameInteractablesHousehold, GameInteractablesThree
|
|
1823
|
+
"warn.interactablesIncomplete": "floorplan-three: cfg.interactives incompleto (GameInteractables, GameInteractablesHousehold, GameInteractablesThree)",
|
|
1824
1824
|
"message.locked": "Trancada.",
|
|
1825
1825
|
"message.boarded": "Trancada: a porta est\xE1 bloqueada com t\xE1buas.",
|
|
1826
1826
|
"message.pickedUp": "Pegou: {name}{qty}",
|
|
@@ -4515,7 +4515,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4515
4515
|
shared.ctx.electricalInfo = null;
|
|
4516
4516
|
if (!E) return;
|
|
4517
4517
|
const R = shared.ctx.r, nA = R.floors.length, lotGroup = R.lot ? "lot" : "f0", concreteColor = 11973547, iron = 4869200, wireRun = 1842206, info = { pole: null, meter: null, panel: null, conduits: [], outlets: [], switches: [], circuits: E.circuits || [], exposed: !!E.exposed };
|
|
4518
|
-
const
|
|
4518
|
+
const en3 = E.serviceEntrance, KV = shared.ctx.iv ? shared.ctx.iv.plane : null;
|
|
4519
4519
|
const wireL = (a, b, r_ = 8e-3) => {
|
|
4520
4520
|
const L = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
4521
4521
|
if (L < 1e-3) return;
|
|
@@ -4531,25 +4531,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
4531
4531
|
for (const dx of [-0.65, -0.2, 0.25, 0.7]) cylBase("plain", u + dx, h - 0.62, v, 0.025, 0.1, 13684680);
|
|
4532
4532
|
cursor.pc = null;
|
|
4533
4533
|
};
|
|
4534
|
-
if (
|
|
4535
|
-
const P =
|
|
4534
|
+
if (en3 && en3.pole) {
|
|
4535
|
+
const P = en3.pole;
|
|
4536
4536
|
if (!(KV && KV.serviceEntrance)) pole(P.u, P.v, P.h);
|
|
4537
4537
|
info.pole = { pos: [P.u, 0, P.v], h: P.h };
|
|
4538
4538
|
for (const k of [-1, 1]) pole(P.u + k * 22, P.v, P.h);
|
|
4539
4539
|
cursor.pc = pieceRecord("wiring:grid", "copper", null, { tags: ["wiring"] });
|
|
4540
4540
|
for (const dx of [-0.65, -0.2, 0.25, 0.7]) for (const k of [-1, 1]) wireL([P.u + dx, P.h - 0.5, P.v], [P.u + k * 22 + dx, P.h - 0.5, P.v], 7e-3);
|
|
4541
|
-
if (
|
|
4542
|
-
const r0 =
|
|
4541
|
+
if (en3.drop && en3.drop.length > 1 && !(KV && KV.serviceEntrance)) {
|
|
4542
|
+
const r0 = en3.drop[0], r1 = en3.drop[en3.drop.length - 1];
|
|
4543
4543
|
for (const dz of [0, 0.04]) wireL([r0[0], r0[2], r0[1]], [r1[0], r1[2], r1[1] + dz], 9e-3);
|
|
4544
4544
|
wireL([P.u - 0.2, P.h - 0.5, P.v], [r0[0], r0[2], r0[1]], 8e-3);
|
|
4545
4545
|
}
|
|
4546
4546
|
cursor.pc = null;
|
|
4547
|
-
if (
|
|
4548
|
-
const d0 =
|
|
4547
|
+
if (en3.descent && en3.descent.length > 1 && !(KV && KV.serviceEntrance)) {
|
|
4548
|
+
const d0 = en3.descent[0], d1 = en3.descent[en3.descent.length - 1];
|
|
4549
4549
|
cylBase("metal", d0[0], d1[2], d0[1], 0.02, d0[2] - d1[2], 9080466);
|
|
4550
4550
|
bx("metal", d0[0] - 0.05, d0[2] - 0.03, d0[1] - 0.05, d0[0] + 0.05, d0[2] + 0.08, d0[1] + 0.05, 8027780);
|
|
4551
4551
|
}
|
|
4552
|
-
const M =
|
|
4552
|
+
const M = en3.meter;
|
|
4553
4553
|
if (M) {
|
|
4554
4554
|
const hw = (M.w || 0.35) / 2, hd = (M.d || 0.2) / 2, hh = (M.h || 0.5) / 2, fr = M.side === "front" ? -1 : 1;
|
|
4555
4555
|
if (!(KV && KV.meter)) bx("plain", M.u - hw, M.y - hh, M.v - hd, M.u + hw, M.y + hh, M.v + hd, 14277597);
|
|
@@ -6978,7 +6978,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6978
6978
|
const wants = (roomId) => lightBase(roomId);
|
|
6979
6979
|
const entById = new Map(plane.items.map((e) => [e.id, e]));
|
|
6980
6980
|
const entByItem = new Map(plane.items.map((e) => [e.item, e]));
|
|
6981
|
-
IV.mats = { plain: shared.mats.plain, metal: shared.mats.metal, wood: shared.mats.wood, glass: shared.mats.glass, fabric: shared.mats.fabric, plant: shared.mats.plant, water: shared.mats.water, emissive: shared.mats.emissive, atlas_picture: shared.mats.picture, atlas_floor: shared.mats.
|
|
6981
|
+
IV.mats = { plain: shared.mats.plain, metal: shared.mats.metal, wood: shared.mats.wood, glass: shared.mats.glass, fabric: shared.mats.fabric, plant: shared.mats.plant, water: shared.mats.water, emissive: shared.mats.emissive, atlas_picture: shared.mats.picture, atlas_floor: shared.mats.floor };
|
|
6982
6982
|
const ev = (e) => ivEvent(h, e);
|
|
6983
6983
|
const world = IV.world = A.createWorld(r, { water, seed: r.seed, onEvent: ev });
|
|
6984
6984
|
const add0 = world.add;
|
|
@@ -6997,10 +6997,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
6997
6997
|
}
|
|
6998
6998
|
return add0(id, spec, tr);
|
|
6999
6999
|
};
|
|
7000
|
-
const
|
|
7000
|
+
const added = A.add(world, plane, { isBlocked: A.blockedOf(r), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
|
|
7001
7001
|
world.add = add0;
|
|
7002
|
-
IV.warnings =
|
|
7003
|
-
IV.
|
|
7002
|
+
IV.warnings = added.warnings;
|
|
7003
|
+
IV.added = added;
|
|
7004
7004
|
if (h.state.iv) {
|
|
7005
7005
|
try {
|
|
7006
7006
|
const st = JSON.parse(JSON.stringify(h.state.iv));
|
|
@@ -7050,7 +7050,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7050
7050
|
for (const l of out.lights) l.removeFromParent();
|
|
7051
7051
|
const group = ivGroup(ent), g0 = cursor.group, root = new THREE.Group();
|
|
7052
7052
|
root.name = "iv:" + ent.id;
|
|
7053
|
-
root.position.set(item.x, ent.
|
|
7053
|
+
root.position.set(item.x, ent.floorY, item.z);
|
|
7054
7054
|
root.rotation.y = item.ry;
|
|
7055
7055
|
root.userData.iv = ent.id;
|
|
7056
7056
|
const screen = spec.devices && spec.devices.some((d) => d.kind === "screen");
|
|
@@ -7074,7 +7074,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7074
7074
|
root.add(m);
|
|
7075
7075
|
continue;
|
|
7076
7076
|
}
|
|
7077
|
-
ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, item.x, ent.
|
|
7077
|
+
ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, item.x, ent.floorY, item.z, item.ry, null);
|
|
7078
7078
|
m.geometry.dispose();
|
|
7079
7079
|
} else root.add(m);
|
|
7080
7080
|
}
|
|
@@ -7095,7 +7095,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7095
7095
|
roomLightMask(m);
|
|
7096
7096
|
}
|
|
7097
7097
|
});
|
|
7098
|
-
const E = { id: ent.id, type, entry: ent, floor: ent.floor, group, root, parts: out.parts, spec, screen: body, pos: [item.x, ent.
|
|
7098
|
+
const E = { id: ent.id, type, entry: ent, floor: ent.floor, group, root, parts: out.parts, spec, screen: body, pos: [item.x, ent.floorY, item.z], ry: item.ry, origin: ent.origin };
|
|
7099
7099
|
IV.entries.set(ent.id, E);
|
|
7100
7100
|
if (root.children.length) IV.roots.push(E);
|
|
7101
7101
|
return spec;
|
|
@@ -7454,7 +7454,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7454
7454
|
breaker: com((circuit, on) => {
|
|
7455
7455
|
if (on === void 0) return w.power.breaker(circuit);
|
|
7456
7456
|
w.power.setBreaker(circuit, !!on);
|
|
7457
|
-
const q = IV.plane.
|
|
7457
|
+
const q = IV.plane.panel && IV.entries.get(IV.plane.panel);
|
|
7458
7458
|
if (q && q.parts["breaker_" + circuit]) w.setPart(q.id, "breaker_" + circuit, on ? 1 : 0);
|
|
7459
7459
|
IV.dirty = true;
|
|
7460
7460
|
return !!on;
|
|
@@ -7523,6 +7523,1345 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7523
7523
|
Object.assign(K, { props, TYPES, newState, enter, tagDamage });
|
|
7524
7524
|
}
|
|
7525
7525
|
|
|
7526
|
+
// ../game-floorplan-interactables/dist/index.js
|
|
7527
|
+
var en2 = {
|
|
7528
|
+
"error.missingKit": "game-floorplan-interactables: create needs GameInteractables and GameInteractablesHousehold",
|
|
7529
|
+
"error.unknownOwnType": "game-floorplan-interactables: unknown own type: {type}",
|
|
7530
|
+
"warn.cylinderNoCabinet": "cylinder {id} under the counter has no kitchen cabinet to hide it",
|
|
7531
|
+
"warn.cabinetNoDoor": "cabinet {cabinet} has no door for the cylinder {id}",
|
|
7532
|
+
"warn.switchUnknownLamp": "switch {id} controls {lamp}, which does not exist",
|
|
7533
|
+
"warn.pointNoObject": "point {id} ({kind}) has no object for {item}",
|
|
7534
|
+
"warn.buildEmpty": "build returned nothing for {id}"
|
|
7535
|
+
};
|
|
7536
|
+
var ptBR2 = {
|
|
7537
|
+
"error.missingKit": "game-floorplan-interactables: create precisa de GameInteractables e GameInteractablesHousehold",
|
|
7538
|
+
"error.unknownOwnType": "game-floorplan-interactables: tipo pr\xF3prio desconhecido: {type}",
|
|
7539
|
+
"warn.cylinderNoCabinet": "botij\xE3o {id} sob a bancada sem arm\xE1rio de cozinha para escond\xEA-lo",
|
|
7540
|
+
"warn.cabinetNoDoor": "arm\xE1rio {cabinet} sem porta para o botij\xE3o {id}",
|
|
7541
|
+
"warn.switchUnknownLamp": "interruptor {id} controla {lamp}, que n\xE3o existe",
|
|
7542
|
+
"warn.pointNoObject": "ponto {id} ({kind}) sem objeto para {item}",
|
|
7543
|
+
"warn.buildEmpty": "construir devolveu vazio para {id}"
|
|
7544
|
+
};
|
|
7545
|
+
function createTranslator2(locale, table) {
|
|
7546
|
+
const base = locale && /^pt/i.test(locale) ? ptBR2 : en2;
|
|
7547
|
+
const messages = { ...base, ...table ?? {} };
|
|
7548
|
+
return (key, params) => (messages[key] ?? key).replace(/\{(\w+)\}/g, (_m, name) => params && params[name] !== void 0 ? String(params[name]) : `{${name}}`);
|
|
7549
|
+
}
|
|
7550
|
+
var TYPE_MAP = Object.freeze({
|
|
7551
|
+
fridge: { type: "fridge" },
|
|
7552
|
+
// was `geladeira`
|
|
7553
|
+
fridge_large: { type: "fridge" },
|
|
7554
|
+
// was `geladeira2`
|
|
7555
|
+
display_fridge_medium: { type: "fridge", variant: "steel" },
|
|
7556
|
+
// was `geladeira_med`
|
|
7557
|
+
display_fridge: { type: "fridge", variant: "steel" },
|
|
7558
|
+
// was `refrig_exp`
|
|
7559
|
+
freezer: { type: "fridge_compact" },
|
|
7560
|
+
// was `freezer`
|
|
7561
|
+
kitchen_cabinet: { compound: "sink" },
|
|
7562
|
+
// was `armario_cozinha`
|
|
7563
|
+
kitchen_cabinet_small: { compound: "sink" },
|
|
7564
|
+
// was `armario_cozinha_p`
|
|
7565
|
+
kitchen_cabinet_large: { compound: "sink" },
|
|
7566
|
+
// was `armario_cozinha_g`
|
|
7567
|
+
washbasin: { compound: "basin" },
|
|
7568
|
+
// was `pia_b`
|
|
7569
|
+
pedestal_basin: { compound: "basin" },
|
|
7570
|
+
// was `pia_coluna`
|
|
7571
|
+
wardrobe: { type: "wardrobe" },
|
|
7572
|
+
// was `guarda`
|
|
7573
|
+
wardrobe_small: { type: "wardrobe" },
|
|
7574
|
+
// was `guarda_peq`
|
|
7575
|
+
wardrobe_large: { type: "wardrobe" },
|
|
7576
|
+
// was `guarda_g`
|
|
7577
|
+
closet_wardrobe: { type: "wardrobe" },
|
|
7578
|
+
// was `guarda_closet`
|
|
7579
|
+
dresser: { type: "dresser" },
|
|
7580
|
+
// was `comoda`
|
|
7581
|
+
nightstand: { type: "nightstand" },
|
|
7582
|
+
// was `criado`
|
|
7583
|
+
pantry: { type: "pantry" },
|
|
7584
|
+
// was `despensa`
|
|
7585
|
+
laundry_cabinet: { type: "pantry" },
|
|
7586
|
+
// was `armario_lav`
|
|
7587
|
+
china_cabinet: { type: "pantry" },
|
|
7588
|
+
// was `cristaleira`
|
|
7589
|
+
filing_cabinet: { type: "dresser" },
|
|
7590
|
+
// was `arquivo`
|
|
7591
|
+
console_table: { type: "dresser" },
|
|
7592
|
+
// was `aparador_c`
|
|
7593
|
+
tv_unit: { type: "kitchen_cabinet_base" },
|
|
7594
|
+
// was `rack`
|
|
7595
|
+
tv_unit_small: { type: "kitchen_cabinet_base" },
|
|
7596
|
+
// was `rack_peq`
|
|
7597
|
+
tv_unit_large: { type: "kitchen_cabinet_base" },
|
|
7598
|
+
// was `rack_grande`
|
|
7599
|
+
stove: { type: "stove" },
|
|
7600
|
+
// was `fogao`
|
|
7601
|
+
stove_4burner: { type: "stove" },
|
|
7602
|
+
// was `fogao4`
|
|
7603
|
+
cooking_gas_cylinder: { type: "gas_bottle", dim: "none" },
|
|
7604
|
+
// was `botijao_gas`
|
|
7605
|
+
gas_cylinder: { type: "gas_bottle", dim: "none" },
|
|
7606
|
+
// was `botijao`
|
|
7607
|
+
tv: { type: "tv" },
|
|
7608
|
+
// was `tv`
|
|
7609
|
+
tv_large: { type: "tv" },
|
|
7610
|
+
// was `tv_grande`
|
|
7611
|
+
microwave: { type: "microwave" },
|
|
7612
|
+
// was `microondas`
|
|
7613
|
+
washing_machine: { type: "washing_machine" },
|
|
7614
|
+
// was `maquina`
|
|
7615
|
+
shower: { type: "shower", dim: "wd" },
|
|
7616
|
+
// was `box`
|
|
7617
|
+
shower_large: { type: "shower", dim: "wd" },
|
|
7618
|
+
// was `box_g`
|
|
7619
|
+
toilet: { type: "toilet", dim: "wd" },
|
|
7620
|
+
// was `vaso`
|
|
7621
|
+
laundry_tub: { type: "utility_sink", dim: "wd" },
|
|
7622
|
+
// was `tanque`
|
|
7623
|
+
sofa_2seat: { type: "sofa" },
|
|
7624
|
+
// was `sofa2`
|
|
7625
|
+
sofa_3seat: { type: "sofa" },
|
|
7626
|
+
// was `sofa3`
|
|
7627
|
+
sofa_l: { type: "sofa" },
|
|
7628
|
+
// was `sofa_l`
|
|
7629
|
+
sofa_xl: { type: "sofa" },
|
|
7630
|
+
// was `sofa_xl`
|
|
7631
|
+
armchair: { type: "armchair" },
|
|
7632
|
+
// was `poltrona`
|
|
7633
|
+
armchair_high: { type: "armchair" },
|
|
7634
|
+
// was `poltrona_alta`
|
|
7635
|
+
stool: { type: "dining_chair" },
|
|
7636
|
+
// was `banqueta`
|
|
7637
|
+
camp_chair: { type: "camp_chair", dim: "wd" },
|
|
7638
|
+
// was `cadeira_camping`
|
|
7639
|
+
rocking_chair: { type: "armchair" },
|
|
7640
|
+
// was `cadeira_balanco`
|
|
7641
|
+
rustic_sink: { compound: "rustic_sink" },
|
|
7642
|
+
// was `pia_rustica`: the sink of the cabin or shack: the basin the whole width, no cabinet under it; a wall cabinet only if there is `overhead` content
|
|
7643
|
+
improvised_bed: { type: "bed_single", dim: "wd" },
|
|
7644
|
+
// was `cama_improvisada`
|
|
7645
|
+
log_bench: { type: "bench", dim: "wd" },
|
|
7646
|
+
// was `banco_tronco`
|
|
7647
|
+
plank_shelf: { type: "pantry", variant: "garage" },
|
|
7648
|
+
// was `prateleira_tabua`
|
|
7649
|
+
sideboard: { type: "dresser" },
|
|
7650
|
+
// was `aparador`
|
|
7651
|
+
buffet: { type: "dresser" },
|
|
7652
|
+
// was `bufe`
|
|
7653
|
+
single_bed: { type: "bed_single", dim: "wd" },
|
|
7654
|
+
// was `cama_solteiro`
|
|
7655
|
+
double_bed: { type: "bed_double", dim: "wd" },
|
|
7656
|
+
// was `cama_casal`
|
|
7657
|
+
queen_bed: { type: "bed_double", dim: "wd" },
|
|
7658
|
+
// was `cama_queen`
|
|
7659
|
+
king_bed: { type: "bed_double", dim: "wd" },
|
|
7660
|
+
// was `cama_king`
|
|
7661
|
+
bench: { type: "bench", dim: "wd" },
|
|
7662
|
+
// was `banco`
|
|
7663
|
+
garden_bench: { type: "bench", dim: "wd" },
|
|
7664
|
+
// was `banco_jardim`
|
|
7665
|
+
waiting_bench: { type: "bench", dim: "wd" },
|
|
7666
|
+
// was `espera`
|
|
7667
|
+
blinds: { type: "blinds" },
|
|
7668
|
+
// was `persiana`
|
|
7669
|
+
curtain: { type: "curtain" },
|
|
7670
|
+
// was `cortina`
|
|
7671
|
+
trash_bin: { type: "trash_bin" },
|
|
7672
|
+
// was `lixeira`
|
|
7673
|
+
outdoor_bin: { type: "wheelie_bin" },
|
|
7674
|
+
// was `lixeira_ext`
|
|
7675
|
+
mailbox: { type: "mailbox", dim: "none" },
|
|
7676
|
+
// was `caixa_correio`: the household draws the box on its post: position and rotation only
|
|
7677
|
+
doghouse: { type: "dog_house" },
|
|
7678
|
+
// was `casinha_cachorro`
|
|
7679
|
+
bbq_grill: { type: "bbq", dim: "wd" },
|
|
7680
|
+
// was `churrasqueira`
|
|
7681
|
+
bbq_simple: { type: "bbq", dim: "wd" },
|
|
7682
|
+
// was `churrasqueira_simples`
|
|
7683
|
+
clothesline: { type: "clothesline", dim: "wh" },
|
|
7684
|
+
// was `varal`
|
|
7685
|
+
tool_shelf: { type: "pantry", variant: "garage" },
|
|
7686
|
+
// was `estante_ferr`
|
|
7687
|
+
workbench: { type: "pantry", variant: "garage" },
|
|
7688
|
+
// was `bancada_ferr`
|
|
7689
|
+
// rural houses and campsite (types of the household pack: rural and camp)
|
|
7690
|
+
bunk_bed: { type: "bunk_bed", dim: "wd" },
|
|
7691
|
+
// was `beliche`
|
|
7692
|
+
wood_stove: { type: "wood_stove", dim: "wd" },
|
|
7693
|
+
// was `fogao_lenha`: the flue rises to the chimney height (cabin); the fireplace is handled in `planSimple` (it moves and changes height)
|
|
7694
|
+
fireplace: { type: "fireplace", dim: "w" },
|
|
7695
|
+
// was `lareira`
|
|
7696
|
+
outhouse: { type: "outhouse", dim: "wdh" },
|
|
7697
|
+
// was `privada`
|
|
7698
|
+
well: { type: "well", dim: "none" },
|
|
7699
|
+
// was `poco`
|
|
7700
|
+
cooler: { type: "cooler", dim: "wd" },
|
|
7701
|
+
// was `cooler`
|
|
7702
|
+
campfire: { type: "campfire", dim: "wd" },
|
|
7703
|
+
// was `fogueira`
|
|
7704
|
+
camp_stove: { type: "camp_stove", dim: "wd" },
|
|
7705
|
+
// was `fogareiro`
|
|
7706
|
+
camp_gas_canister: { type: "gas_canister", dim: "none" },
|
|
7707
|
+
// was `botijao_camping`
|
|
7708
|
+
camp_table: { type: "camp_table", dim: "wdh" },
|
|
7709
|
+
// was `mesa_camping`
|
|
7710
|
+
// kerosene/gas lanterns: a `lamp` device without electricity (the grid does not matter); the ceiling one is the `hanging` variant
|
|
7711
|
+
oil_lamp: { type: "lantern_lamp", dim: "x" },
|
|
7712
|
+
// was `lampiao`
|
|
7713
|
+
camp_lantern: { type: "lantern_lamp", dim: "x" },
|
|
7714
|
+
// was `lampiao_camping`
|
|
7715
|
+
ceiling_oil_lamp: { type: "lantern_lamp", variant: "hanging", dim: "x" },
|
|
7716
|
+
// was `lampiao_teto`
|
|
7717
|
+
// lamps: objects of the adapter (the kit has no lamp mesh; the house renderer draws the fixture)
|
|
7718
|
+
ceiling_light: { type: "lamp", watts: 15 },
|
|
7719
|
+
// was `plafon`
|
|
7720
|
+
pendant: { type: "lamp", watts: 20 },
|
|
7721
|
+
// was `pendente`
|
|
7722
|
+
track_spot: { type: "lamp", watts: 10 },
|
|
7723
|
+
// was `spot_trilho`
|
|
7724
|
+
chandelier: { type: "lamp", watts: 60 },
|
|
7725
|
+
// was `lustre`
|
|
7726
|
+
floor_lamp: { type: "lamp", watts: 12 },
|
|
7727
|
+
// was `luminaria`
|
|
7728
|
+
table_lamp: { type: "lamp", watts: 9 }
|
|
7729
|
+
// was `abajur`
|
|
7730
|
+
});
|
|
7731
|
+
var CHAIR_TABLES = Object.freeze({
|
|
7732
|
+
dining_table: "dining",
|
|
7733
|
+
// was `mesa`
|
|
7734
|
+
dining_table_small: "dining",
|
|
7735
|
+
// was `mesa_peq`
|
|
7736
|
+
dining_table_round: "dining",
|
|
7737
|
+
// was `mesa_red`
|
|
7738
|
+
dining_table_large: "dining",
|
|
7739
|
+
// was `mesa_grande`
|
|
7740
|
+
gourmet_table: "dining",
|
|
7741
|
+
// was `mesa_gourmet`
|
|
7742
|
+
gourmet_table_small: "dining",
|
|
7743
|
+
// was `mesa_gourmet_peq`
|
|
7744
|
+
outdoor_table: "dining",
|
|
7745
|
+
// was `mesa_ext`
|
|
7746
|
+
office_desk: "office",
|
|
7747
|
+
// was `mesa_escr`
|
|
7748
|
+
office_desk_large: "office",
|
|
7749
|
+
// was `mesa_escr_g`
|
|
7750
|
+
desk: "office"
|
|
7751
|
+
// was `escrivaninha`
|
|
7752
|
+
});
|
|
7753
|
+
var DINING_CHAIR_SIDE = 0.45;
|
|
7754
|
+
var CONTENT_MAP = Object.freeze({
|
|
7755
|
+
// food
|
|
7756
|
+
sugar: "sugar",
|
|
7757
|
+
// was `acucar`
|
|
7758
|
+
rice: "rice",
|
|
7759
|
+
// was `arroz`
|
|
7760
|
+
biscuits: "biscuits",
|
|
7761
|
+
// was `biscoito`
|
|
7762
|
+
coffee: "coffee",
|
|
7763
|
+
// was `cafe`
|
|
7764
|
+
raw_beef: "frozen_meat",
|
|
7765
|
+
// was `carne`
|
|
7766
|
+
packed_meat: "frozen_meat",
|
|
7767
|
+
// was `carne`
|
|
7768
|
+
flour: "flour",
|
|
7769
|
+
// was `farinha`
|
|
7770
|
+
beans: "beans",
|
|
7771
|
+
// was `feijao`
|
|
7772
|
+
apple: "apple",
|
|
7773
|
+
// was `fruta`
|
|
7774
|
+
fruit: "apple",
|
|
7775
|
+
// was `fruta`
|
|
7776
|
+
yogurt: "yogurt",
|
|
7777
|
+
// was `iogurte`
|
|
7778
|
+
canned_food: "canned_food",
|
|
7779
|
+
// was `lata_atum`
|
|
7780
|
+
canned_tuna: "canned_food",
|
|
7781
|
+
// was `lata_atum`
|
|
7782
|
+
canned_corn_and_peas: "canned_food",
|
|
7783
|
+
// was `lata_milho`
|
|
7784
|
+
canned_corn: "canned_food",
|
|
7785
|
+
// was `lata_milho`
|
|
7786
|
+
milk_carton: "milk_carton",
|
|
7787
|
+
// was `leite`
|
|
7788
|
+
pasta: "pasta",
|
|
7789
|
+
// was `macarrao`
|
|
7790
|
+
cooking_oil: "cooking_oil",
|
|
7791
|
+
// was `oleo`
|
|
7792
|
+
eggs: "eggs",
|
|
7793
|
+
// was `ovos`
|
|
7794
|
+
cheese: "cheese",
|
|
7795
|
+
// was `queijo`
|
|
7796
|
+
leftover_meal: "bowl",
|
|
7797
|
+
// was `sobras`
|
|
7798
|
+
leftovers: "bowl",
|
|
7799
|
+
// was `sobras`
|
|
7800
|
+
ice_cream: "ice_cream",
|
|
7801
|
+
// was `sorvete`
|
|
7802
|
+
seasoning: "salt",
|
|
7803
|
+
// was `tempero`
|
|
7804
|
+
spices: "salt",
|
|
7805
|
+
// was `tempero`
|
|
7806
|
+
// water and drink
|
|
7807
|
+
water_jug_5l: "water_bottle",
|
|
7808
|
+
// was `agua_galao`
|
|
7809
|
+
water_jug: "water_bottle",
|
|
7810
|
+
// was `agua_galao`
|
|
7811
|
+
water_bottle: "water_bottle",
|
|
7812
|
+
// was `agua_garrafa`
|
|
7813
|
+
soda_can: "soda_can",
|
|
7814
|
+
// was `refrigerante`
|
|
7815
|
+
soda: "soda_can",
|
|
7816
|
+
// was `refrigerante`
|
|
7817
|
+
// medicine
|
|
7818
|
+
alcohol_70: "alcohol_70",
|
|
7819
|
+
// was `alcool`
|
|
7820
|
+
rubbing_alcohol: "alcohol_70",
|
|
7821
|
+
// was `alcool`
|
|
7822
|
+
adhesive_bandages: "bandage",
|
|
7823
|
+
// was `curativo`
|
|
7824
|
+
bandages: "bandage",
|
|
7825
|
+
// was `curativo`
|
|
7826
|
+
insulin: "first_aid_kit",
|
|
7827
|
+
// was `insulina`
|
|
7828
|
+
painkillers: "painkillers",
|
|
7829
|
+
// was `paracetamol`
|
|
7830
|
+
painkiller: "painkillers",
|
|
7831
|
+
// was `paracetamol`
|
|
7832
|
+
maintenance_medication: "painkillers",
|
|
7833
|
+
// was `remedio`
|
|
7834
|
+
medicine: "painkillers",
|
|
7835
|
+
// was `remedio`
|
|
7836
|
+
// cleaning and hygiene
|
|
7837
|
+
bleach: "bleach",
|
|
7838
|
+
// was `agua_sanitaria`
|
|
7839
|
+
disinfectant: "bleach",
|
|
7840
|
+
// was `desinfetante`
|
|
7841
|
+
detergent: "detergent",
|
|
7842
|
+
// was `detergente`
|
|
7843
|
+
dish_soap: "detergent",
|
|
7844
|
+
// was `detergente`
|
|
7845
|
+
toothbrush: "toothbrush",
|
|
7846
|
+
// was `escova_dente`
|
|
7847
|
+
sponge: "sponge",
|
|
7848
|
+
// was `esponja`
|
|
7849
|
+
rubber_gloves: "sponge",
|
|
7850
|
+
// was `luvas`
|
|
7851
|
+
toilet_paper: "toilet_paper",
|
|
7852
|
+
// was `papel_higienico`
|
|
7853
|
+
laundry_powder: "detergent",
|
|
7854
|
+
// was `sabao_po`
|
|
7855
|
+
washing_powder: "detergent",
|
|
7856
|
+
// was `sabao_po`
|
|
7857
|
+
soap: "soap",
|
|
7858
|
+
// was `sabonete`
|
|
7859
|
+
shampoo: "shampoo",
|
|
7860
|
+
// was `shampoo`
|
|
7861
|
+
// clothes
|
|
7862
|
+
jeans: "jeans",
|
|
7863
|
+
// was `calca`
|
|
7864
|
+
trousers: "jeans",
|
|
7865
|
+
// was `calca`
|
|
7866
|
+
tshirt: "tshirt",
|
|
7867
|
+
// was `camisa`
|
|
7868
|
+
shirt: "tshirt",
|
|
7869
|
+
// was `camisa`
|
|
7870
|
+
t_shirt: "tshirt",
|
|
7871
|
+
// was `camiseta`
|
|
7872
|
+
jacket: "jacket",
|
|
7873
|
+
// was `casaco`
|
|
7874
|
+
coat: "jacket",
|
|
7875
|
+
// was `casaco`
|
|
7876
|
+
blanket: "blanket",
|
|
7877
|
+
// was `cobertor`
|
|
7878
|
+
socks: "socks",
|
|
7879
|
+
// was `meias`
|
|
7880
|
+
underwear: "underwear",
|
|
7881
|
+
// was `roupa_intima`
|
|
7882
|
+
sneakers: "sneakers",
|
|
7883
|
+
// was `sapato`
|
|
7884
|
+
shoes: "sneakers",
|
|
7885
|
+
// was `sapato`
|
|
7886
|
+
// utensils
|
|
7887
|
+
cup: "cup",
|
|
7888
|
+
// was `caneca`
|
|
7889
|
+
mug: "cup",
|
|
7890
|
+
// was `caneca`
|
|
7891
|
+
plate: "plate",
|
|
7892
|
+
// was `prato`
|
|
7893
|
+
china_plates: "plate",
|
|
7894
|
+
// was `prato`
|
|
7895
|
+
plates: "plate",
|
|
7896
|
+
// was `prato`
|
|
7897
|
+
wine_glass: "cup",
|
|
7898
|
+
// was `taca`
|
|
7899
|
+
wine_glasses: "cup",
|
|
7900
|
+
// was `taca`
|
|
7901
|
+
pot: "pot",
|
|
7902
|
+
// was `panela`
|
|
7903
|
+
// tools and electronics
|
|
7904
|
+
pliers: "screwdriver",
|
|
7905
|
+
// was `alicate`
|
|
7906
|
+
bucket: "paint_can",
|
|
7907
|
+
// was `balde`
|
|
7908
|
+
cable_bundle: "phone_charger",
|
|
7909
|
+
// was `cabos`
|
|
7910
|
+
cables: "phone_charger",
|
|
7911
|
+
// was `cabos`
|
|
7912
|
+
pen: "pen",
|
|
7913
|
+
// was `caneta`
|
|
7914
|
+
phone_charger: "phone_charger",
|
|
7915
|
+
// was `carregador`
|
|
7916
|
+
charger: "phone_charger",
|
|
7917
|
+
// was `carregador`
|
|
7918
|
+
screwdriver: "screwdriver",
|
|
7919
|
+
// was `chave_fenda`
|
|
7920
|
+
house_key: "wallet",
|
|
7921
|
+
// was `chaves`
|
|
7922
|
+
keys: "wallet",
|
|
7923
|
+
// was `chaves`
|
|
7924
|
+
remote_control: "batteries",
|
|
7925
|
+
// was `controle_remoto`
|
|
7926
|
+
rope: "rope",
|
|
7927
|
+
// was `corda`
|
|
7928
|
+
electrical_tape: "duct_tape",
|
|
7929
|
+
// was `fita_isolante`
|
|
7930
|
+
insulating_tape: "duct_tape",
|
|
7931
|
+
// was `fita_isolante`
|
|
7932
|
+
flashlight: "flashlight",
|
|
7933
|
+
// was `lanterna`
|
|
7934
|
+
backpack: "backpack",
|
|
7935
|
+
// was `mochila`
|
|
7936
|
+
eyeglasses: "wallet",
|
|
7937
|
+
// was `oculos`
|
|
7938
|
+
glasses: "wallet",
|
|
7939
|
+
// was `oculos`
|
|
7940
|
+
screws: "duct_tape",
|
|
7941
|
+
// was `parafusos`
|
|
7942
|
+
batteries: "batteries",
|
|
7943
|
+
// was `pilhas`
|
|
7944
|
+
nails: "duct_tape",
|
|
7945
|
+
// was `pregos`
|
|
7946
|
+
// improvised weapons
|
|
7947
|
+
knife: "knife",
|
|
7948
|
+
// was `faca`
|
|
7949
|
+
kitchen_knife: "knife",
|
|
7950
|
+
// was `faca`
|
|
7951
|
+
stapler: "scissors",
|
|
7952
|
+
// was `grampeador`
|
|
7953
|
+
hammer: "hammer",
|
|
7954
|
+
// was `martelo`
|
|
7955
|
+
handsaw: "hammer",
|
|
7956
|
+
// was `serrote`
|
|
7957
|
+
hand_saw: "hammer",
|
|
7958
|
+
// was `serrote`
|
|
7959
|
+
scissors: "scissors",
|
|
7960
|
+
// was `tesoura`
|
|
7961
|
+
broom: "rope",
|
|
7962
|
+
// was `vassoura`
|
|
7963
|
+
// papers
|
|
7964
|
+
letter: "letter",
|
|
7965
|
+
// was `carta`
|
|
7966
|
+
bill: "bill",
|
|
7967
|
+
// was `conta`
|
|
7968
|
+
documents: "documents",
|
|
7969
|
+
// was `documento`
|
|
7970
|
+
dvd: "notebook",
|
|
7971
|
+
// was `dvd`
|
|
7972
|
+
dvds: "notebook",
|
|
7973
|
+
// was `dvd`
|
|
7974
|
+
book: "notebook",
|
|
7975
|
+
// was `livro`
|
|
7976
|
+
// trash
|
|
7977
|
+
food_packaging: "plastic_bag",
|
|
7978
|
+
// was `embalagem`
|
|
7979
|
+
packaging: "plastic_bag",
|
|
7980
|
+
// was `embalagem`
|
|
7981
|
+
paint_can: "paint_can",
|
|
7982
|
+
// was `lata_tinta`
|
|
7983
|
+
empty_can: "empty_can",
|
|
7984
|
+
// was `lata_vazia`
|
|
7985
|
+
flyer: "flyer",
|
|
7986
|
+
// was `panfleto`
|
|
7987
|
+
crumpled_paper: "crumpled_paper",
|
|
7988
|
+
// was `papel_amassado`
|
|
7989
|
+
trash_bag: "plastic_bag",
|
|
7990
|
+
// was `saco_lixo`
|
|
7991
|
+
full_trash_bag: "plastic_bag"
|
|
7992
|
+
// was `saco_lixo_cheio`
|
|
7993
|
+
});
|
|
7994
|
+
var CONTENT_BY_GROUP = Object.freeze({
|
|
7995
|
+
food: "canned_food",
|
|
7996
|
+
// was `comida`
|
|
7997
|
+
water: "water_bottle",
|
|
7998
|
+
// was `agua`
|
|
7999
|
+
medicine: "painkillers",
|
|
8000
|
+
// was `remedio`
|
|
8001
|
+
tool: "duct_tape",
|
|
8002
|
+
// was `ferramenta`
|
|
8003
|
+
improvised_weapon: "hammer",
|
|
8004
|
+
// was `arma_improvisada`
|
|
8005
|
+
clothes: "tshirt",
|
|
8006
|
+
// was `roupa`
|
|
8007
|
+
document: "documents",
|
|
8008
|
+
// was `documento`
|
|
8009
|
+
cleaning: "detergent",
|
|
8010
|
+
// was `limpeza`
|
|
8011
|
+
trash: "crumpled_paper",
|
|
8012
|
+
// was `lixo`
|
|
8013
|
+
utensil: "plate"
|
|
8014
|
+
// was `utensilio`
|
|
8015
|
+
});
|
|
8016
|
+
var CONTENT_FALLBACK = "crumpled_paper";
|
|
8017
|
+
var FROZEN_ITEMS = Object.freeze(["ice_cream", "frozen_meat"]);
|
|
8018
|
+
var DRAWER_ITEMS = Object.freeze(["underwear", "socks"]);
|
|
8019
|
+
var DRAWER_GROUPS = Object.freeze(["improvised_weapon", "tool"]);
|
|
8020
|
+
var OBJECT_SUBSTITUTES = Object.freeze({ mailbox: ["flyer", "postcard", "letter"] });
|
|
8021
|
+
var FIXTURES_OF_POINT = Object.freeze({
|
|
8022
|
+
tap: ["tap"],
|
|
8023
|
+
// was `torneira`
|
|
8024
|
+
shower: ["shower"],
|
|
8025
|
+
// was `chuveiro`
|
|
8026
|
+
flush: ["flush"],
|
|
8027
|
+
// was `descarga`
|
|
8028
|
+
tub: ["tap", "basin"],
|
|
8029
|
+
// was `tanque`
|
|
8030
|
+
machine: ["inlet"]
|
|
8031
|
+
// was `maquina`
|
|
8032
|
+
});
|
|
8033
|
+
var OWN_TYPES = Object.freeze({ lamp: true, gas_piped: true });
|
|
8034
|
+
var ADAPTER_VERSION = "0.3.0";
|
|
8035
|
+
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
8036
|
+
function mergeRegistry(base, extra) {
|
|
8037
|
+
const out = { ...base };
|
|
8038
|
+
if (extra) {
|
|
8039
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
8040
|
+
if (value == null) delete out[key];
|
|
8041
|
+
else out[key] = value;
|
|
8042
|
+
}
|
|
8043
|
+
}
|
|
8044
|
+
return out;
|
|
8045
|
+
}
|
|
8046
|
+
var PREFERENCE = Object.freeze({
|
|
8047
|
+
fridge: (s, c) => c.frozen(s) ? ["freezer", "fridge"] : ["fridge", "freezer"],
|
|
8048
|
+
fridge_compact: (s, c) => c.frozen(s) ? ["freezer", "fridge"] : ["fridge", "freezer"],
|
|
8049
|
+
kitchen_cabinet_base: (s, c) => DRAWER_GROUPS.includes(c.group(s)) ? ["drawer", "cupboard"] : ["cupboard", "drawer"],
|
|
8050
|
+
wardrobe: (s, c) => c.drawerItem(s) ? ["drawer_1", "drawer_2", "drawer_3", "shelves"] : ["shelves", "drawer_1", "drawer_2", "drawer_3"]
|
|
8051
|
+
});
|
|
8052
|
+
function create2(options = {}) {
|
|
8053
|
+
const opts = options || {};
|
|
8054
|
+
const GI = opts.GameInteractables;
|
|
8055
|
+
const HH = opts.GameInteractablesHousehold;
|
|
8056
|
+
const locale = opts.locale || "pt-BR";
|
|
8057
|
+
const msg = createTranslator2(locale, opts.messages);
|
|
8058
|
+
if (!GI || !HH) throw new Error(msg("error.missingKit"));
|
|
8059
|
+
const region = opts.region || "br";
|
|
8060
|
+
const hh = HH.createHousehold({ locale, region });
|
|
8061
|
+
const householdTypes = new Set(hh.types.map((t) => t.id));
|
|
8062
|
+
const worlds = /* @__PURE__ */ new WeakMap();
|
|
8063
|
+
const typeMap = mergeRegistry(TYPE_MAP, opts.typeMap);
|
|
8064
|
+
const contentMap = mergeRegistry(CONTENT_MAP, opts.contentMap);
|
|
8065
|
+
const contentByGroup = mergeRegistry(CONTENT_BY_GROUP, opts.contentByGroup);
|
|
8066
|
+
const chairTables = mergeRegistry(CHAIR_TABLES, opts.chairTables);
|
|
8067
|
+
const fixturesOfPoint = mergeRegistry(FIXTURES_OF_POINT, opts.fixturesOfPoint);
|
|
8068
|
+
const substitutes = mergeRegistry(OBJECT_SUBSTITUTES, opts.substitutes);
|
|
8069
|
+
const preference = mergeRegistry(PREFERENCE, opts.preference);
|
|
8070
|
+
const ownTypes = mergeRegistry(OWN_TYPES, opts.ownTypes);
|
|
8071
|
+
const frozenItems = new Set(opts.frozenItems ?? FROZEN_ITEMS);
|
|
8072
|
+
const drawerItems = new Set(opts.drawerItems ?? DRAWER_ITEMS);
|
|
8073
|
+
const chairSide = opts.chairSide ?? DINING_CHAIR_SIDE;
|
|
8074
|
+
const contentFallback = opts.contentFallback ?? CONTENT_FALLBACK;
|
|
8075
|
+
const seedKey = (id) => {
|
|
8076
|
+
if (!opts.seedKey) return id;
|
|
8077
|
+
const key = opts.seedKey(id);
|
|
8078
|
+
return key == null ? id : key;
|
|
8079
|
+
};
|
|
8080
|
+
function conv(o) {
|
|
8081
|
+
return {
|
|
8082
|
+
x: (u) => r3(o.ox + u),
|
|
8083
|
+
z: (v) => r3(o.oz + o.inw * v),
|
|
8084
|
+
ry: (fu, fv) => r3(Math.atan2(fu, o.inw * fv)),
|
|
8085
|
+
// local offset (lx, lz) of an object with rotation ry -> offset in the world (same convention as three.js)
|
|
8086
|
+
off: (ry, lx, lz) => [Math.cos(ry) * lx + Math.sin(ry) * lz, -Math.sin(ry) * lx + Math.cos(ry) * lz]
|
|
8087
|
+
};
|
|
8088
|
+
}
|
|
8089
|
+
function floorYOf(res, o, floor) {
|
|
8090
|
+
if (floor == null || floor < 0) return o.base;
|
|
8091
|
+
const f = (res.floors || []).find((x) => x.index === floor);
|
|
8092
|
+
return r3(o.base + (f ? f.y0 : 0));
|
|
8093
|
+
}
|
|
8094
|
+
function colorOf(res, color) {
|
|
8095
|
+
if (color == null) return void 0;
|
|
8096
|
+
if (typeof color === "number") return color;
|
|
8097
|
+
const v = res.colors && res.colors[color];
|
|
8098
|
+
return typeof v === "number" ? v : void 0;
|
|
8099
|
+
}
|
|
8100
|
+
function paletteOf(res) {
|
|
8101
|
+
const c = res.colors || {};
|
|
8102
|
+
const p = {};
|
|
8103
|
+
if (c.wood != null) p.wood = c.wood;
|
|
8104
|
+
if (c.fabric_main != null) p.fabric_main = c.fabric_main;
|
|
8105
|
+
if (c.fabric_accent != null) p.fabric_accent = c.fabric_accent;
|
|
8106
|
+
if (c.metal != null) p.metal = c.metal;
|
|
8107
|
+
return p;
|
|
8108
|
+
}
|
|
8109
|
+
function lightsOfState(res) {
|
|
8110
|
+
const electrical = res.utilities && res.utilities.electrical;
|
|
8111
|
+
return res.state !== "abandoned" && !!electrical && electrical.mode !== "offgrid";
|
|
8112
|
+
}
|
|
8113
|
+
function initialLight(res, popts, id, entry2) {
|
|
8114
|
+
const v = popts && popts.lightsOn;
|
|
8115
|
+
if (typeof v === "function") return !!v(id, entry2);
|
|
8116
|
+
if (typeof v === "boolean") return v;
|
|
8117
|
+
return !!(popts && popts.night) && lightsOfState(res);
|
|
8118
|
+
}
|
|
8119
|
+
const stackGroup = (s) => s.group ?? (opts.groupOf ? opts.groupOf(s.itemId) : null) ?? null;
|
|
8120
|
+
const preferenceContext = {
|
|
8121
|
+
frozen: (s) => frozenItems.has(s.itemId),
|
|
8122
|
+
group: stackGroup,
|
|
8123
|
+
drawerItem: (s) => drawerItems.has(s.itemId)
|
|
8124
|
+
};
|
|
8125
|
+
const itemOfContent = (c) => {
|
|
8126
|
+
const id = contentMap[c.itemId] || (hh.items[c.itemId] ? c.itemId : null) || contentByGroup[stackGroup(c)] || contentFallback;
|
|
8127
|
+
return hh.items[id] ? id : contentFallback;
|
|
8128
|
+
};
|
|
8129
|
+
const volume = (d) => d.size[0] * d.size[1] * d.size[2];
|
|
8130
|
+
const candidates = (id, objectType) => {
|
|
8131
|
+
const def = hh.items[id];
|
|
8132
|
+
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));
|
|
8133
|
+
return [id].concat(siblings.map((i) => i.id), substitutes[objectType] || []);
|
|
8134
|
+
};
|
|
8135
|
+
function distribute(type, probeItem, stacks) {
|
|
8136
|
+
const spec = hh.build(type, probeItem, HH.createRecorder().api);
|
|
8137
|
+
const conts = spec.containers || [];
|
|
8138
|
+
const contents = {};
|
|
8139
|
+
for (const c of conts) contents[c.id] = c.slots.map(() => null);
|
|
8140
|
+
const rejected = [];
|
|
8141
|
+
const pref = preference[type];
|
|
8142
|
+
for (const p of stacks || []) {
|
|
8143
|
+
const original = itemOfContent(p);
|
|
8144
|
+
const order = (pref ? pref(p, preferenceContext) : []).concat(conts.map((c) => c.id));
|
|
8145
|
+
let placed = false;
|
|
8146
|
+
for (const id of candidates(original, type)) {
|
|
8147
|
+
const def = hh.items[id];
|
|
8148
|
+
const qty = Math.max(1, Math.min(p.count || 1, def && def.stack || 1));
|
|
8149
|
+
for (const cid of order) {
|
|
8150
|
+
const c = conts.find((x) => x.id === cid);
|
|
8151
|
+
if (!c) continue;
|
|
8152
|
+
for (let i = 0; i < c.slots.length && !placed; i++) {
|
|
8153
|
+
if (contents[cid][i] || !GI.fitsSlot(id, c.slots[i], hh.items)) continue;
|
|
8154
|
+
const data = { source: p.itemId, group: p.group, pickable: p.pickable !== false };
|
|
8155
|
+
if (id !== original) data.substituteFor = original;
|
|
8156
|
+
contents[cid][i] = { type: id, qty, data };
|
|
8157
|
+
placed = true;
|
|
8158
|
+
}
|
|
8159
|
+
if (placed) break;
|
|
8160
|
+
}
|
|
8161
|
+
if (placed) break;
|
|
8162
|
+
}
|
|
8163
|
+
if (!placed) rejected.push(p);
|
|
8164
|
+
}
|
|
8165
|
+
return { contents, rejected };
|
|
8166
|
+
}
|
|
8167
|
+
function plan(res, popts = {}) {
|
|
8168
|
+
popts = popts || {};
|
|
8169
|
+
const o = { ox: popts.originX || 0, oz: popts.originZ || 0, inw: popts.inw || 1, base: popts.base || 0 };
|
|
8170
|
+
const K = conv(o);
|
|
8171
|
+
const floorSel = popts.floor;
|
|
8172
|
+
const externals = popts.externals !== false;
|
|
8173
|
+
const seed = popts.seed != null ? popts.seed : res.seed;
|
|
8174
|
+
const palette = paletteOf(res);
|
|
8175
|
+
const onFloor = (f, outdoor) => floorSel == null || f === floorSel || (outdoor || f < 0) && externals;
|
|
8176
|
+
const utilities = res.utilities || {};
|
|
8177
|
+
const electrical = utilities.electrical || null;
|
|
8178
|
+
const circuits = electrical && electrical.circuits || [];
|
|
8179
|
+
const contents = res.contents || {};
|
|
8180
|
+
const result = {
|
|
8181
|
+
version: ADAPTER_VERSION,
|
|
8182
|
+
template: res.template,
|
|
8183
|
+
seed: res.seed,
|
|
8184
|
+
floor: floorSel == null ? null : floorSel,
|
|
8185
|
+
items: [],
|
|
8186
|
+
outlets: [],
|
|
8187
|
+
// ids of the wall_socket entries
|
|
8188
|
+
switches: [],
|
|
8189
|
+
// ids of the wall_switch entries
|
|
8190
|
+
lights: [],
|
|
8191
|
+
// ids of the lamps (inside and outside)
|
|
8192
|
+
lanterns: [],
|
|
8193
|
+
// ids of the lanterns (lantern_lamp): kerosene/gas light, no grid
|
|
8194
|
+
canisters: [],
|
|
8195
|
+
// ids of the small camping cylinders (gas_canister)
|
|
8196
|
+
serviceEntrance: null,
|
|
8197
|
+
panel: null,
|
|
8198
|
+
// id of the electrical_panel entry (distribution board)
|
|
8199
|
+
meter: null,
|
|
8200
|
+
// id of the power_meter entry (meter box on the facade or the pillar)
|
|
8201
|
+
conduits: [],
|
|
8202
|
+
cylinders: [],
|
|
8203
|
+
// { id, stove, place }
|
|
8204
|
+
stoves: [],
|
|
8205
|
+
fixtures: [],
|
|
8206
|
+
// { object, fixture, global, point, pointKind }
|
|
8207
|
+
points: {},
|
|
8208
|
+
// global fixture -> point of the plumbing
|
|
8209
|
+
mapped: [],
|
|
8210
|
+
// ids of furniture of the plan that became objects of the kit (the renderer does not need to draw them)
|
|
8211
|
+
chairs: [],
|
|
8212
|
+
// ids of the chairs the adapter put around the tables (origin = the table, which the renderer keeps drawing)
|
|
8213
|
+
unmapped: {},
|
|
8214
|
+
// "category/type" -> count
|
|
8215
|
+
discarded: 0,
|
|
8216
|
+
// stacks of content that fit no slot
|
|
8217
|
+
warnings: [],
|
|
8218
|
+
origin: { x: o.ox, z: o.oz, inw: o.inw, base: o.base }
|
|
8219
|
+
};
|
|
8220
|
+
const byOrigin = /* @__PURE__ */ new Map();
|
|
8221
|
+
const seedOf2 = (id) => GI.hashString(String(seed) + ":" + seedKey(id));
|
|
8222
|
+
function push(e) {
|
|
8223
|
+
result.items.push(e);
|
|
8224
|
+
if (!byOrigin.has(e.origin)) byOrigin.set(e.origin, []);
|
|
8225
|
+
byOrigin.get(e.origin).push(e);
|
|
8226
|
+
return e;
|
|
8227
|
+
}
|
|
8228
|
+
function baseItem(m) {
|
|
8229
|
+
const item = {
|
|
8230
|
+
x: K.x(m.x),
|
|
8231
|
+
z: K.z(m.z),
|
|
8232
|
+
ry: m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0),
|
|
8233
|
+
w: m.w,
|
|
8234
|
+
d: m.d,
|
|
8235
|
+
h: m.h,
|
|
8236
|
+
y: m.y || 0,
|
|
8237
|
+
seed: seedOf2(m.id),
|
|
8238
|
+
palette
|
|
8239
|
+
};
|
|
8240
|
+
const color = colorOf(res, m.color);
|
|
8241
|
+
if (color != null) item.color = color;
|
|
8242
|
+
return item;
|
|
8243
|
+
}
|
|
8244
|
+
function entry2(id, type, item, origin, floor, extra) {
|
|
8245
|
+
return Object.assign({ id, type, item, origin, floor, floorY: floorYOf(res, o, floor), connections: {} }, extra || {});
|
|
8246
|
+
}
|
|
8247
|
+
function store(targets, stacks) {
|
|
8248
|
+
let rest = stacks || [];
|
|
8249
|
+
for (const [type, item] of targets) {
|
|
8250
|
+
const d = distribute(type, item, rest);
|
|
8251
|
+
item.contents = Object.assign(item.contents || {}, d.contents);
|
|
8252
|
+
rest = d.rejected;
|
|
8253
|
+
}
|
|
8254
|
+
result.discarded += rest.length;
|
|
8255
|
+
}
|
|
8256
|
+
const hidden = [];
|
|
8257
|
+
function distRect(c, x, z) {
|
|
8258
|
+
const dx = x - c.item.x;
|
|
8259
|
+
const dz = z - c.item.z;
|
|
8260
|
+
const s = Math.sin(c.item.ry);
|
|
8261
|
+
const co = Math.cos(c.item.ry);
|
|
8262
|
+
const lx = dx * co - dz * s;
|
|
8263
|
+
const lz = dx * s + dz * co;
|
|
8264
|
+
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));
|
|
8265
|
+
}
|
|
8266
|
+
function hideCylinders() {
|
|
8267
|
+
for (const b of hidden) {
|
|
8268
|
+
let target = null;
|
|
8269
|
+
for (const c2 of result.items) {
|
|
8270
|
+
if (c2.type !== "kitchen_cabinet_base" || c2.floor !== b.floor) continue;
|
|
8271
|
+
const dist = distRect(c2, b.item.x, b.item.z);
|
|
8272
|
+
if (!target || dist < target.dist) target = { c: c2, dist };
|
|
8273
|
+
}
|
|
8274
|
+
if (!target) {
|
|
8275
|
+
result.warnings.push(msg("warn.cylinderNoCabinet", { id: b.id }));
|
|
8276
|
+
continue;
|
|
8277
|
+
}
|
|
8278
|
+
const c = target.c;
|
|
8279
|
+
const spec = hh.build(c.type, c.item, HH.createRecorder().api);
|
|
8280
|
+
const sn = Math.sin(c.item.ry);
|
|
8281
|
+
const cs = Math.cos(c.item.ry);
|
|
8282
|
+
let door = null;
|
|
8283
|
+
for (const it of spec.interactions || []) {
|
|
8284
|
+
const pt = it.action && it.action.do === "toggle_part" ? (spec.parts || []).find((q) => q.id === it.action.part) : null;
|
|
8285
|
+
if (!pt || pt.motion.kind !== "hinge") continue;
|
|
8286
|
+
const wx = c.item.x + it.pos[0] * cs + it.pos[2] * sn;
|
|
8287
|
+
const wz = c.item.z - it.pos[0] * sn + it.pos[2] * cs;
|
|
8288
|
+
const dist = Math.hypot(wx - b.item.x, wz - b.item.z);
|
|
8289
|
+
if (!door || dist < door.dist) door = { id: pt.id, dist };
|
|
8290
|
+
}
|
|
8291
|
+
if (!door) {
|
|
8292
|
+
result.warnings.push(msg("warn.cabinetNoDoor", { cabinet: c.id, id: b.id }));
|
|
8293
|
+
continue;
|
|
8294
|
+
}
|
|
8295
|
+
b.item.requires = { object: c.id, part: door.id };
|
|
8296
|
+
}
|
|
8297
|
+
}
|
|
8298
|
+
function initialLanternLight(id, e) {
|
|
8299
|
+
const v = popts.lightsOn;
|
|
8300
|
+
if (typeof v === "function") return !!v(id, e);
|
|
8301
|
+
if (typeof v === "boolean") return v;
|
|
8302
|
+
return !!popts.night && res.state !== "abandoned";
|
|
8303
|
+
}
|
|
8304
|
+
const chimney = res.structureExtras && res.structureExtras.chimney || null;
|
|
8305
|
+
const firstOfType = (type) => (res.items || []).find((m) => typeMap[m.type] && typeMap[m.type].type === type);
|
|
8306
|
+
function chimneyOf(m, role) {
|
|
8307
|
+
if (!chimney) return null;
|
|
8308
|
+
const named = role === "fireplace" ? chimney.fireplace : chimney.stove;
|
|
8309
|
+
if (named != null) return named === m.id ? chimney : null;
|
|
8310
|
+
const first = firstOfType(role === "fireplace" ? "fireplace" : "wood_stove");
|
|
8311
|
+
return chimney.kind === (role === "fireplace" ? "fireplace" : "flue") && first && first.id === m.id ? chimney : null;
|
|
8312
|
+
}
|
|
8313
|
+
const chimneyHeight = (ch) => ch.height != null ? ch.height : ch.top;
|
|
8314
|
+
const campStove = firstOfType("camp_stove");
|
|
8315
|
+
const campCylinder = firstOfType("gas_canister");
|
|
8316
|
+
function planFireplace(m, e, item) {
|
|
8317
|
+
const def = hh.types.find((t) => t.id === "fireplace");
|
|
8318
|
+
const lack = (def.d - m.d) / 2;
|
|
8319
|
+
item.x = r3(item.x + Math.sin(item.ry) * lack);
|
|
8320
|
+
item.z = r3(item.z + Math.cos(item.ry) * lack);
|
|
8321
|
+
const room = (res.rooms || []).find((c) => c.id === m.room && c.floor === m.floor);
|
|
8322
|
+
const f = (res.floors || []).find((x) => x.index === m.floor);
|
|
8323
|
+
item.h = r3(room && room.ceiling || f && f.ceiling || 2.6);
|
|
8324
|
+
const ch = chimneyOf(m, "fireplace");
|
|
8325
|
+
if (ch) {
|
|
8326
|
+
if (ch.material === "stone") item.variant = "stone";
|
|
8327
|
+
const cx = K.x((ch.aabb[0] + ch.aabb[2]) / 2);
|
|
8328
|
+
const cz = K.z((ch.aabb[1] + ch.aabb[3]) / 2);
|
|
8329
|
+
e.connections.chimneyTop = [cx, r3(o.base + chimneyHeight(ch)), cz];
|
|
8330
|
+
}
|
|
8331
|
+
}
|
|
8332
|
+
function planSimple(m, map) {
|
|
8333
|
+
const item = baseItem(m);
|
|
8334
|
+
const dim = map.dim === "none" ? "" : map.dim || "wdh";
|
|
8335
|
+
for (const k of ["w", "d", "h"]) if (dim.indexOf(k) < 0) delete item[k];
|
|
8336
|
+
if (map.dim === "none") delete item.y;
|
|
8337
|
+
if (map.variant) item.variant = map.variant;
|
|
8338
|
+
if (map.type === "tv") item.d = Math.max(item.d || 0, 0.2);
|
|
8339
|
+
const e = entry2(m.id, map.type, item, m.id, m.floor);
|
|
8340
|
+
if (contents[m.id]) store([[map.type, item]], contents[m.id]);
|
|
8341
|
+
if (m.outlet) e.connections.outlet = m.outlet;
|
|
8342
|
+
if (map.type === "shower") e.connections.shower = m.showerHeater || { electric: false };
|
|
8343
|
+
if (map.type === "stove") {
|
|
8344
|
+
result.stoves.push(e.id);
|
|
8345
|
+
e.connections.gas = m.gas || "cylinder";
|
|
8346
|
+
e.connections.cylinder = m.cylinder || null;
|
|
8347
|
+
}
|
|
8348
|
+
if (map.type === "gas_bottle") result.cylinders.push({ id: e.id, stove: m.link || null, place: m.placement || null });
|
|
8349
|
+
if (map.type === "gas_canister") {
|
|
8350
|
+
result.canisters.push(e.id);
|
|
8351
|
+
if (campCylinder && campCylinder.id === m.id && campStove) result.cylinders.push({ id: e.id, stove: campStove.id, place: null });
|
|
8352
|
+
}
|
|
8353
|
+
if (map.type === "wood_stove") {
|
|
8354
|
+
const ch = chimneyOf(m, "stove");
|
|
8355
|
+
if (ch && chimneyHeight(ch)) {
|
|
8356
|
+
const f = (res.floors || []).find((x) => x.index === m.floor);
|
|
8357
|
+
const high = r3(chimneyHeight(ch) - (f ? f.y0 : 0) - (m.y || 0));
|
|
8358
|
+
item.h = high;
|
|
8359
|
+
item.flueHeight = high;
|
|
8360
|
+
}
|
|
8361
|
+
}
|
|
8362
|
+
if (map.type === "fireplace") planFireplace(m, e, item);
|
|
8363
|
+
if (map.type === "lantern_lamp") {
|
|
8364
|
+
e.lit = initialLanternLight(m.id, e);
|
|
8365
|
+
item.on = e.lit;
|
|
8366
|
+
result.lanterns.push(e.id);
|
|
8367
|
+
}
|
|
8368
|
+
if (map.type === "gas_bottle" && m.placement === "under_counter") hidden.push(e);
|
|
8369
|
+
push(e);
|
|
8370
|
+
}
|
|
8371
|
+
function planCompound(m, kind) {
|
|
8372
|
+
const ry = m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0);
|
|
8373
|
+
const cx = K.x(m.x);
|
|
8374
|
+
const cz = K.z(m.z);
|
|
8375
|
+
const part = (id, type, w, d, h, y, lx, lz) => {
|
|
8376
|
+
const [dx, dz] = K.off(ry, lx, lz);
|
|
8377
|
+
const item = baseItem(m);
|
|
8378
|
+
item.x = r3(cx + dx);
|
|
8379
|
+
item.z = r3(cz + dz);
|
|
8380
|
+
item.ry = ry;
|
|
8381
|
+
item.w = r3(w);
|
|
8382
|
+
item.d = r3(d);
|
|
8383
|
+
item.h = r3(h);
|
|
8384
|
+
item.y = y;
|
|
8385
|
+
item.seed = seedOf2(id);
|
|
8386
|
+
return entry2(id, type, item, m.id, m.floor);
|
|
8387
|
+
};
|
|
8388
|
+
const list = [];
|
|
8389
|
+
const overhead = contents[m.id + "#overhead"];
|
|
8390
|
+
if (kind === "rustic_sink") {
|
|
8391
|
+
const dd = Math.max(m.d, 0.56);
|
|
8392
|
+
const basin = part(m.id, "sink_kitchen", m.w, dd, m.h + 0.3, 0, 0, -(dd - m.d) / 2);
|
|
8393
|
+
list.push(basin);
|
|
8394
|
+
const over = overhead || [];
|
|
8395
|
+
if (m.overhead !== false && over.length) {
|
|
8396
|
+
const wall = part(m.id + "#overhead", "kitchen_cabinet_wall", m.w, 0.35, 0.6, 1.55, 0, -(m.d / 2) + 0.175);
|
|
8397
|
+
store([["kitchen_cabinet_wall", wall.item]], over);
|
|
8398
|
+
list.push(wall);
|
|
8399
|
+
}
|
|
8400
|
+
if (contents[m.id]) store([["sink_kitchen", basin.item]], contents[m.id]);
|
|
8401
|
+
if (m.outlet) basin.connections.outlet = m.outlet;
|
|
8402
|
+
} else if (kind === "sink") {
|
|
8403
|
+
const width = m.w;
|
|
8404
|
+
const basinW = width >= 1.5 ? 1 : Math.max(0.6, Math.min(0.8, width - 0.3));
|
|
8405
|
+
const rest = r3(width - basinW);
|
|
8406
|
+
const left = seedOf2(m.id) % 2 === 0;
|
|
8407
|
+
const sink = part(m.id, "sink_kitchen", basinW, m.d, m.h + 0.25, 0, left ? -(width / 2) + basinW / 2 : width / 2 - basinW / 2, 0);
|
|
8408
|
+
list.push(sink);
|
|
8409
|
+
let cabinet = null;
|
|
8410
|
+
if (rest >= 0.35) {
|
|
8411
|
+
cabinet = part(m.id + "#cabinet", "kitchen_cabinet_base", rest, m.d, m.h, 0, left ? width / 2 - rest / 2 : -(width / 2) + rest / 2, 0);
|
|
8412
|
+
list.push(cabinet);
|
|
8413
|
+
}
|
|
8414
|
+
if (contents[m.id]) store(cabinet ? [["kitchen_cabinet_base", cabinet.item], ["sink_kitchen", sink.item]] : [["sink_kitchen", sink.item]], contents[m.id]);
|
|
8415
|
+
if (m.overhead !== false) {
|
|
8416
|
+
const wall = part(m.id + "#overhead", "kitchen_cabinet_wall", width, 0.35, 0.6, 1.55, 0, -(m.d / 2) + 0.175);
|
|
8417
|
+
store([["kitchen_cabinet_wall", wall.item]], overhead || []);
|
|
8418
|
+
list.push(wall);
|
|
8419
|
+
}
|
|
8420
|
+
if (m.outlet) sink.connections.outlet = m.outlet;
|
|
8421
|
+
} else {
|
|
8422
|
+
const basin = part(m.id, "sink_bathroom", m.w, m.d, m.h + 0.2, 0, 0, 0);
|
|
8423
|
+
list.push(basin);
|
|
8424
|
+
if (contents[m.id]) {
|
|
8425
|
+
if (contents[m.id].length) {
|
|
8426
|
+
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);
|
|
8427
|
+
list.push(cabinet);
|
|
8428
|
+
store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]], contents[m.id]);
|
|
8429
|
+
} else {
|
|
8430
|
+
store([["sink_bathroom", basin.item]], []);
|
|
8431
|
+
}
|
|
8432
|
+
}
|
|
8433
|
+
}
|
|
8434
|
+
for (const e of list) push(e);
|
|
8435
|
+
}
|
|
8436
|
+
function circuitOfLight(id) {
|
|
8437
|
+
const direct = circuits.find((c) => (c.lamps || []).indexOf(id) >= 0);
|
|
8438
|
+
if (direct) return direct.id;
|
|
8439
|
+
const sw = (electrical && electrical.switches || []).find((s) => (s.controls || []).indexOf(id) >= 0);
|
|
8440
|
+
const viaSwitch = sw && circuits.find((c) => (c.switches || []).indexOf(sw.id) >= 0);
|
|
8441
|
+
return viaSwitch ? viaSwitch.id : "standalone_circuit";
|
|
8442
|
+
}
|
|
8443
|
+
function planLamp(m, map) {
|
|
8444
|
+
const item = baseItem(m);
|
|
8445
|
+
delete item.palette;
|
|
8446
|
+
const e = entry2(m.id, "lamp", item, m.id, m.floor, { watts: map.watts });
|
|
8447
|
+
e.connections.circuit = circuitOfLight(m.id);
|
|
8448
|
+
e.lit = initialLight(res, popts, m.id, e);
|
|
8449
|
+
push(e);
|
|
8450
|
+
result.lights.push(e.id);
|
|
8451
|
+
}
|
|
8452
|
+
for (const m of res.items || []) {
|
|
8453
|
+
if (!onFloor(m.floor, m.outdoor)) continue;
|
|
8454
|
+
const map = typeMap[m.type];
|
|
8455
|
+
if (!map) {
|
|
8456
|
+
const k = m.category + "/" + m.type;
|
|
8457
|
+
result.unmapped[k] = (result.unmapped[k] || 0) + 1;
|
|
8458
|
+
continue;
|
|
8459
|
+
}
|
|
8460
|
+
result.mapped.push(m.id);
|
|
8461
|
+
if (map.type === "lamp") planLamp(m, map);
|
|
8462
|
+
else if (map.compound) planCompound(m, map.compound);
|
|
8463
|
+
else planSimple(m, map);
|
|
8464
|
+
}
|
|
8465
|
+
result.chairs = [];
|
|
8466
|
+
if (opts.chairs !== false && popts.chairs !== false) {
|
|
8467
|
+
const blocked = blockedOf(res, { originX: o.ox, originZ: o.oz, inw: o.inw });
|
|
8468
|
+
const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && q.aabb;
|
|
8469
|
+
const placed = [];
|
|
8470
|
+
const free = (m, cu, cv, half) => {
|
|
8471
|
+
const a = [cu - half + 0.03, cv - half + 0.03, cu + half - 0.03, cv + half - 0.03];
|
|
8472
|
+
for (const [dx, dz] of [[-1, -1], [1, -1], [-1, 1], [1, 1], [0, 0]]) if (blocked(K.x(cu + dx * half * 0.9), K.z(cv + dz * half * 0.9), m.floor)) return false;
|
|
8473
|
+
for (const q of res.items || []) {
|
|
8474
|
+
if (q === m || !floorKind(q) || q.floor !== m.floor && !(q.outdoor && m.outdoor)) continue;
|
|
8475
|
+
if (a[0] < q.aabb[2] && a[2] > q.aabb[0] && a[1] < q.aabb[3] && a[3] > q.aabb[1]) return false;
|
|
8476
|
+
}
|
|
8477
|
+
for (const c of placed) if (a[0] < c[2] && a[2] > c[0] && a[1] < c[3] && a[3] > c[1] && c[4] === m.floor) return false;
|
|
8478
|
+
placed.push([a[0], a[1], a[2], a[3], m.floor]);
|
|
8479
|
+
return true;
|
|
8480
|
+
};
|
|
8481
|
+
for (const m of res.items || []) {
|
|
8482
|
+
const mode = chairTables[m.type];
|
|
8483
|
+
if (!mode || !onFloor(m.floor, m.outdoor) || m.frontU == null) continue;
|
|
8484
|
+
const f = [m.frontU, m.frontV];
|
|
8485
|
+
const pp = [-m.frontV, m.frontU];
|
|
8486
|
+
const seats = [];
|
|
8487
|
+
if (mode === "dining") {
|
|
8488
|
+
const n = Math.max(1, Math.min(3, Math.floor((m.w - 0.1) / 0.55)));
|
|
8489
|
+
for (const side of [1, -1]) {
|
|
8490
|
+
for (let i = 0; i < n; i++) seats.push([(i - (n - 1) / 2) * (m.w / n), side * (m.d / 2 + 0.17), [-side * f[0], -side * f[1]]]);
|
|
8491
|
+
}
|
|
8492
|
+
if (m.w >= 1.6) for (const side of [1, -1]) seats.push([side * (m.w / 2 + 0.17), 0, [-side * pp[0], -side * pp[1]]]);
|
|
8493
|
+
} else {
|
|
8494
|
+
seats.push([0, m.d / 2 + 0.2, [-f[0], -f[1]]]);
|
|
8495
|
+
}
|
|
8496
|
+
seats.forEach((lg, i) => {
|
|
8497
|
+
const cu = r3(m.x + pp[0] * lg[0] + f[0] * lg[1]);
|
|
8498
|
+
const cv = r3(m.z + pp[1] * lg[0] + f[1] * lg[1]);
|
|
8499
|
+
const half = mode === "dining" ? chairSide / 2 : 0.3;
|
|
8500
|
+
if (!free(m, cu, cv, half)) return;
|
|
8501
|
+
const id = m.id + "#chair" + (i + 1);
|
|
8502
|
+
const item = { x: K.x(cu), z: K.z(cv), ry: K.ry(lg[2][0], lg[2][1]), seed: seedOf2(id), palette };
|
|
8503
|
+
if (mode !== "dining") {
|
|
8504
|
+
item.w = 0.6;
|
|
8505
|
+
item.d = 0.6;
|
|
8506
|
+
item.h = 0.95;
|
|
8507
|
+
}
|
|
8508
|
+
const e = push(entry2(id, mode === "dining" ? "dining_chair" : "armchair", item, m.id, m.floor));
|
|
8509
|
+
result.chairs.push(e.id);
|
|
8510
|
+
});
|
|
8511
|
+
}
|
|
8512
|
+
}
|
|
8513
|
+
function conduit(id, pts, floor) {
|
|
8514
|
+
const x0 = K.x(pts[0][0]);
|
|
8515
|
+
const z0 = K.z(pts[0][1]);
|
|
8516
|
+
const item = {
|
|
8517
|
+
x: x0,
|
|
8518
|
+
z: z0,
|
|
8519
|
+
ry: 0,
|
|
8520
|
+
seed: seedOf2(id),
|
|
8521
|
+
// the points of the plan already have the absolute y of the world: the object stays on the base ground and not on the floor of the storey
|
|
8522
|
+
points: pts.map((p) => [r3(K.x(p[0]) - x0), p[2], r3(K.z(p[1]) - z0)])
|
|
8523
|
+
};
|
|
8524
|
+
const e = entry2(id, "conduit_run", item, id, floor);
|
|
8525
|
+
e.floorY = o.base;
|
|
8526
|
+
push(e);
|
|
8527
|
+
result.conduits.push(e.id);
|
|
8528
|
+
}
|
|
8529
|
+
if (electrical) {
|
|
8530
|
+
for (const l of electrical.outdoorLamps || []) {
|
|
8531
|
+
if (!onFloor(-1, true)) continue;
|
|
8532
|
+
const e = entry2(l.id, "lamp", { x: K.x(l.u), z: K.z(l.v), ry: 0, y: l.y, seed: seedOf2(l.id) }, l.id, -1, { watts: 15 });
|
|
8533
|
+
e.connections.circuit = circuitOfLight(l.id);
|
|
8534
|
+
e.lit = initialLight(res, popts, l.id, e);
|
|
8535
|
+
push(e);
|
|
8536
|
+
result.lights.push(e.id);
|
|
8537
|
+
}
|
|
8538
|
+
for (const t of electrical.outlets || []) {
|
|
8539
|
+
if (!onFloor(t.floor, false)) continue;
|
|
8540
|
+
const c = circuits.find((x) => (x.outlets || []).indexOf(t.id) >= 0);
|
|
8541
|
+
const item = { x: K.x(t.u), z: K.z(t.v), ry: K.ry(t.frontU, t.frontV), y: t.y, seed: seedOf2(t.id) };
|
|
8542
|
+
if (c) item.circuit = c.id;
|
|
8543
|
+
const e = entry2(t.id, "wall_socket", item, t.id, t.floor);
|
|
8544
|
+
e.connections.circuit = c ? c.id : null;
|
|
8545
|
+
push(e);
|
|
8546
|
+
result.outlets.push(e.id);
|
|
8547
|
+
}
|
|
8548
|
+
const lights = new Set(result.lights);
|
|
8549
|
+
for (const s of electrical.switches || []) {
|
|
8550
|
+
if (!onFloor(s.floor, false)) continue;
|
|
8551
|
+
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) };
|
|
8552
|
+
item.controls = (s.controls || []).map((id) => id + ":lamp");
|
|
8553
|
+
const e = entry2(s.id, "wall_switch", item, s.id, s.floor);
|
|
8554
|
+
e.connections.controls = (s.controls || []).slice();
|
|
8555
|
+
e.lit = e.connections.controls.some((id) => (result.items.find((x) => x.id === id) || {}).lit === true);
|
|
8556
|
+
if (floorSel == null) {
|
|
8557
|
+
for (const id of s.controls || []) if (!lights.has(id)) result.warnings.push(msg("warn.switchUnknownLamp", { id: s.id, lamp: id }));
|
|
8558
|
+
}
|
|
8559
|
+
push(e);
|
|
8560
|
+
result.switches.push(e.id);
|
|
8561
|
+
}
|
|
8562
|
+
const ee = electrical.serviceEntrance;
|
|
8563
|
+
if (ee && ee.pole && onFloor(-1, true)) {
|
|
8564
|
+
const drop = ee.drop || [];
|
|
8565
|
+
const end = drop.length ? drop[drop.length - 1] : [ee.pole.u, ee.pole.v, 2.6];
|
|
8566
|
+
const px = K.x(ee.pole.u);
|
|
8567
|
+
const pz = K.z(ee.pole.v);
|
|
8568
|
+
const item = {
|
|
8569
|
+
x: px,
|
|
8570
|
+
z: pz,
|
|
8571
|
+
ry: 0,
|
|
8572
|
+
h: ee.pole.h,
|
|
8573
|
+
seed: seedOf2("service_entrance"),
|
|
8574
|
+
// point where the drop reaches the house, in local coordinates of the pole (absolute y)
|
|
8575
|
+
house: [r3(K.x(end[0]) - px), end[2], r3(K.z(end[1]) - pz)]
|
|
8576
|
+
};
|
|
8577
|
+
if (ee.tap || electrical.mode === "tap") item.variant = "gato";
|
|
8578
|
+
const e = entry2("service_entrance", "service_entrance", item, "service_entrance", -1);
|
|
8579
|
+
push(e);
|
|
8580
|
+
result.serviceEntrance = e.id;
|
|
8581
|
+
if (ee.descent && ee.descent.length > 1) conduit("conduit_descent", ee.descent, -1);
|
|
8582
|
+
}
|
|
8583
|
+
const q = electrical.panel;
|
|
8584
|
+
if (q && onFloor(q.floor, false)) {
|
|
8585
|
+
const hdq = 0.06;
|
|
8586
|
+
const ryq = K.ry(q.frontU, q.frontV);
|
|
8587
|
+
const item = {
|
|
8588
|
+
x: r3(K.x(q.u) + Math.sin(ryq) * hdq),
|
|
8589
|
+
z: r3(K.z(q.v) + Math.cos(ryq) * hdq),
|
|
8590
|
+
ry: ryq,
|
|
8591
|
+
y: q.y,
|
|
8592
|
+
seed: seedOf2("panel"),
|
|
8593
|
+
circuits: circuits.map((c) => ({ id: c.id, label: c.room }))
|
|
8594
|
+
};
|
|
8595
|
+
if (!item.circuits.length) delete item.circuits;
|
|
8596
|
+
const e = entry2("panel", "electrical_panel", item, "panel", q.floor);
|
|
8597
|
+
push(e);
|
|
8598
|
+
result.panel = e.id;
|
|
8599
|
+
}
|
|
8600
|
+
const med = ee && ee.meter;
|
|
8601
|
+
if (med && onFloor(-1, true)) {
|
|
8602
|
+
const hdm = 0.08;
|
|
8603
|
+
const item = { x: K.x(med.u), z: r3(K.z(med.v) - o.inw * hdm), ry: K.ry(0, -1), y: med.y, seed: seedOf2("meter") };
|
|
8604
|
+
const e = entry2("meter", "power_meter", item, "meter", -1);
|
|
8605
|
+
push(e);
|
|
8606
|
+
result.meter = e.id;
|
|
8607
|
+
}
|
|
8608
|
+
for (const ed of electrical.conduits || []) {
|
|
8609
|
+
if (!ed.exposed || !ed.points || ed.points.length < 2) continue;
|
|
8610
|
+
const circ = circuits.find((c) => c.id === ed.circuit);
|
|
8611
|
+
const floor = circ ? circ.floor : 0;
|
|
8612
|
+
if (!onFloor(floor, false)) continue;
|
|
8613
|
+
conduit(ed.id, ed.points, floor);
|
|
8614
|
+
}
|
|
8615
|
+
}
|
|
8616
|
+
const piped = result.items.filter((e) => e.type === "stove" && e.connections.gas === "piped");
|
|
8617
|
+
if (piped.length) {
|
|
8618
|
+
const med = utilities.gas && utilities.gas.meter;
|
|
8619
|
+
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 };
|
|
8620
|
+
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);
|
|
8621
|
+
e.floorY = o.base;
|
|
8622
|
+
push(e);
|
|
8623
|
+
for (const f of piped) f.connections.fuel = "piped_gas:gas";
|
|
8624
|
+
}
|
|
8625
|
+
for (const b of result.cylinders) {
|
|
8626
|
+
const stove = result.items.find((e) => e.id === b.stove);
|
|
8627
|
+
if (stove) stove.connections.fuel = b.id + ":gas";
|
|
8628
|
+
}
|
|
8629
|
+
const plumbing = utilities.plumbing;
|
|
8630
|
+
if (plumbing) {
|
|
8631
|
+
const isCabinet = (t) => t === "kitchen_cabinet_base" || t === "kitchen_cabinet_wall" || t === "bathroom_cabinet";
|
|
8632
|
+
for (const p of plumbing.points || []) {
|
|
8633
|
+
const target = (byOrigin.get(p.item) || []).filter((e) => !isCabinet(e.type))[0];
|
|
8634
|
+
if (!target) {
|
|
8635
|
+
if (floorSel == null) result.warnings.push(msg("warn.pointNoObject", { id: p.id, kind: p.kind, item: p.item }));
|
|
8636
|
+
continue;
|
|
8637
|
+
}
|
|
8638
|
+
target.point = p.id;
|
|
8639
|
+
target.connections.flowLpm = p.flowLpm;
|
|
8640
|
+
for (const f of fixturesOfPoint[p.kind] || []) {
|
|
8641
|
+
result.fixtures.push({ object: target.id, fixture: f, global: target.id + ":" + f, point: p.id, pointKind: p.kind });
|
|
8642
|
+
result.points[target.id + ":" + f] = p.id;
|
|
8643
|
+
}
|
|
8644
|
+
}
|
|
8645
|
+
}
|
|
8646
|
+
hideCylinders();
|
|
8647
|
+
return result;
|
|
8648
|
+
}
|
|
8649
|
+
function ownSpec(entry2) {
|
|
8650
|
+
if (entry2.type === "lamp") {
|
|
8651
|
+
const dev = { id: "lamp", kind: "lamp", watts: entry2.watts || 15, on: !!entry2.lit };
|
|
8652
|
+
if (entry2.connections.circuit) dev.circuit = entry2.connections.circuit;
|
|
8653
|
+
return { type: "lamp", devices: [dev] };
|
|
8654
|
+
}
|
|
8655
|
+
if (entry2.type === "gas_piped") return { type: "gas_piped", fuels: [{ id: "gas", kind: "gas", capacity: 1e3, level: 1e3 }] };
|
|
8656
|
+
throw new Error(msg("error.unknownOwnType", { type: entry2.type }));
|
|
8657
|
+
}
|
|
8658
|
+
function connect(entry2, spec) {
|
|
8659
|
+
const L = entry2.connections || {};
|
|
8660
|
+
if (entry2.type === "wall_switch") {
|
|
8661
|
+
for (const p of spec.parts || []) if (p.id === "rocker") p.t0 = entry2.lit ? 1 : 0;
|
|
8662
|
+
}
|
|
8663
|
+
if (entry2.type !== "shower") {
|
|
8664
|
+
for (const dv of spec.devices || []) if (L.outlet && dv.socket === "auto") dv.socket = L.outlet + ":socket";
|
|
8665
|
+
} else {
|
|
8666
|
+
const sh = L.shower || {};
|
|
8667
|
+
const heater = (spec.devices || []).find((d) => d.id === "heater");
|
|
8668
|
+
if (heater && sh.electric === false) {
|
|
8669
|
+
spec.devices = spec.devices.filter((d) => d !== heater);
|
|
8670
|
+
for (const f of spec.fixtures || []) if (f.heater === "heater") delete f.heater;
|
|
8671
|
+
} else if (heater) {
|
|
8672
|
+
if (sh.powerW) heater.watts = sh.powerW;
|
|
8673
|
+
if (L.outletCircuit) heater.circuit = L.outletCircuit;
|
|
8674
|
+
}
|
|
8675
|
+
}
|
|
8676
|
+
if ((entry2.type === "stove" || entry2.type === "camp_stove") && L.fuel) {
|
|
8677
|
+
for (const b of spec.burners || []) if (b.fuel === "auto") b.fuel = L.fuel;
|
|
8678
|
+
}
|
|
8679
|
+
if (entry2.type === "fireplace" && L.chimneyTop) {
|
|
8680
|
+
const it = entry2.item;
|
|
8681
|
+
const dx = L.chimneyTop[0] - it.x;
|
|
8682
|
+
const dz = L.chimneyTop[2] - it.z;
|
|
8683
|
+
const lx = Math.cos(it.ry) * dx - Math.sin(it.ry) * dz;
|
|
8684
|
+
const lz = Math.sin(it.ry) * dx + Math.cos(it.ry) * dz;
|
|
8685
|
+
for (const em of spec.emitters || []) if (em.kind === "smoke") em.pos = [r3(lx), r3(L.chimneyTop[1] - entry2.floorY + 0.02), r3(lz)];
|
|
8686
|
+
}
|
|
8687
|
+
if (entry2.type === "washing_machine" && entry2.point) {
|
|
8688
|
+
spec.fixtures = spec.fixtures || [];
|
|
8689
|
+
const inlet = spec.fixtures.find((f) => f.id === "inlet");
|
|
8690
|
+
if (inlet) {
|
|
8691
|
+
if (L.flowLpm) inlet.flow = L.flowLpm;
|
|
8692
|
+
inlet.tank = "auto";
|
|
8693
|
+
} else {
|
|
8694
|
+
spec.fixtures.push({ id: "inlet", kind: "hose", outlet: [0, 0.3, -(entry2.item.d || 0.6) / 2], flow: L.flowLpm || 8, tank: "auto" });
|
|
8695
|
+
}
|
|
8696
|
+
}
|
|
8697
|
+
return spec;
|
|
8698
|
+
}
|
|
8699
|
+
function createWorld(res, copts = {}) {
|
|
8700
|
+
copts = copts || {};
|
|
8701
|
+
const info = { points: /* @__PURE__ */ new Map(), water: copts.water || null, lightsOn: copts.lightsOn };
|
|
8702
|
+
const electrical = res.utilities && res.utilities.electrical;
|
|
8703
|
+
const world = GI.createWorld({
|
|
8704
|
+
locale,
|
|
8705
|
+
strings: hh.strings,
|
|
8706
|
+
items: hh.items,
|
|
8707
|
+
loot: hh.loot,
|
|
8708
|
+
seed: copts.seed != null ? copts.seed : res.seed,
|
|
8709
|
+
// no grid: the cabin and the off-grid campsite have no service entrance, sockets or electric lamps (lanterns do not need a grid)
|
|
8710
|
+
grid: copts.grid != null ? !!copts.grid : !!electrical && electrical.mode !== "offgrid",
|
|
8711
|
+
onEvent: copts.onEvent,
|
|
8712
|
+
canInteract: copts.canInteract,
|
|
8713
|
+
waterSupply: {
|
|
8714
|
+
draw(fixtureId, l) {
|
|
8715
|
+
if (!info.water) return l;
|
|
8716
|
+
const point = info.points.get(fixtureId);
|
|
8717
|
+
return point == null ? l : info.water.consume(point, l);
|
|
8718
|
+
}
|
|
8719
|
+
}
|
|
8720
|
+
});
|
|
8721
|
+
worlds.set(world, info);
|
|
8722
|
+
return world;
|
|
8723
|
+
}
|
|
8724
|
+
function pointOf(world, fixtureId) {
|
|
8725
|
+
const info = worlds.get(world);
|
|
8726
|
+
return info ? info.points.get(fixtureId) : void 0;
|
|
8727
|
+
}
|
|
8728
|
+
function blockedOf(res, bopts = {}) {
|
|
8729
|
+
bopts = bopts || {};
|
|
8730
|
+
const ox = bopts.originX || 0;
|
|
8731
|
+
const oz = bopts.originZ || 0;
|
|
8732
|
+
const inw = bopts.inw || 1;
|
|
8733
|
+
const margin = bopts.margin != null ? bopts.margin : 0.02;
|
|
8734
|
+
const segs = (res.walls || []).map((p) => {
|
|
8735
|
+
const e = Math.max(0, p.thickness / 2 - margin);
|
|
8736
|
+
const u0 = Math.min(p.u0, p.u1) - (p.axis === "u" ? 0 : e);
|
|
8737
|
+
const u1 = Math.max(p.u0, p.u1) + (p.axis === "u" ? 0 : e);
|
|
8738
|
+
const v0 = Math.min(p.v0, p.v1) - (p.axis === "v" ? 0 : e);
|
|
8739
|
+
const v1 = Math.max(p.v0, p.v1) + (p.axis === "v" ? 0 : e);
|
|
8740
|
+
const za = oz + inw * v0;
|
|
8741
|
+
const zb = oz + inw * v1;
|
|
8742
|
+
return { floor: p.floor, x0: ox + u0, x1: ox + u1, z0: Math.min(za, zb), z1: Math.max(za, zb) };
|
|
8743
|
+
});
|
|
8744
|
+
const CELL2 = 0.5;
|
|
8745
|
+
const grid = /* @__PURE__ */ new Map();
|
|
8746
|
+
const key = (a, i, j) => (a * 4096 + (i + 2048)) * 4096 + (j + 2048);
|
|
8747
|
+
for (const s of segs) {
|
|
8748
|
+
for (let i = Math.floor(s.x0 / CELL2); i <= Math.floor(s.x1 / CELL2); i++) {
|
|
8749
|
+
for (let j = Math.floor(s.z0 / CELL2); j <= Math.floor(s.z1 / CELL2); j++) {
|
|
8750
|
+
const k = key(s.floor, i, j);
|
|
8751
|
+
if (!grid.has(k)) grid.set(k, []);
|
|
8752
|
+
grid.get(k).push(s);
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
}
|
|
8756
|
+
return function blocked(x, z, floor) {
|
|
8757
|
+
const a = floor == null || floor < 0 ? 0 : floor;
|
|
8758
|
+
const list = grid.get(key(a, Math.floor(x / CELL2), Math.floor(z / CELL2)));
|
|
8759
|
+
if (!list) return false;
|
|
8760
|
+
for (const s of list) if (x > s.x0 && x < s.x1 && z > s.z0 && z < s.z1) return true;
|
|
8761
|
+
return false;
|
|
8762
|
+
};
|
|
8763
|
+
}
|
|
8764
|
+
function add(world, planned, aopts = {}) {
|
|
8765
|
+
aopts = aopts || {};
|
|
8766
|
+
const info = worlds.get(world);
|
|
8767
|
+
const build = aopts.build || ((type, item) => hh.build(type, item, HH.createRecorder().api));
|
|
8768
|
+
const isBlocked = aopts.isBlocked || null;
|
|
8769
|
+
const out = { added: 0, parts: [], hinges: {}, moved: {}, warnings: [] };
|
|
8770
|
+
const override = aopts.lightsOn !== void 0 ? aopts.lightsOn : info && info.lightsOn;
|
|
8771
|
+
if (override !== void 0) {
|
|
8772
|
+
for (const e of planned.items) if (e.type === "lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
8773
|
+
for (const e of planned.items) if (e.type === "lantern_lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
8774
|
+
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);
|
|
8775
|
+
}
|
|
8776
|
+
for (const e of planned.items) if (e.type === "lantern_lamp") e.item.on = !!e.lit;
|
|
8777
|
+
let scratch = null;
|
|
8778
|
+
function probe(e, hinge, setback) {
|
|
8779
|
+
if (!scratch) scratch = GI.createWorld({ locale, strings: hh.strings, items: hh.items, loot: hh.loot, grid: false });
|
|
8780
|
+
const it = e.item;
|
|
8781
|
+
const x = it.x + Math.sin(it.ry) * setback;
|
|
8782
|
+
const z = it.z + Math.cos(it.ry) * setback;
|
|
8783
|
+
const spec = hh.build(e.type, Object.assign({}, it, { hinge }), HH.createRecorder().api);
|
|
8784
|
+
scratch.add("__probe", spec, { x, y: e.floorY, z, ry: it.ry });
|
|
8785
|
+
const blocks = (px, pz) => isBlocked(px, pz, e.floor);
|
|
8786
|
+
let sum = 0;
|
|
8787
|
+
let min = 1;
|
|
8788
|
+
let n = 0;
|
|
8789
|
+
for (const p of spec.parts || []) {
|
|
8790
|
+
if (p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
8791
|
+
const t = scratch.fitSweep("__probe", p.id, blocks);
|
|
8792
|
+
sum += t;
|
|
8793
|
+
min = Math.min(min, t);
|
|
8794
|
+
n++;
|
|
8795
|
+
}
|
|
8796
|
+
scratch.remove("__probe");
|
|
8797
|
+
return { sum, min, n };
|
|
8798
|
+
}
|
|
8799
|
+
const better = (a, b) => a.sum > b.sum + 1e-9 || Math.abs(a.sum - b.sum) <= 1e-9 && a.min > b.min + 1e-9;
|
|
8800
|
+
function fitDoors(e) {
|
|
8801
|
+
if (!isBlocked || !householdTypes.has(e.type)) return;
|
|
8802
|
+
const standard = probe(e, void 0, 0);
|
|
8803
|
+
if (!standard.n || standard.min >= 1) return;
|
|
8804
|
+
let bestSide;
|
|
8805
|
+
let m = standard;
|
|
8806
|
+
for (const side of ["left", "right"]) {
|
|
8807
|
+
const r = probe(e, side, 0);
|
|
8808
|
+
if (better(r, m)) {
|
|
8809
|
+
m = r;
|
|
8810
|
+
bestSide = side;
|
|
8811
|
+
}
|
|
8812
|
+
}
|
|
8813
|
+
if (bestSide) {
|
|
8814
|
+
e.item.hinge = bestSide;
|
|
8815
|
+
out.hinges[e.id] = bestSide;
|
|
8816
|
+
}
|
|
8817
|
+
if (m.min >= 1) return;
|
|
8818
|
+
let target = { setback: 0, r: m };
|
|
8819
|
+
for (const setback of [0.01, 0.02, 0.03, 0.04]) {
|
|
8820
|
+
const r = probe(e, bestSide, setback);
|
|
8821
|
+
if (better(r, target.r)) target = { setback, r };
|
|
8822
|
+
if (r.min >= 1) break;
|
|
8823
|
+
}
|
|
8824
|
+
if (target.setback > 0 && target.r.sum > m.sum + 0.2) {
|
|
8825
|
+
e.item.x = r3(e.item.x + Math.sin(e.item.ry) * target.setback);
|
|
8826
|
+
e.item.z = r3(e.item.z + Math.cos(e.item.ry) * target.setback);
|
|
8827
|
+
e.moved = target.setback;
|
|
8828
|
+
out.moved[e.id] = target.setback;
|
|
8829
|
+
}
|
|
8830
|
+
}
|
|
8831
|
+
for (const e of planned.items) {
|
|
8832
|
+
if (e.type !== "shower" || !e.connections.outlet) continue;
|
|
8833
|
+
const t = planned.items.find((x) => x.id === e.connections.outlet);
|
|
8834
|
+
if (t && t.connections.circuit) e.connections.outletCircuit = t.connections.circuit;
|
|
8835
|
+
}
|
|
8836
|
+
for (const e of planned.items) {
|
|
8837
|
+
let spec;
|
|
8838
|
+
if (ownTypes[e.type]) {
|
|
8839
|
+
spec = ownSpec(e);
|
|
8840
|
+
} else {
|
|
8841
|
+
fitDoors(e);
|
|
8842
|
+
spec = build(e.type, e.item);
|
|
8843
|
+
if (!spec) {
|
|
8844
|
+
out.warnings.push(msg("warn.buildEmpty", { id: e.id }));
|
|
8845
|
+
continue;
|
|
8846
|
+
}
|
|
8847
|
+
}
|
|
8848
|
+
connect(e, spec);
|
|
8849
|
+
world.add(e.id, spec, { x: e.item.x, y: e.floorY, z: e.item.z, ry: e.item.ry });
|
|
8850
|
+
out.added++;
|
|
8851
|
+
if (!isBlocked) continue;
|
|
8852
|
+
for (const p of spec.parts || []) {
|
|
8853
|
+
if (!(p.bounds || p.sweep)) continue;
|
|
8854
|
+
const t = world.fitSweep(e.id, p.id, (x, z) => isBlocked(x, z, e.floor));
|
|
8855
|
+
if (t < 1) out.parts.push({ object: e.id, part: p.id, t });
|
|
8856
|
+
}
|
|
8857
|
+
}
|
|
8858
|
+
if (info) for (const f of planned.fixtures) info.points.set(f.global, f.point);
|
|
8859
|
+
return out;
|
|
8860
|
+
}
|
|
8861
|
+
return { version: ADAPTER_VERSION, household: hh, plan, createWorld, add, blockedOf, pointOf, ownSpec, registries: { typeMap, contentMap, contentByGroup, chairTables, fixturesOfPoint, substitutes, preference, ownTypes } };
|
|
8862
|
+
}
|
|
8863
|
+
var FloorplanInteractables = { version: ADAPTER_VERSION, create: create2, TYPE_MAP, CONTENT_MAP, CONTENT_BY_GROUP, CHAIR_TABLES, PREFERENCE, mergeRegistry };
|
|
8864
|
+
|
|
7526
8865
|
// src/interactables/kit.ts
|
|
7527
8866
|
function installInteractablesKit(K, shared) {
|
|
7528
8867
|
const { t, THREE, DOC, cfg, Reflector } = K;
|
|
@@ -7530,12 +8869,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
7530
8869
|
const IVK = (() => {
|
|
7531
8870
|
const o = cfg.interactives;
|
|
7532
8871
|
if (!o) return null;
|
|
7533
|
-
const GI = o.GameInteractables || null, HH = o.GameInteractablesHousehold || null, GT = o.GameInteractablesThree || null, AD = o.adapter ||
|
|
7534
|
-
if (!GI || !HH || !GT
|
|
8872
|
+
const GI = o.GameInteractables || null, HH = o.GameInteractablesHousehold || null, GT = o.GameInteractablesThree || null, AD = o.adapter || FloorplanInteractables;
|
|
8873
|
+
if (!GI || !HH || !GT) {
|
|
7535
8874
|
console.warn(t("warn.interactablesIncomplete"));
|
|
7536
8875
|
return null;
|
|
7537
8876
|
}
|
|
7538
|
-
const A = AD.plan ? AD : AD.create({ GameInteractables: GI, GameInteractablesHousehold: HH, locale: o.locale, region: o.region });
|
|
8877
|
+
const A = AD.plan ? AD : AD.create({ ...o.adapterOptions || {}, GameInteractables: GI, GameInteractablesHousehold: HH, locale: o.locale || cfg.locale, region: o.region, ...cfg.seedKey ? { seedKey: cfg.seedKey } : {} });
|
|
7539
8878
|
return { GI, HH, GT, A, gfx: GT.createThreeAdapter(THREE, { document: DOC, Reflector }), items: o.items !== false, effects: o.effects !== false, camera: o.camera || null, onEvent: o.onEvent || null, onSeat: o.onSeat || null };
|
|
7540
8879
|
})();
|
|
7541
8880
|
const VEG = (() => {
|
|
@@ -10413,7 +11752,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10413
11752
|
|
|
10414
11753
|
// src/create.ts
|
|
10415
11754
|
var VERSION = "1.0.0";
|
|
10416
|
-
function
|
|
11755
|
+
function create3(THREE, options = {}) {
|
|
10417
11756
|
const cfg = Object.assign({}, options || {});
|
|
10418
11757
|
const DOC = cfg.document || (typeof document !== "undefined" ? document : null);
|
|
10419
11758
|
const PROPS = cfg.props || dist_exports;
|
|
@@ -11162,7 +12501,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11162
12501
|
let made = byId.get(key);
|
|
11163
12502
|
if (!made) {
|
|
11164
12503
|
const plan = engine.generate(def.template, { seed: def.seed ?? 1, ...def.state ? { state: def.state } : {} });
|
|
11165
|
-
const house =
|
|
12504
|
+
const house = create3(THREE, { ...houseOptions, destruction: void 0, destructionRenderer: void 0, interactives: void 0, vegetation: void 0, fleet: null }).build(plan, { quality: "game", terrain: false, noPerimeter: true });
|
|
11166
12505
|
const spec = house.structure.spec({ wallDetail: "coarse", ...def.portico ? { portico: true } : {} });
|
|
11167
12506
|
house.dispose();
|
|
11168
12507
|
made = { spec, plan };
|
|
@@ -11258,7 +12597,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11258
12597
|
const key = `${settings.quality}|${locale}`;
|
|
11259
12598
|
if (!houseRenderer || houseRendererKey !== key) {
|
|
11260
12599
|
houseRenderer?.dispose?.();
|
|
11261
|
-
houseRenderer =
|
|
12600
|
+
houseRenderer = create3(THREE, {
|
|
11262
12601
|
locale,
|
|
11263
12602
|
lod: { interior: 10, hide: 40 },
|
|
11264
12603
|
...options.house,
|
|
@@ -11588,7 +12927,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11588
12927
|
for (const group of groups) {
|
|
11589
12928
|
for (const id of group.templates) {
|
|
11590
12929
|
const plan = engine.generate(id, { seed: 1 });
|
|
11591
|
-
const house =
|
|
12930
|
+
const house = create3(THREE ?? host?.THREE, { locale, ...options.house, destruction: void 0, destructionRenderer: void 0, interactives: void 0, vegetation: void 0, fleet: null }).build(plan, { quality: "game", terrain: false, noPerimeter: true });
|
|
11592
12931
|
const ok = house.structure.parts.length > 0 && house.floors.length >= 1 && house.colliders.length > 0;
|
|
11593
12932
|
expect(ok, `${groupName(group)}: ${templateName(id)} (${house.structure.parts.length})`);
|
|
11594
12933
|
house.dispose();
|