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