@adatechnology/game-vehicles-three 0.7.0 → 0.8.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.
@@ -33,6 +33,7 @@ var GameVehiclesThree = (() => {
33
33
  ENGINE_PROFILES: () => ENGINE_PROFILES,
34
34
  LAMP_RULES: () => LAMP_RULES,
35
35
  LITE_CLASSES: () => LITE_CLASSES,
36
+ MIST_RULES: () => MIST_RULES,
36
37
  PAGE_ITEM_ALIASES: () => PAGE_ITEM_ALIASES,
37
38
  PAGE_SCENARIO_ALIASES: () => PAGE_SCENARIO_ALIASES,
38
39
  PROVING_AREA_ID: () => PROVING_AREA_ID,
@@ -43,6 +44,7 @@ var GameVehiclesThree = (() => {
43
44
  VEHICLE_LOD_DISTANCE: () => VEHICLE_LOD_DISTANCE,
44
45
  VEHICLE_LOOPS: () => VEHICLE_LOOPS,
45
46
  VEHICLE_LOOP_FALLOFF: () => VEHICLE_LOOP_FALLOFF,
47
+ VEHICLE_PRELOAD_SOUNDS: () => VEHICLE_PRELOAD_SOUNDS,
46
48
  VEHICLE_SAMPLE_ALIASES: () => VEHICLE_SAMPLE_ALIASES,
47
49
  VEHICLE_SCENARIO_IDS: () => VEHICLE_SCENARIO_IDS,
48
50
  VEHICLE_SOUNDS: () => VEHICLE_SOUNDS,
@@ -50,6 +52,7 @@ var GameVehiclesThree = (() => {
50
52
  classColor: () => classColor,
51
53
  classify: () => classify,
52
54
  createCabinSmoke: () => createCabinSmoke,
55
+ createEngineBudget: () => createEngineBudget,
53
56
  createGearGuess: () => createGearGuess,
54
57
  createProvingModule: () => createProvingModule,
55
58
  createVehicleBody: () => createVehicleBody,
@@ -60,6 +63,7 @@ var GameVehiclesThree = (() => {
60
63
  createVehiclesTestModule: () => createVehiclesTestModule,
61
64
  createVehiclesThree: () => createVehiclesThree,
62
65
  createWheelRoll: () => createWheelRoll,
66
+ createWindshieldMist: () => createWindshieldMist,
63
67
  defaultEffectIds: () => defaultEffectIds,
64
68
  defaultSoundIds: () => defaultSoundIds,
65
69
  engineMix: () => engineMix,
@@ -5118,7 +5122,7 @@ var GameVehiclesThree = (() => {
5118
5122
  const THREE = kit.THREE;
5119
5123
  const trl = fx.t;
5120
5124
  const lbl = fx.label;
5121
- const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, G2 = kit.geo, profX = kit.profX, halfAt = kit.halfAt, clamp5 = kit.clamp, smooth2 = kit.smooth;
5125
+ const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, G2 = kit.geo, profX = kit.profX, halfAt = kit.halfAt, clamp6 = kit.clamp, smooth2 = kit.smooth;
5122
5126
  const GLOSS = CM("#07080a", { roughness: 0.18, metalness: 0.5 });
5123
5127
  const ALLOY = CM("#b9bec2", { metalness: 0.75, roughness: 0.3 });
5124
5128
  const ALLOYD = CM("#3a3e42", { metalness: 0.6, roughness: 0.35 });
@@ -5132,7 +5136,7 @@ var GameVehiclesThree = (() => {
5132
5136
  const a = (y - o.ys) / (o.belt - o.ys);
5133
5137
  return o.kt * a * a;
5134
5138
  }
5135
- const b = clamp5((o.ys - y) / (o.ys - o.yb), 0, 1.25);
5139
+ const b = clamp6((o.ys - y) / (o.ys - o.yb), 0, 1.25);
5136
5140
  return o.kb * b * b;
5137
5141
  }
5138
5142
  const f = function(x, y, z) {
@@ -5212,13 +5216,13 @@ var GameVehiclesThree = (() => {
5212
5216
  });
5213
5217
  }
5214
5218
  function roofAt(gh, x) {
5215
- const rR = gh.roofR || gh.roof, t = clamp5((x - gh.rt) / (gh.ft - gh.rt), 0, 1);
5219
+ const rR = gh.roofR || gh.roof, t = clamp6((x - gh.rt) / (gh.ft - gh.rt), 0, 1);
5216
5220
  return rR + (gh.roof - rR) * t + (gh.crown || 0) * 4 * t * (1 - t);
5217
5221
  }
5218
5222
  function windows(gh) {
5219
5223
  const inn = 0.07, rise = gh.rise || 0;
5220
5224
  function ybAt(x) {
5221
- return gh.belt + 0.035 + rise * clamp5((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
5225
+ return gh.belt + 0.035 + rise * clamp6((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
5222
5226
  }
5223
5227
  function lx(x0, x1, y, top) {
5224
5228
  return x0 + (x1 - x0) * (y - gh.belt) / (top - gh.belt);
@@ -5421,7 +5425,7 @@ var GameVehiclesThree = (() => {
5421
5425
  }
5422
5426
  const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: tot * (full ? 2 : 1), E, sd };
5423
5427
  G22.at = function(u, y) {
5424
- const fi = clamp5(u, 0, 1) * nu, fj = clamp5((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
5428
+ const fi = clamp6(u, 0, 1) * nu, fj = clamp6((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
5425
5429
  function L(M) {
5426
5430
  return M[i0][j0].clone().multiplyScalar((1 - a) * (1 - b)).addScaledVector(M[i0 + 1][j0], a * (1 - b)).addScaledVector(M[i0][j0 + 1], (1 - a) * b).addScaledVector(M[i0 + 1][j0 + 1], a * b);
5427
5431
  }
@@ -6001,7 +6005,7 @@ var GameVehiclesThree = (() => {
6001
6005
  c.roundBox(x1 - x0, 0.08, 0.035, 0.015, MT.trim, (x0 + x1) / 2, by + 0.05, sd * (hw - 8e-3));
6002
6006
  if (s.clad)
6003
6007
  s.arches.forEach(function(a) {
6004
- const a0 = Math.asin(clamp5((by - a[1]) / a[2], -1, 1)), tor = c.add(new THREE.TorusGeometry(a[2] + 0.02, 0.035, 6, 26, PI - 2 * a0), MT.trim, a[0], a[1], sd * (hw - 0.01));
6008
+ const a0 = Math.asin(clamp6((by - a[1]) / a[2], -1, 1)), tor = c.add(new THREE.TorusGeometry(a[2] + 0.02, 0.035, 6, 26, PI - 2 * a0), MT.trim, a[0], a[1], sd * (hw - 0.01));
6005
6009
  tor.rotation.z = a0;
6006
6010
  tor.scale.z = 0.8;
6007
6011
  });
@@ -6138,7 +6142,7 @@ var GameVehiclesThree = (() => {
6138
6142
  c.cylinder(0.06, 0.06, 0.012, MT.head, x + 0.055, y, z, "x");
6139
6143
  }
6140
6144
  function sm(t) {
6141
- t = clamp5(t, 0, 1);
6145
+ t = clamp6(t, 0, 1);
6142
6146
  return t * t * (3 - 2 * t);
6143
6147
  }
6144
6148
  function sideGrid(S, sd, o) {
@@ -6155,7 +6159,7 @@ var GameVehiclesThree = (() => {
6155
6159
  }
6156
6160
  const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: Math.abs(o.x1 - o.x0) };
6157
6161
  G22.at = function(u, y) {
6158
- const fi = clamp5(u, 0, 1) * nu, fj = clamp5((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
6162
+ const fi = clamp6(u, 0, 1) * nu, fj = clamp6((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
6159
6163
  function L(M) {
6160
6164
  return M[i0][j0].clone().multiplyScalar((1 - a) * (1 - b)).addScaledVector(M[i0 + 1][j0], a * (1 - b)).addScaledVector(M[i0][j0 + 1], (1 - a) * b).addScaledVector(M[i0 + 1][j0 + 1], a * b);
6161
6165
  }
@@ -7889,7 +7893,7 @@ var GameVehiclesThree = (() => {
7889
7893
  const g = K.grid(1, 0, { z1: 0.66, y0: 0.27, y1: 0.61, du: 0.03, dv: 0.03 }), zt = 0.6, zb = 0.43, yB0 = 0.3, yT = 0.585;
7890
7894
  const gyb = function(u) {
7891
7895
  const z = Math.abs(g.zu(u));
7892
- return z <= zb ? yB0 : yB0 + (yT - 0.02 - yB0) * clamp5((z - zb) / (zt - zb), 0, 1);
7896
+ return z <= zb ? yB0 : yB0 + (yT - 0.02 - yB0) * clamp6((z - zb) / (zt - zb), 0, 1);
7893
7897
  };
7894
7898
  K.skin(g, grilleMat("mesh"), { u0: g.uz(-zt), u1: g.uz(zt), yb: gyb, yt: yT, off: 0.022, tile: 0.05, nv: 6 });
7895
7899
  outline(c2, g, { u0: g.uz(-zt), u1: g.uz(zt), yb: gyb, yt: yT }, 0.012, LH, 0.024);
@@ -9525,8 +9529,10 @@ var GameVehiclesThree = (() => {
9525
9529
  c.cylinder(0.36, 0.38, 0.1, plate, -1.3, 3.13, 0);
9526
9530
  c.cylinder(0.3, 0.3, 0.05, MT.steel, -1.3, 3.2, 0);
9527
9531
  c.roundBox(0.2, 0.08, 1.3, 0.03, MT.trim, bx0 - 0.25, 3.13, 0);
9528
- [-0.45, 0, 0.45].forEach(function(z) {
9529
- c.roundBox(0.14, 0.08, 0.3, 0.03, MT.amber, bx0 - 0.25, 3.2, z);
9532
+ [-0.45, 0, 0.45].forEach(function(z, i) {
9533
+ const lamp = c.roundBox(0.14, 0.08, 0.3, 0.03, MT.amber, bx0 - 0.25, 3.2, z);
9534
+ lamp.userData.lamp = "beacon";
9535
+ lamp.userData.beaconSide = i % 2;
9530
9536
  });
9531
9537
  c.rod(new V3(-2.5, 3.08, 0.6), new V3(-2.5, 3.6, 0.6), 8e-3, MT.trim);
9532
9538
  c.rod(new V3(-2.8, 3.08, -0.6), new V3(-2.8, 3.4, -0.6), 0.01, MT.trim);
@@ -14048,7 +14054,7 @@ var GameVehiclesThree = (() => {
14048
14054
  const THREE = kit.THREE;
14049
14055
  const trl = fx.t;
14050
14056
  const lbl = fx.label;
14051
- const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, G2 = kit.geo, profX = kit.profX, halfAt = kit.halfAt, clamp5 = kit.clamp, smooth2 = kit.smooth;
14057
+ const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, G2 = kit.geo, profX = kit.profX, halfAt = kit.halfAt, clamp6 = kit.clamp, smooth2 = kit.smooth;
14052
14058
  const GLOSS = CM("#07080a", { roughness: 0.18, metalness: 0.5 });
14053
14059
  const ALLOY = CM("#b9bec2", { metalness: 0.75, roughness: 0.3 });
14054
14060
  const ALLOYD = CM("#3a3e42", { metalness: 0.6, roughness: 0.35 });
@@ -14067,7 +14073,7 @@ var GameVehiclesThree = (() => {
14067
14073
  const a = (y - o.ys) / (o.belt - o.ys);
14068
14074
  return o.kt * a * a;
14069
14075
  }
14070
- const b = clamp5((o.ys - y) / (o.ys - o.yb), 0, 1.25);
14076
+ const b = clamp6((o.ys - y) / (o.ys - o.yb), 0, 1.25);
14071
14077
  return o.kb * b * b;
14072
14078
  }
14073
14079
  const f = function(x, y, z) {
@@ -14247,13 +14253,13 @@ var GameVehiclesThree = (() => {
14247
14253
  return L;
14248
14254
  }
14249
14255
  function roofAt(gh, x) {
14250
- const rR = gh.roofR || gh.roof, t = clamp5((x - gh.rt) / (gh.ft - gh.rt), 0, 1);
14256
+ const rR = gh.roofR || gh.roof, t = clamp6((x - gh.rt) / (gh.ft - gh.rt), 0, 1);
14251
14257
  return rR + (gh.roof - rR) * t + (gh.crown || 0) * 4 * t * (1 - t);
14252
14258
  }
14253
14259
  function windows(gh) {
14254
14260
  const inn = 0.07, rise = gh.rise || 0;
14255
14261
  function ybAt(x) {
14256
- return gh.belt + 0.035 + rise * clamp5((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
14262
+ return gh.belt + 0.035 + rise * clamp6((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
14257
14263
  }
14258
14264
  function lx(x0, x1, y, top) {
14259
14265
  return x0 + (x1 - x0) * (y - gh.belt) / (top - gh.belt);
@@ -14464,7 +14470,7 @@ var GameVehiclesThree = (() => {
14464
14470
  }
14465
14471
  const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: tot * (full ? 2 : 1), E, sd };
14466
14472
  G22.at = function(u, y) {
14467
- const fi = clamp5(u, 0, 1) * nu, fj = clamp5((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
14473
+ const fi = clamp6(u, 0, 1) * nu, fj = clamp6((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
14468
14474
  function L(M) {
14469
14475
  return M[i0][j0].clone().multiplyScalar((1 - a) * (1 - b)).addScaledVector(M[i0 + 1][j0], a * (1 - b)).addScaledVector(M[i0][j0 + 1], (1 - a) * b).addScaledVector(M[i0 + 1][j0 + 1], a * b);
14470
14476
  }
@@ -15025,7 +15031,7 @@ var GameVehiclesThree = (() => {
15025
15031
  c.roundBox(x1 - x0, 0.08, 0.035, 0.015, MT.trim, (x0 + x1) / 2, by + 0.05, sd * (hw - 8e-3));
15026
15032
  if (s.clad)
15027
15033
  s.arches.forEach(function(a) {
15028
- const a0 = Math.asin(clamp5((by - a[1]) / a[2], -1, 1)), tor = c.add(new THREE.TorusGeometry(a[2] + 0.02, 0.035, 6, 26, PI - 2 * a0), MT.trim, a[0], a[1], sd * (hw - 0.01));
15034
+ const a0 = Math.asin(clamp6((by - a[1]) / a[2], -1, 1)), tor = c.add(new THREE.TorusGeometry(a[2] + 0.02, 0.035, 6, 26, PI - 2 * a0), MT.trim, a[0], a[1], sd * (hw - 0.01));
15029
15035
  tor.rotation.z = a0;
15030
15036
  tor.scale.z = 0.8;
15031
15037
  });
@@ -15149,7 +15155,7 @@ var GameVehiclesThree = (() => {
15149
15155
  c.cylinder(0.06, 0.06, 0.012, MT.head, x + 0.055, y, z, "x");
15150
15156
  }
15151
15157
  function sm(t) {
15152
- t = clamp5(t, 0, 1);
15158
+ t = clamp6(t, 0, 1);
15153
15159
  return t * t * (3 - 2 * t);
15154
15160
  }
15155
15161
  function sideGrid(S, sd, o) {
@@ -15166,7 +15172,7 @@ var GameVehiclesThree = (() => {
15166
15172
  }
15167
15173
  const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: Math.abs(o.x1 - o.x0) };
15168
15174
  G22.at = function(u, y) {
15169
- const fi = clamp5(u, 0, 1) * nu, fj = clamp5((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
15175
+ const fi = clamp6(u, 0, 1) * nu, fj = clamp6((y - o.y0) / (o.y1 - o.y0), 0, 1) * nv, i0 = Math.min(nu - 1, Math.floor(fi)), j0 = Math.min(nv - 1, Math.floor(fj)), a = fi - i0, b = fj - j0;
15170
15176
  function L(M) {
15171
15177
  return M[i0][j0].clone().multiplyScalar((1 - a) * (1 - b)).addScaledVector(M[i0 + 1][j0], a * (1 - b)).addScaledVector(M[i0][j0 + 1], (1 - a) * b).addScaledVector(M[i0 + 1][j0 + 1], a * b);
15172
15178
  }
@@ -15327,7 +15333,7 @@ var GameVehiclesThree = (() => {
15327
15333
  return function(c, I) {
15328
15334
  const gh = I.gh, col = c.meta.color;
15329
15335
  function yb(x) {
15330
- return gh.belt + 0.035 + (gh.rise || 0) * clamp5((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
15336
+ return gh.belt + 0.035 + (gh.rise || 0) * clamp6((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
15331
15337
  }
15332
15338
  ;
15333
15339
  [1, -1].forEach(function(sd) {
@@ -16568,6 +16574,10 @@ var GameVehiclesThree = (() => {
16568
16574
  }
16569
16575
  }
16570
16576
  });
16577
+ beacon[1].userData.lamp = "beacon";
16578
+ beacon[1].userData.beaconSide = 0;
16579
+ beacon[2].userData.lamp = "beacon";
16580
+ beacon[2].userData.beaconSide = 1;
16571
16581
  c2.meta.top = top + 0.15;
16572
16582
  c2.meta.roof.y = Math.max(c2.meta.roof.y, top + 0.15);
16573
16583
  const fx2 = I.fxB + 0.12, push = [];
@@ -17870,7 +17880,9 @@ var GameVehiclesThree = (() => {
17870
17880
  c.roundBox(0.5, 0.018, 6e-3, 2e-3, c.paint("#f2c21a"), -0.7, 0.825, z);
17871
17881
  c.text("PRF", 0.2, 0.08, -0.7, 0.73, z + s * 2e-3, f, { fg: "#1f3f8f", size: 0.85 });
17872
17882
  c.text(trl("texts.federal_highway_police"), 0.3, 0.035, 0.24, 1, s * 0.3, f, { fg: "#f4f2ea", w: 1024, h: 120, size: 0.8 });
17873
- c.roundBox(0.05, 0.05, 0.04, 0.012, s > 0 ? MT.blue : MT.tail, 0.62, 0.95, s * 0.3, { def: true });
17883
+ const flasher = c.roundBox(0.05, 0.05, 0.04, 0.012, s > 0 ? MT.blue : MT.tail, 0.62, 0.95, s * 0.3, { def: true });
17884
+ flasher.userData.lamp = "beacon";
17885
+ flasher.userData.beaconSide = s > 0 ? 1 : 0;
17874
17886
  });
17875
17887
  c.cylinder(0.04, 0.045, 0.06, MT.trim, 0.66, 0.66, 0.36, "x");
17876
17888
  }
@@ -18200,7 +18212,7 @@ var GameVehiclesThree = (() => {
18200
18212
  return n.y > 0.3 && ce.x > 0.9 && ce.y > 0.6;
18201
18213
  },
18202
18214
  sdf: function(x, y, z) {
18203
- const t = clamp5((x - 1.17) / 0.5, 0, 1);
18215
+ const t = clamp6((x - 1.17) / 0.5, 0, 1);
18204
18216
  return Math.max(0.94 - x, x - 1.69, Math.abs(z) - (0.44 - 0.16 * t * t));
18205
18217
  }
18206
18218
  });
@@ -22198,7 +22210,7 @@ var GameVehiclesThree = (() => {
22198
22210
  const THREE = kit.THREE;
22199
22211
  const trl = fx.t;
22200
22212
  const lbl = fx.label;
22201
- const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, clamp5 = kit.clamp, smooth2 = kit.smooth;
22213
+ const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, clamp6 = kit.clamp, smooth2 = kit.smooth;
22202
22214
  const CLAD = CM("#1a1b1d", { roughness: 0.82 }), LINER = CM("#1c1d1f", { roughness: 0.92 }), RIMDARK = CM("#2a2d30", { metalness: 0.6, roughness: 0.4 });
22203
22215
  const RIMSIL = CM("#b9bec2", { metalness: 0.75, roughness: 0.3 }), RIMGUN = CM("#55595d", { metalness: 0.7, roughness: 0.35 });
22204
22216
  function axles(WB, oF, L, dF, dR) {
@@ -22229,16 +22241,16 @@ var GameVehiclesThree = (() => {
22229
22241
  const m = c.meta, W = m.width, by = o.bottom != null ? o.bottom : m.clearance, top = o.top != null ? o.top : m.belt;
22230
22242
  const Wg = m.glasshouse && m.glasshouse.Wg || W, front = m.front, rear = m.rear;
22231
22243
  const tuck = o.tuck == null ? 0.045 : o.tuck, peak = o.peak || 0.45;
22232
- const B = o.sh != null ? o.sh : clamp5(1 - (Wg + 0.06) / W, 0, 0.06);
22244
+ const B = o.sh != null ? o.sh : clamp6(1 - (Wg + 0.06) / W, 0, 0.06);
22233
22245
  const Rf = o.Rf || 0.55, Rr = o.Rr || 0.42, pf = o.pf == null ? 0.08 : o.pf, pr = o.pr == null ? 0.05 : o.pr;
22234
22246
  const bowF = o.bowF == null ? 0.07 : o.bowF, bowR = o.bowR == null ? 0.04 : o.bowR, Rb = o.Rb || 0.35, hw = W / 2;
22235
22247
  const crown = o.crown == null ? 0.045 : o.crown, xc = o.crownX != null ? o.crownX : m.glasshouse ? m.glasshouse.fb : front - 1, y0 = by + 0.55 * (top - by);
22236
22248
  function sc(y) {
22237
- const t = clamp5((y - by) / (top - by), 0, 1);
22249
+ const t = clamp6((y - by) / (top - by), 0, 1);
22238
22250
  return t < peak ? 1 - tuck * Math.pow(1 - t / peak, 2) : 1 - B * Math.pow((t - peak) / (1 - peak), 2);
22239
22251
  }
22240
22252
  function F(v2) {
22241
- const a = smooth2((v2.x - (front - Rf)) / Rf), b = smooth2((rear + Rr - v2.x) / Rr), zz = clamp5(v2.z / hw, -1, 1) * clamp5(v2.z / hw, -1, 1);
22253
+ const a = smooth2((v2.x - (front - Rf)) / Rf), b = smooth2((rear + Rr - v2.x) / Rr), zz = clamp6(v2.z / hw, -1, 1) * clamp6(v2.z / hw, -1, 1);
22242
22254
  const bf = smooth2((v2.x - (front - Rb)) / Rb), br = smooth2((rear + Rb - v2.x) / Rb);
22243
22255
  const cr = crown * (1 - zz) * smooth2((v2.y - y0) / (top - y0)) * smooth2((v2.x - xc) / 0.3);
22244
22256
  v2.x += -bowF * zz * bf + bowR * zz * br;
@@ -22315,7 +22327,7 @@ var GameVehiclesThree = (() => {
22315
22327
  o = o || {};
22316
22328
  const wd = o.w || 0.075, dp = o.d || 0.045, mat = o.mat || CLAD, out = [];
22317
22329
  arches.forEach(function(a) {
22318
- const a0 = Math.asin(clamp5((by - a[1]) / a[2], -1, 1)) - 0.02, r0 = a[2] - (o.inner == null ? 0.055 : o.inner), r1 = a[2] + wd;
22330
+ const a0 = Math.asin(clamp6((by - a[1]) / a[2], -1, 1)) - 0.02, r0 = a[2] - (o.inner == null ? 0.055 : o.inner), r1 = a[2] + wd;
22319
22331
  const sh = new THREE.Shape();
22320
22332
  if (o.trap) {
22321
22333
  const yb0 = Math.sin(a0) * r1, xb0 = Math.cos(a0) * r1, top = r1 * 0.93, xt = r1 * 0.52;
@@ -22665,7 +22677,7 @@ var GameVehiclesThree = (() => {
22665
22677
  function roof(c, drop, x0, x1) {
22666
22678
  const m = c.meta, b = m.glasshouse.belt, h = m.top - b;
22667
22679
  function dy(x, y) {
22668
- const t = clamp5((y - b) / h, 0, 1);
22680
+ const t = clamp6((y - b) / h, 0, 1);
22669
22681
  return t <= 0 ? 0 : drop * smooth2((x0 - x) / (x0 - x1)) * t;
22670
22682
  }
22671
22683
  c.root.updateMatrixWorld(true);
@@ -23859,8 +23871,8 @@ var GameVehiclesThree = (() => {
23859
23871
  setOnHit(pt, function(c2, p0) {
23860
23872
  const o = p0.obj;
23861
23873
  if (o && o.userData.hung && o.parent && o.parent !== c2.vehicle) {
23862
- o.parent.rotation.x = clamp5(o.parent.rotation.x, -0.22, 0.22);
23863
- o.parent.rotation.y = clamp5(o.parent.rotation.y, -0.08, 0.08);
23874
+ o.parent.rotation.x = clamp6(o.parent.rotation.x, -0.22, 0.22);
23875
+ o.parent.rotation.y = clamp6(o.parent.rotation.y, -0.08, 0.08);
23864
23876
  }
23865
23877
  });
23866
23878
  });
@@ -24401,18 +24413,19 @@ var GameVehiclesThree = (() => {
24401
24413
  c2.roundBox(0.03, 0.12, 1.9, 0.01, rd, m.rear - 8e-3, 1.1, 0);
24402
24414
  const beaconBar = [c2.roundBox(0.3, 0.08, 1.5, 0.03, MT.trim, 0.6, m.top + 0.04, 0)];
24403
24415
  [-0.5, -0.17, 0.17, 0.5].forEach(function(z, i) {
24404
- beaconBar.push(
24405
- c2.roundBox(
24406
- 0.24,
24407
- 0.1,
24408
- 0.3,
24409
- 0.04,
24410
- i % 2 ? MT.tail : CM("#f2f2f2", { emissive: new THREE.Color("#ffffff"), emissiveIntensity: 0.6 }),
24411
- 0.6,
24412
- m.top + 0.13,
24413
- z
24414
- )
24416
+ const lamp = c2.roundBox(
24417
+ 0.24,
24418
+ 0.1,
24419
+ 0.3,
24420
+ 0.04,
24421
+ i % 2 ? MT.tail : CM("#f2f2f2", { emissive: new THREE.Color("#ffffff"), emissiveIntensity: 0.6 }),
24422
+ 0.6,
24423
+ m.top + 0.13,
24424
+ z
24415
24425
  );
24426
+ lamp.userData.lamp = "beacon";
24427
+ lamp.userData.beaconSide = z < 0 ? 0 : 1;
24428
+ beaconBar.push(lamp);
24416
24429
  });
24417
24430
  beaconBar.push(
24418
24431
  c2.roundBox(
@@ -24511,7 +24524,7 @@ var GameVehiclesThree = (() => {
24511
24524
  const shared2 = fx.shared;
24512
24525
  const trl = fx.t;
24513
24526
  const lbl = fx.label;
24514
- const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, _paintCol = kit.paintColor, G2 = kit.geo, DS = THREE.DoubleSide, clamp5 = kit.clamp;
24527
+ const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, _paintCol = kit.paintColor, G2 = kit.geo, DS = THREE.DoubleSide, clamp6 = kit.clamp;
24515
24528
  function colorize(geo, fn) {
24516
24529
  const p = geo.attributes.position, col = new Float32Array(p.count * 3);
24517
24530
  for (let i = 0; i < p.count; i++) {
@@ -24527,7 +24540,7 @@ var GameVehiclesThree = (() => {
24527
24540
  return a + (b - a) * t;
24528
24541
  }
24529
24542
  function sstep(a, b, x) {
24530
- const t = clamp5((x - a) / (b - a), 0, 1);
24543
+ const t = clamp6((x - a) / (b - a), 0, 1);
24531
24544
  return t * t * (3 - 2 * t);
24532
24545
  }
24533
24546
  function tab(T) {
@@ -24604,7 +24617,7 @@ var GameVehiclesThree = (() => {
24604
24617
  o,
24605
24618
  sec,
24606
24619
  t: function(x) {
24607
- return clamp5((x - o.x0) / o.L, 0, 1);
24620
+ return clamp6((x - o.x0) / o.L, 0, 1);
24608
24621
  },
24609
24622
  /* half beam of the hull at height y (inside, so floors and decks do not leak) */
24610
24623
  half: function(x, y) {
@@ -24778,7 +24791,7 @@ var GameVehiclesThree = (() => {
24778
24791
  for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
24779
24792
  const a = poly[i], b = poly[j];
24780
24793
  if (a[1] > y !== b[1] > y && x < (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]) + a[0]) inside = !inside;
24781
- const vx = b[0] - a[0], vy = b[1] - a[1], wx = x - a[0], wy = y - a[1], t = clamp5((wx * vx + wy * vy) / (vx * vx + vy * vy), 0, 1);
24794
+ const vx = b[0] - a[0], vy = b[1] - a[1], wx = x - a[0], wy = y - a[1], t = clamp6((wx * vx + wy * vy) / (vx * vx + vy * vy), 0, 1);
24782
24795
  d = Math.min(d, Math.hypot(wx - vx * t, wy - vy * t));
24783
24796
  }
24784
24797
  return inside ? -d : d;
@@ -27901,7 +27914,8 @@ var GameVehiclesThree = (() => {
27901
27914
  const tmp = new THREE.Box3();
27902
27915
  let pruned = 0;
27903
27916
  c.vehicle.updateMatrixWorld(true);
27904
- c.vehicle.traverse((o) => {
27917
+ c.vehicle.traverse((node) => {
27918
+ const o = node;
27905
27919
  if (!o.isMesh || o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
27906
27920
  for (let p = o; p; p = p.parent) if (p.visible === false) return;
27907
27921
  if (o.userData && (o.userData.ghost || o.userData.skipLite)) return;
@@ -28004,7 +28018,8 @@ var GameVehiclesThree = (() => {
28004
28018
  function count(root) {
28005
28019
  let triangles = 0;
28006
28020
  let drawCalls = 0;
28007
- root.traverse((o) => {
28021
+ root.traverse((node) => {
28022
+ const o = node;
28008
28023
  if (!o.isMesh || !o.geometry) return;
28009
28024
  for (let p = o; p; p = p.parent) if (p.visible === false) return;
28010
28025
  const g = o.geometry;
@@ -28019,7 +28034,8 @@ var GameVehiclesThree = (() => {
28019
28034
  let best = null;
28020
28035
  let bestCount = -1;
28021
28036
  const counts = /* @__PURE__ */ new Map();
28022
- c.vehicle.traverse((o) => {
28037
+ c.vehicle.traverse((node) => {
28038
+ const o = node;
28023
28039
  if (!o.isMesh || !o.geometry) return;
28024
28040
  const mats = Array.isArray(o.material) ? o.material : [o.material];
28025
28041
  const g = o.geometry;
@@ -28064,7 +28080,8 @@ var GameVehiclesThree = (() => {
28064
28080
  const bounds = new THREE.Box3();
28065
28081
  const piece = new THREE.Box3();
28066
28082
  const turned = new THREE.Matrix4();
28067
- c.vehicle.traverse((m) => {
28083
+ c.vehicle.traverse((node) => {
28084
+ const m = node;
28068
28085
  if (!m.isMesh || !m.geometry || m.userData.ghost) return;
28069
28086
  for (let p = m; p; p = p.parent) if (p.visible === false) return;
28070
28087
  m.geometry.computeBoundingBox();
@@ -28093,7 +28110,8 @@ var GameVehiclesThree = (() => {
28093
28110
  if (color2 && primary) {
28094
28111
  const repainted = primary.clone();
28095
28112
  repainted.color.set(color2);
28096
- c.vehicle.traverse((m) => {
28113
+ c.vehicle.traverse((node) => {
28114
+ const m = node;
28097
28115
  if (!m.isMesh) return;
28098
28116
  if (Array.isArray(m.material)) m.material = m.material.map((x) => x === primary ? repainted : x);
28099
28117
  else if (m.material === primary) m.material = repainted;
@@ -28129,7 +28147,8 @@ var GameVehiclesThree = (() => {
28129
28147
  context: quality === "high" ? c : null,
28130
28148
  driverEye,
28131
28149
  dispose() {
28132
- group.traverse((m) => {
28150
+ group.traverse((node) => {
28151
+ const m = node;
28133
28152
  if (m.geometry) m.geometry.dispose();
28134
28153
  });
28135
28154
  }
@@ -28151,7 +28170,7 @@ var GameVehiclesThree = (() => {
28151
28170
  }
28152
28171
  }
28153
28172
 
28154
- // ../game-shapes/dist/chunk-M5N2SHNL.js
28173
+ // ../game-shapes/dist/chunk-FZQTELDQ.js
28155
28174
  function canonicalJson(value) {
28156
28175
  if (value === null) return "null";
28157
28176
  if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
@@ -29027,17 +29046,19 @@ var GameVehiclesThree = (() => {
29027
29046
  if (p.prevZ) p.prevZ.nextZ = p.nextZ;
29028
29047
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
29029
29048
  }
29030
- function Node(i, x, y) {
29031
- this.i = i;
29032
- this.x = x;
29033
- this.y = y;
29034
- this.prev = null;
29035
- this.next = null;
29036
- this.z = 0;
29037
- this.prevZ = null;
29038
- this.nextZ = null;
29039
- this.steiner = false;
29040
- }
29049
+ var Node = class {
29050
+ constructor(i, x, y) {
29051
+ this.i = i;
29052
+ this.x = x;
29053
+ this.y = y;
29054
+ this.prev = null;
29055
+ this.next = null;
29056
+ this.z = 0;
29057
+ this.prevZ = null;
29058
+ this.nextZ = null;
29059
+ this.steiner = false;
29060
+ }
29061
+ };
29041
29062
  function signedArea(data, start2, end, dim) {
29042
29063
  let sum = 0;
29043
29064
  for (let i = start2, j = end - dim; i < end; i += dim) {
@@ -30188,10 +30209,11 @@ var GameVehiclesThree = (() => {
30188
30209
  return out;
30189
30210
  }
30190
30211
  function assignDeep(target, source) {
30212
+ const t = target;
30191
30213
  Object.keys(source || {}).forEach(function(k) {
30192
30214
  const v = source[k];
30193
- if (v && typeof v === "object" && !Array.isArray(v)) target[k] = assignDeep(target[k] && typeof target[k] === "object" ? target[k] : {}, v);
30194
- else if (v !== void 0) target[k] = v;
30215
+ if (v && typeof v === "object" && !Array.isArray(v)) t[k] = assignDeep(t[k] && typeof t[k] === "object" ? t[k] : {}, v);
30216
+ else if (v !== void 0) t[k] = v;
30195
30217
  });
30196
30218
  return target;
30197
30219
  }
@@ -30458,30 +30480,30 @@ var GameVehiclesThree = (() => {
30458
30480
  function makeFlatMaterial(color2, o) {
30459
30481
  return makeMaterial(color2, Object.assign({ flatShading: true, roughness: 0.92 }, o || {}));
30460
30482
  }
30461
- const DOUBLE_SIDE = THREE.DoubleSide;
30483
+ const DOUBLE_SIDE2 = THREE.DoubleSide;
30462
30484
  function toColor(hex) {
30463
30485
  return new THREE.Color(hex);
30464
30486
  }
30465
30487
  const MATERIALS = {
30466
30488
  trim: makeMaterial("#17191b", { roughness: 0.7 }),
30467
- rubber: makeMaterial("#111111", { roughness: 0.95, side: DOUBLE_SIDE }),
30489
+ rubber: makeMaterial("#111111", { roughness: 0.95, side: DOUBLE_SIDE2 }),
30468
30490
  chrome: makeMaterial("#b8bcbf", { metalness: 0.9, roughness: 0.28 }),
30469
30491
  steel: makeMaterial("#6c7175", { metalness: 0.7, roughness: 0.45 }),
30470
- glass: makeMaterial("#2a3c44", { roughness: 0.05, metalness: 0.25, transparent: true, opacity: 0.4, depthWrite: false, side: DOUBLE_SIDE }),
30471
- tint: makeMaterial("#121a1e", { roughness: 0.05, metalness: 0.3, transparent: true, opacity: 0.62, depthWrite: false, side: DOUBLE_SIDE }),
30492
+ glass: makeMaterial("#2a3c44", { roughness: 0.05, metalness: 0.25, transparent: true, opacity: 0.4, depthWrite: false, side: DOUBLE_SIDE2 }),
30493
+ tint: makeMaterial("#121a1e", { roughness: 0.05, metalness: 0.3, transparent: true, opacity: 0.62, depthWrite: false, side: DOUBLE_SIDE2 }),
30472
30494
  /* rear glass: darker, so the interior does not look like an open bed seen from behind */
30473
- rearTint: makeMaterial("#0c1114", { roughness: 0.04, metalness: 0.45, transparent: true, opacity: 0.84, depthWrite: false, side: DOUBLE_SIDE }),
30474
- glassDark: makeMaterial("#0c1317", { roughness: 0.06, metalness: 0.75, side: DOUBLE_SIDE }),
30475
- armorGlass: makeMaterial("#1d302d", { roughness: 0.08, metalness: 0.4, transparent: true, opacity: 0.6, depthWrite: false, side: DOUBLE_SIDE }),
30476
- glassEdge: makeMaterial("#a9bcc1", { roughness: 0.25, metalness: 0.1, transparent: true, opacity: 0.6, depthWrite: false, side: DOUBLE_SIDE }),
30495
+ rearTint: makeMaterial("#0c1114", { roughness: 0.04, metalness: 0.45, transparent: true, opacity: 0.84, depthWrite: false, side: DOUBLE_SIDE2 }),
30496
+ glassDark: makeMaterial("#0c1317", { roughness: 0.06, metalness: 0.75, side: DOUBLE_SIDE2 }),
30497
+ armorGlass: makeMaterial("#1d302d", { roughness: 0.08, metalness: 0.4, transparent: true, opacity: 0.6, depthWrite: false, side: DOUBLE_SIDE2 }),
30498
+ glassEdge: makeMaterial("#a9bcc1", { roughness: 0.25, metalness: 0.1, transparent: true, opacity: 0.6, depthWrite: false, side: DOUBLE_SIDE2 }),
30477
30499
  lens: makeMaterial("#eef3f5", { roughness: 0.03, metalness: 0.1, transparent: true, opacity: 0.16, depthWrite: false }),
30478
30500
  lensRed: makeMaterial("#c0281c", { roughness: 0.04, metalness: 0.1, transparent: true, opacity: 0.42, depthWrite: false }),
30479
30501
  lensAmber: makeMaterial("#d88a2a", { roughness: 0.04, transparent: true, opacity: 0.4, depthWrite: false }),
30480
30502
  housing: makeMaterial("#111214", { roughness: 0.45, metalness: 0.2 }),
30481
- reflector: makeMaterial("#dfe3e6", { metalness: 0.9, roughness: 0.12, side: DOUBLE_SIDE }),
30482
- reflectorLit: makeMaterial("#e8e2cc", { metalness: 0.6, roughness: 0.18, emissive: toColor("#cfc19a"), emissiveIntensity: 1.6, side: DOUBLE_SIDE }),
30483
- hole: makeMaterial("#040506", { roughness: 1, side: DOUBLE_SIDE }),
30484
- dark: makeMaterial("#0a0b0c", { roughness: 1, side: DOUBLE_SIDE }),
30503
+ reflector: makeMaterial("#dfe3e6", { metalness: 0.9, roughness: 0.12, side: DOUBLE_SIDE2 }),
30504
+ reflectorLit: makeMaterial("#e8e2cc", { metalness: 0.6, roughness: 0.18, emissive: toColor("#cfc19a"), emissiveIntensity: 1.6, side: DOUBLE_SIDE2 }),
30505
+ hole: makeMaterial("#040506", { roughness: 1, side: DOUBLE_SIDE2 }),
30506
+ dark: makeMaterial("#0a0b0c", { roughness: 1, side: DOUBLE_SIDE2 }),
30485
30507
  head: makeMaterial("#efe6c9", { emissive: toColor("#f0dcaa"), emissiveIntensity: 1.7, roughness: 0.2 }),
30486
30508
  led: makeMaterial("#e6f2ff", { emissive: toColor("#cfe6ff"), emissiveIntensity: 1.6, roughness: 0.2 }),
30487
30509
  tail: makeMaterial("#8a1a14", { emissive: toColor("#7a0d08"), emissiveIntensity: 0.8, roughness: 0.25 }),
@@ -30494,14 +30516,14 @@ var GameVehiclesThree = (() => {
30494
30516
  wood: makeMaterial("#6b4a2e", { roughness: 0.9 }),
30495
30517
  leather: makeMaterial("#4a2f20", { roughness: 0.7 }),
30496
30518
  seat: makeMaterial("#1e1f22", { roughness: 0.85 }),
30497
- alu: makeMaterial("#8e959a", { metalness: 0.6, roughness: 0.42, side: DOUBLE_SIDE }),
30519
+ alu: makeMaterial("#8e959a", { metalness: 0.6, roughness: 0.42, side: DOUBLE_SIDE2 }),
30498
30520
  carpet: makeMaterial("#141517", { roughness: 1 }),
30499
30521
  plastic: makeMaterial("#1f2023", { roughness: 0.75 }),
30500
- headliner: makeMaterial("#6f6c66", { roughness: 0.95, side: DOUBLE_SIDE }),
30522
+ headliner: makeMaterial("#6f6c66", { roughness: 0.95, side: DOUBLE_SIDE2 }),
30501
30523
  gauge: makeMaterial("#0d1512", { emissive: toColor("#4fbf8a"), emissiveIntensity: 0.35, roughness: 0.4 }),
30502
30524
  screen: makeMaterial("#0b1220", { emissive: toColor("#3d6cb0"), emissiveIntensity: 0.4, roughness: 0.2 }),
30503
- bay: makeMaterial("#2c3033", { roughness: 0.8, metalness: 0.2, emissive: toColor("#0c0e10"), emissiveIntensity: 1, side: DOUBLE_SIDE }),
30504
- hoodLiner: makeMaterial("#1c1d1e", { roughness: 0.95, side: DOUBLE_SIDE }),
30525
+ bay: makeMaterial("#2c3033", { roughness: 0.8, metalness: 0.2, emissive: toColor("#0c0e10"), emissiveIntensity: 1, side: DOUBLE_SIDE2 }),
30526
+ hoodLiner: makeMaterial("#1c1d1e", { roughness: 0.95, side: DOUBLE_SIDE2 }),
30505
30527
  block: makeMaterial("#a3abb0", { metalness: 0.55, roughness: 0.38, emissive: toColor("#1a1d1f"), emissiveIntensity: 1 }),
30506
30528
  cover: makeMaterial("#3c4044", { metalness: 0.4, roughness: 0.35, emissive: toColor("#101213"), emissiveIntensity: 1 }),
30507
30529
  radiator: makeMaterial("#3a3f42", { metalness: 0.5, roughness: 0.55 }),
@@ -30568,7 +30590,9 @@ var GameVehiclesThree = (() => {
30568
30590
  return t;
30569
30591
  }
30570
30592
  kit.textTexture = textTexture;
30571
- Object.assign(I, { RUST, cache: cache2, studioEnvironment, makeMaterial, makeFlatMaterial, DOUBLE_SIDE, toColor, MATERIALS, paintColor, texCache, textTexture });
30593
+ const shared2 = { RUST, cache: cache2, studioEnvironment, makeMaterial, makeFlatMaterial, DOUBLE_SIDE: DOUBLE_SIDE2, toColor, MATERIALS, paintColor, texCache, textTexture };
30594
+ Object.assign(I, shared2);
30595
+ return shared2;
30572
30596
  }
30573
30597
  var TRI_BLOCK = 32;
30574
30598
  var cache = /* @__PURE__ */ new WeakMap();
@@ -30721,7 +30745,8 @@ var GameVehiclesThree = (() => {
30721
30745
  }
30722
30746
  return s;
30723
30747
  }
30724
- function indexable(THREE, mesh2) {
30748
+ function indexable(THREE, object2) {
30749
+ const mesh2 = object2;
30725
30750
  const geo = mesh2.geometry;
30726
30751
  if (mesh2.raycast !== THREE.Mesh.prototype.raycast) return false;
30727
30752
  if (!mesh2.isMesh || mesh2.isSkinnedMesh || mesh2.isInstancedMesh || mesh2.isBatchedMesh || !geo || !geo.isBufferGeometry) return false;
@@ -31318,21 +31343,23 @@ var GameVehiclesThree = (() => {
31318
31343
  let wb = 0;
31319
31344
  segs.forEach(function(seg) {
31320
31345
  if (typeof seg[0] === "number") {
31346
+ const run = seg;
31321
31347
  for (let a = 0; a < names.length; a++) {
31322
31348
  const size = sizes[a];
31323
31349
  if (!idx) {
31324
- dst[a].set(arrs[a].subarray(seg[0] * 3 * size, seg[1] * 3 * size), w[a]);
31325
- w[a] += (seg[1] - seg[0]) * 3 * size;
31350
+ dst[a].set(arrs[a].subarray(run[0] * 3 * size, run[1] * 3 * size), w[a]);
31351
+ w[a] += (run[1] - run[0]) * 3 * size;
31326
31352
  continue;
31327
31353
  }
31328
- for (let f = seg[0] * 3; f < seg[1] * 3; f++) for (let q = 0; q < size; q++) dst[a][w[a]++] = arrs[a][idx[f] * size + q];
31354
+ for (let f = run[0] * 3; f < run[1] * 3; f++) for (let q = 0; q < size; q++) dst[a][w[a]++] = arrs[a][idx[f] * size + q];
31329
31355
  }
31330
31356
  if (boxesOut2 && ti) {
31331
- boxesOut2.set(ti.boxes.subarray(seg[0] * 6, seg[1] * 6), wb);
31332
- wb += (seg[1] - seg[0]) * 6;
31357
+ boxesOut2.set(ti.boxes.subarray(run[0] * 6, run[1] * 6), wb);
31358
+ wb += (run[1] - run[0]) * 6;
31333
31359
  }
31334
31360
  return;
31335
31361
  }
31362
+ ;
31336
31363
  seg.forEach(function(t) {
31337
31364
  if (boxesOut2) {
31338
31365
  for (let k = 0; k < 3; k++) {
@@ -31526,14 +31553,16 @@ var GameVehiclesThree = (() => {
31526
31553
  }
31527
31554
  };
31528
31555
  };
31529
- Object.assign(I, { roundedBoxGeometry, taper, subdivide, crease, creaseTask, refreshBounds, pathShape, tumble, loftGeometry, hullGeometry, cutGeometry, mergeGeometries, uvProject });
31556
+ const shared2 = { roundedBoxGeometry, taper, subdivide, crease, creaseTask, refreshBounds, pathShape, tumble, loftGeometry, hullGeometry, cutGeometry, mergeGeometries, uvProject };
31557
+ Object.assign(I, shared2);
31558
+ return shared2;
31530
31559
  }
31531
31560
  function installContext(kit) {
31532
31561
  const THREE = kit.THREE;
31533
31562
  const V3 = THREE.Vector3;
31534
31563
  const PI = Math.PI;
31535
31564
  const I = kit._;
31536
- const { makeMaterial, DOUBLE_SIDE, MATERIALS, crease, mergeGeometries, paintColor, roundedBoxGeometry, subdivide, taper, textTexture } = I;
31565
+ const { makeMaterial, DOUBLE_SIDE: DOUBLE_SIDE2, MATERIALS, crease, mergeGeometries, paintColor, roundedBoxGeometry, subdivide, taper, textTexture } = I;
31537
31566
  function resolveLabel(l) {
31538
31567
  if (l && typeof l === "object") return { key: l.key, label: l.label != null ? l.label : kit.t("parts." + l.key) };
31539
31568
  return { label: l };
@@ -31583,7 +31612,7 @@ var GameVehiclesThree = (() => {
31583
31612
  o = Object.assign({}, o || {});
31584
31613
  const matte = o.matte != null ? o.matte : this.meta.matte;
31585
31614
  delete o.matte;
31586
- const base = matte ? { roughness: this.state === "damaged" ? 0.92 : 0.82, metalness: 0.08, side: DOUBLE_SIDE } : { roughness: this.state === "damaged" ? 0.75 : 0.42, metalness: 0.3, side: DOUBLE_SIDE };
31615
+ const base = matte ? { roughness: this.state === "damaged" ? 0.92 : 0.82, metalness: 0.08, side: DOUBLE_SIDE2 } : { roughness: this.state === "damaged" ? 0.75 : 0.42, metalness: 0.3, side: DOUBLE_SIDE2 };
31587
31616
  const pm = makeMaterial(paintColor(hex, this.state), Object.assign(base, o));
31588
31617
  this.paints.add(pm);
31589
31618
  return pm;
@@ -31778,6 +31807,7 @@ var GameVehiclesThree = (() => {
31778
31807
  }
31779
31808
  kit.BuildContext = BuildContext;
31780
31809
  I.BuildContext = BuildContext;
31810
+ return { resolveLabel, BuildContext };
31781
31811
  }
31782
31812
  function installWarp(kit) {
31783
31813
  const THREE = kit.THREE;
@@ -31971,7 +32001,9 @@ var GameVehiclesThree = (() => {
31971
32001
  kit.applyWarp = applyWarp;
31972
32002
  kit.geo.resample = resample;
31973
32003
  kit.geo.smoothLoft = smoothLoft;
31974
- Object.assign(I, { makeWarp, applyWarp, resample, smoothLoft });
32004
+ const shared2 = { makeWarp, applyWarp, resample, smoothLoft };
32005
+ Object.assign(I, shared2);
32006
+ return shared2;
31975
32007
  }
31976
32008
  function installBody(kit) {
31977
32009
  const THREE = kit.THREE;
@@ -32035,23 +32067,24 @@ var GameVehiclesThree = (() => {
32035
32067
  o.arches.forEach(function(a) {
32036
32068
  const a0 = Math.asin(clamp((o.bottomY - a[1]) / a[2], -1, 1));
32037
32069
  const rr = a[2] - 0.01;
32070
+ const archInner = o.archInner;
32038
32071
  if (o.archInner == null) {
32039
32072
  const wl = c.add(new THREE.CylinderGeometry(rr, rr, o.W - 0.12, 20, 1, true, a0 + PI / 2, PI - 2 * a0), MATERIALS.dark, a[0], a[1], 0);
32040
32073
  wl.rotation.x = PI / 2;
32041
32074
  wl.castShadow = false;
32042
32075
  } else
32043
32076
  [1, -1].forEach(function(s) {
32044
- const len = o.W / 2 - 0.06 - o.archInner;
32077
+ const len = o.W / 2 - 0.06 - archInner;
32045
32078
  const w2 = c.add(
32046
32079
  new THREE.CylinderGeometry(rr, rr, len, 20, 1, true, a0 + PI / 2, PI - 2 * a0),
32047
32080
  MATERIALS.dark,
32048
32081
  a[0],
32049
32082
  a[1],
32050
- s * (o.archInner + len / 2)
32083
+ s * (archInner + len / 2)
32051
32084
  );
32052
32085
  w2.rotation.x = PI / 2;
32053
32086
  w2.castShadow = false;
32054
- const cap = c.add(new THREE.CircleGeometry(rr, 20, a0, PI - 2 * a0), MATERIALS.dark, a[0], a[1], s * o.archInner);
32087
+ const cap = c.add(new THREE.CircleGeometry(rr, 20, a0, PI - 2 * a0), MATERIALS.dark, a[0], a[1], s * archInner);
32055
32088
  cap.castShadow = false;
32056
32089
  });
32057
32090
  });
@@ -32128,8 +32161,12 @@ var GameVehiclesThree = (() => {
32128
32161
  if (!q.isMesh || !q.visible || q.userData.glass || q.userData.decal || q.isSprite) return;
32129
32162
  if (o.all || dset.has(q) || c.paints && c.paints.has(q.material)) cands.push(q);
32130
32163
  });
32131
- const d = (dir.isVector3 ? dir.clone() : new V3(dir[0], dir[1], dir[2])).normalize();
32132
- const p0 = org.isVector3 ? org.clone() : new V3(org[0], org[1], org[2]);
32164
+ const dv = dir;
32165
+ const da = dir;
32166
+ const d = (dv.isVector3 ? dv.clone() : new V3(da[0], da[1], da[2])).normalize();
32167
+ const ov = org;
32168
+ const oa = org;
32169
+ const p0 = ov.isVector3 ? ov.clone() : new V3(oa[0], oa[1], oa[2]);
32133
32170
  _sr.set(p0.clone().applyMatrix4(Mw), d.clone().transformDirection(Mw));
32134
32171
  _sr.near = 0;
32135
32172
  _sr.far = o.max || 20;
@@ -32146,14 +32183,17 @@ var GameVehiclesThree = (() => {
32146
32183
  const h = kit.surfaceAt(c, new V3(x0, y, z || 0), new V3(-sg, 0, 0));
32147
32184
  return h ? h.p.x : items ? profX(items, y, front !== false) : null;
32148
32185
  };
32149
- Object.assign(I, { halfAt, shell, autoWindows, profX, _sr });
32186
+ const shared2 = { halfAt, shell, autoWindows, profX, _sr };
32187
+ Object.assign(I, shared2);
32188
+ return shared2;
32150
32189
  }
32151
32190
  function installGlass(kit) {
32152
32191
  const THREE = kit.THREE;
32153
32192
  const V3 = THREE.Vector3;
32154
32193
  const I = kit._;
32155
32194
  const { MATERIALS, crease, cutGeometry, pathShape, subdivide, tumble, uvProject } = I;
32156
- I.paneSeals = /* @__PURE__ */ new WeakMap();
32195
+ const paneSeals = /* @__PURE__ */ new WeakMap();
32196
+ I.paneSeals = paneSeals;
32157
32197
  kit.addGlass = function(c, geo, label, type, o) {
32158
32198
  o = o || {};
32159
32199
  if (!geo.attributes.uv || o.reuv) o.aspect = uvProject(geo, o.uvAxes);
@@ -32250,7 +32290,7 @@ var GameVehiclesThree = (() => {
32250
32290
  };
32251
32291
  kit.quadDef = function(pb, pt, Wg, T, which, bev, o) {
32252
32292
  o = o || {};
32253
- bev = bev == null ? 0.05 : bev;
32293
+ const bv = bev == null ? 0.05 : bev;
32254
32294
  const dx = pt[0] - pb[0];
32255
32295
  const dy = pt[1] - pb[1];
32256
32296
  const L = Math.hypot(dx, dy);
@@ -32259,13 +32299,13 @@ var GameVehiclesThree = (() => {
32259
32299
  const nx = which === "front" ? uy : -uy;
32260
32300
  const ny = which === "front" ? -ux : ux;
32261
32301
  const ins = o.inset || 0.09;
32262
- const off = bev + 6e-3;
32302
+ const off = bv + 6e-3;
32263
32303
  const sd = o.side || 0.1;
32264
32304
  const b = [pb[0] + ux * ins + nx * off, pb[1] + uy * ins + ny * off];
32265
32305
  const t = [pt[0] - ux * ins * 1.3 + nx * off, pt[1] - uy * ins * 1.3 + ny * off];
32266
32306
  const hb = I.halfAt(Wg, T, b[1]) - sd;
32267
32307
  const ht = I.halfAt(Wg, T, t[1]) - sd;
32268
- return { pb, pt, L, u: [ux, uy], n: [nx, ny], ins, b, t, hb, ht, which, bev, Wg, T };
32308
+ return { pb, pt, L, u: [ux, uy], n: [nx, ny], ins, b, t, hb, ht, which, bev: bv, Wg, T };
32269
32309
  };
32270
32310
  kit.glassQuad = function(c, q, label, o) {
32271
32311
  o = o || {};
@@ -32319,7 +32359,9 @@ var GameVehiclesThree = (() => {
32319
32359
  c.quads.push(q);
32320
32360
  return m;
32321
32361
  };
32322
- Object.assign(I, {});
32362
+ const shared2 = { paneSeals };
32363
+ Object.assign(I, shared2);
32364
+ return shared2;
32323
32365
  }
32324
32366
  function installLights(kit) {
32325
32367
  const THREE = kit.THREE;
@@ -32654,7 +32696,9 @@ var GameVehiclesThree = (() => {
32654
32696
  if (o.emblem !== false) kit.emblem(c, 0.05, st === "closed" ? h * 0.12 : 0, 0, Math.min(0.05, h * 0.3), g);
32655
32697
  return g;
32656
32698
  };
32657
- Object.assign(I, { lampGroup, gm, wedgeY, haloTex, glowTexture, haloMats, halo, lampKit });
32699
+ const shared2 = { lampGroup, gm, wedgeY, haloTex, glowTexture, haloMats, halo, lampKit };
32700
+ Object.assign(I, shared2);
32701
+ return shared2;
32658
32702
  }
32659
32703
  function installInterior(kit) {
32660
32704
  const THREE = kit.THREE;
@@ -32904,7 +32948,9 @@ var GameVehiclesThree = (() => {
32904
32948
  c.roundBox(o.x0 - o.x1 + 1, 0.03, zi * 2, 0.01, MATERIALS.carpet, (o.x0 + o.x1) / 2, o.floor, 0);
32905
32949
  return n;
32906
32950
  };
32907
- Object.assign(I, { consoleBox });
32951
+ const shared2 = { consoleBox };
32952
+ Object.assign(I, shared2);
32953
+ return shared2;
32908
32954
  }
32909
32955
  var HOOD_LIFT = 8e-3;
32910
32956
  function installHood(kit) {
@@ -33297,7 +33343,9 @@ var GameVehiclesThree = (() => {
33297
33343
  };
33298
33344
  return out;
33299
33345
  };
33300
- Object.assign(I, {});
33346
+ const shared2 = {};
33347
+ Object.assign(I, shared2);
33348
+ return shared2;
33301
33349
  }
33302
33350
  function installCar(kit) {
33303
33351
  const THREE = kit.THREE;
@@ -33653,7 +33701,9 @@ var GameVehiclesThree = (() => {
33653
33701
  });
33654
33702
  return out;
33655
33703
  };
33656
- Object.assign(I, {});
33704
+ const shared2 = {};
33705
+ Object.assign(I, shared2);
33706
+ return shared2;
33657
33707
  }
33658
33708
  function installTrucks(kit) {
33659
33709
  const THREE = kit.THREE;
@@ -33796,7 +33846,9 @@ var GameVehiclesThree = (() => {
33796
33846
  m.rear = rear;
33797
33847
  m.length = L;
33798
33848
  };
33799
- Object.assign(I, {});
33849
+ const shared2 = {};
33850
+ Object.assign(I, shared2);
33851
+ return shared2;
33800
33852
  }
33801
33853
  function installWheels(kit) {
33802
33854
  const THREE = kit.THREE;
@@ -33933,7 +33985,9 @@ var GameVehiclesThree = (() => {
33933
33985
  c.part("track", kit.t("parts.track", { s: z > 0 ? 1 : -1 }), tm, new V3((x0 + x1) / 2, 0.3, z), 1.4);
33934
33986
  return { mesh: tm, wheels: gs, sprocket: spr, idler: idl };
33935
33987
  };
33936
- Object.assign(I, {});
33988
+ const shared2 = {};
33989
+ Object.assign(I, shared2);
33990
+ return shared2;
33937
33991
  }
33938
33992
  var ROUTED_PARTICLE_TYPES = { smoke: "particle_puff", dust: "particle_puff", fire: "particle_glow" };
33939
33993
  var PUFF_LOOKS = {
@@ -34358,7 +34412,7 @@ var GameVehiclesThree = (() => {
34358
34412
  }
34359
34413
  });
34360
34414
  }
34361
- Object.assign(I, {
34415
+ const shared2 = {
34362
34416
  PARTICLE_LIMIT,
34363
34417
  PARTICLE_GEOMETRIES,
34364
34418
  PARTICLE_MATERIALS,
@@ -34378,7 +34432,9 @@ var GameVehiclesThree = (() => {
34378
34432
  burst,
34379
34433
  exhaustLook,
34380
34434
  tickEmit
34381
- });
34435
+ };
34436
+ Object.assign(I, shared2);
34437
+ return shared2;
34382
34438
  }
34383
34439
  var PUDDLE_COLORS = {
34384
34440
  coolant: 3123279,
@@ -34393,7 +34449,7 @@ var GameVehiclesThree = (() => {
34393
34449
  const V3 = THREE.Vector3;
34394
34450
  const PI = Math.PI;
34395
34451
  const I = kit._;
34396
- const { DOUBLE_SIDE } = I;
34452
+ const { DOUBLE_SIDE: DOUBLE_SIDE2 } = I;
34397
34453
  kit.fluidTypes = {};
34398
34454
  kit.defineFluid = function(key, def) {
34399
34455
  const d = Object.assign({ dryTime: 600, roughFresh: 0.12, roughDry: 0.92, metalFresh: 0.15, metalDry: 0, wipeable: false }, def || {});
@@ -34414,7 +34470,7 @@ var GameVehiclesThree = (() => {
34414
34470
  color: fdef.freshC.clone(),
34415
34471
  roughness: fdef.roughFresh,
34416
34472
  metalness: fdef.metalFresh,
34417
- side: DOUBLE_SIDE,
34473
+ side: DOUBLE_SIDE2,
34418
34474
  polygonOffset: true,
34419
34475
  polygonOffsetFactor: -2,
34420
34476
  polygonOffsetUnits: -4
@@ -34672,7 +34728,7 @@ var GameVehiclesThree = (() => {
34672
34728
  metalness: 0.7,
34673
34729
  transparent: true,
34674
34730
  opacity: 0,
34675
- side: DOUBLE_SIDE,
34731
+ side: DOUBLE_SIDE2,
34676
34732
  depthWrite: false
34677
34733
  })
34678
34734
  );
@@ -34686,7 +34742,7 @@ var GameVehiclesThree = (() => {
34686
34742
  } else if (kind === "gasoline") {
34687
34743
  const haze = new THREE.Mesh(
34688
34744
  puddleGeometry(),
34689
- new THREE.MeshBasicMaterial({ color: 10465982, transparent: true, opacity: 0.035, depthWrite: false, side: DOUBLE_SIDE })
34745
+ new THREE.MeshBasicMaterial({ color: 10465982, transparent: true, opacity: 0.035, depthWrite: false, side: DOUBLE_SIDE2 })
34690
34746
  );
34691
34747
  haze.position.set(q.x, 0.22, q.z);
34692
34748
  haze.raycast = function() {
@@ -34850,7 +34906,9 @@ var GameVehiclesThree = (() => {
34850
34906
  }
34851
34907
  return n;
34852
34908
  };
34853
- Object.assign(I, { _fr, buildDrip, DOWNHILL, PN, puddleGeometry, rimGeometry, puddle, shapePuddle, updateFluids });
34909
+ const shared2 = { _fr, buildDrip, DOWNHILL, PN, puddleGeometry, rimGeometry, puddle, shapePuddle, updateFluids };
34910
+ Object.assign(I, shared2);
34911
+ return shared2;
34854
34912
  }
34855
34913
  function crackedGlassMaterial(THREE, texture) {
34856
34914
  return new THREE.MeshStandardMaterial({
@@ -35224,14 +35282,16 @@ var GameVehiclesThree = (() => {
35224
35282
  for (const h of L.halo ?? []) h.visible = false;
35225
35283
  }
35226
35284
  kit.crackLight = crackLight;
35227
- Object.assign(I, { glassUV, drawWeb, crackGlass, glassRim, shatterGlass, hitGlass, breakLight, crackLight });
35285
+ const shared2 = { glassUV, drawWeb, crackGlass, glassRim, shatterGlass, hitGlass, breakLight, crackLight };
35286
+ Object.assign(I, shared2);
35287
+ return shared2;
35228
35288
  }
35229
35289
  function installImpact(kit) {
35230
35290
  const THREE = kit.THREE;
35231
35291
  const V3 = THREE.Vector3;
35232
35292
  const PI = Math.PI;
35233
35293
  const I = kit._;
35234
- const { makeMaterial, DOUBLE_SIDE, crease, paintColor } = I;
35294
+ const { makeMaterial, DOUBLE_SIDE: DOUBLE_SIDE2, crease, paintColor } = I;
35235
35295
  function dentField(v, H) {
35236
35296
  const d = v.distanceTo(H.p);
35237
35297
  if (d >= H.R) return 0;
@@ -35580,7 +35640,7 @@ var GameVehiclesThree = (() => {
35580
35640
  I.burst(c, "scrap", pf, Math.round(force * 5), {
35581
35641
  dir: df,
35582
35642
  speed: 1.4,
35583
- mat: makeMaterial(paintColor(m.color || "#777", c.state), { roughness: 0.5, metalness: 0.3, side: DOUBLE_SIDE })
35643
+ mat: makeMaterial(paintColor(m.color || "#777", c.state), { roughness: 0.5, metalness: 0.3, side: DOUBLE_SIDE2 })
35584
35644
  });
35585
35645
  I.burst(c, "plastic", pf, 2, { dir: df, speed: 1.2 });
35586
35646
  }
@@ -35696,7 +35756,7 @@ var GameVehiclesThree = (() => {
35696
35756
  return hit;
35697
35757
  }
35698
35758
  kit.zoneImpact = zoneImpact;
35699
- Object.assign(I, {
35759
+ const shared2 = {
35700
35760
  dentField,
35701
35761
  hangBumper,
35702
35762
  tankFuel,
@@ -35712,14 +35772,16 @@ var GameVehiclesThree = (() => {
35712
35772
  _pr,
35713
35773
  probe,
35714
35774
  zoneImpact
35715
- });
35775
+ };
35776
+ Object.assign(I, shared2);
35777
+ return shared2;
35716
35778
  }
35717
35779
  function installExplosion(kit) {
35718
35780
  const THREE = kit.THREE;
35719
35781
  const V3 = THREE.Vector3;
35720
35782
  const PI = Math.PI;
35721
35783
  const I = kit._;
35722
- const { makeMaterial, DOUBLE_SIDE, MATERIALS, paintColor, textTexture } = I;
35784
+ const { makeMaterial, DOUBLE_SIDE: DOUBLE_SIDE2, MATERIALS, paintColor, textTexture } = I;
35723
35785
  const BURNT = ["#1d1a17", "#26211c", "#171514", "#2e2620"].map(function(h, i) {
35724
35786
  return makeMaterial(h, { roughness: 1, metalness: i === 3 ? 0.35 : 0.15 });
35725
35787
  });
@@ -35730,7 +35792,7 @@ var GameVehiclesThree = (() => {
35730
35792
  transparent: true,
35731
35793
  opacity: op,
35732
35794
  depthWrite: false,
35733
- side: DOUBLE_SIDE,
35795
+ side: DOUBLE_SIDE2,
35734
35796
  fog: false,
35735
35797
  blending: add2 ? THREE.AdditiveBlending : THREE.NormalBlending
35736
35798
  });
@@ -35918,7 +35980,7 @@ var GameVehiclesThree = (() => {
35918
35980
  I.burst(c, "scrap", cen, 14, {
35919
35981
  speed: 5,
35920
35982
  spread: 1.5,
35921
- mat: makeMaterial(paintColor(m.color || "#777", c.state), { roughness: 0.5, metalness: 0.3, side: DOUBLE_SIDE })
35983
+ mat: makeMaterial(paintColor(m.color || "#777", c.state), { roughness: 0.5, metalness: 0.3, side: DOUBLE_SIDE2 })
35922
35984
  });
35923
35985
  I.burst(c, "plastic", cen, 8, { speed: 4 });
35924
35986
  c.glass.slice().forEach(function(gm2) {
@@ -36095,7 +36157,9 @@ var GameVehiclesThree = (() => {
36095
36157
  }
36096
36158
  }
36097
36159
  }
36098
- Object.assign(I, { BURNT, BURNT_RUB, boomMat, enginePos, fling, burnAll, bigBoomFx, detonate, tickBoom, tickFlying });
36160
+ const shared2 = { BURNT, BURNT_RUB, boomMat, enginePos, fling, burnAll, bigBoomFx, detonate, tickBoom, tickFlying };
36161
+ Object.assign(I, shared2);
36162
+ return shared2;
36099
36163
  }
36100
36164
  function installRollover(kit) {
36101
36165
  const THREE = kit.THREE;
@@ -36295,7 +36359,8 @@ var GameVehiclesThree = (() => {
36295
36359
  c.parts.forEach(function(p) {
36296
36360
  if (p.kind !== "rotor" && p.kind !== "tail_rotor" || !p.obj) return;
36297
36361
  const main = p.kind === "rotor";
36298
- p.obj.traverse(function(o) {
36362
+ p.obj.traverse(function(node) {
36363
+ const o = node;
36299
36364
  if (!o.isMesh || !o.visible) return;
36300
36365
  const bb = new THREE.Box3().setFromObject(o).applyMatrix4(inv);
36301
36366
  if (!main && bb.min.y >= -0.01) return;
@@ -36367,7 +36432,9 @@ var GameVehiclesThree = (() => {
36367
36432
  if (p >= 1) finishRoll(c);
36368
36433
  }
36369
36434
  kit.rollContact = rollContact;
36370
- Object.assign(I, { rollMeshes, convexHull, rollContact, exactMinY, finishRoll, tickRoll });
36435
+ const shared2 = { rollMeshes, convexHull, rollContact, exactMinY, finishRoll, tickRoll };
36436
+ Object.assign(I, shared2);
36437
+ return shared2;
36371
36438
  }
36372
36439
  function installTick(kit) {
36373
36440
  const I = kit._;
@@ -36403,7 +36470,9 @@ var GameVehiclesThree = (() => {
36403
36470
  c.hood.target = open ? c.hood.open : 0;
36404
36471
  return true;
36405
36472
  };
36406
- Object.assign(I, {});
36473
+ const shared2 = {};
36474
+ Object.assign(I, shared2);
36475
+ return shared2;
36407
36476
  }
36408
36477
  function installArmor(kit) {
36409
36478
  const THREE = kit.THREE;
@@ -36653,7 +36722,9 @@ var GameVehiclesThree = (() => {
36653
36722
  }
36654
36723
  }
36655
36724
  kit.applyArmor = applyArmor;
36656
- Object.assign(I, { STEEL_MATERIAL, PLATE_MATERIALS, jerryCan, applyArmor });
36725
+ const shared2 = { STEEL_MATERIAL, PLATE_MATERIALS, jerryCan, applyArmor };
36726
+ Object.assign(I, shared2);
36727
+ return shared2;
36657
36728
  }
36658
36729
  function installZoneCore(kit) {
36659
36730
  const THREE = kit.THREE;
@@ -36670,8 +36741,8 @@ var GameVehiclesThree = (() => {
36670
36741
  return { id: b.id, name: kit.t("bands." + b.id), min: b.min, health: b.health, color: b.color };
36671
36742
  });
36672
36743
  function bandOf(h) {
36673
- h = Math.round(clamp(h == null ? 100 : h, 0, 100));
36674
- for (let i = 0; i < BANDS.length; i++) if (h >= BANDS[i].min) return i;
36744
+ const v = Math.round(clamp(h == null ? 100 : h, 0, 100));
36745
+ for (let i = 0; i < BANDS.length; i++) if (v >= BANDS[i].min) return i;
36675
36746
  return 4;
36676
36747
  }
36677
36748
  kit.bands = BANDS;
@@ -36697,8 +36768,12 @@ var GameVehiclesThree = (() => {
36697
36768
  z0: Math.min(b[4], b[5]),
36698
36769
  z1: Math.max(b[4], b[5])
36699
36770
  };
36700
- if (b.isBox3) return { x0: b.min.x, x1: b.max.x, y0: b.min.y, y1: b.max.y, z0: b.min.z, z1: b.max.z };
36701
- return { x0: b.x0, x1: b.x1, y0: b.y0, y1: b.y1, z0: b.z0, z1: b.z1 };
36771
+ if (b.isBox3) {
36772
+ const box2 = b;
36773
+ return { x0: box2.min.x, x1: box2.max.x, y0: box2.min.y, y1: box2.max.y, z0: box2.min.z, z1: box2.max.z };
36774
+ }
36775
+ const r = b;
36776
+ return { x0: r.x0, x1: r.x1, y0: r.y0, y1: r.y1, z0: r.z0, z1: r.z1 };
36702
36777
  }
36703
36778
  kit.normalizeBox = normalizeBox;
36704
36779
  function boxLo(B, a) {
@@ -36735,7 +36810,8 @@ var GameVehiclesThree = (() => {
36735
36810
  const bb = new THREE.Box3();
36736
36811
  const tmp = new THREE.Box3();
36737
36812
  const M = new THREE.Matrix4();
36738
- o.traverse(function(x) {
36813
+ o.traverse(function(node) {
36814
+ const x = node;
36739
36815
  if (!x.isMesh || !x.geometry || !x.geometry.attributes.position || x.userData.decal) return;
36740
36816
  if (!x.geometry.boundingBox) x.geometry.computeBoundingBox();
36741
36817
  tmp.copy(x.geometry.boundingBox).applyMatrix4(M.multiplyMatrices(inv, x.matrixWorld));
@@ -36801,7 +36877,7 @@ var GameVehiclesThree = (() => {
36801
36877
  for (let q = o; q && q !== c.vehicle; q = q.parent) if (q.visible === false) return false;
36802
36878
  return !!o;
36803
36879
  }
36804
- Object.assign(I, {
36880
+ const shared2 = {
36805
36881
  BANDS,
36806
36882
  bandOf,
36807
36883
  ZONE_WEIGHTS,
@@ -36824,16 +36900,18 @@ var GameVehiclesThree = (() => {
36824
36900
  lightBoxOf,
36825
36901
  hideObj,
36826
36902
  shown
36827
- });
36903
+ };
36904
+ Object.assign(I, shared2);
36905
+ return shared2;
36828
36906
  }
36829
36907
  function installZoneDecals(kit) {
36830
36908
  const THREE = kit.THREE;
36831
36909
  const V3 = THREE.Vector3;
36832
36910
  const PI = Math.PI;
36833
36911
  const I = kit._;
36834
- const { makeMaterial, DOUBLE_SIDE } = I;
36912
+ const { makeMaterial, DOUBLE_SIDE: DOUBLE_SIDE2 } = I;
36835
36913
  function dmat(hex, o) {
36836
- return makeMaterial(hex, Object.assign({ polygonOffset: true, polygonOffsetFactor: -2, polygonOffsetUnits: -3, side: DOUBLE_SIDE }, o || {}));
36914
+ return makeMaterial(hex, Object.assign({ polygonOffset: true, polygonOffsetFactor: -2, polygonOffsetUnits: -3, side: DOUBLE_SIDE2 }, o || {}));
36837
36915
  }
36838
36916
  const DAMAGE_MATERIALS = {
36839
36917
  /* without an environment map, high-metalness metal turns black and chipped paint looks like a bullet hole: light, barely metallic metal */
@@ -36851,7 +36929,7 @@ var GameVehiclesThree = (() => {
36851
36929
  transparent: true,
36852
36930
  opacity: 0.62,
36853
36931
  depthWrite: false,
36854
- side: DOUBLE_SIDE,
36932
+ side: DOUBLE_SIDE2,
36855
36933
  polygonOffset: true,
36856
36934
  polygonOffsetFactor: -2,
36857
36935
  polygonOffsetUnits: -3
@@ -37107,7 +37185,10 @@ var GameVehiclesThree = (() => {
37107
37185
  narrowTo(rc, q);
37108
37186
  }
37109
37187
  const hits = rc.intersectObjects(cands, false);
37110
- for (let i = 0; i < hits.length; i++) if (hits[i].object.proxyOf) hits[i].object = hits[i].object.proxyOf;
37188
+ for (let i = 0; i < hits.length; i++) {
37189
+ const proxyOf = hits[i].object.proxyOf;
37190
+ if (proxyOf) hits[i].object = proxyOf;
37191
+ }
37111
37192
  return hits;
37112
37193
  }
37113
37194
  function zoneCands(c, z, inv, glassToo) {
@@ -37308,7 +37389,7 @@ var GameVehiclesThree = (() => {
37308
37389
  for (i = 0; i < (spec.tear || 0); i++) if (s = nx()) tears.push(tearDecal(c, s.p, s.n, 0.07 + R() * 0.06, R, s.obj));
37309
37390
  return S;
37310
37391
  }
37311
- Object.assign(I, {
37392
+ const shared2 = {
37312
37393
  dmat,
37313
37394
  DAMAGE_MATERIALS,
37314
37395
  _zq,
@@ -37329,7 +37410,9 @@ var GameVehiclesThree = (() => {
37329
37410
  ribbonGeo,
37330
37411
  scratchDecal,
37331
37412
  zoneDecals
37332
- });
37413
+ };
37414
+ Object.assign(I, shared2);
37415
+ return shared2;
37333
37416
  }
37334
37417
  function installZoneDent(kit) {
37335
37418
  const THREE = kit.THREE;
@@ -37685,7 +37768,9 @@ var GameVehiclesThree = (() => {
37685
37768
  });
37686
37769
  return piv;
37687
37770
  }
37688
- Object.assign(I, { sm, subdivIn, dentTargets, zoneDent, cutPanel, pivotOf });
37771
+ const shared2 = { sm, subdivIn, dentTargets, zoneDent, cutPanel, pivotOf };
37772
+ Object.assign(I, shared2);
37773
+ return shared2;
37689
37774
  }
37690
37775
  function installDamagePanels(kit) {
37691
37776
  const THREE = kit.THREE;
@@ -38036,7 +38121,9 @@ var GameVehiclesThree = (() => {
38036
38121
  const sgn = new V3().crossVectors(axisV, tangent).dot(outv) > 0 ? 1 : -1;
38037
38122
  piv.quaternion.setFromAxisAngle(axisV, sgn * (0.6 + R() * 0.3));
38038
38123
  }
38039
- Object.assign(I, { panelBand, roofOff, tailOff, followersIn, windowsOver, doorGap, mirrorHang, doorHang, lidHang, flapHang });
38124
+ const shared2 = { panelBand, roofOff, tailOff, followersIn, windowsOver, doorGap, mirrorHang, doorHang, lidHang, flapHang };
38125
+ Object.assign(I, shared2);
38126
+ return shared2;
38040
38127
  }
38041
38128
  function installDamageParts(kit) {
38042
38129
  const THREE = kit.THREE;
@@ -38150,7 +38237,8 @@ var GameVehiclesThree = (() => {
38150
38237
  }
38151
38238
  function tireMeshes(w) {
38152
38239
  const out = [];
38153
- w.traverse(function(o) {
38240
+ w.traverse(function(node) {
38241
+ const o = node;
38154
38242
  if (o.isMesh && o.material === MATERIALS.rubber) out.push(o);
38155
38243
  });
38156
38244
  return out;
@@ -38209,7 +38297,8 @@ var GameVehiclesThree = (() => {
38209
38297
  c.zoneDrops.push({ x: w.position.x, z: w.position.z, d: r * 0.24 });
38210
38298
  } else if (b === 4) {
38211
38299
  let rr = 0;
38212
- w.traverse(function(o) {
38300
+ w.traverse(function(node) {
38301
+ const o = node;
38213
38302
  if (!o.isMesh || o.material === MATERIALS.rubber) return;
38214
38303
  if (!o.geometry.boundingSphere) o.geometry.computeBoundingSphere();
38215
38304
  const cc = o.geometry.boundingSphere.center.clone().applyMatrix4(o.matrix);
@@ -38417,7 +38506,8 @@ var GameVehiclesThree = (() => {
38417
38506
  const xf = H.x0 + (H.x1 - H.x0) * (0.5 + R() * 0.1);
38418
38507
  const k = 0.55 + R() * 0.2;
38419
38508
  const v = new V3();
38420
- H.piv.children.forEach(function(msh) {
38509
+ H.piv.children.forEach(function(node) {
38510
+ const msh = node;
38421
38511
  if (!msh.isMesh) return;
38422
38512
  msh.updateMatrix();
38423
38513
  const M = msh.matrix;
@@ -38610,7 +38700,7 @@ var GameVehiclesThree = (() => {
38610
38700
  });
38611
38701
  void K;
38612
38702
  }
38613
- Object.assign(I, {
38703
+ const shared2 = {
38614
38704
  glassPt,
38615
38705
  glassIn,
38616
38706
  glassBand,
@@ -38628,7 +38718,9 @@ var GameVehiclesThree = (() => {
38628
38718
  bumperBand,
38629
38719
  partBand,
38630
38720
  bendAft
38631
- });
38721
+ };
38722
+ Object.assign(I, shared2);
38723
+ return shared2;
38632
38724
  }
38633
38725
  function installZoneDerive(kit) {
38634
38726
  const THREE = kit.THREE;
@@ -38649,7 +38741,8 @@ var GameVehiclesThree = (() => {
38649
38741
  }
38650
38742
  function resolveObjs(c, list2, z) {
38651
38743
  const out = [];
38652
- (list2 || []).forEach(function(o) {
38744
+ (list2 || []).forEach(function(item) {
38745
+ const o = item;
38653
38746
  if (!o) return;
38654
38747
  if (typeof o === "string") {
38655
38748
  c.parts.forEach(function(p) {
@@ -38898,7 +38991,9 @@ var GameVehiclesThree = (() => {
38898
38991
  return null;
38899
38992
  }
38900
38993
  kit.zoneOwner = ownerOf;
38901
- Object.assign(I, { parseDir, resolveObjs, deriveZones, carMap, zonesOf, ownerOf });
38994
+ const shared2 = { parseDir, resolveObjs, deriveZones, carMap, zonesOf, ownerOf };
38995
+ Object.assign(I, shared2);
38996
+ return shared2;
38902
38997
  }
38903
38998
  var REAR_GLASS_KEYS = ["rear_window", "window_rear", "quarter_glass"];
38904
38999
  function installZoneAuto(kit) {
@@ -39691,7 +39786,9 @@ var GameVehiclesThree = (() => {
39691
39786
  if (!wheelsDone) wheelZones(false);
39692
39787
  return Z;
39693
39788
  }
39694
- Object.assign(I, { autoZones });
39789
+ const shared2 = { autoZones };
39790
+ Object.assign(I, shared2);
39791
+ return shared2;
39695
39792
  }
39696
39793
  function installZoneApply(kit) {
39697
39794
  const THREE = kit.THREE;
@@ -39900,7 +39997,9 @@ var GameVehiclesThree = (() => {
39900
39997
  c.rand = R0;
39901
39998
  return c.zoneState;
39902
39999
  };
39903
- Object.assign(I, { fadePaint, abandonFx, burntFx, settleDrops });
40000
+ const shared2 = { fadePaint, abandonFx, burntFx, settleDrops };
40001
+ Object.assign(I, shared2);
40002
+ return shared2;
39904
40003
  }
39905
40004
  function installScenarios(kit) {
39906
40005
  const THREE = kit.THREE;
@@ -40055,7 +40154,9 @@ var GameVehiclesThree = (() => {
40055
40154
  }
40056
40155
  return { p, dir };
40057
40156
  };
40058
- Object.assign(I, { BODY_TYPES });
40157
+ const shared2 = { BODY_TYPES };
40158
+ Object.assign(I, shared2);
40159
+ return shared2;
40059
40160
  }
40060
40161
  var SVGNS = "http://www.w3.org/2000/svg";
40061
40162
  var BAND_TEXT = ["#10140f", "#1c1606", "#1f1206", "#fff3ef", "#f1f2f2"];
@@ -40210,7 +40311,8 @@ var GameVehiclesThree = (() => {
40210
40311
  }
40211
40312
  g.addEventListener("click", pick);
40212
40313
  g.addEventListener("keydown", function(e) {
40213
- if (e.key === "Enter" || e.key === " ") {
40314
+ const key = e.key;
40315
+ if (key === "Enter" || key === " ") {
40214
40316
  e.preventDefault();
40215
40317
  pick();
40216
40318
  }
@@ -40223,7 +40325,7 @@ var GameVehiclesThree = (() => {
40223
40325
  return kit.bands.map(function(B, i) {
40224
40326
  const b = el("button", null, B.name);
40225
40327
  b.type = "button";
40226
- b.dataset.b = i;
40328
+ b.dataset.b = String(i);
40227
40329
  b.style.setProperty("--band", B.color);
40228
40330
  b.addEventListener("click", function() {
40229
40331
  if (onPick) onPick(B.health, i);
@@ -40445,6 +40547,7 @@ var GameVehiclesThree = (() => {
40445
40547
  hash,
40446
40548
  clamp,
40447
40549
  smooth,
40550
+ // filled by the modules below, each with the helpers it shares
40448
40551
  _: {}
40449
40552
  };
40450
40553
  kit.fuels = {};
@@ -40522,8 +40625,8 @@ var GameVehiclesThree = (() => {
40522
40625
  fn.apply(kit, args);
40523
40626
  });
40524
40627
  };
40525
- kit.configure = function(o) {
40526
- o = o || {};
40628
+ kit.configure = function(cfg) {
40629
+ const o = cfg || {};
40527
40630
  if (o.bands)
40528
40631
  o.bands.forEach(function(b, i) {
40529
40632
  if (kit.bands[i] && b) Object.assign(kit.bands[i], b);
@@ -40559,7 +40662,8 @@ var GameVehiclesThree = (() => {
40559
40662
  }
40560
40663
  ;
40561
40664
  ["impactStain", "defaultSplat", "defaultGroup", "damagedScenario"].forEach(function(k) {
40562
- if (o[k] !== void 0) kit.config[k] = o[k];
40665
+ const v = o[k];
40666
+ if (v !== void 0) kit.config[k] = v;
40563
40667
  });
40564
40668
  return kit;
40565
40669
  };
@@ -44309,7 +44413,7 @@ var GameVehiclesThree = (() => {
44309
44413
  };
44310
44414
  }
44311
44415
 
44312
- // ../game-audio/dist/chunk-C2K7XN2K.js
44416
+ // ../game-audio/dist/chunk-UUWKSG4J.js
44313
44417
  var DISTANCE_CURVES = {
44314
44418
  /** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
44315
44419
  game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
@@ -45144,6 +45248,66 @@ var GameVehiclesThree = (() => {
45144
45248
  duration: 0.09,
45145
45249
  layers: [{ source: { kind: "osc", wave: "sine", frequency: { set: 2300 } }, envelope: [[0, 0.07, "set"], [0.08, 1e-4, "exp", "fixed"]] }],
45146
45250
  falloff: { model: "none" }
45251
+ },
45252
+ {
45253
+ // an emergency siren's wail: a tone rising and falling slowly (one sweep about every 3 s), played again by the cabin as it ends
45254
+ id: "siren_wail",
45255
+ bus: "world",
45256
+ order: "siren",
45257
+ duration: 3,
45258
+ tail: 0.05,
45259
+ layers: [
45260
+ {
45261
+ source: { kind: "osc", wave: "sawtooth", frequency: { set: 1050 } },
45262
+ modulators: [{ target: "frequency", wave: "sine", rate: 0.33, depth: 420 }],
45263
+ filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 2400 } }] },
45264
+ envelope: [[0, 1e-4, "set", "fixed"], [0.08, 0.07, "linear"], [2.95, 0.07, "set"], [3, 1e-4, "exp", "fixed"]]
45265
+ }
45266
+ ],
45267
+ falloff: { model: "none" }
45268
+ },
45269
+ {
45270
+ // the yelp: the same tone swept fast, for a junction
45271
+ id: "siren_yelp",
45272
+ bus: "world",
45273
+ order: "siren",
45274
+ duration: 2,
45275
+ tail: 0.05,
45276
+ layers: [
45277
+ {
45278
+ source: { kind: "osc", wave: "sawtooth", frequency: { set: 1100 } },
45279
+ modulators: [{ target: "frequency", wave: "triangle", rate: 4, depth: 380 }],
45280
+ filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 2600 } }] },
45281
+ envelope: [[0, 1e-4, "set", "fixed"], [0.05, 0.07, "linear"], [1.95, 0.07, "set"], [2, 1e-4, "exp", "fixed"]]
45282
+ }
45283
+ ],
45284
+ falloff: { model: "none" }
45285
+ },
45286
+ {
45287
+ // the wires under the column touching: a crackle of bright noise
45288
+ id: "hotwire_spark",
45289
+ bus: "world",
45290
+ duration: 0.12,
45291
+ layers: [
45292
+ {
45293
+ source: { kind: "noise", offset: "random" },
45294
+ filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3200 } }] },
45295
+ modulators: [{ target: "gain", wave: "square", rate: 60, depth: 0.1, base: 0.12 }],
45296
+ envelope: [[0, 0.2, "set"], [0.12, 1e-4, "exp", "fixed"]]
45297
+ }
45298
+ ],
45299
+ falloff: { model: "none" }
45300
+ },
45301
+ {
45302
+ // the glovebox latch: a small plastic click and the lid dropping
45303
+ id: "glovebox_latch",
45304
+ bus: "world",
45305
+ duration: 0.14,
45306
+ layers: [
45307
+ { source: { kind: "noise", offset: "random" }, filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: 1800 }, q: 2 }] }, envelope: [[0, 0.16, "set"], [0.03, 1e-4, "exp", "fixed"]] },
45308
+ { source: { kind: "osc", wave: "triangle", frequency: { set: 240 } }, envelope: [[0, 1e-4, "set", "fixed"], [0.06, 0.08, "linear"], [0.14, 1e-4, "exp", "fixed"]] }
45309
+ ],
45310
+ falloff: { model: "none" }
45147
45311
  }
45148
45312
  ];
45149
45313
  var CABIN_BANK = { id: "vehicle_cabin", sounds: CABIN_SOUNDS, loops: [] };
@@ -45995,7 +46159,11 @@ var GameVehiclesThree = (() => {
45995
46159
  crashHeavy: "crash_heavy",
45996
46160
  skidAsphalt: "tire_skid_asphalt",
45997
46161
  skidDirt: "tire_skid_dirt",
45998
- roll: "tire_roll"
46162
+ roll: "tire_roll",
46163
+ brakeSqueal: "brake_squeal",
46164
+ hitBody: "vehicle_hit_pedestrian",
46165
+ siren: "siren",
46166
+ rotor: "helicopter_rotor_loop"
45999
46167
  };
46000
46168
  var CRASH_SPEEDS = { medium: 6, heavy: 14 };
46001
46169
  var layers = (id, cutoffs, gains) => [
@@ -46074,7 +46242,16 @@ var GameVehiclesThree = (() => {
46074
46242
  ...engineLoops("bike", 600, 1400, 2800, 1200),
46075
46243
  noiseLoop("tire_skid_asphalt", "bandpass", 1900, 5, "rubber squealing on asphalt: a narrow band of noise near 2 kHz"),
46076
46244
  noiseLoop("tire_skid_dirt", "lowpass", 700, 0.8, "tyres sliding on dirt and gravel: a dull, wide hiss"),
46077
- noiseLoop("tire_roll", "lowpass", 400, 0.7, "road noise of the tyres rolling, brighter with the speed")
46245
+ noiseLoop("tire_roll", "lowpass", 400, 0.7, "road noise of the tyres rolling, brighter with the speed"),
46246
+ // a pad on a disc: a thin, nearly pure whistle near 3.4 kHz (a narrow band of noise, so it wavers as a real squeal does)
46247
+ // a siren: a square through a low-pass, its pitch swept by the vehicle every frame (wail: a slow rise and fall; yelp: a fast one)
46248
+ toneLoop("siren", "square", "lowpass", 2600, 0.8, "emergency siren, the sweep driven by the vehicle"),
46249
+ // the blades: a low rumble chopped at the blade-pass rate (≈ 18 Hz for a light helicopter's main rotor)
46250
+ {
46251
+ ...noiseLoop("helicopter_rotor_loop", "lowpass", 320, 0.9, "helicopter rotor: low rumble chopped by the blades"),
46252
+ modulators: [{ target: "gain", wave: "sine", rate: 18, depth: 0.45, base: 0.55 }]
46253
+ },
46254
+ noiseLoop("brake_squeal", "bandpass", 3400, 28, "brake pads squealing on the discs as the car comes to a stop")
46078
46255
  ];
46079
46256
  var recipe2 = (id, layers2, line) => ({ ...sceneRecipe(id, layers2, line), sources: [SDK, line] });
46080
46257
  var crank = (count2, spacing) => [
@@ -46118,6 +46295,17 @@ var GameVehiclesThree = (() => {
46118
46295
  ],
46119
46296
  "crash above 50 km/h: metal folding, the glass going, debris falling"
46120
46297
  ),
46298
+ // a body hit by a car: the dull slap of the bumper on a person, the body folding over the bonnet, at speed a crack of the windscreen
46299
+ recipe2(
46300
+ "vehicle_hit_pedestrian",
46301
+ [
46302
+ sceneTone({ f: 95, f2: 50, d: 0.14, vol: 0.9 }),
46303
+ sceneNoise({ type: "lowpass", f: 600, d: 0.12, vol: 0.8 }),
46304
+ sceneNoise({ type: "bandpass", f: 280, q: 1.2, d: 0.18, vol: 0.55, delay: 0.09 }),
46305
+ sceneNoise({ type: "highpass", f: 2600, d: 0.05, vol: 0.18, delay: 0.1 })
46306
+ ],
46307
+ "a person hit by a car: the bumper slap, the body on the bonnet"
46308
+ ),
46121
46309
  // the game's horn (two squares at 415 and 523 Hz, jogo L70272) heard from where the car is; a truck's air horn lower and longer
46122
46310
  recipe2("horn_car", [sceneTone({ wave: "square", f: 415, d: 0.6, vol: 0.09 }), sceneTone({ wave: "square", f: 523, d: 0.6, vol: 0.09 })], "car horn: the game chord, placed and panned"),
46123
46311
  recipe2("horn_truck", [sceneTone({ wave: "sawtooth", f: 220, d: 1.1, vol: 0.1 }), sceneTone({ wave: "sawtooth", f: 277, d: 1.1, vol: 0.08 }), sceneNoise({ type: "bandpass", f: 900, q: 2, d: 1.1, vol: 0.05 })], "truck air horn: low reedy chord"),
@@ -46129,6 +46317,8 @@ var GameVehiclesThree = (() => {
46129
46317
  ];
46130
46318
  var CAR_RECORDED_RPM = { idle: 1e3, high: 2520 };
46131
46319
  var CAR_START_RUN_STOP = {
46320
+ /** The take the times below were measured on. */
46321
+ take: "_01.",
46132
46322
  /** The starter and the engine catching (at 0.58 s) and flaring; the loops take over at the crank time of the vehicle. */
46133
46323
  start: { offset: 0, duration: 1.3 },
46134
46324
  /** The ignition off: the engine running down to the end of the file. */
@@ -46148,13 +46338,42 @@ var GameVehiclesThree = (() => {
46148
46338
  carLayer("engine_car_mid", "engine_loop_car_high", CAR_RECORDED_RPM.high, 1),
46149
46339
  // the same file as the mid layer, read from two seconds in, so the two do not sum in phase where they cross
46150
46340
  carLayer("engine_car_high", "engine_loop_car_high", CAR_RECORDED_RPM.high, 2, 2),
46151
- { id: "engine_start", file: "engine_start_run_stop", ...CAR_START_RUN_STOP.start, falloff: VEHICLE_LOOP_FALLOFF },
46152
- { id: "engine_stop", file: "engine_start_run_stop", ...CAR_START_RUN_STOP.stop, falloff: VEHICLE_LOOP_FALLOFF },
46341
+ // the cut points are of take _01 (10.6 s); _02 (21.9 s) starts already running and idles at 9.96 s, so it is left out of both
46342
+ { id: "engine_start", file: "engine_start_run_stop", only: CAR_START_RUN_STOP.take, ...CAR_START_RUN_STOP.start, falloff: VEHICLE_LOOP_FALLOFF },
46343
+ { id: "engine_stop", file: "engine_start_run_stop", only: CAR_START_RUN_STOP.take, ...CAR_START_RUN_STOP.stop, falloff: VEHICLE_LOOP_FALLOFF },
46153
46344
  { id: "car_door_close", file: "car_door_shut" },
46154
46345
  { id: "car_trunk_close", file: "car_trunk_shut" }
46155
46346
  ];
46347
+ var VEHICLE_PRELOAD_SOUNDS = [...VEHICLE_SAMPLE_ALIASES.map((alias) => alias.id), "car_door_open"];
46156
46348
  var VEHICLE_SOUND_BANK = { id: "vehicles_three", sounds: VEHICLE_SOUNDS, loops: VEHICLE_LOOPS, sampleAliases: VEHICLE_SAMPLE_ALIASES };
46157
46349
 
46350
+ // src/audio/engine-budget.ts
46351
+ var distanceSq = (a, b) => (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + (a[2] - b[2]) ** 2;
46352
+ function createEngineBudget(options) {
46353
+ const max = Math.max(1, options.max ?? 6);
46354
+ const places = /* @__PURE__ */ new Map();
46355
+ return {
46356
+ admit(vehicle, position) {
46357
+ const own = distanceSq(position, options.listener());
46358
+ places.set(vehicle, own);
46359
+ if (places.size <= max) return true;
46360
+ let nearer = 0;
46361
+ for (const [other, d] of places) {
46362
+ if (other === vehicle) continue;
46363
+ if (d < own) nearer++;
46364
+ if (nearer >= max) return false;
46365
+ }
46366
+ return true;
46367
+ },
46368
+ release(vehicle) {
46369
+ places.delete(vehicle);
46370
+ },
46371
+ get size() {
46372
+ return places.size;
46373
+ }
46374
+ };
46375
+ }
46376
+
46158
46377
  // src/audio/vehicle-sound.ts
46159
46378
  var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
46160
46379
  function createVehicleSound(audio, options = {}) {
@@ -46163,8 +46382,10 @@ var GameVehiclesThree = (() => {
46163
46382
  const crankSeconds = options.crankSeconds ?? 0.75;
46164
46383
  const gears = createGearGuess(profile);
46165
46384
  const loops = /* @__PURE__ */ new Map();
46385
+ const budget = options.budget;
46386
+ const self = {};
46166
46387
  const levels = {};
46167
- const state = { running: false, cranking: 0, catches: false, flare: 0, rpm: 0 };
46388
+ const state = { running: false, cranking: 0, catches: false, flare: 0, rpm: 0, sirenPhase: 0 };
46168
46389
  const loopOf = (sound) => {
46169
46390
  let handle = loops.get(sound);
46170
46391
  if (!handle && audio?.loop) {
@@ -46198,6 +46419,11 @@ var GameVehiclesThree = (() => {
46198
46419
  play(kind === "heavy" ? keys.crashHeavy : kind === "medium" ? keys.crashMedium : keys.crashLight, position, Math.min(1, 0.35 + v / 20));
46199
46420
  return kind;
46200
46421
  },
46422
+ hit(speed, position, sound) {
46423
+ const v = Math.abs(speed);
46424
+ if (v < 0.5) return;
46425
+ play(sound ?? keys.hitBody, position, Math.min(1, 0.3 + v / 15));
46426
+ },
46201
46427
  update(frame) {
46202
46428
  if (state.cranking > 0) {
46203
46429
  state.cranking -= frame.dt;
@@ -46211,20 +46437,33 @@ var GameVehiclesThree = (() => {
46211
46437
  const driven = frame.rpm ?? gears.rpm(frame.speed, throttle);
46212
46438
  const rpm = state.running ? Math.max(driven, profile.idleRpm * (1 + 1.2 * state.flare * state.flare)) : 0;
46213
46439
  state.rpm = rpm;
46440
+ const heard = budget ? budget.admit(self, frame.position) ? 1 : 0 : 1;
46214
46441
  for (const layer2 of engineMix(profile, { rpm, throttle: Math.max(throttle, state.flare * 0.6) })) {
46215
- setLoop(layer2.sound, layer2.volume, frame.position, { ...layer2.frequency === void 0 ? {} : { frequency: layer2.frequency }, cutoff: layer2.cutoff });
46442
+ setLoop(layer2.sound, heard * layer2.volume, frame.position, { ...layer2.frequency === void 0 ? {} : { frequency: layer2.frequency }, cutoff: layer2.cutoff });
46216
46443
  }
46217
46444
  const speed = Math.abs(frame.speed);
46218
46445
  const slide = clamp012(((frame.slip ?? 0) - 0.15) / 0.5) * clamp012(speed / 4);
46219
46446
  const dirt = frame.surface === "dirt";
46220
- setLoop(keys.skidAsphalt, dirt ? 0 : 0.16 * slide, frame.position, { cutoff: 1700 + 600 * slide });
46221
- setLoop(keys.skidDirt, dirt ? 0.2 * slide : 0, frame.position, { cutoff: 500 + 500 * slide });
46222
- setLoop(keys.roll, 0.06 * clamp012(speed / 25), frame.position, { cutoff: 250 + 45 * Math.min(speed, 40) });
46447
+ setLoop(keys.skidAsphalt, heard * (dirt ? 0 : 0.16 * slide), frame.position, { cutoff: 1700 + 600 * slide });
46448
+ setLoop(keys.skidDirt, heard * (dirt ? 0.2 * slide : 0), frame.position, { cutoff: 500 + 500 * slide });
46449
+ setLoop(keys.roll, heard * 0.06 * clamp012(speed / 25), frame.position, { cutoff: 250 + 45 * Math.min(speed, 40) });
46450
+ const squeal = clamp012(((frame.brake ?? 0) - 0.3) / 0.4) * clamp012(speed / 0.8) * clamp012((5 - speed) / 2) * (slide > 0 ? 0 : 1);
46451
+ setLoop(keys.brakeSqueal, heard * 0.05 * squeal, frame.position, { cutoff: 3200 + 400 * squeal });
46452
+ const siren = frame.siren ?? "off";
46453
+ if (siren !== "off" || loops.has(keys.siren)) {
46454
+ const period = siren === "yelp" ? 0.25 : 4;
46455
+ state.sirenPhase = (state.sirenPhase + frame.dt / period) % 1;
46456
+ const tri = state.sirenPhase < 0.5 ? state.sirenPhase * 2 : 2 - state.sirenPhase * 2;
46457
+ setLoop(keys.siren, heard * (siren === "off" ? 0 : 0.07), frame.position, { frequency: 650 + 850 * tri, cutoff: 2600 });
46458
+ }
46459
+ const rotor = clamp012(frame.rotor ?? 0);
46460
+ setLoop(keys.rotor, heard * 0.12 * rotor, frame.position, { cutoff: 180 + 220 * rotor });
46223
46461
  },
46224
46462
  get reading() {
46225
46463
  return { running: state.running, rpm: state.rpm, levels: { ...levels } };
46226
46464
  },
46227
46465
  dispose() {
46466
+ budget?.release(self);
46228
46467
  for (const handle of loops.values()) handle.stop();
46229
46468
  loops.clear();
46230
46469
  }
@@ -46955,6 +47194,7 @@ var GameVehiclesThree = (() => {
46955
47194
  clutch: ["KeyC"],
46956
47195
  flash: ["KeyX"],
46957
47196
  washer: ["KeyZ"],
47197
+ hotwire: ["KeyI"],
46958
47198
  ignition: ["KeyI"],
46959
47199
  gearbox: ["KeyM"],
46960
47200
  gear_up: ["KeyE"],
@@ -46980,9 +47220,12 @@ var GameVehiclesThree = (() => {
46980
47220
  abs: ["Digit9"],
46981
47221
  cruise: ["Digit0"],
46982
47222
  climate: ["Minus"],
46983
- demist: ["Equal"]
47223
+ demist: ["Equal"],
47224
+ siren: ["Semicolon"],
47225
+ beacon: ["Quote"],
47226
+ glovebox: ["Slash"]
46984
47227
  };
46985
- var HELD_KEYS = ["throttle", "brake", "left", "right", "handbrake", "horn", "clutch", "flash", "washer"];
47228
+ var HELD_KEYS = ["throttle", "brake", "left", "right", "handbrake", "horn", "clutch", "flash", "washer", "hotwire"];
46986
47229
  function createVehicleControls(options) {
46987
47230
  const keys = { ...DEFAULT_CONTROL_KEYS, ...options.keys };
46988
47231
  const auto4 = options.autoFourWheel ?? { slip: 0.18, releaseSeconds: 2 };
@@ -47017,8 +47260,17 @@ var GameVehiclesThree = (() => {
47017
47260
  abs: true,
47018
47261
  cruise: { on: false, speed: 0 },
47019
47262
  climate: { on: false, demist: false },
47020
- cranking: false
47021
- };
47263
+ cranking: false,
47264
+ hotwire: { progress: 0, done: false },
47265
+ siren: "off",
47266
+ beacon: false,
47267
+ beaconSide: 0,
47268
+ glovebox: false
47269
+ };
47270
+ const hasKey = options.hasKey !== false;
47271
+ const hotwireSeconds = Math.max(0.1, options.hotwireSeconds ?? 8);
47272
+ const beaconHz = options.beaconHz ?? 2.5;
47273
+ let beaconClock = 0;
47022
47274
  let crankAsked = false;
47023
47275
  let lastSpeed = 0;
47024
47276
  let engineRunning = !!options.running;
@@ -47035,9 +47287,11 @@ var GameVehiclesThree = (() => {
47035
47287
  const MODES = ["4x2", "4x4", "auto"];
47036
47288
  const WIPERS = ["off", "intermittent", "slow", "fast"];
47037
47289
  const PROFILES = ["eco", "normal", "sport"];
47290
+ const SIRENS = ["off", "wail", "yelp"];
47038
47291
  const command = (c) => {
47039
47292
  switch (c) {
47040
47293
  case "ignition":
47294
+ if (!hasKey && !state.hotwire.done) return emit({ type: "refused", command: c, reason: "no_key" });
47041
47295
  state.ignition = !state.ignition;
47042
47296
  if (state.ignition && state.alarm !== "off") state.alarm = "off";
47043
47297
  if (state.ignition) crankAsked = true;
@@ -47131,6 +47385,20 @@ var GameVehiclesThree = (() => {
47131
47385
  case "seatbelt":
47132
47386
  state.seatbelt = !state.seatbelt;
47133
47387
  break;
47388
+ case "siren":
47389
+ if (!options.emergency) return emit({ type: "refused", command: c, reason: "no_siren" });
47390
+ state.siren = SIRENS[(SIRENS.indexOf(state.siren) + 1) % SIRENS.length];
47391
+ if (state.siren !== "off") state.beacon = true;
47392
+ break;
47393
+ case "beacon":
47394
+ if (!options.emergency) return emit({ type: "refused", command: c, reason: "no_siren" });
47395
+ state.beacon = !state.beacon;
47396
+ if (!state.beacon) state.siren = "off";
47397
+ beaconClock = 0;
47398
+ break;
47399
+ case "glovebox":
47400
+ state.glovebox = !state.glovebox;
47401
+ break;
47134
47402
  }
47135
47403
  emit({ type: "command", command: c, state });
47136
47404
  };
@@ -47169,6 +47437,23 @@ var GameVehiclesThree = (() => {
47169
47437
  else if (turned && way < cancelAt) state.indicator = "off";
47170
47438
  }
47171
47439
  } else state.blinkOn = false;
47440
+ if (state.beacon) {
47441
+ beaconClock += dt;
47442
+ state.beaconSide = Math.floor(beaconClock * beaconHz) % 2;
47443
+ }
47444
+ if (!hasKey && !state.hotwire.done && !state.ignition && any(keys.hotwire)) {
47445
+ if (state.hotwire.progress === 0) {
47446
+ if (state.alarm === "armed") state.alarm = "ringing";
47447
+ emit({ type: "hotwire", stage: "started" });
47448
+ }
47449
+ state.hotwire.progress = Math.min(1, state.hotwire.progress + dt / hotwireSeconds);
47450
+ if (state.hotwire.progress >= 1) {
47451
+ state.hotwire.done = true;
47452
+ state.ignition = true;
47453
+ crankAsked = true;
47454
+ emit({ type: "hotwire", stage: "joined" });
47455
+ }
47456
+ }
47172
47457
  state.horn = any(keys.horn);
47173
47458
  state.lamps.flash = any(keys.flash);
47174
47459
  state.washer = any(keys.washer);
@@ -47253,7 +47538,7 @@ var GameVehiclesThree = (() => {
47253
47538
  ...report.suspension != null ? { suspension: report.suspension } : {}
47254
47539
  };
47255
47540
  }
47256
- var DEFAULT_LOADS = { position: 20, low: 110, high: 130, fog: 110, interior: 10, radio: 25, wipers: 60, indicators: 42, horn: 60, alarm: 5, brakeLights: 42, climate: 180 };
47541
+ var DEFAULT_LOADS = { position: 20, low: 110, high: 130, fog: 110, interior: 10, radio: 25, wipers: 60, indicators: 42, horn: 60, alarm: 5, brakeLights: 42, climate: 180, siren: 100, beacon: 70 };
47257
47542
  var clamp3 = (x, a, b) => Math.max(a, Math.min(b, x));
47258
47543
  function createVehicleSystems(options = {}) {
47259
47544
  const loads = { ...DEFAULT_LOADS, ...options.loads };
@@ -47283,6 +47568,8 @@ var GameVehiclesThree = (() => {
47283
47568
  if (c.alarm !== "off") w += loads.alarm;
47284
47569
  if (c.brakeLights) w += loads.brakeLights;
47285
47570
  if (c.climate.on) w += loads.climate;
47571
+ if (c.siren !== "off") w += loads.siren;
47572
+ if (c.beacon) w += loads.beacon;
47286
47573
  return w;
47287
47574
  };
47288
47575
  return {
@@ -47363,6 +47650,90 @@ var GameVehiclesThree = (() => {
47363
47650
  }
47364
47651
  return best;
47365
47652
  }
47653
+ var GLOVEBOX = { id: "glovebox", slots: 6, capacityKg: 4, access: "cabin" };
47654
+ var trunkFor = (litres = 450) => ({ id: "trunk", slots: Math.max(4, Math.round(litres / 25)), capacityKg: Math.round(litres / 4), access: "lid" });
47655
+ var weightOf = (stack) => stack.unitKg * stack.count;
47656
+ function createVehicleStorage(options = {}) {
47657
+ const compartments = [...options.compartments ?? [GLOVEBOX, trunkFor()]];
47658
+ const slots = new Map(compartments.map((c) => [c.id, Array.from({ length: c.slots }, () => null)]));
47659
+ const specOf = (id) => compartments.find((c) => c.id === id);
47660
+ const load = (id) => (slots.get(id) ?? []).reduce((kg, s) => kg + (s ? weightOf(s) : 0), 0);
47661
+ const reachable2 = (id, access) => {
47662
+ const spec = specOf(id);
47663
+ if (!spec) return false;
47664
+ return spec.access === "lid" ? access.lid >= 0.5 : access.gloveboxOpen && (access.seated || access.frontDoorOpen);
47665
+ };
47666
+ const place = (id, stack) => {
47667
+ const spec = specOf(id);
47668
+ const list2 = slots.get(id);
47669
+ if (!spec || !list2) return "missing";
47670
+ if (load(id) + weightOf(stack) > spec.capacityKg + 1e-9) return "too_heavy";
47671
+ const same = stack.data === void 0 ? list2.findIndex((s) => s !== null && s.itemId === stack.itemId && s.data === void 0) : -1;
47672
+ if (same >= 0) {
47673
+ const s = list2[same];
47674
+ list2[same] = { ...s, count: s.count + stack.count };
47675
+ return "ok";
47676
+ }
47677
+ const free = list2.indexOf(null);
47678
+ if (free < 0) return "full";
47679
+ list2[free] = { ...stack };
47680
+ return "ok";
47681
+ };
47682
+ return {
47683
+ compartments,
47684
+ reachable: reachable2,
47685
+ contents: (id) => [...slots.get(id) ?? []],
47686
+ loadKg: (id) => id === void 0 ? compartments.reduce((kg, c) => kg + load(c.id), 0) : load(id),
47687
+ put(id, stack, access) {
47688
+ if (!specOf(id)) return "missing";
47689
+ if (!reachable2(id, access)) return "shut";
47690
+ return place(id, stack);
47691
+ },
47692
+ take(id, slot, access) {
47693
+ const list2 = slots.get(id);
47694
+ if (!list2 || !reachable2(id, access)) return null;
47695
+ const stack = list2[slot] ?? null;
47696
+ if (stack) list2[slot] = null;
47697
+ return stack;
47698
+ },
47699
+ stock(id, stacks) {
47700
+ return stacks.filter((s) => place(id, s) !== "ok");
47701
+ },
47702
+ clear() {
47703
+ for (const list2 of slots.values()) list2.fill(null);
47704
+ }
47705
+ };
47706
+ }
47707
+ var clamp4 = (x, a, b) => Math.max(a, Math.min(b, x));
47708
+ function createWindshieldFog(options = {}) {
47709
+ const outside = options.outsideHumidity ?? 0.6;
47710
+ const breath = options.breath ?? 4e-3;
47711
+ const wet = options.wet ?? 2e-3;
47712
+ const air = options.air ?? { shut: 2e-3, window: 0.05, climate: 0.01, demist: 0.06 };
47713
+ const coldSpan = options.coldSpan ?? 15;
47714
+ const rates = options.rates ?? { build: 0.05, clear: 0.03, demist: 0.25 };
47715
+ const state = { humidity: outside, fog: 0 };
47716
+ return {
47717
+ state,
47718
+ step({ dt, occupants, outsideC, cabinC, rain = 0, speed = 0, windows = 0, climate, engineWarm = 1 }) {
47719
+ const exchange = air.shut + air.window * clamp4(windows, 0, 1) + (climate.on ? air.climate : 0) + (climate.demist ? air.demist : 0);
47720
+ const source = breath * Math.max(0, occupants) + wet * clamp4(rain, 0, 1) * (occupants > 0 ? 1 : 0);
47721
+ const towards = climate.on ? outside * 0.4 : outside;
47722
+ state.humidity = clamp4(state.humidity + (source - exchange * (state.humidity - towards)) * dt, 0, 1);
47723
+ const cold = Math.max(0, cabinC - outsideC) * (1 - 0.7 * clamp4(windows, 0, 1)) + 6 * clamp4(rain, 0, 1) + 2 * clamp4(speed / 27.8, 0, 1);
47724
+ const warmed = climate.demist ? cold * (1 - 0.9 * clamp4(engineWarm, 0, 1)) : cold;
47725
+ const clearUpTo = 1 - 0.5 * clamp4(warmed / coldSpan, 0, 1);
47726
+ const target = clamp4((state.humidity - clearUpTo) * 6, 0, 1);
47727
+ const down = climate.demist ? rates.demist * (0.3 + 0.7 * clamp4(engineWarm, 0, 1)) : rates.clear;
47728
+ state.fog = target > state.fog ? Math.min(target, state.fog + rates.build * dt) : Math.max(target, state.fog - down * dt);
47729
+ return state;
47730
+ },
47731
+ set(next) {
47732
+ if (next.humidity !== void 0) state.humidity = clamp4(next.humidity, 0, 1);
47733
+ if (next.fog !== void 0) state.fog = clamp4(next.fog, 0, 1);
47734
+ }
47735
+ };
47736
+ }
47366
47737
 
47367
47738
  // src/vehicle-lod.ts
47368
47739
  var VEHICLE_LOD_DISTANCE = 14;
@@ -47385,7 +47756,8 @@ var GameVehiclesThree = (() => {
47385
47756
  culled.clear();
47386
47757
  modelKey = keyOf();
47387
47758
  isUploaded = false;
47388
- full.traverse((object2) => {
47759
+ full.traverse((node) => {
47760
+ const object2 = node;
47389
47761
  if (!object2.isMesh || culled.has(object2)) return;
47390
47762
  culled.set(object2, object2.frustumCulled);
47391
47763
  object2.frustumCulled = false;
@@ -47412,7 +47784,8 @@ var GameVehiclesThree = (() => {
47412
47784
  const shadowProxyOf = (fused) => {
47413
47785
  const positions = [];
47414
47786
  const indices = [];
47415
- for (const mesh2 of fused.children) {
47787
+ for (const child of fused.children) {
47788
+ const mesh2 = child;
47416
47789
  if (!mesh2.isMesh || !mesh2.castShadow) continue;
47417
47790
  const geometry2 = mesh2.geometry.clone().applyMatrix4(mesh2.matrix);
47418
47791
  const offset = positions.length / 3;
@@ -47451,7 +47824,8 @@ var GameVehiclesThree = (() => {
47451
47824
  lite.visible = isFused;
47452
47825
  shadow ?? (shadow = shadowProxyOf(lite));
47453
47826
  shadow.visible = !isFused;
47454
- full.traverse((object2) => {
47827
+ full.traverse((node) => {
47828
+ const object2 = node;
47455
47829
  if (!object2.isMesh || !object2.castShadow) return;
47456
47830
  castsShadow.add(object2);
47457
47831
  object2.castShadow = false;
@@ -47473,7 +47847,8 @@ var GameVehiclesThree = (() => {
47473
47847
  root.updateMatrixWorld(true);
47474
47848
  const inverse = new THREE.Matrix4().copy(root.matrixWorld).invert();
47475
47849
  const textured = [];
47476
- full.traverse((object2) => {
47850
+ full.traverse((node) => {
47851
+ const object2 = node;
47477
47852
  if (!object2.isMesh || object2.userData.skipLite || !isShown2(object2, full)) return;
47478
47853
  const materials = Array.isArray(object2.material) ? object2.material : [object2.material];
47479
47854
  if (materials.some((material) => material?.map && !/plate/i.test(material.name ?? "")) && !/plate/i.test(object2.name ?? "")) textured.push(object2);
@@ -48338,7 +48713,8 @@ var GameVehiclesThree = (() => {
48338
48713
  speed,
48339
48714
  throttle: input.throttle,
48340
48715
  ...semiState ? { rpm: semiState.rpm, slip: Math.max(0, ...semiState.slip.map(Math.abs)) } : { slip: braking && speed > 3 ? 0.6 : 0 },
48341
- surface: /dirt|gravel|sand|grass|mud/.test(settings.surface) ? "dirt" : "asphalt"
48716
+ surface: /dirt|gravel|sand|grass|mud/.test(settings.surface) ? "dirt" : "asphalt",
48717
+ brake: input.brake
48342
48718
  });
48343
48719
  }
48344
48720
  state.exhaust -= dt;
@@ -48514,6 +48890,7 @@ var GameVehiclesThree = (() => {
48514
48890
  if (isRenderPools(lent.pools)) lent.pools.materials.register("vehicles.cracked-glass", () => crackedGlassMaterial(three, new three.DataTexture(new Uint8Array(4), 1, 1)));
48515
48891
  lent.audio?.register?.(LIBRARY_BANK);
48516
48892
  lent.audio?.register?.(VEHICLE_SOUND_BANK);
48893
+ lent.audio?.preload?.(VEHICLE_PRELOAD_SOUNDS);
48517
48894
  return () => {
48518
48895
  stopChange?.();
48519
48896
  stopFrame();
@@ -48954,7 +49331,7 @@ var GameVehiclesThree = (() => {
48954
49331
  // src/body.ts
48955
49332
  var OPEN_SOUND = "car_door_open";
48956
49333
  var SHUT_SOUND = { door: "car_door_close", hood: "car_hood_close", lid: "car_trunk_close" };
48957
- var clamp4 = (x, a, b) => Math.max(a, Math.min(b, x));
49334
+ var clamp5 = (x, a, b) => Math.max(a, Math.min(b, x));
48958
49335
  function createVehicleBody(built2, options) {
48959
49336
  const swing = options.swingSeconds ?? 1.2;
48960
49337
  const windowSeconds = options.windowSeconds ?? 3.5;
@@ -49006,7 +49383,7 @@ var GameVehiclesThree = (() => {
49006
49383
  w.obj.position.copy(w.rest).sub(w.spindle).applyQuaternion(turn).add(w.spindle);
49007
49384
  w.obj.quaternion.copy(turn).multiply(w.restQ);
49008
49385
  };
49009
- const ease = (now, target, seconds, dt) => now + clamp4(target - now, -dt / seconds, dt / seconds);
49386
+ const ease = (now, target, seconds, dt) => now + clamp5(target - now, -dt / seconds, dt / seconds);
49010
49387
  return {
49011
49388
  parts: [...hinges.keys()],
49012
49389
  windows: [...panes.keys()],
@@ -49030,7 +49407,7 @@ var GameVehiclesThree = (() => {
49030
49407
  },
49031
49408
  setWindow(id, open) {
49032
49409
  const w = panes.get(id);
49033
- if (w) w.target = clamp4(open, 0, 1);
49410
+ if (w) w.target = clamp5(open, 0, 1);
49034
49411
  },
49035
49412
  toggleSunroof() {
49036
49413
  sunTarget = sunTarget > 0.5 ? 0 : 1;
@@ -49294,7 +49671,7 @@ var GameVehiclesThree = (() => {
49294
49671
 
49295
49672
  // src/lamps.ts
49296
49673
  var LAMP_RULES = {
49297
- glow: { head: { off: 0.04, position: 0.3, low: 1, high: 1.35 }, tail: { off: 0.15, on: 0.7, brake: 1.6 }, fog: { off: 0.04, on: 1.1 }, amber: { off: 0.1, on: 2.2 } },
49674
+ glow: { head: { off: 0.04, position: 0.3, low: 1, high: 1.35 }, tail: { off: 0.15, on: 0.7, brake: 1.6 }, fog: { off: 0.04, on: 1.1 }, amber: { off: 0.1, on: 2.2 }, beacon: { off: 0.35, dark: 0.12, lit: 2.8 } },
49298
49675
  low: { color: 16773584, intensity: 2.4, distance: 32, angle: 0.42, penumbra: 0.55, decay: 1.6, drop: 0.09 },
49299
49676
  high: { color: 16774882, intensity: 3.6, distance: 70, angle: 0.3, penumbra: 0.45, decay: 1.4, drop: 0.015 },
49300
49677
  fog: { color: 16773320, intensity: 1.6, distance: 16, angle: 0.75, penumbra: 0.7, decay: 1.8, drop: 0.12 },
@@ -49311,7 +49688,11 @@ var GameVehiclesThree = (() => {
49311
49688
  if (o.userData?.lamp === "fog" && o.material && !bulbs.includes(o)) bulbs.push(o);
49312
49689
  });
49313
49690
  if (bulbs.length) lamps.push({ kind: "fog", inner: bulbs });
49314
- const has = { head: lamps.some((l) => l.kind === "headlight"), tail: lamps.some((l) => l.kind === "taillight"), fog: lamps.some((l) => l.kind === "fog"), indicators: false };
49691
+ const beacons = [];
49692
+ built2.group.traverse((o) => {
49693
+ if (o.userData?.lamp === "beacon" && o.material) beacons.push({ mesh: o, side: o.userData.beaconSide === 1 ? 1 : 0 });
49694
+ });
49695
+ const has = { head: lamps.some((l) => l.kind === "headlight"), tail: lamps.some((l) => l.kind === "taillight"), fog: lamps.some((l) => l.kind === "fog"), indicators: false, beacon: beacons.length > 0 };
49315
49696
  const originals = /* @__PURE__ */ new Map();
49316
49697
  const copies = /* @__PURE__ */ new Map();
49317
49698
  const base = /* @__PURE__ */ new Map();
@@ -49326,6 +49707,7 @@ var GameVehiclesThree = (() => {
49326
49707
  mesh2.material = copy;
49327
49708
  return copy;
49328
49709
  };
49710
+ for (const b of beacons) own(b.mesh);
49329
49711
  const haloBase = /* @__PURE__ */ new Map();
49330
49712
  for (const l of lamps) {
49331
49713
  for (const m of l.inner) own(m);
@@ -49401,6 +49783,8 @@ var GameVehiclesThree = (() => {
49401
49783
  else if (l.kind === "fog") glow(l, state.fog ? g.fog.on : g.fog.off);
49402
49784
  }
49403
49785
  for (const m of amber) glowMesh(m, state[sideOf.get(m) ?? "left"] ? g.amber.on : g.amber.off);
49786
+ const lit = state.beacon ?? null;
49787
+ for (const b of beacons) glowMesh(b.mesh, lit === null ? g.beacon.off : lit === b.side ? g.beacon.lit : g.beacon.dark);
49404
49788
  const beamId = state.mode === "low" || state.mode === "high" ? state.mode : null;
49405
49789
  for (const id of ["low", "high"]) beam(id, beamId === id, () => spots(front, LAMP_RULES[id]));
49406
49790
  beam("fog", state.fog && has.fog, () => spots(fogAnchors, LAMP_RULES.fog));
@@ -49414,7 +49798,7 @@ var GameVehiclesThree = (() => {
49414
49798
  return { ...state };
49415
49799
  },
49416
49800
  set(next) {
49417
- if (next.mode === state.mode && next.fog === state.fog && next.interior === state.interior && next.brake === state.brake && next.reverse === state.reverse && next.left === state.left && next.right === state.right) return;
49801
+ if (next.mode === state.mode && next.fog === state.fog && next.interior === state.interior && next.brake === state.brake && next.reverse === state.reverse && next.left === state.left && next.right === state.right && (next.beacon ?? null) === (state.beacon ?? null)) return;
49418
49802
  Object.assign(state, next);
49419
49803
  apply();
49420
49804
  },
@@ -49423,15 +49807,17 @@ var GameVehiclesThree = (() => {
49423
49807
  sources.clear();
49424
49808
  for (const a of anchors) a.removeFromParent();
49425
49809
  anchors.length = 0;
49810
+ const giveBack = (m) => {
49811
+ const copy = m.material;
49812
+ const original = originals.get(m);
49813
+ if (!original) return;
49814
+ originals.delete(m);
49815
+ m.material = original;
49816
+ if (copy && !Array.isArray(copy)) copy.dispose?.();
49817
+ };
49818
+ for (const b of beacons) giveBack(b.mesh);
49426
49819
  for (const l of lamps) {
49427
- for (const m of l.inner) {
49428
- const copy = m.material;
49429
- const original = originals.get(m);
49430
- if (original) {
49431
- m.material = original;
49432
- if (copy && !Array.isArray(copy)) copy.dispose?.();
49433
- }
49434
- }
49820
+ for (const m of l.inner) giveBack(m);
49435
49821
  for (const h of l.halo ?? []) {
49436
49822
  h.visible = true;
49437
49823
  const s = haloBase.get(h) ?? 1;
@@ -49445,8 +49831,66 @@ var GameVehiclesThree = (() => {
49445
49831
  };
49446
49832
  }
49447
49833
 
49834
+ // src/windshield-mist.ts
49835
+ var MIST_RULES = { color: 15001836, opacity: 0.72, others: 0.8 };
49836
+ var DOUBLE_SIDE = 2;
49837
+ function createWindshieldMist(THREE, built2) {
49838
+ const glass = (built2.context?.glass ?? []).filter((p) => p?.geometry);
49839
+ const films = [];
49840
+ for (const pane of glass) {
49841
+ const side2 = !Array.isArray(pane.material) && pane.material?.side || DOUBLE_SIDE;
49842
+ const material = new THREE.MeshBasicMaterial({ color: MIST_RULES.color, transparent: true, opacity: 0, depthWrite: false, side: side2, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1 });
49843
+ const mesh2 = new THREE.Mesh(pane.geometry, material);
49844
+ mesh2.name = "windshield_mist";
49845
+ mesh2.raycast = () => {
49846
+ };
49847
+ mesh2.userData.mist = true;
49848
+ mesh2.renderOrder = pane.renderOrder + 1;
49849
+ mesh2.visible = false;
49850
+ pane.add(mesh2);
49851
+ films.push({ mesh: mesh2, material, share: pane.userData.glass?.key === "windshield" ? 1 : MIST_RULES.others });
49852
+ }
49853
+ let fog = 0;
49854
+ return {
49855
+ panes: films.length,
49856
+ get fog() {
49857
+ return fog;
49858
+ },
49859
+ set(next) {
49860
+ const share = Math.max(0, Math.min(1, next));
49861
+ if (Math.abs(share - fog) < 5e-3 && share > 0 === fog > 0) return;
49862
+ fog = share;
49863
+ for (const f of films) {
49864
+ f.material.opacity = MIST_RULES.opacity * fog * f.share;
49865
+ f.mesh.visible = fog > 0.01;
49866
+ }
49867
+ },
49868
+ dispose() {
49869
+ for (const f of films) {
49870
+ f.mesh.removeFromParent();
49871
+ f.material.dispose();
49872
+ }
49873
+ films.length = 0;
49874
+ }
49875
+ };
49876
+ }
49877
+
49448
49878
  // src/test-area/proving/cockpit.ts
49449
- var DEFAULT_COCKPIT_SOUNDS = { horn: "horn", blinker: "blinker_tick", starter: "starter_crank", alarm: "car_alarm", chirp: "alarm_chirp", wiper: "wiper_swish", chime: "seatbelt_chime", radio: "radio_static", beep: "parking_beep" };
49879
+ var DEFAULT_COCKPIT_SOUNDS = {
49880
+ horn: "horn",
49881
+ blinker: "blinker_tick",
49882
+ starter: "starter_crank",
49883
+ alarm: "car_alarm",
49884
+ chirp: "alarm_chirp",
49885
+ wiper: "wiper_swish",
49886
+ chime: "seatbelt_chime",
49887
+ radio: "radio_static",
49888
+ beep: "parking_beep",
49889
+ wail: "siren_wail",
49890
+ yelp: "siren_yelp",
49891
+ spark: "hotwire_spark",
49892
+ glovebox: "glovebox_latch"
49893
+ };
49450
49894
  var BODY_KEYS = {
49451
49895
  Digit1: "door_front_left",
49452
49896
  Digit2: "door_front_right",
@@ -49464,6 +49908,8 @@ var GameVehiclesThree = (() => {
49464
49908
  const driver = createSemiSimDriver(spec);
49465
49909
  driver.place(o.place[0], o.place[1], o.place[2]);
49466
49910
  const lamps = createVehicleLamps(o.THREE, o.built, { lights: o.host.lights, owner: "proving-ground" });
49911
+ const mist = createWindshieldMist(o.THREE, o.built);
49912
+ const fog = createWindshieldFog();
49467
49913
  const audio = o.host.audio;
49468
49914
  const top = o.subject.stats.maxSpeedKmh;
49469
49915
  const dashboard = o.gauge ? createVehicleDashboard(o.THREE, o.built, { gauge: o.gauge, needle: o.needle, redlineRpm: spec.engine.redlineRpm, maxKmh: top ? Math.ceil((top + 10) / 20) * 20 : void 0 }) : null;
@@ -49477,11 +49923,25 @@ var GameVehiclesThree = (() => {
49477
49923
  let beepAgain = 0;
49478
49924
  let bar = 0;
49479
49925
  let exitAsked = false;
49926
+ let sirenAgain = 0;
49927
+ let sparkAgain = 0;
49928
+ let wiresBefore = 0;
49480
49929
  let gas = 0;
49481
49930
  const systems = createVehicleSystems();
49482
49931
  const context = o.built.context;
49483
49932
  const destructible = o.kit && context ? createVehicleDestructible(o.kit, context, { id: "driven", frame: o.built.group }) : null;
49484
49933
  const body = destructible ? createVehicleBody(o.built, { THREE: o.THREE, clips: destructible.animations() }) : null;
49934
+ const compartments = [];
49935
+ if (!body || body.parts.some((p) => p.startsWith("door"))) compartments.push(GLOVEBOX);
49936
+ if (body?.parts.includes("lid")) compartments.push(trunkFor(o.trunkLitres));
49937
+ const storage = createVehicleStorage({ compartments });
49938
+ for (const c of compartments) storage.stock(c.id, o.stock?.(c.id) ?? []);
49939
+ const access = () => ({
49940
+ seated: true,
49941
+ frontDoorOpen: (body?.openness("door_front_left") ?? 0) >= 0.5 || (body?.openness("door_front_right") ?? 0) >= 0.5,
49942
+ gloveboxOpen: controls.state.glovebox,
49943
+ lid: body?.openness("lid") ?? 0
49944
+ });
49485
49945
  const bodyEvents = (events) => {
49486
49946
  for (const event of events) {
49487
49947
  if (event.type === "sound") play(event.key, 0.9);
@@ -49497,6 +49957,8 @@ var GameVehiclesThree = (() => {
49497
49957
  fogLamps: lamps.has.fog,
49498
49958
  clutchPedal: true,
49499
49959
  radioTracks: RADIO_TRACKS.length,
49960
+ hasKey: o.hasKey,
49961
+ emergency: lamps.has.beacon,
49500
49962
  onEvent: (event) => {
49501
49963
  if (event.type === "command") {
49502
49964
  if (event.command === "ignition" && !event.state.ignition) driver.state.engineOn = false;
@@ -49507,6 +49969,8 @@ var GameVehiclesThree = (() => {
49507
49969
  bar = 0;
49508
49970
  }
49509
49971
  if (event.command === "exit") exitAsked = true;
49972
+ if (event.command === "siren") sirenAgain = 0;
49973
+ if (event.command === "glovebox") play(sounds.glovebox, 0.8);
49510
49974
  }
49511
49975
  o.onEvent?.(event);
49512
49976
  }
@@ -49540,6 +50004,12 @@ var GameVehiclesThree = (() => {
49540
50004
  target?.addEventListener("blur", blur);
49541
50005
  const cockpit = {
49542
50006
  radiator: 1,
50007
+ storage,
50008
+ access,
50009
+ fog,
50010
+ mist,
50011
+ weather: { ...o.weather ?? { outsideC: 25, rain: 0 } },
50012
+ emergency: lamps.has.beacon,
49543
50013
  driver,
49544
50014
  controls,
49545
50015
  systems,
@@ -49568,8 +50038,24 @@ var GameVehiclesThree = (() => {
49568
50038
  brake: s.brakeLights,
49569
50039
  reverse: s.reverseLights,
49570
50040
  left: s.blinkOn && (s.indicator === "left" || s.indicator === "hazard"),
49571
- right: s.blinkOn && (s.indicator === "right" || s.indicator === "hazard")
49572
- });
50041
+ right: s.blinkOn && (s.indicator === "right" || s.indicator === "hazard"),
50042
+ beacon: s.beacon && powered ? s.beaconSide : null
50043
+ });
50044
+ const w = cockpit.weather;
50045
+ const windows = body ? body.windows.reduce((sum, id) => sum + body.window(id), 0) / Math.max(1, body.windows.length) : 0;
50046
+ const warm = systems.state.temperature;
50047
+ const cabinC = s.climate.on ? 22 : w.outsideC + (driver.state.engineOn ? 3 + 5 * Math.min(1, warm * 2) : 2);
50048
+ mist.set(fog.step({ dt, occupants: 1, outsideC: w.outsideC, cabinC, rain: w.rain, speed: Math.abs(driver.state.u), windows, climate: s.climate, engineWarm: driver.state.engineOn ? Math.min(1, warm * 2) : 0 }).fog);
50049
+ if (s.siren !== "off" && powered && (sirenAgain -= dt) <= 0) {
50050
+ play(s.siren === "wail" ? sounds.wail : sounds.yelp);
50051
+ sirenAgain = s.siren === "wail" ? 2.95 : 1.95;
50052
+ }
50053
+ const working = s.hotwire.progress > wiresBefore;
50054
+ wiresBefore = s.hotwire.progress;
50055
+ if (working && (sparkAgain -= dt) <= 0) {
50056
+ play(sounds.spark, 0.7);
50057
+ sparkAgain = 0.45 + 0.4 * (s.hotwire.progress * 7 % 1);
50058
+ }
49573
50059
  dashboard?.update(
49574
50060
  {
49575
50061
  kmh: Math.abs(driver.state.u) * 3.6,
@@ -49645,6 +50131,8 @@ var GameVehiclesThree = (() => {
49645
50131
  target?.removeEventListener("blur", blur);
49646
50132
  controls.release();
49647
50133
  lamps.dispose();
50134
+ mist.dispose();
50135
+ storage.clear();
49648
50136
  dashboard?.dispose();
49649
50137
  body?.dispose();
49650
50138
  destructible?.dispose?.();
@@ -49722,7 +50210,7 @@ var GameVehiclesThree = (() => {
49722
50210
  // src/test-area/proving/systems-text.ts
49723
50211
  var SYSTEMS_TEXT = {
49724
50212
  "pt-BR": {
49725
- keys: "C embreagem (c\xE2mbio manual) \xB7 X lampejo do farol alto \xB7 Z esguicho do limpador \xB7 7 modo econ\xF4mico/normal/esporte \xB7 8 controle de tra\xE7\xE3o \xB7 9 ABS \xB7 0 piloto autom\xE1tico \xB7 - ar-condicionado \xB7 = desemba\xE7ador \xB7 ] troca a faixa do r\xE1dio ou da fita",
50213
+ keys: "C embreagem (c\xE2mbio manual) \xB7 X lampejo do farol alto \xB7 Z esguicho do limpador \xB7 7 modo econ\xF4mico/normal/esporte \xB7 8 controle de tra\xE7\xE3o \xB7 9 ABS \xB7 0 piloto autom\xE1tico \xB7 - ar-condicionado \xB7 = desemba\xE7ador \xB7 ] troca a faixa do r\xE1dio ou da fita \xB7 ; sirene \xB7 ' giroflex (ve\xEDculo de emerg\xEAncia) \xB7 / porta-luvas \xB7 sem a chave, segure I: liga\xE7\xE3o direta",
49726
50214
  profile: "Modo de condu\xE7\xE3o",
49727
50215
  profiles: { eco: "econ\xF4mico", normal: "normal", sport: "esporte" },
49728
50216
  traction: "Controle de tra\xE7\xE3o",
@@ -49732,7 +50220,7 @@ var GameVehiclesThree = (() => {
49732
50220
  climate: "Ar-condicionado",
49733
50221
  demist: "Desemba\xE7ador",
49734
50222
  wiperModes: { off: "desligado", intermittent: "intermitente", slow: "lento", fast: "r\xE1pido" },
49735
- refused: { battery_flat: "Bateria descarregada: o motor de partida n\xE3o gira", too_slow: "Piloto autom\xE1tico s\xF3 acima de 30 km/h", locked: "Porta travada", missing: "Este ve\xEDculo n\xE3o tem essa pe\xE7a" },
50223
+ refused: { battery_flat: "Bateria descarregada: o motor de partida n\xE3o gira", too_slow: "Piloto autom\xE1tico s\xF3 acima de 30 km/h", locked: "Porta travada", missing: "Este ve\xEDculo n\xE3o tem essa pe\xE7a", no_key: "Sem a chave: segure I para fazer a liga\xE7\xE3o direta", no_siren: "Este ve\xEDculo n\xE3o tem sirene nem giroflex" },
49736
50224
  events: {
49737
50225
  stall: "O motor morreu",
49738
50226
  out_of_fuel: "Acabou o combust\xEDvel",
@@ -49743,9 +50231,20 @@ var GameVehiclesThree = (() => {
49743
50231
  seized: "O motor fundiu de tanto esquentar",
49744
50232
  spare_fitted: "Estepe colocado",
49745
50233
  no_spare: "N\xE3o h\xE1 estepe",
49746
- cruise_cancelled: "Piloto autom\xE1tico desligado"
50234
+ cruise_cancelled: "Piloto autom\xE1tico desligado",
50235
+ hotwire_started: "Fios descascados sob a coluna: continue segurando I",
50236
+ hotwire_joined: "Liga\xE7\xE3o direta feita: a igni\xE7\xE3o pegou e o motor de partida gira"
49747
50237
  },
49748
- actions: { puncture: "Furar pneu (dianteiro esquerdo)", fit_spare: "Trocar pelo estepe", refuel: "Abastecer", drain_battery: "Descarregar bateria", jump_start: "Chupeta (carregar bateria)", break_radiator: "Furar o radiador", empty_tank: "Deixar o tanque na reserva", remote_lock: "Controle: travar (arma o alarme)", remote_unlock: "Controle: destravar", force_door: "For\xE7ar a porta do motorista", crash_wall: "Bater no muro (parada seca)", park_behind: "Estacionar um carro atr\xE1s (sensor de r\xE9)" },
50238
+ actions: { puncture: "Furar pneu (dianteiro esquerdo)", fit_spare: "Trocar pelo estepe", refuel: "Abastecer", drain_battery: "Descarregar bateria", jump_start: "Chupeta (carregar bateria)", break_radiator: "Furar o radiador", empty_tank: "Deixar o tanque na reserva", remote_lock: "Controle: travar (arma o alarme)", remote_unlock: "Controle: destravar", force_door: "For\xE7ar a porta do motorista", crash_wall: "Bater no muro (parada seca)", park_behind: "Estacionar um carro atr\xE1s (sensor de r\xE9)", take_key: "Tirar a chave (liga\xE7\xE3o direta) / devolver", cold_rain: "Tempo: frio e chuva / bom", glovebox_contents: "Ver o porta-luvas", trunk_contents: "Ver o porta-malas", take_from_trunk: "Tirar um item do porta-malas para o ch\xE3o" },
50239
+ siren: "Sirene",
50240
+ sirenModes: { off: "desligada", wail: "cont\xEDnua", yelp: "r\xE1pida (cruzamento)" },
50241
+ beacon: "Giroflex",
50242
+ glovebox: "Porta-luvas",
50243
+ lid: { open: "aberto", shut: "fechado" },
50244
+ storage: { names: { glovebox: "Porta-luvas", trunk: "Porta-malas" }, empty: "{0}: vazio", shut: "{0} fechado: abra antes (porta-luvas com / sentado, porta-malas com 6)", list: "{0} ({1} kg): {2}", none: "Este ve\xEDculo n\xE3o tem {0}", taken: "{0} tirado do porta-malas e posto no ch\xE3o", ground: "{0} tirado do porta-malas (sem cat\xE1logo de itens nesta sala para p\xF4-lo no ch\xE3o)" },
50245
+ fog: { misted: "O para-brisa emba\xE7ou por dentro: = desemba\xE7ador, ar-condicionado ou um vidro aberto", clear: "Para-brisa desemba\xE7ado", weather: "L\xE1 fora: 8 \xB0C e chuva", fair: "L\xE1 fora: 25 \xB0C, sem chuva", metric: "Vidro emba\xE7ado" },
50246
+ keyTaken: "Sem a chave no contato: segure I para a liga\xE7\xE3o direta",
50247
+ keyBack: "Chave de volta no contato",
49749
50248
  parking: { placed: "Carro parado 3 m atr\xE1s: d\xEA r\xE9 e escute o sensor", none: "Sem cat\xE1logo de ve\xEDculos nesta sala: o sensor n\xE3o tem o que ver" },
49750
50249
  track: "faixa {0}",
49751
50250
  adjust: { seat_forward: "Banco: frente/tr\xE1s (m)", seat_height: "Banco: altura (m)", mirror_left: "Retrovisor esquerdo: \xE2ngulo", mirror_right: "Retrovisor direito: \xE2ngulo" },
@@ -49755,7 +50254,7 @@ var GameVehiclesThree = (() => {
49755
50254
  done: { puncture: "Pneu dianteiro esquerdo furado", refuel: "Tanque cheio", drain_battery: "Bateria quase sem carga", jump_start: "Bateria carregada", break_radiator: "Radiador furado: o motor vai esquentar", empty_tank: "Tanque na reserva" }
49756
50255
  },
49757
50256
  en: {
49758
- keys: "C clutch (manual gearbox) \xB7 X flash the high beam \xB7 Z washer \xB7 7 eco/normal/sport \xB7 8 traction control \xB7 9 ABS \xB7 0 cruise control \xB7 - air conditioning \xB7 = demister \xB7 ] next radio or tape track",
50257
+ keys: "C clutch (manual gearbox) \xB7 X flash the high beam \xB7 Z washer \xB7 7 eco/normal/sport \xB7 8 traction control \xB7 9 ABS \xB7 0 cruise control \xB7 - air conditioning \xB7 = demister \xB7 ] next radio or tape track \xB7 ; siren \xB7 ' beacon (emergency vehicle) \xB7 / glovebox \xB7 without the key, hold I: hotwire",
49759
50258
  profile: "Drive profile",
49760
50259
  profiles: { eco: "eco", normal: "normal", sport: "sport" },
49761
50260
  traction: "Traction control",
@@ -49765,7 +50264,7 @@ var GameVehiclesThree = (() => {
49765
50264
  climate: "Air conditioning",
49766
50265
  demist: "Demister",
49767
50266
  wiperModes: { off: "off", intermittent: "intermittent", slow: "slow", fast: "fast" },
49768
- refused: { battery_flat: "Flat battery: the starter does not turn", too_slow: "Cruise control only above 30 km/h", locked: "The door is locked", missing: "This vehicle has no such part" },
50267
+ refused: { battery_flat: "Flat battery: the starter does not turn", too_slow: "Cruise control only above 30 km/h", locked: "The door is locked", missing: "This vehicle has no such part", no_key: "No key: hold I to hotwire it", no_siren: "This vehicle has no siren or beacon" },
49769
50268
  events: {
49770
50269
  stall: "The engine stalled",
49771
50270
  out_of_fuel: "Out of fuel",
@@ -49776,9 +50275,20 @@ var GameVehiclesThree = (() => {
49776
50275
  seized: "The engine seized from the heat",
49777
50276
  spare_fitted: "Spare tyre fitted",
49778
50277
  no_spare: "No spare tyre left",
49779
- cruise_cancelled: "Cruise control off"
50278
+ cruise_cancelled: "Cruise control off",
50279
+ hotwire_started: "Wires stripped under the column: keep holding I",
50280
+ hotwire_joined: "Hotwired: the ignition is live and the starter turns"
49780
50281
  },
49781
- actions: { puncture: "Puncture a tyre (front left)", fit_spare: "Fit the spare", refuel: "Refuel", drain_battery: "Drain the battery", jump_start: "Jump start (charge the battery)", break_radiator: "Puncture the radiator", empty_tank: "Leave the tank on reserve", remote_lock: "Remote: lock (arms the alarm)", remote_unlock: "Remote: unlock", force_door: "Force the driver's door", crash_wall: "Hit a wall (dead stop)", park_behind: "Park a car behind (rear sensor)" },
50282
+ actions: { puncture: "Puncture a tyre (front left)", fit_spare: "Fit the spare", refuel: "Refuel", drain_battery: "Drain the battery", jump_start: "Jump start (charge the battery)", break_radiator: "Puncture the radiator", empty_tank: "Leave the tank on reserve", remote_lock: "Remote: lock (arms the alarm)", remote_unlock: "Remote: unlock", force_door: "Force the driver's door", crash_wall: "Hit a wall (dead stop)", park_behind: "Park a car behind (rear sensor)", take_key: "Take the key out (hotwire) / give it back", cold_rain: "Weather: cold and rain / fair", glovebox_contents: "Look in the glovebox", trunk_contents: "Look in the trunk", take_from_trunk: "Take an item out of the trunk to the ground" },
50283
+ siren: "Siren",
50284
+ sirenModes: { off: "off", wail: "wail", yelp: "yelp (junction)" },
50285
+ beacon: "Beacon",
50286
+ glovebox: "Glovebox",
50287
+ lid: { open: "open", shut: "shut" },
50288
+ storage: { names: { glovebox: "Glovebox", trunk: "Trunk" }, empty: "{0}: empty", shut: "{0} shut: open it first (glovebox with / while seated, trunk with 6)", list: "{0} ({1} kg): {2}", none: "This vehicle has no {0}", taken: "{0} taken out of the trunk and put on the ground", ground: "{0} taken out of the trunk (no item catalogue in this room to put it on the ground)" },
50289
+ fog: { misted: "The windshield misted up inside: = demister, air conditioning or a window down", clear: "Windshield clear", weather: "Outside: 8 \xB0C and rain", fair: "Outside: 25 \xB0C, no rain", metric: "Glass misted" },
50290
+ keyTaken: "No key in the ignition: hold I to hotwire",
50291
+ keyBack: "Key back in the ignition",
49782
50292
  parking: { placed: "A car parked 3 m behind: reverse and listen to the sensor", none: "No vehicle catalogue in this room: the sensor has nothing to see" },
49783
50293
  track: "track {0}",
49784
50294
  adjust: { seat_forward: "Seat: forward/back (m)", seat_height: "Seat: height (m)", mirror_left: "Left mirror: angle", mirror_right: "Right mirror: angle" },
@@ -49964,6 +50474,9 @@ var GameVehiclesThree = (() => {
49964
50474
  return turn ? { ...pose2, look: [pose2.look[0] + turn, pose2.look[1], pose2.look[2]] } : pose2;
49965
50475
  };
49966
50476
  let gearbox = "automatic";
50477
+ let hasKey = true;
50478
+ let weather = { outsideC: 25, rain: 0 };
50479
+ let misted = false;
49967
50480
  let lastGear = null;
49968
50481
  let driveClock = 0;
49969
50482
  let queue = [];
@@ -50283,7 +50796,8 @@ var GameVehiclesThree = (() => {
50283
50796
  run = null;
50284
50797
  queue = [];
50285
50798
  parking = null;
50286
- setSurface("dry_asphalt");
50799
+ setSurface(weather.rain > 0 ? "wet_asphalt" : "dry_asphalt");
50800
+ misted = false;
50287
50801
  driving = createCockpit({
50288
50802
  THREE: three,
50289
50803
  host,
@@ -50296,8 +50810,16 @@ var GameVehiclesThree = (() => {
50296
50810
  needle: kitFor(three).materials?.amber,
50297
50811
  // the engine's own sound turns the key (starter, catch, idle by RPM)
50298
50812
  sounds: { starter: "" },
50813
+ hasKey,
50814
+ weather,
50815
+ stock: (compartment) => options.stock?.(compartment, settings.vehicle) ?? [],
50299
50816
  onExit: () => stopDriving(),
50300
50817
  onEvent: (event) => {
50818
+ if (event.type === "hotwire") {
50819
+ host?.log(sysText.events[event.stage === "joined" ? "hotwire_joined" : "hotwire_started"], { vehicle: settings.vehicle, stage: event.stage }, "proving_system");
50820
+ if (event.stage === "joined" && car && driving?.systems.canCrank() !== false) engine?.start([car.built.group.position.x, 0.5, car.built.group.position.z]);
50821
+ return;
50822
+ }
50301
50823
  if (event.type === "refused") return host?.log(text.cabin.refused[event.reason] ?? sysText.refused[event.reason] ?? event.reason);
50302
50824
  if (event.type === "sound") return;
50303
50825
  if (event.type !== "command") {
@@ -50379,11 +50901,41 @@ var GameVehiclesThree = (() => {
50379
50901
  return `${sysText.demist}: ${onOff(st.climate.demist)}`;
50380
50902
  case "seatbelt":
50381
50903
  return `${c.seatbelt}: ${onOff(st.seatbelt)}`;
50904
+ case "siren":
50905
+ return `${sysText.siren}: ${sysText.sirenModes[st.siren]}`;
50906
+ case "beacon":
50907
+ return `${sysText.beacon}: ${onOff(st.beacon)}`;
50908
+ case "glovebox":
50909
+ return `${sysText.glovebox}: ${sysText.lid[st.glovebox ? "open" : "shut"]}`;
50382
50910
  default:
50383
50911
  return null;
50384
50912
  }
50385
50913
  };
50914
+ const itemName = (id) => options.itemName?.(id) ?? id;
50915
+ const listCompartment = (cockpit, id) => {
50916
+ const label = sysText.storage.names[id];
50917
+ const data = { vehicle: settings.vehicle, compartment: id };
50918
+ if (!cockpit.storage.compartments.some((c) => c.id === id)) return host?.log(fillText(sysText.storage.none, label.toLowerCase()), data, "proving_storage");
50919
+ if (!cockpit.storage.reachable(id, cockpit.access())) return host?.log(fillText(sysText.storage.shut, label), data, "proving_storage");
50920
+ const stacks = cockpit.storage.contents(id).filter((x) => x !== null);
50921
+ if (!stacks.length) return host?.log(fillText(sysText.storage.empty, label), data, "proving_storage");
50922
+ host?.log(fillText(sysText.storage.list, label, cockpit.storage.loadKg(id).toFixed(1), stacks.map((x) => x.count > 1 ? `${x.count}\xD7 ${itemName(x.itemId)}` : itemName(x.itemId)).join(", ")), { ...data, stacks: stacks.map((x) => ({ item: x.itemId, count: x.count })) }, "proving_storage");
50923
+ };
50386
50924
  const systemsAction = (id) => {
50925
+ if (id === "take_key") {
50926
+ hasKey = !hasKey;
50927
+ if (driving) stopDriving();
50928
+ startDriving();
50929
+ host?.log(hasKey ? sysText.keyBack : sysText.keyTaken, { vehicle: settings.vehicle, hasKey }, "proving_system");
50930
+ return;
50931
+ }
50932
+ if (id === "cold_rain") {
50933
+ weather = weather.rain > 0 ? { outsideC: 25, rain: 0 } : { outsideC: 8, rain: 1 };
50934
+ if (driving) driving.weather = { ...weather };
50935
+ setSurface(weather.rain > 0 ? "wet_asphalt" : "dry_asphalt");
50936
+ host?.log(weather.rain > 0 ? sysText.fog.weather : sysText.fog.fair, { vehicle: settings.vehicle, ...weather }, "proving_system");
50937
+ return;
50938
+ }
50387
50939
  if (!driving) startDriving();
50388
50940
  const cockpit = driving;
50389
50941
  if (!cockpit) return;
@@ -50449,6 +51001,23 @@ var GameVehiclesThree = (() => {
50449
51001
  host.log(placed ? sysText.parking.placed : sysText.parking.none, { vehicle: settings.vehicle }, "proving_system");
50450
51002
  return;
50451
51003
  }
51004
+ case "glovebox_contents":
51005
+ return listCompartment(cockpit, "glovebox");
51006
+ case "trunk_contents":
51007
+ return listCompartment(cockpit, "trunk");
51008
+ case "take_from_trunk": {
51009
+ const storage = cockpit.storage;
51010
+ if (!storage.compartments.some((c) => c.id === "trunk")) return listCompartment(cockpit, "trunk");
51011
+ const slot = storage.contents("trunk").findIndex((x) => x !== null);
51012
+ if (slot < 0 || !storage.reachable("trunk", cockpit.access())) return listCompartment(cockpit, "trunk");
51013
+ const stack = storage.take("trunk", slot, cockpit.access());
51014
+ if (!stack) return;
51015
+ const g = car?.built.group;
51016
+ const back = (car?.built.length ?? 4.5) / 2 + 0.8;
51017
+ const placed = g ? host?.addObject?.(stack.itemId, { position: [g.position.x - Math.sin(g.rotation.y) * back, 0, g.position.z - Math.cos(g.rotation.y) * back] }) : null;
51018
+ host?.log(fillText(placed ? sysText.storage.taken : sysText.storage.ground, itemName(stack.itemId)), { vehicle: settings.vehicle, item: stack.itemId, count: stack.count, placed: !!placed }, "proving_storage");
51019
+ return;
51020
+ }
50452
51021
  case "force_door": {
50453
51022
  const body = cockpit.body;
50454
51023
  if (!body) return;
@@ -50555,6 +51124,13 @@ var GameVehiclesThree = (() => {
50555
51124
  const d = driving;
50556
51125
  d.step(dt);
50557
51126
  if (!driving) return;
51127
+ if (!misted && d.fog.state.fog > 0.6) {
51128
+ misted = true;
51129
+ host.log(sysText.fog.misted, { vehicle: settings.vehicle, fog: +d.fog.state.fog.toFixed(2), humidity: +d.fog.state.humidity.toFixed(2) }, "proving_system");
51130
+ } else if (misted && d.fog.state.fog < 0.1) {
51131
+ misted = false;
51132
+ host.log(sysText.fog.clear, { vehicle: settings.vehicle }, "proving_system");
51133
+ }
50558
51134
  pose(d.driver.state, d.driver.state.steerAngle);
50559
51135
  speed = d.driver.state.u;
50560
51136
  steer = d.driver.state.steerAngle;
@@ -50650,6 +51226,7 @@ var GameVehiclesThree = (() => {
50650
51226
  { id: "gear", name: text.metrics.gear, read: () => driving?.driver.state.gear ?? run?.driver.state.gear ?? 0 },
50651
51227
  { id: "rpm", name: text.metrics.rpm, unit: "rpm", digits: 0, read: () => driving?.driver.state.rpm ?? run?.driver.state.rpm ?? 0 },
50652
51228
  { id: "time", name: text.metrics.time, unit: "s", digits: 1, read: () => run?.time ?? 0 },
51229
+ { id: "fog", name: sysText.fog.metric, unit: "%", digits: 0, read: () => (driving?.fog.state.fog ?? 0) * 100 },
50653
51230
  { id: "value", name: text.metrics.value, digits: 1, read: () => run ? run.trace[run.trace.length - 1]?.[1] ?? 0 : 0 },
50654
51231
  { id: "passed", name: text.metrics.passed, read: () => counts("pass") },
50655
51232
  { id: "failed", name: text.metrics.failed, read: () => counts("fail") },