@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.
@@ -27,10 +27,10 @@ var GameFloorplanThree = (() => {
27
27
  VERSION: () => VERSION,
28
28
  bindNavigator: () => bindNavigator,
29
29
  buildSpecimenMeshes: () => buildSpecimenMeshes,
30
- create: () => create2,
30
+ create: () => create3,
31
31
  createFloorNavigator: () => createFloorNavigator,
32
32
  createFloorplanTestModule: () => createFloorplanTestModule,
33
- createHouseRenderer: () => create2,
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, adapter)",
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, adapter)",
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 en2 = E.serviceEntrance, KV = shared.ctx.iv ? shared.ctx.iv.plane : null;
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 (en2 && en2.pole) {
4535
- const P = en2.pole;
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 (en2.drop && en2.drop.length > 1 && !(KV && KV.serviceEntrance)) {
4542
- const r0 = en2.drop[0], r1 = en2.drop[en2.drop.length - 1];
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 (en2.descent && en2.descent.length > 1 && !(KV && KV.serviceEntrance)) {
4548
- const d0 = en2.descent[0], d1 = en2.descent[en2.descent.length - 1];
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 = en2.meter;
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.floorKind };
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 exitPoint = A.add(world, plane, { isBlocked: A.blockedOf(r), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
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 = exitPoint.warnings;
7003
- IV.exitPoint = exitPoint;
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.floorKind, item.z);
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.floorKind, item.z, item.ry, null);
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.floorKind, item.z], ry: item.ry, origin: ent.origin };
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.picture && IV.entries.get(IV.plane.picture);
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 || null;
7534
- if (!GI || !HH || !GT || !AD) {
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 create2(THREE, options = {}) {
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 = create2(THREE, { ...houseOptions, destruction: void 0, destructionRenderer: void 0, interactives: void 0, vegetation: void 0, fleet: null }).build(plan, { quality: "game", terrain: false, noPerimeter: true });
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 = create2(THREE, {
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 = create2(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 });
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();