@adatechnology/game-floorplan-interactables 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/MIGRATION.md +307 -0
- package/README.md +44 -2
- package/dist/index.d.ts +167 -0
- package/dist/index.global.js +1392 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1367 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -3
|
@@ -0,0 +1,1392 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var GameFloorplanInteractables = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
ADAPTER_VERSION: () => ADAPTER_VERSION,
|
|
25
|
+
CHAIR_TABLES: () => CHAIR_TABLES,
|
|
26
|
+
CONTENT_BY_GROUP: () => CONTENT_BY_GROUP,
|
|
27
|
+
CONTENT_FALLBACK: () => CONTENT_FALLBACK,
|
|
28
|
+
CONTENT_MAP: () => CONTENT_MAP,
|
|
29
|
+
DINING_CHAIR_SIDE: () => DINING_CHAIR_SIDE,
|
|
30
|
+
DRAWER_GROUPS: () => DRAWER_GROUPS,
|
|
31
|
+
DRAWER_ITEMS: () => DRAWER_ITEMS,
|
|
32
|
+
FIXTURES_OF_POINT: () => FIXTURES_OF_POINT,
|
|
33
|
+
FROZEN_ITEMS: () => FROZEN_ITEMS,
|
|
34
|
+
FloorplanInteractables: () => FloorplanInteractables,
|
|
35
|
+
OBJECT_SUBSTITUTES: () => OBJECT_SUBSTITUTES,
|
|
36
|
+
OWN_TYPES: () => OWN_TYPES,
|
|
37
|
+
PREFERENCE: () => PREFERENCE,
|
|
38
|
+
TYPE_MAP: () => TYPE_MAP,
|
|
39
|
+
create: () => create,
|
|
40
|
+
createTranslator: () => createTranslator,
|
|
41
|
+
locales: () => locales,
|
|
42
|
+
mergeRegistry: () => mergeRegistry
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// src/locale.ts
|
|
46
|
+
var en = {
|
|
47
|
+
"error.missingKit": "game-floorplan-interactables: create needs GameInteractables and GameInteractablesHousehold",
|
|
48
|
+
"error.unknownOwnType": "game-floorplan-interactables: unknown own type: {type}",
|
|
49
|
+
"warn.cylinderNoCabinet": "cylinder {id} under the counter has no kitchen cabinet to hide it",
|
|
50
|
+
"warn.cabinetNoDoor": "cabinet {cabinet} has no door for the cylinder {id}",
|
|
51
|
+
"warn.switchUnknownLamp": "switch {id} controls {lamp}, which does not exist",
|
|
52
|
+
"warn.pointNoObject": "point {id} ({kind}) has no object for {item}",
|
|
53
|
+
"warn.buildEmpty": "build returned nothing for {id}"
|
|
54
|
+
};
|
|
55
|
+
var ptBR = {
|
|
56
|
+
"error.missingKit": "game-floorplan-interactables: create precisa de GameInteractables e GameInteractablesHousehold",
|
|
57
|
+
"error.unknownOwnType": "game-floorplan-interactables: tipo pr\xF3prio desconhecido: {type}",
|
|
58
|
+
"warn.cylinderNoCabinet": "botij\xE3o {id} sob a bancada sem arm\xE1rio de cozinha para escond\xEA-lo",
|
|
59
|
+
"warn.cabinetNoDoor": "arm\xE1rio {cabinet} sem porta para o botij\xE3o {id}",
|
|
60
|
+
"warn.switchUnknownLamp": "interruptor {id} controla {lamp}, que n\xE3o existe",
|
|
61
|
+
"warn.pointNoObject": "ponto {id} ({kind}) sem objeto para {item}",
|
|
62
|
+
"warn.buildEmpty": "construir devolveu vazio para {id}"
|
|
63
|
+
};
|
|
64
|
+
var locales = { en, "pt-BR": ptBR };
|
|
65
|
+
function createTranslator(locale, table) {
|
|
66
|
+
const base = locale && /^pt/i.test(locale) ? ptBR : en;
|
|
67
|
+
const messages = { ...base, ...table ?? {} };
|
|
68
|
+
return (key, params) => (messages[key] ?? key).replace(/\{(\w+)\}/g, (_m, name) => params && params[name] !== void 0 ? String(params[name]) : `{${name}}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/tables.ts
|
|
72
|
+
var TYPE_MAP = Object.freeze({
|
|
73
|
+
fridge: { type: "fridge" },
|
|
74
|
+
// was `geladeira`
|
|
75
|
+
fridge_large: { type: "fridge" },
|
|
76
|
+
// was `geladeira2`
|
|
77
|
+
display_fridge_medium: { type: "fridge", variant: "steel" },
|
|
78
|
+
// was `geladeira_med`
|
|
79
|
+
display_fridge: { type: "fridge", variant: "steel" },
|
|
80
|
+
// was `refrig_exp`
|
|
81
|
+
freezer: { type: "fridge_compact" },
|
|
82
|
+
// was `freezer`
|
|
83
|
+
kitchen_cabinet: { compound: "sink" },
|
|
84
|
+
// was `armario_cozinha`
|
|
85
|
+
kitchen_cabinet_small: { compound: "sink" },
|
|
86
|
+
// was `armario_cozinha_p`
|
|
87
|
+
kitchen_cabinet_large: { compound: "sink" },
|
|
88
|
+
// was `armario_cozinha_g`
|
|
89
|
+
washbasin: { compound: "basin" },
|
|
90
|
+
// was `pia_b`
|
|
91
|
+
pedestal_basin: { compound: "basin" },
|
|
92
|
+
// was `pia_coluna`
|
|
93
|
+
wardrobe: { type: "wardrobe" },
|
|
94
|
+
// was `guarda`
|
|
95
|
+
wardrobe_small: { type: "wardrobe" },
|
|
96
|
+
// was `guarda_peq`
|
|
97
|
+
wardrobe_large: { type: "wardrobe" },
|
|
98
|
+
// was `guarda_g`
|
|
99
|
+
closet_wardrobe: { type: "wardrobe" },
|
|
100
|
+
// was `guarda_closet`
|
|
101
|
+
dresser: { type: "dresser" },
|
|
102
|
+
// was `comoda`
|
|
103
|
+
nightstand: { type: "nightstand" },
|
|
104
|
+
// was `criado`
|
|
105
|
+
pantry: { type: "pantry" },
|
|
106
|
+
// was `despensa`
|
|
107
|
+
laundry_cabinet: { type: "pantry" },
|
|
108
|
+
// was `armario_lav`
|
|
109
|
+
china_cabinet: { type: "pantry" },
|
|
110
|
+
// was `cristaleira`
|
|
111
|
+
filing_cabinet: { type: "dresser" },
|
|
112
|
+
// was `arquivo`
|
|
113
|
+
console_table: { type: "dresser" },
|
|
114
|
+
// was `aparador_c`
|
|
115
|
+
tv_unit: { type: "kitchen_cabinet_base" },
|
|
116
|
+
// was `rack`
|
|
117
|
+
tv_unit_small: { type: "kitchen_cabinet_base" },
|
|
118
|
+
// was `rack_peq`
|
|
119
|
+
tv_unit_large: { type: "kitchen_cabinet_base" },
|
|
120
|
+
// was `rack_grande`
|
|
121
|
+
stove: { type: "stove" },
|
|
122
|
+
// was `fogao`
|
|
123
|
+
stove_4burner: { type: "stove" },
|
|
124
|
+
// was `fogao4`
|
|
125
|
+
cooking_gas_cylinder: { type: "gas_bottle", dim: "none" },
|
|
126
|
+
// was `botijao_gas`
|
|
127
|
+
gas_cylinder: { type: "gas_bottle", dim: "none" },
|
|
128
|
+
// was `botijao`
|
|
129
|
+
tv: { type: "tv" },
|
|
130
|
+
// was `tv`
|
|
131
|
+
tv_large: { type: "tv" },
|
|
132
|
+
// was `tv_grande`
|
|
133
|
+
microwave: { type: "microwave" },
|
|
134
|
+
// was `microondas`
|
|
135
|
+
washing_machine: { type: "washing_machine" },
|
|
136
|
+
// was `maquina`
|
|
137
|
+
shower: { type: "shower", dim: "wd" },
|
|
138
|
+
// was `box`
|
|
139
|
+
shower_large: { type: "shower", dim: "wd" },
|
|
140
|
+
// was `box_g`
|
|
141
|
+
toilet: { type: "toilet", dim: "wd" },
|
|
142
|
+
// was `vaso`
|
|
143
|
+
laundry_tub: { type: "utility_sink", dim: "wd" },
|
|
144
|
+
// was `tanque`
|
|
145
|
+
sofa_2seat: { type: "sofa" },
|
|
146
|
+
// was `sofa2`
|
|
147
|
+
sofa_3seat: { type: "sofa" },
|
|
148
|
+
// was `sofa3`
|
|
149
|
+
sofa_l: { type: "sofa" },
|
|
150
|
+
// was `sofa_l`
|
|
151
|
+
sofa_xl: { type: "sofa" },
|
|
152
|
+
// was `sofa_xl`
|
|
153
|
+
armchair: { type: "armchair" },
|
|
154
|
+
// was `poltrona`
|
|
155
|
+
armchair_high: { type: "armchair" },
|
|
156
|
+
// was `poltrona_alta`
|
|
157
|
+
stool: { type: "dining_chair" },
|
|
158
|
+
// was `banqueta`
|
|
159
|
+
camp_chair: { type: "camp_chair", dim: "wd" },
|
|
160
|
+
// was `cadeira_camping`
|
|
161
|
+
rocking_chair: { type: "armchair" },
|
|
162
|
+
// was `cadeira_balanco`
|
|
163
|
+
rustic_sink: { compound: "rustic_sink" },
|
|
164
|
+
// 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
|
|
165
|
+
improvised_bed: { type: "bed_single", dim: "wd" },
|
|
166
|
+
// was `cama_improvisada`
|
|
167
|
+
log_bench: { type: "bench", dim: "wd" },
|
|
168
|
+
// was `banco_tronco`
|
|
169
|
+
plank_shelf: { type: "pantry", variant: "garage" },
|
|
170
|
+
// was `prateleira_tabua`
|
|
171
|
+
sideboard: { type: "dresser" },
|
|
172
|
+
// was `aparador`
|
|
173
|
+
buffet: { type: "dresser" },
|
|
174
|
+
// was `bufe`
|
|
175
|
+
single_bed: { type: "bed_single", dim: "wd" },
|
|
176
|
+
// was `cama_solteiro`
|
|
177
|
+
double_bed: { type: "bed_double", dim: "wd" },
|
|
178
|
+
// was `cama_casal`
|
|
179
|
+
queen_bed: { type: "bed_double", dim: "wd" },
|
|
180
|
+
// was `cama_queen`
|
|
181
|
+
king_bed: { type: "bed_double", dim: "wd" },
|
|
182
|
+
// was `cama_king`
|
|
183
|
+
bench: { type: "bench", dim: "wd" },
|
|
184
|
+
// was `banco`
|
|
185
|
+
garden_bench: { type: "bench", dim: "wd" },
|
|
186
|
+
// was `banco_jardim`
|
|
187
|
+
waiting_bench: { type: "bench", dim: "wd" },
|
|
188
|
+
// was `espera`
|
|
189
|
+
blinds: { type: "blinds" },
|
|
190
|
+
// was `persiana`
|
|
191
|
+
curtain: { type: "curtain" },
|
|
192
|
+
// was `cortina`
|
|
193
|
+
trash_bin: { type: "trash_bin" },
|
|
194
|
+
// was `lixeira`
|
|
195
|
+
outdoor_bin: { type: "wheelie_bin" },
|
|
196
|
+
// was `lixeira_ext`
|
|
197
|
+
mailbox: { type: "mailbox", dim: "none" },
|
|
198
|
+
// was `caixa_correio`: the household draws the box on its post: position and rotation only
|
|
199
|
+
doghouse: { type: "dog_house" },
|
|
200
|
+
// was `casinha_cachorro`
|
|
201
|
+
bbq_grill: { type: "bbq", dim: "wd" },
|
|
202
|
+
// was `churrasqueira`
|
|
203
|
+
bbq_simple: { type: "bbq", dim: "wd" },
|
|
204
|
+
// was `churrasqueira_simples`
|
|
205
|
+
clothesline: { type: "clothesline", dim: "wh" },
|
|
206
|
+
// was `varal`
|
|
207
|
+
tool_shelf: { type: "pantry", variant: "garage" },
|
|
208
|
+
// was `estante_ferr`
|
|
209
|
+
workbench: { type: "pantry", variant: "garage" },
|
|
210
|
+
// was `bancada_ferr`
|
|
211
|
+
// rural houses and campsite (types of the household pack: rural and camp)
|
|
212
|
+
bunk_bed: { type: "bunk_bed", dim: "wd" },
|
|
213
|
+
// was `beliche`
|
|
214
|
+
wood_stove: { type: "wood_stove", dim: "wd" },
|
|
215
|
+
// was `fogao_lenha`: the flue rises to the chimney height (cabin); the fireplace is handled in `planSimple` (it moves and changes height)
|
|
216
|
+
fireplace: { type: "fireplace", dim: "w" },
|
|
217
|
+
// was `lareira`
|
|
218
|
+
outhouse: { type: "outhouse", dim: "wdh" },
|
|
219
|
+
// was `privada`
|
|
220
|
+
well: { type: "well", dim: "none" },
|
|
221
|
+
// was `poco`
|
|
222
|
+
cooler: { type: "cooler", dim: "wd" },
|
|
223
|
+
// was `cooler`
|
|
224
|
+
campfire: { type: "campfire", dim: "wd" },
|
|
225
|
+
// was `fogueira`
|
|
226
|
+
camp_stove: { type: "camp_stove", dim: "wd" },
|
|
227
|
+
// was `fogareiro`
|
|
228
|
+
camp_gas_canister: { type: "gas_canister", dim: "none" },
|
|
229
|
+
// was `botijao_camping`
|
|
230
|
+
camp_table: { type: "camp_table", dim: "wdh" },
|
|
231
|
+
// was `mesa_camping`
|
|
232
|
+
// kerosene/gas lanterns: a `lamp` device without electricity (the grid does not matter); the ceiling one is the `hanging` variant
|
|
233
|
+
oil_lamp: { type: "lantern_lamp", dim: "x" },
|
|
234
|
+
// was `lampiao`
|
|
235
|
+
camp_lantern: { type: "lantern_lamp", dim: "x" },
|
|
236
|
+
// was `lampiao_camping`
|
|
237
|
+
ceiling_oil_lamp: { type: "lantern_lamp", variant: "hanging", dim: "x" },
|
|
238
|
+
// was `lampiao_teto`
|
|
239
|
+
// lamps: objects of the adapter (the kit has no lamp mesh; the house renderer draws the fixture)
|
|
240
|
+
ceiling_light: { type: "lamp", watts: 15 },
|
|
241
|
+
// was `plafon`
|
|
242
|
+
pendant: { type: "lamp", watts: 20 },
|
|
243
|
+
// was `pendente`
|
|
244
|
+
track_spot: { type: "lamp", watts: 10 },
|
|
245
|
+
// was `spot_trilho`
|
|
246
|
+
chandelier: { type: "lamp", watts: 60 },
|
|
247
|
+
// was `lustre`
|
|
248
|
+
floor_lamp: { type: "lamp", watts: 12 },
|
|
249
|
+
// was `luminaria`
|
|
250
|
+
table_lamp: { type: "lamp", watts: 9 }
|
|
251
|
+
// was `abajur`
|
|
252
|
+
});
|
|
253
|
+
var CHAIR_TABLES = Object.freeze({
|
|
254
|
+
dining_table: "dining",
|
|
255
|
+
// was `mesa`
|
|
256
|
+
dining_table_small: "dining",
|
|
257
|
+
// was `mesa_peq`
|
|
258
|
+
dining_table_round: "dining",
|
|
259
|
+
// was `mesa_red`
|
|
260
|
+
dining_table_large: "dining",
|
|
261
|
+
// was `mesa_grande`
|
|
262
|
+
gourmet_table: "dining",
|
|
263
|
+
// was `mesa_gourmet`
|
|
264
|
+
gourmet_table_small: "dining",
|
|
265
|
+
// was `mesa_gourmet_peq`
|
|
266
|
+
outdoor_table: "dining",
|
|
267
|
+
// was `mesa_ext`
|
|
268
|
+
office_desk: "office",
|
|
269
|
+
// was `mesa_escr`
|
|
270
|
+
office_desk_large: "office",
|
|
271
|
+
// was `mesa_escr_g`
|
|
272
|
+
desk: "office"
|
|
273
|
+
// was `escrivaninha`
|
|
274
|
+
});
|
|
275
|
+
var DINING_CHAIR_SIDE = 0.45;
|
|
276
|
+
var CONTENT_MAP = Object.freeze({
|
|
277
|
+
// food
|
|
278
|
+
sugar: "sugar",
|
|
279
|
+
// was `acucar`
|
|
280
|
+
rice: "rice",
|
|
281
|
+
// was `arroz`
|
|
282
|
+
biscuits: "biscuits",
|
|
283
|
+
// was `biscoito`
|
|
284
|
+
coffee: "coffee",
|
|
285
|
+
// was `cafe`
|
|
286
|
+
raw_beef: "frozen_meat",
|
|
287
|
+
// was `carne`
|
|
288
|
+
packed_meat: "frozen_meat",
|
|
289
|
+
// was `carne`
|
|
290
|
+
flour: "flour",
|
|
291
|
+
// was `farinha`
|
|
292
|
+
beans: "beans",
|
|
293
|
+
// was `feijao`
|
|
294
|
+
apple: "apple",
|
|
295
|
+
// was `fruta`
|
|
296
|
+
fruit: "apple",
|
|
297
|
+
// was `fruta`
|
|
298
|
+
yogurt: "yogurt",
|
|
299
|
+
// was `iogurte`
|
|
300
|
+
canned_food: "canned_food",
|
|
301
|
+
// was `lata_atum`
|
|
302
|
+
canned_tuna: "canned_food",
|
|
303
|
+
// was `lata_atum`
|
|
304
|
+
canned_corn_and_peas: "canned_food",
|
|
305
|
+
// was `lata_milho`
|
|
306
|
+
canned_corn: "canned_food",
|
|
307
|
+
// was `lata_milho`
|
|
308
|
+
milk_carton: "milk_carton",
|
|
309
|
+
// was `leite`
|
|
310
|
+
pasta: "pasta",
|
|
311
|
+
// was `macarrao`
|
|
312
|
+
cooking_oil: "cooking_oil",
|
|
313
|
+
// was `oleo`
|
|
314
|
+
eggs: "eggs",
|
|
315
|
+
// was `ovos`
|
|
316
|
+
cheese: "cheese",
|
|
317
|
+
// was `queijo`
|
|
318
|
+
leftover_meal: "bowl",
|
|
319
|
+
// was `sobras`
|
|
320
|
+
leftovers: "bowl",
|
|
321
|
+
// was `sobras`
|
|
322
|
+
ice_cream: "ice_cream",
|
|
323
|
+
// was `sorvete`
|
|
324
|
+
seasoning: "salt",
|
|
325
|
+
// was `tempero`
|
|
326
|
+
spices: "salt",
|
|
327
|
+
// was `tempero`
|
|
328
|
+
// water and drink
|
|
329
|
+
water_jug_5l: "water_bottle",
|
|
330
|
+
// was `agua_galao`
|
|
331
|
+
water_jug: "water_bottle",
|
|
332
|
+
// was `agua_galao`
|
|
333
|
+
water_bottle: "water_bottle",
|
|
334
|
+
// was `agua_garrafa`
|
|
335
|
+
soda_can: "soda_can",
|
|
336
|
+
// was `refrigerante`
|
|
337
|
+
soda: "soda_can",
|
|
338
|
+
// was `refrigerante`
|
|
339
|
+
// medicine
|
|
340
|
+
alcohol_70: "alcohol_70",
|
|
341
|
+
// was `alcool`
|
|
342
|
+
rubbing_alcohol: "alcohol_70",
|
|
343
|
+
// was `alcool`
|
|
344
|
+
adhesive_bandages: "bandage",
|
|
345
|
+
// was `curativo`
|
|
346
|
+
bandages: "bandage",
|
|
347
|
+
// was `curativo`
|
|
348
|
+
insulin: "first_aid_kit",
|
|
349
|
+
// was `insulina`
|
|
350
|
+
painkillers: "painkillers",
|
|
351
|
+
// was `paracetamol`
|
|
352
|
+
painkiller: "painkillers",
|
|
353
|
+
// was `paracetamol`
|
|
354
|
+
maintenance_medication: "painkillers",
|
|
355
|
+
// was `remedio`
|
|
356
|
+
medicine: "painkillers",
|
|
357
|
+
// was `remedio`
|
|
358
|
+
// cleaning and hygiene
|
|
359
|
+
bleach: "bleach",
|
|
360
|
+
// was `agua_sanitaria`
|
|
361
|
+
disinfectant: "bleach",
|
|
362
|
+
// was `desinfetante`
|
|
363
|
+
detergent: "detergent",
|
|
364
|
+
// was `detergente`
|
|
365
|
+
dish_soap: "detergent",
|
|
366
|
+
// was `detergente`
|
|
367
|
+
toothbrush: "toothbrush",
|
|
368
|
+
// was `escova_dente`
|
|
369
|
+
sponge: "sponge",
|
|
370
|
+
// was `esponja`
|
|
371
|
+
rubber_gloves: "sponge",
|
|
372
|
+
// was `luvas`
|
|
373
|
+
toilet_paper: "toilet_paper",
|
|
374
|
+
// was `papel_higienico`
|
|
375
|
+
laundry_powder: "detergent",
|
|
376
|
+
// was `sabao_po`
|
|
377
|
+
washing_powder: "detergent",
|
|
378
|
+
// was `sabao_po`
|
|
379
|
+
soap: "soap",
|
|
380
|
+
// was `sabonete`
|
|
381
|
+
shampoo: "shampoo",
|
|
382
|
+
// was `shampoo`
|
|
383
|
+
// clothes
|
|
384
|
+
jeans: "jeans",
|
|
385
|
+
// was `calca`
|
|
386
|
+
trousers: "jeans",
|
|
387
|
+
// was `calca`
|
|
388
|
+
tshirt: "tshirt",
|
|
389
|
+
// was `camisa`
|
|
390
|
+
shirt: "tshirt",
|
|
391
|
+
// was `camisa`
|
|
392
|
+
t_shirt: "tshirt",
|
|
393
|
+
// was `camiseta`
|
|
394
|
+
jacket: "jacket",
|
|
395
|
+
// was `casaco`
|
|
396
|
+
coat: "jacket",
|
|
397
|
+
// was `casaco`
|
|
398
|
+
blanket: "blanket",
|
|
399
|
+
// was `cobertor`
|
|
400
|
+
socks: "socks",
|
|
401
|
+
// was `meias`
|
|
402
|
+
underwear: "underwear",
|
|
403
|
+
// was `roupa_intima`
|
|
404
|
+
sneakers: "sneakers",
|
|
405
|
+
// was `sapato`
|
|
406
|
+
shoes: "sneakers",
|
|
407
|
+
// was `sapato`
|
|
408
|
+
// utensils
|
|
409
|
+
cup: "cup",
|
|
410
|
+
// was `caneca`
|
|
411
|
+
mug: "cup",
|
|
412
|
+
// was `caneca`
|
|
413
|
+
plate: "plate",
|
|
414
|
+
// was `prato`
|
|
415
|
+
china_plates: "plate",
|
|
416
|
+
// was `prato`
|
|
417
|
+
plates: "plate",
|
|
418
|
+
// was `prato`
|
|
419
|
+
wine_glass: "cup",
|
|
420
|
+
// was `taca`
|
|
421
|
+
wine_glasses: "cup",
|
|
422
|
+
// was `taca`
|
|
423
|
+
pot: "pot",
|
|
424
|
+
// was `panela`
|
|
425
|
+
// tools and electronics
|
|
426
|
+
pliers: "screwdriver",
|
|
427
|
+
// was `alicate`
|
|
428
|
+
bucket: "paint_can",
|
|
429
|
+
// was `balde`
|
|
430
|
+
cable_bundle: "phone_charger",
|
|
431
|
+
// was `cabos`
|
|
432
|
+
cables: "phone_charger",
|
|
433
|
+
// was `cabos`
|
|
434
|
+
pen: "pen",
|
|
435
|
+
// was `caneta`
|
|
436
|
+
phone_charger: "phone_charger",
|
|
437
|
+
// was `carregador`
|
|
438
|
+
charger: "phone_charger",
|
|
439
|
+
// was `carregador`
|
|
440
|
+
screwdriver: "screwdriver",
|
|
441
|
+
// was `chave_fenda`
|
|
442
|
+
house_key: "wallet",
|
|
443
|
+
// was `chaves`
|
|
444
|
+
keys: "wallet",
|
|
445
|
+
// was `chaves`
|
|
446
|
+
remote_control: "batteries",
|
|
447
|
+
// was `controle_remoto`
|
|
448
|
+
rope: "rope",
|
|
449
|
+
// was `corda`
|
|
450
|
+
electrical_tape: "duct_tape",
|
|
451
|
+
// was `fita_isolante`
|
|
452
|
+
insulating_tape: "duct_tape",
|
|
453
|
+
// was `fita_isolante`
|
|
454
|
+
flashlight: "flashlight",
|
|
455
|
+
// was `lanterna`
|
|
456
|
+
backpack: "backpack",
|
|
457
|
+
// was `mochila`
|
|
458
|
+
eyeglasses: "wallet",
|
|
459
|
+
// was `oculos`
|
|
460
|
+
glasses: "wallet",
|
|
461
|
+
// was `oculos`
|
|
462
|
+
screws: "duct_tape",
|
|
463
|
+
// was `parafusos`
|
|
464
|
+
batteries: "batteries",
|
|
465
|
+
// was `pilhas`
|
|
466
|
+
nails: "duct_tape",
|
|
467
|
+
// was `pregos`
|
|
468
|
+
// improvised weapons
|
|
469
|
+
knife: "knife",
|
|
470
|
+
// was `faca`
|
|
471
|
+
kitchen_knife: "knife",
|
|
472
|
+
// was `faca`
|
|
473
|
+
stapler: "scissors",
|
|
474
|
+
// was `grampeador`
|
|
475
|
+
hammer: "hammer",
|
|
476
|
+
// was `martelo`
|
|
477
|
+
handsaw: "hammer",
|
|
478
|
+
// was `serrote`
|
|
479
|
+
hand_saw: "hammer",
|
|
480
|
+
// was `serrote`
|
|
481
|
+
scissors: "scissors",
|
|
482
|
+
// was `tesoura`
|
|
483
|
+
broom: "rope",
|
|
484
|
+
// was `vassoura`
|
|
485
|
+
// papers
|
|
486
|
+
letter: "letter",
|
|
487
|
+
// was `carta`
|
|
488
|
+
bill: "bill",
|
|
489
|
+
// was `conta`
|
|
490
|
+
documents: "documents",
|
|
491
|
+
// was `documento`
|
|
492
|
+
dvd: "notebook",
|
|
493
|
+
// was `dvd`
|
|
494
|
+
dvds: "notebook",
|
|
495
|
+
// was `dvd`
|
|
496
|
+
book: "notebook",
|
|
497
|
+
// was `livro`
|
|
498
|
+
// trash
|
|
499
|
+
food_packaging: "plastic_bag",
|
|
500
|
+
// was `embalagem`
|
|
501
|
+
packaging: "plastic_bag",
|
|
502
|
+
// was `embalagem`
|
|
503
|
+
paint_can: "paint_can",
|
|
504
|
+
// was `lata_tinta`
|
|
505
|
+
empty_can: "empty_can",
|
|
506
|
+
// was `lata_vazia`
|
|
507
|
+
flyer: "flyer",
|
|
508
|
+
// was `panfleto`
|
|
509
|
+
crumpled_paper: "crumpled_paper",
|
|
510
|
+
// was `papel_amassado`
|
|
511
|
+
trash_bag: "plastic_bag",
|
|
512
|
+
// was `saco_lixo`
|
|
513
|
+
full_trash_bag: "plastic_bag"
|
|
514
|
+
// was `saco_lixo_cheio`
|
|
515
|
+
});
|
|
516
|
+
var CONTENT_BY_GROUP = Object.freeze({
|
|
517
|
+
food: "canned_food",
|
|
518
|
+
// was `comida`
|
|
519
|
+
water: "water_bottle",
|
|
520
|
+
// was `agua`
|
|
521
|
+
medicine: "painkillers",
|
|
522
|
+
// was `remedio`
|
|
523
|
+
tool: "duct_tape",
|
|
524
|
+
// was `ferramenta`
|
|
525
|
+
improvised_weapon: "hammer",
|
|
526
|
+
// was `arma_improvisada`
|
|
527
|
+
clothes: "tshirt",
|
|
528
|
+
// was `roupa`
|
|
529
|
+
document: "documents",
|
|
530
|
+
// was `documento`
|
|
531
|
+
cleaning: "detergent",
|
|
532
|
+
// was `limpeza`
|
|
533
|
+
trash: "crumpled_paper",
|
|
534
|
+
// was `lixo`
|
|
535
|
+
utensil: "plate"
|
|
536
|
+
// was `utensilio`
|
|
537
|
+
});
|
|
538
|
+
var CONTENT_FALLBACK = "crumpled_paper";
|
|
539
|
+
var FROZEN_ITEMS = Object.freeze(["ice_cream", "frozen_meat"]);
|
|
540
|
+
var DRAWER_ITEMS = Object.freeze(["underwear", "socks"]);
|
|
541
|
+
var DRAWER_GROUPS = Object.freeze(["improvised_weapon", "tool"]);
|
|
542
|
+
var OBJECT_SUBSTITUTES = Object.freeze({ mailbox: ["flyer", "postcard", "letter"] });
|
|
543
|
+
var FIXTURES_OF_POINT = Object.freeze({
|
|
544
|
+
tap: ["tap"],
|
|
545
|
+
// was `torneira`
|
|
546
|
+
shower: ["shower"],
|
|
547
|
+
// was `chuveiro`
|
|
548
|
+
flush: ["flush"],
|
|
549
|
+
// was `descarga`
|
|
550
|
+
tub: ["tap", "basin"],
|
|
551
|
+
// was `tanque`
|
|
552
|
+
machine: ["inlet"]
|
|
553
|
+
// was `maquina`
|
|
554
|
+
});
|
|
555
|
+
var OWN_TYPES = Object.freeze({ lamp: true, gas_piped: true });
|
|
556
|
+
|
|
557
|
+
// src/adapter.ts
|
|
558
|
+
var ADAPTER_VERSION = "0.3.0";
|
|
559
|
+
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
560
|
+
function mergeRegistry(base, extra) {
|
|
561
|
+
const out = { ...base };
|
|
562
|
+
if (extra) {
|
|
563
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
564
|
+
if (value == null) delete out[key];
|
|
565
|
+
else out[key] = value;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return out;
|
|
569
|
+
}
|
|
570
|
+
var PREFERENCE = Object.freeze({
|
|
571
|
+
fridge: (s, c) => c.frozen(s) ? ["freezer", "fridge"] : ["fridge", "freezer"],
|
|
572
|
+
fridge_compact: (s, c) => c.frozen(s) ? ["freezer", "fridge"] : ["fridge", "freezer"],
|
|
573
|
+
kitchen_cabinet_base: (s, c) => DRAWER_GROUPS.includes(c.group(s)) ? ["drawer", "cupboard"] : ["cupboard", "drawer"],
|
|
574
|
+
wardrobe: (s, c) => c.drawerItem(s) ? ["drawer_1", "drawer_2", "drawer_3", "shelves"] : ["shelves", "drawer_1", "drawer_2", "drawer_3"]
|
|
575
|
+
});
|
|
576
|
+
function create(options = {}) {
|
|
577
|
+
const opts = options || {};
|
|
578
|
+
const GI = opts.GameInteractables;
|
|
579
|
+
const HH = opts.GameInteractablesHousehold;
|
|
580
|
+
const locale = opts.locale || "pt-BR";
|
|
581
|
+
const msg = createTranslator(locale, opts.messages);
|
|
582
|
+
if (!GI || !HH) throw new Error(msg("error.missingKit"));
|
|
583
|
+
const region = opts.region || "br";
|
|
584
|
+
const hh = HH.createHousehold({ locale, region });
|
|
585
|
+
const householdTypes = new Set(hh.types.map((t) => t.id));
|
|
586
|
+
const worlds = /* @__PURE__ */ new WeakMap();
|
|
587
|
+
const typeMap = mergeRegistry(TYPE_MAP, opts.typeMap);
|
|
588
|
+
const contentMap = mergeRegistry(CONTENT_MAP, opts.contentMap);
|
|
589
|
+
const contentByGroup = mergeRegistry(CONTENT_BY_GROUP, opts.contentByGroup);
|
|
590
|
+
const chairTables = mergeRegistry(CHAIR_TABLES, opts.chairTables);
|
|
591
|
+
const fixturesOfPoint = mergeRegistry(FIXTURES_OF_POINT, opts.fixturesOfPoint);
|
|
592
|
+
const substitutes = mergeRegistry(OBJECT_SUBSTITUTES, opts.substitutes);
|
|
593
|
+
const preference = mergeRegistry(PREFERENCE, opts.preference);
|
|
594
|
+
const ownTypes = mergeRegistry(OWN_TYPES, opts.ownTypes);
|
|
595
|
+
const frozenItems = new Set(opts.frozenItems ?? FROZEN_ITEMS);
|
|
596
|
+
const drawerItems = new Set(opts.drawerItems ?? DRAWER_ITEMS);
|
|
597
|
+
const chairSide = opts.chairSide ?? DINING_CHAIR_SIDE;
|
|
598
|
+
const contentFallback = opts.contentFallback ?? CONTENT_FALLBACK;
|
|
599
|
+
const seedKey = (id) => {
|
|
600
|
+
if (!opts.seedKey) return id;
|
|
601
|
+
const key = opts.seedKey(id);
|
|
602
|
+
return key == null ? id : key;
|
|
603
|
+
};
|
|
604
|
+
function conv(o) {
|
|
605
|
+
return {
|
|
606
|
+
x: (u) => r3(o.ox + u),
|
|
607
|
+
z: (v) => r3(o.oz + o.inw * v),
|
|
608
|
+
ry: (fu, fv) => r3(Math.atan2(fu, o.inw * fv)),
|
|
609
|
+
// local offset (lx, lz) of an object with rotation ry -> offset in the world (same convention as three.js)
|
|
610
|
+
off: (ry, lx, lz) => [Math.cos(ry) * lx + Math.sin(ry) * lz, -Math.sin(ry) * lx + Math.cos(ry) * lz]
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
function floorYOf(res, o, floor) {
|
|
614
|
+
if (floor == null || floor < 0) return o.base;
|
|
615
|
+
const f = (res.floors || []).find((x) => x.index === floor);
|
|
616
|
+
return r3(o.base + (f ? f.y0 : 0));
|
|
617
|
+
}
|
|
618
|
+
function colorOf(res, color) {
|
|
619
|
+
if (color == null) return void 0;
|
|
620
|
+
if (typeof color === "number") return color;
|
|
621
|
+
const v = res.colors && res.colors[color];
|
|
622
|
+
return typeof v === "number" ? v : void 0;
|
|
623
|
+
}
|
|
624
|
+
function paletteOf(res) {
|
|
625
|
+
const c = res.colors || {};
|
|
626
|
+
const p = {};
|
|
627
|
+
if (c.wood != null) p.wood = c.wood;
|
|
628
|
+
if (c.fabric_main != null) p.fabric_main = c.fabric_main;
|
|
629
|
+
if (c.fabric_accent != null) p.fabric_accent = c.fabric_accent;
|
|
630
|
+
if (c.metal != null) p.metal = c.metal;
|
|
631
|
+
return p;
|
|
632
|
+
}
|
|
633
|
+
function lightsOfState(res) {
|
|
634
|
+
const electrical = res.utilities && res.utilities.electrical;
|
|
635
|
+
return res.state !== "abandoned" && !!electrical && electrical.mode !== "offgrid";
|
|
636
|
+
}
|
|
637
|
+
function initialLight(res, popts, id, entry) {
|
|
638
|
+
const v = popts && popts.lightsOn;
|
|
639
|
+
if (typeof v === "function") return !!v(id, entry);
|
|
640
|
+
if (typeof v === "boolean") return v;
|
|
641
|
+
return !!(popts && popts.night) && lightsOfState(res);
|
|
642
|
+
}
|
|
643
|
+
const stackGroup = (s) => s.group ?? (opts.groupOf ? opts.groupOf(s.itemId) : null) ?? null;
|
|
644
|
+
const preferenceContext = {
|
|
645
|
+
frozen: (s) => frozenItems.has(s.itemId),
|
|
646
|
+
group: stackGroup,
|
|
647
|
+
drawerItem: (s) => drawerItems.has(s.itemId)
|
|
648
|
+
};
|
|
649
|
+
const itemOfContent = (c) => {
|
|
650
|
+
const id = contentMap[c.itemId] || (hh.items[c.itemId] ? c.itemId : null) || contentByGroup[stackGroup(c)] || contentFallback;
|
|
651
|
+
return hh.items[id] ? id : contentFallback;
|
|
652
|
+
};
|
|
653
|
+
const volume = (d) => d.size[0] * d.size[1] * d.size[2];
|
|
654
|
+
const candidates = (id, objectType) => {
|
|
655
|
+
const def = hh.items[id];
|
|
656
|
+
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));
|
|
657
|
+
return [id].concat(siblings.map((i) => i.id), substitutes[objectType] || []);
|
|
658
|
+
};
|
|
659
|
+
function distribute(type, probeItem, stacks) {
|
|
660
|
+
const spec = hh.build(type, probeItem, HH.createRecorder().api);
|
|
661
|
+
const conts = spec.containers || [];
|
|
662
|
+
const contents = {};
|
|
663
|
+
for (const c of conts) contents[c.id] = c.slots.map(() => null);
|
|
664
|
+
const rejected = [];
|
|
665
|
+
const pref = preference[type];
|
|
666
|
+
for (const p of stacks || []) {
|
|
667
|
+
const original = itemOfContent(p);
|
|
668
|
+
const order = (pref ? pref(p, preferenceContext) : []).concat(conts.map((c) => c.id));
|
|
669
|
+
let placed = false;
|
|
670
|
+
for (const id of candidates(original, type)) {
|
|
671
|
+
const def = hh.items[id];
|
|
672
|
+
const qty = Math.max(1, Math.min(p.count || 1, def && def.stack || 1));
|
|
673
|
+
for (const cid of order) {
|
|
674
|
+
const c = conts.find((x) => x.id === cid);
|
|
675
|
+
if (!c) continue;
|
|
676
|
+
for (let i = 0; i < c.slots.length && !placed; i++) {
|
|
677
|
+
if (contents[cid][i] || !GI.fitsSlot(id, c.slots[i], hh.items)) continue;
|
|
678
|
+
const data = { source: p.itemId, group: p.group, pickable: p.pickable !== false };
|
|
679
|
+
if (id !== original) data.substituteFor = original;
|
|
680
|
+
contents[cid][i] = { type: id, qty, data };
|
|
681
|
+
placed = true;
|
|
682
|
+
}
|
|
683
|
+
if (placed) break;
|
|
684
|
+
}
|
|
685
|
+
if (placed) break;
|
|
686
|
+
}
|
|
687
|
+
if (!placed) rejected.push(p);
|
|
688
|
+
}
|
|
689
|
+
return { contents, rejected };
|
|
690
|
+
}
|
|
691
|
+
function plan(res, popts = {}) {
|
|
692
|
+
popts = popts || {};
|
|
693
|
+
const o = { ox: popts.originX || 0, oz: popts.originZ || 0, inw: popts.inw || 1, base: popts.base || 0 };
|
|
694
|
+
const K = conv(o);
|
|
695
|
+
const floorSel = popts.floor;
|
|
696
|
+
const externals = popts.externals !== false;
|
|
697
|
+
const seed = popts.seed != null ? popts.seed : res.seed;
|
|
698
|
+
const palette = paletteOf(res);
|
|
699
|
+
const onFloor = (f, outdoor) => floorSel == null || f === floorSel || (outdoor || f < 0) && externals;
|
|
700
|
+
const utilities = res.utilities || {};
|
|
701
|
+
const electrical = utilities.electrical || null;
|
|
702
|
+
const circuits = electrical && electrical.circuits || [];
|
|
703
|
+
const contents = res.contents || {};
|
|
704
|
+
const result = {
|
|
705
|
+
version: ADAPTER_VERSION,
|
|
706
|
+
template: res.template,
|
|
707
|
+
seed: res.seed,
|
|
708
|
+
floor: floorSel == null ? null : floorSel,
|
|
709
|
+
items: [],
|
|
710
|
+
outlets: [],
|
|
711
|
+
// ids of the wall_socket entries
|
|
712
|
+
switches: [],
|
|
713
|
+
// ids of the wall_switch entries
|
|
714
|
+
lights: [],
|
|
715
|
+
// ids of the lamps (inside and outside)
|
|
716
|
+
lanterns: [],
|
|
717
|
+
// ids of the lanterns (lantern_lamp): kerosene/gas light, no grid
|
|
718
|
+
canisters: [],
|
|
719
|
+
// ids of the small camping cylinders (gas_canister)
|
|
720
|
+
serviceEntrance: null,
|
|
721
|
+
panel: null,
|
|
722
|
+
// id of the electrical_panel entry (distribution board)
|
|
723
|
+
meter: null,
|
|
724
|
+
// id of the power_meter entry (meter box on the facade or the pillar)
|
|
725
|
+
conduits: [],
|
|
726
|
+
cylinders: [],
|
|
727
|
+
// { id, stove, place }
|
|
728
|
+
stoves: [],
|
|
729
|
+
fixtures: [],
|
|
730
|
+
// { object, fixture, global, point, pointKind }
|
|
731
|
+
points: {},
|
|
732
|
+
// global fixture -> point of the plumbing
|
|
733
|
+
mapped: [],
|
|
734
|
+
// ids of furniture of the plan that became objects of the kit (the renderer does not need to draw them)
|
|
735
|
+
chairs: [],
|
|
736
|
+
// ids of the chairs the adapter put around the tables (origin = the table, which the renderer keeps drawing)
|
|
737
|
+
unmapped: {},
|
|
738
|
+
// "category/type" -> count
|
|
739
|
+
discarded: 0,
|
|
740
|
+
// stacks of content that fit no slot
|
|
741
|
+
warnings: [],
|
|
742
|
+
origin: { x: o.ox, z: o.oz, inw: o.inw, base: o.base }
|
|
743
|
+
};
|
|
744
|
+
const byOrigin = /* @__PURE__ */ new Map();
|
|
745
|
+
const seedOf = (id) => GI.hashString(String(seed) + ":" + seedKey(id));
|
|
746
|
+
function push(e) {
|
|
747
|
+
result.items.push(e);
|
|
748
|
+
if (!byOrigin.has(e.origin)) byOrigin.set(e.origin, []);
|
|
749
|
+
byOrigin.get(e.origin).push(e);
|
|
750
|
+
return e;
|
|
751
|
+
}
|
|
752
|
+
function baseItem(m) {
|
|
753
|
+
const item = {
|
|
754
|
+
x: K.x(m.x),
|
|
755
|
+
z: K.z(m.z),
|
|
756
|
+
ry: m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0),
|
|
757
|
+
w: m.w,
|
|
758
|
+
d: m.d,
|
|
759
|
+
h: m.h,
|
|
760
|
+
y: m.y || 0,
|
|
761
|
+
seed: seedOf(m.id),
|
|
762
|
+
palette
|
|
763
|
+
};
|
|
764
|
+
const color = colorOf(res, m.color);
|
|
765
|
+
if (color != null) item.color = color;
|
|
766
|
+
return item;
|
|
767
|
+
}
|
|
768
|
+
function entry(id, type, item, origin, floor, extra) {
|
|
769
|
+
return Object.assign({ id, type, item, origin, floor, floorY: floorYOf(res, o, floor), connections: {} }, extra || {});
|
|
770
|
+
}
|
|
771
|
+
function store(targets, stacks) {
|
|
772
|
+
let rest = stacks || [];
|
|
773
|
+
for (const [type, item] of targets) {
|
|
774
|
+
const d = distribute(type, item, rest);
|
|
775
|
+
item.contents = Object.assign(item.contents || {}, d.contents);
|
|
776
|
+
rest = d.rejected;
|
|
777
|
+
}
|
|
778
|
+
result.discarded += rest.length;
|
|
779
|
+
}
|
|
780
|
+
const hidden = [];
|
|
781
|
+
function distRect(c, x, z) {
|
|
782
|
+
const dx = x - c.item.x;
|
|
783
|
+
const dz = z - c.item.z;
|
|
784
|
+
const s = Math.sin(c.item.ry);
|
|
785
|
+
const co = Math.cos(c.item.ry);
|
|
786
|
+
const lx = dx * co - dz * s;
|
|
787
|
+
const lz = dx * s + dz * co;
|
|
788
|
+
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));
|
|
789
|
+
}
|
|
790
|
+
function hideCylinders() {
|
|
791
|
+
for (const b of hidden) {
|
|
792
|
+
let target = null;
|
|
793
|
+
for (const c2 of result.items) {
|
|
794
|
+
if (c2.type !== "kitchen_cabinet_base" || c2.floor !== b.floor) continue;
|
|
795
|
+
const dist = distRect(c2, b.item.x, b.item.z);
|
|
796
|
+
if (!target || dist < target.dist) target = { c: c2, dist };
|
|
797
|
+
}
|
|
798
|
+
if (!target) {
|
|
799
|
+
result.warnings.push(msg("warn.cylinderNoCabinet", { id: b.id }));
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
const c = target.c;
|
|
803
|
+
const spec = hh.build(c.type, c.item, HH.createRecorder().api);
|
|
804
|
+
const sn = Math.sin(c.item.ry);
|
|
805
|
+
const cs = Math.cos(c.item.ry);
|
|
806
|
+
let door = null;
|
|
807
|
+
for (const it of spec.interactions || []) {
|
|
808
|
+
const pt = it.action && it.action.do === "toggle_part" ? (spec.parts || []).find((q) => q.id === it.action.part) : null;
|
|
809
|
+
if (!pt || pt.motion.kind !== "hinge") continue;
|
|
810
|
+
const wx = c.item.x + it.pos[0] * cs + it.pos[2] * sn;
|
|
811
|
+
const wz = c.item.z - it.pos[0] * sn + it.pos[2] * cs;
|
|
812
|
+
const dist = Math.hypot(wx - b.item.x, wz - b.item.z);
|
|
813
|
+
if (!door || dist < door.dist) door = { id: pt.id, dist };
|
|
814
|
+
}
|
|
815
|
+
if (!door) {
|
|
816
|
+
result.warnings.push(msg("warn.cabinetNoDoor", { cabinet: c.id, id: b.id }));
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
b.item.requires = { object: c.id, part: door.id };
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
function initialLanternLight(id, e) {
|
|
823
|
+
const v = popts.lightsOn;
|
|
824
|
+
if (typeof v === "function") return !!v(id, e);
|
|
825
|
+
if (typeof v === "boolean") return v;
|
|
826
|
+
return !!popts.night && res.state !== "abandoned";
|
|
827
|
+
}
|
|
828
|
+
const chimney = res.structureExtras && res.structureExtras.chimney || null;
|
|
829
|
+
const firstOfType = (type) => (res.items || []).find((m) => typeMap[m.type] && typeMap[m.type].type === type);
|
|
830
|
+
function chimneyOf(m, role) {
|
|
831
|
+
if (!chimney) return null;
|
|
832
|
+
const named = role === "fireplace" ? chimney.fireplace : chimney.stove;
|
|
833
|
+
if (named != null) return named === m.id ? chimney : null;
|
|
834
|
+
const first = firstOfType(role === "fireplace" ? "fireplace" : "wood_stove");
|
|
835
|
+
return chimney.kind === (role === "fireplace" ? "fireplace" : "flue") && first && first.id === m.id ? chimney : null;
|
|
836
|
+
}
|
|
837
|
+
const chimneyHeight = (ch) => ch.height != null ? ch.height : ch.top;
|
|
838
|
+
const campStove = firstOfType("camp_stove");
|
|
839
|
+
const campCylinder = firstOfType("gas_canister");
|
|
840
|
+
function planFireplace(m, e, item) {
|
|
841
|
+
const def = hh.types.find((t) => t.id === "fireplace");
|
|
842
|
+
const lack = (def.d - m.d) / 2;
|
|
843
|
+
item.x = r3(item.x + Math.sin(item.ry) * lack);
|
|
844
|
+
item.z = r3(item.z + Math.cos(item.ry) * lack);
|
|
845
|
+
const room = (res.rooms || []).find((c) => c.id === m.room && c.floor === m.floor);
|
|
846
|
+
const f = (res.floors || []).find((x) => x.index === m.floor);
|
|
847
|
+
item.h = r3(room && room.ceiling || f && f.ceiling || 2.6);
|
|
848
|
+
const ch = chimneyOf(m, "fireplace");
|
|
849
|
+
if (ch) {
|
|
850
|
+
if (ch.material === "stone") item.variant = "stone";
|
|
851
|
+
const cx = K.x((ch.aabb[0] + ch.aabb[2]) / 2);
|
|
852
|
+
const cz = K.z((ch.aabb[1] + ch.aabb[3]) / 2);
|
|
853
|
+
e.connections.chimneyTop = [cx, r3(o.base + chimneyHeight(ch)), cz];
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
function planSimple(m, map) {
|
|
857
|
+
const item = baseItem(m);
|
|
858
|
+
const dim = map.dim === "none" ? "" : map.dim || "wdh";
|
|
859
|
+
for (const k of ["w", "d", "h"]) if (dim.indexOf(k) < 0) delete item[k];
|
|
860
|
+
if (map.dim === "none") delete item.y;
|
|
861
|
+
if (map.variant) item.variant = map.variant;
|
|
862
|
+
if (map.type === "tv") item.d = Math.max(item.d || 0, 0.2);
|
|
863
|
+
const e = entry(m.id, map.type, item, m.id, m.floor);
|
|
864
|
+
if (contents[m.id]) store([[map.type, item]], contents[m.id]);
|
|
865
|
+
if (m.outlet) e.connections.outlet = m.outlet;
|
|
866
|
+
if (map.type === "shower") e.connections.shower = m.showerHeater || { electric: false };
|
|
867
|
+
if (map.type === "stove") {
|
|
868
|
+
result.stoves.push(e.id);
|
|
869
|
+
e.connections.gas = m.gas || "cylinder";
|
|
870
|
+
e.connections.cylinder = m.cylinder || null;
|
|
871
|
+
}
|
|
872
|
+
if (map.type === "gas_bottle") result.cylinders.push({ id: e.id, stove: m.link || null, place: m.placement || null });
|
|
873
|
+
if (map.type === "gas_canister") {
|
|
874
|
+
result.canisters.push(e.id);
|
|
875
|
+
if (campCylinder && campCylinder.id === m.id && campStove) result.cylinders.push({ id: e.id, stove: campStove.id, place: null });
|
|
876
|
+
}
|
|
877
|
+
if (map.type === "wood_stove") {
|
|
878
|
+
const ch = chimneyOf(m, "stove");
|
|
879
|
+
if (ch && chimneyHeight(ch)) {
|
|
880
|
+
const f = (res.floors || []).find((x) => x.index === m.floor);
|
|
881
|
+
const high = r3(chimneyHeight(ch) - (f ? f.y0 : 0) - (m.y || 0));
|
|
882
|
+
item.h = high;
|
|
883
|
+
item.flueHeight = high;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (map.type === "fireplace") planFireplace(m, e, item);
|
|
887
|
+
if (map.type === "lantern_lamp") {
|
|
888
|
+
e.lit = initialLanternLight(m.id, e);
|
|
889
|
+
item.on = e.lit;
|
|
890
|
+
result.lanterns.push(e.id);
|
|
891
|
+
}
|
|
892
|
+
if (map.type === "gas_bottle" && m.placement === "under_counter") hidden.push(e);
|
|
893
|
+
push(e);
|
|
894
|
+
}
|
|
895
|
+
function planCompound(m, kind) {
|
|
896
|
+
const ry = m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0);
|
|
897
|
+
const cx = K.x(m.x);
|
|
898
|
+
const cz = K.z(m.z);
|
|
899
|
+
const part = (id, type, w, d, h, y, lx, lz) => {
|
|
900
|
+
const [dx, dz] = K.off(ry, lx, lz);
|
|
901
|
+
const item = baseItem(m);
|
|
902
|
+
item.x = r3(cx + dx);
|
|
903
|
+
item.z = r3(cz + dz);
|
|
904
|
+
item.ry = ry;
|
|
905
|
+
item.w = r3(w);
|
|
906
|
+
item.d = r3(d);
|
|
907
|
+
item.h = r3(h);
|
|
908
|
+
item.y = y;
|
|
909
|
+
item.seed = seedOf(id);
|
|
910
|
+
return entry(id, type, item, m.id, m.floor);
|
|
911
|
+
};
|
|
912
|
+
const list = [];
|
|
913
|
+
const overhead = contents[m.id + "#overhead"];
|
|
914
|
+
if (kind === "rustic_sink") {
|
|
915
|
+
const dd = Math.max(m.d, 0.56);
|
|
916
|
+
const basin = part(m.id, "sink_kitchen", m.w, dd, m.h + 0.3, 0, 0, -(dd - m.d) / 2);
|
|
917
|
+
list.push(basin);
|
|
918
|
+
const over = overhead || [];
|
|
919
|
+
if (m.overhead !== false && over.length) {
|
|
920
|
+
const wall = part(m.id + "#overhead", "kitchen_cabinet_wall", m.w, 0.35, 0.6, 1.55, 0, -(m.d / 2) + 0.175);
|
|
921
|
+
store([["kitchen_cabinet_wall", wall.item]], over);
|
|
922
|
+
list.push(wall);
|
|
923
|
+
}
|
|
924
|
+
if (contents[m.id]) store([["sink_kitchen", basin.item]], contents[m.id]);
|
|
925
|
+
if (m.outlet) basin.connections.outlet = m.outlet;
|
|
926
|
+
} else if (kind === "sink") {
|
|
927
|
+
const width = m.w;
|
|
928
|
+
const basinW = width >= 1.5 ? 1 : Math.max(0.6, Math.min(0.8, width - 0.3));
|
|
929
|
+
const rest = r3(width - basinW);
|
|
930
|
+
const left = seedOf(m.id) % 2 === 0;
|
|
931
|
+
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);
|
|
932
|
+
list.push(sink);
|
|
933
|
+
let cabinet = null;
|
|
934
|
+
if (rest >= 0.35) {
|
|
935
|
+
cabinet = part(m.id + "#cabinet", "kitchen_cabinet_base", rest, m.d, m.h, 0, left ? width / 2 - rest / 2 : -(width / 2) + rest / 2, 0);
|
|
936
|
+
list.push(cabinet);
|
|
937
|
+
}
|
|
938
|
+
if (contents[m.id]) store(cabinet ? [["kitchen_cabinet_base", cabinet.item], ["sink_kitchen", sink.item]] : [["sink_kitchen", sink.item]], contents[m.id]);
|
|
939
|
+
if (m.overhead !== false) {
|
|
940
|
+
const wall = part(m.id + "#overhead", "kitchen_cabinet_wall", width, 0.35, 0.6, 1.55, 0, -(m.d / 2) + 0.175);
|
|
941
|
+
store([["kitchen_cabinet_wall", wall.item]], overhead || []);
|
|
942
|
+
list.push(wall);
|
|
943
|
+
}
|
|
944
|
+
if (m.outlet) sink.connections.outlet = m.outlet;
|
|
945
|
+
} else {
|
|
946
|
+
const basin = part(m.id, "sink_bathroom", m.w, m.d, m.h + 0.2, 0, 0, 0);
|
|
947
|
+
list.push(basin);
|
|
948
|
+
if (contents[m.id]) {
|
|
949
|
+
if (contents[m.id].length) {
|
|
950
|
+
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);
|
|
951
|
+
list.push(cabinet);
|
|
952
|
+
store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]], contents[m.id]);
|
|
953
|
+
} else {
|
|
954
|
+
store([["sink_bathroom", basin.item]], []);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
for (const e of list) push(e);
|
|
959
|
+
}
|
|
960
|
+
function circuitOfLight(id) {
|
|
961
|
+
const direct = circuits.find((c) => (c.lamps || []).indexOf(id) >= 0);
|
|
962
|
+
if (direct) return direct.id;
|
|
963
|
+
const sw = (electrical && electrical.switches || []).find((s) => (s.controls || []).indexOf(id) >= 0);
|
|
964
|
+
const viaSwitch = sw && circuits.find((c) => (c.switches || []).indexOf(sw.id) >= 0);
|
|
965
|
+
return viaSwitch ? viaSwitch.id : "standalone_circuit";
|
|
966
|
+
}
|
|
967
|
+
function planLamp(m, map) {
|
|
968
|
+
const item = baseItem(m);
|
|
969
|
+
delete item.palette;
|
|
970
|
+
const e = entry(m.id, "lamp", item, m.id, m.floor, { watts: map.watts });
|
|
971
|
+
e.connections.circuit = circuitOfLight(m.id);
|
|
972
|
+
e.lit = initialLight(res, popts, m.id, e);
|
|
973
|
+
push(e);
|
|
974
|
+
result.lights.push(e.id);
|
|
975
|
+
}
|
|
976
|
+
for (const m of res.items || []) {
|
|
977
|
+
if (!onFloor(m.floor, m.outdoor)) continue;
|
|
978
|
+
const map = typeMap[m.type];
|
|
979
|
+
if (!map) {
|
|
980
|
+
const k = m.category + "/" + m.type;
|
|
981
|
+
result.unmapped[k] = (result.unmapped[k] || 0) + 1;
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
result.mapped.push(m.id);
|
|
985
|
+
if (map.type === "lamp") planLamp(m, map);
|
|
986
|
+
else if (map.compound) planCompound(m, map.compound);
|
|
987
|
+
else planSimple(m, map);
|
|
988
|
+
}
|
|
989
|
+
result.chairs = [];
|
|
990
|
+
if (opts.chairs !== false && popts.chairs !== false) {
|
|
991
|
+
const blocked = blockedOf(res, { originX: o.ox, originZ: o.oz, inw: o.inw });
|
|
992
|
+
const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && q.aabb;
|
|
993
|
+
const placed = [];
|
|
994
|
+
const free = (m, cu, cv, half) => {
|
|
995
|
+
const a = [cu - half + 0.03, cv - half + 0.03, cu + half - 0.03, cv + half - 0.03];
|
|
996
|
+
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;
|
|
997
|
+
for (const q of res.items || []) {
|
|
998
|
+
if (q === m || !floorKind(q) || q.floor !== m.floor && !(q.outdoor && m.outdoor)) continue;
|
|
999
|
+
if (a[0] < q.aabb[2] && a[2] > q.aabb[0] && a[1] < q.aabb[3] && a[3] > q.aabb[1]) return false;
|
|
1000
|
+
}
|
|
1001
|
+
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;
|
|
1002
|
+
placed.push([a[0], a[1], a[2], a[3], m.floor]);
|
|
1003
|
+
return true;
|
|
1004
|
+
};
|
|
1005
|
+
for (const m of res.items || []) {
|
|
1006
|
+
const mode = chairTables[m.type];
|
|
1007
|
+
if (!mode || !onFloor(m.floor, m.outdoor) || m.frontU == null) continue;
|
|
1008
|
+
const f = [m.frontU, m.frontV];
|
|
1009
|
+
const pp = [-m.frontV, m.frontU];
|
|
1010
|
+
const seats = [];
|
|
1011
|
+
if (mode === "dining") {
|
|
1012
|
+
const n = Math.max(1, Math.min(3, Math.floor((m.w - 0.1) / 0.55)));
|
|
1013
|
+
for (const side of [1, -1]) {
|
|
1014
|
+
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]]]);
|
|
1015
|
+
}
|
|
1016
|
+
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]]]);
|
|
1017
|
+
} else {
|
|
1018
|
+
seats.push([0, m.d / 2 + 0.2, [-f[0], -f[1]]]);
|
|
1019
|
+
}
|
|
1020
|
+
seats.forEach((lg, i) => {
|
|
1021
|
+
const cu = r3(m.x + pp[0] * lg[0] + f[0] * lg[1]);
|
|
1022
|
+
const cv = r3(m.z + pp[1] * lg[0] + f[1] * lg[1]);
|
|
1023
|
+
const half = mode === "dining" ? chairSide / 2 : 0.3;
|
|
1024
|
+
if (!free(m, cu, cv, half)) return;
|
|
1025
|
+
const id = m.id + "#chair" + (i + 1);
|
|
1026
|
+
const item = { x: K.x(cu), z: K.z(cv), ry: K.ry(lg[2][0], lg[2][1]), seed: seedOf(id), palette };
|
|
1027
|
+
if (mode !== "dining") {
|
|
1028
|
+
item.w = 0.6;
|
|
1029
|
+
item.d = 0.6;
|
|
1030
|
+
item.h = 0.95;
|
|
1031
|
+
}
|
|
1032
|
+
const e = push(entry(id, mode === "dining" ? "dining_chair" : "armchair", item, m.id, m.floor));
|
|
1033
|
+
result.chairs.push(e.id);
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
function conduit(id, pts, floor) {
|
|
1038
|
+
const x0 = K.x(pts[0][0]);
|
|
1039
|
+
const z0 = K.z(pts[0][1]);
|
|
1040
|
+
const item = {
|
|
1041
|
+
x: x0,
|
|
1042
|
+
z: z0,
|
|
1043
|
+
ry: 0,
|
|
1044
|
+
seed: seedOf(id),
|
|
1045
|
+
// 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
|
|
1046
|
+
points: pts.map((p) => [r3(K.x(p[0]) - x0), p[2], r3(K.z(p[1]) - z0)])
|
|
1047
|
+
};
|
|
1048
|
+
const e = entry(id, "conduit_run", item, id, floor);
|
|
1049
|
+
e.floorY = o.base;
|
|
1050
|
+
push(e);
|
|
1051
|
+
result.conduits.push(e.id);
|
|
1052
|
+
}
|
|
1053
|
+
if (electrical) {
|
|
1054
|
+
for (const l of electrical.outdoorLamps || []) {
|
|
1055
|
+
if (!onFloor(-1, true)) continue;
|
|
1056
|
+
const e = entry(l.id, "lamp", { x: K.x(l.u), z: K.z(l.v), ry: 0, y: l.y, seed: seedOf(l.id) }, l.id, -1, { watts: 15 });
|
|
1057
|
+
e.connections.circuit = circuitOfLight(l.id);
|
|
1058
|
+
e.lit = initialLight(res, popts, l.id, e);
|
|
1059
|
+
push(e);
|
|
1060
|
+
result.lights.push(e.id);
|
|
1061
|
+
}
|
|
1062
|
+
for (const t of electrical.outlets || []) {
|
|
1063
|
+
if (!onFloor(t.floor, false)) continue;
|
|
1064
|
+
const c = circuits.find((x) => (x.outlets || []).indexOf(t.id) >= 0);
|
|
1065
|
+
const item = { x: K.x(t.u), z: K.z(t.v), ry: K.ry(t.frontU, t.frontV), y: t.y, seed: seedOf(t.id) };
|
|
1066
|
+
if (c) item.circuit = c.id;
|
|
1067
|
+
const e = entry(t.id, "wall_socket", item, t.id, t.floor);
|
|
1068
|
+
e.connections.circuit = c ? c.id : null;
|
|
1069
|
+
push(e);
|
|
1070
|
+
result.outlets.push(e.id);
|
|
1071
|
+
}
|
|
1072
|
+
const lights = new Set(result.lights);
|
|
1073
|
+
for (const s of electrical.switches || []) {
|
|
1074
|
+
if (!onFloor(s.floor, false)) continue;
|
|
1075
|
+
const item = { x: K.x(s.u), z: K.z(s.v), ry: K.ry(s.frontU, s.frontV), y: s.y, seed: seedOf(s.id) };
|
|
1076
|
+
item.controls = (s.controls || []).map((id) => id + ":lamp");
|
|
1077
|
+
const e = entry(s.id, "wall_switch", item, s.id, s.floor);
|
|
1078
|
+
e.connections.controls = (s.controls || []).slice();
|
|
1079
|
+
e.lit = e.connections.controls.some((id) => (result.items.find((x) => x.id === id) || {}).lit === true);
|
|
1080
|
+
if (floorSel == null) {
|
|
1081
|
+
for (const id of s.controls || []) if (!lights.has(id)) result.warnings.push(msg("warn.switchUnknownLamp", { id: s.id, lamp: id }));
|
|
1082
|
+
}
|
|
1083
|
+
push(e);
|
|
1084
|
+
result.switches.push(e.id);
|
|
1085
|
+
}
|
|
1086
|
+
const ee = electrical.serviceEntrance;
|
|
1087
|
+
if (ee && ee.pole && onFloor(-1, true)) {
|
|
1088
|
+
const drop = ee.drop || [];
|
|
1089
|
+
const end = drop.length ? drop[drop.length - 1] : [ee.pole.u, ee.pole.v, 2.6];
|
|
1090
|
+
const px = K.x(ee.pole.u);
|
|
1091
|
+
const pz = K.z(ee.pole.v);
|
|
1092
|
+
const item = {
|
|
1093
|
+
x: px,
|
|
1094
|
+
z: pz,
|
|
1095
|
+
ry: 0,
|
|
1096
|
+
h: ee.pole.h,
|
|
1097
|
+
seed: seedOf("service_entrance"),
|
|
1098
|
+
// point where the drop reaches the house, in local coordinates of the pole (absolute y)
|
|
1099
|
+
house: [r3(K.x(end[0]) - px), end[2], r3(K.z(end[1]) - pz)]
|
|
1100
|
+
};
|
|
1101
|
+
if (ee.tap || electrical.mode === "tap") item.variant = "gato";
|
|
1102
|
+
const e = entry("service_entrance", "service_entrance", item, "service_entrance", -1);
|
|
1103
|
+
push(e);
|
|
1104
|
+
result.serviceEntrance = e.id;
|
|
1105
|
+
if (ee.descent && ee.descent.length > 1) conduit("conduit_descent", ee.descent, -1);
|
|
1106
|
+
}
|
|
1107
|
+
const q = electrical.panel;
|
|
1108
|
+
if (q && onFloor(q.floor, false)) {
|
|
1109
|
+
const hdq = 0.06;
|
|
1110
|
+
const ryq = K.ry(q.frontU, q.frontV);
|
|
1111
|
+
const item = {
|
|
1112
|
+
x: r3(K.x(q.u) + Math.sin(ryq) * hdq),
|
|
1113
|
+
z: r3(K.z(q.v) + Math.cos(ryq) * hdq),
|
|
1114
|
+
ry: ryq,
|
|
1115
|
+
y: q.y,
|
|
1116
|
+
seed: seedOf("panel"),
|
|
1117
|
+
circuits: circuits.map((c) => ({ id: c.id, label: c.room }))
|
|
1118
|
+
};
|
|
1119
|
+
if (!item.circuits.length) delete item.circuits;
|
|
1120
|
+
const e = entry("panel", "electrical_panel", item, "panel", q.floor);
|
|
1121
|
+
push(e);
|
|
1122
|
+
result.panel = e.id;
|
|
1123
|
+
}
|
|
1124
|
+
const med = ee && ee.meter;
|
|
1125
|
+
if (med && onFloor(-1, true)) {
|
|
1126
|
+
const hdm = 0.08;
|
|
1127
|
+
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: seedOf("meter") };
|
|
1128
|
+
const e = entry("meter", "power_meter", item, "meter", -1);
|
|
1129
|
+
push(e);
|
|
1130
|
+
result.meter = e.id;
|
|
1131
|
+
}
|
|
1132
|
+
for (const ed of electrical.conduits || []) {
|
|
1133
|
+
if (!ed.exposed || !ed.points || ed.points.length < 2) continue;
|
|
1134
|
+
const circ = circuits.find((c) => c.id === ed.circuit);
|
|
1135
|
+
const floor = circ ? circ.floor : 0;
|
|
1136
|
+
if (!onFloor(floor, false)) continue;
|
|
1137
|
+
conduit(ed.id, ed.points, floor);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
const piped = result.items.filter((e) => e.type === "stove" && e.connections.gas === "piped");
|
|
1141
|
+
if (piped.length) {
|
|
1142
|
+
const med = utilities.gas && utilities.gas.meter;
|
|
1143
|
+
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 };
|
|
1144
|
+
const e = entry("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf("piped_gas") }, "piped_gas", piped[0].floor);
|
|
1145
|
+
e.floorY = o.base;
|
|
1146
|
+
push(e);
|
|
1147
|
+
for (const f of piped) f.connections.fuel = "piped_gas:gas";
|
|
1148
|
+
}
|
|
1149
|
+
for (const b of result.cylinders) {
|
|
1150
|
+
const stove = result.items.find((e) => e.id === b.stove);
|
|
1151
|
+
if (stove) stove.connections.fuel = b.id + ":gas";
|
|
1152
|
+
}
|
|
1153
|
+
const plumbing = utilities.plumbing;
|
|
1154
|
+
if (plumbing) {
|
|
1155
|
+
const isCabinet = (t) => t === "kitchen_cabinet_base" || t === "kitchen_cabinet_wall" || t === "bathroom_cabinet";
|
|
1156
|
+
for (const p of plumbing.points || []) {
|
|
1157
|
+
const target = (byOrigin.get(p.item) || []).filter((e) => !isCabinet(e.type))[0];
|
|
1158
|
+
if (!target) {
|
|
1159
|
+
if (floorSel == null) result.warnings.push(msg("warn.pointNoObject", { id: p.id, kind: p.kind, item: p.item }));
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
target.point = p.id;
|
|
1163
|
+
target.connections.flowLpm = p.flowLpm;
|
|
1164
|
+
for (const f of fixturesOfPoint[p.kind] || []) {
|
|
1165
|
+
result.fixtures.push({ object: target.id, fixture: f, global: target.id + ":" + f, point: p.id, pointKind: p.kind });
|
|
1166
|
+
result.points[target.id + ":" + f] = p.id;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
hideCylinders();
|
|
1171
|
+
return result;
|
|
1172
|
+
}
|
|
1173
|
+
function ownSpec(entry) {
|
|
1174
|
+
if (entry.type === "lamp") {
|
|
1175
|
+
const dev = { id: "lamp", kind: "lamp", watts: entry.watts || 15, on: !!entry.lit };
|
|
1176
|
+
if (entry.connections.circuit) dev.circuit = entry.connections.circuit;
|
|
1177
|
+
return { type: "lamp", devices: [dev] };
|
|
1178
|
+
}
|
|
1179
|
+
if (entry.type === "gas_piped") return { type: "gas_piped", fuels: [{ id: "gas", kind: "gas", capacity: 1e3, level: 1e3 }] };
|
|
1180
|
+
throw new Error(msg("error.unknownOwnType", { type: entry.type }));
|
|
1181
|
+
}
|
|
1182
|
+
function connect(entry, spec) {
|
|
1183
|
+
const L = entry.connections || {};
|
|
1184
|
+
if (entry.type === "wall_switch") {
|
|
1185
|
+
for (const p of spec.parts || []) if (p.id === "rocker") p.t0 = entry.lit ? 1 : 0;
|
|
1186
|
+
}
|
|
1187
|
+
if (entry.type !== "shower") {
|
|
1188
|
+
for (const dv of spec.devices || []) if (L.outlet && dv.socket === "auto") dv.socket = L.outlet + ":socket";
|
|
1189
|
+
} else {
|
|
1190
|
+
const sh = L.shower || {};
|
|
1191
|
+
const heater = (spec.devices || []).find((d) => d.id === "heater");
|
|
1192
|
+
if (heater && sh.electric === false) {
|
|
1193
|
+
spec.devices = spec.devices.filter((d) => d !== heater);
|
|
1194
|
+
for (const f of spec.fixtures || []) if (f.heater === "heater") delete f.heater;
|
|
1195
|
+
} else if (heater) {
|
|
1196
|
+
if (sh.powerW) heater.watts = sh.powerW;
|
|
1197
|
+
if (L.outletCircuit) heater.circuit = L.outletCircuit;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
if ((entry.type === "stove" || entry.type === "camp_stove") && L.fuel) {
|
|
1201
|
+
for (const b of spec.burners || []) if (b.fuel === "auto") b.fuel = L.fuel;
|
|
1202
|
+
}
|
|
1203
|
+
if (entry.type === "fireplace" && L.chimneyTop) {
|
|
1204
|
+
const it = entry.item;
|
|
1205
|
+
const dx = L.chimneyTop[0] - it.x;
|
|
1206
|
+
const dz = L.chimneyTop[2] - it.z;
|
|
1207
|
+
const lx = Math.cos(it.ry) * dx - Math.sin(it.ry) * dz;
|
|
1208
|
+
const lz = Math.sin(it.ry) * dx + Math.cos(it.ry) * dz;
|
|
1209
|
+
for (const em of spec.emitters || []) if (em.kind === "smoke") em.pos = [r3(lx), r3(L.chimneyTop[1] - entry.floorY + 0.02), r3(lz)];
|
|
1210
|
+
}
|
|
1211
|
+
if (entry.type === "washing_machine" && entry.point) {
|
|
1212
|
+
spec.fixtures = spec.fixtures || [];
|
|
1213
|
+
const inlet = spec.fixtures.find((f) => f.id === "inlet");
|
|
1214
|
+
if (inlet) {
|
|
1215
|
+
if (L.flowLpm) inlet.flow = L.flowLpm;
|
|
1216
|
+
inlet.tank = "auto";
|
|
1217
|
+
} else {
|
|
1218
|
+
spec.fixtures.push({ id: "inlet", kind: "hose", outlet: [0, 0.3, -(entry.item.d || 0.6) / 2], flow: L.flowLpm || 8, tank: "auto" });
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return spec;
|
|
1222
|
+
}
|
|
1223
|
+
function createWorld(res, copts = {}) {
|
|
1224
|
+
copts = copts || {};
|
|
1225
|
+
const info = { points: /* @__PURE__ */ new Map(), water: copts.water || null, lightsOn: copts.lightsOn };
|
|
1226
|
+
const electrical = res.utilities && res.utilities.electrical;
|
|
1227
|
+
const world = GI.createWorld({
|
|
1228
|
+
locale,
|
|
1229
|
+
strings: hh.strings,
|
|
1230
|
+
items: hh.items,
|
|
1231
|
+
loot: hh.loot,
|
|
1232
|
+
seed: copts.seed != null ? copts.seed : res.seed,
|
|
1233
|
+
// no grid: the cabin and the off-grid campsite have no service entrance, sockets or electric lamps (lanterns do not need a grid)
|
|
1234
|
+
grid: copts.grid != null ? !!copts.grid : !!electrical && electrical.mode !== "offgrid",
|
|
1235
|
+
onEvent: copts.onEvent,
|
|
1236
|
+
canInteract: copts.canInteract,
|
|
1237
|
+
waterSupply: {
|
|
1238
|
+
draw(fixtureId, l) {
|
|
1239
|
+
if (!info.water) return l;
|
|
1240
|
+
const point = info.points.get(fixtureId);
|
|
1241
|
+
return point == null ? l : info.water.consume(point, l);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
worlds.set(world, info);
|
|
1246
|
+
return world;
|
|
1247
|
+
}
|
|
1248
|
+
function pointOf(world, fixtureId) {
|
|
1249
|
+
const info = worlds.get(world);
|
|
1250
|
+
return info ? info.points.get(fixtureId) : void 0;
|
|
1251
|
+
}
|
|
1252
|
+
function blockedOf(res, bopts = {}) {
|
|
1253
|
+
bopts = bopts || {};
|
|
1254
|
+
const ox = bopts.originX || 0;
|
|
1255
|
+
const oz = bopts.originZ || 0;
|
|
1256
|
+
const inw = bopts.inw || 1;
|
|
1257
|
+
const margin = bopts.margin != null ? bopts.margin : 0.02;
|
|
1258
|
+
const segs = (res.walls || []).map((p) => {
|
|
1259
|
+
const e = Math.max(0, p.thickness / 2 - margin);
|
|
1260
|
+
const u0 = Math.min(p.u0, p.u1) - (p.axis === "u" ? 0 : e);
|
|
1261
|
+
const u1 = Math.max(p.u0, p.u1) + (p.axis === "u" ? 0 : e);
|
|
1262
|
+
const v0 = Math.min(p.v0, p.v1) - (p.axis === "v" ? 0 : e);
|
|
1263
|
+
const v1 = Math.max(p.v0, p.v1) + (p.axis === "v" ? 0 : e);
|
|
1264
|
+
const za = oz + inw * v0;
|
|
1265
|
+
const zb = oz + inw * v1;
|
|
1266
|
+
return { floor: p.floor, x0: ox + u0, x1: ox + u1, z0: Math.min(za, zb), z1: Math.max(za, zb) };
|
|
1267
|
+
});
|
|
1268
|
+
const CELL = 0.5;
|
|
1269
|
+
const grid = /* @__PURE__ */ new Map();
|
|
1270
|
+
const key = (a, i, j) => (a * 4096 + (i + 2048)) * 4096 + (j + 2048);
|
|
1271
|
+
for (const s of segs) {
|
|
1272
|
+
for (let i = Math.floor(s.x0 / CELL); i <= Math.floor(s.x1 / CELL); i++) {
|
|
1273
|
+
for (let j = Math.floor(s.z0 / CELL); j <= Math.floor(s.z1 / CELL); j++) {
|
|
1274
|
+
const k = key(s.floor, i, j);
|
|
1275
|
+
if (!grid.has(k)) grid.set(k, []);
|
|
1276
|
+
grid.get(k).push(s);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
return function blocked(x, z, floor) {
|
|
1281
|
+
const a = floor == null || floor < 0 ? 0 : floor;
|
|
1282
|
+
const list = grid.get(key(a, Math.floor(x / CELL), Math.floor(z / CELL)));
|
|
1283
|
+
if (!list) return false;
|
|
1284
|
+
for (const s of list) if (x > s.x0 && x < s.x1 && z > s.z0 && z < s.z1) return true;
|
|
1285
|
+
return false;
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
function add(world, planned, aopts = {}) {
|
|
1289
|
+
aopts = aopts || {};
|
|
1290
|
+
const info = worlds.get(world);
|
|
1291
|
+
const build = aopts.build || ((type, item) => hh.build(type, item, HH.createRecorder().api));
|
|
1292
|
+
const isBlocked = aopts.isBlocked || null;
|
|
1293
|
+
const out = { added: 0, parts: [], hinges: {}, moved: {}, warnings: [] };
|
|
1294
|
+
const override = aopts.lightsOn !== void 0 ? aopts.lightsOn : info && info.lightsOn;
|
|
1295
|
+
if (override !== void 0) {
|
|
1296
|
+
for (const e of planned.items) if (e.type === "lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
1297
|
+
for (const e of planned.items) if (e.type === "lantern_lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
1298
|
+
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);
|
|
1299
|
+
}
|
|
1300
|
+
for (const e of planned.items) if (e.type === "lantern_lamp") e.item.on = !!e.lit;
|
|
1301
|
+
let scratch = null;
|
|
1302
|
+
function probe(e, hinge, setback) {
|
|
1303
|
+
if (!scratch) scratch = GI.createWorld({ locale, strings: hh.strings, items: hh.items, loot: hh.loot, grid: false });
|
|
1304
|
+
const it = e.item;
|
|
1305
|
+
const x = it.x + Math.sin(it.ry) * setback;
|
|
1306
|
+
const z = it.z + Math.cos(it.ry) * setback;
|
|
1307
|
+
const spec = hh.build(e.type, Object.assign({}, it, { hinge }), HH.createRecorder().api);
|
|
1308
|
+
scratch.add("__probe", spec, { x, y: e.floorY, z, ry: it.ry });
|
|
1309
|
+
const blocks = (px, pz) => isBlocked(px, pz, e.floor);
|
|
1310
|
+
let sum = 0;
|
|
1311
|
+
let min = 1;
|
|
1312
|
+
let n = 0;
|
|
1313
|
+
for (const p of spec.parts || []) {
|
|
1314
|
+
if (p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
1315
|
+
const t = scratch.fitSweep("__probe", p.id, blocks);
|
|
1316
|
+
sum += t;
|
|
1317
|
+
min = Math.min(min, t);
|
|
1318
|
+
n++;
|
|
1319
|
+
}
|
|
1320
|
+
scratch.remove("__probe");
|
|
1321
|
+
return { sum, min, n };
|
|
1322
|
+
}
|
|
1323
|
+
const better = (a, b) => a.sum > b.sum + 1e-9 || Math.abs(a.sum - b.sum) <= 1e-9 && a.min > b.min + 1e-9;
|
|
1324
|
+
function fitDoors(e) {
|
|
1325
|
+
if (!isBlocked || !householdTypes.has(e.type)) return;
|
|
1326
|
+
const standard = probe(e, void 0, 0);
|
|
1327
|
+
if (!standard.n || standard.min >= 1) return;
|
|
1328
|
+
let bestSide;
|
|
1329
|
+
let m = standard;
|
|
1330
|
+
for (const side of ["left", "right"]) {
|
|
1331
|
+
const r = probe(e, side, 0);
|
|
1332
|
+
if (better(r, m)) {
|
|
1333
|
+
m = r;
|
|
1334
|
+
bestSide = side;
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
if (bestSide) {
|
|
1338
|
+
e.item.hinge = bestSide;
|
|
1339
|
+
out.hinges[e.id] = bestSide;
|
|
1340
|
+
}
|
|
1341
|
+
if (m.min >= 1) return;
|
|
1342
|
+
let target = { setback: 0, r: m };
|
|
1343
|
+
for (const setback of [0.01, 0.02, 0.03, 0.04]) {
|
|
1344
|
+
const r = probe(e, bestSide, setback);
|
|
1345
|
+
if (better(r, target.r)) target = { setback, r };
|
|
1346
|
+
if (r.min >= 1) break;
|
|
1347
|
+
}
|
|
1348
|
+
if (target.setback > 0 && target.r.sum > m.sum + 0.2) {
|
|
1349
|
+
e.item.x = r3(e.item.x + Math.sin(e.item.ry) * target.setback);
|
|
1350
|
+
e.item.z = r3(e.item.z + Math.cos(e.item.ry) * target.setback);
|
|
1351
|
+
e.moved = target.setback;
|
|
1352
|
+
out.moved[e.id] = target.setback;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
for (const e of planned.items) {
|
|
1356
|
+
if (e.type !== "shower" || !e.connections.outlet) continue;
|
|
1357
|
+
const t = planned.items.find((x) => x.id === e.connections.outlet);
|
|
1358
|
+
if (t && t.connections.circuit) e.connections.outletCircuit = t.connections.circuit;
|
|
1359
|
+
}
|
|
1360
|
+
for (const e of planned.items) {
|
|
1361
|
+
let spec;
|
|
1362
|
+
if (ownTypes[e.type]) {
|
|
1363
|
+
spec = ownSpec(e);
|
|
1364
|
+
} else {
|
|
1365
|
+
fitDoors(e);
|
|
1366
|
+
spec = build(e.type, e.item);
|
|
1367
|
+
if (!spec) {
|
|
1368
|
+
out.warnings.push(msg("warn.buildEmpty", { id: e.id }));
|
|
1369
|
+
continue;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
connect(e, spec);
|
|
1373
|
+
world.add(e.id, spec, { x: e.item.x, y: e.floorY, z: e.item.z, ry: e.item.ry });
|
|
1374
|
+
out.added++;
|
|
1375
|
+
if (!isBlocked) continue;
|
|
1376
|
+
for (const p of spec.parts || []) {
|
|
1377
|
+
if (!(p.bounds || p.sweep)) continue;
|
|
1378
|
+
const t = world.fitSweep(e.id, p.id, (x, z) => isBlocked(x, z, e.floor));
|
|
1379
|
+
if (t < 1) out.parts.push({ object: e.id, part: p.id, t });
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
if (info) for (const f of planned.fixtures) info.points.set(f.global, f.point);
|
|
1383
|
+
return out;
|
|
1384
|
+
}
|
|
1385
|
+
return { version: ADAPTER_VERSION, household: hh, plan, createWorld, add, blockedOf, pointOf, ownSpec, registries: { typeMap, contentMap, contentByGroup, chairTables, fixturesOfPoint, substitutes, preference, ownTypes } };
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// src/index.ts
|
|
1389
|
+
var FloorplanInteractables = { version: ADAPTER_VERSION, create, TYPE_MAP, CONTENT_MAP, CONTENT_BY_GROUP, CHAIR_TABLES, PREFERENCE, mergeRegistry };
|
|
1390
|
+
return __toCommonJS(index_exports);
|
|
1391
|
+
})();
|
|
1392
|
+
//# sourceMappingURL=index.global.js.map
|