@adatechnology/game-vehicles-three 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,7 @@ var GameVehiclesThree = (() => {
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
24
  DEFAULT_TEST_VEHICLES: () => DEFAULT_TEST_VEHICLES,
25
+ DEFAULT_TEST_WRECKS: () => DEFAULT_TEST_WRECKS,
25
26
  LITE_CLASSES: () => LITE_CLASSES,
26
27
  PAGE_ITEM_ALIASES: () => PAGE_ITEM_ALIASES,
27
28
  PAGE_SCENARIO_ALIASES: () => PAGE_SCENARIO_ALIASES,
@@ -40,6 +41,84 @@ var GameVehiclesThree = (() => {
40
41
  loadVehiclesTestModule: () => loadVehiclesTestModule
41
42
  });
42
43
 
44
+ // ../game-contracts/dist/index.js
45
+ var DEFAULT_IGNITION_RULES = {
46
+ fillCurve: [
47
+ [0, 0.6],
48
+ [0.1, 1],
49
+ [0.35, 0.6],
50
+ [0.65, 0.3],
51
+ [0.9, 0.15],
52
+ [1, 0.12]
53
+ ],
54
+ flameFillInfluence: 0.5,
55
+ flameDefaults: { incendiary: 0.7, tracer: 0.2 },
56
+ sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },
57
+ sparkMetalDefault: 0.5,
58
+ sparkFluid: { diesel: 0.15 },
59
+ fireNear: { radius: 1.5, chancePerSecond: 0.5 }
60
+ };
61
+ var resolveIgnitionRules = (rules) => ({
62
+ ...DEFAULT_IGNITION_RULES,
63
+ ...rules,
64
+ flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },
65
+ sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },
66
+ sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },
67
+ fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear }
68
+ });
69
+ var fillFactor = (fill2, curve = DEFAULT_IGNITION_RULES.fillCurve) => {
70
+ if (curve.length === 0) return 1;
71
+ const f = Math.min(1, Math.max(0, fill2));
72
+ if (f <= curve[0][0]) return curve[0][1];
73
+ for (let i = 1; i < curve.length; i++) {
74
+ const [x1, y1] = curve[i];
75
+ const [x0, y0] = curve[i - 1];
76
+ if (f <= x1) return x1 === x0 ? y1 : y0 + (y1 - y0) * (f - x0) / (x1 - x0);
77
+ }
78
+ return curve[curve.length - 1][1];
79
+ };
80
+ var sparkTargetFactor = (materialId, metal, rules = DEFAULT_IGNITION_RULES) => !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault;
81
+ var ignitionChance = (hit, target, rules = DEFAULT_IGNITION_RULES) => {
82
+ const k = fillFactor(target.fill, rules.fillCurve);
83
+ const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === void 0 ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k;
84
+ const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0);
85
+ const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
86
+ return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
87
+ };
88
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
89
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
90
+ var deepMerge = (base, patch) => {
91
+ if (!patch) return base;
92
+ const result = { ...base };
93
+ for (const [key, value] of Object.entries(patch)) {
94
+ if (value === void 0 || UNSAFE_KEYS.has(key)) continue;
95
+ const current = result[key];
96
+ result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value;
97
+ }
98
+ return result;
99
+ };
100
+ var mergeById = (shipped, extra) => {
101
+ const entries = /* @__PURE__ */ new Map();
102
+ for (const entry of [...shipped, ...extra ?? []]) entries.set(entry.id, entry);
103
+ return entries;
104
+ };
105
+ var applyPatches = (entries, patches) => {
106
+ for (const [id, patch] of Object.entries(patches ?? {})) {
107
+ const entry = entries.get(id);
108
+ if (entry) entries.set(id, deepMerge(entry, patch));
109
+ }
110
+ };
111
+ var removeIds = (entries, ids) => {
112
+ for (const id of ids ?? []) entries.delete(id);
113
+ };
114
+ var KIT_ORIGIN_KEY = "kitOrigin";
115
+ function markKitOrigin(object2, origin) {
116
+ const node = object2;
117
+ node.userData = node.userData ?? {};
118
+ node.userData[KIT_ORIGIN_KEY] = { ...origin };
119
+ return object2;
120
+ }
121
+
43
122
  // ../game-vehicles-fleet/dist/index.js
44
123
  var military = [
45
124
  "light_4x4",
@@ -27825,6 +27904,7 @@ var GameVehiclesThree = (() => {
27825
27904
  const pivotMatrix = new THREE.Matrix4().makeTranslation(-cx, -bounds.min.y, -cz).multiply(rotation);
27826
27905
  const group = new THREE.Group();
27827
27906
  group.name = `vehicle:${key}`;
27907
+ markKitOrigin(group, { owner: "game-vehicles-three", kind: "vehicle", id: key });
27828
27908
  const damageables = kit.damageables(c, pivotMatrix);
27829
27909
  let pruned = 0;
27830
27910
  if (quality === "high") {
@@ -29412,77 +29492,6 @@ var GameVehiclesThree = (() => {
29412
29492
  return result;
29413
29493
  }
29414
29494
 
29415
- // ../game-contracts/dist/index.js
29416
- var DEFAULT_IGNITION_RULES = {
29417
- fillCurve: [
29418
- [0, 0.6],
29419
- [0.1, 1],
29420
- [0.35, 0.6],
29421
- [0.65, 0.3],
29422
- [0.9, 0.15],
29423
- [1, 0.12]
29424
- ],
29425
- flameFillInfluence: 0.5,
29426
- flameDefaults: { incendiary: 0.7, tracer: 0.2 },
29427
- sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },
29428
- sparkMetalDefault: 0.5,
29429
- sparkFluid: { diesel: 0.15 },
29430
- fireNear: { radius: 1.5, chancePerSecond: 0.5 }
29431
- };
29432
- var resolveIgnitionRules = (rules) => ({
29433
- ...DEFAULT_IGNITION_RULES,
29434
- ...rules,
29435
- flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },
29436
- sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },
29437
- sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },
29438
- fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear }
29439
- });
29440
- var fillFactor = (fill2, curve = DEFAULT_IGNITION_RULES.fillCurve) => {
29441
- if (curve.length === 0) return 1;
29442
- const f = Math.min(1, Math.max(0, fill2));
29443
- if (f <= curve[0][0]) return curve[0][1];
29444
- for (let i = 1; i < curve.length; i++) {
29445
- const [x1, y1] = curve[i];
29446
- const [x0, y0] = curve[i - 1];
29447
- if (f <= x1) return x1 === x0 ? y1 : y0 + (y1 - y0) * (f - x0) / (x1 - x0);
29448
- }
29449
- return curve[curve.length - 1][1];
29450
- };
29451
- var sparkTargetFactor = (materialId, metal, rules = DEFAULT_IGNITION_RULES) => !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault;
29452
- var ignitionChance = (hit, target, rules = DEFAULT_IGNITION_RULES) => {
29453
- const k = fillFactor(target.fill, rules.fillCurve);
29454
- const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === void 0 ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k;
29455
- const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0);
29456
- const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
29457
- return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
29458
- };
29459
- var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
29460
- var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
29461
- var deepMerge = (base, patch) => {
29462
- if (!patch) return base;
29463
- const result = { ...base };
29464
- for (const [key, value] of Object.entries(patch)) {
29465
- if (value === void 0 || UNSAFE_KEYS.has(key)) continue;
29466
- const current = result[key];
29467
- result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value;
29468
- }
29469
- return result;
29470
- };
29471
- var mergeById = (shipped, extra) => {
29472
- const entries = /* @__PURE__ */ new Map();
29473
- for (const entry of [...shipped, ...extra ?? []]) entries.set(entry.id, entry);
29474
- return entries;
29475
- };
29476
- var applyPatches = (entries, patches) => {
29477
- for (const [id, patch] of Object.entries(patches ?? {})) {
29478
- const entry = entries.get(id);
29479
- if (entry) entries.set(id, deepMerge(entry, patch));
29480
- }
29481
- };
29482
- var removeIds = (entries, ids) => {
29483
- for (const id of ids ?? []) entries.delete(id);
29484
- };
29485
-
29486
29495
  // ../game-vehicles/dist/index.js
