@adatechnology/game-vehicles-three 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-MRUPKE7J.js → chunk-L63R2JQA.js} +542 -29
- package/dist/chunk-L63R2JQA.js.map +1 -0
- package/dist/index.d.ts +148 -5
- package/dist/index.global.js +1401 -261
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +11 -1
- package/dist/{testing-C-BgV7gj.d.ts → testing-DI0_R8dH.d.ts} +4 -5
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-MRUPKE7J.js.map +0 -1
package/dist/index.global.js
CHANGED
|
@@ -23,6 +23,8 @@ var GameVehiclesThree = (() => {
|
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
BIKE_ENGINE: () => BIKE_ENGINE,
|
|
25
25
|
CAR_ENGINE: () => CAR_ENGINE,
|
|
26
|
+
CAR_RECORDED_RPM: () => CAR_RECORDED_RPM,
|
|
27
|
+
CAR_START_RUN_STOP: () => CAR_START_RUN_STOP,
|
|
26
28
|
CRASH_SPEEDS: () => CRASH_SPEEDS,
|
|
27
29
|
DASHBOARD_LOOK: () => DASHBOARD_LOOK,
|
|
28
30
|
DEFAULT_TEST_VEHICLES: () => DEFAULT_TEST_VEHICLES,
|
|
@@ -41,6 +43,7 @@ var GameVehiclesThree = (() => {
|
|
|
41
43
|
VEHICLE_LOD_DISTANCE: () => VEHICLE_LOD_DISTANCE,
|
|
42
44
|
VEHICLE_LOOPS: () => VEHICLE_LOOPS,
|
|
43
45
|
VEHICLE_LOOP_FALLOFF: () => VEHICLE_LOOP_FALLOFF,
|
|
46
|
+
VEHICLE_SAMPLE_ALIASES: () => VEHICLE_SAMPLE_ALIASES,
|
|
44
47
|
VEHICLE_SCENARIO_IDS: () => VEHICLE_SCENARIO_IDS,
|
|
45
48
|
VEHICLE_SOUNDS: () => VEHICLE_SOUNDS,
|
|
46
49
|
VEHICLE_SOUND_BANK: () => VEHICLE_SOUND_BANK,
|
|
@@ -49,12 +52,14 @@ var GameVehiclesThree = (() => {
|
|
|
49
52
|
createCabinSmoke: () => createCabinSmoke,
|
|
50
53
|
createGearGuess: () => createGearGuess,
|
|
51
54
|
createProvingModule: () => createProvingModule,
|
|
55
|
+
createVehicleBody: () => createVehicleBody,
|
|
52
56
|
createVehicleDashboard: () => createVehicleDashboard,
|
|
53
57
|
createVehicleLamps: () => createVehicleLamps,
|
|
54
58
|
createVehicleLod: () => createVehicleLod,
|
|
55
59
|
createVehicleSound: () => createVehicleSound,
|
|
56
60
|
createVehiclesTestModule: () => createVehiclesTestModule,
|
|
57
61
|
createVehiclesThree: () => createVehiclesThree,
|
|
62
|
+
createWheelRoll: () => createWheelRoll,
|
|
58
63
|
defaultEffectIds: () => defaultEffectIds,
|
|
59
64
|
defaultSoundIds: () => defaultSoundIds,
|
|
60
65
|
engineMix: () => engineMix,
|
|
@@ -70,6 +75,10 @@ var GameVehiclesThree = (() => {
|
|
|
70
75
|
|
|
71
76
|
// ../game-contracts/dist/index.js
|
|
72
77
|
var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
|
|
78
|
+
var LAUNCHED = "launched";
|
|
79
|
+
function launchBody(root, velocity) {
|
|
80
|
+
root.userData[LAUNCHED] = [velocity[0], velocity[1], velocity[2]];
|
|
81
|
+
}
|
|
73
82
|
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
74
83
|
var DEFAULT_IGNITION_RULES = {
|
|
75
84
|
fillCurve: [
|
|
@@ -3861,9 +3870,9 @@ var GameVehiclesThree = (() => {
|
|
|
3861
3870
|
let x = bx + (Hd[0] - bx) * v;
|
|
3862
3871
|
const y = by + (Hd[1] - by) * v;
|
|
3863
3872
|
let z = bz + (Hd[2] - bz) * v;
|
|
3864
|
-
const
|
|
3873
|
+
const chord2 = Math.hypot(C[0] - T[0], C[1] - T[1]) * (1 - v);
|
|
3865
3874
|
x -= roach * u * Math.sin(v * PI) * (u > 0.7 ? 1 : u / 0.7);
|
|
3866
|
-
z += cam *
|
|
3875
|
+
z += cam * chord2 * 4 * u * (1 - u) * (0.6 + 0.4 * (1 - v));
|
|
3867
3876
|
pos.push(x, y, z);
|
|
3868
3877
|
}
|
|
3869
3878
|
}
|
|
@@ -5092,12 +5101,24 @@ var GameVehiclesThree = (() => {
|
|
|
5092
5101
|
}
|
|
5093
5102
|
);
|
|
5094
5103
|
}
|
|
5104
|
+
var WIPER_SWEEP = 1.5;
|
|
5105
|
+
function tagWiper(params) {
|
|
5106
|
+
var _a;
|
|
5107
|
+
const tag = { arm: params.index, sweep: WIPER_SWEEP, spindle: [params.spindle.x, params.spindle.y, params.spindle.z], axis: [params.normal.x, params.normal.y, params.normal.z] };
|
|
5108
|
+
(_a = params.context).wipers ?? (_a.wipers = []);
|
|
5109
|
+
for (const part of params.parts) params.context.wipers.push({ part, tag });
|
|
5110
|
+
}
|
|
5111
|
+
function markSunroof(pane, slide) {
|
|
5112
|
+
pane.name = "sunroof";
|
|
5113
|
+
pane.userData.sunroof = { slide };
|
|
5114
|
+
return pane;
|
|
5115
|
+
}
|
|
5095
5116
|
function installCarsExtra(fx) {
|
|
5096
5117
|
const kit = fx.kit;
|
|
5097
5118
|
const THREE = kit.THREE;
|
|
5098
5119
|
const trl = fx.t;
|
|
5099
5120
|
const lbl = fx.label;
|
|
5100
|
-
const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, G2 = kit.geo, profX = kit.profX, halfAt = kit.halfAt,
|
|
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;
|
|
5101
5122
|
const GLOSS = CM("#07080a", { roughness: 0.18, metalness: 0.5 });
|
|
5102
5123
|
const ALLOY = CM("#b9bec2", { metalness: 0.75, roughness: 0.3 });
|
|
5103
5124
|
const ALLOYD = CM("#3a3e42", { metalness: 0.6, roughness: 0.35 });
|
|
@@ -5111,7 +5132,7 @@ var GameVehiclesThree = (() => {
|
|
|
5111
5132
|
const a = (y - o.ys) / (o.belt - o.ys);
|
|
5112
5133
|
return o.kt * a * a;
|
|
5113
5134
|
}
|
|
5114
|
-
const b =
|
|
5135
|
+
const b = clamp5((o.ys - y) / (o.ys - o.yb), 0, 1.25);
|
|
5115
5136
|
return o.kb * b * b;
|
|
5116
5137
|
}
|
|
5117
5138
|
const f = function(x, y, z) {
|
|
@@ -5191,13 +5212,13 @@ var GameVehiclesThree = (() => {
|
|
|
5191
5212
|
});
|
|
5192
5213
|
}
|
|
5193
5214
|
function roofAt(gh, x) {
|
|
5194
|
-
const rR = gh.roofR || gh.roof, t =
|
|
5215
|
+
const rR = gh.roofR || gh.roof, t = clamp5((x - gh.rt) / (gh.ft - gh.rt), 0, 1);
|
|
5195
5216
|
return rR + (gh.roof - rR) * t + (gh.crown || 0) * 4 * t * (1 - t);
|
|
5196
5217
|
}
|
|
5197
5218
|
function windows(gh) {
|
|
5198
5219
|
const inn = 0.07, rise = gh.rise || 0;
|
|
5199
5220
|
function ybAt(x) {
|
|
5200
|
-
return gh.belt + 0.035 + rise *
|
|
5221
|
+
return gh.belt + 0.035 + rise * clamp5((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
|
|
5201
5222
|
}
|
|
5202
5223
|
function lx(x0, x1, y, top) {
|
|
5203
5224
|
return x0 + (x1 - x0) * (y - gh.belt) / (top - gh.belt);
|
|
@@ -5400,7 +5421,7 @@ var GameVehiclesThree = (() => {
|
|
|
5400
5421
|
}
|
|
5401
5422
|
const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: tot * (full ? 2 : 1), E, sd };
|
|
5402
5423
|
G22.at = function(u, y) {
|
|
5403
|
-
const fi =
|
|
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;
|
|
5404
5425
|
function L(M) {
|
|
5405
5426
|
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);
|
|
5406
5427
|
}
|
|
@@ -5588,7 +5609,7 @@ var GameVehiclesThree = (() => {
|
|
|
5588
5609
|
off: 3e-3,
|
|
5589
5610
|
nv: 4
|
|
5590
5611
|
});
|
|
5591
|
-
skin(c, Gd, o.refl || REFL, { u0: pu, u1: 1 - pu, yb, yt, off: 6e-3, nv: 4 });
|
|
5612
|
+
const reflector = skin(c, Gd, o.refl || REFL, { u0: pu, u1: 1 - pu, yb, yt, off: 6e-3, nv: 4 });
|
|
5592
5613
|
(o.proj || []).forEach(function(q) {
|
|
5593
5614
|
const r = sh(q[0]), y = (r[0] + r[1]) / 2 + (q[1] || 0), s = Gd.at(q[0], y), rad = q[2] || Math.min(0.034, (r[1] - r[0]) * 0.4);
|
|
5594
5615
|
const cup = onSurf(c.cylinder(rad * 1.35, rad * 1.2, 0.012, LH, 0, 0, 0), s, 8e-3);
|
|
@@ -5619,7 +5640,7 @@ var GameVehiclesThree = (() => {
|
|
|
5619
5640
|
lens.push(ln);
|
|
5620
5641
|
if (!inner.length) inner.push(ln);
|
|
5621
5642
|
const cs = Gd.at(0.5, (rg[0] + rg[1]) / 2).p;
|
|
5622
|
-
regLight(c, "headlight", o.label || (sd > 0 ? trl("labels.right_headlight") : trl("labels.left_headlight")), inner, lens, cs);
|
|
5643
|
+
Object.assign(regLight(c, "headlight", o.label || (sd > 0 ? trl("labels.right_headlight") : trl("labels.left_headlight")), inner, lens, cs), { reflector: [reflector] });
|
|
5623
5644
|
return Gd;
|
|
5624
5645
|
};
|
|
5625
5646
|
K.tail = function(sd, o) {
|
|
@@ -5980,7 +6001,7 @@ var GameVehiclesThree = (() => {
|
|
|
5980
6001
|
c.roundBox(x1 - x0, 0.08, 0.035, 0.015, MT.trim, (x0 + x1) / 2, by + 0.05, sd * (hw - 8e-3));
|
|
5981
6002
|
if (s.clad)
|
|
5982
6003
|
s.arches.forEach(function(a) {
|
|
5983
|
-
const a0 = Math.asin(
|
|
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));
|
|
5984
6005
|
tor.rotation.z = a0;
|
|
5985
6006
|
tor.scale.z = 0.8;
|
|
5986
6007
|
});
|
|
@@ -6005,12 +6026,18 @@ var GameVehiclesThree = (() => {
|
|
|
6005
6026
|
(s.wiper === 1 ? [[0.12, 0.66, -0.5]] : [
|
|
6006
6027
|
[-0.3, 0.42, -0.36],
|
|
6007
6028
|
[0.2, 0.42, -0.36]
|
|
6008
|
-
]).forEach(function(q) {
|
|
6029
|
+
]).forEach(function(q, index) {
|
|
6009
6030
|
const p0 = new V3(gh.fb, gh.belt, q[0]).addScaledVector(wd, 0.07).addScaledVector(wn, 0.035), p1 = p0.clone().addScaledVector(wd, q[1] * 0.42);
|
|
6010
6031
|
p1.z += q[2];
|
|
6011
|
-
c.rod(p0, p1, 9e-3, MT.trim);
|
|
6012
|
-
c.cylinder(0.018, 0.018, 0.03, MT.trim, p0.x, p0.y, p0.z);
|
|
6032
|
+
const blade = c.rod(p0, p1, 9e-3, MT.trim);
|
|
6033
|
+
const cap = c.cylinder(0.018, 0.018, 0.03, MT.trim, p0.x, p0.y, p0.z);
|
|
6034
|
+
tagWiper({ context: c, parts: [blade, cap], spindle: p0, normal: wn, index });
|
|
6013
6035
|
});
|
|
6036
|
+
if (s.sunroof) {
|
|
6037
|
+
const sx = gh.rt + (gh.ft - gh.rt) * 0.62, sl = 0.62, sw = 2 * (halfAt(gh.Wg, T, gh.roof) - 0.24), sy = roofAt(gh, sx), tilt = Math.atan2(roofAt(gh, sx + 0.3) - roofAt(gh, sx - 0.3), 0.6);
|
|
6038
|
+
c.roundBox(sl, 8e-3, sw, 0.01, PLASTIC, sx, sy + 4e-3, 0, { rot: [0, 0, tilt] }).castShadow = false;
|
|
6039
|
+
markSunroof(c.roundBox(sl + 0.03, 0.012, sw + 0.03, 0.01, MT.tint, sx, sy + 0.013, 0, { rot: [0, 0, tilt] }), sl * 0.85);
|
|
6040
|
+
}
|
|
6014
6041
|
if (s.fin !== false)
|
|
6015
6042
|
c.sphere(0.1, s.roofCol ? c.paint(s.roofCol) : GLOSS, gh.rt + 0.2, roofAt(gh, gh.rt + 0.2) + 0.045, 0, 1, 0.45, 0.28, {
|
|
6016
6043
|
tl: PI / 2
|
|
@@ -6111,7 +6138,7 @@ var GameVehiclesThree = (() => {
|
|
|
6111
6138
|
c.cylinder(0.06, 0.06, 0.012, MT.head, x + 0.055, y, z, "x");
|
|
6112
6139
|
}
|
|
6113
6140
|
function sm(t) {
|
|
6114
|
-
t =
|
|
6141
|
+
t = clamp5(t, 0, 1);
|
|
6115
6142
|
return t * t * (3 - 2 * t);
|
|
6116
6143
|
}
|
|
6117
6144
|
function sideGrid(S, sd, o) {
|
|
@@ -6128,7 +6155,7 @@ var GameVehiclesThree = (() => {
|
|
|
6128
6155
|
}
|
|
6129
6156
|
const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: Math.abs(o.x1 - o.x0) };
|
|
6130
6157
|
G22.at = function(u, y) {
|
|
6131
|
-
const fi =
|
|
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;
|
|
6132
6159
|
function L(M) {
|
|
6133
6160
|
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);
|
|
6134
6161
|
}
|
|
@@ -6986,6 +7013,7 @@ var GameVehiclesThree = (() => {
|
|
|
6986
7013
|
function(c) {
|
|
6987
7014
|
const hex = "#8c2b2b";
|
|
6988
7015
|
car(c, {
|
|
7016
|
+
sunroof: fx.hasSunroof("turbo_hatch"),
|
|
6989
7017
|
W: 1.751,
|
|
6990
7018
|
col: hex,
|
|
6991
7019
|
shelf: 0.42,
|
|
@@ -7263,6 +7291,7 @@ var GameVehiclesThree = (() => {
|
|
|
7263
7291
|
function(c) {
|
|
7264
7292
|
const hex = "#5a5f66";
|
|
7265
7293
|
car(c, {
|
|
7294
|
+
sunroof: fx.hasSunroof("fastback_sedan"),
|
|
7266
7295
|
W: 1.799,
|
|
7267
7296
|
col: hex,
|
|
7268
7297
|
bottomY: 0.2,
|
|
@@ -7557,6 +7586,8 @@ var GameVehiclesThree = (() => {
|
|
|
7557
7586
|
fx.register(
|
|
7558
7587
|
{
|
|
7559
7588
|
key: "classic_six_sedan",
|
|
7589
|
+
// glass headlight lenses, as on cars of its time: they shatter (a modern car's are polycarbonate)
|
|
7590
|
+
headlightLens: "glass",
|
|
7560
7591
|
group: "cars",
|
|
7561
7592
|
name: trl("vehicles.classic_six_sedan.name"),
|
|
7562
7593
|
inspired: trl("vehicles.classic_six_sedan.inspired"),
|
|
@@ -7858,7 +7889,7 @@ var GameVehiclesThree = (() => {
|
|
|
7858
7889
|
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;
|
|
7859
7890
|
const gyb = function(u) {
|
|
7860
7891
|
const z = Math.abs(g.zu(u));
|
|
7861
|
-
return z <= zb ? yB0 : yB0 + (yT - 0.02 - yB0) *
|
|
7892
|
+
return z <= zb ? yB0 : yB0 + (yT - 0.02 - yB0) * clamp5((z - zb) / (zt - zb), 0, 1);
|
|
7862
7893
|
};
|
|
7863
7894
|
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 });
|
|
7864
7895
|
outline(c2, g, { u0: g.uz(-zt), u1: g.uz(zt), yb: gyb, yt: yT }, 0.012, LH, 0.024);
|
|
@@ -8667,7 +8698,7 @@ var GameVehiclesThree = (() => {
|
|
|
8667
8698
|
lightsY: 0.82
|
|
8668
8699
|
});
|
|
8669
8700
|
const tx = -1.25, len2 = 6.2, ty = 2.08, sy = 0.82, sz = 1.16;
|
|
8670
|
-
function
|
|
8701
|
+
function hz2(y) {
|
|
8671
8702
|
const d = (y - ty) / sy;
|
|
8672
8703
|
return sz * Math.sqrt(Math.max(0, 1 - d * d));
|
|
8673
8704
|
}
|
|
@@ -8721,12 +8752,12 @@ var GameVehiclesThree = (() => {
|
|
|
8721
8752
|
[1, -1].forEach(function(s) {
|
|
8722
8753
|
c.cylinder(0.12, 0.12, 2.3, ALU, 0.25, 1.36, s * 1, "x");
|
|
8723
8754
|
c.cylinder(0.1, 0.1, 0.02, MT.dark, -0.91, 1.36, s * 1, "x");
|
|
8724
|
-
c.roundBox(0.42, 0.32, 0.012, 0.01, CM("#d9771c"), tx + 1.6, ty - 0.25, s * (
|
|
8725
|
-
c.text("33", 0.36, 0.13, tx + 1.6, ty - 0.18, s * (
|
|
8726
|
-
c.text("1203", 0.36, 0.13, tx + 1.6, ty - 0.32, s * (
|
|
8727
|
-
const dia = c.roundBox(0.3, 0.3, 0.012, 0.01, CM("#c3271c"), tx + 2.15, ty - 0.25, s * (
|
|
8755
|
+
c.roundBox(0.42, 0.32, 0.012, 0.01, CM("#d9771c"), tx + 1.6, ty - 0.25, s * (hz2(ty - 0.1) + 6e-3));
|
|
8756
|
+
c.text("33", 0.36, 0.13, tx + 1.6, ty - 0.18, s * (hz2(ty - 0.1) + 0.014), s > 0 ? "+z" : "-z", { fg: "#111", size: 0.85 });
|
|
8757
|
+
c.text("1203", 0.36, 0.13, tx + 1.6, ty - 0.32, s * (hz2(ty - 0.1) + 0.014), s > 0 ? "+z" : "-z", { fg: "#111", size: 0.85 });
|
|
8758
|
+
const dia = c.roundBox(0.3, 0.3, 0.012, 0.01, CM("#c3271c"), tx + 2.15, ty - 0.25, s * (hz2(ty - 0.05) + 6e-3));
|
|
8728
8759
|
dia.rotation.z = PI / 4;
|
|
8729
|
-
c.text("3", 0.18, 0.18, tx + 2.15, ty - 0.27, s * (
|
|
8760
|
+
c.text("3", 0.18, 0.18, tx + 2.15, ty - 0.27, s * (hz2(ty - 0.05) + 0.014), s > 0 ? "+z" : "-z", { fg: "#fff", size: 0.9 });
|
|
8730
8761
|
c.text(trl("texts.flammable"), 1.12, 0.3, tx - 0.625, ty + 0.12, s * (sz + 0.012), s > 0 ? "+z" : "-z", { fg: "#b3261e" });
|
|
8731
8762
|
for (let k = 0; k < 11; k++)
|
|
8732
8763
|
c.roundBox(
|
|
@@ -8737,7 +8768,7 @@ var GameVehiclesThree = (() => {
|
|
|
8737
8768
|
k % 2 ? REFL_W : REFL_R,
|
|
8738
8769
|
tx - 2.8 + k * 0.55,
|
|
8739
8770
|
ty - sy * 0.72,
|
|
8740
|
-
s * (
|
|
8771
|
+
s * (hz2(ty - sy * 0.62) + 6e-3)
|
|
8741
8772
|
);
|
|
8742
8773
|
c.roundBox(0.42, 0.42, 0.25, 0.04, CM("#b3261e"), 2.2, 1, s * (W / 2 - 0.15));
|
|
8743
8774
|
});
|
|
@@ -11753,7 +11784,7 @@ var GameVehiclesThree = (() => {
|
|
|
11753
11784
|
m.castShadow = true;
|
|
11754
11785
|
m.receiveShadow = false;
|
|
11755
11786
|
for (let k = 0; k < 14; k++) {
|
|
11756
|
-
const hx = x0 + 0.2 + (x1 - x0 - 0.4) * kit.hash(k, 1, 7),
|
|
11787
|
+
const hx = x0 + 0.2 + (x1 - x0 - 0.4) * kit.hash(k, 1, 7), hz2 = (kit.hash(k, 2, 7) - 0.5) * w * 0.85, n = 3 + Math.floor(kit.hash(k, 4, 7) * 3);
|
|
11757
11788
|
for (let q = 0; q < n; q++) {
|
|
11758
11789
|
const r = 0.07 + kit.hash(k, q, 11) * 0.07, geo = new THREE.IcosahedronGeometry(r, 1), p = geo.attributes.position;
|
|
11759
11790
|
for (let vi = 0; vi < p.count; vi++) {
|
|
@@ -11761,7 +11792,7 @@ var GameVehiclesThree = (() => {
|
|
|
11761
11792
|
p.setXYZ(vi, p.getX(vi) * f, p.getY(vi) * f * 0.8, p.getZ(vi) * f);
|
|
11762
11793
|
}
|
|
11763
11794
|
geo.computeVertexNormals();
|
|
11764
|
-
const ang = q / n * PI * 2 + k, tf = c.add(geo, (k + q) % 2 ? NET : NET2, hx + Math.cos(ang) * 0.1, prof(
|
|
11795
|
+
const ang = q / n * PI * 2 + k, tf = c.add(geo, (k + q) % 2 ? NET : NET2, hx + Math.cos(ang) * 0.1, prof(hz2) + 0.1 + r * 0.5, hz2 + Math.sin(ang) * 0.1);
|
|
11765
11796
|
tf.rotation.set(kit.hash(k, q, 1) * 3, kit.hash(k, q, 2) * 3, 0);
|
|
11766
11797
|
}
|
|
11767
11798
|
}
|
|
@@ -13644,7 +13675,7 @@ var GameVehiclesThree = (() => {
|
|
|
13644
13675
|
}
|
|
13645
13676
|
};
|
|
13646
13677
|
}
|
|
13647
|
-
function militaryRotor(c, x, y, z, n, len,
|
|
13678
|
+
function militaryRotor(c, x, y, z, n, len, chord2, mat, o) {
|
|
13648
13679
|
o = o || {};
|
|
13649
13680
|
const g = new THREE.Group();
|
|
13650
13681
|
g.position.set(x, y, z);
|
|
@@ -13652,7 +13683,7 @@ var GameVehiclesThree = (() => {
|
|
|
13652
13683
|
for (let i = 0; i < n; i++) {
|
|
13653
13684
|
const piv = new THREE.Group();
|
|
13654
13685
|
piv.rotation[o.axis === "z" ? "z" : "y"] = i / n * PI * 2 + (o.phase || 0);
|
|
13655
|
-
const geo = G2.roundedBox(len, o.th || 0.06,
|
|
13686
|
+
const geo = G2.roundedBox(len, o.th || 0.06, chord2, 0.02);
|
|
13656
13687
|
geo.translate(len / 2 + (o.hub || 0.3), 0, 0);
|
|
13657
13688
|
if (o.droop) {
|
|
13658
13689
|
const p = geo.attributes.position;
|
|
@@ -13667,7 +13698,7 @@ var GameVehiclesThree = (() => {
|
|
|
13667
13698
|
if (o.axis === "z") b.rotation.x = PI / 2;
|
|
13668
13699
|
piv.add(b);
|
|
13669
13700
|
if (o.tip) {
|
|
13670
|
-
const tp = new THREE.Mesh(G2.roundedBox(0.25, (o.th || 0.06) + 5e-3,
|
|
13701
|
+
const tp = new THREE.Mesh(G2.roundedBox(0.25, (o.th || 0.06) + 5e-3, chord2 + 5e-3, 0.01), o.tip);
|
|
13671
13702
|
tp.position.set(len + (o.hub || 0.3) - 0.12, -(o.droop || 0), 0);
|
|
13672
13703
|
if (o.axis === "z") tp.rotation.x = PI / 2;
|
|
13673
13704
|
piv.add(tp);
|
|
@@ -14017,7 +14048,7 @@ var GameVehiclesThree = (() => {
|
|
|
14017
14048
|
const THREE = kit.THREE;
|
|
14018
14049
|
const trl = fx.t;
|
|
14019
14050
|
const lbl = fx.label;
|
|
14020
|
-
const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, G2 = kit.geo, profX = kit.profX, halfAt = kit.halfAt,
|
|
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;
|
|
14021
14052
|
const GLOSS = CM("#07080a", { roughness: 0.18, metalness: 0.5 });
|
|
14022
14053
|
const ALLOY = CM("#b9bec2", { metalness: 0.75, roughness: 0.3 });
|
|
14023
14054
|
const ALLOYD = CM("#3a3e42", { metalness: 0.6, roughness: 0.35 });
|
|
@@ -14036,7 +14067,7 @@ var GameVehiclesThree = (() => {
|
|
|
14036
14067
|
const a = (y - o.ys) / (o.belt - o.ys);
|
|
14037
14068
|
return o.kt * a * a;
|
|
14038
14069
|
}
|
|
14039
|
-
const b =
|
|
14070
|
+
const b = clamp5((o.ys - y) / (o.ys - o.yb), 0, 1.25);
|
|
14040
14071
|
return o.kb * b * b;
|
|
14041
14072
|
}
|
|
14042
14073
|
const f = function(x, y, z) {
|
|
@@ -14216,13 +14247,13 @@ var GameVehiclesThree = (() => {
|
|
|
14216
14247
|
return L;
|
|
14217
14248
|
}
|
|
14218
14249
|
function roofAt(gh, x) {
|
|
14219
|
-
const rR = gh.roofR || gh.roof, t =
|
|
14250
|
+
const rR = gh.roofR || gh.roof, t = clamp5((x - gh.rt) / (gh.ft - gh.rt), 0, 1);
|
|
14220
14251
|
return rR + (gh.roof - rR) * t + (gh.crown || 0) * 4 * t * (1 - t);
|
|
14221
14252
|
}
|
|
14222
14253
|
function windows(gh) {
|
|
14223
14254
|
const inn = 0.07, rise = gh.rise || 0;
|
|
14224
14255
|
function ybAt(x) {
|
|
14225
|
-
return gh.belt + 0.035 + rise *
|
|
14256
|
+
return gh.belt + 0.035 + rise * clamp5((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
|
|
14226
14257
|
}
|
|
14227
14258
|
function lx(x0, x1, y, top) {
|
|
14228
14259
|
return x0 + (x1 - x0) * (y - gh.belt) / (top - gh.belt);
|
|
@@ -14433,7 +14464,7 @@ var GameVehiclesThree = (() => {
|
|
|
14433
14464
|
}
|
|
14434
14465
|
const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: tot * (full ? 2 : 1), E, sd };
|
|
14435
14466
|
G22.at = function(u, y) {
|
|
14436
|
-
const fi =
|
|
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;
|
|
14437
14468
|
function L(M) {
|
|
14438
14469
|
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);
|
|
14439
14470
|
}
|
|
@@ -14994,7 +15025,7 @@ var GameVehiclesThree = (() => {
|
|
|
14994
15025
|
c.roundBox(x1 - x0, 0.08, 0.035, 0.015, MT.trim, (x0 + x1) / 2, by + 0.05, sd * (hw - 8e-3));
|
|
14995
15026
|
if (s.clad)
|
|
14996
15027
|
s.arches.forEach(function(a) {
|
|
14997
|
-
const a0 = Math.asin(
|
|
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));
|
|
14998
15029
|
tor.rotation.z = a0;
|
|
14999
15030
|
tor.scale.z = 0.8;
|
|
15000
15031
|
});
|
|
@@ -15012,8 +15043,11 @@ var GameVehiclesThree = (() => {
|
|
|
15012
15043
|
);
|
|
15013
15044
|
});
|
|
15014
15045
|
const wy = gh.belt + 0.06, wx = gh.fb - 0.03;
|
|
15015
|
-
[-0.3, 0.2].forEach(function(z) {
|
|
15016
|
-
|
|
15046
|
+
[-0.3, 0.2].forEach(function(z, index) {
|
|
15047
|
+
const spindle = new V3(wx + 0.02, wy, z + 0.02);
|
|
15048
|
+
const blade = c.rod(spindle, new V3(wx - 0.13, wy + 0.13, z - 0.36), 9e-3, MT.trim);
|
|
15049
|
+
const along = new V3(gh.ft - gh.fb, gh.roof - gh.belt, 0).normalize();
|
|
15050
|
+
tagWiper({ context: c, parts: [blade], spindle, normal: new V3(along.y, -along.x, 0), index });
|
|
15017
15051
|
});
|
|
15018
15052
|
if (s.fin !== false)
|
|
15019
15053
|
c.sphere(0.1, s.roofCol ? c.paint(s.roofCol) : GLOSS, gh.rt + 0.2, roofAt(gh, gh.rt + 0.2) + 0.045, 0, 1, 0.45, 0.28, {
|
|
@@ -15115,7 +15149,7 @@ var GameVehiclesThree = (() => {
|
|
|
15115
15149
|
c.cylinder(0.06, 0.06, 0.012, MT.head, x + 0.055, y, z, "x");
|
|
15116
15150
|
}
|
|
15117
15151
|
function sm(t) {
|
|
15118
|
-
t =
|
|
15152
|
+
t = clamp5(t, 0, 1);
|
|
15119
15153
|
return t * t * (3 - 2 * t);
|
|
15120
15154
|
}
|
|
15121
15155
|
function sideGrid(S, sd, o) {
|
|
@@ -15132,7 +15166,7 @@ var GameVehiclesThree = (() => {
|
|
|
15132
15166
|
}
|
|
15133
15167
|
const G22 = { P, N, nu, nv, y0: o.y0, y1: o.y1, len: Math.abs(o.x1 - o.x0) };
|
|
15134
15168
|
G22.at = function(u, y) {
|
|
15135
|
-
const fi =
|
|
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;
|
|
15136
15170
|
function L(M) {
|
|
15137
15171
|
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);
|
|
15138
15172
|
}
|
|
@@ -15293,7 +15327,7 @@ var GameVehiclesThree = (() => {
|
|
|
15293
15327
|
return function(c, I) {
|
|
15294
15328
|
const gh = I.gh, col = c.meta.color;
|
|
15295
15329
|
function yb(x) {
|
|
15296
|
-
return gh.belt + 0.035 + (gh.rise || 0) *
|
|
15330
|
+
return gh.belt + 0.035 + (gh.rise || 0) * clamp5((gh.fb - x) / (gh.fb - gh.rb), 0, 1);
|
|
15297
15331
|
}
|
|
15298
15332
|
;
|
|
15299
15333
|
[1, -1].forEach(function(sd) {
|
|
@@ -18089,6 +18123,8 @@ var GameVehiclesThree = (() => {
|
|
|
18089
18123
|
fx.register(
|
|
18090
18124
|
{
|
|
18091
18125
|
key: "beetle",
|
|
18126
|
+
// glass headlight lenses, as on cars of its time: they shatter (a modern car's are polycarbonate)
|
|
18127
|
+
headlightLens: "glass",
|
|
18092
18128
|
group: "cars",
|
|
18093
18129
|
name: trl("vehicles.beetle.name"),
|
|
18094
18130
|
inspired: trl("vehicles.beetle.inspired"),
|
|
@@ -18164,7 +18200,7 @@ var GameVehiclesThree = (() => {
|
|
|
18164
18200
|
return n.y > 0.3 && ce.x > 0.9 && ce.y > 0.6;
|
|
18165
18201
|
},
|
|
18166
18202
|
sdf: function(x, y, z) {
|
|
18167
|
-
const t =
|
|
18203
|
+
const t = clamp5((x - 1.17) / 0.5, 0, 1);
|
|
18168
18204
|
return Math.max(0.94 - x, x - 1.69, Math.abs(z) - (0.44 - 0.16 * t * t));
|
|
18169
18205
|
}
|
|
18170
18206
|
});
|
|
@@ -18868,8 +18904,8 @@ var GameVehiclesThree = (() => {
|
|
|
18868
18904
|
];
|
|
18869
18905
|
body(c, RB, col);
|
|
18870
18906
|
[1, -1].forEach(function(s) {
|
|
18871
|
-
const x = -0.3, y = 0.6,
|
|
18872
|
-
c.text(trl("texts.bis_125"), 0.2, 0.05, x, y, s *
|
|
18907
|
+
const x = -0.3, y = 0.6, hz2 = loftHalf(RB, x, y) + 4e-3;
|
|
18908
|
+
c.text(trl("texts.bis_125"), 0.2, 0.05, x, y, s * hz2, s > 0 ? "+z" : "-z", { fg: "#f2f0ea", size: 0.85 });
|
|
18873
18909
|
body(
|
|
18874
18910
|
c,
|
|
18875
18911
|
[
|
|
@@ -22162,7 +22198,7 @@ var GameVehiclesThree = (() => {
|
|
|
22162
22198
|
const THREE = kit.THREE;
|
|
22163
22199
|
const trl = fx.t;
|
|
22164
22200
|
const lbl = fx.label;
|
|
22165
|
-
const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial,
|
|
22201
|
+
const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, clamp5 = kit.clamp, smooth2 = kit.smooth;
|
|
22166
22202
|
const CLAD = CM("#1a1b1d", { roughness: 0.82 }), LINER = CM("#1c1d1f", { roughness: 0.92 }), RIMDARK = CM("#2a2d30", { metalness: 0.6, roughness: 0.4 });
|
|
22167
22203
|
const RIMSIL = CM("#b9bec2", { metalness: 0.75, roughness: 0.3 }), RIMGUN = CM("#55595d", { metalness: 0.7, roughness: 0.35 });
|
|
22168
22204
|
function axles(WB, oF, L, dF, dR) {
|
|
@@ -22193,16 +22229,16 @@ var GameVehiclesThree = (() => {
|
|
|
22193
22229
|
const m = c.meta, W = m.width, by = o.bottom != null ? o.bottom : m.clearance, top = o.top != null ? o.top : m.belt;
|
|
22194
22230
|
const Wg = m.glasshouse && m.glasshouse.Wg || W, front = m.front, rear = m.rear;
|
|
22195
22231
|
const tuck = o.tuck == null ? 0.045 : o.tuck, peak = o.peak || 0.45;
|
|
22196
|
-
const B = o.sh != null ? o.sh :
|
|
22232
|
+
const B = o.sh != null ? o.sh : clamp5(1 - (Wg + 0.06) / W, 0, 0.06);
|
|
22197
22233
|
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;
|
|
22198
22234
|
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;
|
|
22199
22235
|
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);
|
|
22200
22236
|
function sc(y) {
|
|
22201
|
-
const t =
|
|
22237
|
+
const t = clamp5((y - by) / (top - by), 0, 1);
|
|
22202
22238
|
return t < peak ? 1 - tuck * Math.pow(1 - t / peak, 2) : 1 - B * Math.pow((t - peak) / (1 - peak), 2);
|
|
22203
22239
|
}
|
|
22204
22240
|
function F(v2) {
|
|
22205
|
-
const a = smooth2((v2.x - (front - Rf)) / Rf), b = smooth2((rear + Rr - v2.x) / Rr), zz =
|
|
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);
|
|
22206
22242
|
const bf = smooth2((v2.x - (front - Rb)) / Rb), br = smooth2((rear + Rb - v2.x) / Rb);
|
|
22207
22243
|
const cr = crown * (1 - zz) * smooth2((v2.y - y0) / (top - y0)) * smooth2((v2.x - xc) / 0.3);
|
|
22208
22244
|
v2.x += -bowF * zz * bf + bowR * zz * br;
|
|
@@ -22279,7 +22315,7 @@ var GameVehiclesThree = (() => {
|
|
|
22279
22315
|
o = o || {};
|
|
22280
22316
|
const wd = o.w || 0.075, dp = o.d || 0.045, mat = o.mat || CLAD, out = [];
|
|
22281
22317
|
arches.forEach(function(a) {
|
|
22282
|
-
const a0 = Math.asin(
|
|
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;
|
|
22283
22319
|
const sh = new THREE.Shape();
|
|
22284
22320
|
if (o.trap) {
|
|
22285
22321
|
const yb0 = Math.sin(a0) * r1, xb0 = Math.cos(a0) * r1, top = r1 * 0.93, xt = r1 * 0.52;
|
|
@@ -22629,7 +22665,7 @@ var GameVehiclesThree = (() => {
|
|
|
22629
22665
|
function roof(c, drop, x0, x1) {
|
|
22630
22666
|
const m = c.meta, b = m.glasshouse.belt, h = m.top - b;
|
|
22631
22667
|
function dy(x, y) {
|
|
22632
|
-
const t =
|
|
22668
|
+
const t = clamp5((y - b) / h, 0, 1);
|
|
22633
22669
|
return t <= 0 ? 0 : drop * smooth2((x0 - x) / (x0 - x1)) * t;
|
|
22634
22670
|
}
|
|
22635
22671
|
c.root.updateMatrixWorld(true);
|
|
@@ -23116,17 +23152,17 @@ var GameVehiclesThree = (() => {
|
|
|
23116
23152
|
}
|
|
23117
23153
|
beltline(c2, -0.35, 0.035, col);
|
|
23118
23154
|
pillarC(c2, -1.12, [-1.36, 1.25]);
|
|
23119
|
-
const E = glasshouse(c2),
|
|
23155
|
+
const E = glasshouse(c2), hz2 = function(y) {
|
|
23120
23156
|
return kit.halfAt(m.glasshouse.Wg, m.tumble, y) + 0.03;
|
|
23121
23157
|
};
|
|
23122
23158
|
[1, -1].forEach(function(sd) {
|
|
23123
23159
|
c2.tube(
|
|
23124
23160
|
[
|
|
23125
|
-
[m.glasshouse.fb - 0.08, E.yb - 0.03, sd *
|
|
23126
|
-
[-0.35, E.yb - 0.03, sd *
|
|
23127
|
-
[-1.45, E.yb + 0.01, sd *
|
|
23128
|
-
[E.back(E.yb + 0.15) + 0.05, E.yb + 0.15, sd *
|
|
23129
|
-
[E.back(E.top - 0.05) + 0.06, E.top - 0.05, sd *
|
|
23161
|
+
[m.glasshouse.fb - 0.08, E.yb - 0.03, sd * hz2(E.yb)],
|
|
23162
|
+
[-0.35, E.yb - 0.03, sd * hz2(E.yb)],
|
|
23163
|
+
[-1.45, E.yb + 0.01, sd * hz2(E.yb)],
|
|
23164
|
+
[E.back(E.yb + 0.15) + 0.05, E.yb + 0.15, sd * hz2(E.yb + 0.15)],
|
|
23165
|
+
[E.back(E.top - 0.05) + 0.06, E.top - 0.05, sd * hz2(E.top - 0.05)]
|
|
23130
23166
|
],
|
|
23131
23167
|
9e-3,
|
|
23132
23168
|
MT.chrome,
|
|
@@ -23823,8 +23859,8 @@ var GameVehiclesThree = (() => {
|
|
|
23823
23859
|
setOnHit(pt, function(c2, p0) {
|
|
23824
23860
|
const o = p0.obj;
|
|
23825
23861
|
if (o && o.userData.hung && o.parent && o.parent !== c2.vehicle) {
|
|
23826
|
-
o.parent.rotation.x =
|
|
23827
|
-
o.parent.rotation.y =
|
|
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);
|
|
23828
23864
|
}
|
|
23829
23865
|
});
|
|
23830
23866
|
});
|
|
@@ -24475,7 +24511,7 @@ var GameVehiclesThree = (() => {
|
|
|
24475
24511
|
const shared2 = fx.shared;
|
|
24476
24512
|
const trl = fx.t;
|
|
24477
24513
|
const lbl = fx.label;
|
|
24478
|
-
const V3 = kit.V3, PI = Math.PI, MT = kit.materials, CM = kit.makeMaterial, _paintCol = kit.paintColor, G2 = kit.geo, DS = THREE.DoubleSide,
|
|
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;
|
|
24479
24515
|
function colorize(geo, fn) {
|
|
24480
24516
|
const p = geo.attributes.position, col = new Float32Array(p.count * 3);
|
|
24481
24517
|
for (let i = 0; i < p.count; i++) {
|
|
@@ -24491,7 +24527,7 @@ var GameVehiclesThree = (() => {
|
|
|
24491
24527
|
return a + (b - a) * t;
|
|
24492
24528
|
}
|
|
24493
24529
|
function sstep(a, b, x) {
|
|
24494
|
-
const t =
|
|
24530
|
+
const t = clamp5((x - a) / (b - a), 0, 1);
|
|
24495
24531
|
return t * t * (3 - 2 * t);
|
|
24496
24532
|
}
|
|
24497
24533
|
function tab(T) {
|
|
@@ -24568,7 +24604,7 @@ var GameVehiclesThree = (() => {
|
|
|
24568
24604
|
o,
|
|
24569
24605
|
sec,
|
|
24570
24606
|
t: function(x) {
|
|
24571
|
-
return
|
|
24607
|
+
return clamp5((x - o.x0) / o.L, 0, 1);
|
|
24572
24608
|
},
|
|
24573
24609
|
/* half beam of the hull at height y (inside, so floors and decks do not leak) */
|
|
24574
24610
|
half: function(x, y) {
|
|
@@ -24742,7 +24778,7 @@ var GameVehiclesThree = (() => {
|
|
|
24742
24778
|
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
|
24743
24779
|
const a = poly[i], b = poly[j];
|
|
24744
24780
|
if (a[1] > y !== b[1] > y && x < (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]) + a[0]) inside = !inside;
|
|
24745
|
-
const vx = b[0] - a[0], vy = b[1] - a[1], wx = x - a[0], wy = y - a[1], t =
|
|
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);
|
|
24746
24782
|
d = Math.min(d, Math.hypot(wx - vx * t, wy - vy * t));
|
|
24747
24783
|
}
|
|
24748
24784
|
return inside ? -d : d;
|
|
@@ -27290,6 +27326,7 @@ var GameVehiclesThree = (() => {
|
|
|
27290
27326
|
shared: shared2,
|
|
27291
27327
|
t,
|
|
27292
27328
|
label: (key) => ({ key, label: t("labels." + key) }),
|
|
27329
|
+
hasSunroof: (key) => !!options.sunroofs?.includes(key),
|
|
27293
27330
|
register(spec, build) {
|
|
27294
27331
|
if (!groups.has(spec.group) || only && !only.has(spec.key) || skip.has(spec.key)) return;
|
|
27295
27332
|
kit.register({ ...spec, seedKey: legacyVehicleSeeds[spec.key] }, build);
|
|
@@ -29267,8 +29304,8 @@ var GameVehiclesThree = (() => {
|
|
|
29267
29304
|
const face = faces[i];
|
|
29268
29305
|
f3(face[2] + offset, face[1] + offset, face[0] + offset);
|
|
29269
29306
|
}
|
|
29270
|
-
const
|
|
29271
|
-
offset = vlen *
|
|
29307
|
+
const layer2 = steps + bevelSegments * 2;
|
|
29308
|
+
offset = vlen * layer2;
|
|
29272
29309
|
for (let i = 0; i < flen; i++) {
|
|
29273
29310
|
const face = faces[i];
|
|
29274
29311
|
f3(face[0] + offset, face[1] + offset, face[2] + offset);
|
|
@@ -30771,7 +30808,7 @@ var GameVehiclesThree = (() => {
|
|
|
30771
30808
|
const nr = g.attributes.normal;
|
|
30772
30809
|
const hx = w / 2 - r;
|
|
30773
30810
|
const hy = h / 2 - r;
|
|
30774
|
-
const
|
|
30811
|
+
const hz2 = d / 2 - r;
|
|
30775
30812
|
function map(v, hi) {
|
|
30776
30813
|
const i = Math.round((v + 0.5) * n);
|
|
30777
30814
|
return i <= nb ? -hi - r * (nb - i) / nb : hi + r * (i - nb - 1) / nb;
|
|
@@ -30780,8 +30817,8 @@ var GameVehiclesThree = (() => {
|
|
|
30780
30817
|
const c = new V3();
|
|
30781
30818
|
const dir = new V3();
|
|
30782
30819
|
for (let i = 0; i < p.count; i++) {
|
|
30783
|
-
q.set(map(p.getX(i), hx), map(p.getY(i), hy), map(p.getZ(i),
|
|
30784
|
-
c.set(clamp(q.x, -hx, hx), clamp(q.y, -hy, hy), clamp(q.z, -
|
|
30820
|
+
q.set(map(p.getX(i), hx), map(p.getY(i), hy), map(p.getZ(i), hz2));
|
|
30821
|
+
c.set(clamp(q.x, -hx, hx), clamp(q.y, -hy, hy), clamp(q.z, -hz2, hz2));
|
|
30785
30822
|
dir.subVectors(q, c);
|
|
30786
30823
|
if (dir.lengthSq() > 1e-12) {
|
|
30787
30824
|
dir.normalize();
|
|
@@ -33504,13 +33541,13 @@ var GameVehiclesThree = (() => {
|
|
|
33504
33541
|
);
|
|
33505
33542
|
const hy = hl.y || s.headY || s.noseY - 0.06;
|
|
33506
33543
|
const hx = I.profX(it, hy, true);
|
|
33507
|
-
const
|
|
33544
|
+
const hz2 = W / 2 - hl.in - hl.w / 2;
|
|
33508
33545
|
[1, -1].forEach(function(sd) {
|
|
33509
33546
|
kit.headlight(c, {
|
|
33510
33547
|
style: hl.style,
|
|
33511
33548
|
x: hx + 0.02 + (hl.dx || 0),
|
|
33512
33549
|
y: hy,
|
|
33513
|
-
z: sd *
|
|
33550
|
+
z: sd * hz2,
|
|
33514
33551
|
w: hl.w,
|
|
33515
33552
|
h: hl.h,
|
|
33516
33553
|
side: sd,
|
|
@@ -33518,7 +33555,7 @@ var GameVehiclesThree = (() => {
|
|
|
33518
33555
|
mat: hl.mat
|
|
33519
33556
|
});
|
|
33520
33557
|
});
|
|
33521
|
-
if (hl.style === "ledbar") kit.lightBar(c, hx + 0.03, hy + hl.h * 0.3, -
|
|
33558
|
+
if (hl.style === "ledbar") kit.lightBar(c, hx + 0.03, hy + hl.h * 0.3, -hz2 + hl.w / 2, hz2 - hl.w / 2, 0.018, 1);
|
|
33522
33559
|
if (s.grille !== false && !s.noGrille) {
|
|
33523
33560
|
const gr = Object.assign({ style: "bars", w: W * 0.44, h: Math.max(0.08, hy - bumperY - 0.12) }, s.grille || {});
|
|
33524
33561
|
const gy = gr.y || (bumperY + hy) / 2 + 0.02;
|
|
@@ -35135,8 +35172,20 @@ var GameVehiclesThree = (() => {
|
|
|
35135
35172
|
if (!L || L.broken) return;
|
|
35136
35173
|
L.broken = true;
|
|
35137
35174
|
L.lens.forEach(function(m) {
|
|
35138
|
-
m.
|
|
35175
|
+
const rim = L.lensMaterial ? glassRim(m.geometry, c.rand) : null;
|
|
35176
|
+
if (!rim) {
|
|
35177
|
+
m.visible = false;
|
|
35178
|
+
return;
|
|
35179
|
+
}
|
|
35180
|
+
m.geometry.dispose();
|
|
35181
|
+
m.geometry = rim;
|
|
35182
|
+
m.material = MATERIALS.glassEdge;
|
|
35183
|
+
m.userData.lensRim = true;
|
|
35139
35184
|
});
|
|
35185
|
+
if (L.lensMaterial)
|
|
35186
|
+
(L.reflector || []).forEach(function(m) {
|
|
35187
|
+
m.material = MATERIALS.broken;
|
|
35188
|
+
});
|
|
35140
35189
|
L.inner.forEach(function(m) {
|
|
35141
35190
|
m.material = MATERIALS.bulbBroken;
|
|
35142
35191
|
});
|
|
@@ -35144,11 +35193,38 @@ var GameVehiclesThree = (() => {
|
|
|
35144
35193
|
h.visible = false;
|
|
35145
35194
|
});
|
|
35146
35195
|
const p = L.group ? L.group.position.clone() : L.inner[0] ? L.inner[0].position.clone() : new V3();
|
|
35147
|
-
|
|
35148
|
-
I.burst(c, "
|
|
35196
|
+
const glass = L.lensMaterial !== "plastic";
|
|
35197
|
+
I.burst(c, "lens", c.toEffects(p), glass ? 10 : 5, { dir: c.dirToEffects(dir.clone().negate()), speed: glass ? 1.4 : 1.1, variant: L.tint === "red" ? "red" : "clear" });
|
|
35198
|
+
I.burst(c, "plastic", c.toEffects(p), glass ? 2 : 5, { dir: c.dirToEffects(dir.clone().negate()), speed: 1 });
|
|
35149
35199
|
}
|
|
35150
35200
|
kit.breakLight = breakLight;
|
|
35151
|
-
|
|
35201
|
+
const crazedCache = /* @__PURE__ */ new Map();
|
|
35202
|
+
const CRAZED_OPACITY = 0.6;
|
|
35203
|
+
function crazed(material) {
|
|
35204
|
+
const known = crazedCache.get(material);
|
|
35205
|
+
if (known) return known;
|
|
35206
|
+
const m = I.crackLens(material).clone();
|
|
35207
|
+
m.opacity = Math.max(m.opacity ?? 1, CRAZED_OPACITY);
|
|
35208
|
+
m.transparent = true;
|
|
35209
|
+
m.userData.shared = true;
|
|
35210
|
+
crazedCache.set(material, m);
|
|
35211
|
+
return m;
|
|
35212
|
+
}
|
|
35213
|
+
function crackLight(c, L, dir, pierced) {
|
|
35214
|
+
if (!L || L.broken) return;
|
|
35215
|
+
if (!L.cracked) {
|
|
35216
|
+
L.cracked = true;
|
|
35217
|
+
for (const m of L.lens) if (m.material && !Array.isArray(m.material)) m.material = crazed(m.material);
|
|
35218
|
+
}
|
|
35219
|
+
const p = L.group ? L.group.position.clone() : L.inner[0] ? L.inner[0].position.clone() : new V3();
|
|
35220
|
+
I.burst(c, "lens", c.toEffects(p), 3, { dir: c.dirToEffects(dir.clone().negate()), speed: 0.9, variant: L.tint === "red" ? "red" : "clear" });
|
|
35221
|
+
if (!pierced || L.dark) return;
|
|
35222
|
+
L.dark = true;
|
|
35223
|
+
for (const m of L.inner) m.material = MATERIALS.bulbBroken;
|
|
35224
|
+
for (const h of L.halo ?? []) h.visible = false;
|
|
35225
|
+
}
|
|
35226
|
+
kit.crackLight = crackLight;
|
|
35227
|
+
Object.assign(I, { glassUV, drawWeb, crackGlass, glassRim, shatterGlass, hitGlass, breakLight, crackLight });
|
|
35152
35228
|
}
|
|
35153
35229
|
function installImpact(kit) {
|
|
35154
35230
|
const THREE = kit.THREE;
|
|
@@ -40658,6 +40734,8 @@ var GameVehiclesThree = (() => {
|
|
|
40658
40734
|
heli: ["battery", "alternator", "gearbox"]
|
|
40659
40735
|
};
|
|
40660
40736
|
var HITCH_CHANCE = { car: 30, truck: 60, bus: 0, tractor: 100, quad: 40, bike: 0, tank: 0, boat: 0, plane: 0, heli: 0 };
|
|
40737
|
+
var GLASS_LENS_HP = 320;
|
|
40738
|
+
var PLASTIC_LENS_HP = 900;
|
|
40661
40739
|
var STEEL_KG_M2 = 7;
|
|
40662
40740
|
var ALU_KG_M2 = 3.2;
|
|
40663
40741
|
var kindOf = (c) => {
|
|
@@ -40815,7 +40893,9 @@ var GameVehiclesThree = (() => {
|
|
|
40815
40893
|
continue;
|
|
40816
40894
|
}
|
|
40817
40895
|
if (role === "light") {
|
|
40818
|
-
|
|
40896
|
+
const lens = /^head/.test(id) ? spec.headlightLens ?? "polycarbonate" : "acrylic";
|
|
40897
|
+
const glassLens = lens === "glass";
|
|
40898
|
+
add2({ id, role, name: label, material: glassLens ? "glass" : "plastic", box: box2, mass: 1.2 + 4 * area3, hp: glassLens ? GLASS_LENS_HP : PLASTIC_LENS_HP, zoneId: id, visual: true, tags: ["light", `lens_${lens}`, ...tags] });
|
|
40819
40899
|
continue;
|
|
40820
40900
|
}
|
|
40821
40901
|
if (role === "bumper") {
|
|
@@ -41269,20 +41349,185 @@ var GameVehiclesThree = (() => {
|
|
|
41269
41349
|
mesh2.geometry.dispose();
|
|
41270
41350
|
mesh2.geometry = g;
|
|
41271
41351
|
}
|
|
41352
|
+
var STRIP_SMOOTH_DEG = 180;
|
|
41353
|
+
var SKIN_BAND = 0.05;
|
|
41354
|
+
var BODY_FACING = 0.5;
|
|
41355
|
+
var FIELDS = 4;
|
|
41356
|
+
var SEAM_THIN = 0.03;
|
|
41357
|
+
var SEAM_AT_EDGE = 0.04;
|
|
41358
|
+
var SEAM_TALL = 0.4;
|
|
41359
|
+
var SLIVER_AREA = 1e-10;
|
|
41360
|
+
function cutStripOverDoor(vehicleKit, params) {
|
|
41361
|
+
const kit = vehicleKit;
|
|
41362
|
+
const strip = params.strip;
|
|
41363
|
+
const toVehicle = params.toVehicle;
|
|
41364
|
+
const { x0, x1 } = params;
|
|
41365
|
+
const THREE = kit.THREE;
|
|
41366
|
+
const at = new THREE.Vector3();
|
|
41367
|
+
const along = (x, y, z) => at.set(x, y, z).applyMatrix4(toVehicle).x;
|
|
41368
|
+
const piece = (tests) => {
|
|
41369
|
+
const mesh2 = new THREE.Mesh(strip.geometry.clone(), strip.material);
|
|
41370
|
+
kit.cutMesh(mesh2, tests, STRIP_SMOOTH_DEG, {});
|
|
41371
|
+
return mesh2;
|
|
41372
|
+
};
|
|
41373
|
+
const over = piece([{ sdf: (x, y, z) => along(x, y, z) - x0 }, { sdf: (x, y, z) => x1 - along(x, y, z) }]);
|
|
41374
|
+
const after = piece([{ sdf: (x, y, z) => along(x, y, z) - x1 }]);
|
|
41375
|
+
kit.cutMesh(strip, [{ sdf: (x, y, z) => x0 - along(x, y, z) }], STRIP_SMOOTH_DEG, {});
|
|
41376
|
+
const joined = joinTriangles(THREE, strip.geometry, after.geometry);
|
|
41377
|
+
strip.geometry.dispose();
|
|
41378
|
+
after.geometry.dispose();
|
|
41379
|
+
strip.geometry = joined;
|
|
41380
|
+
return over;
|
|
41381
|
+
}
|
|
41382
|
+
function joinTriangles(THREE, first, second) {
|
|
41383
|
+
const a = first.index ? first.toNonIndexed() : first;
|
|
41384
|
+
const b = second.index ? second.toNonIndexed() : second;
|
|
41385
|
+
const flags = [...solidTriangles(THREE, a), ...solidTriangles(THREE, b)];
|
|
41386
|
+
const both = new THREE.BufferGeometry();
|
|
41387
|
+
for (const name of Object.keys(a.attributes)) {
|
|
41388
|
+
const p = a.getAttribute(name);
|
|
41389
|
+
const q = b.getAttribute(name);
|
|
41390
|
+
if (!q || q.itemSize !== p.itemSize) continue;
|
|
41391
|
+
const array = new Float32Array(p.array.length + q.array.length);
|
|
41392
|
+
array.set(p.array, 0);
|
|
41393
|
+
array.set(q.array, p.array.length);
|
|
41394
|
+
both.setAttribute(name, new THREE.Float32BufferAttribute(array, p.itemSize));
|
|
41395
|
+
}
|
|
41396
|
+
if (a !== first) a.dispose();
|
|
41397
|
+
if (b !== second) b.dispose();
|
|
41398
|
+
const out = pickTriangles(THREE, both, flags, true) ?? new THREE.BufferGeometry();
|
|
41399
|
+
both.dispose();
|
|
41400
|
+
return out;
|
|
41401
|
+
}
|
|
41402
|
+
function solidTriangles(THREE, geometry) {
|
|
41403
|
+
const pos = geometry.getAttribute("position");
|
|
41404
|
+
const triangle = new THREE.Triangle();
|
|
41405
|
+
const flags = [];
|
|
41406
|
+
for (let t = 0; t * 3 + 2 < pos.count; t++) {
|
|
41407
|
+
triangle.a.fromBufferAttribute(pos, t * 3);
|
|
41408
|
+
triangle.b.fromBufferAttribute(pos, t * 3 + 1);
|
|
41409
|
+
triangle.c.fromBufferAttribute(pos, t * 3 + 2);
|
|
41410
|
+
flags.push(triangle.getArea() > SLIVER_AREA);
|
|
41411
|
+
}
|
|
41412
|
+
return flags;
|
|
41413
|
+
}
|
|
41414
|
+
function splitDoorSkin(three, meshes, toVehicleOf, side2, depth) {
|
|
41415
|
+
const THREE = three;
|
|
41416
|
+
const pieces = meshes;
|
|
41417
|
+
const toVehicle = toVehicleOf;
|
|
41418
|
+
const v = new THREE.Vector3();
|
|
41419
|
+
const corners = [new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3()];
|
|
41420
|
+
const triangle = new THREE.Triangle();
|
|
41421
|
+
const centres = pieces.map((mesh2) => {
|
|
41422
|
+
const geometry = mesh2.geometry.index ? mesh2.geometry.toNonIndexed() : mesh2.geometry;
|
|
41423
|
+
const matrix = toVehicle(mesh2);
|
|
41424
|
+
const pos = geometry.getAttribute("position");
|
|
41425
|
+
const out = new Float32Array(pos.count / 3 * FIELDS);
|
|
41426
|
+
for (let t = 0; t * 3 + 2 < pos.count; t++) {
|
|
41427
|
+
let y = 0;
|
|
41428
|
+
let across = 0;
|
|
41429
|
+
for (let k = 0; k < 3; k++) {
|
|
41430
|
+
corners[k].fromBufferAttribute(pos, t * 3 + k).applyMatrix4(matrix);
|
|
41431
|
+
y += corners[k].y / 3;
|
|
41432
|
+
across += side2 * corners[k].z / 3;
|
|
41433
|
+
}
|
|
41434
|
+
out[t * FIELDS] = y;
|
|
41435
|
+
out[t * FIELDS + 1] = across;
|
|
41436
|
+
triangle.set(corners[0], corners[1], corners[2]).getNormal(v);
|
|
41437
|
+
out[t * FIELDS + 2] = v.y;
|
|
41438
|
+
out[t * FIELDS + 3] = v.x;
|
|
41439
|
+
}
|
|
41440
|
+
return { geometry, out };
|
|
41441
|
+
});
|
|
41442
|
+
const outer = /* @__PURE__ */ new Map();
|
|
41443
|
+
for (const { out } of centres)
|
|
41444
|
+
for (let t = 0; t * FIELDS < out.length; t++) {
|
|
41445
|
+
const band = Math.floor(out[t * FIELDS] / SKIN_BAND);
|
|
41446
|
+
outer.set(band, Math.max(outer.get(band) ?? -Infinity, out[t * FIELDS + 1]));
|
|
41447
|
+
}
|
|
41448
|
+
const surfaceAt = (y) => {
|
|
41449
|
+
const band = Math.floor(y / SKIN_BAND);
|
|
41450
|
+
return Math.max(outer.get(band - 1) ?? -Infinity, outer.get(band) ?? -Infinity, outer.get(band + 1) ?? -Infinity);
|
|
41451
|
+
};
|
|
41452
|
+
return centres.map(({ geometry, out }, i) => {
|
|
41453
|
+
const near = [];
|
|
41454
|
+
for (let t = 0; t * FIELDS < out.length; t++) {
|
|
41455
|
+
const f = t * FIELDS;
|
|
41456
|
+
const body = out[f + 1] < surfaceAt(out[f]) - depth && (out[f + 2] < -BODY_FACING || Math.abs(out[f + 3]) > BODY_FACING);
|
|
41457
|
+
near.push(!body);
|
|
41458
|
+
}
|
|
41459
|
+
const result = { skin: pickTriangles(THREE, geometry, near, true), deep: pickTriangles(THREE, geometry, near, false) };
|
|
41460
|
+
if (geometry !== pieces[i].geometry) geometry.dispose();
|
|
41461
|
+
return result;
|
|
41462
|
+
});
|
|
41463
|
+
}
|
|
41464
|
+
function leaveDeepSkinOnBody(three, meshes, params) {
|
|
41465
|
+
const THREE = three;
|
|
41466
|
+
const pieces = meshes;
|
|
41467
|
+
const toVehicle = params.toVehicle;
|
|
41468
|
+
const { side: side2, depth } = params;
|
|
41469
|
+
const split = splitDoorSkin(THREE, pieces, (mesh2) => new THREE.Matrix4().multiplyMatrices(toVehicle, mesh2.matrixWorld), side2, depth);
|
|
41470
|
+
split.forEach(({ skin, deep }, i) => {
|
|
41471
|
+
const piece = pieces[i];
|
|
41472
|
+
if (!deep || !skin || !piece.parent) return;
|
|
41473
|
+
const body = new THREE.Mesh(deep, piece.material);
|
|
41474
|
+
body.position.copy(piece.position);
|
|
41475
|
+
body.quaternion.copy(piece.quaternion);
|
|
41476
|
+
body.scale.copy(piece.scale);
|
|
41477
|
+
body.castShadow = piece.castShadow;
|
|
41478
|
+
body.receiveShadow = piece.receiveShadow;
|
|
41479
|
+
piece.parent.add(body);
|
|
41480
|
+
piece.geometry.dispose();
|
|
41481
|
+
piece.geometry = skin;
|
|
41482
|
+
});
|
|
41483
|
+
}
|
|
41484
|
+
function pickTriangles(THREE, geometry, flags, wanted) {
|
|
41485
|
+
const count2 = flags.filter((flag) => flag === wanted).length;
|
|
41486
|
+
if (!count2) return null;
|
|
41487
|
+
const out = new THREE.BufferGeometry();
|
|
41488
|
+
for (const name of Object.keys(geometry.attributes)) {
|
|
41489
|
+
const attribute = geometry.getAttribute(name);
|
|
41490
|
+
const size = attribute.itemSize;
|
|
41491
|
+
const source = attribute.array;
|
|
41492
|
+
const array = new Float32Array(count2 * 3 * size);
|
|
41493
|
+
let w = 0;
|
|
41494
|
+
flags.forEach((flag, t) => {
|
|
41495
|
+
if (flag !== wanted) return;
|
|
41496
|
+
array.set(source.subarray(t * 3 * size, (t + 1) * 3 * size), w);
|
|
41497
|
+
w += 3 * size;
|
|
41498
|
+
});
|
|
41499
|
+
out.setAttribute(name, new THREE.Float32BufferAttribute(array, size));
|
|
41500
|
+
}
|
|
41501
|
+
out.computeBoundingBox();
|
|
41502
|
+
out.computeBoundingSphere();
|
|
41503
|
+
return out;
|
|
41504
|
+
}
|
|
41505
|
+
function isDoorSeam(three, params) {
|
|
41506
|
+
const THREE = three;
|
|
41507
|
+
const box2 = params.box;
|
|
41508
|
+
const { zone, side: side2, dark } = params;
|
|
41509
|
+
if (!dark || box2.isEmpty()) return false;
|
|
41510
|
+
const size = box2.getSize(new THREE.Vector3());
|
|
41511
|
+
const centre = box2.getCenter(new THREE.Vector3());
|
|
41512
|
+
if (Math.sign(centre.z) !== Math.sign(side2) || size.x > SEAM_THIN || size.z > SEAM_THIN || size.y < (zone.y1 - zone.y0) * SEAM_TALL) return false;
|
|
41513
|
+
if (centre.y < zone.y0 || centre.y > zone.y1) return false;
|
|
41514
|
+
return Math.abs(centre.x - zone.x0) < SEAM_AT_EDGE || Math.abs(centre.x - zone.x1) < SEAM_AT_EDGE;
|
|
41515
|
+
}
|
|
41272
41516
|
var HOLE_DECAL_SCALE = 2.4;
|
|
41273
41517
|
var DOOR_DEPTH = 0.07;
|
|
41518
|
+
var DOOR_SKIN_DEPTH = 0.09;
|
|
41519
|
+
var DOOR_FLOOR_DEPTH = 0.2;
|
|
41274
41520
|
var DOOR_EDGE_PIECES = 8;
|
|
41275
41521
|
var DOOR_EDGE_REACH = 0.08;
|
|
41276
41522
|
var DOOR_CARD_COLOR = "#3b3e42";
|
|
41277
41523
|
var DOOR_LINER_COLOR = "#5a5e64";
|
|
41278
41524
|
var DOOR_LINER_DARK = 0.15;
|
|
41279
|
-
var DOOR_STRIP_THIN = 0.
|
|
41525
|
+
var DOOR_STRIP_THIN = 0.13;
|
|
41280
41526
|
var DOOR_STRIP_NEAR = 0.04;
|
|
41281
41527
|
var DOOR_STRIP_TALL = 0.22;
|
|
41282
|
-
var
|
|
41283
|
-
var DOOR_STRIP_VERTICES = 2e4;
|
|
41528
|
+
var DOOR_STRIP_VERTICES = 6e4;
|
|
41284
41529
|
var DOOR_SILL = 0.25;
|
|
41285
|
-
var DOOR_STRIP_OVER = 0.
|
|
41530
|
+
var DOOR_STRIP_OVER = 0.05;
|
|
41286
41531
|
var DOOR_TOP_OVER_PANE = 0.03;
|
|
41287
41532
|
var HOLE_TEXTURE_SIZE = 64;
|
|
41288
41533
|
var LAMINATED_HP = 1e3;
|
|
@@ -41386,6 +41631,8 @@ var GameVehiclesThree = (() => {
|
|
|
41386
41631
|
__publicField(this, "syncPlates", /* @__PURE__ */ new Map());
|
|
41387
41632
|
__publicField(this, "skins", /* @__PURE__ */ new Map());
|
|
41388
41633
|
__publicField(this, "doorTops", /* @__PURE__ */ new Map());
|
|
41634
|
+
__publicField(this, "seams", /* @__PURE__ */ new Map());
|
|
41635
|
+
__publicField(this, "openNow", /* @__PURE__ */ new Set());
|
|
41389
41636
|
__publicField(this, "lightsOn", true);
|
|
41390
41637
|
__publicField(this, "warming");
|
|
41391
41638
|
__publicField(this, "tornThisFrame", false);
|
|
@@ -41562,6 +41809,11 @@ var GameVehiclesThree = (() => {
|
|
|
41562
41809
|
}
|
|
41563
41810
|
panel.visible = open && !this.skins.get(id);
|
|
41564
41811
|
recess.visible = open && !this.skins.get(id);
|
|
41812
|
+
if (open) this.openNow.add(id);
|
|
41813
|
+
else this.openNow.delete(id);
|
|
41814
|
+
this.seams.forEach((doors, seam) => {
|
|
41815
|
+
if (doors.has(id)) seam.visible = ![...doors].some((door) => this.openNow.has(door));
|
|
41816
|
+
});
|
|
41565
41817
|
};
|
|
41566
41818
|
const euler = piv.rotation;
|
|
41567
41819
|
const quaternion = piv.quaternion;
|
|
@@ -41604,11 +41856,13 @@ var GameVehiclesThree = (() => {
|
|
|
41604
41856
|
const pcs = I.cutPanel(this.c, z, rect, true, dirty, { anyN: true }).map((x) => x.mesh).filter((m) => !!m);
|
|
41605
41857
|
this.mend(dirty);
|
|
41606
41858
|
if (pcs.length) {
|
|
41859
|
+
leaveDeepSkinOnBody(this.THREE, pcs, { toVehicle: inv, side: z.side < 0 ? -1 : 1, depth: DOOR_SKIN_DEPTH });
|
|
41607
41860
|
const panes = I.windowsOver(this.c, z, inv);
|
|
41608
41861
|
const seals = panes.map((g) => I.paneSeals.get(g)).filter((s) => !!s);
|
|
41609
41862
|
const mirrors = this.mirrorsOn(z);
|
|
41610
41863
|
const frames = this.framesAround(panes, inv);
|
|
41611
|
-
|
|
41864
|
+
const followers = I.followersIn(this.c, z, inv).filter((o) => !this.takeSeam(o, id, z, inv) && !this.inFloor(o, piv, z, inv));
|
|
41865
|
+
objs = [...pcs, ...followers, ...panes, ...seals, ...mirrors, ...frames];
|
|
41612
41866
|
}
|
|
41613
41867
|
} else {
|
|
41614
41868
|
const pcs = this.cutZone(z);
|
|
@@ -41636,6 +41890,25 @@ var GameVehiclesThree = (() => {
|
|
|
41636
41890
|
this.c.root.updateMatrixWorld(true);
|
|
41637
41891
|
return objs.length > 0;
|
|
41638
41892
|
}
|
|
41893
|
+
/** A thin part at the foot of the opening, well inside the skin (a step, a sill trim, a rail on the floor), is the floor's: it does not swing with the door. */
|
|
41894
|
+
inFloor(o, piv, z, inv) {
|
|
41895
|
+
const side2 = z.side < 0 ? -1 : 1;
|
|
41896
|
+
const centre = this.I.localBox(this.c, o, inv).getCenter(new this.THREE.Vector3());
|
|
41897
|
+
const skin = side2 * (piv.position.z - side2 * 0.016);
|
|
41898
|
+
return centre.y < z.box.y0 + DOOR_SILL && side2 * centre.z < skin - DOOR_FLOOR_DEPTH;
|
|
41899
|
+
}
|
|
41900
|
+
/** A shut line drawn at the door's edge stays on the body, hidden while a door it marks stands open; answers whether `o` is one. */
|
|
41901
|
+
takeSeam(o, id, z, inv) {
|
|
41902
|
+
const B = z.box;
|
|
41903
|
+
const box2 = this.I.localBox(this.c, o, inv);
|
|
41904
|
+
const color2 = o.material?.color;
|
|
41905
|
+
const dark = !!color2 && color2.getHSL({ h: 0, s: 0, l: 0 }).l < DOOR_LINER_DARK;
|
|
41906
|
+
if (!o.isMesh || !isDoorSeam(this.THREE, { box: box2, zone: { x0: B.x0, x1: B.x1, y0: B.y0, y1: B.y1 }, side: z.side, dark })) return false;
|
|
41907
|
+
const doors = this.seams.get(o) ?? /* @__PURE__ */ new Set();
|
|
41908
|
+
doors.add(id);
|
|
41909
|
+
this.seams.set(o, doors);
|
|
41910
|
+
return true;
|
|
41911
|
+
}
|
|
41639
41912
|
/** A door has edges: a band that follows the skin all round closes it to its card and hides where the cut followed the triangles of the shell; the same band, in the same paint as on a real car, lines the opening. */
|
|
41640
41913
|
doorEdges(piv, z, y1) {
|
|
41641
41914
|
const THREE = this.THREE;
|
|
@@ -41657,13 +41930,15 @@ var GameVehiclesThree = (() => {
|
|
|
41657
41930
|
const at = this.surface("z", side2, B, [[x, y]]);
|
|
41658
41931
|
return at != null && Math.abs(at - flat) < DOOR_EDGE_REACH ? at : flat;
|
|
41659
41932
|
});
|
|
41660
|
-
const band = (lift) => {
|
|
41933
|
+
const band = (lift, path, closed) => {
|
|
41661
41934
|
const position = [];
|
|
41662
41935
|
const index = [];
|
|
41663
|
-
|
|
41664
|
-
|
|
41936
|
+
path.forEach((at, i) => {
|
|
41937
|
+
const [x, y] = loop[at];
|
|
41938
|
+
position.push(x, y, heights[at] + side2 * lift, x, y, heights[at] + side2 * (lift - DOOR_DEPTH));
|
|
41939
|
+
if (!closed && i === path.length - 1) return;
|
|
41665
41940
|
const a = i * 2;
|
|
41666
|
-
const b = (i + 1) %
|
|
41941
|
+
const b = (i + 1) % path.length * 2;
|
|
41667
41942
|
index.push(a, a + 1, b, b, a + 1, b + 1);
|
|
41668
41943
|
});
|
|
41669
41944
|
const g = new THREE.BufferGeometry();
|
|
@@ -41691,8 +41966,11 @@ var GameVehiclesThree = (() => {
|
|
|
41691
41966
|
card.castShadow = false;
|
|
41692
41967
|
this.c.vehicle.add(card);
|
|
41693
41968
|
piv.attach(card);
|
|
41694
|
-
const
|
|
41695
|
-
const
|
|
41969
|
+
const all = loop.map((_, i) => i);
|
|
41970
|
+
const top = 2 * DOOR_EDGE_PIECES;
|
|
41971
|
+
const sides = [...all.slice(3 * DOOR_EDGE_PIECES), ...all.slice(0, top + 1)];
|
|
41972
|
+
const edges = new THREE.Mesh(band(2e-3, all, true), paint);
|
|
41973
|
+
const lining = new THREE.Mesh(band(2e-3, sides, false), paint);
|
|
41696
41974
|
for (const m of [edges, lining]) {
|
|
41697
41975
|
m.userData.noFollow = true;
|
|
41698
41976
|
m.castShadow = false;
|
|
@@ -41749,26 +42027,14 @@ var GameVehiclesThree = (() => {
|
|
|
41749
42027
|
const box2 = this.I.localBox(this.c, o, inv);
|
|
41750
42028
|
const size = box2.getSize(new THREE.Vector3());
|
|
41751
42029
|
const mid = box2.getCenter(new THREE.Vector3());
|
|
41752
|
-
if (Math.sign(mid.z) !== Math.sign(z.side) || size.z > DOOR_STRIP_THIN || size.y > DOOR_STRIP_TALL || Math.min(box2.max.x, x1) - Math.max(box2.min.x, x0) <
|
|
42030
|
+
if (Math.sign(mid.z) !== Math.sign(z.side) || size.z > DOOR_STRIP_THIN || size.y > DOOR_STRIP_TALL || Math.min(box2.max.x, x1) - Math.max(box2.min.x, x0) < DOOR_STRIP_OVER || mid.y < y0 || mid.y > y1) continue;
|
|
41753
42031
|
const toVehicle = new THREE.Matrix4().multiplyMatrices(inv, o.matrixWorld);
|
|
41754
|
-
const
|
|
41755
|
-
const sdf = (x, y, zz) => {
|
|
41756
|
-
v.set(x, y, zz).applyMatrix4(toVehicle);
|
|
41757
|
-
return Math.max(x0 - v.x, v.x - x1);
|
|
41758
|
-
};
|
|
41759
|
-
const over = new THREE.Mesh(o.geometry.clone(), o.material);
|
|
42032
|
+
const over = cutStripOverDoor(this.kit, { strip: o, toVehicle, x0, x1 });
|
|
41760
42033
|
over.position.copy(o.position);
|
|
41761
42034
|
over.quaternion.copy(o.quaternion);
|
|
41762
42035
|
over.scale.copy(o.scale);
|
|
41763
42036
|
this.c.vehicle.add(over);
|
|
41764
42037
|
over.updateMatrixWorld(true);
|
|
41765
|
-
const overToVehicle = new THREE.Matrix4().multiplyMatrices(inv, over.matrixWorld);
|
|
41766
|
-
const w = new THREE.Vector3();
|
|
41767
|
-
this.kit.cutMesh(over, [{ sdf: (x, y, zz) => {
|
|
41768
|
-
w.set(x, y, zz).applyMatrix4(overToVehicle);
|
|
41769
|
-
return -Math.max(x0 - w.x, w.x - x1);
|
|
41770
|
-
} }], STRIP_SMOOTH_DEG, {});
|
|
41771
|
-
this.kit.cutMesh(o, [{ sdf }], STRIP_SMOOTH_DEG, {});
|
|
41772
42038
|
over.userData.noFollow = true;
|
|
41773
42039
|
piv.attach(over);
|
|
41774
42040
|
}
|
|
@@ -42349,11 +42615,18 @@ var GameVehiclesThree = (() => {
|
|
|
42349
42615
|
}
|
|
42350
42616
|
}
|
|
42351
42617
|
}
|
|
42618
|
+
/** The lens of a light is holed or cracked and stays; `pierced`: a round went through it to the bulb, and the lamp goes dark. */
|
|
42619
|
+
crackLight(p, pierced) {
|
|
42620
|
+
const z = this.zone(p);
|
|
42621
|
+
if (!z) return;
|
|
42622
|
+
for (const L of z.lights) this.kit.crackLight(this.c, L, new this.THREE.Vector3(p.box.center[0] > 0 ? -1 : 1, 0, 0), pierced);
|
|
42623
|
+
}
|
|
42352
42624
|
/** The lens of a light breaks and its unit stays (damaged) or goes (destroyed). */
|
|
42353
42625
|
breakLight(p, gone) {
|
|
42354
42626
|
const z = this.zone(p);
|
|
42355
42627
|
if (!z) return;
|
|
42356
42628
|
for (const L of z.lights) {
|
|
42629
|
+
L.lensMaterial = p.material;
|
|
42357
42630
|
this.kit.breakLight(this.c, L, new this.THREE.Vector3(p.box.center[0] > 0 ? -1 : 1, 0, 0));
|
|
42358
42631
|
if (gone) {
|
|
42359
42632
|
if (L.group) L.group.visible = false;
|
|
@@ -42995,6 +43268,7 @@ var GameVehiclesThree = (() => {
|
|
|
42995
43268
|
wear(p, amount, out);
|
|
42996
43269
|
syncZone(p);
|
|
42997
43270
|
if (p.hp <= 0) lose(p, "broken", out, cause);
|
|
43271
|
+
else if (p.def.role === "light") vis?.crackLight(p.def, dtype === "ballistic");
|
|
42998
43272
|
if (p.def.role === "tyre" && !p.flat && p.hp < p.def.hp * 0.6 && !p.lost) {
|
|
42999
43273
|
p.flat = true;
|
|
43000
43274
|
vis?.tyreFlat(p.def, 0.24);
|
|
@@ -43807,7 +44081,7 @@ var GameVehiclesThree = (() => {
|
|
|
43807
44081
|
if (!list2.length) return 1;
|
|
43808
44082
|
return Math.min(...list2.map((p) => p.lost || !attached(p.def.id) ? 0 : p.hp / p.def.hp));
|
|
43809
44083
|
};
|
|
43810
|
-
const tyres = [...ps.values()].filter((p) => p.def.role === "tyre").map((p) => ({ x: p.def.box.center[0], z: p.def.box.center[2], health: tyreHealth(p) }));
|
|
44084
|
+
const tyres = [...ps.values()].filter((p) => p.def.role === "tyre").map((p) => ({ x: p.def.box.center[0], z: p.def.box.center[2], health: tyreHealth(p), rim: p.lost }));
|
|
43811
44085
|
const status = computeStatus();
|
|
43812
44086
|
const brakeSystem = [...ps.values()].find((p) => p.def.role === "brakes" && p.def.contains);
|
|
43813
44087
|
const fluidLeft = brakeSystem ? clamp((brakeSystem.liters ?? 0) / brakeSystem.def.contains.liters / BRAKE_FLUID_NEEDED, 0, 1) : 1;
|
|
@@ -44035,7 +44309,7 @@ var GameVehiclesThree = (() => {
|
|
|
44035
44309
|
};
|
|
44036
44310
|
}
|
|
44037
44311
|
|
|
44038
|
-
// ../game-audio/dist/chunk-
|
|
44312
|
+
// ../game-audio/dist/chunk-C2K7XN2K.js
|
|
44039
44313
|
var DISTANCE_CURVES = {
|
|
44040
44314
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
44041
44315
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -44340,7 +44614,22 @@ var GameVehiclesThree = (() => {
|
|
|
44340
44614
|
["smg_45_auto", 2, "sfx_pistol"],
|
|
44341
44615
|
["weapon_draw", 2],
|
|
44342
44616
|
["suppressor_attach", 3],
|
|
44343
|
-
["suppressor_detach", 3]
|
|
44617
|
+
["suppressor_detach", 3],
|
|
44618
|
+
["minigun_loop", 3],
|
|
44619
|
+
["smg_5_7x28", 3],
|
|
44620
|
+
["mg_belt_adjust", 3],
|
|
44621
|
+
["mg_belt_box_attach", 3],
|
|
44622
|
+
["mg_cover_open", 3],
|
|
44623
|
+
["mg_cover_close", 3],
|
|
44624
|
+
["weapon_holster", 3],
|
|
44625
|
+
["scope_zoom", 3]
|
|
44626
|
+
]),
|
|
44627
|
+
...entries("impactos", [
|
|
44628
|
+
["knife_hit_wall", 3],
|
|
44629
|
+
["helmet_hit", 3],
|
|
44630
|
+
["vest_hit", 3],
|
|
44631
|
+
["headshot", 3],
|
|
44632
|
+
["blood_squirt", 3]
|
|
44344
44633
|
]),
|
|
44345
44634
|
...entries("explosoes-fogo", [
|
|
44346
44635
|
["explosion_grenade", 1, "boom"],
|
|
@@ -44358,7 +44647,13 @@ var GameVehiclesThree = (() => {
|
|
|
44358
44647
|
["grenade_bounce", 1],
|
|
44359
44648
|
["c4_plant", 2],
|
|
44360
44649
|
["c4_beep", 2],
|
|
44361
|
-
["c4_disarm", 2]
|
|
44650
|
+
["c4_disarm", 2],
|
|
44651
|
+
["c4_disarming_loop", 3],
|
|
44652
|
+
["c4_remote_detonate", 3],
|
|
44653
|
+
["smoke_grenade_hiss", 3],
|
|
44654
|
+
["grenade_pin_pull", 3],
|
|
44655
|
+
["electric_shock", 3],
|
|
44656
|
+
["electric_spark", 3]
|
|
44362
44657
|
]),
|
|
44363
44658
|
...entries("personagem", [
|
|
44364
44659
|
["footstep_concrete_walk", 1, "sfx_step"],
|
|
@@ -44386,7 +44681,13 @@ var GameVehiclesThree = (() => {
|
|
|
44386
44681
|
["zombie_attack", 1],
|
|
44387
44682
|
["zombie_pain", 1],
|
|
44388
44683
|
["zombie_claw_hit", 1, "sfx_flesh"],
|
|
44389
|
-
["zombie_claw_miss", 2]
|
|
44684
|
+
["zombie_claw_miss", 2],
|
|
44685
|
+
["swing_whoosh", 3],
|
|
44686
|
+
["heartbeat_critical", 3],
|
|
44687
|
+
["fall_water", 3],
|
|
44688
|
+
["fall_damage", 3],
|
|
44689
|
+
["fall_scream", 3],
|
|
44690
|
+
["footstep_glass_walk", 3]
|
|
44390
44691
|
]),
|
|
44391
44692
|
...entries("veiculos", [
|
|
44392
44693
|
["engine_loop_car", 1],
|
|
@@ -44396,7 +44697,12 @@ var GameVehiclesThree = (() => {
|
|
|
44396
44697
|
["car_door_open", 1, "latch"],
|
|
44397
44698
|
["car_door_close", 1, "shut_metal"],
|
|
44398
44699
|
["horn_car", 2, "horn"],
|
|
44399
|
-
["tire_skid_asphalt", 2]
|
|
44700
|
+
["tire_skid_asphalt", 2],
|
|
44701
|
+
["jet_flyby", 3],
|
|
44702
|
+
["helicopter_turbine", 3],
|
|
44703
|
+
["tire_burnout", 3],
|
|
44704
|
+
["handbrake_turn", 3],
|
|
44705
|
+
["siren_police", 3]
|
|
44400
44706
|
]),
|
|
44401
44707
|
...entries("itens-portas", [
|
|
44402
44708
|
["item_pickup_metal", 1],
|
|
@@ -44407,7 +44713,27 @@ var GameVehiclesThree = (() => {
|
|
|
44407
44713
|
["door_creak", 1, "creak_wood"],
|
|
44408
44714
|
["door_locked_rattle", 1, "rattle"],
|
|
44409
44715
|
["drawer_open", 2, "slide"],
|
|
44410
|
-
["fridge_close", 2, "shut_metal"]
|
|
44716
|
+
["fridge_close", 2, "shut_metal"],
|
|
44717
|
+
["inventory_open", 3],
|
|
44718
|
+
["inventory_close", 3],
|
|
44719
|
+
["inventory_select", 3],
|
|
44720
|
+
["inventory_place", 3],
|
|
44721
|
+
["pickup_chime", 3],
|
|
44722
|
+
["item_pickup_coins", 3],
|
|
44723
|
+
["bandage_use", 3],
|
|
44724
|
+
["bandage_refuse", 3],
|
|
44725
|
+
["flashlight_toggle", 3],
|
|
44726
|
+
["gear_draw", 3],
|
|
44727
|
+
["gear_holster", 3],
|
|
44728
|
+
["button_press", 3],
|
|
44729
|
+
["lock_desk_open", 3],
|
|
44730
|
+
["elevator_move_loop", 3],
|
|
44731
|
+
["elevator_stop", 3],
|
|
44732
|
+
["door_sliding", 3],
|
|
44733
|
+
["door_kick", 3],
|
|
44734
|
+
["door_wood_break", 3],
|
|
44735
|
+
["gate_iron_open", 3],
|
|
44736
|
+
["gate_iron_close", 3]
|
|
44411
44737
|
]),
|
|
44412
44738
|
...entries("ambiente", [
|
|
44413
44739
|
["rain_loop", 2],
|
|
@@ -44415,7 +44741,16 @@ var GameVehiclesThree = (() => {
|
|
|
44415
44741
|
["thunder_near", 2],
|
|
44416
44742
|
["thunder_far", 2],
|
|
44417
44743
|
["water_splash", 2],
|
|
44418
|
-
["helicopter_loop", 3]
|
|
44744
|
+
["helicopter_loop", 3],
|
|
44745
|
+
["bird_flush", 3],
|
|
44746
|
+
["dog_growl", 3],
|
|
44747
|
+
["dog_whimper", 3],
|
|
44748
|
+
["dog_howl", 3],
|
|
44749
|
+
["zombie_dog_bark", 3],
|
|
44750
|
+
["zombie_dog_howl_far", 3],
|
|
44751
|
+
["insect_squash", 3],
|
|
44752
|
+
["insect_crawl", 3],
|
|
44753
|
+
["fan_loop", 3]
|
|
44419
44754
|
])
|
|
44420
44755
|
];
|
|
44421
44756
|
var SFX_MATERIALS = [
|
|
@@ -44497,6 +44832,7 @@ var GameVehiclesThree = (() => {
|
|
|
44497
44832
|
burst: 20,
|
|
44498
44833
|
burstSpacing: 0.06
|
|
44499
44834
|
};
|
|
44835
|
+
var CATALOG = new Map([...SFX_CATALOG, ...SFX_IMPACTS].map((entry) => [entry.id, entry]));
|
|
44500
44836
|
var PT = {
|
|
44501
44837
|
group: "Som",
|
|
44502
44838
|
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
@@ -44571,9 +44907,9 @@ var GameVehiclesThree = (() => {
|
|
|
44571
44907
|
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
44572
44908
|
states: { file: "A", synth: "S", missing: "F" },
|
|
44573
44909
|
criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
|
|
44574
|
-
metrics: { source: "1 \xB7 Fonte do que tocou", chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
|
|
44910
|
+
metrics: { source: "1 \xB7 Fonte do que tocou", chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo", unlicensed: "1 \xB7 Arquivo sem licen\xE7a" },
|
|
44575
44911
|
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
44576
|
-
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
44912
|
+
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono", local_file: "arquivo do pacote local", sdk_file: "grava\xE7\xE3o do SDK", synth: "s\xEDntese do SDK" },
|
|
44577
44913
|
sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
|
|
44578
44914
|
probe: "Fonte do som",
|
|
44579
44915
|
wall: "Parede (oclus\xE3o)",
|
|
@@ -44644,9 +44980,9 @@ var GameVehiclesThree = (() => {
|
|
|
44644
44980
|
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
44645
44981
|
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
44646
44982
|
criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
|
|
44647
|
-
metrics: { source: "1 \xB7 Source of what played", chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
|
|
44983
|
+
metrics: { source: "1 \xB7 Source of what played", chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue", unlicensed: "1 \xB7 File without licence" },
|
|
44648
44984
|
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
44649
|
-
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
44985
|
+
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner", local_file: "local pack file", sdk_file: "SDK recording", synth: "SDK synthesis" },
|
|
44650
44986
|
sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
|
|
44651
44987
|
probe: "Sound source",
|
|
44652
44988
|
wall: "Wall (occlusion)",
|
|
@@ -44800,9 +45136,77 @@ var GameVehiclesThree = (() => {
|
|
|
44800
45136
|
duration: 0.5,
|
|
44801
45137
|
layers: [{ source: { kind: "osc", wave: "sine", frequency: { set: 880 } }, repeat: { count: 3, spacing: 0.7 }, envelope: [[0, 0.06, "set"], [0.5, 1e-4, "exp", "fixed"]] }],
|
|
44802
45138
|
falloff: { model: "none" }
|
|
45139
|
+
},
|
|
45140
|
+
{
|
|
45141
|
+
// the parking sensor: a short high beep, repeated by the cabin faster as the obstacle comes close
|
|
45142
|
+
id: "parking_beep",
|
|
45143
|
+
bus: "world",
|
|
45144
|
+
duration: 0.09,
|
|
45145
|
+
layers: [{ source: { kind: "osc", wave: "sine", frequency: { set: 2300 } }, envelope: [[0, 0.07, "set"], [0.08, 1e-4, "exp", "fixed"]] }],
|
|
45146
|
+
falloff: { model: "none" }
|
|
44803
45147
|
}
|
|
44804
45148
|
];
|
|
44805
45149
|
var CABIN_BANK = { id: "vehicle_cabin", sounds: CABIN_SOUNDS, loops: [] };
|
|
45150
|
+
var hz = (midi) => 440 * 2 ** ((midi - 69) / 12);
|
|
45151
|
+
var layer = (note, beat, wave, level) => {
|
|
45152
|
+
const [at, midi, beats] = note;
|
|
45153
|
+
const length = beats * beat;
|
|
45154
|
+
return {
|
|
45155
|
+
at: at * beat,
|
|
45156
|
+
duration: length,
|
|
45157
|
+
source: { kind: "osc", wave, frequency: { set: hz(midi) } },
|
|
45158
|
+
envelope: [[0, 1e-4, "set"], [0.01, level, "linear"], [Math.max(0.02, length * 0.9), level * 0.35, "linear"], [length, 1e-4, "exp", "fixed"]]
|
|
45159
|
+
};
|
|
45160
|
+
};
|
|
45161
|
+
function radioTrack(spec) {
|
|
45162
|
+
const beat = 60 / spec.bpm;
|
|
45163
|
+
const recipes = Array.from({ length: spec.bars }, (_, bar) => {
|
|
45164
|
+
const inBar = (notes) => notes.filter((n) => n[0] >= bar * 4 && n[0] < bar * 4 + 4).map((n) => [n[0] - bar * 4, n[1], n[2]]);
|
|
45165
|
+
const layers2 = [
|
|
45166
|
+
...inBar(spec.bass).map((n) => layer(n, beat, "triangle", 0.16)),
|
|
45167
|
+
...inBar(spec.chords).map((n) => layer(n, beat, "sine", 0.05)),
|
|
45168
|
+
...inBar(spec.melody).map((n) => layer(n, beat, spec.wave, 0.07))
|
|
45169
|
+
];
|
|
45170
|
+
return { id: `${spec.id}_${bar}`, bus: "world", duration: 4 * beat, layers: layers2, falloff: { model: "none" } };
|
|
45171
|
+
});
|
|
45172
|
+
return { song: { id: spec.id, barSeconds: 4 * beat, bars: recipes.map((r) => r.id) }, recipes };
|
|
45173
|
+
}
|
|
45174
|
+
var chord = (bar, root, minor = false) => [[bar * 4, root, 4], [bar * 4, root + (minor ? 3 : 4), 4], [bar * 4, root + 7, 4]];
|
|
45175
|
+
var bassLine = (roots, pattern) => roots.flatMap((root, bar) => pattern.map((b) => [bar * 4 + b, root - 12, 0.9]));
|
|
45176
|
+
var TRACKS = [
|
|
45177
|
+
// a bright pop loop: I–V–vi–IV in C
|
|
45178
|
+
radioTrack({
|
|
45179
|
+
id: "radio_track_pop",
|
|
45180
|
+
bpm: 112,
|
|
45181
|
+
bars: 4,
|
|
45182
|
+
wave: "square",
|
|
45183
|
+
bass: bassLine([48, 55, 57, 53], [0, 1.5, 2, 3]),
|
|
45184
|
+
chords: [...chord(0, 60), ...chord(1, 55), ...chord(2, 57, true), ...chord(3, 53)],
|
|
45185
|
+
melody: [[0, 76, 1], [1, 74, 0.5], [1.5, 72, 1.5], [4, 74, 1], [5, 76, 1], [6, 79, 2], [8, 76, 1], [9, 74, 1], [10, 72, 2], [12, 72, 1], [13, 74, 1], [14, 72, 2]]
|
|
45186
|
+
}),
|
|
45187
|
+
// a syncopated loop in A minor, the bass on the off-beats
|
|
45188
|
+
radioTrack({
|
|
45189
|
+
id: "radio_track_groove",
|
|
45190
|
+
bpm: 100,
|
|
45191
|
+
bars: 4,
|
|
45192
|
+
wave: "triangle",
|
|
45193
|
+
bass: bassLine([57, 62, 64, 57], [0, 0.75, 1.5, 2.5, 3.25]),
|
|
45194
|
+
chords: [...chord(0, 57, true), ...chord(1, 62, true), ...chord(2, 64), ...chord(3, 57, true)],
|
|
45195
|
+
melody: [[0.5, 72, 0.5], [1.25, 76, 0.75], [2.5, 74, 1], [4.5, 77, 0.5], [5.25, 74, 0.75], [6.5, 72, 1.5], [8.5, 71, 0.5], [9.25, 74, 0.75], [10.5, 76, 1.5], [12.5, 72, 0.5], [13.25, 69, 2]]
|
|
45196
|
+
}),
|
|
45197
|
+
// a slow blues-like loop in F with a swung melody
|
|
45198
|
+
radioTrack({
|
|
45199
|
+
id: "radio_track_slow",
|
|
45200
|
+
bpm: 76,
|
|
45201
|
+
bars: 4,
|
|
45202
|
+
wave: "sine",
|
|
45203
|
+
bass: bassLine([53, 58, 53, 60], [0, 2]),
|
|
45204
|
+
chords: [...chord(0, 65), ...chord(1, 58), ...chord(2, 65), ...chord(3, 60)],
|
|
45205
|
+
melody: [[0, 72, 1.5], [1.67, 75, 0.33], [2, 77, 2], [4, 74, 1], [5, 72, 1], [6, 70, 2], [8, 72, 1.5], [9.67, 69, 0.33], [10, 65, 2], [12, 67, 1], [13, 70, 1], [14, 72, 2]]
|
|
45206
|
+
})
|
|
45207
|
+
];
|
|
45208
|
+
var RADIO_TRACKS = TRACKS.map((t) => t.song);
|
|
45209
|
+
var RADIO_BANK = { id: "vehicle_radio", sounds: TRACKS.flatMap((t) => t.recipes), loops: [] };
|
|
44806
45210
|
var FOLEY_FALLOFF = {
|
|
44807
45211
|
model: "inverse_square",
|
|
44808
45212
|
k: 0.02,
|
|
@@ -45409,11 +45813,11 @@ var GameVehiclesThree = (() => {
|
|
|
45409
45813
|
...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
|
|
45410
45814
|
];
|
|
45411
45815
|
}
|
|
45412
|
-
var quieter = (level, layers2) => layers2.map((
|
|
45413
|
-
const gain =
|
|
45414
|
-
if (typeof gain === "number") return { ...
|
|
45415
|
-
if (Array.isArray(gain)) return { ...
|
|
45416
|
-
return
|
|
45816
|
+
var quieter = (level, layers2) => layers2.map((layer2) => {
|
|
45817
|
+
const gain = layer2.gain ?? 1;
|
|
45818
|
+
if (typeof gain === "number") return { ...layer2, gain: gain * level };
|
|
45819
|
+
if (Array.isArray(gain)) return { ...layer2, gain: [gain[0] * level, gain[1] * level] };
|
|
45820
|
+
return layer2;
|
|
45417
45821
|
});
|
|
45418
45822
|
var recipe = (id, layers2, falloff, bus = "world") => ({ id, bus, pan: true, layers: layers2, falloff, sources: ["sdk"] });
|
|
45419
45823
|
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
@@ -45429,7 +45833,7 @@ var GameVehiclesThree = (() => {
|
|
|
45429
45833
|
(take) => quieter(LANDING_LEVEL, [
|
|
45430
45834
|
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
45431
45835
|
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
45432
|
-
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((
|
|
45836
|
+
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer2) => ({ ...layer2, at: (typeof layer2.at === "number" ? layer2.at : 0) + 0.018 * take.t })),
|
|
45433
45837
|
sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
|
|
45434
45838
|
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
45435
45839
|
]),
|
|
@@ -45475,7 +45879,7 @@ var GameVehiclesThree = (() => {
|
|
|
45475
45879
|
fall_damage: (take) => [
|
|
45476
45880
|
...BODY.body_fall(take),
|
|
45477
45881
|
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
45478
|
-
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((
|
|
45882
|
+
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer2) => ({ ...layer2, at: 0.08 }))
|
|
45479
45883
|
],
|
|
45480
45884
|
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
45481
45885
|
player_breath_run: (take) => [
|
|
@@ -45533,6 +45937,105 @@ var GameVehiclesThree = (() => {
|
|
|
45533
45937
|
};
|
|
45534
45938
|
var BODY_FOLEY_SET_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
45535
45939
|
|
|
45940
|
+
// src/audio/engine-mix.ts
|
|
45941
|
+
var clamp01 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
45942
|
+
var firingHz = (profile, rpm) => rpm / 60 * (profile.cylinders / 2);
|
|
45943
|
+
var rpmShare = (profile, rpm) => clamp01((rpm - profile.idleRpm) / (profile.redlineRpm - profile.idleRpm));
|
|
45944
|
+
var layerWeight = (centre, width, n) => {
|
|
45945
|
+
const d = Math.abs(n - centre) / width;
|
|
45946
|
+
return d >= 1 ? 0 : Math.cos(d * Math.PI / 2);
|
|
45947
|
+
};
|
|
45948
|
+
function engineMix(profile, input) {
|
|
45949
|
+
const throttle = clamp01(input.throttle);
|
|
45950
|
+
const on = input.rpm > 0;
|
|
45951
|
+
const n = rpmShare(profile, input.rpm);
|
|
45952
|
+
const level = on ? profile.closedThrottle + (1 - profile.closedThrottle) * throttle : 0;
|
|
45953
|
+
const open = 0.5 * n + 0.5 * throttle;
|
|
45954
|
+
const hz2 = firingHz(profile, input.rpm);
|
|
45955
|
+
const tones = profile.layers.map((layer2) => ({
|
|
45956
|
+
sound: layer2.sound,
|
|
45957
|
+
volume: layer2.gain * level * layerWeight(layer2.centre, layer2.width, n),
|
|
45958
|
+
frequency: hz2 * layer2.harmonic,
|
|
45959
|
+
cutoff: layer2.cutoff[0] + (layer2.cutoff[1] - layer2.cutoff[0]) * open
|
|
45960
|
+
}));
|
|
45961
|
+
const load = profile.load;
|
|
45962
|
+
return [
|
|
45963
|
+
...tones,
|
|
45964
|
+
{ sound: load.sound, volume: on ? load.gain * (0.15 + 0.85 * throttle) * (0.35 + 0.65 * n) : 0, cutoff: load.cutoff[0] + (load.cutoff[1] - load.cutoff[0]) * open }
|
|
45965
|
+
];
|
|
45966
|
+
}
|
|
45967
|
+
function createGearGuess(profile) {
|
|
45968
|
+
let gear = 0;
|
|
45969
|
+
return {
|
|
45970
|
+
rpm(speed, throttle) {
|
|
45971
|
+
const v = Math.abs(speed);
|
|
45972
|
+
const ratios = profile.rpmPerMps;
|
|
45973
|
+
if (v < 0.3) {
|
|
45974
|
+
gear = 0;
|
|
45975
|
+
return profile.idleRpm + (profile.redlineRpm - profile.idleRpm) * 0.12 * clamp01(throttle);
|
|
45976
|
+
}
|
|
45977
|
+
const at = (g) => v * ratios[g];
|
|
45978
|
+
while (gear < ratios.length - 1 && at(gear) > profile.redlineRpm * 0.85) gear++;
|
|
45979
|
+
while (gear > 0 && at(gear) < profile.redlineRpm * 0.4) gear--;
|
|
45980
|
+
return Math.max(profile.idleRpm, Math.min(profile.redlineRpm, at(gear)));
|
|
45981
|
+
},
|
|
45982
|
+
get gear() {
|
|
45983
|
+
return gear;
|
|
45984
|
+
}
|
|
45985
|
+
};
|
|
45986
|
+
}
|
|
45987
|
+
|
|
45988
|
+
// src/audio/profiles.ts
|
|
45989
|
+
var DEFAULT_VEHICLE_SOUND_KEYS = {
|
|
45990
|
+
start: "engine_start",
|
|
45991
|
+
stop: "engine_stop",
|
|
45992
|
+
fail: "engine_fail",
|
|
45993
|
+
crashLight: "crash_light",
|
|
45994
|
+
crashMedium: "crash_medium",
|
|
45995
|
+
crashHeavy: "crash_heavy",
|
|
45996
|
+
skidAsphalt: "tire_skid_asphalt",
|
|
45997
|
+
skidDirt: "tire_skid_dirt",
|
|
45998
|
+
roll: "tire_roll"
|
|
45999
|
+
};
|
|
46000
|
+
var CRASH_SPEEDS = { medium: 6, heavy: 14 };
|
|
46001
|
+
var layers = (id, cutoffs, gains) => [
|
|
46002
|
+
{ sound: `engine_${id}_low`, centre: 0, width: 0.5, harmonic: 1, gain: gains[0], cutoff: cutoffs[0] },
|
|
46003
|
+
{ sound: `engine_${id}_mid`, centre: 0.45, width: 0.5, harmonic: 1, gain: gains[1], cutoff: cutoffs[1] },
|
|
46004
|
+
{ sound: `engine_${id}_high`, centre: 1, width: 0.6, harmonic: 2, gain: gains[2], cutoff: cutoffs[2] }
|
|
46005
|
+
];
|
|
46006
|
+
var CAR_ENGINE = {
|
|
46007
|
+
id: "car",
|
|
46008
|
+
cylinders: 4,
|
|
46009
|
+
idleRpm: 800,
|
|
46010
|
+
redlineRpm: 6500,
|
|
46011
|
+
// a 5-speed hatch: 1st tops at ~13 m/s, 5th at ~50 m/s
|
|
46012
|
+
rpmPerMps: [500, 300, 205, 155, 125],
|
|
46013
|
+
layers: layers("car", [[220, 520], [420, 1300], [900, 2600]], [0.11, 0.075, 0.04]),
|
|
46014
|
+
load: { sound: "engine_car_load", gain: 0.05, cutoff: [350, 1600] },
|
|
46015
|
+
closedThrottle: 0.55
|
|
46016
|
+
};
|
|
46017
|
+
var TRUCK_ENGINE = {
|
|
46018
|
+
id: "truck",
|
|
46019
|
+
cylinders: 6,
|
|
46020
|
+
idleRpm: 650,
|
|
46021
|
+
redlineRpm: 2600,
|
|
46022
|
+
rpmPerMps: [420, 260, 170, 120, 90, 72],
|
|
46023
|
+
layers: layers("truck", [[160, 380], [300, 800], [600, 1500]], [0.13, 0.08, 0.035]),
|
|
46024
|
+
load: { sound: "engine_truck_load", gain: 0.06, cutoff: [250, 900] },
|
|
46025
|
+
closedThrottle: 0.6
|
|
46026
|
+
};
|
|
46027
|
+
var BIKE_ENGINE = {
|
|
46028
|
+
id: "bike",
|
|
46029
|
+
cylinders: 4,
|
|
46030
|
+
idleRpm: 1300,
|
|
46031
|
+
redlineRpm: 12e3,
|
|
46032
|
+
rpmPerMps: [900, 640, 500, 410, 350, 310],
|
|
46033
|
+
layers: layers("bike", [[350, 900], [700, 2200], [1500, 4200]], [0.08, 0.07, 0.05]),
|
|
46034
|
+
load: { sound: "engine_bike_load", gain: 0.045, cutoff: [600, 2600] },
|
|
46035
|
+
closedThrottle: 0.5
|
|
46036
|
+
};
|
|
46037
|
+
var ENGINE_PROFILES = { car: CAR_ENGINE, truck: TRUCK_ENGINE, bike: BIKE_ENGINE };
|
|
46038
|
+
|
|
45536
46039
|
// src/audio/bank.ts
|
|
45537
46040
|
var VEHICLE_LOOP_FALLOFF = { model: "inverse_square", k: 4e-3, cutoffK: 0.01 };
|
|
45538
46041
|
var SDK = "sdk: vehicle sounds (sons/checklist-sons.md 5.6)";
|
|
@@ -45624,106 +46127,33 @@ var GameVehiclesThree = (() => {
|
|
|
45624
46127
|
recipe2("car_trunk_close", [sceneTone({ f: 90, f2: 55, d: 0.15, vol: 0.65 }), sceneNoise({ type: "bandpass", f: 500, q: 1, d: 0.12, vol: 0.5 }), ...latch(0.01, 0.28), sceneNoise({ type: "bandpass", f: 1800, q: 3, d: 0.04, vol: 0.1, delay: 0.06 })], "trunk or hatch shut: a lighter thump, the latch and a small rattle"),
|
|
45625
46128
|
recipe2("car_hood_close", [sceneTone({ f: 70, f2: 40, d: 0.22, vol: 0.8 }), sceneNoise({ type: "bandpass", f: 850, q: 1.4, d: 0.2, vol: 0.6, wet: 0.3 }), sceneTone({ f: 900, f2: 860, d: 0.18, vol: 0.05 }), ...latch(0.015, 0.3)], "hood slammed: a big sheet of metal ringing a little, the latch")
|
|
45626
46129
|
];
|
|
45627
|
-
var
|
|
45628
|
-
|
|
45629
|
-
|
|
45630
|
-
|
|
45631
|
-
|
|
45632
|
-
|
|
45633
|
-
var layerWeight = (centre, width, n) => {
|
|
45634
|
-
const d = Math.abs(n - centre) / width;
|
|
45635
|
-
return d >= 1 ? 0 : Math.cos(d * Math.PI / 2);
|
|
45636
|
-
};
|
|
45637
|
-
function engineMix(profile, input) {
|
|
45638
|
-
const throttle = clamp01(input.throttle);
|
|
45639
|
-
const on = input.rpm > 0;
|
|
45640
|
-
const n = rpmShare(profile, input.rpm);
|
|
45641
|
-
const level = on ? profile.closedThrottle + (1 - profile.closedThrottle) * throttle : 0;
|
|
45642
|
-
const open = 0.5 * n + 0.5 * throttle;
|
|
45643
|
-
const hz = firingHz(profile, input.rpm);
|
|
45644
|
-
const tones = profile.layers.map((layer) => ({
|
|
45645
|
-
sound: layer.sound,
|
|
45646
|
-
volume: layer.gain * level * layerWeight(layer.centre, layer.width, n),
|
|
45647
|
-
frequency: hz * layer.harmonic,
|
|
45648
|
-
cutoff: layer.cutoff[0] + (layer.cutoff[1] - layer.cutoff[0]) * open
|
|
45649
|
-
}));
|
|
45650
|
-
const load = profile.load;
|
|
45651
|
-
return [
|
|
45652
|
-
...tones,
|
|
45653
|
-
{ sound: load.sound, volume: on ? load.gain * (0.15 + 0.85 * throttle) * (0.35 + 0.65 * n) : 0, cutoff: load.cutoff[0] + (load.cutoff[1] - load.cutoff[0]) * open }
|
|
45654
|
-
];
|
|
45655
|
-
}
|
|
45656
|
-
function createGearGuess(profile) {
|
|
45657
|
-
let gear = 0;
|
|
45658
|
-
return {
|
|
45659
|
-
rpm(speed, throttle) {
|
|
45660
|
-
const v = Math.abs(speed);
|
|
45661
|
-
const ratios = profile.rpmPerMps;
|
|
45662
|
-
if (v < 0.3) {
|
|
45663
|
-
gear = 0;
|
|
45664
|
-
return profile.idleRpm + (profile.redlineRpm - profile.idleRpm) * 0.12 * clamp01(throttle);
|
|
45665
|
-
}
|
|
45666
|
-
const at = (g) => v * ratios[g];
|
|
45667
|
-
while (gear < ratios.length - 1 && at(gear) > profile.redlineRpm * 0.85) gear++;
|
|
45668
|
-
while (gear > 0 && at(gear) < profile.redlineRpm * 0.4) gear--;
|
|
45669
|
-
return Math.max(profile.idleRpm, Math.min(profile.redlineRpm, at(gear)));
|
|
45670
|
-
},
|
|
45671
|
-
get gear() {
|
|
45672
|
-
return gear;
|
|
45673
|
-
}
|
|
45674
|
-
};
|
|
45675
|
-
}
|
|
45676
|
-
|
|
45677
|
-
// src/audio/profiles.ts
|
|
45678
|
-
var DEFAULT_VEHICLE_SOUND_KEYS = {
|
|
45679
|
-
start: "engine_start",
|
|
45680
|
-
stop: "engine_stop",
|
|
45681
|
-
fail: "engine_fail",
|
|
45682
|
-
crashLight: "crash_light",
|
|
45683
|
-
crashMedium: "crash_medium",
|
|
45684
|
-
crashHeavy: "crash_heavy",
|
|
45685
|
-
skidAsphalt: "tire_skid_asphalt",
|
|
45686
|
-
skidDirt: "tire_skid_dirt",
|
|
45687
|
-
roll: "tire_roll"
|
|
46130
|
+
var CAR_RECORDED_RPM = { idle: 1e3, high: 2520 };
|
|
46131
|
+
var CAR_START_RUN_STOP = {
|
|
46132
|
+
/** The starter and the engine catching (at 0.58 s) and flaring; the loops take over at the crank time of the vehicle. */
|
|
46133
|
+
start: { offset: 0, duration: 1.3 },
|
|
46134
|
+
/** The ignition off: the engine running down to the end of the file. */
|
|
46135
|
+
stop: { offset: 9.96, duration: 0.64 }
|
|
45688
46136
|
};
|
|
45689
|
-
var
|
|
45690
|
-
|
|
45691
|
-
|
|
45692
|
-
|
|
45693
|
-
|
|
46137
|
+
var carLayer = (id, file, rpm, harmonic, offset) => ({
|
|
46138
|
+
id,
|
|
46139
|
+
file,
|
|
46140
|
+
loop: true,
|
|
46141
|
+
// the layer's oscillator plays the firing frequency times its harmonic: the file sounds at that frequency for the RPM it was recorded at
|
|
46142
|
+
baseFrequency: firingHz(CAR_ENGINE, rpm) * harmonic,
|
|
46143
|
+
falloff: VEHICLE_LOOP_FALLOFF,
|
|
46144
|
+
...offset === void 0 ? {} : { offset }
|
|
46145
|
+
});
|
|
46146
|
+
var VEHICLE_SAMPLE_ALIASES = [
|
|
46147
|
+
carLayer("engine_car_low", "engine_loop_car_idle", CAR_RECORDED_RPM.idle, 1),
|
|
46148
|
+
carLayer("engine_car_mid", "engine_loop_car_high", CAR_RECORDED_RPM.high, 1),
|
|
46149
|
+
// the same file as the mid layer, read from two seconds in, so the two do not sum in phase where they cross
|
|
46150
|
+
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 },
|
|
46153
|
+
{ id: "car_door_close", file: "car_door_shut" },
|
|
46154
|
+
{ id: "car_trunk_close", file: "car_trunk_shut" }
|
|
45694
46155
|
];
|
|
45695
|
-
var
|
|
45696
|
-
id: "car",
|
|
45697
|
-
cylinders: 4,
|
|
45698
|
-
idleRpm: 800,
|
|
45699
|
-
redlineRpm: 6500,
|
|
45700
|
-
// a 5-speed hatch: 1st tops at ~13 m/s, 5th at ~50 m/s
|
|
45701
|
-
rpmPerMps: [500, 300, 205, 155, 125],
|
|
45702
|
-
layers: layers("car", [[220, 520], [420, 1300], [900, 2600]], [0.11, 0.075, 0.04]),
|
|
45703
|
-
load: { sound: "engine_car_load", gain: 0.05, cutoff: [350, 1600] },
|
|
45704
|
-
closedThrottle: 0.55
|
|
45705
|
-
};
|
|
45706
|
-
var TRUCK_ENGINE = {
|
|
45707
|
-
id: "truck",
|
|
45708
|
-
cylinders: 6,
|
|
45709
|
-
idleRpm: 650,
|
|
45710
|
-
redlineRpm: 2600,
|
|
45711
|
-
rpmPerMps: [420, 260, 170, 120, 90, 72],
|
|
45712
|
-
layers: layers("truck", [[160, 380], [300, 800], [600, 1500]], [0.13, 0.08, 0.035]),
|
|
45713
|
-
load: { sound: "engine_truck_load", gain: 0.06, cutoff: [250, 900] },
|
|
45714
|
-
closedThrottle: 0.6
|
|
45715
|
-
};
|
|
45716
|
-
var BIKE_ENGINE = {
|
|
45717
|
-
id: "bike",
|
|
45718
|
-
cylinders: 4,
|
|
45719
|
-
idleRpm: 1300,
|
|
45720
|
-
redlineRpm: 12e3,
|
|
45721
|
-
rpmPerMps: [900, 640, 500, 410, 350, 310],
|
|
45722
|
-
layers: layers("bike", [[350, 900], [700, 2200], [1500, 4200]], [0.08, 0.07, 0.05]),
|
|
45723
|
-
load: { sound: "engine_bike_load", gain: 0.045, cutoff: [600, 2600] },
|
|
45724
|
-
closedThrottle: 0.5
|
|
45725
|
-
};
|
|
45726
|
-
var ENGINE_PROFILES = { car: CAR_ENGINE, truck: TRUCK_ENGINE, bike: BIKE_ENGINE };
|
|
46156
|
+
var VEHICLE_SOUND_BANK = { id: "vehicles_three", sounds: VEHICLE_SOUNDS, loops: VEHICLE_LOOPS, sampleAliases: VEHICLE_SAMPLE_ALIASES };
|
|
45727
46157
|
|
|
45728
46158
|
// src/audio/vehicle-sound.ts
|
|
45729
46159
|
var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
@@ -45781,8 +46211,8 @@ var GameVehiclesThree = (() => {
|
|
|
45781
46211
|
const driven = frame.rpm ?? gears.rpm(frame.speed, throttle);
|
|
45782
46212
|
const rpm = state.running ? Math.max(driven, profile.idleRpm * (1 + 1.2 * state.flare * state.flare)) : 0;
|
|
45783
46213
|
state.rpm = rpm;
|
|
45784
|
-
for (const
|
|
45785
|
-
setLoop(
|
|
46214
|
+
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 });
|
|
45786
46216
|
}
|
|
45787
46217
|
const speed = Math.abs(frame.speed);
|
|
45788
46218
|
const slide = clamp012(((frame.slip ?? 0) - 0.15) / 0.5) * clamp012(speed / 4);
|
|
@@ -46184,7 +46614,15 @@ var GameVehiclesThree = (() => {
|
|
|
46184
46614
|
var clamp22 = (x, a, b) => Math.max(a, Math.min(b, x));
|
|
46185
46615
|
var MAX_SUBSTEP = 1 / 240;
|
|
46186
46616
|
var FLAT_BELOW = 0.2;
|
|
46617
|
+
var RIM_RADIUS_SHARE = 0.7;
|
|
46618
|
+
var RIM_FRICTION = 0.4;
|
|
46619
|
+
var RIM_ROLLING = 0.25;
|
|
46620
|
+
var FLAT_SAG = 0.05;
|
|
46621
|
+
var FLAT_ROLLING = 6;
|
|
46187
46622
|
var STALL_HEALTH = 0.3;
|
|
46623
|
+
var CLUTCH_BITE = 0.7;
|
|
46624
|
+
var STALL_RPM = 0.5;
|
|
46625
|
+
var STALL_GAS = 0.35;
|
|
46188
46626
|
var defaultSemiSpec = {
|
|
46189
46627
|
mass: 1300,
|
|
46190
46628
|
centreHeight: 0.5,
|
|
@@ -46325,7 +46763,14 @@ var GameVehiclesThree = (() => {
|
|
|
46325
46763
|
const accelInput = reversing ? input.brake : input.throttle;
|
|
46326
46764
|
const brakeInput = clamp22(reversing ? input.throttle : input.brake, 0, 1);
|
|
46327
46765
|
const ratio = ratioOf(state.gear) * spec.finalDrive;
|
|
46328
|
-
state.
|
|
46766
|
+
const engaged = input.clutch == null || state.gear === 0 ? 1 : 1 - clamp22(input.clutch, 0, 1);
|
|
46767
|
+
const coupled = wheelRpm * ratio;
|
|
46768
|
+
const free = spec.engine.idleRpm + clamp22(accelInput, 0, 1) * (spec.engine.redlineRpm * 0.7 - spec.engine.idleRpm);
|
|
46769
|
+
state.rpm = clamp22(coupled * engaged + Math.max(coupled, free) * (1 - engaged), spec.engine.idleRpm, spec.engine.redlineRpm + 200);
|
|
46770
|
+
if (input.clutch != null && state.gear !== 0 && state.engineOn && engaged > CLUTCH_BITE && coupled < spec.engine.idleRpm * STALL_RPM && accelInput < STALL_GAS) {
|
|
46771
|
+
state.engineOn = false;
|
|
46772
|
+
events.push({ type: "stall" });
|
|
46773
|
+
}
|
|
46329
46774
|
if (!state.engineOn || state.fuel <= 0) state.rpm = 0;
|
|
46330
46775
|
let throttle = clamp22(accelInput, 0, 1);
|
|
46331
46776
|
if (engineHealth < STALL_HEALTH && throttle > 0.8) {
|
|
@@ -46336,12 +46781,13 @@ var GameVehiclesThree = (() => {
|
|
|
46336
46781
|
}
|
|
46337
46782
|
throttle *= 0.5;
|
|
46338
46783
|
} else stallWatch.throttleTime = 0;
|
|
46339
|
-
|
|
46784
|
+
const starting = input.start ?? (accelInput > 0 && Math.abs(state.u) < 0.5);
|
|
46785
|
+
if (!state.engineOn && starting && engineHealth >= STALL_HEALTH && state.fuel > 0) state.engineOn = true;
|
|
46340
46786
|
if (state.fuel <= 0 && state.engineOn) {
|
|
46341
46787
|
state.engineOn = false;
|
|
46342
46788
|
events.push({ type: "out_of_fuel" });
|
|
46343
46789
|
}
|
|
46344
|
-
const engineTorque = state.engineOn ? torqueAt(spec, state.rpm) * throttle * (0.55 + 0.45 * engineHealth) : 0;
|
|
46790
|
+
const engineTorque = state.engineOn ? torqueAt(spec, state.rpm) * throttle * (0.55 + 0.45 * engineHealth) * clamp22(input.powerLimit ?? 1, 0, 1) * engaged : 0;
|
|
46345
46791
|
const driveForceTotal = state.gear === 0 ? 0 : (reversing ? -1 : 1) * engineTorque * ratio * spec.efficiency / spec.wheelRadius;
|
|
46346
46792
|
if (state.engineOn) {
|
|
46347
46793
|
const burned = fuelRate(fuelModel, state.rpm / spec.engine.redlineRpm, throttle, cargo / baseMass, engineHealth) * dt;
|
|
@@ -46359,19 +46805,21 @@ var GameVehiclesThree = (() => {
|
|
|
46359
46805
|
const wz = state.z - w.x * sn + w.z * cs;
|
|
46360
46806
|
const ground = world.ground ? world.ground(wx, wz) : {};
|
|
46361
46807
|
const surface = surfaces.get(contamination && contamination.left > 0 && surfaces.get(contamination.id).grip < surfaces.get(ground.surface ?? "dry_asphalt").grip ? contamination.id : ground.surface ?? "dry_asphalt");
|
|
46808
|
+
const tyreHealth = cond.tyres ? clamp22(cond.tyres[i] ?? 1, 0, 1) : 1;
|
|
46809
|
+
const rim = !!cond.rims?.[i];
|
|
46810
|
+
const flat = rim || tyreHealth < FLAT_BELOW;
|
|
46811
|
+
const radius = rim ? spec.rimRadius ?? spec.wheelRadius * RIM_RADIUS_SHARE : flat ? spec.wheelRadius - FLAT_SAG : spec.wheelRadius;
|
|
46362
46812
|
const top = state.height + w.x * state.pitch - w.z * state.roll;
|
|
46363
|
-
const length = top - (ground.height ?? 0) -
|
|
46813
|
+
const length = top - (ground.height ?? 0) - radius;
|
|
46364
46814
|
const compression = ride - length;
|
|
46365
46815
|
const rate = -(state.heightRate + w.x * state.pitchRate - w.z * state.rollRate);
|
|
46366
46816
|
const k = spec.suspension.spring * (0.5 + 0.5 * suspensionHealth);
|
|
46367
46817
|
const c = spec.suspension.damper * (0.5 + 0.5 * suspensionHealth);
|
|
46368
46818
|
const load = Math.max(0, k * compression + c * rate);
|
|
46369
|
-
const tyreHealth = cond.tyres ? clamp22(cond.tyres[i] ?? 1, 0, 1) : 1;
|
|
46370
|
-
const flat = tyreHealth < FLAT_BELOW;
|
|
46371
46819
|
const bog = !!surface.bogs && !spec.fourWheelDrive;
|
|
46372
46820
|
if (bog) bogging = true;
|
|
46373
|
-
const grip = surfaceGrip(surface, state.u) * (flat ? 0.5 : 1);
|
|
46374
|
-
wheelState.push({ n: load, grip, surface: surface.id, bog, flat });
|
|
46821
|
+
const grip = surfaceGrip(surface, state.u) * (rim ? RIM_FRICTION / spec.tyre.friction : flat ? 0.5 : 1);
|
|
46822
|
+
wheelState.push({ n: load, grip, surface: surface.id, bog, flat, rim });
|
|
46375
46823
|
sumN += load;
|
|
46376
46824
|
sumNA += load * w.x;
|
|
46377
46825
|
sumNB += load * w.z;
|
|
@@ -46407,7 +46855,7 @@ var GameVehiclesThree = (() => {
|
|
|
46407
46855
|
if (locked || lockedByBrake) fl += moving ? -Math.sign(vl) * capacity * (lockedByBrake ? SLIDING_GRIP : 1) : 0;
|
|
46408
46856
|
else if (brakeShare > 0 && moving) fl += -Math.sign(vl) * brakeShare;
|
|
46409
46857
|
if (brakeShare > 0 && moving) brakeWork += Math.min(brakeShare, capacity) * Math.abs(vl) * dt;
|
|
46410
|
-
const rolling = ws.bog && accelInput > 0 ? spec.bogResistance : spec.rolling * (ws.flat ?
|
|
46858
|
+
const rolling = ws.bog && accelInput > 0 ? spec.bogResistance : ws.rim ? RIM_ROLLING : spec.rolling * (ws.flat ? FLAT_ROLLING : 1);
|
|
46411
46859
|
const alpha = Math.atan2(vc, Math.abs(vl) + 0.5);
|
|
46412
46860
|
let fc = -Math.tanh(spec.tyre.corneringStiffness * alpha) * capacity;
|
|
46413
46861
|
if (locked) fc *= 0.6;
|
|
@@ -46482,6 +46930,21 @@ var GameVehiclesThree = (() => {
|
|
|
46482
46930
|
const brakeForce = base.brakeForce ?? body.mass * 9.81 * (carRatio + (0.6 - carRatio) * heavyShare);
|
|
46483
46931
|
return { ...spec, mass: body.mass, wheels, fourWheelDrive: driveAll, engine, gears, drag, brakeForce, tyre: { ...spec.tyre, friction: 0.8 + 0.03 * stats2.handling } };
|
|
46484
46932
|
}
|
|
46933
|
+
var DRIVE_PROFILES = {
|
|
46934
|
+
eco: { throttle: 0.7, upshift: 0.55, downshift: 0.25 },
|
|
46935
|
+
normal: { throttle: 1, upshift: 0.85, downshift: 0.35 },
|
|
46936
|
+
sport: { throttle: 1, upshift: 0.97, downshift: 0.55 }
|
|
46937
|
+
};
|
|
46938
|
+
var DEFAULT_TRACTION = { slip: 0.97, floor: 0.35 };
|
|
46939
|
+
function tractionLimit(slips, options = DEFAULT_TRACTION) {
|
|
46940
|
+
const worst = Math.max(0, ...slips);
|
|
46941
|
+
if (worst <= options.slip) return 1;
|
|
46942
|
+
return Math.max(options.floor, 1 - (worst - options.slip) / (1 - options.slip));
|
|
46943
|
+
}
|
|
46944
|
+
var DEFAULT_CRUISE = { gain: 0.35, minSpeed: 8.3 };
|
|
46945
|
+
function cruiseThrottle(target, speed, options = DEFAULT_CRUISE) {
|
|
46946
|
+
return Math.max(0, Math.min(1, (target - speed) * options.gain + 0.12));
|
|
46947
|
+
}
|
|
46485
46948
|
var DEFAULT_CONTROL_KEYS = {
|
|
46486
46949
|
throttle: ["KeyW", "ArrowUp"],
|
|
46487
46950
|
brake: ["KeyS", "ArrowDown"],
|
|
@@ -46489,6 +46952,9 @@ var GameVehiclesThree = (() => {
|
|
|
46489
46952
|
right: ["KeyD", "ArrowRight"],
|
|
46490
46953
|
handbrake: ["Space"],
|
|
46491
46954
|
horn: ["KeyH"],
|
|
46955
|
+
clutch: ["KeyC"],
|
|
46956
|
+
flash: ["KeyX"],
|
|
46957
|
+
washer: ["KeyZ"],
|
|
46492
46958
|
ignition: ["KeyI"],
|
|
46493
46959
|
gearbox: ["KeyM"],
|
|
46494
46960
|
gear_up: ["KeyE"],
|
|
@@ -46502,13 +46968,21 @@ var GameVehiclesThree = (() => {
|
|
|
46502
46968
|
alarm: ["KeyY"],
|
|
46503
46969
|
radio: ["KeyR"],
|
|
46504
46970
|
radio_source: ["KeyT"],
|
|
46971
|
+
radio_track: ["BracketRight"],
|
|
46505
46972
|
exit: ["KeyF"],
|
|
46506
46973
|
indicator_left: ["Comma"],
|
|
46507
46974
|
indicator_right: ["Period"],
|
|
46508
46975
|
hazard: ["KeyB"],
|
|
46509
46976
|
wipers: ["KeyO"],
|
|
46510
|
-
seatbelt: ["KeyJ"]
|
|
46977
|
+
seatbelt: ["KeyJ"],
|
|
46978
|
+
drive_profile: ["Digit7"],
|
|
46979
|
+
traction_control: ["Digit8"],
|
|
46980
|
+
abs: ["Digit9"],
|
|
46981
|
+
cruise: ["Digit0"],
|
|
46982
|
+
climate: ["Minus"],
|
|
46983
|
+
demist: ["Equal"]
|
|
46511
46984
|
};
|
|
46985
|
+
var HELD_KEYS = ["throttle", "brake", "left", "right", "handbrake", "horn", "clutch", "flash", "washer"];
|
|
46512
46986
|
function createVehicleControls(options) {
|
|
46513
46987
|
const keys = { ...DEFAULT_CONTROL_KEYS, ...options.keys };
|
|
46514
46988
|
const auto4 = options.autoFourWheel ?? { slip: 0.18, releaseSeconds: 2 };
|
|
@@ -46516,7 +46990,7 @@ var GameVehiclesThree = (() => {
|
|
|
46516
46990
|
const held = /* @__PURE__ */ new Set();
|
|
46517
46991
|
const any = (codes) => codes.some((c) => held.has(c));
|
|
46518
46992
|
const commandOf = /* @__PURE__ */ new Map();
|
|
46519
|
-
for (const [command2, codes] of Object.entries(keys)) if (!
|
|
46993
|
+
for (const [command2, codes] of Object.entries(keys)) if (!HELD_KEYS.includes(command2)) for (const code of codes) commandOf.set(code, command2);
|
|
46520
46994
|
const driving = new Set(Object.values(keys).flat());
|
|
46521
46995
|
const state = {
|
|
46522
46996
|
ignition: !!options.running,
|
|
@@ -46525,18 +46999,29 @@ var GameVehiclesThree = (() => {
|
|
|
46525
46999
|
parkingBrake: false,
|
|
46526
47000
|
driveMode: options.fourWheelDrive ? "auto" : "4x2",
|
|
46527
47001
|
fourWheelEngaged: false,
|
|
46528
|
-
lamps: { mode: "off", fog: false, interior: false },
|
|
47002
|
+
lamps: { mode: "off", fog: false, interior: false, flash: false },
|
|
46529
47003
|
brakeLights: false,
|
|
46530
47004
|
reverseLights: false,
|
|
46531
47005
|
horn: false,
|
|
46532
47006
|
alarm: "off",
|
|
46533
|
-
radio: { on: false, source: "radio" },
|
|
47007
|
+
radio: { on: false, source: "radio", track: 0 },
|
|
46534
47008
|
indicator: "off",
|
|
46535
47009
|
blinkOn: false,
|
|
46536
47010
|
tick: false,
|
|
46537
47011
|
wipers: "off",
|
|
46538
|
-
|
|
46539
|
-
|
|
47012
|
+
washer: false,
|
|
47013
|
+
seatbelt: false,
|
|
47014
|
+
clutch: 0,
|
|
47015
|
+
profile: "normal",
|
|
47016
|
+
tractionControl: true,
|
|
47017
|
+
abs: true,
|
|
47018
|
+
cruise: { on: false, speed: 0 },
|
|
47019
|
+
climate: { on: false, demist: false },
|
|
47020
|
+
cranking: false
|
|
47021
|
+
};
|
|
47022
|
+
let crankAsked = false;
|
|
47023
|
+
let lastSpeed = 0;
|
|
47024
|
+
let engineRunning = !!options.running;
|
|
46540
47025
|
const blinkHz = options.blinkHz ?? 1.5;
|
|
46541
47026
|
const cancelAt = options.indicatorCancel ?? 0.15;
|
|
46542
47027
|
let blink = 0;
|
|
@@ -46548,15 +47033,19 @@ var GameVehiclesThree = (() => {
|
|
|
46548
47033
|
const emit = (event) => options.onEvent?.(event);
|
|
46549
47034
|
const LAMPS = ["off", "position", "low"];
|
|
46550
47035
|
const MODES = ["4x2", "4x4", "auto"];
|
|
47036
|
+
const WIPERS = ["off", "intermittent", "slow", "fast"];
|
|
47037
|
+
const PROFILES = ["eco", "normal", "sport"];
|
|
46551
47038
|
const command = (c) => {
|
|
46552
47039
|
switch (c) {
|
|
46553
47040
|
case "ignition":
|
|
46554
47041
|
state.ignition = !state.ignition;
|
|
46555
47042
|
if (state.ignition && state.alarm !== "off") state.alarm = "off";
|
|
47043
|
+
if (state.ignition) crankAsked = true;
|
|
47044
|
+
else state.cruise.on = false;
|
|
46556
47045
|
break;
|
|
46557
47046
|
case "gearbox":
|
|
46558
47047
|
state.gearbox = state.gearbox === "automatic" ? "manual" : "automatic";
|
|
46559
|
-
state.gear = Math.max(1, state.gear);
|
|
47048
|
+
state.gear = options.clutchPedal && state.gearbox === "manual" && Math.abs(lastSpeed) < 0.5 ? 0 : Math.max(1, state.gear);
|
|
46560
47049
|
break;
|
|
46561
47050
|
case "gear_up":
|
|
46562
47051
|
case "gear_down":
|
|
@@ -46595,6 +47084,9 @@ var GameVehiclesThree = (() => {
|
|
|
46595
47084
|
case "radio_source":
|
|
46596
47085
|
state.radio.source = state.radio.source === "radio" ? "tape" : "radio";
|
|
46597
47086
|
break;
|
|
47087
|
+
case "radio_track":
|
|
47088
|
+
state.radio.track = (state.radio.track + 1) % Math.max(1, options.radioTracks ?? 3);
|
|
47089
|
+
break;
|
|
46598
47090
|
case "exit":
|
|
46599
47091
|
break;
|
|
46600
47092
|
case "indicator_left":
|
|
@@ -46611,7 +47103,30 @@ var GameVehiclesThree = (() => {
|
|
|
46611
47103
|
blink = 0;
|
|
46612
47104
|
break;
|
|
46613
47105
|
case "wipers":
|
|
46614
|
-
state.wipers = state.wipers
|
|
47106
|
+
state.wipers = WIPERS[(WIPERS.indexOf(state.wipers) + 1) % WIPERS.length];
|
|
47107
|
+
break;
|
|
47108
|
+
case "drive_profile":
|
|
47109
|
+
state.profile = PROFILES[(PROFILES.indexOf(state.profile) + 1) % PROFILES.length];
|
|
47110
|
+
break;
|
|
47111
|
+
case "traction_control":
|
|
47112
|
+
state.tractionControl = !state.tractionControl;
|
|
47113
|
+
break;
|
|
47114
|
+
case "abs":
|
|
47115
|
+
state.abs = !state.abs;
|
|
47116
|
+
break;
|
|
47117
|
+
case "cruise":
|
|
47118
|
+
if (state.cruise.on) state.cruise.on = false;
|
|
47119
|
+
else if (!engineRunning) return emit({ type: "refused", command: c, reason: "ignition_off" });
|
|
47120
|
+
else if (lastSpeed < DEFAULT_CRUISE.minSpeed) return emit({ type: "refused", command: c, reason: "too_slow" });
|
|
47121
|
+
else state.cruise = { on: true, speed: lastSpeed };
|
|
47122
|
+
break;
|
|
47123
|
+
case "climate":
|
|
47124
|
+
state.climate.on = !state.climate.on;
|
|
47125
|
+
if (!state.climate.on) state.climate.demist = false;
|
|
47126
|
+
break;
|
|
47127
|
+
case "demist":
|
|
47128
|
+
state.climate.demist = !state.climate.demist;
|
|
47129
|
+
if (state.climate.demist) state.climate.on = true;
|
|
46615
47130
|
break;
|
|
46616
47131
|
case "seatbelt":
|
|
46617
47132
|
state.seatbelt = !state.seatbelt;
|
|
@@ -46655,16 +47170,48 @@ var GameVehiclesThree = (() => {
|
|
|
46655
47170
|
}
|
|
46656
47171
|
} else state.blinkOn = false;
|
|
46657
47172
|
state.horn = any(keys.horn);
|
|
46658
|
-
|
|
47173
|
+
state.lamps.flash = any(keys.flash);
|
|
47174
|
+
state.washer = any(keys.washer);
|
|
47175
|
+
state.clutch = ease(state.clutch, any(keys.clutch) ? 1 : 0, any(keys.clutch) ? 8 : 2.5, dt);
|
|
47176
|
+
const speed = driver?.state.u ?? 0;
|
|
47177
|
+
lastSpeed = speed;
|
|
47178
|
+
if (state.cruise.on && (brake > 0.05 || state.clutch > 0.5 || handbrake)) {
|
|
47179
|
+
state.cruise.on = false;
|
|
47180
|
+
emit({ type: "cruise_cancelled" });
|
|
47181
|
+
}
|
|
47182
|
+
const tune = DRIVE_PROFILES[state.profile];
|
|
47183
|
+
let gasNow = state.ignition ? throttle * tune.throttle : 0;
|
|
47184
|
+
if (state.cruise.on && state.ignition) gasNow = Math.max(gasNow, cruiseThrottle(state.cruise.speed, speed));
|
|
47185
|
+
const gasStart = state.gearbox === "automatic" && state.ignition && !engineRunning && throttle > 0 && Math.abs(speed) < 0.5;
|
|
47186
|
+
state.cranking = false;
|
|
47187
|
+
if (crankAsked || gasStart) {
|
|
47188
|
+
crankAsked = false;
|
|
47189
|
+
if (options.canCrank && !options.canCrank()) emit({ type: "refused", command: "ignition", reason: "battery_flat" });
|
|
47190
|
+
else {
|
|
47191
|
+
state.cranking = true;
|
|
47192
|
+
options.onCrank?.();
|
|
47193
|
+
}
|
|
47194
|
+
}
|
|
47195
|
+
const driven = (driver?.state.slip ?? []).filter((_, i) => driver?.spec.wheels?.[i]?.drive ?? true);
|
|
47196
|
+
const powerLimit = (state.tractionControl ? tractionLimit(driven) : 1) * (options.powerLimit?.() ?? 1);
|
|
46659
47197
|
const reversing = state.gearbox === "manual" ? state.gear < 0 : (driver?.state.gear ?? 1) < 0;
|
|
46660
47198
|
state.reverseLights = reversing;
|
|
46661
|
-
state.brakeLights = handbrake || (reversing ? gasNow > 0.05 &&
|
|
46662
|
-
|
|
46663
|
-
|
|
47199
|
+
state.brakeLights = handbrake || (reversing ? gasNow > 0.05 && speed < -0.3 : brake > 0.05);
|
|
47200
|
+
const common = { steer, handbrake, horn: state.horn, start: state.cranking, powerLimit };
|
|
47201
|
+
if (state.gearbox === "automatic") return { ...common, throttle: gasNow, brake };
|
|
47202
|
+
const pedals = state.gear < 0 ? { throttle: brake, brake: gasNow } : { throttle: gasNow, brake };
|
|
47203
|
+
return { ...common, ...pedals, gear: state.gear, ...options.clutchPedal ? { clutch: state.clutch } : {} };
|
|
46664
47204
|
},
|
|
46665
47205
|
after(driver, dt) {
|
|
46666
|
-
if (driver.state.engineOn && !state.ignition && driver.state.u !== 0) state.ignition = true;
|
|
46667
47206
|
if (!state.ignition && driver.state.engineOn) driver.state.engineOn = false;
|
|
47207
|
+
engineRunning = driver.state.engineOn;
|
|
47208
|
+
if (!engineRunning) state.cruise.on = false;
|
|
47209
|
+
const spec = driver.spec;
|
|
47210
|
+
spec.abs = state.abs;
|
|
47211
|
+
if (spec.upshiftFraction != null) {
|
|
47212
|
+
spec.upshiftFraction = DRIVE_PROFILES[state.profile].upshift;
|
|
47213
|
+
spec.downshiftFraction = DRIVE_PROFILES[state.profile].downshift;
|
|
47214
|
+
}
|
|
46668
47215
|
if (state.driveMode === "auto" && options.fourWheelDrive) {
|
|
46669
47216
|
const slip = Math.max(0, ...driver.state.slip);
|
|
46670
47217
|
if (slip > auto4.slip) {
|
|
@@ -46678,6 +47225,10 @@ var GameVehiclesThree = (() => {
|
|
|
46678
47225
|
held.clear();
|
|
46679
47226
|
throttle = brake = steer = 0;
|
|
46680
47227
|
state.horn = false;
|
|
47228
|
+
state.lamps.flash = false;
|
|
47229
|
+
state.washer = false;
|
|
47230
|
+
state.clutch = 0;
|
|
47231
|
+
state.cruise.on = false;
|
|
46681
47232
|
}
|
|
46682
47233
|
};
|
|
46683
47234
|
}
|
|
@@ -46692,15 +47243,126 @@ var GameVehiclesThree = (() => {
|
|
|
46692
47243
|
best = tyre;
|
|
46693
47244
|
}
|
|
46694
47245
|
}
|
|
46695
|
-
return best
|
|
47246
|
+
return best;
|
|
46696
47247
|
});
|
|
46697
47248
|
return {
|
|
46698
|
-
tyres,
|
|
47249
|
+
tyres: tyres.map((tyre) => tyre?.health ?? 1),
|
|
47250
|
+
rims: tyres.map((tyre) => !!tyre?.rim),
|
|
46699
47251
|
...report.brakes != null ? { brakes: report.brakes } : {},
|
|
46700
47252
|
...report.engine != null ? { engine: report.engine } : {},
|
|
46701
47253
|
...report.suspension != null ? { suspension: report.suspension } : {}
|
|
46702
47254
|
};
|
|
46703
47255
|
}
|
|
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 };
|
|
47257
|
+
var clamp3 = (x, a, b) => Math.max(a, Math.min(b, x));
|
|
47258
|
+
function createVehicleSystems(options = {}) {
|
|
47259
|
+
const loads = { ...DEFAULT_LOADS, ...options.loads };
|
|
47260
|
+
const capacity = options.batteryWh ?? 720;
|
|
47261
|
+
const alternator = options.alternatorW ?? { idle: 350, full: 1100 };
|
|
47262
|
+
const crankCharge = options.crankCharge ?? 0.25;
|
|
47263
|
+
const startWh = options.startWh ?? 0.6;
|
|
47264
|
+
const ambient = options.ambientC ?? 25;
|
|
47265
|
+
const thermostat = options.thermostatC ?? 90;
|
|
47266
|
+
const limp = options.limpC ?? 115;
|
|
47267
|
+
const seize = options.seizeC ?? 130;
|
|
47268
|
+
const heat = options.heatPerSecond ?? 0.5;
|
|
47269
|
+
const cooling = options.cooling ?? { stopped: 4e-3, fast: 0.03 };
|
|
47270
|
+
const state = { charge: clamp3(options.charge ?? 1, 0, 1), coolantC: ambient, temperature: 0, overheating: false, seized: false, spares: options.spares ?? 1, netW: 0 };
|
|
47271
|
+
const draw = (c) => {
|
|
47272
|
+
const lamps = c.lamps;
|
|
47273
|
+
let w = lamps.mode === "off" ? 0 : loads.position;
|
|
47274
|
+
if (lamps.mode === "low") w += loads.low;
|
|
47275
|
+
if (lamps.mode === "high") w += loads.low + loads.high;
|
|
47276
|
+
if (lamps.flash) w += loads.high;
|
|
47277
|
+
if (lamps.fog) w += loads.fog;
|
|
47278
|
+
if (lamps.interior) w += loads.interior;
|
|
47279
|
+
if (c.radio.on) w += loads.radio;
|
|
47280
|
+
if (c.wipers !== "off" || c.washer) w += loads.wipers;
|
|
47281
|
+
if (c.indicator !== "off") w += loads.indicators * (c.indicator === "hazard" ? 2 : 1) * 0.5;
|
|
47282
|
+
if (c.horn) w += loads.horn;
|
|
47283
|
+
if (c.alarm !== "off") w += loads.alarm;
|
|
47284
|
+
if (c.brakeLights) w += loads.brakeLights;
|
|
47285
|
+
if (c.climate.on) w += loads.climate;
|
|
47286
|
+
return w;
|
|
47287
|
+
};
|
|
47288
|
+
return {
|
|
47289
|
+
state,
|
|
47290
|
+
canCrank: () => state.charge >= crankCharge && !state.seized,
|
|
47291
|
+
crank() {
|
|
47292
|
+
state.charge = clamp3(state.charge - startWh / capacity, 0, 1);
|
|
47293
|
+
},
|
|
47294
|
+
powerLimit: () => state.coolantC <= limp ? 1 : clamp3(1 - (state.coolantC - limp) / (seize - limp), 0.25, 1),
|
|
47295
|
+
step({ driver, controls, throttle, dt, radiator = 1, coolantC }) {
|
|
47296
|
+
const events = [];
|
|
47297
|
+
const running = driver.state.engineOn;
|
|
47298
|
+
const charging = running ? alternator.idle + (alternator.full - alternator.idle) * clamp3((driver.state.rpm - 900) / 1100, 0, 1) : 0;
|
|
47299
|
+
const net = charging - draw(controls);
|
|
47300
|
+
state.netW = net;
|
|
47301
|
+
const before = state.charge;
|
|
47302
|
+
state.charge = clamp3(state.charge + net * dt / 3600 / capacity, 0, 1);
|
|
47303
|
+
if (before >= crankCharge && state.charge < crankCharge && !running) events.push({ type: "battery_flat" });
|
|
47304
|
+
const work = running ? clamp3(0.15 + 0.85 * throttle * (driver.state.rpm / 6500), 0, 1) : 0;
|
|
47305
|
+
const air = cooling.stopped + (cooling.fast - cooling.stopped) * clamp3(Math.abs(driver.state.u) / 27.8, 0, 1);
|
|
47306
|
+
const cool = air * clamp3(radiator, 0.05, 1) * (running ? 1 + (controls.climate.on ? 0.15 : 0) : 1);
|
|
47307
|
+
const opened = state.coolantC >= thermostat ? 1 : 0.15;
|
|
47308
|
+
state.coolantC += (heat * work - cool * opened * (state.coolantC - ambient)) * dt;
|
|
47309
|
+
state.coolantC = coolantC ?? Math.max(ambient, state.coolantC);
|
|
47310
|
+
state.temperature = clamp3((state.coolantC - ambient) / (seize - ambient), 0, 1);
|
|
47311
|
+
const hot = state.coolantC > limp;
|
|
47312
|
+
if (hot && !state.overheating) events.push({ type: "overheating" });
|
|
47313
|
+
state.overheating = hot;
|
|
47314
|
+
if (state.coolantC >= seize && !state.seized) {
|
|
47315
|
+
state.seized = true;
|
|
47316
|
+
events.push({ type: "seized" });
|
|
47317
|
+
}
|
|
47318
|
+
if (state.seized) driver.state.engineOn = false;
|
|
47319
|
+
return events;
|
|
47320
|
+
},
|
|
47321
|
+
fitSpare(driver, wheel) {
|
|
47322
|
+
if (state.spares <= 0) return { type: "no_spare" };
|
|
47323
|
+
state.spares--;
|
|
47324
|
+
const tyres = [...driver.condition.tyres ?? []];
|
|
47325
|
+
tyres[wheel] = 1;
|
|
47326
|
+
driver.condition = { ...driver.condition, tyres };
|
|
47327
|
+
return { type: "spare_fitted", wheel };
|
|
47328
|
+
},
|
|
47329
|
+
charge(share) {
|
|
47330
|
+
state.charge = clamp3(state.charge + share, 0, 1);
|
|
47331
|
+
}
|
|
47332
|
+
};
|
|
47333
|
+
}
|
|
47334
|
+
var DEFAULT_EJECTION = { frontal: 8.3, side: 6, keep: 0.8, lift: 2.5 };
|
|
47335
|
+
function ejectionOf(pulse, belted, options = DEFAULT_EJECTION) {
|
|
47336
|
+
if (belted) return null;
|
|
47337
|
+
const du = pulse.after.u - pulse.before.u;
|
|
47338
|
+
const dw = pulse.after.w - pulse.before.w;
|
|
47339
|
+
const deltaV = Math.hypot(du, dw);
|
|
47340
|
+
const frontal = Math.abs(du) >= Math.abs(dw);
|
|
47341
|
+
if (frontal && Math.abs(du) < options.frontal && !pulse.rolled) return null;
|
|
47342
|
+
if (!frontal && Math.abs(dw) < options.side && !pulse.rolled) return null;
|
|
47343
|
+
const exit = frontal ? du < 0 ? "windshield" : "rear_window" : dw < 0 ? "right_window" : "left_window";
|
|
47344
|
+
return { exit, velocity: [pulse.before.u * options.keep, pulse.before.w * options.keep, options.lift], deltaV };
|
|
47345
|
+
}
|
|
47346
|
+
var DEFAULT_PARKING_SENSOR = { range: 1.5, solid: 0.3, slowest: 0.8, fastest: 0.12 };
|
|
47347
|
+
function parkingBeepInterval(distance, options = DEFAULT_PARKING_SENSOR) {
|
|
47348
|
+
if (distance > options.range) return null;
|
|
47349
|
+
if (distance <= options.solid) return 0;
|
|
47350
|
+
const t = (distance - options.solid) / (options.range - options.solid);
|
|
47351
|
+
return options.fastest + (options.slowest - options.fastest) * t;
|
|
47352
|
+
}
|
|
47353
|
+
function bumperDistance(params) {
|
|
47354
|
+
const [hx, hz2] = params.heading;
|
|
47355
|
+
const sign2 = params.forward ? 1 : -1;
|
|
47356
|
+
let best = Infinity;
|
|
47357
|
+
for (const [ox, oz] of params.obstacles) {
|
|
47358
|
+
const dx = ox - params.x;
|
|
47359
|
+
const dz = oz - params.z;
|
|
47360
|
+
const along = (dx * hx + dz * hz2) * sign2 - params.length / 2;
|
|
47361
|
+
const side2 = Math.abs(-dx * hz2 + dz * hx);
|
|
47362
|
+
if (along >= 0 && side2 <= params.width / 2 + 0.2) best = Math.min(best, along);
|
|
47363
|
+
}
|
|
47364
|
+
return best;
|
|
47365
|
+
}
|
|
46704
47366
|
|
|
46705
47367
|
// src/vehicle-lod.ts
|
|
46706
47368
|
var VEHICLE_LOD_DISTANCE = 14;
|
|
@@ -47341,6 +48003,7 @@ var GameVehiclesThree = (() => {
|
|
|
47341
48003
|
var itemId = (key) => ITEM_OF[key] ?? key;
|
|
47342
48004
|
var LANE = { z: 11, from: -12, wall: 13 };
|
|
47343
48005
|
var SPARK_EVERY_S = 0.08;
|
|
48006
|
+
var TYRE_DAMAGE = /* @__PURE__ */ new Set(["flat_tyre", "torn_tyre", "run_flat"]);
|
|
47344
48007
|
var LEAF_REST_RADIANS = 0.02;
|
|
47345
48008
|
var MATERIAL_COLOURS = { metal: 13421772, glass: 4500223, rubber: 16750848, fuel: 16724736 };
|
|
47346
48009
|
var LANE_START_S = 1.2;
|
|
@@ -47636,7 +48299,8 @@ var GameVehiclesThree = (() => {
|
|
|
47636
48299
|
state.time += dt;
|
|
47637
48300
|
const braking = settings.damage !== "into_wall" && gap() < brakeAt() && state.time > 0.5;
|
|
47638
48301
|
const moving = state.time > LANE_START_S;
|
|
47639
|
-
const
|
|
48302
|
+
const straight = settings.damage === "into_wall" || TYRE_DAMAGE.has(settings.damage) || !moving;
|
|
48303
|
+
const input = { ...idle2, throttle: braking || !moving ? 0 : 1, brake: braking ? 1 : 0, steer: straight ? 0 : Math.sin(state.time * 1.4) * 0.15 };
|
|
47640
48304
|
if (mode === "arcade") {
|
|
47641
48305
|
const { events } = arcade.step(input, dt, { blocked: (x, z, yaw) => vehicleCorners(arcade.spec, x, z, yaw).some(([px]) => px >= LANE.wall) });
|
|
47642
48306
|
for (const e of events) {
|
|
@@ -48287,6 +48951,127 @@ var GameVehiclesThree = (() => {
|
|
|
48287
48951
|
return { ...certificate, results, status: statusOf(results) };
|
|
48288
48952
|
}
|
|
48289
48953
|
|
|
48954
|
+
// src/body.ts
|
|
48955
|
+
var OPEN_SOUND = "car_door_open";
|
|
48956
|
+
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));
|
|
48958
|
+
function createVehicleBody(built2, options) {
|
|
48959
|
+
const swing = options.swingSeconds ?? 1.2;
|
|
48960
|
+
const windowSeconds = options.windowSeconds ?? 3.5;
|
|
48961
|
+
const travel = options.windowTravel ?? 0.92;
|
|
48962
|
+
const root = built2.context?.vehicle ?? built2.group;
|
|
48963
|
+
const poses = /* @__PURE__ */ new Map();
|
|
48964
|
+
for (const clip of options.clips) {
|
|
48965
|
+
if (!clip.id.startsWith("open_")) continue;
|
|
48966
|
+
const last = clip.keys[clip.keys.length - 1];
|
|
48967
|
+
for (const [id, pose] of Object.entries(last?.parts ?? {})) if (pose.rotation) poses.set(id, pose.rotation);
|
|
48968
|
+
}
|
|
48969
|
+
const hinges = /* @__PURE__ */ new Map();
|
|
48970
|
+
for (const [id, open] of poses) {
|
|
48971
|
+
const pivot = root.getObjectByName(id);
|
|
48972
|
+
if (pivot) hinges.set(id, { pivot, open, now: 0, target: 0 });
|
|
48973
|
+
}
|
|
48974
|
+
const kind = (part) => part.startsWith("door") ? "door" : part === "hood" ? "hood" : "lid";
|
|
48975
|
+
const panes = /* @__PURE__ */ new Map();
|
|
48976
|
+
for (const glass of built2.context?.glass ?? []) {
|
|
48977
|
+
const g = glass.userData.glass;
|
|
48978
|
+
if (!g || g.key !== "window_front" && g.key !== "window_rear") continue;
|
|
48979
|
+
const id = `${g.key === "window_front" ? "front" : "rear"}_${(g.side ?? 1) < 0 ? "left" : "right"}`;
|
|
48980
|
+
if (panes.has(id) || !glass.geometry) continue;
|
|
48981
|
+
glass.geometry.computeBoundingBox();
|
|
48982
|
+
const box2 = glass.geometry.boundingBox;
|
|
48983
|
+
if (box2) panes.set(id, { pane: glass, drop: (box2.max.y - box2.min.y) * travel, now: 0, target: 0, applied: 0 });
|
|
48984
|
+
}
|
|
48985
|
+
const sunroofs = [];
|
|
48986
|
+
const wipers = [];
|
|
48987
|
+
const T = options.THREE;
|
|
48988
|
+
const turn = new T.Quaternion();
|
|
48989
|
+
root.traverse((o) => {
|
|
48990
|
+
const sun = o.userData.sunroof;
|
|
48991
|
+
if (sun) sunroofs.push({ obj: o, slide: sun.slide, base: o.position.x });
|
|
48992
|
+
});
|
|
48993
|
+
for (const { part, tag } of built2.context?.wipers ?? [])
|
|
48994
|
+
wipers.push({ obj: part, arm: tag.arm, sweep: tag.sweep, spindle: new T.Vector3(...tag.spindle), axis: new T.Vector3(...tag.axis), rest: part.position.clone(), restQ: part.quaternion.clone() });
|
|
48995
|
+
let sunNow = 0;
|
|
48996
|
+
let sunTarget = 0;
|
|
48997
|
+
let wipePhase = 0;
|
|
48998
|
+
let locked = false;
|
|
48999
|
+
const placeWiper = (w, angle) => {
|
|
49000
|
+
if (angle === 0) {
|
|
49001
|
+
w.obj.position.copy(w.rest);
|
|
49002
|
+
w.obj.quaternion.copy(w.restQ);
|
|
49003
|
+
return;
|
|
49004
|
+
}
|
|
49005
|
+
turn.setFromAxisAngle(w.axis, angle);
|
|
49006
|
+
w.obj.position.copy(w.rest).sub(w.spindle).applyQuaternion(turn).add(w.spindle);
|
|
49007
|
+
w.obj.quaternion.copy(turn).multiply(w.restQ);
|
|
49008
|
+
};
|
|
49009
|
+
const ease = (now, target, seconds, dt) => now + clamp4(target - now, -dt / seconds, dt / seconds);
|
|
49010
|
+
return {
|
|
49011
|
+
parts: [...hinges.keys()],
|
|
49012
|
+
windows: [...panes.keys()],
|
|
49013
|
+
hasSunroof: sunroofs.length > 0,
|
|
49014
|
+
wipers: new Set(wipers.map((w) => w.arm)).size,
|
|
49015
|
+
get locked() {
|
|
49016
|
+
return locked;
|
|
49017
|
+
},
|
|
49018
|
+
openness: (part) => hinges.get(part)?.now ?? 0,
|
|
49019
|
+
toggle(part) {
|
|
49020
|
+
const h = hinges.get(part);
|
|
49021
|
+
if (!h) return [{ type: "refused", part, reason: "missing" }];
|
|
49022
|
+
if (locked && kind(part) !== "hood" && h.target === 0) return [{ type: "refused", part, reason: "locked" }];
|
|
49023
|
+
h.target = h.target > 0 ? 0 : 1;
|
|
49024
|
+
return h.target > 0 ? [{ type: "sound", key: OPEN_SOUND, part }] : [];
|
|
49025
|
+
},
|
|
49026
|
+
window: (id) => panes.get(id)?.now ?? 0,
|
|
49027
|
+
toggleWindow(id) {
|
|
49028
|
+
const w = panes.get(id);
|
|
49029
|
+
if (w) w.target = w.target > 0.5 ? 0 : 1;
|
|
49030
|
+
},
|
|
49031
|
+
setWindow(id, open) {
|
|
49032
|
+
const w = panes.get(id);
|
|
49033
|
+
if (w) w.target = clamp4(open, 0, 1);
|
|
49034
|
+
},
|
|
49035
|
+
toggleSunroof() {
|
|
49036
|
+
sunTarget = sunTarget > 0.5 ? 0 : 1;
|
|
49037
|
+
},
|
|
49038
|
+
lock(on) {
|
|
49039
|
+
locked = on;
|
|
49040
|
+
return [{ type: "sound", key: "blinker_tick", part: "doors" }];
|
|
49041
|
+
},
|
|
49042
|
+
update(dt, wipe = 0) {
|
|
49043
|
+
const events = [];
|
|
49044
|
+
for (const [id, h] of hinges) {
|
|
49045
|
+
if (h.now === h.target) continue;
|
|
49046
|
+
h.now = ease(h.now, h.target, swing, dt);
|
|
49047
|
+
h.pivot.rotation.set(h.open[0] * h.now, h.open[1] * h.now, h.open[2] * h.now);
|
|
49048
|
+
if (h.now === 0) events.push({ type: "sound", key: SHUT_SOUND[kind(id)] ?? "car_door_close", part: id });
|
|
49049
|
+
}
|
|
49050
|
+
for (const w of panes.values()) {
|
|
49051
|
+
if (w.now === w.target) continue;
|
|
49052
|
+
w.now = ease(w.now, w.target, windowSeconds, dt);
|
|
49053
|
+
const offset = -w.drop * w.now;
|
|
49054
|
+
w.pane.position.y += offset - w.applied;
|
|
49055
|
+
w.applied = offset;
|
|
49056
|
+
}
|
|
49057
|
+
if (sunNow !== sunTarget) {
|
|
49058
|
+
sunNow = ease(sunNow, sunTarget, 2.5, dt);
|
|
49059
|
+
for (const s of sunroofs) s.obj.position.x = s.base - s.slide * sunNow;
|
|
49060
|
+
}
|
|
49061
|
+
wipePhase = wipe > 0 ? (wipePhase + dt * wipe) % 1 : wipePhase > 0 ? Math.min(1, wipePhase + dt * 1.5) % 1 : 0;
|
|
49062
|
+
const sweep = Math.sin(Math.PI * wipePhase);
|
|
49063
|
+
for (const w of wipers) placeWiper(w, w.sweep * sweep);
|
|
49064
|
+
return events;
|
|
49065
|
+
},
|
|
49066
|
+
dispose() {
|
|
49067
|
+
for (const h of hinges.values()) h.pivot.rotation.set(0, 0, 0);
|
|
49068
|
+
for (const w of panes.values()) w.pane.position.y -= w.applied;
|
|
49069
|
+
for (const s of sunroofs) s.obj.position.x = s.base;
|
|
49070
|
+
for (const w of wipers) placeWiper(w, 0);
|
|
49071
|
+
}
|
|
49072
|
+
};
|
|
49073
|
+
}
|
|
49074
|
+
|
|
48290
49075
|
// src/dashboard.ts
|
|
48291
49076
|
var DASHBOARD_LOOK = {
|
|
48292
49077
|
face: "#0b1110",
|
|
@@ -48461,6 +49246,8 @@ var GameVehiclesThree = (() => {
|
|
|
48461
49246
|
lamp(g, 104, 214, r.highBeam, DASHBOARD_LOOK.blue, beam);
|
|
48462
49247
|
lamp(g, 152, 214, r.lowBeam || r.fog, r.fog ? DASHBOARD_LOOK.amber : DASHBOARD_LOOK.green, beam);
|
|
48463
49248
|
bar(g, 40, r.fuel, false, "F");
|
|
49249
|
+
lamp(g, 104, 244, !!r.cruise, DASHBOARD_LOOK.green, letter("CRZ"));
|
|
49250
|
+
if (r.profile && r.profile !== "normal") lamp(g, 152, 244, true, r.profile === "eco" ? DASHBOARD_LOOK.green : DASHBOARD_LOOK.amber, letter(r.profile === "eco" ? "E" : "S"));
|
|
48464
49251
|
} else {
|
|
48465
49252
|
dial(g, r.rpm / 1e3, Math.ceil(redline / 1e3) + 1, 1, redline / 1e3, (v) => String(Math.round(v)));
|
|
48466
49253
|
g.fillStyle = DASHBOARD_LOOK.marks;
|
|
@@ -48469,7 +49256,9 @@ var GameVehiclesThree = (() => {
|
|
|
48469
49256
|
g.fillText(r.gear < 0 ? "R" : r.gear === 0 ? "N" : String(r.gear), SIZE / 2, SIZE / 2 + 54);
|
|
48470
49257
|
lamp(g, 86, 178, r.parkingBrake, DASHBOARD_LOOK.red, ring2("P"));
|
|
48471
49258
|
lamp(g, 128, 214, r.ignition && !r.seatbelt, DASHBOARD_LOOK.red, belt);
|
|
48472
|
-
lamp(g, 170, 178, warn, DASHBOARD_LOOK.red, letter("+\u2212"));
|
|
49259
|
+
lamp(g, 170, 178, warn || r.engineOn && r.charging === false, DASHBOARD_LOOK.red, letter("+\u2212"));
|
|
49260
|
+
lamp(g, 104, 244, r.ignition && !!r.tractionOff, DASHBOARD_LOOK.amber, letter("TC"));
|
|
49261
|
+
lamp(g, 152, 244, r.ignition && !!r.absOff, DASHBOARD_LOOK.amber, letter("ABS"));
|
|
48473
49262
|
lamp(g, 86, 214, warn, DASHBOARD_LOOK.red, letter("OIL"));
|
|
48474
49263
|
lamp(g, 170, 214, r.fourWheel, DASHBOARD_LOOK.green, letter("4x4"));
|
|
48475
49264
|
bar(g, SIZE - 40, r.temperature, true, "T");
|
|
@@ -48657,7 +49446,18 @@ var GameVehiclesThree = (() => {
|
|
|
48657
49446
|
}
|
|
48658
49447
|
|
|
48659
49448
|
// src/test-area/proving/cockpit.ts
|
|
48660
|
-
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" };
|
|
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" };
|
|
49450
|
+
var BODY_KEYS = {
|
|
49451
|
+
Digit1: "door_front_left",
|
|
49452
|
+
Digit2: "door_front_right",
|
|
49453
|
+
Digit3: "door_rear_left",
|
|
49454
|
+
Digit4: "door_rear_right",
|
|
49455
|
+
Digit5: "hood",
|
|
49456
|
+
Digit6: "lid"
|
|
49457
|
+
};
|
|
49458
|
+
var WINDOW_KEYS = { Digit1: "front_left", Digit2: "front_right", Digit3: "rear_left", Digit4: "rear_right" };
|
|
49459
|
+
var LOCK_KEY = "KeyV";
|
|
49460
|
+
var WIPE_RATE = { off: 0, intermittent: 0.25, slow: 0.7, fast: 1.4 };
|
|
48661
49461
|
function createCockpit(o) {
|
|
48662
49462
|
const sounds = { ...DEFAULT_COCKPIT_SOUNDS, ...o.sounds };
|
|
48663
49463
|
const spec = subjectSpec(o.subject);
|
|
@@ -48674,19 +49474,38 @@ var GameVehiclesThree = (() => {
|
|
|
48674
49474
|
let wipeAgain = 0;
|
|
48675
49475
|
let chimeAgain = 0;
|
|
48676
49476
|
let radioAgain = 0;
|
|
49477
|
+
let beepAgain = 0;
|
|
49478
|
+
let bar = 0;
|
|
48677
49479
|
let exitAsked = false;
|
|
48678
49480
|
let gas = 0;
|
|
49481
|
+
const systems = createVehicleSystems();
|
|
49482
|
+
const context = o.built.context;
|
|
49483
|
+
const destructible = o.kit && context ? createVehicleDestructible(o.kit, context, { id: "driven", frame: o.built.group }) : null;
|
|
49484
|
+
const body = destructible ? createVehicleBody(o.built, { THREE: o.THREE, clips: destructible.animations() }) : null;
|
|
49485
|
+
const bodyEvents = (events) => {
|
|
49486
|
+
for (const event of events) {
|
|
49487
|
+
if (event.type === "sound") play(event.key, 0.9);
|
|
49488
|
+
o.onEvent?.(event);
|
|
49489
|
+
}
|
|
49490
|
+
};
|
|
48679
49491
|
const controls = createVehicleControls({
|
|
49492
|
+
canCrank: systems.canCrank,
|
|
49493
|
+
onCrank: systems.crank,
|
|
49494
|
+
powerLimit: systems.powerLimit,
|
|
48680
49495
|
gears: spec.gears?.length ?? 5,
|
|
48681
49496
|
fourWheelDrive: !!o.subject.body.fourWheelDrive,
|
|
48682
49497
|
fogLamps: lamps.has.fog,
|
|
49498
|
+
clutchPedal: true,
|
|
49499
|
+
radioTracks: RADIO_TRACKS.length,
|
|
48683
49500
|
onEvent: (event) => {
|
|
48684
49501
|
if (event.type === "command") {
|
|
48685
|
-
if (event.command === "ignition" && event.state.ignition && sounds.starter) play(sounds.starter);
|
|
48686
49502
|
if (event.command === "ignition" && !event.state.ignition) driver.state.engineOn = false;
|
|
48687
49503
|
if (event.command === "alarm" && event.state.alarm === "armed") play(sounds.chirp);
|
|
48688
49504
|
if (event.command === "alarm") alarmAgain = 0;
|
|
48689
|
-
if (event.command === "radio" || event.command === "radio_source"
|
|
49505
|
+
if (event.command === "radio" || event.command === "radio_source" || event.command === "radio_track") {
|
|
49506
|
+
radioAgain = 0;
|
|
49507
|
+
bar = 0;
|
|
49508
|
+
}
|
|
48690
49509
|
if (event.command === "exit") exitAsked = true;
|
|
48691
49510
|
}
|
|
48692
49511
|
o.onEvent?.(event);
|
|
@@ -48694,7 +49513,20 @@ var GameVehiclesThree = (() => {
|
|
|
48694
49513
|
});
|
|
48695
49514
|
driver.state.engineOn = false;
|
|
48696
49515
|
const target = typeof window !== "undefined" ? window : null;
|
|
49516
|
+
const bodyKey = (e) => {
|
|
49517
|
+
if (!body) return false;
|
|
49518
|
+
if (e.code === LOCK_KEY) bodyEvents(body.lock(!body.locked));
|
|
49519
|
+
else if (e.shiftKey && e.code === "Digit5") body.toggleSunroof();
|
|
49520
|
+
else if (e.shiftKey && WINDOW_KEYS[e.code]) body.toggleWindow(WINDOW_KEYS[e.code]);
|
|
49521
|
+
else if (!e.shiftKey && BODY_KEYS[e.code]) bodyEvents(body.toggle(BODY_KEYS[e.code]));
|
|
49522
|
+
else return false;
|
|
49523
|
+
return true;
|
|
49524
|
+
};
|
|
48697
49525
|
const down = (e) => {
|
|
49526
|
+
if (!e.repeat && bodyKey(e)) {
|
|
49527
|
+
e.stopImmediatePropagation();
|
|
49528
|
+
return;
|
|
49529
|
+
}
|
|
48698
49530
|
if (!controls.key(e.code, true)) return;
|
|
48699
49531
|
e.stopImmediatePropagation();
|
|
48700
49532
|
if (e.code.startsWith("Arrow") || e.code === "Space") e.preventDefault();
|
|
@@ -48706,9 +49538,13 @@ var GameVehiclesThree = (() => {
|
|
|
48706
49538
|
target?.addEventListener("keydown", down, true);
|
|
48707
49539
|
target?.addEventListener("keyup", up, true);
|
|
48708
49540
|
target?.addEventListener("blur", blur);
|
|
48709
|
-
|
|
49541
|
+
const cockpit = {
|
|
49542
|
+
radiator: 1,
|
|
48710
49543
|
driver,
|
|
48711
49544
|
controls,
|
|
49545
|
+
systems,
|
|
49546
|
+
body,
|
|
49547
|
+
destructible,
|
|
48712
49548
|
lamps,
|
|
48713
49549
|
dashboard,
|
|
48714
49550
|
get throttle() {
|
|
@@ -48717,11 +49553,16 @@ var GameVehiclesThree = (() => {
|
|
|
48717
49553
|
step(dt) {
|
|
48718
49554
|
const input = controls.input(dt, driver);
|
|
48719
49555
|
gas = input.throttle;
|
|
48720
|
-
|
|
49556
|
+
if (input.start && sounds.starter) play(sounds.starter);
|
|
49557
|
+
const engine = driver.step(input, dt).events;
|
|
48721
49558
|
controls.after(driver, dt);
|
|
48722
49559
|
const s = controls.state;
|
|
49560
|
+
const report = [...engine.filter((e) => e.type !== "shift"), ...systems.step({ driver, controls: s, throttle: input.throttle, dt, radiator: cockpit.radiator })];
|
|
49561
|
+
for (const event of report) o.onEvent?.(event);
|
|
49562
|
+
const powered = driver.state.engineOn || systems.state.charge > 0;
|
|
49563
|
+
const high = s.lamps.mode === "high" || s.lamps.flash;
|
|
48723
49564
|
lamps.set({
|
|
48724
|
-
mode: s.lamps.mode,
|
|
49565
|
+
mode: !powered ? "off" : s.lamps.flash ? "high" : s.lamps.mode,
|
|
48725
49566
|
fog: s.lamps.fog,
|
|
48726
49567
|
interior: s.lamps.interior,
|
|
48727
49568
|
brake: s.brakeLights,
|
|
@@ -48738,7 +49579,14 @@ var GameVehiclesThree = (() => {
|
|
|
48738
49579
|
engineOn: driver.state.engineOn,
|
|
48739
49580
|
left: s.blinkOn && (s.indicator === "left" || s.indicator === "hazard"),
|
|
48740
49581
|
right: s.blinkOn && (s.indicator === "right" || s.indicator === "hazard"),
|
|
48741
|
-
highBeam:
|
|
49582
|
+
highBeam: high,
|
|
49583
|
+
fuel: driver.state.fuel / spec.tank.capacity,
|
|
49584
|
+
temperature: systems.state.temperature,
|
|
49585
|
+
cruise: s.cruise.on,
|
|
49586
|
+
profile: s.profile,
|
|
49587
|
+
tractionOff: !s.tractionControl,
|
|
49588
|
+
absOff: !s.abs,
|
|
49589
|
+
charging: systems.state.netW >= 0,
|
|
48742
49590
|
lowBeam: s.lamps.mode === "low" || s.lamps.mode === "position",
|
|
48743
49591
|
fog: s.lamps.fog,
|
|
48744
49592
|
parkingBrake: s.parkingBrake,
|
|
@@ -48747,7 +49595,19 @@ var GameVehiclesThree = (() => {
|
|
|
48747
49595
|
},
|
|
48748
49596
|
dt
|
|
48749
49597
|
);
|
|
49598
|
+
if (body) bodyEvents(body.update(dt, s.washer ? 1.2 : WIPE_RATE[s.wipers] ?? 0));
|
|
48750
49599
|
if (s.tick) play(sounds.blinker, 0.8);
|
|
49600
|
+
const near = o.obstacles?.() ?? [];
|
|
49601
|
+
if (s.ignition && near.length && Math.abs(driver.state.u) < 3) {
|
|
49602
|
+
const g = o.built.group;
|
|
49603
|
+
const reversing = driver.state.gear < 0 || driver.state.u < -0.05;
|
|
49604
|
+
const distance = bumperDistance({ x: g.position.x, z: g.position.z, heading: [Math.sin(g.rotation.y), Math.cos(g.rotation.y)], length: o.built.length, width: o.built.width, forward: !reversing, obstacles: near });
|
|
49605
|
+
const every = parkingBeepInterval(distance);
|
|
49606
|
+
if (every != null && (beepAgain -= dt) <= 0) {
|
|
49607
|
+
play(sounds.beep, 0.7);
|
|
49608
|
+
beepAgain = every === 0 ? 0.09 : every;
|
|
49609
|
+
}
|
|
49610
|
+
}
|
|
48751
49611
|
if (s.horn && (hornAgain -= dt) <= 0) {
|
|
48752
49612
|
play(sounds.horn);
|
|
48753
49613
|
hornAgain = 0.5;
|
|
@@ -48756,9 +49616,9 @@ var GameVehiclesThree = (() => {
|
|
|
48756
49616
|
play(sounds.alarm);
|
|
48757
49617
|
alarmAgain = 2.9;
|
|
48758
49618
|
}
|
|
48759
|
-
if (s.wipers !== "off" && (wipeAgain -= dt) <= 0) {
|
|
49619
|
+
if ((s.wipers !== "off" || s.washer) && (wipeAgain -= dt) <= 0) {
|
|
48760
49620
|
play(sounds.wiper, 0.7);
|
|
48761
|
-
wipeAgain = s.wipers === "fast" ? 0.6 : 1.4;
|
|
49621
|
+
wipeAgain = s.washer || s.wipers === "fast" ? 0.6 : s.wipers === "slow" ? 1.4 : 4;
|
|
48762
49622
|
}
|
|
48763
49623
|
const kmh2 = Math.abs(driver.state.u) * 3.6;
|
|
48764
49624
|
if (!s.seatbelt && s.ignition && kmh2 > 10 && (chimeAgain -= dt) <= 0) {
|
|
@@ -48766,8 +49626,13 @@ var GameVehiclesThree = (() => {
|
|
|
48766
49626
|
chimeAgain = 6;
|
|
48767
49627
|
}
|
|
48768
49628
|
if (s.radio.on && (radioAgain -= dt) <= 0) {
|
|
48769
|
-
|
|
48770
|
-
|
|
49629
|
+
const song = RADIO_TRACKS[s.radio.track % RADIO_TRACKS.length];
|
|
49630
|
+
if (song) {
|
|
49631
|
+
play(song.bars[bar % song.bars.length], s.radio.source === "tape" ? 0.8 : 0.7);
|
|
49632
|
+
bar++;
|
|
49633
|
+
}
|
|
49634
|
+
if (s.radio.source === "radio") play(sounds.radio, 0.12);
|
|
49635
|
+
radioAgain = song?.barSeconds ?? 2;
|
|
48771
49636
|
}
|
|
48772
49637
|
if (exitAsked) {
|
|
48773
49638
|
exitAsked = false;
|
|
@@ -48781,10 +49646,149 @@ var GameVehiclesThree = (() => {
|
|
|
48781
49646
|
controls.release();
|
|
48782
49647
|
lamps.dispose();
|
|
48783
49648
|
dashboard?.dispose();
|
|
49649
|
+
body?.dispose();
|
|
49650
|
+
destructible?.dispose?.();
|
|
49651
|
+
}
|
|
49652
|
+
};
|
|
49653
|
+
return cockpit;
|
|
49654
|
+
}
|
|
49655
|
+
|
|
49656
|
+
// src/wheel-roll.ts
|
|
49657
|
+
var DEFAULT_RADIUS = 0.32;
|
|
49658
|
+
function createWheelRoll(THREE, built2) {
|
|
49659
|
+
const wheels = (built2.context?.wheels ?? []).map((wheel) => ({
|
|
49660
|
+
wheel,
|
|
49661
|
+
rest: wheel.quaternion.clone(),
|
|
49662
|
+
radius: Number(wheel.userData.r) || DEFAULT_RADIUS,
|
|
49663
|
+
// in the kit's frame the front is +x: the wheels ahead of the middle steer
|
|
49664
|
+
front: wheel.position.x > 0,
|
|
49665
|
+
angle: 0
|
|
49666
|
+
}));
|
|
49667
|
+
const axle = new THREE.Vector3(0, 0, 1);
|
|
49668
|
+
const up = new THREE.Vector3(0, 1, 0);
|
|
49669
|
+
const spin = new THREE.Quaternion();
|
|
49670
|
+
const steering = new THREE.Quaternion();
|
|
49671
|
+
return {
|
|
49672
|
+
count: wheels.length,
|
|
49673
|
+
roll(distance, steer) {
|
|
49674
|
+
for (const w of wheels) {
|
|
49675
|
+
w.angle = (w.angle - distance / w.radius) % (Math.PI * 2);
|
|
49676
|
+
spin.setFromAxisAngle(axle, w.angle);
|
|
49677
|
+
steering.setFromAxisAngle(up, w.front ? steer : 0);
|
|
49678
|
+
w.wheel.quaternion.copy(w.rest).premultiply(spin).premultiply(steering);
|
|
49679
|
+
}
|
|
49680
|
+
},
|
|
49681
|
+
dispose() {
|
|
49682
|
+
for (const w of wheels) w.wheel.quaternion.copy(w.rest);
|
|
48784
49683
|
}
|
|
48785
49684
|
};
|
|
48786
49685
|
}
|
|
48787
49686
|
|
|
49687
|
+
// src/test-area/proving/crash.ts
|
|
49688
|
+
var GLASS_BLOW = 6e3;
|
|
49689
|
+
function createProvingCrash(host, occupant) {
|
|
49690
|
+
const thrown = [];
|
|
49691
|
+
const breakGlass = (destructible, exit, forward) => {
|
|
49692
|
+
if (!destructible) return;
|
|
49693
|
+
const want = exit === "windshield" ? "windshield" : exit === "rear_window" ? "rear" : exit.startsWith("left") ? "left" : "right";
|
|
49694
|
+
const pane = destructible.describe().parts.find((p) => p.id.includes(exit === "windshield" || exit === "rear_window" ? want : "window") && (exit === "windshield" || exit === "rear_window" || p.id.includes(want)));
|
|
49695
|
+
if (!pane) return;
|
|
49696
|
+
destructible.hit({ type: "blunt", partId: pane.id, point: destructible.partWorldCenter(pane.id), direction: forward, energy: GLASS_BLOW, radius: 0.35, source: "occupant" });
|
|
49697
|
+
};
|
|
49698
|
+
return {
|
|
49699
|
+
crash({ car, u, w, belted, destructible }) {
|
|
49700
|
+
const ejection = ejectionOf({ before: { u, w }, after: { u: 0, w: 0 } }, belted);
|
|
49701
|
+
if (!ejection) return null;
|
|
49702
|
+
const s = Math.sin(car.rotationY);
|
|
49703
|
+
const c = Math.cos(car.rotationY);
|
|
49704
|
+
const forward = [s, 0, c];
|
|
49705
|
+
const right = [-c, 0, s];
|
|
49706
|
+
breakGlass(destructible, ejection.exit, forward);
|
|
49707
|
+
const [vf, vr, vu] = ejection.velocity;
|
|
49708
|
+
const start2 = [car.position.x + forward[0] * 1.2, 1.1, car.position.z + forward[2] * 1.2];
|
|
49709
|
+
const placed = occupant ? host.addObject?.(occupant, { position: start2, rotationY: car.rotationY }) : null;
|
|
49710
|
+
if (placed) {
|
|
49711
|
+
launchBody(placed.root, [forward[0] * vf + right[0] * vr, vu, forward[2] * vf + right[2] * vr]);
|
|
49712
|
+
thrown.push(placed.remove);
|
|
49713
|
+
}
|
|
49714
|
+
return ejection;
|
|
49715
|
+
},
|
|
49716
|
+
dispose() {
|
|
49717
|
+
for (const remove of thrown.splice(0)) remove();
|
|
49718
|
+
}
|
|
49719
|
+
};
|
|
49720
|
+
}
|
|
49721
|
+
|
|
49722
|
+
// src/test-area/proving/systems-text.ts
|
|
49723
|
+
var SYSTEMS_TEXT = {
|
|
49724
|
+
"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",
|
|
49726
|
+
profile: "Modo de condu\xE7\xE3o",
|
|
49727
|
+
profiles: { eco: "econ\xF4mico", normal: "normal", sport: "esporte" },
|
|
49728
|
+
traction: "Controle de tra\xE7\xE3o",
|
|
49729
|
+
abs: "ABS",
|
|
49730
|
+
cruise: "Piloto autom\xE1tico",
|
|
49731
|
+
cruiseSet: "Piloto autom\xE1tico: segurando {0} km/h",
|
|
49732
|
+
climate: "Ar-condicionado",
|
|
49733
|
+
demist: "Desemba\xE7ador",
|
|
49734
|
+
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" },
|
|
49736
|
+
events: {
|
|
49737
|
+
stall: "O motor morreu",
|
|
49738
|
+
out_of_fuel: "Acabou o combust\xEDvel",
|
|
49739
|
+
bogged: "Atolou",
|
|
49740
|
+
aquaplaning: "Aquaplanagem",
|
|
49741
|
+
battery_flat: "A bateria descarregou",
|
|
49742
|
+
overheating: "Motor superaquecendo: perdendo pot\xEAncia",
|
|
49743
|
+
seized: "O motor fundiu de tanto esquentar",
|
|
49744
|
+
spare_fitted: "Estepe colocado",
|
|
49745
|
+
no_spare: "N\xE3o h\xE1 estepe",
|
|
49746
|
+
cruise_cancelled: "Piloto autom\xE1tico desligado"
|
|
49747
|
+
},
|
|
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)" },
|
|
49749
|
+
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
|
+
track: "faixa {0}",
|
|
49751
|
+
adjust: { seat_forward: "Banco: frente/tr\xE1s (m)", seat_height: "Banco: altura (m)", mirror_left: "Retrovisor esquerdo: \xE2ngulo", mirror_right: "Retrovisor direito: \xE2ngulo" },
|
|
49752
|
+
crash: { mild: "Batida a {0} km/h: fraca demais para lan\xE7ar quem est\xE1 sem cinto", stayed: "Batida a {0} km/h: o cinto segurou o motorista", ejected: "Batida a {0} km/h sem cinto: o motorista saiu pelo {1}", exits: { windshield: "para-brisa", left_window: "vidro esquerdo", right_window: "vidro direito", rear_window: "vidro traseiro" } },
|
|
49753
|
+
bodyKeys: "1 a 4 portas \xB7 5 cap\xF4 \xB7 6 porta-malas \xB7 Shift+1 a 4 vidros \xB7 Shift+5 teto solar \xB7 V trava as portas",
|
|
49754
|
+
remote: { locked: "Travado pelo controle: alarme armado", unlocked: "Destravado pelo controle", forced: "Porta for\xE7ada" },
|
|
49755
|
+
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
|
+
},
|
|
49757
|
+
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",
|
|
49759
|
+
profile: "Drive profile",
|
|
49760
|
+
profiles: { eco: "eco", normal: "normal", sport: "sport" },
|
|
49761
|
+
traction: "Traction control",
|
|
49762
|
+
abs: "ABS",
|
|
49763
|
+
cruise: "Cruise control",
|
|
49764
|
+
cruiseSet: "Cruise control: holding {0} km/h",
|
|
49765
|
+
climate: "Air conditioning",
|
|
49766
|
+
demist: "Demister",
|
|
49767
|
+
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" },
|
|
49769
|
+
events: {
|
|
49770
|
+
stall: "The engine stalled",
|
|
49771
|
+
out_of_fuel: "Out of fuel",
|
|
49772
|
+
bogged: "Bogged down",
|
|
49773
|
+
aquaplaning: "Aquaplaning",
|
|
49774
|
+
battery_flat: "The battery went flat",
|
|
49775
|
+
overheating: "Engine overheating: losing power",
|
|
49776
|
+
seized: "The engine seized from the heat",
|
|
49777
|
+
spare_fitted: "Spare tyre fitted",
|
|
49778
|
+
no_spare: "No spare tyre left",
|
|
49779
|
+
cruise_cancelled: "Cruise control off"
|
|
49780
|
+
},
|
|
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)" },
|
|
49782
|
+
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
|
+
track: "track {0}",
|
|
49784
|
+
adjust: { seat_forward: "Seat: forward/back (m)", seat_height: "Seat: height (m)", mirror_left: "Left mirror: angle", mirror_right: "Right mirror: angle" },
|
|
49785
|
+
crash: { mild: "Crash at {0} km/h: too mild to throw an unbelted occupant out", stayed: "Crash at {0} km/h: the belt held the driver", ejected: "Crash at {0} km/h without a belt: the driver went out through the {1}", exits: { windshield: "windshield", left_window: "left window", right_window: "right window", rear_window: "rear window" } },
|
|
49786
|
+
bodyKeys: "1 to 4 doors \xB7 5 hood \xB7 6 trunk \xB7 Shift+1 to 4 windows \xB7 Shift+5 sunroof \xB7 V locks the doors",
|
|
49787
|
+
remote: { locked: "Locked by the remote: alarm armed", unlocked: "Unlocked by the remote", forced: "Door forced" },
|
|
49788
|
+
done: { puncture: "Front left tyre punctured", refuel: "Tank full", drain_battery: "Battery almost flat", jump_start: "Battery charged", break_radiator: "Radiator punctured: the engine will heat up", empty_tank: "Tank on reserve" }
|
|
49789
|
+
}
|
|
49790
|
+
};
|
|
49791
|
+
|
|
48788
49792
|
// src/test-area/proving/text.ts
|
|
48789
49793
|
var PROVING_TEXT = {
|
|
48790
49794
|
"pt-BR": {
|
|
@@ -48929,9 +49933,11 @@ var GameVehiclesThree = (() => {
|
|
|
48929
49933
|
right: { x: 0.79, y: 0.72, width: 0.19, height: 0.13, rounded: 0.3 },
|
|
48930
49934
|
reverse: { x: 0.36, y: 0.13, width: 0.28, height: 0.18, rounded: 0.06 }
|
|
48931
49935
|
};
|
|
49936
|
+
var ADJUST_KEYS = { seat_forward: "seatForward", seat_height: "seatHeight", mirror_left: "mirrorLeft", mirror_right: "mirrorRight" };
|
|
48932
49937
|
function createProvingModule(options) {
|
|
48933
49938
|
const locale = options.locale ?? "pt-BR";
|
|
48934
49939
|
const text = PROVING_TEXT[locale] ?? PROVING_TEXT["pt-BR"];
|
|
49940
|
+
const sysText = SYSTEMS_TEXT[locale] ?? SYSTEMS_TEXT["pt-BR"];
|
|
48935
49941
|
const tests = options.tests ?? createProvingTests();
|
|
48936
49942
|
const vehicles = options.vehicles;
|
|
48937
49943
|
const sounds = { ...defaultSoundIds, ...options.sounds };
|
|
@@ -48948,6 +49954,15 @@ var GameVehiclesThree = (() => {
|
|
|
48948
49954
|
let run = null;
|
|
48949
49955
|
let parking = null;
|
|
48950
49956
|
let driving = null;
|
|
49957
|
+
let crashes = null;
|
|
49958
|
+
let wheels = null;
|
|
49959
|
+
let lastAt = null;
|
|
49960
|
+
let parked = null;
|
|
49961
|
+
const adjust = { seatForward: 0, seatHeight: 0, mirrorLeft: 0, mirrorRight: 0 };
|
|
49962
|
+
const aimed = (pose2) => {
|
|
49963
|
+
const turn = pose2.id === "left" ? adjust.mirrorLeft : pose2.id === "right" ? -adjust.mirrorRight : 0;
|
|
49964
|
+
return turn ? { ...pose2, look: [pose2.look[0] + turn, pose2.look[1], pose2.look[2]] } : pose2;
|
|
49965
|
+
};
|
|
48951
49966
|
let gearbox = "automatic";
|
|
48952
49967
|
let lastGear = null;
|
|
48953
49968
|
let driveClock = 0;
|
|
@@ -49109,6 +50124,8 @@ var GameVehiclesThree = (() => {
|
|
|
49109
50124
|
};
|
|
49110
50125
|
const removeCar = () => {
|
|
49111
50126
|
if (!car) return;
|
|
50127
|
+
wheels = null;
|
|
50128
|
+
lastAt = null;
|
|
49112
50129
|
discardObject3D(car.built.group);
|
|
49113
50130
|
car = null;
|
|
49114
50131
|
};
|
|
@@ -49122,6 +50139,7 @@ var GameVehiclesThree = (() => {
|
|
|
49122
50139
|
built2.group.add(guides);
|
|
49123
50140
|
host.scene.add(built2.group);
|
|
49124
50141
|
car = { built: built2, guides, subject };
|
|
50142
|
+
wheels = createWheelRoll(three, built2);
|
|
49125
50143
|
pose({ x: 0, z: TRACK.start, yaw: 0, pitch: 0, roll: 0, height: 0 }, 0);
|
|
49126
50144
|
rig.vehicle?.reset();
|
|
49127
50145
|
drawBoard();
|
|
@@ -49172,11 +50190,18 @@ var GameVehiclesThree = (() => {
|
|
|
49172
50190
|
car.built.group.position.set(TRACK.x0 + wrapped, 0, TRACK.z + s.z);
|
|
49173
50191
|
car.built.group.rotation.set(-s.pitch, s.yaw + Math.PI / 2, s.roll, "YXZ");
|
|
49174
50192
|
bendGuides(steer);
|
|
50193
|
+
if (lastAt) {
|
|
50194
|
+
const along = (s.x - lastAt.x) * Math.cos(s.yaw) - (s.z - lastAt.z) * Math.sin(s.yaw);
|
|
50195
|
+
if (Math.abs(along) < 5) wheels?.roll(along, steer);
|
|
50196
|
+
}
|
|
50197
|
+
lastAt = { x: s.x, z: s.z };
|
|
49175
50198
|
};
|
|
49176
50199
|
const frameOf = (speed) => {
|
|
49177
50200
|
if (!car) return null;
|
|
49178
50201
|
const g = car.built.group;
|
|
49179
|
-
|
|
50202
|
+
const size = { length: car.built.length, width: car.built.width, height: car.built.height };
|
|
50203
|
+
const [ex, ey, ez] = car.built.driverEye ?? defaultEye(size);
|
|
50204
|
+
return { x: g.position.x, y: g.position.y, z: g.position.z, yaw: g.rotation.y, pitch: -g.rotation.x, roll: g.rotation.z, speed, ...size, eye: [ex, ey + adjust.seatHeight, ez + adjust.seatForward] };
|
|
49180
50205
|
};
|
|
49181
50206
|
const applyCamera = () => {
|
|
49182
50207
|
if (!host?.setViewCamera) return;
|
|
@@ -49265,19 +50290,26 @@ var GameVehiclesThree = (() => {
|
|
|
49265
50290
|
built: car.built,
|
|
49266
50291
|
subject: car.subject,
|
|
49267
50292
|
place: [0, 0, 0],
|
|
50293
|
+
kit: kitFor(three),
|
|
50294
|
+
obstacles: () => parked ? [[parked.root.position.x, parked.root.position.z]] : [],
|
|
49268
50295
|
gauge: kitFor(three).materials?.gauge,
|
|
49269
50296
|
needle: kitFor(three).materials?.amber,
|
|
49270
50297
|
// the engine's own sound turns the key (starter, catch, idle by RPM)
|
|
49271
50298
|
sounds: { starter: "" },
|
|
49272
50299
|
onExit: () => stopDriving(),
|
|
49273
50300
|
onEvent: (event) => {
|
|
49274
|
-
if (event.type === "refused") return host?.log(text.cabin.refused[event.reason] ?? event.reason);
|
|
50301
|
+
if (event.type === "refused") return host?.log(text.cabin.refused[event.reason] ?? sysText.refused[event.reason] ?? event.reason);
|
|
50302
|
+
if (event.type === "sound") return;
|
|
50303
|
+
if (event.type !== "command") {
|
|
50304
|
+
if (event.type === "out_of_fuel" || event.type === "stall" || event.type === "seized") engine?.stop([car?.built.group.position.x ?? 0, 0.5, car?.built.group.position.z ?? 0]);
|
|
50305
|
+
return host?.log(sysText.events[event.type] ?? event.type, { vehicle: settings.vehicle, ...event }, "proving_system");
|
|
50306
|
+
}
|
|
49275
50307
|
const st = event.state;
|
|
49276
50308
|
const line = cabinLine(event.command, st);
|
|
49277
50309
|
if (line) host?.log(line);
|
|
49278
50310
|
if (event.command === "ignition" && car) {
|
|
49279
50311
|
const at = [car.built.group.position.x, 0.5, car.built.group.position.z];
|
|
49280
|
-
if (st.ignition) engine?.start(at);
|
|
50312
|
+
if (st.ignition && driving?.systems.canCrank() !== false) engine?.start(at);
|
|
49281
50313
|
else engine?.stop(at);
|
|
49282
50314
|
}
|
|
49283
50315
|
if (event.command === "gearbox") {
|
|
@@ -49296,7 +50328,7 @@ var GameVehiclesThree = (() => {
|
|
|
49296
50328
|
rig.vehicle?.reset();
|
|
49297
50329
|
stopEngine();
|
|
49298
50330
|
engine = createVehicleSound(host.audio, { sounds });
|
|
49299
|
-
host.bench?.sheet?.({ kicker: text.name, title: fillText(text.log.drive, name(settings.vehicle)), body: text.cabin.keys });
|
|
50331
|
+
host.bench?.sheet?.({ kicker: text.name, title: fillText(text.log.drive, name(settings.vehicle)), body: `${text.cabin.keys} \xB7 ${sysText.keys} \xB7 ${sysText.bodyKeys}` });
|
|
49300
50332
|
host.log(fillText(text.log.drive, name(settings.vehicle)));
|
|
49301
50333
|
};
|
|
49302
50334
|
const onOff = (on) => on ? text.cabin.on : text.cabin.off;
|
|
@@ -49325,19 +50357,109 @@ var GameVehiclesThree = (() => {
|
|
|
49325
50357
|
return `${c.alarm}: ${c.alarmStates[st.alarm]}`;
|
|
49326
50358
|
case "radio":
|
|
49327
50359
|
case "radio_source":
|
|
49328
|
-
|
|
50360
|
+
case "radio_track":
|
|
50361
|
+
return `${c.radio}: ${st.radio.on ? `${c.sources[st.radio.source]} \xB7 ${fillText(sysText.track, st.radio.track + 1)}` : c.off}`;
|
|
49329
50362
|
case "indicator_left":
|
|
49330
50363
|
case "indicator_right":
|
|
49331
50364
|
case "hazard":
|
|
49332
50365
|
return `${c.indicator}: ${c.indicators[st.indicator]}`;
|
|
49333
50366
|
case "wipers":
|
|
49334
|
-
return `${c.wipers}: ${
|
|
50367
|
+
return `${c.wipers}: ${sysText.wiperModes[st.wipers]}`;
|
|
50368
|
+
case "drive_profile":
|
|
50369
|
+
return `${sysText.profile}: ${sysText.profiles[st.profile]}`;
|
|
50370
|
+
case "traction_control":
|
|
50371
|
+
return `${sysText.traction}: ${onOff(st.tractionControl)}`;
|
|
50372
|
+
case "abs":
|
|
50373
|
+
return `${sysText.abs}: ${onOff(st.abs)}`;
|
|
50374
|
+
case "cruise":
|
|
50375
|
+
return st.cruise.on ? fillText(sysText.cruiseSet, Math.round(st.cruise.speed * 3.6)) : `${sysText.cruise}: ${c.off}`;
|
|
50376
|
+
case "climate":
|
|
50377
|
+
return `${sysText.climate}: ${onOff(st.climate.on)}`;
|
|
50378
|
+
case "demist":
|
|
50379
|
+
return `${sysText.demist}: ${onOff(st.climate.demist)}`;
|
|
49335
50380
|
case "seatbelt":
|
|
49336
50381
|
return `${c.seatbelt}: ${onOff(st.seatbelt)}`;
|
|
49337
50382
|
default:
|
|
49338
50383
|
return null;
|
|
49339
50384
|
}
|
|
49340
50385
|
};
|
|
50386
|
+
const systemsAction = (id) => {
|
|
50387
|
+
if (!driving) startDriving();
|
|
50388
|
+
const cockpit = driving;
|
|
50389
|
+
if (!cockpit) return;
|
|
50390
|
+
const d = cockpit.driver;
|
|
50391
|
+
const done = (key) => host?.log(sysText.done[key], { vehicle: settings.vehicle, action: key }, "proving_system");
|
|
50392
|
+
switch (id) {
|
|
50393
|
+
case "puncture": {
|
|
50394
|
+
const tyres = d.spec.wheels.map((_, i) => d.condition.tyres?.[i] ?? 1);
|
|
50395
|
+
tyres[0] = 0;
|
|
50396
|
+
d.condition = { ...d.condition, tyres };
|
|
50397
|
+
return done("puncture");
|
|
50398
|
+
}
|
|
50399
|
+
case "fit_spare": {
|
|
50400
|
+
const flat = d.spec.wheels.findIndex((_, i) => (d.condition.tyres?.[i] ?? 1) < 0.2);
|
|
50401
|
+
const event = cockpit.systems.fitSpare(d, Math.max(0, flat));
|
|
50402
|
+
host?.log(sysText.events[event.type], { vehicle: settings.vehicle, ...event }, "proving_system");
|
|
50403
|
+
return;
|
|
50404
|
+
}
|
|
50405
|
+
case "refuel":
|
|
50406
|
+
d.refuel(d.spec.tank.capacity);
|
|
50407
|
+
return done("refuel");
|
|
50408
|
+
case "empty_tank":
|
|
50409
|
+
d.state.fuel = Math.min(d.state.fuel, d.spec.tank.capacity * 0.04);
|
|
50410
|
+
return done("empty_tank");
|
|
50411
|
+
case "drain_battery":
|
|
50412
|
+
cockpit.systems.charge(-(cockpit.systems.state.charge - 0.15));
|
|
50413
|
+
return done("drain_battery");
|
|
50414
|
+
case "jump_start":
|
|
50415
|
+
cockpit.systems.charge(1);
|
|
50416
|
+
return done("jump_start");
|
|
50417
|
+
case "break_radiator":
|
|
50418
|
+
cockpit.radiator = 0.05;
|
|
50419
|
+
return done("break_radiator");
|
|
50420
|
+
case "remote_lock":
|
|
50421
|
+
case "remote_unlock": {
|
|
50422
|
+
const lock = id === "remote_lock";
|
|
50423
|
+
cockpit.body?.lock(lock);
|
|
50424
|
+
cockpit.controls.state.alarm = lock ? "armed" : "off";
|
|
50425
|
+
host?.audio?.play?.({ sound: "alarm_chirp", position: [car?.built.group.position.x ?? 0, 1, car?.built.group.position.z ?? 0] });
|
|
50426
|
+
host?.log(sysText.remote[lock ? "locked" : "unlocked"], { vehicle: settings.vehicle, locked: lock }, "proving_system");
|
|
50427
|
+
return;
|
|
50428
|
+
}
|
|
50429
|
+
case "crash_wall": {
|
|
50430
|
+
const g = car?.built.group;
|
|
50431
|
+
if (!g || !host) return;
|
|
50432
|
+
crashes ?? (crashes = createProvingCrash(host, options.occupant));
|
|
50433
|
+
const speed = d.state.u;
|
|
50434
|
+
const ejection = crashes.crash({ car: { position: g.position, rotationY: g.rotation.y }, u: d.state.u, w: d.state.w, belted: cockpit.controls.state.seatbelt, destructible: cockpit.destructible });
|
|
50435
|
+
d.state.u = d.state.w = d.state.yawRate = 0;
|
|
50436
|
+
const kmh2 = Math.round(Math.abs(speed) * 3.6);
|
|
50437
|
+
const belted = cockpit.controls.state.seatbelt;
|
|
50438
|
+
host.log(ejection ? fillText(sysText.crash.ejected, kmh2, sysText.crash.exits[ejection.exit]) : fillText(belted ? sysText.crash.stayed : sysText.crash.mild, kmh2), { vehicle: settings.vehicle, kmh: kmh2, belted: cockpit.controls.state.seatbelt, ejection }, "proving_crash");
|
|
50439
|
+
return;
|
|
50440
|
+
}
|
|
50441
|
+
case "park_behind": {
|
|
50442
|
+
const g = car?.built.group;
|
|
50443
|
+
if (!g || !host) return;
|
|
50444
|
+
parked?.remove();
|
|
50445
|
+
const back = (car?.built.length ?? 4.5) / 2 + 3 + 2.3;
|
|
50446
|
+
const at = [g.position.x - Math.sin(g.rotation.y) * back, 0, g.position.z - Math.cos(g.rotation.y) * back];
|
|
50447
|
+
const placed = host.addObject?.(options.parkedCar ?? "sedan", { position: at, rotationY: g.rotation.y });
|
|
50448
|
+
parked = placed ? { root: placed.root, remove: placed.remove } : null;
|
|
50449
|
+
host.log(placed ? sysText.parking.placed : sysText.parking.none, { vehicle: settings.vehicle }, "proving_system");
|
|
50450
|
+
return;
|
|
50451
|
+
}
|
|
50452
|
+
case "force_door": {
|
|
50453
|
+
const body = cockpit.body;
|
|
50454
|
+
if (!body) return;
|
|
50455
|
+
if (body.locked) body.lock(false);
|
|
50456
|
+
body.toggle("door_front_left");
|
|
50457
|
+
if (cockpit.controls.state.alarm === "armed") cockpit.controls.state.alarm = "ringing";
|
|
50458
|
+
host?.log(sysText.remote.forced, { vehicle: settings.vehicle, alarm: cockpit.controls.state.alarm }, "proving_system");
|
|
50459
|
+
return;
|
|
50460
|
+
}
|
|
50461
|
+
}
|
|
50462
|
+
};
|
|
49341
50463
|
const gearName = (gear) => gear < 0 ? "R" : gear === 0 ? "N" : String(gear);
|
|
49342
50464
|
const onChange = (change) => {
|
|
49343
50465
|
if (change.kind === "layer") {
|
|
@@ -49346,6 +50468,7 @@ var GameVehiclesThree = (() => {
|
|
|
49346
50468
|
}
|
|
49347
50469
|
if (change.kind === "action") {
|
|
49348
50470
|
if (change.id === "drive") return driving ? stopDriving() : startDriving();
|
|
50471
|
+
if (change.id in sysText.actions) return systemsAction(change.id);
|
|
49349
50472
|
if (change.id === "run_test" || change.id === "run_all" || change.id === "reverse_park") stopDriving();
|
|
49350
50473
|
if (change.id === "run_test") {
|
|
49351
50474
|
queue = [];
|
|
@@ -49392,6 +50515,12 @@ var GameVehiclesThree = (() => {
|
|
|
49392
50515
|
settings.camera = String(change.value);
|
|
49393
50516
|
applyCamera();
|
|
49394
50517
|
break;
|
|
50518
|
+
case "seat_forward":
|
|
50519
|
+
case "seat_height":
|
|
50520
|
+
case "mirror_left":
|
|
50521
|
+
case "mirror_right":
|
|
50522
|
+
adjust[ADJUST_KEYS[change.id]] = Number(change.value);
|
|
50523
|
+
break;
|
|
49395
50524
|
case "time_scale":
|
|
49396
50525
|
settings.timeScale = Number(change.value);
|
|
49397
50526
|
break;
|
|
@@ -49441,7 +50570,7 @@ var GameVehiclesThree = (() => {
|
|
|
49441
50570
|
if (car) engine?.update({ dt, position: [car.built.group.position.x, 0.5, car.built.group.position.z], speed, throttle: run ? 1 : driving?.throttle ?? 0, rpm: driving ? driving.driver.state.rpm : void 0 });
|
|
49442
50571
|
const f = frameOf(speed);
|
|
49443
50572
|
if (f && rig.vehicle && settings.camera !== "room") rig.vehicle.update(rig.camera, f, dt);
|
|
49444
|
-
if (f && rig.vehicle) for (const m of rig.mirrors) rig.vehicle.placeMirror(m.camera, m.pose, f);
|
|
50573
|
+
if (f && rig.vehicle) for (const m of rig.mirrors) rig.vehicle.placeMirror(m.camera, aimed(m.pose), f);
|
|
49445
50574
|
void steer;
|
|
49446
50575
|
const key = `${host.bench?.layer("mirrors")}|${host.bench?.layer("reverse_camera")}`;
|
|
49447
50576
|
if (key !== mirrorKey) {
|
|
@@ -49460,6 +50589,10 @@ var GameVehiclesThree = (() => {
|
|
|
49460
50589
|
const speedNow = () => Math.abs(run?.driver.state.u ?? driving?.driver.state.u ?? parking?.driver.state.u ?? 0) * 3.6;
|
|
49461
50590
|
const counts = (verdict) => certificateOf(settings.vehicle)?.results.filter((r) => r.verdict === verdict).length ?? 0;
|
|
49462
50591
|
const teardown = () => {
|
|
50592
|
+
crashes?.dispose();
|
|
50593
|
+
crashes = null;
|
|
50594
|
+
parked?.remove();
|
|
50595
|
+
parked = null;
|
|
49463
50596
|
stopDriving();
|
|
49464
50597
|
stopEngine();
|
|
49465
50598
|
for (const m of rig.mirrors) m.remove();
|
|
@@ -49490,9 +50623,14 @@ var GameVehiclesThree = (() => {
|
|
|
49490
50623
|
{ kind: "choice", id: "vehicle", name: text.controls.vehicle, hint: text.hints.vehicle, options: vehicles.map((id) => ({ id, name: name(id) })), default: settings.vehicle },
|
|
49491
50624
|
{ kind: "choice", id: "test", name: text.controls.test, hint: text.hints.test, options: measured.map((id) => ({ id, name: text.tests[id] ?? id })), default: settings.test },
|
|
49492
50625
|
{ kind: "choice", id: "camera", name: text.controls.camera, hint: text.hints.camera, options: ["room", "chase", "cockpit", "hood"].map((id) => ({ id, name: text.cameras[id] })), default: settings.camera },
|
|
50626
|
+
{ kind: "number", id: "seat_forward", name: sysText.adjust.seat_forward, min: -0.2, max: 0.2, step: 0.02, default: 0 },
|
|
50627
|
+
{ kind: "number", id: "seat_height", name: sysText.adjust.seat_height, min: -0.1, max: 0.1, step: 0.01, default: 0 },
|
|
50628
|
+
{ kind: "number", id: "mirror_left", name: sysText.adjust.mirror_left, min: -0.3, max: 0.3, step: 0.02, default: 0 },
|
|
50629
|
+
{ kind: "number", id: "mirror_right", name: sysText.adjust.mirror_right, min: -0.3, max: 0.3, step: 0.02, default: 0 },
|
|
49493
50630
|
{ kind: "number", id: "time_scale", name: text.controls.time_scale, hint: text.hints.time_scale, min: 1, max: 20, step: 1, default: settings.timeScale },
|
|
49494
50631
|
{ kind: "choice", id: "visual_check", name: text.controls.visual_check, hint: text.hints.visual_check, options: VISUAL_CHECKS.map((id) => ({ id, name: text.tests[id] ?? id })), default: settings.visual },
|
|
49495
50632
|
{ kind: "action", id: "drive", name: text.actions.drive },
|
|
50633
|
+
...Object.keys(sysText.actions).map((id) => ({ kind: "action", id, name: sysText.actions[id] })),
|
|
49496
50634
|
{ kind: "choice", id: "gearbox", name: text.controls.gearbox, hint: text.hints.gearbox, options: ["automatic", "manual"].map((id) => ({ id, name: text.gearbox[id] })), default: gearbox },
|
|
49497
50635
|
{ kind: "action", id: "run_test", name: text.actions.run_test },
|
|
49498
50636
|
{ kind: "action", id: "run_all", name: text.actions.run_all },
|
|
@@ -49526,6 +50664,8 @@ var GameVehiclesThree = (() => {
|
|
|
49526
50664
|
rig.vehicle = createVehicleCamera(three);
|
|
49527
50665
|
lent.audio?.register?.(LIBRARY_BANK);
|
|
49528
50666
|
lent.audio?.register?.(CABIN_BANK);
|
|
50667
|
+
lent.audio?.register?.(VEHICLE_SOUND_BANK);
|
|
50668
|
+
lent.audio?.register?.(RADIO_BANK);
|
|
49529
50669
|
const stopChange = lent.bench?.onChange(onChange);
|
|
49530
50670
|
const stopFrame = lent.onFrame(frame);
|
|
49531
50671
|
const stopClear = lent.onClear?.(() => {
|