@fboes/aerofly-custom-missions 1.2.0 → 1.2.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/CHANGELOG.md +15 -1
- package/README.md +2 -7
- package/dist/index.js +184 -111
- package/dist/index.test.js +99 -39
- package/docs/custom_missions_user.tmc +49 -1234
- package/package.json +1 -1
- package/src/index.test.ts +109 -34
- package/src/index.ts +244 -138
- package/types/index.d.ts +96 -108
- package/types/index.d.ts.map +1 -1
- package/types/index.test.d.ts +1 -1
package/src/index.ts
CHANGED
|
@@ -25,7 +25,17 @@ export type AeroflyMissionPosition = {
|
|
|
25
25
|
/**
|
|
26
26
|
* State of aircraft systems. Configures power settings, flap positions etc
|
|
27
27
|
*/
|
|
28
|
-
export type AeroflyMissionSetting =
|
|
28
|
+
export type AeroflyMissionSetting =
|
|
29
|
+
| "cold_and_dark"
|
|
30
|
+
| "before_start"
|
|
31
|
+
| "taxi"
|
|
32
|
+
| "takeoff"
|
|
33
|
+
| "cruise"
|
|
34
|
+
| "approach"
|
|
35
|
+
| "landing"
|
|
36
|
+
| "winch_launch"
|
|
37
|
+
| "aerotow"
|
|
38
|
+
| "pushback";
|
|
29
39
|
|
|
30
40
|
/**
|
|
31
41
|
* Types of checkpoints. Required are usually "origin", "departure_runway" at the start and "destination_runway", "destination" at the end.
|
|
@@ -69,6 +79,42 @@ export type AeroflyMissionConditionsWind = {
|
|
|
69
79
|
*/
|
|
70
80
|
export type AeroflyMissionConditionsCloudCoverCode = "CLR" | "FEW" | "SCT" | "BKN" | "OVC";
|
|
71
81
|
|
|
82
|
+
export class AeroflyConfigFileSet {
|
|
83
|
+
#indent: number;
|
|
84
|
+
elements: string[];
|
|
85
|
+
|
|
86
|
+
constructor(indent: number, type: string, name: string, value: string = "") {
|
|
87
|
+
this.#indent = indent;
|
|
88
|
+
this.elements = [`${this.indent}<[${type}][${name}][${value}]`];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get indent(): string {
|
|
92
|
+
return " ".repeat(this.#indent);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
push(type: string, name: string, value: string | number | string[] | number[] | boolean, comment: string = "") {
|
|
96
|
+
if (value instanceof Array) {
|
|
97
|
+
value = value.join(" ");
|
|
98
|
+
} else if (typeof value === "boolean") {
|
|
99
|
+
value = value ? "true" : "false";
|
|
100
|
+
}
|
|
101
|
+
let tag = `${this.indent} <[${type}][${name}][${value}]>`;
|
|
102
|
+
if (comment) {
|
|
103
|
+
tag += ` // ${comment}`;
|
|
104
|
+
}
|
|
105
|
+
return this.pushRaw(tag);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pushRaw(s: string) {
|
|
109
|
+
this.elements.push(s);
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
toString() {
|
|
114
|
+
return this.elements.join("\n") + "\n" + `${this.indent}>`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
72
118
|
/**
|
|
73
119
|
* @class
|
|
74
120
|
* A list of flight plans.
|
|
@@ -95,7 +141,8 @@ export class AeroflyMissionsList {
|
|
|
95
141
|
*/
|
|
96
142
|
toString(): string {
|
|
97
143
|
const separator = "\n// -----------------------------------------------------------------------------\n";
|
|
98
|
-
return
|
|
144
|
+
return `\
|
|
145
|
+
<[file][][]
|
|
99
146
|
<[tmmissions_list][][]
|
|
100
147
|
<[list_tmmission_definition][missions][]${separator + this.missions.join(separator) + separator} >
|
|
101
148
|
>
|
|
@@ -112,7 +159,10 @@ export class AeroflyMissionsList {
|
|
|
112
159
|
* for this file via the `toString()` method.
|
|
113
160
|
*/
|
|
114
161
|
export class AeroflyMission {
|
|
115
|
-
|
|
162
|
+
/**
|
|
163
|
+
* @property {?string} tutorialName will create a link to a tutorial page at https://www.aerofly.com/aircraft-tutorials/
|
|
164
|
+
*/
|
|
165
|
+
tutorialName: string | null;
|
|
116
166
|
|
|
117
167
|
/**
|
|
118
168
|
* @property {string} title of this flight plan
|
|
@@ -135,17 +185,17 @@ export class AeroflyMission {
|
|
|
135
185
|
tags: string[];
|
|
136
186
|
|
|
137
187
|
/**
|
|
138
|
-
* @property {boolean} isFeatured makes this mission pop up in "Challenges"
|
|
188
|
+
* @property {?boolean} isFeatured makes this mission pop up in "Challenges"
|
|
139
189
|
*/
|
|
140
|
-
isFeatured: boolean;
|
|
190
|
+
isFeatured: boolean | null;
|
|
141
191
|
|
|
142
192
|
/**
|
|
143
|
-
* @property {number
|
|
193
|
+
* @property {?number} difficulty values between 0.00 and 2.00 have been encountered, but they seem to be without limit
|
|
144
194
|
*/
|
|
145
|
-
difficulty: number |
|
|
195
|
+
difficulty: number | null;
|
|
146
196
|
|
|
147
197
|
/**
|
|
148
|
-
* @property {"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"} flightSetting of aircraft, like "taxi", "cruise"
|
|
198
|
+
* @property {"cold_and_dark"|"before_start"|"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"|"pushback"} flightSetting of aircraft, like "taxi", "cruise"
|
|
149
199
|
*/
|
|
150
200
|
flightSetting: AeroflyMissionSetting;
|
|
151
201
|
|
|
@@ -170,14 +220,19 @@ export class AeroflyMission {
|
|
|
170
220
|
destination: AeroflyMissionPosition;
|
|
171
221
|
|
|
172
222
|
/**
|
|
173
|
-
* @property {number} in meters
|
|
223
|
+
* @property {?number} distance in meters
|
|
224
|
+
*/
|
|
225
|
+
distance: number | null;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* @property {?number} duration in seconds
|
|
174
229
|
*/
|
|
175
|
-
|
|
230
|
+
duration: number | null;
|
|
176
231
|
|
|
177
232
|
/**
|
|
178
|
-
* @property {
|
|
233
|
+
* @property {?boolean} isScheduled marks this flight as "Scheduled flight".
|
|
179
234
|
*/
|
|
180
|
-
|
|
235
|
+
isScheduled: boolean | null;
|
|
181
236
|
|
|
182
237
|
/**
|
|
183
238
|
* @property {?AeroflyMissionTargetPlane} finish as finish condition
|
|
@@ -199,16 +254,18 @@ export class AeroflyMission {
|
|
|
199
254
|
* @param {object} [additionalAttributes] allows to set additional attributes on creation
|
|
200
255
|
* @param {string} [additionalAttributes.description] text, mission briefing, etc
|
|
201
256
|
* @param {AeroflyLocalizedText[]} [additionalAttributes.localizedTexts] translations for title and description
|
|
257
|
+
* @param {?string} [additionalAttributes.tutorialName] will create a link to a tutorial page at https://www.aerofly.com/aircraft-tutorials/
|
|
202
258
|
* @param {string[]} [additionalAttributes.tags]
|
|
203
|
-
* @param {boolean} [additionalAttributes.isFeatured] makes this mission pop up in "Challenges"
|
|
204
|
-
* @param {number
|
|
205
|
-
* @param {"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"} [additionalAttributes.flightSetting] of aircraft, like "taxi", "cruise"
|
|
259
|
+
* @param {?boolean} [additionalAttributes.isFeatured] makes this mission pop up in "Challenges"
|
|
260
|
+
* @param {?number} [additionalAttributes.difficulty] values between 0.00 and 2.00 have been encountered, but they seem to be without limit
|
|
261
|
+
* @param {"cold_and_dark"|"before_start"|"taxi"|"takeoff"|"cruise"|"approach"|"landing"|"winch_launch"|"aerotow"|"pushback"} [additionalAttributes.flightSetting] of aircraft, like "taxi", "cruise"
|
|
206
262
|
* @param {{name:string,livery:string,icao:string}} [additionalAttributes.aircraft] for this mission
|
|
207
263
|
* @param {string} [additionalAttributes.callsign] of aircraft, uppercased
|
|
208
264
|
* @param {object} [additionalAttributes.origin] position of aircraft, as well as name of starting airport. Position does not have match airport.
|
|
209
265
|
* @param {object} [additionalAttributes.destination] position of aircraft, as well as name of destination airport. Position does not have match airport.
|
|
210
|
-
* @param {number} [additionalAttributes.distance] in meters
|
|
211
|
-
* @param {number} [additionalAttributes.duration] in seconds
|
|
266
|
+
* @param {?number} [additionalAttributes.distance] in meters
|
|
267
|
+
* @param {?number} [additionalAttributes.duration] in seconds
|
|
268
|
+
* @param {?boolean} [additionalAttributes.isScheduled] marks this flight as "Scheduled flight".
|
|
212
269
|
* @param {?AeroflyMissionTargetPlane} [additionalAttributes.finish] as finish condition
|
|
213
270
|
* @param {AeroflyMissionConditions} [additionalAttributes.conditions] like time and weather for mission
|
|
214
271
|
* @param {AeroflyMissionCheckpoint[]} [additionalAttributes.checkpoints] form the actual flight plan
|
|
@@ -216,11 +273,12 @@ export class AeroflyMission {
|
|
|
216
273
|
constructor(
|
|
217
274
|
title: string,
|
|
218
275
|
{
|
|
276
|
+
tutorialName = null,
|
|
219
277
|
description = "",
|
|
220
278
|
localizedTexts = [],
|
|
221
279
|
tags = [],
|
|
222
|
-
isFeatured =
|
|
223
|
-
difficulty =
|
|
280
|
+
isFeatured = null,
|
|
281
|
+
difficulty = null,
|
|
224
282
|
flightSetting = "taxi",
|
|
225
283
|
aircraft = {
|
|
226
284
|
name: "c172",
|
|
@@ -242,29 +300,33 @@ export class AeroflyMission {
|
|
|
242
300
|
dir: 0,
|
|
243
301
|
alt: 0,
|
|
244
302
|
},
|
|
245
|
-
distance =
|
|
246
|
-
duration =
|
|
303
|
+
distance = null,
|
|
304
|
+
duration = null,
|
|
305
|
+
isScheduled = null,
|
|
247
306
|
finish = null,
|
|
248
307
|
conditions = new AeroflyMissionConditions(),
|
|
249
308
|
checkpoints = [],
|
|
250
309
|
}: {
|
|
310
|
+
tutorialName?: string | null;
|
|
251
311
|
description?: string;
|
|
252
312
|
localizedTexts?: AeroflyLocalizedText[];
|
|
253
313
|
tags?: string[];
|
|
254
|
-
isFeatured?: boolean;
|
|
255
|
-
difficulty?: number |
|
|
314
|
+
isFeatured?: boolean | null;
|
|
315
|
+
difficulty?: number | null;
|
|
256
316
|
flightSetting?: AeroflyMissionSetting;
|
|
257
317
|
aircraft?: AeroflyMissionAircraft;
|
|
258
318
|
callsign?: string;
|
|
259
319
|
origin?: AeroflyMissionPosition;
|
|
260
320
|
destination?: AeroflyMissionPosition;
|
|
261
|
-
distance?: number;
|
|
262
|
-
duration?: number;
|
|
321
|
+
distance?: number | null;
|
|
322
|
+
duration?: number | null;
|
|
323
|
+
isScheduled?: boolean | null;
|
|
263
324
|
finish?: AeroflyMissionTargetPlane | null;
|
|
264
325
|
conditions?: AeroflyMissionConditions;
|
|
265
326
|
checkpoints?: AeroflyMissionCheckpoint[];
|
|
266
327
|
} = {},
|
|
267
328
|
) {
|
|
329
|
+
this.tutorialName = tutorialName;
|
|
268
330
|
this.title = title;
|
|
269
331
|
this.checkpoints = checkpoints;
|
|
270
332
|
this.description = description;
|
|
@@ -279,6 +341,7 @@ export class AeroflyMission {
|
|
|
279
341
|
this.destination = destination;
|
|
280
342
|
this.distance = distance;
|
|
281
343
|
this.duration = duration;
|
|
344
|
+
this.isScheduled = isScheduled;
|
|
282
345
|
this.finish = finish;
|
|
283
346
|
this.conditions = conditions;
|
|
284
347
|
}
|
|
@@ -310,10 +373,6 @@ export class AeroflyMission {
|
|
|
310
373
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
311
374
|
*/
|
|
312
375
|
toString(): string {
|
|
313
|
-
if (this.checkpoints.length < 2) {
|
|
314
|
-
throw Error("this.checkpoints.length < 2");
|
|
315
|
-
}
|
|
316
|
-
|
|
317
376
|
if (!this.origin.icao) {
|
|
318
377
|
const firstCheckpoint = this.checkpoints[0];
|
|
319
378
|
this.origin = {
|
|
@@ -336,60 +395,79 @@ export class AeroflyMission {
|
|
|
336
395
|
};
|
|
337
396
|
}
|
|
338
397
|
|
|
339
|
-
const
|
|
398
|
+
const fileSet = new AeroflyConfigFileSet(3, "tmmission_definition", "mission");
|
|
399
|
+
fileSet.push("string8", "title", this.title);
|
|
400
|
+
fileSet.push("string8", "description", this.description);
|
|
401
|
+
|
|
402
|
+
if (this.tutorialName !== null) {
|
|
403
|
+
fileSet.push(
|
|
404
|
+
"string8",
|
|
405
|
+
"tutorial_name",
|
|
406
|
+
this.tutorialName,
|
|
407
|
+
`Opens https://www.aerofly.com/aircraft-tutorials/${this.tutorialName}`,
|
|
408
|
+
);
|
|
409
|
+
}
|
|
340
410
|
if (this.localizedTexts.length > 0) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
411
|
+
fileSet.pushRaw(
|
|
412
|
+
new AeroflyConfigFileSet(4, "list_tmmission_definition_localized", "localized_text")
|
|
413
|
+
.pushRaw(this.getLocalizedTextsString())
|
|
414
|
+
.toString(),
|
|
415
|
+
);
|
|
344
416
|
}
|
|
345
417
|
if (this.tags.length > 0) {
|
|
346
|
-
|
|
418
|
+
fileSet.push("string8u", "tags", this.tags.join(" "));
|
|
347
419
|
}
|
|
348
|
-
if (this.difficulty !==
|
|
349
|
-
|
|
420
|
+
if (this.difficulty !== null) {
|
|
421
|
+
fileSet.push("float64", "difficulty", this.difficulty);
|
|
350
422
|
}
|
|
351
|
-
if (this.isFeatured) {
|
|
352
|
-
|
|
353
|
-
` <[bool] [is_featured] [${this.isFeatured ? "true" : "false"}]>`,
|
|
354
|
-
);
|
|
423
|
+
if (this.isFeatured !== null) {
|
|
424
|
+
fileSet.push("bool", "is_featured", this.isFeatured);
|
|
355
425
|
}
|
|
356
426
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
427
|
+
fileSet.push("string8", "flight_setting", this.flightSetting);
|
|
428
|
+
fileSet.push("string8u", "aircraft_name", this.aircraft.name);
|
|
429
|
+
/*if (this.aircraft.livery) {
|
|
430
|
+
fileSet.push("string8", "aircraft_livery", this.aircraft.livery);
|
|
431
|
+
}*/
|
|
432
|
+
fileSet.push("stringt8c", "aircraft_icao", this.aircraft.icao);
|
|
433
|
+
fileSet.push("stringt8c", "callsign", this.callsign);
|
|
434
|
+
fileSet.push("stringt8c", "origin_icao", this.origin.icao);
|
|
435
|
+
fileSet.push("tmvector2d", "origin_lon_lat", [this.origin.longitude, this.origin.latitude]);
|
|
436
|
+
fileSet.push("float64", "origin_alt", this.origin.alt, `${Math.ceil(this.origin.alt * feetPerMeter)} ft MSL`);
|
|
437
|
+
fileSet.push("float64", "origin_dir", this.origin.dir);
|
|
438
|
+
fileSet.push("stringt8c", "destination_icao", this.destination.icao);
|
|
439
|
+
fileSet.push("tmvector2d", "destination_lon_lat", [this.destination.longitude, this.destination.latitude]);
|
|
440
|
+
fileSet.push(
|
|
441
|
+
"float64",
|
|
442
|
+
"destination_alt",
|
|
443
|
+
this.destination.alt,
|
|
444
|
+
`${Math.ceil(this.destination.alt * feetPerMeter)} ft MSL`,
|
|
445
|
+
);
|
|
446
|
+
fileSet.push("float64", "destination_dir", this.destination.dir);
|
|
447
|
+
|
|
448
|
+
if (this.distance !== null) {
|
|
449
|
+
fileSet.push("float64", "distance", this.distance, `${Math.round(this.distance / 1000)} km`);
|
|
362
450
|
}
|
|
363
|
-
if (this.duration) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
451
|
+
if (this.duration !== null) {
|
|
452
|
+
fileSet.push("float64", "duration", this.duration, `${Math.round(this.duration / 60)} min`);
|
|
453
|
+
}
|
|
454
|
+
if (this.isScheduled !== null) {
|
|
455
|
+
fileSet.push("bool", "is_scheduled", this.isScheduled ? "true" : "false");
|
|
367
456
|
}
|
|
368
|
-
if (this.finish) {
|
|
369
|
-
|
|
457
|
+
if (this.finish !== null) {
|
|
458
|
+
fileSet.pushRaw(this.finish.toString());
|
|
370
459
|
}
|
|
371
460
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
<[float64] [origin_alt] [${this.origin.alt}]> // ${Math.ceil(this.origin.alt * feetPerMeter)} ft MSL
|
|
383
|
-
<[float64] [origin_dir] [${this.origin.dir}]>
|
|
384
|
-
<[stringt8c] [destination_icao] [${this.destination.icao}]>
|
|
385
|
-
<[tmvector2d][destination_lon_lat][${this.destination.longitude} ${this.destination.latitude}]>
|
|
386
|
-
<[float64] [destination_alt] [${this.destination.alt}]> // ${Math.ceil(this.destination.alt * feetPerMeter)} ft MSL
|
|
387
|
-
<[float64] [destination_dir] [${this.destination.dir}]>${moreOptionalProperties.length > 0 ? "\n" + moreOptionalProperties.join("\n") : ""}
|
|
388
|
-
${this.conditions}
|
|
389
|
-
<[list_tmmission_checkpoint][checkpoints][]
|
|
390
|
-
${this.getCheckpointsString()}
|
|
391
|
-
>
|
|
392
|
-
>`;
|
|
461
|
+
fileSet.pushRaw(this.conditions.toString());
|
|
462
|
+
if (this.checkpoints.length > 0) {
|
|
463
|
+
fileSet.pushRaw(
|
|
464
|
+
new AeroflyConfigFileSet(4, "list_tmmission_checkpoint", "checkpoints")
|
|
465
|
+
.pushRaw(this.getCheckpointsString())
|
|
466
|
+
.toString(),
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return fileSet.toString();
|
|
393
471
|
}
|
|
394
472
|
}
|
|
395
473
|
|
|
@@ -441,8 +519,8 @@ export class AeroflyMissionConditions {
|
|
|
441
519
|
* @param {number} [additionalAttributes.turbulenceStrength] 0..1, percentage
|
|
442
520
|
* @param {number} [additionalAttributes.thermalStrength] 0..1, percentage
|
|
443
521
|
* @param {number} [additionalAttributes.visibility] in meters
|
|
444
|
-
* @param {number
|
|
445
|
-
* @param {number
|
|
522
|
+
* @param {?number} [additionalAttributes.visibility_sm] in statute miles, will overwrite visibility
|
|
523
|
+
* @param {?number} [additionalAttributes.temperature] in °C, will overwrite thermalStrength
|
|
446
524
|
* @param {AeroflyMissionConditionsCloud[]} [additionalAttributes.clouds] for the whole flight
|
|
447
525
|
*/
|
|
448
526
|
constructor({
|
|
@@ -554,21 +632,23 @@ export class AeroflyMissionConditions {
|
|
|
554
632
|
this.clouds = [new AeroflyMissionConditionsCloud(0, 0)];
|
|
555
633
|
}
|
|
556
634
|
|
|
557
|
-
return
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
635
|
+
return new AeroflyConfigFileSet(4, "tmmission_conditions", "conditions")
|
|
636
|
+
.pushRaw(
|
|
637
|
+
new AeroflyConfigFileSet(5, "tm_time_utc", "time")
|
|
638
|
+
.push("int32", "time_year", this.time.getUTCFullYear())
|
|
639
|
+
.push("int32", "time_month", this.time.getUTCMonth() + 1)
|
|
640
|
+
.push("int32", "time_day", this.time.getUTCDate())
|
|
641
|
+
.push("float64", "time_hours", this.time_hours, `${this.time_presentational} UTC`)
|
|
642
|
+
.toString(),
|
|
643
|
+
)
|
|
644
|
+
.push("float64", "wind_direction", this.wind.direction)
|
|
645
|
+
.push("float64", "wind_speed", this.wind.speed, "kts")
|
|
646
|
+
.push("float64", "wind_gusts", this.wind.gusts, "kts")
|
|
647
|
+
.push("float64", "turbulence_strength", this.turbulenceStrength)
|
|
648
|
+
.push("float64", "thermal_strength", this.thermalStrength, `${this.temperature} °C`)
|
|
649
|
+
.push("float64", "visibility", this.visibility, `${this.visibility_sm} SM`)
|
|
650
|
+
.pushRaw(this.getCloudsString())
|
|
651
|
+
.toString();
|
|
572
652
|
}
|
|
573
653
|
}
|
|
574
654
|
|
|
@@ -644,19 +724,25 @@ export class AeroflyMissionConditionsCloud {
|
|
|
644
724
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
645
725
|
*/
|
|
646
726
|
toString(index: number = 0): string {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
727
|
+
const getIndexString = (index: number) => {
|
|
728
|
+
switch (index) {
|
|
729
|
+
case 0:
|
|
730
|
+
return "cloud";
|
|
731
|
+
case 1:
|
|
732
|
+
return "cirrus";
|
|
733
|
+
case 2:
|
|
734
|
+
return "cumulus_mediocris";
|
|
735
|
+
default:
|
|
736
|
+
return "more_clouds";
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
const indexString = getIndexString(index);
|
|
741
|
+
const comment = index > 1 ? '//' : '';
|
|
657
742
|
|
|
658
|
-
return
|
|
659
|
-
<[float64][${indexString}
|
|
743
|
+
return `\
|
|
744
|
+
${comment}<[float64][${indexString}_cover][${this.cover ?? 0}]> // ${this.cover_code}
|
|
745
|
+
${comment}<[float64][${indexString}_base][${this.base}]> // ${this.base_feet} ft AGL`;
|
|
660
746
|
}
|
|
661
747
|
}
|
|
662
748
|
|
|
@@ -700,6 +786,13 @@ export class AeroflyMissionCheckpoint {
|
|
|
700
786
|
*/
|
|
701
787
|
altitude: number;
|
|
702
788
|
|
|
789
|
+
/**
|
|
790
|
+
* @property {?boolean} altitudeConstraint The altitude given in `altitude`
|
|
791
|
+
* will be interpreted as mandatory flight plan altitude instead of
|
|
792
|
+
* suggestion.
|
|
793
|
+
*/
|
|
794
|
+
altitudeConstraint: boolean | null;
|
|
795
|
+
|
|
703
796
|
/**
|
|
704
797
|
* @property {?number} direction of runway, in degree
|
|
705
798
|
*/
|
|
@@ -721,9 +814,9 @@ export class AeroflyMissionCheckpoint {
|
|
|
721
814
|
frequency: number | null;
|
|
722
815
|
|
|
723
816
|
/**
|
|
724
|
-
* @property {boolean
|
|
817
|
+
* @property {?boolean} flyOver if waypoint is meant to be flown over
|
|
725
818
|
*/
|
|
726
|
-
flyOver: boolean |
|
|
819
|
+
flyOver: boolean | null;
|
|
727
820
|
|
|
728
821
|
/**
|
|
729
822
|
* @param {string} name ICAO code for airport, runway designator, navaid
|
|
@@ -738,14 +831,17 @@ export class AeroflyMissionCheckpoint {
|
|
|
738
831
|
* @param {object} additionalAttributes allows to set additional attributes on creation
|
|
739
832
|
* @param {number} [additionalAttributes.altitude] The height in meters above or below the WGS
|
|
740
833
|
* 84 reference ellipsoid
|
|
741
|
-
* @param {number
|
|
834
|
+
* @param {?number} [additionalAttributes.altitude_feet] The height in feet above or below the WGS
|
|
742
835
|
* 84 reference ellipsoid. Will overwrite altitude
|
|
743
|
-
* @param {number} [additionalAttributes.
|
|
744
|
-
*
|
|
745
|
-
*
|
|
746
|
-
* @param {
|
|
747
|
-
* @param {number
|
|
748
|
-
* @param {
|
|
836
|
+
* @param {number} [additionalAttributes.altitudeConstraint] The altitude given in `altitude`
|
|
837
|
+
* will be interpreted as mandatory flight plan altitude instead of
|
|
838
|
+
* suggestion.
|
|
839
|
+
* @param {boolean} [additionalAttributes.direction] of runway, in degree
|
|
840
|
+
* @param {?number} [additionalAttributes.slope] of runway
|
|
841
|
+
* @param {?number} [additionalAttributes.length] of runway, in meters
|
|
842
|
+
* @param {?number} [additionalAttributes.length_feet] of runway, in feet. Will overwrite length
|
|
843
|
+
* @param {?number} [additionalAttributes.frequency] of runways or navigational aids, in Hz; multiply by 1000 for kHz, 1_000_000 for MHz
|
|
844
|
+
* @param {?boolean} [additionalAttributes.flyOver] if waypoint is meant to be flown over
|
|
749
845
|
*/
|
|
750
846
|
constructor(
|
|
751
847
|
name: string,
|
|
@@ -755,21 +851,23 @@ export class AeroflyMissionCheckpoint {
|
|
|
755
851
|
{
|
|
756
852
|
altitude = 0,
|
|
757
853
|
altitude_feet = null,
|
|
854
|
+
altitudeConstraint = null,
|
|
758
855
|
direction = null,
|
|
759
856
|
slope = null,
|
|
760
857
|
length = null,
|
|
761
858
|
length_feet = null,
|
|
762
859
|
frequency = null,
|
|
763
|
-
flyOver =
|
|
860
|
+
flyOver = null,
|
|
764
861
|
}: {
|
|
765
862
|
altitude?: number;
|
|
766
863
|
altitude_feet?: number | null;
|
|
864
|
+
altitudeConstraint?: boolean | null;
|
|
767
865
|
direction?: number | null;
|
|
768
866
|
slope?: number | null;
|
|
769
867
|
length?: number | null;
|
|
770
868
|
length_feet?: number | null;
|
|
771
869
|
frequency?: number | null;
|
|
772
|
-
flyOver?: boolean |
|
|
870
|
+
flyOver?: boolean | null;
|
|
773
871
|
} = {},
|
|
774
872
|
) {
|
|
775
873
|
this.type = type;
|
|
@@ -777,6 +875,7 @@ export class AeroflyMissionCheckpoint {
|
|
|
777
875
|
this.longitude = longitude;
|
|
778
876
|
this.latitude = latitude;
|
|
779
877
|
this.altitude = altitude;
|
|
878
|
+
this.altitudeConstraint = altitudeConstraint;
|
|
780
879
|
this.direction = direction;
|
|
781
880
|
this.slope = slope;
|
|
782
881
|
this.length = length;
|
|
@@ -841,32 +940,35 @@ export class AeroflyMissionCheckpoint {
|
|
|
841
940
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
842
941
|
*/
|
|
843
942
|
toString(index: number = 0): string {
|
|
844
|
-
const
|
|
943
|
+
const fileSet = new AeroflyConfigFileSet(5, "tmmission_checkpoint", "element", String(index))
|
|
944
|
+
.push("string8u", "type", this.type)
|
|
945
|
+
.push("string8u", "name", this.name)
|
|
946
|
+
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
947
|
+
.push("float64", "altitude", this.altitude, `${Math.ceil(this.altitude_feet)} ft`)
|
|
948
|
+
.push("float64", "direction", this.direction ?? (index === 0 ? -1 : 0))
|
|
949
|
+
.push("float64", "slope", this.slope ?? 0);
|
|
950
|
+
|
|
951
|
+
if (this.altitudeConstraint !== null) {
|
|
952
|
+
fileSet.push("bool", "alt_cst", this.altitudeConstraint);
|
|
953
|
+
}
|
|
845
954
|
if (this.length) {
|
|
846
|
-
|
|
847
|
-
` <[float64][length][${this.length ?? 0}]> // ${Math.floor(this.length_feet)} ft`,
|
|
848
|
-
);
|
|
955
|
+
fileSet.push("float64", "length", this.length ?? 0, `${Math.floor(this.length_feet)} ft`);
|
|
849
956
|
}
|
|
850
957
|
if (this.frequency) {
|
|
851
|
-
|
|
852
|
-
` <[float64][frequency][${this.frequency ?? 0}]> // ${this.frequency_string}`,
|
|
853
|
-
);
|
|
958
|
+
fileSet.push("float64", "frequency", this.frequency ?? 0, `${this.frequency_string}`);
|
|
854
959
|
}
|
|
855
|
-
if (this.flyOver !==
|
|
856
|
-
|
|
960
|
+
if (this.flyOver !== null) {
|
|
961
|
+
fileSet.push("bool", "fly_over", this.flyOver);
|
|
857
962
|
}
|
|
858
963
|
|
|
859
|
-
return
|
|
860
|
-
<[string8u][type][${this.type}]>
|
|
861
|
-
<[string8u][name][${this.name}]>
|
|
862
|
-
<[vector2_float64][lon_lat][${this.longitude} ${this.latitude}]>
|
|
863
|
-
<[float64][altitude][${this.altitude}]> // ${Math.ceil(this.altitude_feet)} ft
|
|
864
|
-
<[float64][direction][${this.direction ?? (index === 0 ? -1 : 0)}]>
|
|
865
|
-
<[float64][slope][${this.slope ?? 0}]>${optionalProperties.length > 0 ? "\n" + optionalProperties.join("\n") : ""}
|
|
866
|
-
>`;
|
|
964
|
+
return fileSet.toString();
|
|
867
965
|
}
|
|
868
966
|
}
|
|
869
967
|
|
|
968
|
+
/**
|
|
969
|
+
* @class
|
|
970
|
+
* A translation for the mission title and description.
|
|
971
|
+
*/
|
|
870
972
|
export class AeroflyLocalizedText {
|
|
871
973
|
/**
|
|
872
974
|
* @property {string} language ISO 639-1 like
|
|
@@ -923,14 +1025,18 @@ export class AeroflyLocalizedText {
|
|
|
923
1025
|
* @returns {string} to use in Aerofly FS4's `custom_missions_user.tmc`
|
|
924
1026
|
*/
|
|
925
1027
|
toString(index: number = 0): string {
|
|
926
|
-
return
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1028
|
+
return new AeroflyConfigFileSet(4, "tmmission_definition_localized", "element", String(index))
|
|
1029
|
+
.push("string8u", "language", this.language)
|
|
1030
|
+
.push("string8", "title", this.title)
|
|
1031
|
+
.push("string8", "description", this.description)
|
|
1032
|
+
.toString();
|
|
931
1033
|
}
|
|
932
1034
|
}
|
|
933
1035
|
|
|
1036
|
+
/**
|
|
1037
|
+
* @class
|
|
1038
|
+
* A target plane which the aircraft needs to cross.
|
|
1039
|
+
*/
|
|
934
1040
|
export class AeroflyMissionTargetPlane {
|
|
935
1041
|
/**
|
|
936
1042
|
* @property {number} longitude easting, using the World Geodetic
|
|
@@ -975,10 +1081,10 @@ export class AeroflyMissionTargetPlane {
|
|
|
975
1081
|
}
|
|
976
1082
|
|
|
977
1083
|
toString(): string {
|
|
978
|
-
return
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1084
|
+
return new AeroflyConfigFileSet(4, "tmmission_target_plane", this.name)
|
|
1085
|
+
.push("vector2_float64", "lon_lat", [this.longitude, this.latitude])
|
|
1086
|
+
.push("float64", "direction", this.dir)
|
|
1087
|
+
.toString();
|
|
982
1088
|
}
|
|
983
1089
|
}
|
|
984
1090
|
|