29487
29496
  var __defProp2 = Object.defineProperty;
29488
29497
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -30404,46 +30413,79 @@ var GameVehiclesThree = (() => {
30404
30413
  }
30405
30414
  const p = geo.attributes.position;
30406
30415
  const n = p.count;
30407
- const FN = [];
30408
- const map = {};
30409
- const A = new V3();
30410
- const B = new V3();
30411
- const C = new V3();
30412
- const e1 = new V3();
30413
- const e2 = new V3();
30416
+ const faces = n / 3;
30417
+ const FN = new Float64Array(faces * 3);
30418
+ const map = /* @__PURE__ */ new Map();
30419
+ const RANGE = 65536;
30414
30420
  function key(i) {
30415
- return Math.round(p.getX(i) * 2e3) + "," + Math.round(p.getY(i) * 2e3) + "," + Math.round(p.getZ(i) * 2e3);
30421
+ const x = Math.round(p.getX(i) * 2e3);
30422
+ const y = Math.round(p.getY(i) * 2e3);
30423
+ const z = Math.round(p.getZ(i) * 2e3);
30424
+ if (Math.abs(x) < RANGE && Math.abs(y) < RANGE && Math.abs(z) < RANGE) return ((x + RANGE) * 131072 + (y + RANGE)) * 131072 + (z + RANGE);
30425
+ return x + "," + y + "," + z;
30416
30426
  }
30417
30427
  const keys = new Array(n);
30418
- for (let f = 0; f < n / 3; f++) {
30419
- A.fromBufferAttribute(p, 3 * f);
30420
- B.fromBufferAttribute(p, 3 * f + 1);
30421
- C.fromBufferAttribute(p, 3 * f + 2);
30422
- const nn = new V3().crossVectors(e1.subVectors(C, B), e2.subVectors(A, B));
30423
- if (nn.lengthSq() > 1e-20) nn.normalize();
30424
- FN.push(nn);
30428
+ for (let f = 0; f < faces; f++) {
30429
+ const ax = p.getX(3 * f);
30430
+ const ay = p.getY(3 * f);
30431
+ const az = p.getZ(3 * f);
30432
+ const bx = p.getX(3 * f + 1);
30433
+ const by = p.getY(3 * f + 1);
30434
+ const bz = p.getZ(3 * f + 1);
30435
+ const cx = p.getX(3 * f + 2);
30436
+ const cy = p.getY(3 * f + 2);
30437
+ const cz = p.getZ(3 * f + 2);
30438
+ const e1x = cx - bx;
30439
+ const e1y = cy - by;
30440
+ const e1z = cz - bz;
30441
+ const e2x = ax - bx;
30442
+ const e2y = ay - by;
30443
+ const e2z = az - bz;
30444
+ let nx = e1y * e2z - e1z * e2y;
30445
+ let ny = e1z * e2x - e1x * e2z;
30446
+ let nz = e1x * e2y - e1y * e2x;
30447
+ if (nx * nx + ny * ny + nz * nz > 1e-20) {
30448
+ const inv = 1 / (Math.sqrt(nx * nx + ny * ny + nz * nz) || 1);
30449
+ nx *= inv;
30450
+ ny *= inv;
30451
+ nz *= inv;
30452
+ }
30453
+ FN[3 * f] = nx;
30454
+ FN[3 * f + 1] = ny;
30455
+ FN[3 * f + 2] = nz;
30425
30456
  for (let k = 0; k < 3; k++) {
30426
30457
  const kk = key(3 * f + k);
30427
30458
  keys[3 * f + k] = kk;
30428
- (map[kk] || (map[kk] = [])).push(f);
30459
+ const list2 = map.get(kk);
30460
+ if (list2) list2.push(f);
30461
+ else map.set(kk, [f]);
30429
30462
  }
30430
30463
  }
30431
30464
  const cs = Math.cos(deg * PI / 180);
30432
30465
  const out = new Float32Array(n * 3);
30433
- const s = new V3();
30434
30466
  for (let i = 0; i < n; i++) {
30435
- const fi = i / 3 | 0;
30436
- const list2 = map[keys[i]];
30437
- s.set(0, 0, 0);
30467
+ const fi = (i / 3 | 0) * 3;
30468
+ const list2 = map.get(keys[i]);
30469
+ let sx = 0;
30470
+ let sy = 0;
30471
+ let sz = 0;
30438
30472
  for (let j = 0; j < list2.length; j++) {
30439
- const g = FN[list2[j]];
30440
- if (g.dot(FN[fi]) >= cs) s.add(g);
30473
+ const g = list2[j] * 3;
30474
+ if (FN[g] * FN[fi] + FN[g + 1] * FN[fi + 1] + FN[g + 2] * FN[fi + 2] >= cs) {
30475
+ sx += FN[g];
30476
+ sy += FN[g + 1];
30477
+ sz += FN[g + 2];
30478
+ }
30441
30479
  }
30442
- if (s.lengthSq() < 1e-20) s.copy(FN[fi]);
30443
- s.normalize();
30444
- out[3 * i] = s.x;
30445
- out[3 * i + 1] = s.y;
30446
- out[3 * i + 2] = s.z;
30480
+ if (sx * sx + sy * sy + sz * sz < 1e-20) {
30481
+ sx = FN[fi];
30482
+ sy = FN[fi + 1];
30483
+ sz = FN[fi + 2];
30484
+ }
30485
+ const inv = 1 / (Math.sqrt(sx * sx + sy * sy + sz * sz) || 1);
30486
+ out[3 * i] = sx * inv;
30487
+ out[3 * i + 1] = sy * inv;
30488
+ out[3 * i + 2] = sz * inv;
30447
30489
  }
30448
30490
  geo.setAttribute("normal", new THREE.BufferAttribute(out, 3));
30449
30491
  geo.userData.crease = true;
@@ -30845,6 +30887,7 @@ var GameVehiclesThree = (() => {
30845
30887
  this.effects = new THREE.Group();
30846
30888
  this.root.add(this.vehicle);
30847
30889
  this.root.add(this.effects);
30890
+ markKitOrigin(this.root, { owner: "game-vehicles", kind: "vehicle" });
30848
30891
  this.state = state;
30849
30892
  this.glass = [];
30850
30893
  this.quads = [];
@@ -36061,6 +36104,153 @@ var GameVehiclesThree = (() => {
36061
36104
  return hole;
36062
36105
  }
36063
36106
  const _zr = new THREE.Raycaster();
36107
+ const PROXY_MIN_TRIANGLES = 500;
36108
+ const STROKE_REACH = 0.6;
36109
+ const _pv = new V3();
36110
+ const _pm = new THREE.Matrix4();
36111
+ function decalRegion(c, z) {
36112
+ const B = z.box;
36113
+ const lo = [0, 1, 2].map(function(k) {
36114
+ return I.boxLo(B, k) - STROKE_REACH;
36115
+ });
36116
+ const hi = [0, 1, 2].map(function(k) {
36117
+ return I.boxHi(B, k) + STROKE_REACH;
36118
+ });
36119
+ const a = axisOf(z.dir);
36120
+ const dn = z.dir.clone().normalize();
36121
+ const sg = z.dir.getComponent(a) > 0 ? 1 : -1;
36122
+ const outer = sg > 0 ? I.boxLo(B, a) - 0.6 : I.boxHi(B, a) + 0.6;
36123
+ const far = 0.6 + (I.boxHi(B, a) - I.boxLo(B, a)) + 0.05;
36124
+ for (let i = 0; i < 8; i++) {
36125
+ const p = new V3();
36126
+ p.setComponent(a, outer);
36127
+ [0, 1, 2].filter(function(k) {
36128
+ return k !== a;
36129
+ }).forEach(function(k, j) {
36130
+ p.setComponent(k, i >> j & 1 ? I.boxHi(B, k) : I.boxLo(B, k));
36131
+ });
36132
+ for (let e = 0; e < 2; e++) {
36133
+ const q = e ? p.clone().addScaledVector(dn, far) : p;
36134
+ for (let k = 0; k < 3; k++) {
36135
+ lo[k] = Math.min(lo[k], q.getComponent(k) - 0.05);
36136
+ hi[k] = Math.max(hi[k], q.getComponent(k) + 0.05);
36137
+ }
36138
+ }
36139
+ }
36140
+ return { lo, hi };
36141
+ }
36142
+ function regionCands(c, z, cands) {
36143
+ if (!cands.some(heavy)) return cands;
36144
+ const R = decalRegion(c, z);
36145
+ const Mw = c.vehicle.matrixWorld;
36146
+ return cands.map(function(o) {
36147
+ if (!heavy(o)) return o;
36148
+ if (!o.geometry.boundingSphere) o.geometry.computeBoundingSphere();
36149
+ if (!o.geometry.boundingBox) o.geometry.computeBoundingBox();
36150
+ return proxyIn(o, Mw, R);
36151
+ });
36152
+ }
36153
+ function heavy(o) {
36154
+ const g = o.geometry;
36155
+ const pos = g && g.attributes && g.attributes.position;
36156
+ return o.raycast === THREE.Mesh.prototype.raycast && !o.isSkinnedMesh && !Array.isArray(o.material) && pos && !pos.isInterleavedBufferAttribute && pos.itemSize === 3 && !g.groups.length && !(g.morphAttributes && g.morphAttributes.position) && (g.index ? g.index.count : pos.count) / 3 >= PROXY_MIN_TRIANGLES;
36157
+ }
36158
+ function proxyIn(o, Mw, R) {
36159
+ _pm.copy(o.matrixWorld).invert().multiply(Mw);
36160
+ const lo = [Infinity, Infinity, Infinity];
36161
+ const hi = [-Infinity, -Infinity, -Infinity];
36162
+ for (let i = 0; i < 8; i++) {
36163
+ _pv.set(i & 1 ? R.hi[0] : R.lo[0], i & 2 ? R.hi[1] : R.lo[1], i & 4 ? R.hi[2] : R.lo[2]).applyMatrix4(_pm);
36164
+ for (let k = 0; k < 3; k++) {
36165
+ lo[k] = Math.min(lo[k], _pv.getComponent(k));
36166
+ hi[k] = Math.max(hi[k], _pv.getComponent(k));
36167
+ }
36168
+ }
36169
+ const g = o.geometry;
36170
+ const P = g.attributes.position.array;
36171
+ const ix = g.index ? g.index.array : null;
36172
+ const n = ix ? ix.length : P.length / 3;
36173
+ const keep = new Uint32Array(n - n % 3);
36174
+ let nk = 0;
36175
+ for (let t = 0; t + 2 < n; t += 3) {
36176
+ const a = (ix ? ix[t] : t) * 3;
36177
+ const b = (ix ? ix[t + 1] : t + 1) * 3;
36178
+ const d = (ix ? ix[t + 2] : t + 2) * 3;
36179
+ let out = false;
36180
+ for (let k = 0; k < 3 && !out; k++) {
36181
+ const u = P[a + k];
36182
+ const v = P[b + k];
36183
+ const w = P[d + k];
36184
+ out = Math.max(u, v, w) < lo[k] || Math.min(u, v, w) > hi[k];
36185
+ }
36186
+ if (!out) {
36187
+ keep[nk++] = ix ? ix[t] : t;
36188
+ keep[nk++] = ix ? ix[t + 1] : t + 1;
36189
+ keep[nk++] = ix ? ix[t + 2] : t + 2;
36190
+ }
36191
+ }
36192
+ if (!nk) return null;
36193
+ const kept = keep.slice(0, nk);
36194
+ const box2 = new Float32Array(kept.length / 3 * 6);
36195
+ for (let t = 0, j = 0; t < kept.length; t += 3, j += 6) {
36196
+ const a = kept[t] * 3;
36197
+ const b = kept[t + 1] * 3;
36198
+ const d = kept[t + 2] * 3;
36199
+ for (let k = 0; k < 3; k++) {
36200
+ box2[j + k] = Math.min(P[a + k], P[b + k], P[d + k]);
36201
+ box2[j + 3 + k] = Math.max(P[a + k], P[b + k], P[d + k]);
36202
+ }
36203
+ }
36204
+ const pg = new THREE.BufferGeometry();
36205
+ pg.setAttribute("position", g.attributes.position);
36206
+ pg.setIndex(new THREE.BufferAttribute(new Uint32Array(kept.length), 1));
36207
+ pg.boundingSphere = g.boundingSphere;
36208
+ pg.boundingBox = g.boundingBox;
36209
+ const proxy = new THREE.Mesh(pg, o.material);
36210
+ proxy.layers.mask = o.layers.mask;
36211
+ proxy.proxyOf = o;
36212
+ proxy.kept = kept;
36213
+ proxy.keptBox = box2;
36214
+ return proxy;
36215
+ }
36216
+ function narrowTo(rc, proxy) {
36217
+ const o = proxy.proxyOf;
36218
+ const ray = rc.ray;
36219
+ _pm.copy(o.matrixWorld).invert();
36220
+ _pv.copy(ray.origin).applyMatrix4(_pm);
36221
+ const x0 = _pv.x;
36222
+ const y0 = _pv.y;
36223
+ const z0 = _pv.z;
36224
+ _pv.copy(ray.direction).multiplyScalar(rc.far).add(ray.origin).applyMatrix4(_pm);
36225
+ const lo0 = Math.min(x0, _pv.x) - 1e-4;
36226
+ const lo1 = Math.min(y0, _pv.y) - 1e-4;
36227
+ const lo2 = Math.min(z0, _pv.z) - 1e-4;
36228
+ const hi0 = Math.max(x0, _pv.x) + 1e-4;
36229
+ const hi1 = Math.max(y0, _pv.y) + 1e-4;
36230
+ const hi2 = Math.max(z0, _pv.z) + 1e-4;
36231
+ const K = proxy.kept;
36232
+ const X = proxy.keptBox;
36233
+ const dst = proxy.geometry.index.array;
36234
+ let m = 0;
36235
+ for (let t = 0, j = 0; t < K.length; t += 3, j += 6) {
36236
+ if (X[j + 3] < lo0 || X[j] > hi0 || X[j + 4] < lo1 || X[j + 1] > hi1 || X[j + 5] < lo2 || X[j + 2] > hi2) continue;
36237
+ dst[m++] = K[t];
36238
+ dst[m++] = K[t + 1];
36239
+ dst[m++] = K[t + 2];
36240
+ }
36241
+ proxy.geometry.setDrawRange(0, m);
36242
+ }
36243
+ function castAt(rc, cands) {
36244
+ for (let i = 0; i < cands.length; i++) {
36245
+ const q = cands[i];
36246
+ if (!q.proxyOf) continue;
36247
+ q.matrixWorld.copy(q.proxyOf.matrixWorld);
36248
+ narrowTo(rc, q);
36249
+ }
36250
+ const hits = rc.intersectObjects(cands, false);
36251
+ for (let i = 0; i < hits.length; i++) if (hits[i].object.proxyOf) hits[i].object = hits[i].object.proxyOf;
36252
+ return hits;
36253
+ }
36064
36254
  function zoneCands(c, z, inv, glassToo) {
36065
36255
  const out = [];
36066
36256
  c.vehicle.traverse(function(o) {
@@ -36113,7 +36303,7 @@ var GameVehiclesThree = (() => {
36113
36303
  });
36114
36304
  _zr.set(org.clone().applyMatrix4(Mw), d.clone().transformDirection(Mw));
36115
36305
  _zr.far = 0.6 + (I.boxHi(B, a) - I.boxLo(B, a)) + 0.05;
36116
- const hits = _zr.intersectObjects(cands, false);
36306
+ const hits = castAt(_zr, cands);
36117
36307
  for (let i = 0; i < hits.length; i++) {
36118
36308
  const h = hits[i];
36119
36309
  if (!h.face) continue;
@@ -36141,7 +36331,7 @@ var GameVehiclesThree = (() => {
36141
36331
  const q = s.p.clone().addScaledVector(t, len * 0.5 * k / M);
36142
36332
  _rt.set(q.clone().addScaledVector(n, 0.08).applyMatrix4(Mw), n.clone().negate().transformDirection(Mw));
36143
36333
  _rt.far = 0.2;
36144
- const h = _rt.intersectObjects(cands, false).find(function(x) {
36334
+ const h = castAt(_rt, cands).find(function(x) {
36145
36335
  return x.face;
36146
36336
  });
36147
36337
  if (!h) return null;
@@ -36212,6 +36402,7 @@ var GameVehiclesThree = (() => {
36212
36402
  const R = c.rand;
36213
36403
  const need = (spec.fine || 0) + (spec.deep || 0) + (spec.chip || 0) + (spec.rust || 0) + (spec.tear || 0) + (spec.ding || 0) + (spec.soot || 0) + (spec.crater || 0);
36214
36404
  if (!need) return [];
36405
+ cands = regionCands(c, z, cands).filter(Boolean);
36215
36406
  const S = zoneSurf(c, z, need + 2, R, cands);
36216
36407
  let k = 0;
36217
36408
  const ang0 = R() * PI;
@@ -36290,8 +36481,25 @@ var GameVehiclesThree = (() => {
36290
36481
  }
36291
36482
  function subdivIn(geo, rel, B, maxLen) {
36292
36483
  const a = geo.attributes.position.array;
36293
- const out = [];
36294
- const v = new V3();
36484
+ let out = new Float32Array(a.length + 4096);
36485
+ let used = 0;
36486
+ const push = function(a0, a1, a2, b0, b1, b2, c0, c1, c2) {
36487
+ if (used + 9 > out.length) {
36488
+ const bigger = new Float32Array(out.length * 2);
36489
+ bigger.set(out);
36490
+ out = bigger;
36491
+ }
36492
+ out[used] = a0;
36493
+ out[used + 1] = a1;
36494
+ out[used + 2] = a2;
36495
+ out[used + 3] = b0;
36496
+ out[used + 4] = b1;
36497
+ out[used + 5] = b2;
36498
+ out[used + 6] = c0;
36499
+ out[used + 7] = c1;
36500
+ out[used + 8] = c2;
36501
+ used += 9;
36502
+ };
36295
36503
  const e = 0.15;
36296
36504
  function d(p, q) {
36297
36505
  return Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]);
@@ -36305,7 +36513,7 @@ var GameVehiclesThree = (() => {
36305
36513
  const ca = d(C, A);
36306
36514
  const mx = Math.max(ab, bc, ca);
36307
36515
  if (mx <= maxLen || depth > 9) {
36308
- out.push(A[0], A[1], A[2], Bv[0], Bv[1], Bv[2], C[0], C[1], C[2]);
36516
+ push(A[0], A[1], A[2], Bv[0], Bv[1], Bv[2], C[0], C[1], C[2]);
36309
36517
  return;
36310
36518
  }
36311
36519
  if (mx === ab) {
@@ -36322,31 +36530,26 @@ var GameVehiclesThree = (() => {
36322
36530
  tri(F2, Bv, C, depth + 1);
36323
36531
  }
36324
36532
  }
36533
+ const M = rel.elements;
36534
+ const at = function(x, y, z, k) {
36535
+ const w = 1 / (M[3] * x + M[7] * y + M[11] * z + M[15]);
36536
+ return k === 0 ? (M[0] * x + M[4] * y + M[8] * z + M[12]) * w : k === 1 ? (M[1] * x + M[5] * y + M[9] * z + M[13]) * w : (M[2] * x + M[6] * y + M[10] * z + M[14]) * w;
36537
+ };
36538
+ const lo = [B.x0 - e, B.y0 - e, B.z0 - e];
36539
+ const hi = [B.x1 + e, B.y1 + e, B.z1 + e];
36325
36540
  for (let i = 0; i < a.length; i += 9) {
36326
- const A = [a[i], a[i + 1], a[i + 2]];
36327
- const Bv = [a[i + 3], a[i + 4], a[i + 5]];
36328
- const C = [a[i + 6], a[i + 7], a[i + 8]];
36329
- let x0 = 1e9;
36330
- let x1 = -1e9;
36331
- let y0 = 1e9;
36332
- let y1 = -1e9;
36333
- let z0 = 1e9;
36334
- let z1 = -1e9;
36335
- [A, Bv, C].forEach(function(p) {
36336
- v.set(p[0], p[1], p[2]).applyMatrix4(rel);
36337
- x0 = Math.min(x0, v.x);
36338
- x1 = Math.max(x1, v.x);
36339
- y0 = Math.min(y0, v.y);
36340
- y1 = Math.max(y1, v.y);
36341
- z0 = Math.min(z0, v.z);
36342
- z1 = Math.max(z1, v.z);
36343
- });
36344
- if (x1 < B.x0 - e || x0 > B.x1 + e || y1 < B.y0 - e || y0 > B.y1 + e || z1 < B.z0 - e || z0 > B.z1 + e)
36345
- out.push(A[0], A[1], A[2], Bv[0], Bv[1], Bv[2], C[0], C[1], C[2]);
36346
- else tri(A, Bv, C, 0);
36541
+ let outside = false;
36542
+ for (let k = 0; k < 3 && !outside; k++) {
36543
+ const p = at(a[i], a[i + 1], a[i + 2], k);
36544
+ const q = at(a[i + 3], a[i + 4], a[i + 5], k);
36545
+ const r = at(a[i + 6], a[i + 7], a[i + 8], k);
36546
+ outside = Math.max(p, q, r) < lo[k] || Math.min(p, q, r) > hi[k];
36547
+ }
36548
+ if (outside) push(a[i], a[i + 1], a[i + 2], a[i + 3], a[i + 4], a[i + 5], a[i + 6], a[i + 7], a[i + 8]);
36549
+ else tri([a[i], a[i + 1], a[i + 2]], [a[i + 3], a[i + 4], a[i + 5]], [a[i + 6], a[i + 7], a[i + 8]], 0);
36347
36550
  }
36348
36551
  const g = new THREE.BufferGeometry();
36349
- g.setAttribute("position", new THREE.Float32BufferAttribute(out, 3));
36552
+ g.setAttribute("position", new THREE.BufferAttribute(out.slice(0, used), 3));
36350
36553
  g.userData.crease = true;
36351
36554
  g.userData.p0 = null;
36352
36555
  return g;
@@ -36369,6 +36572,17 @@ var GameVehiclesThree = (() => {
36369
36572
  });
36370
36573
  return out;
36371
36574
  }
36575
+ function boxInFrame(B, m, tmp) {
36576
+ const r = [Infinity, Infinity, Infinity, -Infinity, -Infinity, -Infinity];
36577
+ for (let i = 0; i < 8; i++) {
36578
+ tmp.set(i & 1 ? B.x1 : B.x0, i & 2 ? B.y1 : B.y0, i & 4 ? B.z1 : B.z0).applyMatrix4(m);
36579
+ for (let k = 0; k < 3; k++) {
36580
+ r[k] = Math.min(r[k], tmp.getComponent(k) - 1e-4);
36581
+ r[k + 3] = Math.max(r[k + 3], tmp.getComponent(k) + 1e-4);
36582
+ }
36583
+ }
36584
+ return r;
36585
+ }
36372
36586
  function zoneDent(c, z, dents, dirty, opt) {
36373
36587
  opt = opt || {};
36374
36588
  const B = z.box;
@@ -36423,6 +36637,7 @@ var GameVehiclesThree = (() => {
36423
36637
  g = msh.geometry = g.clone();
36424
36638
  msh.userData.zCloned = true;
36425
36639
  }
36640
+ let boundsDue = false;
36426
36641
  const nonIdx = !g.index;
36427
36642
  const onlyPos = Object.keys(g.attributes).every(function(k) {
36428
36643
  return k === "position" || k === "normal";
@@ -36431,15 +36646,17 @@ var GameVehiclesThree = (() => {
36431
36646
  const ng = subdivIn(g, rel, B, opt.sub || 0.075);
36432
36647
  g.dispose();
36433
36648
  g = msh.geometry = ng;
36434
- ng.computeBoundingSphere();
36435
- ng.computeBoundingBox();
36649
+ boundsDue = true;
36436
36650
  dirty.add(msh);
36437
36651
  }
36438
36652
  irel.copy(rel).invert();
36439
36653
  const pos = g.attributes.position;
36440
36654
  let changed = false;
36655
+ const near = boxInFrame(B, irel, v);
36441
36656
  for (let i = 0; i < pos.count; i++) {
36442
- v.fromBufferAttribute(pos, i).applyMatrix4(rel);
36657
+ v.fromBufferAttribute(pos, i);
36658
+ if (v.x < near[0] || v.x > near[3] || v.y < near[1] || v.y > near[4] || v.z < near[2] || v.z > near[5]) continue;
36659
+ v.applyMatrix4(rel);
36443
36660
  const f = field(v);
36444
36661
  if (f <= 1e-5) continue;
36445
36662
  v.addScaledVector(d, f);
@@ -36460,9 +36677,11 @@ var GameVehiclesThree = (() => {
36460
36677
  }
36461
36678
  if (changed) {
36462
36679
  pos.needsUpdate = true;
36680
+ dirty.add(msh);
36681
+ }
36682
+ if (changed || boundsDue) {
36463
36683
  g.computeBoundingSphere();
36464
36684
  g.computeBoundingBox();
36465
- dirty.add(msh);
36466
36685
  }
36467
36686
  });
36468
36687
  const dset = new Set(c.deform);
@@ -39545,6 +39764,20 @@ var GameVehiclesThree = (() => {
39545
39764
  else kit.applyArmor(c);
39546
39765
  }
39547
39766
  if (zoneState == null && st === "damaged" && kit.config.damagedScenario) zoneState = kit.zoneScenario(c, kit.config.damagedScenario);
39767
+ else if (zoneState && zoneState.scenario != null) {
39768
+ c.scenario = zoneState.scenario;
39769
+ let fromScenario = { health: {}, flags: {} };
39770
+ try {
39771
+ fromScenario = kit.zoneScenario(c, zoneState.scenario);
39772
+ } catch (e) {
39773
+ ;
39774
+ (c.zoneErrors = c.zoneErrors || []).push("scenario: " + (e && e.message));
39775
+ }
39776
+ zoneState = {
39777
+ health: Object.assign({}, fromScenario.health, zoneState.health),
39778
+ flags: Object.assign({}, fromScenario.flags, zoneState.flags)
39779
+ };
39780
+ }
39548
39781
  if (zoneState) kit.applyZones(c, zoneState);
39549
39782
  else {
39550
39783
  c.zoneState = { health: {}, flags: {} };
@@ -41488,7 +41721,7 @@ var GameVehiclesThree = (() => {
41488
41721
  const reset = () => {
41489
41722
  const old = c;
41490
41723
  const parent = old.root.parent;
41491
- const next = kit.build(old.key, old.state);
41724
+ const next = kit.build(old.key, old.state, old.scenario != null ? { scenario: old.scenario } : void 0);
41492
41725
  if (parent) {
41493
41726
  next.root.position.copy(old.root.position);
41494
41727
  next.root.quaternion.copy(old.root.quaternion);
@@ -41543,7 +41776,8 @@ var GameVehiclesThree = (() => {
41543
41776
  }
41544
41777
  function buildVehicleItem(kit, key, options = {}) {
41545
41778
  const THREE = kit.THREE;
41546
- const vehicle = options.lod ? kit.build(key, options.state ?? "intact", void 0, { lod: true }) : kit.build(key, options.state ?? "intact");
41779
+ const zoneState = options.scenario != null ? { scenario: options.scenario } : void 0;
41780
+ const vehicle = options.lod ? kit.build(key, options.state ?? "intact", zoneState, { lod: true }) : kit.build(key, options.state ?? "intact", zoneState);
41547
41781
  const m = vehicle.meta;
41548
41782
  const root = new THREE.Group();
41549
41783
  root.name = key;
@@ -41984,6 +42218,7 @@ var GameVehiclesThree = (() => {
41984
42218
  "vehicles_kill_battery",
41985
42219
  "vehicles_rollover",
41986
42220
  "vehicles_melt",
42221
+ "vehicles_burnt_wreck",
41987
42222
  "vehicles_drive_arcade",
41988
42223
  "vehicles_drive_semi"
41989
42224
  ];
@@ -42015,7 +42250,7 @@ var GameVehiclesThree = (() => {
42015
42250
  en: {
42016
42251
  group: "Vehicles",
42017
42252
  name: "Vehicles area",
42018
- items: { hatch: "Compact hatch", sedan: "Midsize sedan", pickup: "Midsize pickup", sport_bike: "Sport bike", box_truck: "Box truck", city_bus: "City bus", battle_tank: "Battle tank", attack_helicopter: "Attack helicopter" },
42253
+ items: { hatch: "Compact hatch", sedan: "Midsize sedan", pickup: "Midsize pickup", sport_bike: "Sport bike", box_truck: "Box truck", city_bus: "City bus", battle_tank: "Battle tank", attack_helicopter: "Attack helicopter", sedan_burnt: "Burnt sedan", hatch_burnt: "Burnt hatch" },
42019
42254
  controls: { quality: "Quality", paint_by_seed: "Paint by seed", color_seed: "Colour seed", palette: "Palette", driving: "Driving", surface: "Surface" },
42020
42255
  hints: {
42021
42256
  quality: "High: the kit at full detail. Light: fewer segments and no interior (the light mode of the fleet); applies to the vehicles placed from now on",
@@ -42048,7 +42283,8 @@ var GameVehiclesThree = (() => {
42048
42283
  vehicles_rollover: "Vehicles: roll over",
42049
42284
  vehicles_melt: "Vehicles: melt (long fire burns the tyres)",
42050
42285
  vehicles_drive_arcade: "Vehicles: arcade driving down a lane that ends in a wall",
42051
- vehicles_drive_semi: "Vehicles: semi-simulation braking on dry, wet and mud"
42286
+ vehicles_drive_semi: "Vehicles: semi-simulation braking on dry, wet and mud",
42287
+ vehicles_burnt_wreck: "Vehicles: the burnt sedan comes out of the kit burnt, with the glass gone"
42052
42288
  },
42053
42289
  checks: {
42054
42290
  windshield_holes: "Windshield: {0} hole(s), went through {1:b} (expected: 1, true)",
@@ -42073,13 +42309,15 @@ var GameVehiclesThree = (() => {
42073
42309
  arcade_bounce: "Arcade: the car bounces back at {0} m/s (expected: below 0)",
42074
42310
  arcade_noise: "Arcade: {0} engine noise(s) and {1} crash noise(s) (expected: 1 or more each)",
42075
42311
  semi_order: "Semi: braking from 80 km/h takes dry {0} m, wet {1} m, mud {2} m (expected: dry shorter than wet shorter than mud)",
42076
- semi_mud: "Semi: a 2WD car on mud {0:on} (expected: bogged on, a bog event)"
42312
+ semi_mud: "Semi: a 2WD car on mud {0:on} (expected: bogged on, a bog event)",
42313
+ wreck_burnt: "Burnt sedan: burnt flag {0:b} (expected: yes)",
42314
+ wreck_glass: "Burnt sedan: {0} glass zone(s), {1} still above 0 (expected: 1 or more, none above 0)"
42077
42315
  }
42078
42316
  },
42079
42317
  "pt-BR": {
42080
42318
  group: "Ve\xEDculos",
42081
42319
  name: "\xC1rea de ve\xEDculos",
42082
- items: { hatch: "Hatch compacto", sedan: "Sed\xE3 m\xE9dio", pickup: "Picape m\xE9dia", sport_bike: "Moto esportiva", box_truck: "Caminh\xE3o ba\xFA", city_bus: "\xD4nibus urbano", battle_tank: "Tanque de guerra", attack_helicopter: "Helic\xF3ptero de ataque" },
42320
+ items: { hatch: "Hatch compacto", sedan: "Sed\xE3 m\xE9dio", pickup: "Picape m\xE9dia", sport_bike: "Moto esportiva", box_truck: "Caminh\xE3o ba\xFA", city_bus: "\xD4nibus urbano", battle_tank: "Tanque de guerra", attack_helicopter: "Helic\xF3ptero de ataque", sedan_burnt: "Sed\xE3 queimado", hatch_burnt: "Hatch queimado" },
42083
42321
  controls: { quality: "Qualidade", paint_by_seed: "Pintar pela semente", color_seed: "Semente da cor", palette: "Paleta", driving: "Dire\xE7\xE3o", surface: "Piso" },
42084
42322
  hints: {
42085
42323
  quality: "Alta: o kit com todo o detalhe. Leve: menos segmentos e sem interior (o modo leve da frota); vale para os ve\xEDculos postos daqui em diante",
@@ -42112,7 +42350,8 @@ var GameVehiclesThree = (() => {
42112
42350
  vehicles_rollover: "Ve\xEDculos: capotar",
42113
42351
  vehicles_melt: "Ve\xEDculos: derreter (fogo longo queima os pneus)",
42114
42352
  vehicles_drive_arcade: "Ve\xEDculos: dire\xE7\xE3o arcade numa pista que acaba num muro",
42115
- vehicles_drive_semi: "Ve\xEDculos: frenagem da semissimula\xE7\xE3o no seco, no molhado e na lama"
42353
+ vehicles_drive_semi: "Ve\xEDculos: frenagem da semissimula\xE7\xE3o no seco, no molhado e na lama",
42354
+ vehicles_burnt_wreck: "Ve\xEDculos: o sed\xE3 queimado sai do kit queimado, sem os vidros"
42116
42355
  },
42117
42356
  checks: {
42118
42357
  windshield_holes: "Para-brisa: {0} furo(s), atravessou {1:b} (esperado: 1, sim)",
@@ -42137,7 +42376,9 @@ var GameVehiclesThree = (() => {
42137
42376
  arcade_bounce: "Arcade: o carro volta a {0} m/s (esperado: abaixo de 0)",
42138
42377
  arcade_noise: "Arcade: {0} ru\xEDdo(s) de motor e {1} de batida (esperado: 1 ou mais de cada)",
42139
42378
  semi_order: "Semi: frear de 80 km/h leva no seco {0} m, no molhado {1} m, na lama {2} m (esperado: seco menor que molhado menor que lama)",
42140
- semi_mud: "Semi: um carro 2WD na lama {0:on} (esperado: atolado, com evento de atolamento)"
42379
+ semi_mud: "Semi: um carro 2WD na lama {0:on} (esperado: atolado, com evento de atolamento)",
42380
+ wreck_burnt: "Sed\xE3 queimado: marca de queimado {0:b} (esperado: sim)",
42381
+ wreck_glass: "Sed\xE3 queimado: {0} zona(s) de vidro, {1} ainda acima de 0 (esperado: 1 ou mais, nenhuma acima de 0)"
42141
42382
  }
42142
42383
  }
42143
42384
  };
@@ -42296,6 +42537,14 @@ var GameVehiclesThree = (() => {
42296
42537
  const t = part(room, v, "tyre_front_left");
42297
42538
  expect(events(room, "melt", v) >= 1 && (t.status === "melted" || t.melt > 0.5), say("tyre_melt", t.status, Math.round(t.melt * 100), events(room, "melt", v)));
42298
42539
  }),
42540
+ // new in the kit: the burnt wreck comes ready from the kit (the fleet's `burnt` scenario built into the vehicle), no damage applied by the area
42541
+ scenario("vehicles_burnt_wreck", ({ room, expect }) => {
42542
+ const c = room.spawn("sedan_burnt", [0, 0, -7], 0).root.userData.vehicle;
42543
+ expect(c.zoneState.flags.burnt === true, say("wreck_burnt", c.zoneState.flags.burnt === true));
42544
+ const glass = c.zones.filter((z) => z.type === "glass");
42545
+ const up = glass.filter((z) => (c.zoneState.health[z.id] ?? 100) > 0);
42546
+ expect(glass.length >= 1 && up.length === 0, say("wreck_glass", glass.length, up.length));
42547
+ }),
42299
42548
  // new in the kit: the drivers, headless (no vehicle is spawned)
42300
42549
  scenario("vehicles_drive_arcade", ({ expect }) => {
42301
42550
  const driver = createArcadeDriver();
@@ -42576,6 +42825,10 @@ var GameVehiclesThree = (() => {
42576
42825
  exhaust: "vehicle_exhaust"
42577
42826
  };
42578
42827
  var defaultSoundIds = { engine: "engine_saw", horn: "horn", crash: "sfx_impact" };
42828
+ var DEFAULT_TEST_WRECKS = [
42829
+ { key: "sedan_burnt", vehicle: "midsize_sedan", scenario: "burnt" },
42830
+ { key: "hatch_burnt", vehicle: "compact_hatch", scenario: "burnt" }
42831
+ ];
42579
42832
 
42580
42833
  // src/test-area/module.ts
42581
42834
  var VEHICLES_AREA_ID = "vehicles_area";
@@ -42589,6 +42842,8 @@ var GameVehiclesThree = (() => {
42589
42842
  const locale = options.locale ?? "pt-BR";
42590
42843
  const text = TEXT[locale] ?? TEXT["pt-BR"];
42591
42844
  const keys = options.vehicles ?? DEFAULT_TEST_VEHICLES;
42845
+ const wrecks = options.wrecks ?? DEFAULT_TEST_WRECKS;
42846
+ const entries = [...keys.map((key) => ({ key, id: itemId(key) })), ...wrecks.map((w) => ({ key: w.vehicle, id: w.key, scenario: w.scenario }))];
42592
42847
  const effectIds = { ...defaultEffectIds, ...options.effects };
42593
42848
  const soundIds = { ...defaultSoundIds, ...options.sounds };
42594
42849
  const settings = { quality: "high", paint: false, seed: 1, palette: "auto", driving: "arcade", surface: "dry_asphalt" };
@@ -42637,17 +42892,17 @@ var GameVehiclesThree = (() => {
42637
42892
  }
42638
42893
  entry.paint.color.set(color2);
42639
42894
  };
42640
- const item = (key) => ({
42641
- id: itemId(key),
42642
- name: text.items[itemId(key)] ?? key,
42895
+ const item = ({ key, id: itemKey, scenario }) => ({
42896
+ id: itemKey,
42897
+ name: text.items[itemKey] ?? key,
42643
42898
  movable: false,
42644
42899
  // the first build of a vehicle takes most of a second
42645
42900
  slow: true,
42646
42901
  build: (THREE) => {
42647
42902
  const kit = kitFor(THREE);
42648
- const built = buildVehicleItem(kit, key, { lod: settings.quality === "lite" });
42903
+ const built = buildVehicleItem(kit, key, { lod: settings.quality === "lite", ...scenario ? { scenario } : {} });
42649
42904
  built.root.userData.kit = kit;
42650
- const entry = { root: built.root, key, item: built, index: counter++, helpers: [] };
42905
+ const entry = { root: built.root, key, ...scenario ? { scenario } : {}, item: built, index: counter++, helpers: [] };
42651
42906
  placed.set(built.root.uuid, entry);
42652
42907
  measure(entry);
42653
42908
  paintOf(entry);
@@ -42656,7 +42911,7 @@ var GameVehiclesThree = (() => {
42656
42911
  impl: (root, id) => {
42657
42912
  const r = root;
42658
42913
  const kit = r.userData.kit;
42659
- const d = createVehicleDestructible(kit, r.userData.vehicle, { id, frame: root, name: text.items[itemId(key)] ?? key });
42914
+ const d = createVehicleDestructible(kit, r.userData.vehicle, { id, frame: root, name: text.items[itemKey] ?? key });
42660
42915
  tapEffects(d);
42661
42916
  r.userData.destructible = d;
42662
42917
  return d;
@@ -42930,7 +43185,7 @@ var GameVehiclesThree = (() => {
42930
43185
  for (const entry of placed.values()) {
42931
43186
  const want = fleetDims(entry.key);
42932
43187
  const got = entry.size;
42933
- if (!want || !got) continue;
43188
+ if (!want || !got || entry.scenario) continue;
42934
43189
  worst = Math.max(worst, Math.abs(got.length - want.length), Math.abs(got.width - want.width), Math.abs(got.height - want.height));
42935
43190
  }
42936
43191
  return Math.round(worst * 1e3);
@@ -42942,23 +43197,23 @@ var GameVehiclesThree = (() => {
42942
43197
  get placed() {
42943
43198
  return placed;
42944
43199
  },
42945
- items: () => keys.map(item),
43200
+ items: () => entries.map(item),
42946
43201
  area: () => {
42947
43202
  const gap = 1.6;
42948
43203
  const WIDE = 6;
42949
43204
  const rowOf = (list2, z) => {
42950
43205
  let cursor = 0;
42951
- const spots = list2.map((key) => {
42952
- const width = fleetDims(key)?.width ?? 2;
43206
+ const spots = list2.map((entry) => {
43207
+ const width = fleetDims(entry.key)?.width ?? 2;
42953
43208
  const x = cursor + width / 2;
42954
43209
  cursor += width + gap;
42955
- return { key, x };
43210
+ return { id: entry.id, x };
42956
43211
  });
42957
43212
  return { spots, z, width: Math.max(0, cursor - gap) };
42958
43213
  };
42959
- const front = rowOf(keys.filter((key) => (fleetDims(key)?.width ?? 2) <= WIDE), 0);
42960
- const back = rowOf(keys.filter((key) => (fleetDims(key)?.width ?? 2) > WIDE), -16);
42961
- const placements = [front, back].flatMap((row) => row.spots.map(({ key, x }) => ({ item: itemId(key), position: [x - row.width / 2, 0, row.z], rotationY: 0 })));
43214
+ const front = rowOf(entries.filter((e) => (fleetDims(e.key)?.width ?? 2) <= WIDE), 0);
43215
+ const back = rowOf(entries.filter((e) => (fleetDims(e.key)?.width ?? 2) > WIDE), -16);
43216
+ const placements = [front, back].flatMap((row) => row.spots.map(({ id, x }) => ({ item: id, position: [x - row.width / 2, 0, row.z], rotationY: 0 })));
42962
43217
  return { placements, view: { eye: [0, 5, Math.max(14, front.width * 0.6)], target: [0, 1, -2] } };
42963
43218
  },
42964
43219
  controls: () => {