@adatechnology/game-vehicles-three 0.6.0 → 0.6.2
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-4SUQMRS3.js → chunk-MRUPKE7J.js} +732 -23
- package/dist/chunk-MRUPKE7J.js.map +1 -0
- package/dist/index.d.ts +168 -3
- package/dist/index.global.js +1050 -26
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/{testing-gEnSqEF6.d.ts → testing-C-BgV7gj.d.ts} +40 -9
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +7 -7
- package/dist/chunk-4SUQMRS3.js.map +0 -1
package/dist/index.global.js
CHANGED
|
@@ -24,10 +24,12 @@ var GameVehiclesThree = (() => {
|
|
|
24
24
|
BIKE_ENGINE: () => BIKE_ENGINE,
|
|
25
25
|
CAR_ENGINE: () => CAR_ENGINE,
|
|
26
26
|
CRASH_SPEEDS: () => CRASH_SPEEDS,
|
|
27
|
+
DASHBOARD_LOOK: () => DASHBOARD_LOOK,
|
|
27
28
|
DEFAULT_TEST_VEHICLES: () => DEFAULT_TEST_VEHICLES,
|
|
28
29
|
DEFAULT_TEST_WRECKS: () => DEFAULT_TEST_WRECKS,
|
|
29
30
|
DEFAULT_VEHICLE_SOUND_KEYS: () => DEFAULT_VEHICLE_SOUND_KEYS,
|
|
30
31
|
ENGINE_PROFILES: () => ENGINE_PROFILES,
|
|
32
|
+
LAMP_RULES: () => LAMP_RULES,
|
|
31
33
|
LITE_CLASSES: () => LITE_CLASSES,
|
|
32
34
|
PAGE_ITEM_ALIASES: () => PAGE_ITEM_ALIASES,
|
|
33
35
|
PAGE_SCENARIO_ALIASES: () => PAGE_SCENARIO_ALIASES,
|
|
@@ -47,6 +49,8 @@ var GameVehiclesThree = (() => {
|
|
|
47
49
|
createCabinSmoke: () => createCabinSmoke,
|
|
48
50
|
createGearGuess: () => createGearGuess,
|
|
49
51
|
createProvingModule: () => createProvingModule,
|
|
52
|
+
createVehicleDashboard: () => createVehicleDashboard,
|
|
53
|
+
createVehicleLamps: () => createVehicleLamps,
|
|
50
54
|
createVehicleLod: () => createVehicleLod,
|
|
51
55
|
createVehicleSound: () => createVehicleSound,
|
|
52
56
|
createVehiclesTestModule: () => createVehiclesTestModule,
|
|
@@ -65,6 +69,7 @@ var GameVehiclesThree = (() => {
|
|
|
65
69
|
});
|
|
66
70
|
|
|
67
71
|
// ../game-contracts/dist/index.js
|
|
72
|
+
var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
|
|
68
73
|
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
69
74
|
var DEFAULT_IGNITION_RULES = {
|
|
70
75
|
fillCurve: [
|
|
@@ -6137,7 +6142,9 @@ var GameVehiclesThree = (() => {
|
|
|
6137
6142
|
function fogLamp(c, s, r) {
|
|
6138
6143
|
onSurf(c.cylinder(r * 1.4, r * 1.4, 0.014, LH, 0, 0, 0), s, 6e-3).castShadow = false;
|
|
6139
6144
|
onSurf(c.cylinder(r, r, 0.012, REFL, 0, 0, 0), s, 0.012).castShadow = false;
|
|
6140
|
-
onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016)
|
|
6145
|
+
const bulb = onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016);
|
|
6146
|
+
bulb.castShadow = false;
|
|
6147
|
+
(c.fogBulbs ?? (c.fogBulbs = [])).push(bulb);
|
|
6141
6148
|
}
|
|
6142
6149
|
function crease(c, I, sd, pts, o) {
|
|
6143
6150
|
o = o || {};
|
|
@@ -15139,7 +15146,9 @@ var GameVehiclesThree = (() => {
|
|
|
15139
15146
|
function fogLamp(c, s, r) {
|
|
15140
15147
|
onSurf(c.cylinder(r * 1.4, r * 1.4, 0.014, LH, 0, 0, 0), s, 6e-3).castShadow = false;
|
|
15141
15148
|
onSurf(c.cylinder(r, r, 0.012, REFL, 0, 0, 0), s, 0.012).castShadow = false;
|
|
15142
|
-
onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016)
|
|
15149
|
+
const bulb = onSurf(c.sphere(r * 0.45, MT.head, 0, 0, 0, 1, 0.5, 1), s, 0.016);
|
|
15150
|
+
bulb.castShadow = false;
|
|
15151
|
+
(c.fogBulbs ?? (c.fogBulbs = [])).push(bulb);
|
|
15143
15152
|
}
|
|
15144
15153
|
function crease(c, I, sd, pts, o) {
|
|
15145
15154
|
o = o || {};
|
|
@@ -22348,7 +22357,7 @@ var GameVehiclesThree = (() => {
|
|
|
22348
22357
|
const x = kit.profX(s.lower, s.bottomY + 0.14, true) + 0.09;
|
|
22349
22358
|
[1, -1].forEach(function(sd) {
|
|
22350
22359
|
c.roundBox(0.04, r * 2.6, r * 3.2, 0.015, MT.housing, x, y, sd * z);
|
|
22351
|
-
kit.headlight(c, {
|
|
22360
|
+
const lamp = kit.headlight(c, {
|
|
22352
22361
|
style: "round",
|
|
22353
22362
|
x: x + 0.01,
|
|
22354
22363
|
y,
|
|
@@ -22360,6 +22369,7 @@ var GameVehiclesThree = (() => {
|
|
|
22360
22369
|
label: sd > 0 ? trl("labels.right_fog_light") : trl("labels.left_fog_light"),
|
|
22361
22370
|
reach: 0.5
|
|
22362
22371
|
});
|
|
22372
|
+
lamp.fog = true;
|
|
22363
22373
|
});
|
|
22364
22374
|
}
|
|
22365
22375
|
function roofBars(c, z, h, r) {
|
|
@@ -27987,6 +27997,16 @@ var GameVehiclesThree = (() => {
|
|
|
27987
27997
|
});
|
|
27988
27998
|
return best;
|
|
27989
27999
|
}
|
|
28000
|
+
var SEATED_EYE = { up: 0.55, back: 0.28 };
|
|
28001
|
+
function eyeOf(THREE, c) {
|
|
28002
|
+
const tops = c.seatTops ?? [];
|
|
28003
|
+
if (!tops.length) return null;
|
|
28004
|
+
const points = tops.map((t) => c.vehicle.localToWorld(new THREE.Vector3(t.x, t.y, t.z)));
|
|
28005
|
+
const front = Math.max(...points.map((p) => p.z));
|
|
28006
|
+
const row = points.filter((p) => p.z > front - 0.25);
|
|
28007
|
+
const seat = row.reduce((a, b) => b.x > a.x ? b : a);
|
|
28008
|
+
return [+seat.x.toFixed(3), +(seat.y + SEATED_EYE.up).toFixed(3), +(seat.z - SEATED_EYE.back).toFixed(3)];
|
|
28009
|
+
}
|
|
27990
28010
|
function createVehiclesThree(THREE, options) {
|
|
27991
28011
|
const kit = options.kit;
|
|
27992
28012
|
const fleet = options.fleet ?? { colorFromSeed, fleetDims, paintPalettes, paletteOf };
|
|
@@ -28022,6 +28042,7 @@ var GameVehiclesThree = (() => {
|
|
|
28022
28042
|
markKitOrigin(group, { owner: "game-vehicles-three", kind: "vehicle", id: key });
|
|
28023
28043
|
const damageables = kit.damageables(c, pivotMatrix);
|
|
28024
28044
|
let pruned = 0;
|
|
28045
|
+
let driverEye = null;
|
|
28025
28046
|
if (quality === "high") {
|
|
28026
28047
|
const pivot = new THREE.Group();
|
|
28027
28048
|
pivot.name = "vehicle";
|
|
@@ -28043,6 +28064,7 @@ var GameVehiclesThree = (() => {
|
|
|
28043
28064
|
}
|
|
28044
28065
|
markDamageables(c, damageables);
|
|
28045
28066
|
group.updateMatrixWorld(true);
|
|
28067
|
+
driverEye = eyeOf(THREE, c);
|
|
28046
28068
|
} else {
|
|
28047
28069
|
const fusion = fuse(THREE, c, pivotMatrix, color2 ? new THREE.Color(color2) : null, primary, kit.lodHiddenMaterials());
|
|
28048
28070
|
for (const mesh2 of liteMeshes(THREE, fusion, liteMaterials(THREE, kit.studioEnvironment()))) group.add(mesh2);
|
|
@@ -28068,6 +28090,7 @@ var GameVehiclesThree = (() => {
|
|
|
28068
28090
|
pruned,
|
|
28069
28091
|
expected: fleetDims2(key),
|
|
28070
28092
|
context: quality === "high" ? c : null,
|
|
28093
|
+
driverEye,
|
|
28071
28094
|
dispose() {
|
|
28072
28095
|
group.traverse((m) => {
|
|
28073
28096
|
if (m.geometry) m.geometry.dispose();
|
|
@@ -44012,7 +44035,7 @@ var GameVehiclesThree = (() => {
|
|
|
44012
44035
|
};
|
|
44013
44036
|
}
|
|
44014
44037
|
|
|
44015
|
-
// ../game-audio/dist/chunk-
|
|
44038
|
+
// ../game-audio/dist/chunk-KBTUANNG.js
|
|
44016
44039
|
var DISTANCE_CURVES = {
|
|
44017
44040
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
44018
44041
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -44313,7 +44336,11 @@ var GameVehiclesThree = (() => {
|
|
|
44313
44336
|
["casing_drop_terra_pistol", 1],
|
|
44314
44337
|
["casing_drop_terra_rifle", 1],
|
|
44315
44338
|
["casing_drop_terra_shell", 1],
|
|
44316
|
-
["rocket_fire", 2]
|
|
44339
|
+
["rocket_fire", 2],
|
|
44340
|
+
["smg_45_auto", 2, "sfx_pistol"],
|
|
44341
|
+
["weapon_draw", 2],
|
|
44342
|
+
["suppressor_attach", 3],
|
|
44343
|
+
["suppressor_detach", 3]
|
|
44317
44344
|
]),
|
|
44318
44345
|
...entries("explosoes-fogo", [
|
|
44319
44346
|
["explosion_grenade", 1, "boom"],
|
|
@@ -44327,7 +44354,11 @@ var GameVehiclesThree = (() => {
|
|
|
44327
44354
|
["fire_loop_large", 1],
|
|
44328
44355
|
["fire_extinguish", 2, "hiss"],
|
|
44329
44356
|
["gas_leak_hiss", 2],
|
|
44330
|
-
["structure_collapse", 2, "crumble"]
|
|
44357
|
+
["structure_collapse", 2, "crumble"],
|
|
44358
|
+
["grenade_bounce", 1],
|
|
44359
|
+
["c4_plant", 2],
|
|
44360
|
+
["c4_beep", 2],
|
|
44361
|
+
["c4_disarm", 2]
|
|
44331
44362
|
]),
|
|
44332
44363
|
...entries("personagem", [
|
|
44333
44364
|
["footstep_concrete_walk", 1, "sfx_step"],
|
|
@@ -44343,7 +44374,19 @@ var GameVehiclesThree = (() => {
|
|
|
44343
44374
|
["blunt_hit", 1],
|
|
44344
44375
|
["bite", 1, "sfx_flesh"],
|
|
44345
44376
|
["body_fall", 1],
|
|
44346
|
-
["player_hurt", 2]
|
|
44377
|
+
["player_hurt", 2],
|
|
44378
|
+
["footstep_tile_walk", 1, "sfx_step"],
|
|
44379
|
+
["footstep_water_walk", 1, "sfx_step"],
|
|
44380
|
+
["footstep_grate_walk", 2, "sfx_step"],
|
|
44381
|
+
["footstep_duct_walk", 3, "sfx_step"],
|
|
44382
|
+
["ladder_climb", 2],
|
|
44383
|
+
["swim", 2],
|
|
44384
|
+
["zombie_groan", 1],
|
|
44385
|
+
["zombie_alert", 1],
|
|
44386
|
+
["zombie_attack", 1],
|
|
44387
|
+
["zombie_pain", 1],
|
|
44388
|
+
["zombie_claw_hit", 1, "sfx_flesh"],
|
|
44389
|
+
["zombie_claw_miss", 2]
|
|
44347
44390
|
]),
|
|
44348
44391
|
...entries("veiculos", [
|
|
44349
44392
|
["engine_loop_car", 1],
|
|
@@ -44371,7 +44414,8 @@ var GameVehiclesThree = (() => {
|
|
|
44371
44414
|
["wind_loop", 2],
|
|
44372
44415
|
["thunder_near", 2],
|
|
44373
44416
|
["thunder_far", 2],
|
|
44374
|
-
["water_splash", 2]
|
|
44417
|
+
["water_splash", 2],
|
|
44418
|
+
["helicopter_loop", 3]
|
|
44375
44419
|
])
|
|
44376
44420
|
];
|
|
44377
44421
|
var SFX_MATERIALS = [
|
|
@@ -44460,6 +44504,7 @@ var GameVehiclesThree = (() => {
|
|
|
44460
44504
|
category: "1 \xB7 Categoria",
|
|
44461
44505
|
sound: "1 \xB7 Som",
|
|
44462
44506
|
play: "1 \xB7 \u25B6 Tocar",
|
|
44507
|
+
play_user: "1 \xB7 \u25B6 Tocar o seu",
|
|
44463
44508
|
material: "2 \xB7 Material",
|
|
44464
44509
|
blow: "2 \xB7 Golpe",
|
|
44465
44510
|
strike: "2 \xB7 \u25B6 Tocar golpe",
|
|
@@ -44481,6 +44526,7 @@ var GameVehiclesThree = (() => {
|
|
|
44481
44526
|
approve: "5 \xB7 Aprovo (C10)"
|
|
44482
44527
|
},
|
|
44483
44528
|
hints: {
|
|
44529
|
+
play_user: "Toca a sua grava\xE7\xE3o deste som (dos seus pacotes, fora do git), mesmo quando o SDK tem uma melhor e toca na frente.",
|
|
44484
44530
|
sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
|
|
44485
44531
|
strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
|
|
44486
44532
|
wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
|
|
@@ -44525,9 +44571,10 @@ var GameVehiclesThree = (() => {
|
|
|
44525
44571
|
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
44526
44572
|
states: { file: "A", synth: "S", missing: "F" },
|
|
44527
44573
|
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" },
|
|
44528
|
-
metrics: { 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" },
|
|
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" },
|
|
44529
44575
|
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
44530
44576
|
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
44577
|
+
sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
|
|
44531
44578
|
probe: "Fonte do som",
|
|
44532
44579
|
wall: "Parede (oclus\xE3o)",
|
|
44533
44580
|
scenarios: { pipeline: "Arquivo \u2192 decodifica \u2192 toca (round-robin, cauda)", criteria: "Crit\xE9rios C1\u2013C9 no som de calibra\xE7\xE3o", loop: "Loop de arquivo: emenda sem buraco (crossfade)", panel: "Painel: categorias, matriz, A/B e parede" }
|
|
@@ -44540,6 +44587,7 @@ var GameVehiclesThree = (() => {
|
|
|
44540
44587
|
category: "1 \xB7 Category",
|
|
44541
44588
|
sound: "1 \xB7 Sound",
|
|
44542
44589
|
play: "1 \xB7 \u25B6 Play",
|
|
44590
|
+
play_user: "1 \xB7 \u25B6 Play yours",
|
|
44543
44591
|
material: "2 \xB7 Material",
|
|
44544
44592
|
blow: "2 \xB7 Blow",
|
|
44545
44593
|
strike: "2 \xB7 \u25B6 Play blow",
|
|
@@ -44561,6 +44609,7 @@ var GameVehiclesThree = (() => {
|
|
|
44561
44609
|
approve: "5 \xB7 Approve (C10)"
|
|
44562
44610
|
},
|
|
44563
44611
|
hints: {
|
|
44612
|
+
play_user: "Plays your own take of this sound (from your packs, kept out of git), even where the SDK has a better one that plays first.",
|
|
44564
44613
|
sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
|
|
44565
44614
|
strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
|
|
44566
44615
|
wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
|
|
@@ -44595,9 +44644,10 @@ var GameVehiclesThree = (() => {
|
|
|
44595
44644
|
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
44596
44645
|
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
44597
44646
|
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" },
|
|
44598
|
-
metrics: { 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" },
|
|
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" },
|
|
44599
44648
|
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
44600
44649
|
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
44650
|
+
sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
|
|
44601
44651
|
probe: "Sound source",
|
|
44602
44652
|
wall: "Wall (occlusion)",
|
|
44603
44653
|
scenarios: { pipeline: "File \u2192 decode \u2192 play (round-robin, tail)", criteria: "Criteria C1\u2013C9 on the calibration sound", loop: "File loop: seamless joins (crossfade)", panel: "Panel: categories, matrix, A/B and wall" }
|
|
@@ -44679,6 +44729,80 @@ var GameVehiclesThree = (() => {
|
|
|
44679
44729
|
sources: [`cena:${line}`]
|
|
44680
44730
|
};
|
|
44681
44731
|
}
|
|
44732
|
+
var CABIN_SOUNDS = [
|
|
44733
|
+
{
|
|
44734
|
+
id: "blinker_tick",
|
|
44735
|
+
bus: "world",
|
|
44736
|
+
duration: 0.03,
|
|
44737
|
+
layers: [
|
|
44738
|
+
// the relay: a click of bright noise and a short low knock
|
|
44739
|
+
{ source: { kind: "noise", offset: "random" }, filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 2600 } }] }, envelope: [[0, 0.22, "set"], [0.025, 1e-4, "exp", "fixed"]] },
|
|
44740
|
+
{ source: { kind: "osc", wave: "triangle", frequency: { set: 180 } }, envelope: [[0, 0.12, "set"], [0.03, 1e-4, "exp", "fixed"]] }
|
|
44741
|
+
],
|
|
44742
|
+
falloff: { model: "none" }
|
|
44743
|
+
},
|
|
44744
|
+
{
|
|
44745
|
+
id: "starter_crank",
|
|
44746
|
+
bus: "world",
|
|
44747
|
+
duration: 0.9,
|
|
44748
|
+
layers: [
|
|
44749
|
+
// the starter motor turning the engine over: low noise chopped at the compression strokes
|
|
44750
|
+
{
|
|
44751
|
+
source: { kind: "noise", offset: "random" },
|
|
44752
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 420 } }] },
|
|
44753
|
+
modulators: [{ target: "gain", wave: "square", rate: 11, depth: 0.08, base: 0.1 }],
|
|
44754
|
+
envelope: [[0, 1e-4, "set", "fixed"], [0.05, 0.25, "linear"], [0.8, 0.22, "set"], [0.9, 1e-4, "exp", "fixed"]]
|
|
44755
|
+
},
|
|
44756
|
+
{ source: { kind: "osc", wave: "sawtooth", frequency: { set: 95, to: 120, curve: "linear", over: 0.9 } }, filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 300 } }] }, envelope: [[0, 0.04, "set"], [0.9, 1e-4, "exp", "fixed"]] }
|
|
44757
|
+
],
|
|
44758
|
+
falloff: { model: "none" }
|
|
44759
|
+
},
|
|
44760
|
+
{
|
|
44761
|
+
id: "car_alarm",
|
|
44762
|
+
bus: "world",
|
|
44763
|
+
order: "siren",
|
|
44764
|
+
duration: 3,
|
|
44765
|
+
tail: 0.1,
|
|
44766
|
+
layers: [
|
|
44767
|
+
// the whoop of a car alarm: a square swept up and down three times a second
|
|
44768
|
+
{
|
|
44769
|
+
source: { kind: "osc", wave: "square", frequency: { set: 1100 } },
|
|
44770
|
+
modulators: [{ target: "frequency", wave: "triangle", rate: 3, depth: 420 }],
|
|
44771
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 2600 } }] },
|
|
44772
|
+
envelope: [[0, 1e-4, "set", "fixed"], [0.05, 0.05, "linear"], [2.9, 0.05, "set"], [3, 1e-4, "exp", "fixed"]]
|
|
44773
|
+
}
|
|
44774
|
+
],
|
|
44775
|
+
falloff: { model: "none" }
|
|
44776
|
+
},
|
|
44777
|
+
{
|
|
44778
|
+
id: "alarm_chirp",
|
|
44779
|
+
bus: "world",
|
|
44780
|
+
duration: 0.1,
|
|
44781
|
+
layers: [{ source: { kind: "osc", wave: "square", frequency: { set: 2300 } }, repeat: { count: 2, spacing: 0.16 }, envelope: [[0, 0.05, "set"], [0.09, 1e-4, "exp", "fixed"]] }],
|
|
44782
|
+
falloff: { model: "none" }
|
|
44783
|
+
},
|
|
44784
|
+
{
|
|
44785
|
+
id: "wiper_swish",
|
|
44786
|
+
bus: "world",
|
|
44787
|
+
duration: 0.45,
|
|
44788
|
+
layers: [
|
|
44789
|
+
{
|
|
44790
|
+
source: { kind: "noise", offset: "random" },
|
|
44791
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: 700, to: 1100, curve: "linear", over: 0.45 }, q: 1.2 }] },
|
|
44792
|
+
envelope: [[0, 1e-4, "set", "fixed"], [0.2, 0.06, "linear"], [0.45, 1e-4, "exp", "fixed"]]
|
|
44793
|
+
}
|
|
44794
|
+
],
|
|
44795
|
+
falloff: { model: "none" }
|
|
44796
|
+
},
|
|
44797
|
+
{
|
|
44798
|
+
id: "seatbelt_chime",
|
|
44799
|
+
bus: "world",
|
|
44800
|
+
duration: 0.5,
|
|
44801
|
+
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
|
+
falloff: { model: "none" }
|
|
44803
|
+
}
|
|
44804
|
+
];
|
|
44805
|
+
var CABIN_BANK = { id: "vehicle_cabin", sounds: CABIN_SOUNDS, loops: [] };
|
|
44682
44806
|
var FOLEY_FALLOFF = {
|
|
44683
44807
|
model: "inverse_square",
|
|
44684
44808
|
k: 0.02,
|
|
@@ -45679,6 +45803,21 @@ var GameVehiclesThree = (() => {
|
|
|
45679
45803
|
|
|
45680
45804
|
// ../game-render-three/dist/index.js
|
|
45681
45805
|
var DEFAULT_ANGLE = Math.PI / 3;
|
|
45806
|
+
var LIGHT_PRIORITY = {
|
|
45807
|
+
blast: 900,
|
|
45808
|
+
rocket: 800,
|
|
45809
|
+
muzzle: 750,
|
|
45810
|
+
fire: 600,
|
|
45811
|
+
flare: 500,
|
|
45812
|
+
headlight: 400,
|
|
45813
|
+
weaponLight: 400,
|
|
45814
|
+
lamp: 200,
|
|
45815
|
+
street: 150
|
|
45816
|
+
};
|
|
45817
|
+
function isLightBudget(value) {
|
|
45818
|
+
const candidate = value;
|
|
45819
|
+
return typeof candidate === "object" && candidate !== null && typeof candidate.acquire === "function" && typeof candidate.addSource === "function" && typeof candidate.lease === "function" && typeof candidate.present === "function";
|
|
45820
|
+
}
|
|
45682
45821
|
var EFFECT_STEP_SECONDS = 1 / 50;
|
|
45683
45822
|
function isRenderPools(value) {
|
|
45684
45823
|
const candidate = value;
|
|
@@ -46343,6 +46482,205 @@ var GameVehiclesThree = (() => {
|
|
|
46343
46482
|
const brakeForce = base.brakeForce ?? body.mass * 9.81 * (carRatio + (0.6 - carRatio) * heavyShare);
|
|
46344
46483
|
return { ...spec, mass: body.mass, wheels, fourWheelDrive: driveAll, engine, gears, drag, brakeForce, tyre: { ...spec.tyre, friction: 0.8 + 0.03 * stats2.handling } };
|
|
46345
46484
|
}
|
|
46485
|
+
var DEFAULT_CONTROL_KEYS = {
|
|
46486
|
+
throttle: ["KeyW", "ArrowUp"],
|
|
46487
|
+
brake: ["KeyS", "ArrowDown"],
|
|
46488
|
+
left: ["KeyA", "ArrowLeft"],
|
|
46489
|
+
right: ["KeyD", "ArrowRight"],
|
|
46490
|
+
handbrake: ["Space"],
|
|
46491
|
+
horn: ["KeyH"],
|
|
46492
|
+
ignition: ["KeyI"],
|
|
46493
|
+
gearbox: ["KeyM"],
|
|
46494
|
+
gear_up: ["KeyE"],
|
|
46495
|
+
gear_down: ["KeyQ"],
|
|
46496
|
+
parking_brake: ["KeyP"],
|
|
46497
|
+
drive_mode: ["KeyG"],
|
|
46498
|
+
lights: ["KeyL"],
|
|
46499
|
+
high_beam: ["KeyK"],
|
|
46500
|
+
fog_lights: ["KeyN"],
|
|
46501
|
+
interior_light: ["KeyU"],
|
|
46502
|
+
alarm: ["KeyY"],
|
|
46503
|
+
radio: ["KeyR"],
|
|
46504
|
+
radio_source: ["KeyT"],
|
|
46505
|
+
exit: ["KeyF"],
|
|
46506
|
+
indicator_left: ["Comma"],
|
|
46507
|
+
indicator_right: ["Period"],
|
|
46508
|
+
hazard: ["KeyB"],
|
|
46509
|
+
wipers: ["KeyO"],
|
|
46510
|
+
seatbelt: ["KeyJ"]
|
|
46511
|
+
};
|
|
46512
|
+
function createVehicleControls(options) {
|
|
46513
|
+
const keys = { ...DEFAULT_CONTROL_KEYS, ...options.keys };
|
|
46514
|
+
const auto4 = options.autoFourWheel ?? { slip: 0.18, releaseSeconds: 2 };
|
|
46515
|
+
const hasFog = options.fogLamps !== false;
|
|
46516
|
+
const held = /* @__PURE__ */ new Set();
|
|
46517
|
+
const any = (codes) => codes.some((c) => held.has(c));
|
|
46518
|
+
const commandOf = /* @__PURE__ */ new Map();
|
|
46519
|
+
for (const [command2, codes] of Object.entries(keys)) if (!["throttle", "brake", "left", "right", "handbrake", "horn"].includes(command2)) for (const code of codes) commandOf.set(code, command2);
|
|
46520
|
+
const driving = new Set(Object.values(keys).flat());
|
|
46521
|
+
const state = {
|
|
46522
|
+
ignition: !!options.running,
|
|
46523
|
+
gearbox: options.gearbox ?? "automatic",
|
|
46524
|
+
gear: 1,
|
|
46525
|
+
parkingBrake: false,
|
|
46526
|
+
driveMode: options.fourWheelDrive ? "auto" : "4x2",
|
|
46527
|
+
fourWheelEngaged: false,
|
|
46528
|
+
lamps: { mode: "off", fog: false, interior: false },
|
|
46529
|
+
brakeLights: false,
|
|
46530
|
+
reverseLights: false,
|
|
46531
|
+
horn: false,
|
|
46532
|
+
alarm: "off",
|
|
46533
|
+
radio: { on: false, source: "radio" },
|
|
46534
|
+
indicator: "off",
|
|
46535
|
+
blinkOn: false,
|
|
46536
|
+
tick: false,
|
|
46537
|
+
wipers: "off",
|
|
46538
|
+
seatbelt: false
|
|
46539
|
+
};
|
|
46540
|
+
const blinkHz = options.blinkHz ?? 1.5;
|
|
46541
|
+
const cancelAt = options.indicatorCancel ?? 0.15;
|
|
46542
|
+
let blink = 0;
|
|
46543
|
+
let turned = 0;
|
|
46544
|
+
let throttle = 0;
|
|
46545
|
+
let brake = 0;
|
|
46546
|
+
let steer = 0;
|
|
46547
|
+
let calm = 0;
|
|
46548
|
+
const emit = (event) => options.onEvent?.(event);
|
|
46549
|
+
const LAMPS = ["off", "position", "low"];
|
|
46550
|
+
const MODES = ["4x2", "4x4", "auto"];
|
|
46551
|
+
const command = (c) => {
|
|
46552
|
+
switch (c) {
|
|
46553
|
+
case "ignition":
|
|
46554
|
+
state.ignition = !state.ignition;
|
|
46555
|
+
if (state.ignition && state.alarm !== "off") state.alarm = "off";
|
|
46556
|
+
break;
|
|
46557
|
+
case "gearbox":
|
|
46558
|
+
state.gearbox = state.gearbox === "automatic" ? "manual" : "automatic";
|
|
46559
|
+
state.gear = Math.max(1, state.gear);
|
|
46560
|
+
break;
|
|
46561
|
+
case "gear_up":
|
|
46562
|
+
case "gear_down":
|
|
46563
|
+
if (state.gearbox !== "manual") return;
|
|
46564
|
+
state.gear = Math.max(-1, Math.min(options.gears, state.gear + (c === "gear_up" ? 1 : -1)));
|
|
46565
|
+
break;
|
|
46566
|
+
case "parking_brake":
|
|
46567
|
+
state.parkingBrake = !state.parkingBrake;
|
|
46568
|
+
break;
|
|
46569
|
+
case "drive_mode": {
|
|
46570
|
+
if (!options.fourWheelDrive) return emit({ type: "refused", command: c, reason: "no_four_wheel_drive" });
|
|
46571
|
+
state.driveMode = MODES[(MODES.indexOf(state.driveMode) + 1) % MODES.length];
|
|
46572
|
+
state.fourWheelEngaged = state.driveMode === "4x4";
|
|
46573
|
+
break;
|
|
46574
|
+
}
|
|
46575
|
+
case "lights":
|
|
46576
|
+
state.lamps.mode = state.lamps.mode === "high" ? "off" : LAMPS[(LAMPS.indexOf(state.lamps.mode) + 1) % LAMPS.length];
|
|
46577
|
+
break;
|
|
46578
|
+
case "high_beam":
|
|
46579
|
+
state.lamps.mode = state.lamps.mode === "high" ? "low" : "high";
|
|
46580
|
+
break;
|
|
46581
|
+
case "fog_lights":
|
|
46582
|
+
if (!hasFog) return emit({ type: "refused", command: c, reason: "no_fog_lamps" });
|
|
46583
|
+
state.lamps.fog = !state.lamps.fog;
|
|
46584
|
+
if (state.lamps.fog && state.lamps.mode === "off") state.lamps.mode = "position";
|
|
46585
|
+
break;
|
|
46586
|
+
case "interior_light":
|
|
46587
|
+
state.lamps.interior = !state.lamps.interior;
|
|
46588
|
+
break;
|
|
46589
|
+
case "alarm":
|
|
46590
|
+
state.alarm = state.alarm === "off" ? "armed" : state.alarm === "armed" ? "ringing" : "off";
|
|
46591
|
+
break;
|
|
46592
|
+
case "radio":
|
|
46593
|
+
state.radio.on = !state.radio.on;
|
|
46594
|
+
break;
|
|
46595
|
+
case "radio_source":
|
|
46596
|
+
state.radio.source = state.radio.source === "radio" ? "tape" : "radio";
|
|
46597
|
+
break;
|
|
46598
|
+
case "exit":
|
|
46599
|
+
break;
|
|
46600
|
+
case "indicator_left":
|
|
46601
|
+
case "indicator_right": {
|
|
46602
|
+
const side2 = c === "indicator_left" ? "left" : "right";
|
|
46603
|
+
if (state.indicator === "hazard") return;
|
|
46604
|
+
state.indicator = state.indicator === side2 ? "off" : side2;
|
|
46605
|
+
turned = 0;
|
|
46606
|
+
blink = 0;
|
|
46607
|
+
break;
|
|
46608
|
+
}
|
|
46609
|
+
case "hazard":
|
|
46610
|
+
state.indicator = state.indicator === "hazard" ? "off" : "hazard";
|
|
46611
|
+
blink = 0;
|
|
46612
|
+
break;
|
|
46613
|
+
case "wipers":
|
|
46614
|
+
state.wipers = state.wipers === "off" ? "slow" : state.wipers === "slow" ? "fast" : "off";
|
|
46615
|
+
break;
|
|
46616
|
+
case "seatbelt":
|
|
46617
|
+
state.seatbelt = !state.seatbelt;
|
|
46618
|
+
break;
|
|
46619
|
+
}
|
|
46620
|
+
emit({ type: "command", command: c, state });
|
|
46621
|
+
};
|
|
46622
|
+
const ease = (from, to, rate, dt) => from + Math.sign(to - from) * Math.min(Math.abs(to - from), rate * dt);
|
|
46623
|
+
return {
|
|
46624
|
+
keys,
|
|
46625
|
+
state,
|
|
46626
|
+
key(code, down) {
|
|
46627
|
+
if (!driving.has(code)) return false;
|
|
46628
|
+
const was = held.has(code);
|
|
46629
|
+
if (down) held.add(code);
|
|
46630
|
+
else held.delete(code);
|
|
46631
|
+
const c = commandOf.get(code);
|
|
46632
|
+
if (c && down && !was) command(c);
|
|
46633
|
+
return true;
|
|
46634
|
+
},
|
|
46635
|
+
command,
|
|
46636
|
+
input(dt, driver) {
|
|
46637
|
+
const gas = any(keys.throttle) ? 1 : 0;
|
|
46638
|
+
const stop = any(keys.brake) ? 1 : 0;
|
|
46639
|
+
const wheel = (any(keys.left) ? 1 : 0) - (any(keys.right) ? 1 : 0);
|
|
46640
|
+
throttle = ease(throttle, gas, gas > throttle ? 4 : 8, dt);
|
|
46641
|
+
brake = ease(brake, stop, stop > brake ? 6 : 10, dt);
|
|
46642
|
+
steer = ease(steer, wheel, wheel !== 0 && Math.sign(wheel) === Math.sign(steer || wheel) ? 3 : 6, dt);
|
|
46643
|
+
const handbrake = state.parkingBrake || any(keys.handbrake);
|
|
46644
|
+
state.tick = false;
|
|
46645
|
+
if (state.indicator !== "off") {
|
|
46646
|
+
const before = Math.floor(blink * blinkHz * 2);
|
|
46647
|
+
blink += dt;
|
|
46648
|
+
const now = Math.floor(blink * blinkHz * 2);
|
|
46649
|
+
state.blinkOn = now % 2 === 0;
|
|
46650
|
+
state.tick = now !== before;
|
|
46651
|
+
if (state.indicator !== "hazard") {
|
|
46652
|
+
const way = state.indicator === "left" ? steer : -steer;
|
|
46653
|
+
if (way > 0.5) turned = 1;
|
|
46654
|
+
else if (turned && way < cancelAt) state.indicator = "off";
|
|
46655
|
+
}
|
|
46656
|
+
} else state.blinkOn = false;
|
|
46657
|
+
state.horn = any(keys.horn);
|
|
46658
|
+
const gasNow = state.ignition ? throttle : 0;
|
|
46659
|
+
const reversing = state.gearbox === "manual" ? state.gear < 0 : (driver?.state.gear ?? 1) < 0;
|
|
46660
|
+
state.reverseLights = reversing;
|
|
46661
|
+
state.brakeLights = handbrake || (reversing ? gasNow > 0.05 && (driver?.state.u ?? 0) < -0.3 : brake > 0.05);
|
|
46662
|
+
if (state.gearbox === "automatic") return { throttle: gasNow, brake, steer, handbrake, horn: state.horn };
|
|
46663
|
+
return state.gear < 0 ? { throttle: brake, brake: gasNow, steer, handbrake, horn: state.horn, gear: state.gear } : { throttle: gasNow, brake, steer, handbrake, horn: state.horn, gear: state.gear };
|
|
46664
|
+
},
|
|
46665
|
+
after(driver, dt) {
|
|
46666
|
+
if (driver.state.engineOn && !state.ignition && driver.state.u !== 0) state.ignition = true;
|
|
46667
|
+
if (!state.ignition && driver.state.engineOn) driver.state.engineOn = false;
|
|
46668
|
+
if (state.driveMode === "auto" && options.fourWheelDrive) {
|
|
46669
|
+
const slip = Math.max(0, ...driver.state.slip);
|
|
46670
|
+
if (slip > auto4.slip) {
|
|
46671
|
+
state.fourWheelEngaged = true;
|
|
46672
|
+
calm = 0;
|
|
46673
|
+
} else if (state.fourWheelEngaged && (calm += dt) > auto4.releaseSeconds) state.fourWheelEngaged = false;
|
|
46674
|
+
} else state.fourWheelEngaged = state.driveMode === "4x4";
|
|
46675
|
+
driver.spec.fourWheelDrive = !!options.fourWheelDrive && state.fourWheelEngaged;
|
|
46676
|
+
},
|
|
46677
|
+
release() {
|
|
46678
|
+
held.clear();
|
|
46679
|
+
throttle = brake = steer = 0;
|
|
46680
|
+
state.horn = false;
|
|
46681
|
+
}
|
|
46682
|
+
};
|
|
46683
|
+
}
|
|
46346
46684
|
function conditionFromDamage(spec, report) {
|
|
46347
46685
|
const tyres = spec.wheels.map((wheel) => {
|
|
46348
46686
|
let best;
|
|
@@ -47949,21 +48287,521 @@ var GameVehiclesThree = (() => {
|
|
|
47949
48287
|
return { ...certificate, results, status: statusOf(results) };
|
|
47950
48288
|
}
|
|
47951
48289
|
|
|
48290
|
+
// src/dashboard.ts
|
|
48291
|
+
var DASHBOARD_LOOK = {
|
|
48292
|
+
face: "#0b1110",
|
|
48293
|
+
ring: "#2f3a36",
|
|
48294
|
+
marks: "#cfe8dc",
|
|
48295
|
+
needle: "#ff6a2a",
|
|
48296
|
+
red: "#e2402f",
|
|
48297
|
+
amber: "#f2a630",
|
|
48298
|
+
green: "#46d16f",
|
|
48299
|
+
blue: "#3f8cff",
|
|
48300
|
+
dim: "rgba(207,232,220,0.12)",
|
|
48301
|
+
/** How far in front of the kit's dial the face sits, metres (the kit's needle sticks out 6 mm). */
|
|
48302
|
+
lift: 0.011
|
|
48303
|
+
};
|
|
48304
|
+
var SIZE = 256;
|
|
48305
|
+
function createVehicleDashboard(THREE, built2, options) {
|
|
48306
|
+
const maxKmh = options.maxKmh ?? 220;
|
|
48307
|
+
const redline = options.redlineRpm ?? 6500;
|
|
48308
|
+
const doc = options.document ?? (typeof document !== "undefined" ? document : null);
|
|
48309
|
+
const dials = [];
|
|
48310
|
+
built2.group.traverse((o) => {
|
|
48311
|
+
if (o.isMesh && o.material === options.gauge) dials.push(o);
|
|
48312
|
+
});
|
|
48313
|
+
const eye = built2.driverEye;
|
|
48314
|
+
const hidden = [];
|
|
48315
|
+
const faces = [];
|
|
48316
|
+
if (doc && eye && dials.length) {
|
|
48317
|
+
built2.group.updateMatrixWorld(true);
|
|
48318
|
+
const eyeWorld = built2.group.localToWorld(new THREE.Vector3(eye[0], eye[1], eye[2]));
|
|
48319
|
+
const near = dials.map((d) => ({ d, at: d.getWorldPosition(new THREE.Vector3()) })).sort((a, b) => a.at.distanceTo(eyeWorld) - b.at.distanceTo(eyeWorld)).slice(0, 2).sort((a, b) => built2.group.worldToLocal(b.at.clone()).x - built2.group.worldToLocal(a.at.clone()).x);
|
|
48320
|
+
near.forEach(({ d, at }, i) => {
|
|
48321
|
+
const canvas = doc.createElement("canvas");
|
|
48322
|
+
canvas.width = canvas.height = SIZE;
|
|
48323
|
+
const g = canvas.getContext("2d");
|
|
48324
|
+
if (!g) return;
|
|
48325
|
+
const texture = new THREE.CanvasTexture(canvas);
|
|
48326
|
+
const radius = d.geometry.parameters?.radiusTop ?? 0.055;
|
|
48327
|
+
const mesh2 = new THREE.Mesh(new THREE.CircleGeometry(radius * 1.12, 40), new THREE.MeshBasicMaterial({ map: texture, transparent: true, toneMapped: false, depthWrite: false }));
|
|
48328
|
+
mesh2.name = "dashboard_face";
|
|
48329
|
+
const axis = new THREE.Vector3(0, 1, 0).applyQuaternion(d.getWorldQuaternion(d.quaternion.clone())).normalize();
|
|
48330
|
+
if (axis.dot(eyeWorld.clone().sub(at)) < 0) axis.negate();
|
|
48331
|
+
const front = at.clone().addScaledVector(axis, DASHBOARD_LOOK.lift);
|
|
48332
|
+
mesh2.position.copy(built2.group.worldToLocal(front.clone()));
|
|
48333
|
+
built2.group.add(mesh2);
|
|
48334
|
+
mesh2.updateMatrixWorld(true);
|
|
48335
|
+
mesh2.lookAt(front.add(axis));
|
|
48336
|
+
d.visible = false;
|
|
48337
|
+
hidden.push(d);
|
|
48338
|
+
if (options.needle)
|
|
48339
|
+
built2.group.traverse((o) => {
|
|
48340
|
+
if (o.isMesh && o.material === options.needle && o.visible && o.getWorldPosition(new THREE.Vector3()).distanceTo(at) < radius * 1.2) {
|
|
48341
|
+
o.visible = false;
|
|
48342
|
+
hidden.push(o);
|
|
48343
|
+
}
|
|
48344
|
+
});
|
|
48345
|
+
faces.push({ mesh: mesh2, canvas, g, texture, kind: near.length === 1 || i === 0 ? "speed" : "rpm" });
|
|
48346
|
+
});
|
|
48347
|
+
}
|
|
48348
|
+
const lamp = (g, x, y, on, colour, draw2) => {
|
|
48349
|
+
g.save();
|
|
48350
|
+
g.translate(x, y);
|
|
48351
|
+
g.fillStyle = g.strokeStyle = on ? colour : DASHBOARD_LOOK.dim;
|
|
48352
|
+
g.lineWidth = 4;
|
|
48353
|
+
draw2(g);
|
|
48354
|
+
g.restore();
|
|
48355
|
+
};
|
|
48356
|
+
const arrow = (dir) => (g) => {
|
|
48357
|
+
g.beginPath();
|
|
48358
|
+
g.moveTo(dir * 14, 0);
|
|
48359
|
+
g.lineTo(-dir * 2, -12);
|
|
48360
|
+
g.lineTo(-dir * 2, -5);
|
|
48361
|
+
g.lineTo(-dir * 14, -5);
|
|
48362
|
+
g.lineTo(-dir * 14, 5);
|
|
48363
|
+
g.lineTo(-dir * 2, 5);
|
|
48364
|
+
g.lineTo(-dir * 2, 12);
|
|
48365
|
+
g.closePath();
|
|
48366
|
+
g.fill();
|
|
48367
|
+
};
|
|
48368
|
+
const beam = (g) => {
|
|
48369
|
+
g.beginPath();
|
|
48370
|
+
g.arc(-4, 0, 10, Math.PI / 2, -Math.PI / 2, true);
|
|
48371
|
+
g.closePath();
|
|
48372
|
+
g.fill();
|
|
48373
|
+
for (let k = -1; k <= 1; k++) g.fillRect(8, k * 6 - 1.5, 10, 3);
|
|
48374
|
+
};
|
|
48375
|
+
const belt = (g) => {
|
|
48376
|
+
g.beginPath();
|
|
48377
|
+
g.arc(0, -10, 5, 0, Math.PI * 2);
|
|
48378
|
+
g.fill();
|
|
48379
|
+
g.fillRect(-6, -3, 12, 16);
|
|
48380
|
+
g.strokeStyle = DASHBOARD_LOOK.face;
|
|
48381
|
+
g.lineWidth = 3;
|
|
48382
|
+
g.beginPath();
|
|
48383
|
+
g.moveTo(-7, -3);
|
|
48384
|
+
g.lineTo(7, 12);
|
|
48385
|
+
g.stroke();
|
|
48386
|
+
};
|
|
48387
|
+
const letter = (text) => (g) => {
|
|
48388
|
+
g.font = "bold 22px sans-serif";
|
|
48389
|
+
g.textAlign = "center";
|
|
48390
|
+
g.textBaseline = "middle";
|
|
48391
|
+
g.fillText(text, 0, 1);
|
|
48392
|
+
};
|
|
48393
|
+
const ring2 = (text) => (g) => {
|
|
48394
|
+
g.beginPath();
|
|
48395
|
+
g.arc(0, 0, 13, 0, Math.PI * 2);
|
|
48396
|
+
g.stroke();
|
|
48397
|
+
letter(text)(g);
|
|
48398
|
+
};
|
|
48399
|
+
const dial = (g, value, top, step, redFrom, label) => {
|
|
48400
|
+
const c = SIZE / 2;
|
|
48401
|
+
g.clearRect(0, 0, SIZE, SIZE);
|
|
48402
|
+
g.fillStyle = DASHBOARD_LOOK.face;
|
|
48403
|
+
g.beginPath();
|
|
48404
|
+
g.arc(c, c, c - 2, 0, Math.PI * 2);
|
|
48405
|
+
g.fill();
|
|
48406
|
+
g.strokeStyle = DASHBOARD_LOOK.ring;
|
|
48407
|
+
g.lineWidth = 6;
|
|
48408
|
+
g.stroke();
|
|
48409
|
+
const angle = (v) => Math.PI * 0.75 + Math.max(0, Math.min(top, v)) / top * Math.PI * 1.5;
|
|
48410
|
+
for (let v = 0; v <= top + 1e-6; v += step) {
|
|
48411
|
+
const a2 = angle(v);
|
|
48412
|
+
g.strokeStyle = redFrom !== null && v >= redFrom ? DASHBOARD_LOOK.red : DASHBOARD_LOOK.marks;
|
|
48413
|
+
g.lineWidth = 4;
|
|
48414
|
+
g.beginPath();
|
|
48415
|
+
g.moveTo(c + Math.cos(a2) * (c - 12), c + Math.sin(a2) * (c - 12));
|
|
48416
|
+
g.lineTo(c + Math.cos(a2) * (c - 30), c + Math.sin(a2) * (c - 30));
|
|
48417
|
+
g.stroke();
|
|
48418
|
+
g.fillStyle = DASHBOARD_LOOK.marks;
|
|
48419
|
+
g.font = "18px sans-serif";
|
|
48420
|
+
g.textAlign = "center";
|
|
48421
|
+
g.textBaseline = "middle";
|
|
48422
|
+
g.fillText(label(v), c + Math.cos(a2) * (c - 48), c + Math.sin(a2) * (c - 48));
|
|
48423
|
+
}
|
|
48424
|
+
const a = angle(value);
|
|
48425
|
+
g.strokeStyle = DASHBOARD_LOOK.needle;
|
|
48426
|
+
g.lineWidth = 6;
|
|
48427
|
+
g.beginPath();
|
|
48428
|
+
g.moveTo(c - Math.cos(a) * 14, c - Math.sin(a) * 14);
|
|
48429
|
+
g.lineTo(c + Math.cos(a) * (c - 22), c + Math.sin(a) * (c - 22));
|
|
48430
|
+
g.stroke();
|
|
48431
|
+
g.fillStyle = DASHBOARD_LOOK.ring;
|
|
48432
|
+
g.beginPath();
|
|
48433
|
+
g.arc(c, c, 10, 0, Math.PI * 2);
|
|
48434
|
+
g.fill();
|
|
48435
|
+
};
|
|
48436
|
+
const bar = (g, x, share, warnAbove, label) => {
|
|
48437
|
+
if (share === void 0) return;
|
|
48438
|
+
const h = 60;
|
|
48439
|
+
g.strokeStyle = DASHBOARD_LOOK.marks;
|
|
48440
|
+
g.lineWidth = 2;
|
|
48441
|
+
g.strokeRect(x - 5, 150, 10, h);
|
|
48442
|
+
const s = Math.max(0, Math.min(1, share));
|
|
48443
|
+
g.fillStyle = (warnAbove ? s > 0.85 : s < 0.12) ? DASHBOARD_LOOK.red : DASHBOARD_LOOK.marks;
|
|
48444
|
+
g.fillRect(x - 4, 150 + h * (1 - s), 8, h * s);
|
|
48445
|
+
g.font = "14px sans-serif";
|
|
48446
|
+
g.textAlign = "center";
|
|
48447
|
+
g.fillText(label, x, 222);
|
|
48448
|
+
};
|
|
48449
|
+
const draw = (r) => {
|
|
48450
|
+
const warn = r.ignition && !r.engineOn;
|
|
48451
|
+
for (const f of faces) {
|
|
48452
|
+
const g = f.g;
|
|
48453
|
+
if (f.kind === "speed") {
|
|
48454
|
+
dial(g, r.kmh, maxKmh, maxKmh > 160 ? 20 : 10, null, (v) => String(Math.round(v)));
|
|
48455
|
+
g.fillStyle = DASHBOARD_LOOK.marks;
|
|
48456
|
+
g.font = "bold 30px sans-serif";
|
|
48457
|
+
g.textAlign = "center";
|
|
48458
|
+
g.fillText(String(Math.round(r.kmh)), SIZE / 2, SIZE / 2 + 52);
|
|
48459
|
+
lamp(g, 92, 178, r.left, DASHBOARD_LOOK.green, arrow(-1));
|
|
48460
|
+
lamp(g, 164, 178, r.right, DASHBOARD_LOOK.green, arrow(1));
|
|
48461
|
+
lamp(g, 104, 214, r.highBeam, DASHBOARD_LOOK.blue, beam);
|
|
48462
|
+
lamp(g, 152, 214, r.lowBeam || r.fog, r.fog ? DASHBOARD_LOOK.amber : DASHBOARD_LOOK.green, beam);
|
|
48463
|
+
bar(g, 40, r.fuel, false, "F");
|
|
48464
|
+
} else {
|
|
48465
|
+
dial(g, r.rpm / 1e3, Math.ceil(redline / 1e3) + 1, 1, redline / 1e3, (v) => String(Math.round(v)));
|
|
48466
|
+
g.fillStyle = DASHBOARD_LOOK.marks;
|
|
48467
|
+
g.font = "bold 34px sans-serif";
|
|
48468
|
+
g.textAlign = "center";
|
|
48469
|
+
g.fillText(r.gear < 0 ? "R" : r.gear === 0 ? "N" : String(r.gear), SIZE / 2, SIZE / 2 + 54);
|
|
48470
|
+
lamp(g, 86, 178, r.parkingBrake, DASHBOARD_LOOK.red, ring2("P"));
|
|
48471
|
+
lamp(g, 128, 214, r.ignition && !r.seatbelt, DASHBOARD_LOOK.red, belt);
|
|
48472
|
+
lamp(g, 170, 178, warn, DASHBOARD_LOOK.red, letter("+\u2212"));
|
|
48473
|
+
lamp(g, 86, 214, warn, DASHBOARD_LOOK.red, letter("OIL"));
|
|
48474
|
+
lamp(g, 170, 214, r.fourWheel, DASHBOARD_LOOK.green, letter("4x4"));
|
|
48475
|
+
bar(g, SIZE - 40, r.temperature, true, "T");
|
|
48476
|
+
}
|
|
48477
|
+
f.texture.needsUpdate = true;
|
|
48478
|
+
}
|
|
48479
|
+
};
|
|
48480
|
+
let wait = 0;
|
|
48481
|
+
let last = "";
|
|
48482
|
+
return {
|
|
48483
|
+
dials: faces.length,
|
|
48484
|
+
update(reading, dt) {
|
|
48485
|
+
if (!faces.length) return;
|
|
48486
|
+
wait -= dt;
|
|
48487
|
+
const key = JSON.stringify(reading);
|
|
48488
|
+
if (wait > 0 || key === last) return;
|
|
48489
|
+
wait = 1 / (options.fps ?? 15);
|
|
48490
|
+
last = key;
|
|
48491
|
+
draw(reading);
|
|
48492
|
+
},
|
|
48493
|
+
dispose() {
|
|
48494
|
+
for (const f of faces) {
|
|
48495
|
+
discardObject3D(f.mesh);
|
|
48496
|
+
f.texture.dispose();
|
|
48497
|
+
f.canvas.width = f.canvas.height = 0;
|
|
48498
|
+
}
|
|
48499
|
+
faces.length = 0;
|
|
48500
|
+
for (const o of hidden) o.visible = true;
|
|
48501
|
+
hidden.length = 0;
|
|
48502
|
+
}
|
|
48503
|
+
};
|
|
48504
|
+
}
|
|
48505
|
+
|
|
48506
|
+
// src/lamps.ts
|
|
48507
|
+
var LAMP_RULES = {
|
|
48508
|
+
glow: { head: { off: 0.04, position: 0.3, low: 1, high: 1.35 }, tail: { off: 0.15, on: 0.7, brake: 1.6 }, fog: { off: 0.04, on: 1.1 }, amber: { off: 0.1, on: 2.2 } },
|
|
48509
|
+
low: { color: 16773584, intensity: 2.4, distance: 32, angle: 0.42, penumbra: 0.55, decay: 1.6, drop: 0.09 },
|
|
48510
|
+
high: { color: 16774882, intensity: 3.6, distance: 70, angle: 0.3, penumbra: 0.45, decay: 1.4, drop: 0.015 },
|
|
48511
|
+
fog: { color: 16773320, intensity: 1.6, distance: 16, angle: 0.75, penumbra: 0.7, decay: 1.8, drop: 0.12 },
|
|
48512
|
+
reverse: { color: 16054015, intensity: 0.9, distance: 7, decay: 2 },
|
|
48513
|
+
interior: { color: 16769712, intensity: 0.5, distance: 2.4, decay: 2 }
|
|
48514
|
+
};
|
|
48515
|
+
function createVehicleLamps(THREE, built2, options = {}) {
|
|
48516
|
+
const budget = isLightBudget(options.lights) ? options.lights : null;
|
|
48517
|
+
const owner = options.owner ?? "vehicle-lamps";
|
|
48518
|
+
const context = built2.context;
|
|
48519
|
+
const lamps = (context?.lights ?? []).filter((l) => l && Array.isArray(l.inner)).map((l) => l.fog ? { ...l, kind: "fog" } : l);
|
|
48520
|
+
const bulbs = (context?.fogBulbs ?? []).filter((o) => o?.material);
|
|
48521
|
+
built2.group.traverse((o) => {
|
|
48522
|
+
if (o.userData?.lamp === "fog" && o.material && !bulbs.includes(o)) bulbs.push(o);
|
|
48523
|
+
});
|
|
48524
|
+
if (bulbs.length) lamps.push({ kind: "fog", inner: bulbs });
|
|
48525
|
+
const has = { head: lamps.some((l) => l.kind === "headlight"), tail: lamps.some((l) => l.kind === "taillight"), fog: lamps.some((l) => l.kind === "fog"), indicators: false };
|
|
48526
|
+
const originals = /* @__PURE__ */ new Map();
|
|
48527
|
+
const copies = /* @__PURE__ */ new Map();
|
|
48528
|
+
const base = /* @__PURE__ */ new Map();
|
|
48529
|
+
const own = (mesh2) => {
|
|
48530
|
+
const mat = mesh2.material;
|
|
48531
|
+
if (!mat || Array.isArray(mat)) return null;
|
|
48532
|
+
if (copies.has(mat) || base.has(mat)) return mat;
|
|
48533
|
+
const copy = mat.clone();
|
|
48534
|
+
originals.set(mesh2, mat);
|
|
48535
|
+
copies.set(copy, mat);
|
|
48536
|
+
base.set(copy, mat.emissiveIntensity ?? 1);
|
|
48537
|
+
mesh2.material = copy;
|
|
48538
|
+
return copy;
|
|
48539
|
+
};
|
|
48540
|
+
const haloBase = /* @__PURE__ */ new Map();
|
|
48541
|
+
for (const l of lamps) {
|
|
48542
|
+
for (const m of l.inner) own(m);
|
|
48543
|
+
for (const h of l.halo ?? []) haloBase.set(h, h.scale.x);
|
|
48544
|
+
}
|
|
48545
|
+
const amber = /* @__PURE__ */ new Set();
|
|
48546
|
+
const sideOf = /* @__PURE__ */ new Map();
|
|
48547
|
+
for (const l of lamps) {
|
|
48548
|
+
const x = l.group?.position?.x ?? 0;
|
|
48549
|
+
for (const m of l.inner) {
|
|
48550
|
+
const mat = Array.isArray(m.material) ? null : m.material;
|
|
48551
|
+
const c = (mat && (copies.get(mat) ?? mat))?.color;
|
|
48552
|
+
if (c && c.r > 0.5 && c.r - c.b > 0.35 && c.g < c.r * 0.8 && c.g > c.b) {
|
|
48553
|
+
amber.add(m);
|
|
48554
|
+
sideOf.set(m, x >= 0 ? "left" : "right");
|
|
48555
|
+
}
|
|
48556
|
+
}
|
|
48557
|
+
}
|
|
48558
|
+
has.indicators = amber.size > 0;
|
|
48559
|
+
const glowMesh = (m, share) => {
|
|
48560
|
+
const mat = m.material;
|
|
48561
|
+
if (mat && !Array.isArray(mat) && base.has(mat) && "emissiveIntensity" in mat) mat.emissiveIntensity = base.get(mat) * share;
|
|
48562
|
+
};
|
|
48563
|
+
const glow = (l, share) => {
|
|
48564
|
+
for (const m of l.inner) {
|
|
48565
|
+
if (amber.has(m)) continue;
|
|
48566
|
+
glowMesh(m, share);
|
|
48567
|
+
}
|
|
48568
|
+
for (const h of l.halo ?? []) {
|
|
48569
|
+
h.visible = share > 0.5;
|
|
48570
|
+
const s = (haloBase.get(h) ?? 1) * Math.min(1.4, share);
|
|
48571
|
+
h.scale.set(s, s, 1);
|
|
48572
|
+
}
|
|
48573
|
+
};
|
|
48574
|
+
const L = built2.length;
|
|
48575
|
+
const W = built2.width;
|
|
48576
|
+
const H = built2.height;
|
|
48577
|
+
const anchors = [];
|
|
48578
|
+
const anchor = (x, y, z, yaw, drop) => {
|
|
48579
|
+
const a = new THREE.Object3D();
|
|
48580
|
+
a.position.set(x, y, z);
|
|
48581
|
+
a.rotation.set(-drop, yaw, 0, "YXZ");
|
|
48582
|
+
built2.group.add(a);
|
|
48583
|
+
anchors.push(a);
|
|
48584
|
+
return a;
|
|
48585
|
+
};
|
|
48586
|
+
const front = [-1, 1].map((s) => anchor(s * W * 0.34, Math.min(0.9, H * 0.48), L / 2 - 0.05, Math.PI, 0));
|
|
48587
|
+
const fogAnchors = [-1, 1].map((s) => anchor(s * W * 0.38, Math.min(0.45, H * 0.25), L / 2 - 0.03, Math.PI, 0));
|
|
48588
|
+
const rear = anchor(0, Math.min(0.9, H * 0.45), -L / 2 - 0.3, 0, 0);
|
|
48589
|
+
const cabin = anchor(0, H * 0.85, 0, 0, 0);
|
|
48590
|
+
const sources = /* @__PURE__ */ new Map();
|
|
48591
|
+
const beam = (id, on, make2) => {
|
|
48592
|
+
const now = sources.get(id);
|
|
48593
|
+
if (on && !now && budget) sources.set(id, make2());
|
|
48594
|
+
if (!on && now) {
|
|
48595
|
+
for (const s of now) s.remove();
|
|
48596
|
+
sources.delete(id);
|
|
48597
|
+
}
|
|
48598
|
+
};
|
|
48599
|
+
const spots = (at, rule) => at.map((a) => {
|
|
48600
|
+
a.rotation.x = -rule.drop;
|
|
48601
|
+
return budget.addSource({ owner, kind: "spot", priority: LIGHT_PRIORITY.headlight, color: rule.color, intensity: rule.intensity, distance: rule.distance, decay: rule.decay, angle: rule.angle, penumbra: rule.penumbra, position: [0, 0, 0], follow: a });
|
|
48602
|
+
});
|
|
48603
|
+
const point = (a, rule) => [
|
|
48604
|
+
budget.addSource({ owner, kind: "point", priority: LIGHT_PRIORITY.lamp, color: rule.color, intensity: rule.intensity, distance: rule.distance, decay: rule.decay, position: [0, 0, 0], follow: a })
|
|
48605
|
+
];
|
|
48606
|
+
const state = { mode: "off", fog: false, interior: false, brake: false, reverse: false, left: false, right: false };
|
|
48607
|
+
const apply = () => {
|
|
48608
|
+
const g = LAMP_RULES.glow;
|
|
48609
|
+
for (const l of lamps) {
|
|
48610
|
+
if (l.kind === "headlight") glow(l, g.head[state.mode]);
|
|
48611
|
+
else if (l.kind === "taillight") glow(l, state.brake ? g.tail.brake : state.mode === "off" ? g.tail.off : g.tail.on);
|
|
48612
|
+
else if (l.kind === "fog") glow(l, state.fog ? g.fog.on : g.fog.off);
|
|
48613
|
+
}
|
|
48614
|
+
for (const m of amber) glowMesh(m, state[sideOf.get(m) ?? "left"] ? g.amber.on : g.amber.off);
|
|
48615
|
+
const beamId = state.mode === "low" || state.mode === "high" ? state.mode : null;
|
|
48616
|
+
for (const id of ["low", "high"]) beam(id, beamId === id, () => spots(front, LAMP_RULES[id]));
|
|
48617
|
+
beam("fog", state.fog && has.fog, () => spots(fogAnchors, LAMP_RULES.fog));
|
|
48618
|
+
beam("reverse", state.reverse, () => point(rear, LAMP_RULES.reverse));
|
|
48619
|
+
beam("interior", state.interior, () => point(cabin, LAMP_RULES.interior));
|
|
48620
|
+
};
|
|
48621
|
+
apply();
|
|
48622
|
+
return {
|
|
48623
|
+
has,
|
|
48624
|
+
get state() {
|
|
48625
|
+
return { ...state };
|
|
48626
|
+
},
|
|
48627
|
+
set(next) {
|
|
48628
|
+
if (next.mode === state.mode && next.fog === state.fog && next.interior === state.interior && next.brake === state.brake && next.reverse === state.reverse && next.left === state.left && next.right === state.right) return;
|
|
48629
|
+
Object.assign(state, next);
|
|
48630
|
+
apply();
|
|
48631
|
+
},
|
|
48632
|
+
dispose() {
|
|
48633
|
+
for (const list2 of sources.values()) for (const s of list2) s.remove();
|
|
48634
|
+
sources.clear();
|
|
48635
|
+
for (const a of anchors) a.removeFromParent();
|
|
48636
|
+
anchors.length = 0;
|
|
48637
|
+
for (const l of lamps) {
|
|
48638
|
+
for (const m of l.inner) {
|
|
48639
|
+
const copy = m.material;
|
|
48640
|
+
const original = originals.get(m);
|
|
48641
|
+
if (original) {
|
|
48642
|
+
m.material = original;
|
|
48643
|
+
if (copy && !Array.isArray(copy)) copy.dispose?.();
|
|
48644
|
+
}
|
|
48645
|
+
}
|
|
48646
|
+
for (const h of l.halo ?? []) {
|
|
48647
|
+
h.visible = true;
|
|
48648
|
+
const s = haloBase.get(h) ?? 1;
|
|
48649
|
+
h.scale.set(s, s, 1);
|
|
48650
|
+
}
|
|
48651
|
+
}
|
|
48652
|
+
originals.clear();
|
|
48653
|
+
copies.clear();
|
|
48654
|
+
base.clear();
|
|
48655
|
+
}
|
|
48656
|
+
};
|
|
48657
|
+
}
|
|
48658
|
+
|
|
48659
|
+
// 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" };
|
|
48661
|
+
function createCockpit(o) {
|
|
48662
|
+
const sounds = { ...DEFAULT_COCKPIT_SOUNDS, ...o.sounds };
|
|
48663
|
+
const spec = subjectSpec(o.subject);
|
|
48664
|
+
const driver = createSemiSimDriver(spec);
|
|
48665
|
+
driver.place(o.place[0], o.place[1], o.place[2]);
|
|
48666
|
+
const lamps = createVehicleLamps(o.THREE, o.built, { lights: o.host.lights, owner: "proving-ground" });
|
|
48667
|
+
const audio = o.host.audio;
|
|
48668
|
+
const top = o.subject.stats.maxSpeedKmh;
|
|
48669
|
+
const dashboard = o.gauge ? createVehicleDashboard(o.THREE, o.built, { gauge: o.gauge, needle: o.needle, redlineRpm: spec.engine.redlineRpm, maxKmh: top ? Math.ceil((top + 10) / 20) * 20 : void 0 }) : null;
|
|
48670
|
+
const at = () => [o.built.group.position.x, 1, o.built.group.position.z];
|
|
48671
|
+
const play = (sound, volume = 1) => void audio?.play?.({ sound, position: at(), volume });
|
|
48672
|
+
let alarmAgain = 0;
|
|
48673
|
+
let hornAgain = 0;
|
|
48674
|
+
let wipeAgain = 0;
|
|
48675
|
+
let chimeAgain = 0;
|
|
48676
|
+
let radioAgain = 0;
|
|
48677
|
+
let exitAsked = false;
|
|
48678
|
+
let gas = 0;
|
|
48679
|
+
const controls = createVehicleControls({
|
|
48680
|
+
gears: spec.gears?.length ?? 5,
|
|
48681
|
+
fourWheelDrive: !!o.subject.body.fourWheelDrive,
|
|
48682
|
+
fogLamps: lamps.has.fog,
|
|
48683
|
+
onEvent: (event) => {
|
|
48684
|
+
if (event.type === "command") {
|
|
48685
|
+
if (event.command === "ignition" && event.state.ignition && sounds.starter) play(sounds.starter);
|
|
48686
|
+
if (event.command === "ignition" && !event.state.ignition) driver.state.engineOn = false;
|
|
48687
|
+
if (event.command === "alarm" && event.state.alarm === "armed") play(sounds.chirp);
|
|
48688
|
+
if (event.command === "alarm") alarmAgain = 0;
|
|
48689
|
+
if (event.command === "radio" || event.command === "radio_source") radioAgain = 0;
|
|
48690
|
+
if (event.command === "exit") exitAsked = true;
|
|
48691
|
+
}
|
|
48692
|
+
o.onEvent?.(event);
|
|
48693
|
+
}
|
|
48694
|
+
});
|
|
48695
|
+
driver.state.engineOn = false;
|
|
48696
|
+
const target = typeof window !== "undefined" ? window : null;
|
|
48697
|
+
const down = (e) => {
|
|
48698
|
+
if (!controls.key(e.code, true)) return;
|
|
48699
|
+
e.stopImmediatePropagation();
|
|
48700
|
+
if (e.code.startsWith("Arrow") || e.code === "Space") e.preventDefault();
|
|
48701
|
+
};
|
|
48702
|
+
const up = (e) => {
|
|
48703
|
+
if (controls.key(e.code, false)) e.stopImmediatePropagation();
|
|
48704
|
+
};
|
|
48705
|
+
const blur = () => controls.release();
|
|
48706
|
+
target?.addEventListener("keydown", down, true);
|
|
48707
|
+
target?.addEventListener("keyup", up, true);
|
|
48708
|
+
target?.addEventListener("blur", blur);
|
|
48709
|
+
return {
|
|
48710
|
+
driver,
|
|
48711
|
+
controls,
|
|
48712
|
+
lamps,
|
|
48713
|
+
dashboard,
|
|
48714
|
+
get throttle() {
|
|
48715
|
+
return gas;
|
|
48716
|
+
},
|
|
48717
|
+
step(dt) {
|
|
48718
|
+
const input = controls.input(dt, driver);
|
|
48719
|
+
gas = input.throttle;
|
|
48720
|
+
driver.step(input, dt);
|
|
48721
|
+
controls.after(driver, dt);
|
|
48722
|
+
const s = controls.state;
|
|
48723
|
+
lamps.set({
|
|
48724
|
+
mode: s.lamps.mode,
|
|
48725
|
+
fog: s.lamps.fog,
|
|
48726
|
+
interior: s.lamps.interior,
|
|
48727
|
+
brake: s.brakeLights,
|
|
48728
|
+
reverse: s.reverseLights,
|
|
48729
|
+
left: s.blinkOn && (s.indicator === "left" || s.indicator === "hazard"),
|
|
48730
|
+
right: s.blinkOn && (s.indicator === "right" || s.indicator === "hazard")
|
|
48731
|
+
});
|
|
48732
|
+
dashboard?.update(
|
|
48733
|
+
{
|
|
48734
|
+
kmh: Math.abs(driver.state.u) * 3.6,
|
|
48735
|
+
rpm: driver.state.engineOn ? driver.state.rpm : 0,
|
|
48736
|
+
gear: driver.state.gear,
|
|
48737
|
+
ignition: s.ignition,
|
|
48738
|
+
engineOn: driver.state.engineOn,
|
|
48739
|
+
left: s.blinkOn && (s.indicator === "left" || s.indicator === "hazard"),
|
|
48740
|
+
right: s.blinkOn && (s.indicator === "right" || s.indicator === "hazard"),
|
|
48741
|
+
highBeam: s.lamps.mode === "high",
|
|
48742
|
+
lowBeam: s.lamps.mode === "low" || s.lamps.mode === "position",
|
|
48743
|
+
fog: s.lamps.fog,
|
|
48744
|
+
parkingBrake: s.parkingBrake,
|
|
48745
|
+
seatbelt: s.seatbelt,
|
|
48746
|
+
fourWheel: s.fourWheelEngaged
|
|
48747
|
+
},
|
|
48748
|
+
dt
|
|
48749
|
+
);
|
|
48750
|
+
if (s.tick) play(sounds.blinker, 0.8);
|
|
48751
|
+
if (s.horn && (hornAgain -= dt) <= 0) {
|
|
48752
|
+
play(sounds.horn);
|
|
48753
|
+
hornAgain = 0.5;
|
|
48754
|
+
} else if (!s.horn) hornAgain = 0;
|
|
48755
|
+
if (s.alarm === "ringing" && (alarmAgain -= dt) <= 0) {
|
|
48756
|
+
play(sounds.alarm);
|
|
48757
|
+
alarmAgain = 2.9;
|
|
48758
|
+
}
|
|
48759
|
+
if (s.wipers !== "off" && (wipeAgain -= dt) <= 0) {
|
|
48760
|
+
play(sounds.wiper, 0.7);
|
|
48761
|
+
wipeAgain = s.wipers === "fast" ? 0.6 : 1.4;
|
|
48762
|
+
}
|
|
48763
|
+
const kmh2 = Math.abs(driver.state.u) * 3.6;
|
|
48764
|
+
if (!s.seatbelt && s.ignition && kmh2 > 10 && (chimeAgain -= dt) <= 0) {
|
|
48765
|
+
play(sounds.chime, 0.6);
|
|
48766
|
+
chimeAgain = 6;
|
|
48767
|
+
}
|
|
48768
|
+
if (s.radio.on && (radioAgain -= dt) <= 0) {
|
|
48769
|
+
play(sounds.radio, s.radio.source === "tape" ? 0.25 : 0.45);
|
|
48770
|
+
radioAgain = 0.55;
|
|
48771
|
+
}
|
|
48772
|
+
if (exitAsked) {
|
|
48773
|
+
exitAsked = false;
|
|
48774
|
+
o.onExit();
|
|
48775
|
+
}
|
|
48776
|
+
},
|
|
48777
|
+
stop() {
|
|
48778
|
+
target?.removeEventListener("keydown", down, true);
|
|
48779
|
+
target?.removeEventListener("keyup", up, true);
|
|
48780
|
+
target?.removeEventListener("blur", blur);
|
|
48781
|
+
controls.release();
|
|
48782
|
+
lamps.dispose();
|
|
48783
|
+
dashboard?.dispose();
|
|
48784
|
+
}
|
|
48785
|
+
};
|
|
48786
|
+
}
|
|
48787
|
+
|
|
47952
48788
|
// src/test-area/proving/text.ts
|
|
47953
48789
|
var PROVING_TEXT = {
|
|
47954
48790
|
"pt-BR": {
|
|
47955
48791
|
name: "Banco de provas",
|
|
47956
|
-
controls: { vehicle: "Ve\xEDculo", test: "Prova", camera: "C\xE2mera", time_scale: "Velocidade da simula\xE7\xE3o", visual_check: "Checagem visual" },
|
|
48792
|
+
controls: { vehicle: "Ve\xEDculo", test: "Prova", camera: "C\xE2mera", time_scale: "Velocidade da simula\xE7\xE3o", visual_check: "Checagem visual", gearbox: "C\xE2mbio" },
|
|
48793
|
+
gearbox: { automatic: "Autom\xE1tico", manual: "Manual" },
|
|
47957
48794
|
hints: {
|
|
48795
|
+
gearbox: "Autom\xE1tico troca sozinho. Manual: E sobe e Q desce a marcha (abaixo da 1\xAA v\xEAm o neutro e a r\xE9). M alterna dirigindo",
|
|
47958
48796
|
vehicle: "Ve\xEDculo da frota que vai para a pista",
|
|
47959
48797
|
test: "Prova medida que o bot\xE3o Rodar prova executa",
|
|
47960
48798
|
camera: "Sala: a c\xE2mera do jogador. Persegui\xE7\xE3o, cabine e cap\xF4 seguem o ve\xEDculo",
|
|
47961
48799
|
time_scale: "Quantas vezes mais r\xE1pido que o tempo real a prova roda",
|
|
47962
48800
|
visual_check: "O que voc\xEA olhou e vai aprovar ou reprovar"
|
|
47963
48801
|
},
|
|
47964
|
-
actions: { run_test: "Rodar prova", run_all: "Rodar todas na pista", certify_now: "Homologar agora (sem anima\xE7\xE3o)", reverse_park: "Dar r\xE9 (c\xE2mera de r\xE9)", sign_ok: "Aprovar checagem visual", sign_fail: "Reprovar checagem visual", reset: "Limpar ficha" },
|
|
48802
|
+
actions: { drive: "Dirigir (entrar / sair)", run_test: "Rodar prova", run_all: "Rodar todas na pista", certify_now: "Homologar agora (sem anima\xE7\xE3o)", reverse_park: "Dar r\xE9 (c\xE2mera de r\xE9)", sign_ok: "Aprovar checagem visual", sign_fail: "Reprovar checagem visual", reset: "Limpar ficha" },
|
|
47965
48803
|
layers: { mirrors: "Retrovisores", reverse_camera: "C\xE2mera de r\xE9", scoreboard: "Painel da ficha" },
|
|
47966
|
-
metrics: { speed: "Velocidade", time: "Tempo da prova", value: "Medi\xE7\xE3o", passed: "Aprovadas", failed: "Reprovadas", pending: "Pendentes", status: "Situa\xE7\xE3o (0 pend., 1 aprov., -1 reprov.)" },
|
|
48804
|
+
metrics: { gear: "Marcha (-1 r\xE9, 0 neutro)", rpm: "Rota\xE7\xE3o", speed: "Velocidade", time: "Tempo da prova", value: "Medi\xE7\xE3o", passed: "Aprovadas", failed: "Reprovadas", pending: "Pendentes", status: "Situa\xE7\xE3o (0 pend., 1 aprov., -1 reprov.)" },
|
|
47967
48805
|
cameras: { room: "Sala", chase: "Persegui\xE7\xE3o (3\xAA pessoa)", cockpit: "Cabine (1\xAA pessoa)", hood: "Cap\xF4" },
|
|
47968
48806
|
tests: {
|
|
47969
48807
|
accel_0_100: "0 a 100 km/h",
|
|
@@ -47985,22 +48823,49 @@ var GameVehiclesThree = (() => {
|
|
|
47985
48823
|
},
|
|
47986
48824
|
status: { approved: "APROVADO", rejected: "REPROVADO", pending: "PENDENTE" },
|
|
47987
48825
|
verdict: { pass: "ok", fail: "falhou", pending: "\u2026" },
|
|
47988
|
-
board: { title: "Ficha de homologa\xE7\xE3o", test: "Prova", value: "Medido", range: "Faixa", verdict: "Resultado", notRun: "n\xE3o rodada", running: "rodando" },
|
|
47989
|
-
log: { start: "Prova {0}: {1}", result: "{0} \xB7 {1}: {2} {3} (faixa {4}) \u2192 {5}", signed: "{0} \xB7 {1}: {2} na sala", certified: "{0}: {1}" }
|
|
48826
|
+
board: { title: "Ficha de homologa\xE7\xE3o", test: "Prova", value: "Medido", range: "Faixa", verdict: "Resultado", notRun: "n\xE3o rodada", running: "rodando", gear: "Marcha {0} \xB7 {1} rpm \xB7 {2} km/h" },
|
|
48827
|
+
log: { start: "Prova {0}: {1}", result: "{0} \xB7 {1}: {2} {3} (faixa {4}) \u2192 {5}", signed: "{0} \xB7 {1}: {2} na sala", certified: "{0}: {1}", drive: "Dirigindo {0}: I liga o motor, F sai do carro", leave: "Saiu do volante", shift: "Marcha {0} \u2192 {1} a {2} km/h" },
|
|
48828
|
+
cabin: {
|
|
48829
|
+
keys: "W ou \u2191 acelera \xB7 S ou \u2193 freia (parado, d\xE1 r\xE9) \xB7 A/D ou \u2190/\u2192 vira \xB7 Espa\xE7o freio de m\xE3o \xB7 P puxa o freio de m\xE3o \xB7 I liga e desliga \xB7 M c\xE2mbio manual/autom\xE1tico \xB7 E sobe e Q desce marcha \xB7 G tra\xE7\xE3o 4x2/4x4/4x4 autom\xE1tica \xB7 L luzes (posi\xE7\xE3o, baixa) \xB7 K farol alto \xB7 N neblina \xB7 U luz interna \xB7 v\xEDrgula e ponto setas \xB7 B pisca-alerta \xB7 O limpador \xB7 J cinto \xB7 H buzina \xB7 Y alarme \xB7 R r\xE1dio \xB7 T r\xE1dio/fita \xB7 F sai do carro",
|
|
48830
|
+
on: "ligado",
|
|
48831
|
+
off: "desligado",
|
|
48832
|
+
ignition: "Motor",
|
|
48833
|
+
gearbox: "C\xE2mbio",
|
|
48834
|
+
gear: "Marcha",
|
|
48835
|
+
parkingBrake: "Freio de m\xE3o",
|
|
48836
|
+
driveMode: "Tra\xE7\xE3o",
|
|
48837
|
+
modes: { "4x2": "4x2", "4x4": "4x4", auto: "4x4 autom\xE1tica" },
|
|
48838
|
+
lights: "Luzes",
|
|
48839
|
+
lampModes: { off: "apagadas", position: "posi\xE7\xE3o", low: "farol baixo", high: "farol alto" },
|
|
48840
|
+
fog: "Neblina",
|
|
48841
|
+
interior: "Luz interna",
|
|
48842
|
+
alarm: "Alarme",
|
|
48843
|
+
alarmStates: { off: "desligado", armed: "armado", ringing: "disparado" },
|
|
48844
|
+
radio: "Som",
|
|
48845
|
+
sources: { radio: "r\xE1dio", tape: "toca-fitas" },
|
|
48846
|
+
indicator: "Setas",
|
|
48847
|
+
indicators: { off: "desligadas", left: "esquerda", right: "direita", hazard: "pisca-alerta" },
|
|
48848
|
+
wipers: "Limpador",
|
|
48849
|
+
wiperModes: { off: "desligado", slow: "lento", fast: "r\xE1pido" },
|
|
48850
|
+
seatbelt: "Cinto",
|
|
48851
|
+
refused: { no_four_wheel_drive: "Este ve\xEDculo n\xE3o tem tra\xE7\xE3o 4x4", no_fog_lamps: "Este ve\xEDculo n\xE3o tem farol de neblina", ignition_off: "Ligue o motor primeiro" }
|
|
48852
|
+
}
|
|
47990
48853
|
},
|
|
47991
48854
|
en: {
|
|
47992
48855
|
name: "Proving ground",
|
|
47993
|
-
controls: { vehicle: "Vehicle", test: "Test", camera: "Camera", time_scale: "Simulation speed", visual_check: "Visual check" },
|
|
48856
|
+
controls: { vehicle: "Vehicle", test: "Test", camera: "Camera", time_scale: "Simulation speed", visual_check: "Visual check", gearbox: "Gearbox" },
|
|
48857
|
+
gearbox: { automatic: "Automatic", manual: "Manual" },
|
|
47994
48858
|
hints: {
|
|
48859
|
+
gearbox: "Automatic shifts by itself. Manual: E shifts up and Q down (below 1st come neutral and reverse). M switches while driving",
|
|
47995
48860
|
vehicle: "Fleet vehicle that goes on the track",
|
|
47996
48861
|
test: "Measured test the Run test button runs",
|
|
47997
48862
|
camera: "Room: the player camera. Chase, cockpit and hood follow the vehicle",
|
|
47998
48863
|
time_scale: "How many times faster than real time the test runs",
|
|
47999
48864
|
visual_check: "What you looked at and will approve or refuse"
|
|
48000
48865
|
},
|
|
48001
|
-
actions: { run_test: "Run test", run_all: "Run all on the track", certify_now: "Certify now (no animation)", reverse_park: "Reverse (reversing camera)", sign_ok: "Approve visual check", sign_fail: "Refuse visual check", reset: "Clear certificate" },
|
|
48866
|
+
actions: { drive: "Drive (get in / out)", run_test: "Run test", run_all: "Run all on the track", certify_now: "Certify now (no animation)", reverse_park: "Reverse (reversing camera)", sign_ok: "Approve visual check", sign_fail: "Refuse visual check", reset: "Clear certificate" },
|
|
48002
48867
|
layers: { mirrors: "Mirrors", reverse_camera: "Reversing camera", scoreboard: "Certificate board" },
|
|
48003
|
-
metrics: { speed: "Speed", time: "Test time", value: "Measured", passed: "Passed", failed: "Failed", pending: "Pending", status: "Status (0 pending, 1 approved, -1 rejected)" },
|
|
48868
|
+
metrics: { gear: "Gear (-1 reverse, 0 neutral)", rpm: "Engine speed", speed: "Speed", time: "Test time", value: "Measured", passed: "Passed", failed: "Failed", pending: "Pending", status: "Status (0 pending, 1 approved, -1 rejected)" },
|
|
48004
48869
|
cameras: { room: "Room", chase: "Chase (third person)", cockpit: "Cockpit (first person)", hood: "Hood" },
|
|
48005
48870
|
tests: {
|
|
48006
48871
|
accel_0_100: "0 to 100 km/h",
|
|
@@ -48022,8 +48887,33 @@ var GameVehiclesThree = (() => {
|
|
|
48022
48887
|
},
|
|
48023
48888
|
status: { approved: "APPROVED", rejected: "REJECTED", pending: "PENDING" },
|
|
48024
48889
|
verdict: { pass: "ok", fail: "failed", pending: "\u2026" },
|
|
48025
|
-
board: { title: "Certificate", test: "Test", value: "Measured", range: "Range", verdict: "Result", notRun: "not run", running: "running" },
|
|
48026
|
-
log: { start: "Test {0}: {1}", result: "{0} \xB7 {1}: {2} {3} (range {4}) \u2192 {5}", signed: "{0} \xB7 {1}: {2} in the room", certified: "{0}: {1}" }
|
|
48890
|
+
board: { title: "Certificate", test: "Test", value: "Measured", range: "Range", verdict: "Result", notRun: "not run", running: "running", gear: "Gear {0} \xB7 {1} rpm \xB7 {2} km/h" },
|
|
48891
|
+
log: { start: "Test {0}: {1}", result: "{0} \xB7 {1}: {2} {3} (range {4}) \u2192 {5}", signed: "{0} \xB7 {1}: {2} in the room", certified: "{0}: {1}", drive: "Driving {0}: I starts the engine, F gets out", leave: "Left the wheel", shift: "Gear {0} \u2192 {1} at {2} km/h" },
|
|
48892
|
+
cabin: {
|
|
48893
|
+
keys: "W or \u2191 accelerates \xB7 S or \u2193 brakes (stopped, reverses) \xB7 A/D or \u2190/\u2192 steer \xB7 Space handbrake \xB7 P pulls the handbrake \xB7 I ignition \xB7 M manual/automatic gearbox \xB7 E shifts up, Q down \xB7 G drive 4x2/4x4/auto 4x4 \xB7 L lamps (position, low) \xB7 K high beam \xB7 N fog \xB7 U cabin light \xB7 comma and period indicators \xB7 B hazard \xB7 O wipers \xB7 J seat belt \xB7 H horn \xB7 Y alarm \xB7 R radio \xB7 T radio/tape \xB7 F gets out",
|
|
48894
|
+
on: "on",
|
|
48895
|
+
off: "off",
|
|
48896
|
+
ignition: "Engine",
|
|
48897
|
+
gearbox: "Gearbox",
|
|
48898
|
+
gear: "Gear",
|
|
48899
|
+
parkingBrake: "Handbrake",
|
|
48900
|
+
driveMode: "Drive",
|
|
48901
|
+
modes: { "4x2": "4x2", "4x4": "4x4", auto: "automatic 4x4" },
|
|
48902
|
+
lights: "Lamps",
|
|
48903
|
+
lampModes: { off: "off", position: "position", low: "low beam", high: "high beam" },
|
|
48904
|
+
fog: "Fog lamps",
|
|
48905
|
+
interior: "Cabin light",
|
|
48906
|
+
alarm: "Alarm",
|
|
48907
|
+
alarmStates: { off: "off", armed: "armed", ringing: "ringing" },
|
|
48908
|
+
radio: "Sound",
|
|
48909
|
+
sources: { radio: "radio", tape: "tape" },
|
|
48910
|
+
indicator: "Indicators",
|
|
48911
|
+
indicators: { off: "off", left: "left", right: "right", hazard: "hazard" },
|
|
48912
|
+
wipers: "Wipers",
|
|
48913
|
+
wiperModes: { off: "off", slow: "slow", fast: "fast" },
|
|
48914
|
+
seatbelt: "Seat belt",
|
|
48915
|
+
refused: { no_four_wheel_drive: "This vehicle has no 4x4", no_fog_lamps: "This vehicle has no fog lamps", ignition_off: "Start the engine first" }
|
|
48916
|
+
}
|
|
48027
48917
|
}
|
|
48028
48918
|
};
|
|
48029
48919
|
var fillText = (template, ...values) => template.replace(/\{(\d+)\}/g, (_, i) => String(values[Number(i)] ?? ""));
|
|
@@ -48057,6 +48947,10 @@ var GameVehiclesThree = (() => {
|
|
|
48057
48947
|
let car = null;
|
|
48058
48948
|
let run = null;
|
|
48059
48949
|
let parking = null;
|
|
48950
|
+
let driving = null;
|
|
48951
|
+
let gearbox = "automatic";
|
|
48952
|
+
let lastGear = null;
|
|
48953
|
+
let driveClock = 0;
|
|
48060
48954
|
let queue = [];
|
|
48061
48955
|
let open = false;
|
|
48062
48956
|
let lastWrap = 0;
|
|
@@ -48191,13 +49085,13 @@ var GameVehiclesThree = (() => {
|
|
|
48191
49085
|
[text.board.test, text.board.value, text.board.range, text.board.verdict].forEach((h, i) => g.fillText(h.toUpperCase(), cols[i], 150));
|
|
48192
49086
|
let y = 190;
|
|
48193
49087
|
for (const r of cert.results) {
|
|
48194
|
-
const
|
|
49088
|
+
const live2 = run && run.test.id === r.test && !run.done;
|
|
48195
49089
|
g.fillStyle = "#e7e9ec";
|
|
48196
49090
|
g.font = "26px sans-serif";
|
|
48197
49091
|
g.fillText(text.tests[r.test] ?? r.test, cols[0], y);
|
|
48198
49092
|
g.font = "26px monospace";
|
|
48199
49093
|
g.fillStyle = "#5fd4e0";
|
|
48200
|
-
const value =
|
|
49094
|
+
const value = live2 ? text.board.running : r.value == null ? r.kind === "measured" && r.note === "not run" ? text.board.notRun : "\u2014" : `${r.value} ${r.unit}`;
|
|
48201
49095
|
g.fillText(value, cols[1], y);
|
|
48202
49096
|
g.fillStyle = "#8d95a3";
|
|
48203
49097
|
g.fillText(r.kind === "measured" ? fmtRange(r.range) : r.kind === "visual" ? "visual" : "sala", cols[2], y);
|
|
@@ -48205,6 +49099,12 @@ var GameVehiclesThree = (() => {
|
|
|
48205
49099
|
g.fillText(r.verdict === "pass" ? "\u2713 " + text.verdict.pass : r.verdict === "fail" ? "\u2717 " + text.verdict.fail : "\u2026", cols[3], y);
|
|
48206
49100
|
y += 30;
|
|
48207
49101
|
}
|
|
49102
|
+
const live = run?.driver.state ?? driving?.driver.state;
|
|
49103
|
+
if (live) {
|
|
49104
|
+
g.font = "24px monospace";
|
|
49105
|
+
g.fillStyle = "#f2c230";
|
|
49106
|
+
g.fillText(fillText(text.board.gear, gearName(live.gear), Math.round(live.rpm), Math.round(Math.abs(live.u) * 3.6)), cols[0], y + 16);
|
|
49107
|
+
}
|
|
48208
49108
|
board.texture.needsUpdate = true;
|
|
48209
49109
|
};
|
|
48210
49110
|
const removeCar = () => {
|
|
@@ -48276,7 +49176,7 @@ var GameVehiclesThree = (() => {
|
|
|
48276
49176
|
const frameOf = (speed) => {
|
|
48277
49177
|
if (!car) return null;
|
|
48278
49178
|
const g = car.built.group;
|
|
48279
|
-
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, length: car.built.length, width: car.built.width, height: car.built.height };
|
|
49179
|
+
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, length: car.built.length, width: car.built.width, height: car.built.height, ...car.built.driverEye ? { eye: car.built.driverEye } : {} };
|
|
48280
49180
|
};
|
|
48281
49181
|
const applyCamera = () => {
|
|
48282
49182
|
if (!host?.setViewCamera) return;
|
|
@@ -48342,12 +49242,111 @@ var GameVehiclesThree = (() => {
|
|
|
48342
49242
|
driver.place(40, 0, 0);
|
|
48343
49243
|
parking = { driver, time: 0 };
|
|
48344
49244
|
};
|
|
49245
|
+
const stopDriving = () => {
|
|
49246
|
+
if (!driving) return;
|
|
49247
|
+
driving.stop();
|
|
49248
|
+
driving = null;
|
|
49249
|
+
host?.holdPlayer?.(false);
|
|
49250
|
+
host?.bench?.sheet?.(null);
|
|
49251
|
+
stopEngine();
|
|
49252
|
+
host?.log(text.log.leave);
|
|
49253
|
+
};
|
|
49254
|
+
const startDriving = () => {
|
|
49255
|
+
if (!host || !three) return;
|
|
49256
|
+
if (!car || car.subject.id !== settings.vehicle) placeCar();
|
|
49257
|
+
if (!car) return;
|
|
49258
|
+
run = null;
|
|
49259
|
+
queue = [];
|
|
49260
|
+
parking = null;
|
|
49261
|
+
setSurface("dry_asphalt");
|
|
49262
|
+
driving = createCockpit({
|
|
49263
|
+
THREE: three,
|
|
49264
|
+
host,
|
|
49265
|
+
built: car.built,
|
|
49266
|
+
subject: car.subject,
|
|
49267
|
+
place: [0, 0, 0],
|
|
49268
|
+
gauge: kitFor(three).materials?.gauge,
|
|
49269
|
+
needle: kitFor(three).materials?.amber,
|
|
49270
|
+
// the engine's own sound turns the key (starter, catch, idle by RPM)
|
|
49271
|
+
sounds: { starter: "" },
|
|
49272
|
+
onExit: () => stopDriving(),
|
|
49273
|
+
onEvent: (event) => {
|
|
49274
|
+
if (event.type === "refused") return host?.log(text.cabin.refused[event.reason] ?? event.reason);
|
|
49275
|
+
const st = event.state;
|
|
49276
|
+
const line = cabinLine(event.command, st);
|
|
49277
|
+
if (line) host?.log(line);
|
|
49278
|
+
if (event.command === "ignition" && car) {
|
|
49279
|
+
const at = [car.built.group.position.x, 0.5, car.built.group.position.z];
|
|
49280
|
+
if (st.ignition) engine?.start(at);
|
|
49281
|
+
else engine?.stop(at);
|
|
49282
|
+
}
|
|
49283
|
+
if (event.command === "gearbox") {
|
|
49284
|
+
gearbox = st.gearbox;
|
|
49285
|
+
host?.bench?.patch("gearbox", { value: st.gearbox });
|
|
49286
|
+
}
|
|
49287
|
+
}
|
|
49288
|
+
});
|
|
49289
|
+
if (gearbox !== driving.controls.state.gearbox) driving.controls.command("gearbox");
|
|
49290
|
+
host.holdPlayer?.(true);
|
|
49291
|
+
if (settings.camera === "room") {
|
|
49292
|
+
settings.camera = "cockpit";
|
|
49293
|
+
host.bench?.patch("camera", { value: "cockpit" });
|
|
49294
|
+
applyCamera();
|
|
49295
|
+
}
|
|
49296
|
+
rig.vehicle?.reset();
|
|
49297
|
+
stopEngine();
|
|
49298
|
+
engine = createVehicleSound(host.audio, { sounds });
|
|
49299
|
+
host.bench?.sheet?.({ kicker: text.name, title: fillText(text.log.drive, name(settings.vehicle)), body: text.cabin.keys });
|
|
49300
|
+
host.log(fillText(text.log.drive, name(settings.vehicle)));
|
|
49301
|
+
};
|
|
49302
|
+
const onOff = (on) => on ? text.cabin.on : text.cabin.off;
|
|
49303
|
+
const cabinLine = (command, st) => {
|
|
49304
|
+
const c = text.cabin;
|
|
49305
|
+
switch (command) {
|
|
49306
|
+
case "ignition":
|
|
49307
|
+
return `${c.ignition}: ${onOff(st.ignition)}`;
|
|
49308
|
+
case "gearbox":
|
|
49309
|
+
return `${c.gearbox}: ${text.gearbox[st.gearbox]}`;
|
|
49310
|
+
case "gear_up":
|
|
49311
|
+
case "gear_down":
|
|
49312
|
+
return `${c.gear}: ${gearName(st.gear)}`;
|
|
49313
|
+
case "parking_brake":
|
|
49314
|
+
return `${c.parkingBrake}: ${onOff(st.parkingBrake)}`;
|
|
49315
|
+
case "drive_mode":
|
|
49316
|
+
return `${c.driveMode}: ${c.modes[st.driveMode]}`;
|
|
49317
|
+
case "lights":
|
|
49318
|
+
case "high_beam":
|
|
49319
|
+
return `${c.lights}: ${c.lampModes[st.lamps.mode]}`;
|
|
49320
|
+
case "fog_lights":
|
|
49321
|
+
return `${c.fog}: ${onOff(st.lamps.fog)}`;
|
|
49322
|
+
case "interior_light":
|
|
49323
|
+
return `${c.interior}: ${onOff(st.lamps.interior)}`;
|
|
49324
|
+
case "alarm":
|
|
49325
|
+
return `${c.alarm}: ${c.alarmStates[st.alarm]}`;
|
|
49326
|
+
case "radio":
|
|
49327
|
+
case "radio_source":
|
|
49328
|
+
return `${c.radio}: ${st.radio.on ? c.sources[st.radio.source] : c.off}`;
|
|
49329
|
+
case "indicator_left":
|
|
49330
|
+
case "indicator_right":
|
|
49331
|
+
case "hazard":
|
|
49332
|
+
return `${c.indicator}: ${c.indicators[st.indicator]}`;
|
|
49333
|
+
case "wipers":
|
|
49334
|
+
return `${c.wipers}: ${c.wiperModes[st.wipers]}`;
|
|
49335
|
+
case "seatbelt":
|
|
49336
|
+
return `${c.seatbelt}: ${onOff(st.seatbelt)}`;
|
|
49337
|
+
default:
|
|
49338
|
+
return null;
|
|
49339
|
+
}
|
|
49340
|
+
};
|
|
49341
|
+
const gearName = (gear) => gear < 0 ? "R" : gear === 0 ? "N" : String(gear);
|
|
48345
49342
|
const onChange = (change) => {
|
|
48346
49343
|
if (change.kind === "layer") {
|
|
48347
49344
|
if (change.id === "scoreboard" && board) board.mesh.visible = !!host?.bench?.layer("scoreboard");
|
|
48348
49345
|
return refreshMirrors();
|
|
48349
49346
|
}
|
|
48350
49347
|
if (change.kind === "action") {
|
|
49348
|
+
if (change.id === "drive") return driving ? stopDriving() : startDriving();
|
|
49349
|
+
if (change.id === "run_test" || change.id === "run_all" || change.id === "reverse_park") stopDriving();
|
|
48351
49350
|
if (change.id === "run_test") {
|
|
48352
49351
|
queue = [];
|
|
48353
49352
|
startTest(settings.test);
|
|
@@ -48378,6 +49377,7 @@ var GameVehiclesThree = (() => {
|
|
|
48378
49377
|
switch (change.id) {
|
|
48379
49378
|
case "vehicle":
|
|
48380
49379
|
settings.vehicle = String(change.value);
|
|
49380
|
+
stopDriving();
|
|
48381
49381
|
run = null;
|
|
48382
49382
|
queue = [];
|
|
48383
49383
|
parking = null;
|
|
@@ -48395,6 +49395,10 @@ var GameVehiclesThree = (() => {
|
|
|
48395
49395
|
case "time_scale":
|
|
48396
49396
|
settings.timeScale = Number(change.value);
|
|
48397
49397
|
break;
|
|
49398
|
+
case "gearbox":
|
|
49399
|
+
gearbox = change.value === "manual" ? "manual" : "automatic";
|
|
49400
|
+
if (driving && driving.controls.state.gearbox !== gearbox) driving.controls.command("gearbox");
|
|
49401
|
+
break;
|
|
48398
49402
|
case "visual_check":
|
|
48399
49403
|
settings.visual = String(change.value);
|
|
48400
49404
|
break;
|
|
@@ -48418,6 +49422,13 @@ var GameVehiclesThree = (() => {
|
|
|
48418
49422
|
speed = s.u;
|
|
48419
49423
|
steer = s.steerAngle;
|
|
48420
49424
|
if (run.done) finishTest();
|
|
49425
|
+
} else if (driving) {
|
|
49426
|
+
const d = driving;
|
|
49427
|
+
d.step(dt);
|
|
49428
|
+
if (!driving) return;
|
|
49429
|
+
pose(d.driver.state, d.driver.state.steerAngle);
|
|
49430
|
+
speed = d.driver.state.u;
|
|
49431
|
+
steer = d.driver.state.steerAngle;
|
|
48421
49432
|
} else if (parking) {
|
|
48422
49433
|
parking.time += dt;
|
|
48423
49434
|
const p = parking;
|
|
@@ -48427,7 +49438,7 @@ var GameVehiclesThree = (() => {
|
|
|
48427
49438
|
steer = p.driver.state.steerAngle;
|
|
48428
49439
|
if (p.time > 9) parking = null;
|
|
48429
49440
|
}
|
|
48430
|
-
if (car) engine?.update({ dt, position: [car.built.group.position.x, 0.5, car.built.group.position.z], speed, throttle: run ? 1 : 0 });
|
|
49441
|
+
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 });
|
|
48431
49442
|
const f = frameOf(speed);
|
|
48432
49443
|
if (f && rig.vehicle && settings.camera !== "room") rig.vehicle.update(rig.camera, f, dt);
|
|
48433
49444
|
if (f && rig.vehicle) for (const m of rig.mirrors) rig.vehicle.placeMirror(m.camera, m.pose, f);
|
|
@@ -48437,11 +49448,19 @@ var GameVehiclesThree = (() => {
|
|
|
48437
49448
|
mirrorKey = key;
|
|
48438
49449
|
refreshMirrors();
|
|
48439
49450
|
}
|
|
48440
|
-
|
|
49451
|
+
const geared = run?.driver.state ?? driving?.driver.state;
|
|
49452
|
+
if (geared && geared.gear !== lastGear) {
|
|
49453
|
+
if (lastGear !== null && geared.gear > 0) host.log(fillText(text.log.shift, gearName(lastGear), gearName(geared.gear), Math.round(Math.abs(geared.u) * 3.6)), { from: lastGear, to: geared.gear, kmh: +(Math.abs(geared.u) * 3.6).toFixed(1), rpm: Math.round(geared.rpm) }, "proving_shift");
|
|
49454
|
+
lastGear = geared.gear;
|
|
49455
|
+
drawBoard();
|
|
49456
|
+
} else if (!geared) lastGear = null;
|
|
49457
|
+
if (run && Math.floor(run.time * 2) !== Math.floor((run.time - dt * settings.timeScale) * 2) || driving && Math.floor(driveClock * 2) !== Math.floor((driveClock - dt) * 2)) drawBoard();
|
|
49458
|
+
if (driving) driveClock += dt;
|
|
48441
49459
|
};
|
|
48442
|
-
const speedNow = () => Math.abs(run?.driver.state.u ?? parking?.driver.state.u ?? 0) * 3.6;
|
|
49460
|
+
const speedNow = () => Math.abs(run?.driver.state.u ?? driving?.driver.state.u ?? parking?.driver.state.u ?? 0) * 3.6;
|
|
48443
49461
|
const counts = (verdict) => certificateOf(settings.vehicle)?.results.filter((r) => r.verdict === verdict).length ?? 0;
|
|
48444
49462
|
const teardown = () => {
|
|
49463
|
+
stopDriving();
|
|
48445
49464
|
stopEngine();
|
|
48446
49465
|
for (const m of rig.mirrors) m.remove();
|
|
48447
49466
|
rig.mirrors = [];
|
|
@@ -48473,6 +49492,8 @@ var GameVehiclesThree = (() => {
|
|
|
48473
49492
|
{ 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 },
|
|
48474
49493
|
{ kind: "number", id: "time_scale", name: text.controls.time_scale, hint: text.hints.time_scale, min: 1, max: 20, step: 1, default: settings.timeScale },
|
|
48475
49494
|
{ 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
|
+
{ kind: "action", id: "drive", name: text.actions.drive },
|
|
49496
|
+
{ kind: "choice", id: "gearbox", name: text.controls.gearbox, hint: text.hints.gearbox, options: ["automatic", "manual"].map((id) => ({ id, name: text.gearbox[id] })), default: gearbox },
|
|
48476
49497
|
{ kind: "action", id: "run_test", name: text.actions.run_test },
|
|
48477
49498
|
{ kind: "action", id: "run_all", name: text.actions.run_all },
|
|
48478
49499
|
{ kind: "action", id: "certify_now", name: text.actions.certify_now },
|
|
@@ -48488,6 +49509,8 @@ var GameVehiclesThree = (() => {
|
|
|
48488
49509
|
],
|
|
48489
49510
|
metrics: () => [
|
|
48490
49511
|
{ id: "speed", name: text.metrics.speed, unit: "km/h", digits: 0, read: speedNow },
|
|
49512
|
+
{ id: "gear", name: text.metrics.gear, read: () => driving?.driver.state.gear ?? run?.driver.state.gear ?? 0 },
|
|
49513
|
+
{ id: "rpm", name: text.metrics.rpm, unit: "rpm", digits: 0, read: () => driving?.driver.state.rpm ?? run?.driver.state.rpm ?? 0 },
|
|
48491
49514
|
{ id: "time", name: text.metrics.time, unit: "s", digits: 1, read: () => run?.time ?? 0 },
|
|
48492
49515
|
{ id: "value", name: text.metrics.value, digits: 1, read: () => run ? run.trace[run.trace.length - 1]?.[1] ?? 0 : 0 },
|
|
48493
49516
|
{ id: "passed", name: text.metrics.passed, read: () => counts("pass") },
|
|
@@ -48502,6 +49525,7 @@ var GameVehiclesThree = (() => {
|
|
|
48502
49525
|
rig.camera = new three.PerspectiveCamera(60, 1.6, 0.05, 900);
|
|
48503
49526
|
rig.vehicle = createVehicleCamera(three);
|
|
48504
49527
|
lent.audio?.register?.(LIBRARY_BANK);
|
|
49528
|
+
lent.audio?.register?.(CABIN_BANK);
|
|
48505
49529
|
const stopChange = lent.bench?.onChange(onChange);
|
|
48506
49530
|
const stopFrame = lent.onFrame(frame);
|
|
48507
49531
|
const stopClear = lent.onClear?.(() => {
|